summaryrefslogtreecommitdiffstats
path: root/o3d
diff options
context:
space:
mode:
authorapatrick@google.com <apatrick@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-12 19:56:24 +0000
committerapatrick@google.com <apatrick@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-12 19:56:24 +0000
commitccf02ac9bd67d4d49ad8264ae7fc6098e361ff4b (patch)
treefc6e4a0552431c7297798fad46f57fb76c35a3b3 /o3d
parentdfe9d1d2de7fd8d244599b79a22898cce8df7c81 (diff)
downloadchromium_src-ccf02ac9bd67d4d49ad8264ae7fc6098e361ff4b.zip
chromium_src-ccf02ac9bd67d4d49ad8264ae7fc6098e361ff4b.tar.gz
chromium_src-ccf02ac9bd67d4d49ad8264ae7fc6098e361ff4b.tar.bz2
Made all line endings consistently LF and added svn:eol-style=LF property to files with these names / extensions.
c cc h mm txt idl py js html css gyp gypi xml shader json htm README DEPS git-svn-id: svn://svn.chromium.org/chrome/trunk/src@31811 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d')
-rw-r--r--o3d/README6
-rw-r--r--o3d/build/file_exists.py20
-rw-r--r--o3d/build/is_admin.py118
-rw-r--r--o3d/collada_edge/cross/collada_edge.cpp174
-rw-r--r--o3d/collada_edge/cross/conditioner.cpp738
-rw-r--r--o3d/collada_edge/cross/conditioner.h238
-rw-r--r--o3d/collada_edge/cross/precompile.h104
-rw-r--r--o3d/collada_edge/cross/utility.h86
-rw-r--r--o3d/core/cross/bitmap.h808
-rw-r--r--o3d/core/cross/client_info.h270
-rw-r--r--o3d/core/cross/gl/gl_headers.h86
-rw-r--r--o3d/core/cross/image_utils.h576
-rw-r--r--o3d/core/cross/pointer_utils.h116
-rw-r--r--o3d/core/win/d3d9/software_renderer_d3d9.h2
-rwxr-xr-xo3d/documentation/externs/o3d-extra-externs.js96
-rw-r--r--o3d/documentation/get_docs_files.py104
-rw-r--r--o3d/documentation/jsdoc-toolkit-templates/static/prettify.css68
-rwxr-xr-xo3d/gypbuild.py592
-rw-r--r--o3d/import/cross/camera_info.h442
-rw-r--r--o3d/import/cross/destination_buffer.h166
-rw-r--r--o3d/import/cross/json_object.h578
-rw-r--r--o3d/plugin/idl/bitmap.idl224
-rw-r--r--o3d/plugin/idl/get_idl_files.py52
-rw-r--r--o3d/samples/GoogleIO-2009/assets/style.css16
-rw-r--r--o3d/samples/bitmap-draw-image.html492
-rw-r--r--o3d/samples/box2d-3d/third_party/box2d/box2d.js2074
-rw-r--r--o3d/samples/manipulators/translate1.html546
-rw-r--r--o3d/samples/o3djs/manipulators.js1924
-rw-r--r--o3d/samples/o3djs/performance.js404
-rw-r--r--o3d/samples/o3djs/texture.js478
-rw-r--r--o3d/samples/siteswap/animation.js396
-rw-r--r--o3d/samples/siteswap/math.js2984
-rw-r--r--o3d/samples/siteswap/siteswap.html646
-rw-r--r--o3d/samples/siteswap/siteswap.js830
-rw-r--r--o3d/serializer/cross/README.txt134
-rw-r--r--o3d/tests/lab/runner_constants.py2
-rw-r--r--o3d/tests/selenium/pdiff_test.py264
-rw-r--r--o3d/tests/selenium/tests/render-target-clear-test.html312
-rw-r--r--o3d/utils/cross/base64.h184
-rw-r--r--o3d/utils/cross/dataurl.h140
-rw-r--r--o3d/utils/cross/math_gtest.h142
41 files changed, 8816 insertions, 8816 deletions
diff --git a/o3d/README b/o3d/README
index fc54408..f0c492a 100644
--- a/o3d/README
+++ b/o3d/README
@@ -1,4 +1,4 @@
-This is the Google O3D source code, currently copied from the
-code.google.com repository at http://code.google.com/p/o3d
-
+This is the Google O3D source code, currently copied from the
+code.google.com repository at http://code.google.com/p/o3d
+
It is currently not referenced or built as part of the Chrome build. \ No newline at end of file
diff --git a/o3d/build/file_exists.py b/o3d/build/file_exists.py
index 6f6abb2..aac99b7 100644
--- a/o3d/build/file_exists.py
+++ b/o3d/build/file_exists.py
@@ -1,10 +1,10 @@
-#!/usr/bin/env python
-# Copyright (c) 2009 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import os.path
-import sys
-
-sys.stdout.write(str(os.path.exists(sys.argv[1])))
-sys.exit(0)
+#!/usr/bin/env python
+# Copyright (c) 2009 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os.path
+import sys
+
+sys.stdout.write(str(os.path.exists(sys.argv[1])))
+sys.exit(0)
diff --git a/o3d/build/is_admin.py b/o3d/build/is_admin.py
index 8fa30c4..33789a4 100644
--- a/o3d/build/is_admin.py
+++ b/o3d/build/is_admin.py
@@ -1,59 +1,59 @@
-#!/usr/bin/env python
-# Copyright (c) 2009 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-#
-# Checks if the user is running as admin
-
-import os
-import os.path
-import sys
-import subprocess
-import platform
-import re
-
-def IsAdminNT():
- # (1, 4, 0): '95',
- # (1, 4, 10): '98',
- # (1, 4, 90): 'ME',
- # (2, 4, 0): 'NT',
- # (2, 5, 0): '2000',
- # (2, 5, 1): 'XP',
- # (2, 5, 2): '2003',
- v = sys.getwindowsversion()
- v = v[3], v[0], v[1]
- # check that we are in vista or greater so we know that
- # 'whoami.exe' exists.
- if v[0] > 2 or (v[0] == 2 and v[1] >= 6):
- output = subprocess.Popen(['whoami.exe', '/all'],
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE).communicate()[0]
- elevated_sid = "S-1-16-12288"
- admin_sid = "S-1-5-32-544"
-
- if re.search(elevated_sid, output) and re.search(admin_sid, output):
- return True
- return False
- else:
- # Where in XP or 2000. For now just assume we are admin.
- return True
-
-def IsAdmin():
- if os.name == 'nt':
- is_admin = IsAdminNT()
- elif platform.system() == 'Darwin':
- is_admin = False
- elif platform.system() == 'Linux':
- is_admin = False
- else:
- is_admin = False
- return is_admin
-
-
-def main(args):
- sys.stdout.write(str(IsAdmin()))
-
-
-if __name__ == "__main__":
- main(sys.argv)
- sys.exit(0)
+#!/usr/bin/env python
+# Copyright (c) 2009 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# Checks if the user is running as admin
+
+import os
+import os.path
+import sys
+import subprocess
+import platform
+import re
+
+def IsAdminNT():
+ # (1, 4, 0): '95',
+ # (1, 4, 10): '98',
+ # (1, 4, 90): 'ME',
+ # (2, 4, 0): 'NT',
+ # (2, 5, 0): '2000',
+ # (2, 5, 1): 'XP',
+ # (2, 5, 2): '2003',
+ v = sys.getwindowsversion()
+ v = v[3], v[0], v[1]
+ # check that we are in vista or greater so we know that
+ # 'whoami.exe' exists.
+ if v[0] > 2 or (v[0] == 2 and v[1] >= 6):
+ output = subprocess.Popen(['whoami.exe', '/all'],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE).communicate()[0]
+ elevated_sid = "S-1-16-12288"
+ admin_sid = "S-1-5-32-544"
+
+ if re.search(elevated_sid, output) and re.search(admin_sid, output):
+ return True
+ return False
+ else:
+ # Where in XP or 2000. For now just assume we are admin.
+ return True
+
+def IsAdmin():
+ if os.name == 'nt':
+ is_admin = IsAdminNT()
+ elif platform.system() == 'Darwin':
+ is_admin = False
+ elif platform.system() == 'Linux':
+ is_admin = False
+ else:
+ is_admin = False
+ return is_admin
+
+
+def main(args):
+ sys.stdout.write(str(IsAdmin()))
+
+
+if __name__ == "__main__":
+ main(sys.argv)
+ sys.exit(0)
diff --git a/o3d/collada_edge/cross/collada_edge.cpp b/o3d/collada_edge/cross/collada_edge.cpp
index d989476..81bb477 100644
--- a/o3d/collada_edge/cross/collada_edge.cpp
+++ b/o3d/collada_edge/cross/collada_edge.cpp
@@ -1,87 +1,87 @@
-/*
- * 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.
- */
-
-// collada_edge.cpp : Defines the entry point for the console application.
-#include "precompile.h"
-#include "conditioner.h"
-#include <cstdio>
-
-static const char *usage =
-"\nUsage: ColladaEdgeConditioner <infile.dae> <outifle.dae> [ options ]\n\n\
-Options:\n\
- -sharpEdgeThreshold t : sharp edge threshold defined by dihedral \n\
- angle. Edges with a angle smaller than t\n\
- will be defined as a sharp edge.\n\
- -sharpEdgeColor r,g,b : color of addtional edges.\n\
- default value is 1,0,0 .(no space)\n\n\
-ColladaEdgeConditioner checks all polygon edges in <infile.dae> and add\n\
-addtional edges to the model if normal angle of certain edge is larger\n\
-than the pre-defined threshold.\n";
-
-int wmain(int argc, wchar_t **argv) {
- wchar_t* input_file = NULL;
- wchar_t* output_file = NULL;
- Options options;
-
- if (argc < 3) {
- printf("%s", usage);
- return -1;
- }
- int file_count = 0;
- for (int i = 1; i < argc; i++) {
- if (wcscmp(argv[i], L"-sharpEdgeThreshold") == 0) {
- if (++i < argc) {
- options.enable_soften_edge = true;
- options.soften_edge_threshold = static_cast<float>(_wtof(argv[i]));
- }
- } else if (wcscmp(argv[i], L"-sharpEdgeColor") == 0) {
- if (++i < argc) {
- int r, g, b;
- if (swscanf_s(argv[i], L"%d,%d,%d", &r, &g, &b) != 3) {
- printf("Invalid -sharpEdgeColor. Should be -sharpEdgeColor=x,y,z\n");
- return -1;
- }
- options.sharp_edge_color = Vector3(static_cast<float>(r),
- static_cast<float>(g),
- static_cast<float>(b));
- }
- } else if (file_count < 2) {
- ++file_count;
- if (file_count == 1)
- input_file = argv[i];
- else
- output_file = argv[i];
- }
- }
-
- bool result = Condition(input_file, output_file, options);
- return 0;
-}
+/*
+ * 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.
+ */
+
+// collada_edge.cpp : Defines the entry point for the console application.
+#include "precompile.h"
+#include "conditioner.h"
+#include <cstdio>
+
+static const char *usage =
+"\nUsage: ColladaEdgeConditioner <infile.dae> <outifle.dae> [ options ]\n\n\
+Options:\n\
+ -sharpEdgeThreshold t : sharp edge threshold defined by dihedral \n\
+ angle. Edges with a angle smaller than t\n\
+ will be defined as a sharp edge.\n\
+ -sharpEdgeColor r,g,b : color of addtional edges.\n\
+ default value is 1,0,0 .(no space)\n\n\
+ColladaEdgeConditioner checks all polygon edges in <infile.dae> and add\n\
+addtional edges to the model if normal angle of certain edge is larger\n\
+than the pre-defined threshold.\n";
+
+int wmain(int argc, wchar_t **argv) {
+ wchar_t* input_file = NULL;
+ wchar_t* output_file = NULL;
+ Options options;
+
+ if (argc < 3) {
+ printf("%s", usage);
+ return -1;
+ }
+ int file_count = 0;
+ for (int i = 1; i < argc; i++) {
+ if (wcscmp(argv[i], L"-sharpEdgeThreshold") == 0) {
+ if (++i < argc) {
+ options.enable_soften_edge = true;
+ options.soften_edge_threshold = static_cast<float>(_wtof(argv[i]));
+ }
+ } else if (wcscmp(argv[i], L"-sharpEdgeColor") == 0) {
+ if (++i < argc) {
+ int r, g, b;
+ if (swscanf_s(argv[i], L"%d,%d,%d", &r, &g, &b) != 3) {
+ printf("Invalid -sharpEdgeColor. Should be -sharpEdgeColor=x,y,z\n");
+ return -1;
+ }
+ options.sharp_edge_color = Vector3(static_cast<float>(r),
+ static_cast<float>(g),
+ static_cast<float>(b));
+ }
+ } else if (file_count < 2) {
+ ++file_count;
+ if (file_count == 1)
+ input_file = argv[i];
+ else
+ output_file = argv[i];
+ }
+ }
+
+ bool result = Condition(input_file, output_file, options);
+ return 0;
+}
diff --git a/o3d/collada_edge/cross/conditioner.cpp b/o3d/collada_edge/cross/conditioner.cpp
index 6f8580a..e1592b4 100644
--- a/o3d/collada_edge/cross/conditioner.cpp
+++ b/o3d/collada_edge/cross/conditioner.cpp
@@ -1,370 +1,370 @@
-/*
- * 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.
- */
-#include "precompile.h"
-
-#include "conditioner.h"
-
-#include <cstdio>
-#include <map>
-#include <vector>
-
-const float kEpsilon = 0.001f;
-static const float kPi = 3.14159265358979f;
-FCDMaterial* edge_material = NULL;
-FCDEffect* edge_effect = NULL;
-
-// Constructor, make sure points order is unique. If x-coordinate is
-// the same, compare y-coordinate. If y value is also the same, compare z.
-Edge::Edge(Point3 p1, Point3 p2, uint32 i1, uint32 i2) {
- bool isRightOrder = false;
- if (fabs(p1.getX() - p2.getX()) < kEpsilon) {
- if (fabs(p1.getY() - p2.getY()) < kEpsilon) {
- if (p1.getZ() < p2.getZ())
- isRightOrder = true;
- } else {
- if (p1.getY() < p2.getY())
- isRightOrder = true;
- }
- } else {
- if (p1.getX() < p2.getX())
- isRightOrder = true;
- }
- if (isRightOrder) {
- pts.push_back(p1);
- pts.push_back(p2);
- indices.push_back(i1);
- indices.push_back(i2);
- } else {
- pts.push_back(p2);
- pts.push_back(p1);
- indices.push_back(i2);
- indices.push_back(i1);
- }
-}
-
-// less than operator overload, necessary function for edge-triangle map.
-bool operator<(const Edge& left, const Edge& right) {
- // compare two edges by their actually coordinates.
- if (dist(left.pts[0], right.pts[0]) < kEpsilon) {
- if (fabs(left.pts[1].getX() - right.pts[1].getX()) < kEpsilon) {
- if (fabs(left.pts[1].getY() - right.pts[1].getY()) < kEpsilon) {
- return left.pts[1].getZ() < right.pts[1].getZ();
- }
- return left.pts[1].getY() < right.pts[1].getY();
- }
- return left.pts[1].getX() < right.pts[1].getX();
- } else {
- if (fabs(left.pts[0].getX() - right.pts[0].getX()) < kEpsilon) {
- if (fabs(left.pts[0].getY() - right.pts[0].getY()) < kEpsilon) {
- return left.pts[0].getZ() < right.pts[0].getZ();
- }
- return left.pts[0].getY() < right.pts[0].getY();
- }
- return left.pts[0].getX() < right.pts[0].getX();
- }
-}
-
-// go through triangles who share this edge. And check whether
-// the max normal angle is larger than the threshold.
-void CheckSharpEdge(const Edge& shared_edge,
- const std::vector<Triangle>& triangle_list,
- std::vector<Edge>* sharp_edges, float threshold) {
- for (size_t i = 0; i < triangle_list.size(); i++)
- for (size_t j = i + 1; j < triangle_list.size(); j++) {
- Triangle t1 = triangle_list[i];
- Triangle t2 = triangle_list[j];
- int same_vertices_count = 0;
- // Same triangle might be stored twice to represent inner and
- // outer faces. Check the order of indices of vertices to not
- // mix inner and outer faces togeter.
- std::vector<int> same_vertices_pos;
- for (int k = 0; k < 3; k++)
- for (int l = 0; l < 3; l++) {
- if (dist(t1.pts[k], t2.pts[l]) < kEpsilon) {
- same_vertices_count++;
- same_vertices_pos.push_back(k);
- same_vertices_pos.push_back(l);
- }
- }
- if (same_vertices_count != 2)
- continue;
- // check the order of positions to make sure triangles are on
- // the same face.
- int i1 = same_vertices_pos[2] - same_vertices_pos[0];
- int i2 = same_vertices_pos[3] - same_vertices_pos[1];
- // if triangles are on different faces.
- if (!(i1 * i2 == -1 || i1 * i2 == 2 || i1 * i2 == -4))
- continue;
-
- Vector3 v12 = t1.pts[1] - t1.pts[0];
- Vector3 v13 = t1.pts[2] - t1.pts[0];
- Vector3 n1 = cross(v12, v13);
- Vector3 v22 = t2.pts[1] - t2.pts[0];
- Vector3 v23 = t2.pts[2] - t2.pts[0];
- Vector3 n2 = cross(v22, v23);
- float iAngle = acos(dot(n1, n2) / (length(n1) * length(n2)));
- iAngle = iAngle * 180 / kPi;
- if (iAngle >= threshold) {
- sharp_edges->push_back(shared_edge);
- return;
- }
- }
-}
-
-// insert edge-triangle pair to edge triangle map.
-void InsertEdgeTrianglePair(const Edge& edge, const Triangle& triangle,
- std::map<Edge, std::vector<Triangle>>* et_map) {
- std::map<Edge, std::vector<Triangle>>::iterator iter1 =
- et_map->find(edge);
- if (iter1 == et_map->end()) {
- std::vector<Triangle> same_edge_triangle_list;
- same_edge_triangle_list.push_back(triangle);
- et_map->insert(make_pair(edge, same_edge_triangle_list));
- } else {
- iter1->second.push_back(triangle);
- }
-}
-
-NodeInstance* CreateInstanceTree(FCDSceneNode *node) {
- NodeInstance *instance = new NodeInstance(node);
- NodeInstance::NodeInstanceList &children = instance->children();
- for (size_t i = 0; i < node->GetChildrenCount(); ++i) {
- FCDSceneNode *child_node = node->GetChild(i);
- NodeInstance *child_instance = CreateInstanceTree(child_node);
- children.push_back(child_instance);
- }
- return instance;
-}
-
-// go through all polygons in geom_instance, and add all sharp edges
-// as a new polygon in geom. And also, add material and effect based
-// on the given sharpEdgeColor option.
-void BuildSharpEdge(FCDocument* doc, FCDGeometryInstance* geom_instance,
- const Options& options) {
- FCDGeometry* geom = static_cast<FCDGeometry*>(geom_instance->GetEntity());
- if (!(geom && geom->IsMesh()))
- return;
- FCDGeometryMesh* mesh = geom->GetMesh();
- FCDGeometryPolygonsTools::Triangulate(mesh);
- FCDGeometryPolygonsTools::GenerateUniqueIndices(mesh, NULL, NULL);
-
- size_t num_polygons = mesh->GetPolygonsCount();
- size_t num_indices = mesh->GetFaceVertexCount();
- if (num_polygons <= 0 || num_indices <= 0) return;
- FCDGeometrySource* pos_source =
- mesh->FindSourceByType(FUDaeGeometryInput::POSITION);
- if (pos_source == NULL) return;
- size_t num_vertices = pos_source->GetValueCount();
- float* pos_source_data = pos_source->GetData();
- std::vector<Point3> point_list;
- for (size_t i = 0; i + 2 < num_vertices * 3; i += 3) {
- Point3 point(pos_source_data[i + 0],
- pos_source_data[i + 1],
- pos_source_data[i + 2]);
- point_list.push_back(point);
- }
-
- for (size_t p = 0; p < num_polygons; ++p) {
- FCDGeometryPolygons* polys = mesh->GetPolygons(p);
-
- if (polys->GetPrimitiveType() != FCDGeometryPolygons::POLYGONS)
- continue;
- FCDGeometryPolygonsInput* input = polys->GetInput(0);
- size_t size = input->GetIndexCount();
- if (size == 0) continue;
- // meshed triangle list.
- size_t vertices_per_primitive = 3;
- if (size % vertices_per_primitive != 0) {
- continue;
- }
- uint32* indices = input->GetIndices();
- size_t indexCount = input->GetIndexCount();
- // create triangle list.
- std::vector<Triangle> triangle_list;
- for (size_t i = 0; i + 2 < indexCount; i += 3) {
- Triangle triangle(point_list[indices[i + 0]],
- point_list[indices[i + 1]],
- point_list[indices[i + 2]],
- indices[i + 0],
- indices[i + 1],
- indices[i + 2]);
- triangle_list.push_back(triangle);
- }
- std::map<Edge, std::vector<Triangle>> edge_triangle_map;
- for (size_t i = 0; i < triangle_list.size(); i++) {
- Triangle triangle = triangle_list[i];
- Edge e1(triangle.pts[0], triangle.pts[1],
- triangle.indices[0], triangle.indices[1]);
- Edge e2(triangle.pts[1], triangle.pts[2],
- triangle.indices[1], triangle.indices[2]);
- Edge e3(triangle.pts[0], triangle.pts[2],
- triangle.indices[0], triangle.indices[2]);
- InsertEdgeTrianglePair(e1, triangle, &edge_triangle_map);
- InsertEdgeTrianglePair(e2, triangle, &edge_triangle_map);
- InsertEdgeTrianglePair(e3, triangle, &edge_triangle_map);
- }
- // go through the edge-triangle map.
- std::map<Edge, std::vector<Triangle>>::iterator iter;
- std::vector<Edge> sharp_edges;
- for (iter = edge_triangle_map.begin();
- iter != edge_triangle_map.end(); iter++) {
- if (iter->second.size() < 2)
- continue;
- CheckSharpEdge(iter->first, iter->second, &sharp_edges,
- options.soften_edge_threshold);
- }
- if (sharp_edges.size() > 0) {
- FCDGeometryPolygons* edge_polys = mesh->AddPolygons();
- edge_polys->AddFaceVertexCount(sharp_edges.size() * 2);
- edge_polys->SetPrimitiveType(FCDGeometryPolygons::LINES);
- FCDGeometrySource* vertex_source = mesh->GetVertexSource(0);
- FCDGeometryPolygonsInput* edge_input =
- edge_polys->AddInput(vertex_source, 0);
- FUDaeGeometryInput::Semantic semantic = edge_input->GetSemantic();
- if (edge_input == NULL)
- return;
- FCDGeometrySource* edge_source = edge_input->GetSource();
- if (edge_source == NULL)
- return;
- for (size_t i = 0; i < sharp_edges.size(); i++) {
- edge_input->AddIndex(sharp_edges[i].indices[0]);
- edge_input->AddIndex(sharp_edges[i].indices[1]);
- }
- edge_input->SetIndexCount(sharp_edges.size() * 2);
- edge_input->SetOffset(0);
-
- if (edge_material == NULL) {
- // add material to material lib.
- FCDMaterialLibrary* material_library = doc->GetMaterialLibrary();
- FCDEffectLibrary* effect_library = doc->GetEffectLibrary();
- edge_material =
- static_cast<FCDMaterial*>(material_library->AddEntity());
- edge_material->SetDaeId("o3d_hard_edge_materialID");
- edge_material->SetName(L"o3d_hard_edge_material");
- edge_effect = static_cast<FCDEffect*>(effect_library->AddEntity());
- edge_effect->SetDaeId("o3d_hard_edge_effectID");
- edge_effect->SetName(L"o3d_hard_edge_effect");
- if (edge_effect == NULL || edge_material == NULL)
- return;
- edge_material->SetEffect(edge_effect);
- FCDEffectStandard* edge_effect_profile =
- static_cast<FCDEffectStandard*>(edge_effect->AddProfile(
- FUDaeProfileType::COMMON));
- edge_effect_profile->SetLightingType(FCDEffectStandard::LAMBERT);
- edge_effect_profile->
- SetEmissionColor(FMVector4(options.sharp_edge_color.getX(),
- options.sharp_edge_color.getY(),
- options.sharp_edge_color.getZ(), 1));
- }
- // add material instance to visual scenes lib.
- FCDMaterialInstance* edge_material_instance =
- geom_instance->AddMaterialInstance(edge_material, edge_polys);
- edge_material_instance->SetSemantic(L"o3d_hard_edge_material");
- edge_polys->SetMaterialSemantic(L"o3d_hard_edge_material");
- }
- }
-}
-
-// go through the collada tree and import instance. if found a
-// geometry instance, call BuildSharpEdge function.
-bool ImportTreeInstances(FCDocument* doc,
- NodeInstance *node_instance,
- const Options& options) {
- FCDSceneNode *node = node_instance->node();
- // recursively import the rest of the nodes in the tree
- const NodeInstance::NodeInstanceList &children = node_instance->children();
- for (size_t i = 0; i < children.size(); ++i) {
- if (!ImportTreeInstances(doc, children[i], options)) {
- return false;
- }
- }
- for (size_t i = 0; i < node->GetInstanceCount(); ++i) {
- FCDEntityInstance* instance = node->GetInstance(i);
- FCDCamera* camera(NULL);
- FCDGeometryInstance* geom_instance(NULL);
- FCDMaterialInstance* mat_instance(NULL);
- // Import each node based on what kind of entity it is
- switch (instance->GetEntityType()) {
- case FCDEntity::GEOMETRY: {
- // geometry entity
- geom_instance = static_cast<FCDGeometryInstance*>(instance);
- BuildSharpEdge(doc, geom_instance, options);
- break;
- }
- case FCDEntity::CAMERA:
- case FCDEntity::CONTROLLER:
- default: break;
- }
- }
- return true;
-}
-
-bool ConditionDoc(FCDocument* doc, const Options& options) {
- // The root of the instance node tree.
- NodeInstance* instance_root_;
- bool status = false;
- // Import the scene objects, starting at the root.
- FCDSceneNode* scene = doc->GetVisualSceneInstance();
- if (scene) {
- instance_root_ = CreateInstanceTree(scene);
- if (ImportTreeInstances(doc, instance_root_, options)) {
- status = true;
- }
- delete instance_root_;
- }
- return status;
-}
-
-bool Condition(const wchar_t* in_filename, const wchar_t* out_filename,
- const Options& options) {
- FCollada::Initialize();
- FCDocument* doc = FCollada::NewTopDocument();
- bool retval = false;
- if (doc) {
- // Load and parse the COLLADA file.
- if (FCollada::LoadDocumentFromFile(doc, in_filename)) {
- doc->SetFileUrl(out_filename);
-
- // condition it.
- retval = ConditionDoc(doc, options);
- if (retval) {
- FCollada::SaveDocument(doc, out_filename);
- }
- } else {
- printf("Error: couldn't open the input file.\n");
- }
- doc->Release();
- } else {
- printf("Internal error: Couldn't create FCollada document.\n");
- }
- FCollada::Release();
- return retval;
+/*
+ * 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.
+ */
+#include "precompile.h"
+
+#include "conditioner.h"
+
+#include <cstdio>
+#include <map>
+#include <vector>
+
+const float kEpsilon = 0.001f;
+static const float kPi = 3.14159265358979f;
+FCDMaterial* edge_material = NULL;
+FCDEffect* edge_effect = NULL;
+
+// Constructor, make sure points order is unique. If x-coordinate is
+// the same, compare y-coordinate. If y value is also the same, compare z.
+Edge::Edge(Point3 p1, Point3 p2, uint32 i1, uint32 i2) {
+ bool isRightOrder = false;
+ if (fabs(p1.getX() - p2.getX()) < kEpsilon) {
+ if (fabs(p1.getY() - p2.getY()) < kEpsilon) {
+ if (p1.getZ() < p2.getZ())
+ isRightOrder = true;
+ } else {
+ if (p1.getY() < p2.getY())
+ isRightOrder = true;
+ }
+ } else {
+ if (p1.getX() < p2.getX())
+ isRightOrder = true;
+ }
+ if (isRightOrder) {
+ pts.push_back(p1);
+ pts.push_back(p2);
+ indices.push_back(i1);
+ indices.push_back(i2);
+ } else {
+ pts.push_back(p2);
+ pts.push_back(p1);
+ indices.push_back(i2);
+ indices.push_back(i1);
+ }
+}
+
+// less than operator overload, necessary function for edge-triangle map.
+bool operator<(const Edge& left, const Edge& right) {
+ // compare two edges by their actually coordinates.
+ if (dist(left.pts[0], right.pts[0]) < kEpsilon) {
+ if (fabs(left.pts[1].getX() - right.pts[1].getX()) < kEpsilon) {
+ if (fabs(left.pts[1].getY() - right.pts[1].getY()) < kEpsilon) {
+ return left.pts[1].getZ() < right.pts[1].getZ();
+ }
+ return left.pts[1].getY() < right.pts[1].getY();
+ }
+ return left.pts[1].getX() < right.pts[1].getX();
+ } else {
+ if (fabs(left.pts[0].getX() - right.pts[0].getX()) < kEpsilon) {
+ if (fabs(left.pts[0].getY() - right.pts[0].getY()) < kEpsilon) {
+ return left.pts[0].getZ() < right.pts[0].getZ();
+ }
+ return left.pts[0].getY() < right.pts[0].getY();
+ }
+ return left.pts[0].getX() < right.pts[0].getX();
+ }
+}
+
+// go through triangles who share this edge. And check whether
+// the max normal angle is larger than the threshold.
+void CheckSharpEdge(const Edge& shared_edge,
+ const std::vector<Triangle>& triangle_list,
+ std::vector<Edge>* sharp_edges, float threshold) {
+ for (size_t i = 0; i < triangle_list.size(); i++)
+ for (size_t j = i + 1; j < triangle_list.size(); j++) {
+ Triangle t1 = triangle_list[i];
+ Triangle t2 = triangle_list[j];
+ int same_vertices_count = 0;
+ // Same triangle might be stored twice to represent inner and
+ // outer faces. Check the order of indices of vertices to not
+ // mix inner and outer faces togeter.
+ std::vector<int> same_vertices_pos;
+ for (int k = 0; k < 3; k++)
+ for (int l = 0; l < 3; l++) {
+ if (dist(t1.pts[k], t2.pts[l]) < kEpsilon) {
+ same_vertices_count++;
+ same_vertices_pos.push_back(k);
+ same_vertices_pos.push_back(l);
+ }
+ }
+ if (same_vertices_count != 2)
+ continue;
+ // check the order of positions to make sure triangles are on
+ // the same face.
+ int i1 = same_vertices_pos[2] - same_vertices_pos[0];
+ int i2 = same_vertices_pos[3] - same_vertices_pos[1];
+ // if triangles are on different faces.
+ if (!(i1 * i2 == -1 || i1 * i2 == 2 || i1 * i2 == -4))
+ continue;
+
+ Vector3 v12 = t1.pts[1] - t1.pts[0];
+ Vector3 v13 = t1.pts[2] - t1.pts[0];
+ Vector3 n1 = cross(v12, v13);
+ Vector3 v22 = t2.pts[1] - t2.pts[0];
+ Vector3 v23 = t2.pts[2] - t2.pts[0];
+ Vector3 n2 = cross(v22, v23);
+ float iAngle = acos(dot(n1, n2) / (length(n1) * length(n2)));
+ iAngle = iAngle * 180 / kPi;
+ if (iAngle >= threshold) {
+ sharp_edges->push_back(shared_edge);
+ return;
+ }
+ }
+}
+
+// insert edge-triangle pair to edge triangle map.
+void InsertEdgeTrianglePair(const Edge& edge, const Triangle& triangle,
+ std::map<Edge, std::vector<Triangle>>* et_map) {
+ std::map<Edge, std::vector<Triangle>>::iterator iter1 =
+ et_map->find(edge);
+ if (iter1 == et_map->end()) {
+ std::vector<Triangle> same_edge_triangle_list;
+ same_edge_triangle_list.push_back(triangle);
+ et_map->insert(make_pair(edge, same_edge_triangle_list));
+ } else {
+ iter1->second.push_back(triangle);
+ }
+}
+
+NodeInstance* CreateInstanceTree(FCDSceneNode *node) {
+ NodeInstance *instance = new NodeInstance(node);
+ NodeInstance::NodeInstanceList &children = instance->children();
+ for (size_t i = 0; i < node->GetChildrenCount(); ++i) {
+ FCDSceneNode *child_node = node->GetChild(i);
+ NodeInstance *child_instance = CreateInstanceTree(child_node);
+ children.push_back(child_instance);
+ }
+ return instance;
+}
+
+// go through all polygons in geom_instance, and add all sharp edges
+// as a new polygon in geom. And also, add material and effect based
+// on the given sharpEdgeColor option.
+void BuildSharpEdge(FCDocument* doc, FCDGeometryInstance* geom_instance,
+ const Options& options) {
+ FCDGeometry* geom = static_cast<FCDGeometry*>(geom_instance->GetEntity());
+ if (!(geom && geom->IsMesh()))
+ return;
+ FCDGeometryMesh* mesh = geom->GetMesh();
+ FCDGeometryPolygonsTools::Triangulate(mesh);
+ FCDGeometryPolygonsTools::GenerateUniqueIndices(mesh, NULL, NULL);
+
+ size_t num_polygons = mesh->GetPolygonsCount();
+ size_t num_indices = mesh->GetFaceVertexCount();
+ if (num_polygons <= 0 || num_indices <= 0) return;
+ FCDGeometrySource* pos_source =
+ mesh->FindSourceByType(FUDaeGeometryInput::POSITION);
+ if (pos_source == NULL) return;
+ size_t num_vertices = pos_source->GetValueCount();
+ float* pos_source_data = pos_source->GetData();
+ std::vector<Point3> point_list;
+ for (size_t i = 0; i + 2 < num_vertices * 3; i += 3) {
+ Point3 point(pos_source_data[i + 0],
+ pos_source_data[i + 1],
+ pos_source_data[i + 2]);
+ point_list.push_back(point);
+ }
+
+ for (size_t p = 0; p < num_polygons; ++p) {
+ FCDGeometryPolygons* polys = mesh->GetPolygons(p);
+
+ if (polys->GetPrimitiveType() != FCDGeometryPolygons::POLYGONS)
+ continue;
+ FCDGeometryPolygonsInput* input = polys->GetInput(0);
+ size_t size = input->GetIndexCount();
+ if (size == 0) continue;
+ // meshed triangle list.
+ size_t vertices_per_primitive = 3;
+ if (size % vertices_per_primitive != 0) {
+ continue;
+ }
+ uint32* indices = input->GetIndices();
+ size_t indexCount = input->GetIndexCount();
+ // create triangle list.
+ std::vector<Triangle> triangle_list;
+ for (size_t i = 0; i + 2 < indexCount; i += 3) {
+ Triangle triangle(point_list[indices[i + 0]],
+ point_list[indices[i + 1]],
+ point_list[indices[i + 2]],
+ indices[i + 0],
+ indices[i + 1],
+ indices[i + 2]);
+ triangle_list.push_back(triangle);
+ }
+ std::map<Edge, std::vector<Triangle>> edge_triangle_map;
+ for (size_t i = 0; i < triangle_list.size(); i++) {
+ Triangle triangle = triangle_list[i];
+ Edge e1(triangle.pts[0], triangle.pts[1],
+ triangle.indices[0], triangle.indices[1]);
+ Edge e2(triangle.pts[1], triangle.pts[2],
+ triangle.indices[1], triangle.indices[2]);
+ Edge e3(triangle.pts[0], triangle.pts[2],
+ triangle.indices[0], triangle.indices[2]);
+ InsertEdgeTrianglePair(e1, triangle, &edge_triangle_map);
+ InsertEdgeTrianglePair(e2, triangle, &edge_triangle_map);
+ InsertEdgeTrianglePair(e3, triangle, &edge_triangle_map);
+ }
+ // go through the edge-triangle map.
+ std::map<Edge, std::vector<Triangle>>::iterator iter;
+ std::vector<Edge> sharp_edges;
+ for (iter = edge_triangle_map.begin();
+ iter != edge_triangle_map.end(); iter++) {
+ if (iter->second.size() < 2)
+ continue;
+ CheckSharpEdge(iter->first, iter->second, &sharp_edges,
+ options.soften_edge_threshold);
+ }
+ if (sharp_edges.size() > 0) {
+ FCDGeometryPolygons* edge_polys = mesh->AddPolygons();
+ edge_polys->AddFaceVertexCount(sharp_edges.size() * 2);
+ edge_polys->SetPrimitiveType(FCDGeometryPolygons::LINES);
+ FCDGeometrySource* vertex_source = mesh->GetVertexSource(0);
+ FCDGeometryPolygonsInput* edge_input =
+ edge_polys->AddInput(vertex_source, 0);
+ FUDaeGeometryInput::Semantic semantic = edge_input->GetSemantic();
+ if (edge_input == NULL)
+ return;
+ FCDGeometrySource* edge_source = edge_input->GetSource();
+ if (edge_source == NULL)
+ return;
+ for (size_t i = 0; i < sharp_edges.size(); i++) {
+ edge_input->AddIndex(sharp_edges[i].indices[0]);
+ edge_input->AddIndex(sharp_edges[i].indices[1]);
+ }
+ edge_input->SetIndexCount(sharp_edges.size() * 2);
+ edge_input->SetOffset(0);
+
+ if (edge_material == NULL) {
+ // add material to material lib.
+ FCDMaterialLibrary* material_library = doc->GetMaterialLibrary();
+ FCDEffectLibrary* effect_library = doc->GetEffectLibrary();
+ edge_material =
+ static_cast<FCDMaterial*>(material_library->AddEntity());
+ edge_material->SetDaeId("o3d_hard_edge_materialID");
+ edge_material->SetName(L"o3d_hard_edge_material");
+ edge_effect = static_cast<FCDEffect*>(effect_library->AddEntity());
+ edge_effect->SetDaeId("o3d_hard_edge_effectID");
+ edge_effect->SetName(L"o3d_hard_edge_effect");
+ if (edge_effect == NULL || edge_material == NULL)
+ return;
+ edge_material->SetEffect(edge_effect);
+ FCDEffectStandard* edge_effect_profile =
+ static_cast<FCDEffectStandard*>(edge_effect->AddProfile(
+ FUDaeProfileType::COMMON));
+ edge_effect_profile->SetLightingType(FCDEffectStandard::LAMBERT);
+ edge_effect_profile->
+ SetEmissionColor(FMVector4(options.sharp_edge_color.getX(),
+ options.sharp_edge_color.getY(),
+ options.sharp_edge_color.getZ(), 1));
+ }
+ // add material instance to visual scenes lib.
+ FCDMaterialInstance* edge_material_instance =
+ geom_instance->AddMaterialInstance(edge_material, edge_polys);
+ edge_material_instance->SetSemantic(L"o3d_hard_edge_material");
+ edge_polys->SetMaterialSemantic(L"o3d_hard_edge_material");
+ }
+ }
+}
+
+// go through the collada tree and import instance. if found a
+// geometry instance, call BuildSharpEdge function.
+bool ImportTreeInstances(FCDocument* doc,
+ NodeInstance *node_instance,
+ const Options& options) {
+ FCDSceneNode *node = node_instance->node();
+ // recursively import the rest of the nodes in the tree
+ const NodeInstance::NodeInstanceList &children = node_instance->children();
+ for (size_t i = 0; i < children.size(); ++i) {
+ if (!ImportTreeInstances(doc, children[i], options)) {
+ return false;
+ }
+ }
+ for (size_t i = 0; i < node->GetInstanceCount(); ++i) {
+ FCDEntityInstance* instance = node->GetInstance(i);
+ FCDCamera* camera(NULL);
+ FCDGeometryInstance* geom_instance(NULL);
+ FCDMaterialInstance* mat_instance(NULL);
+ // Import each node based on what kind of entity it is
+ switch (instance->GetEntityType()) {
+ case FCDEntity::GEOMETRY: {
+ // geometry entity
+ geom_instance = static_cast<FCDGeometryInstance*>(instance);
+ BuildSharpEdge(doc, geom_instance, options);
+ break;
+ }
+ case FCDEntity::CAMERA:
+ case FCDEntity::CONTROLLER:
+ default: break;
+ }
+ }
+ return true;
+}
+
+bool ConditionDoc(FCDocument* doc, const Options& options) {
+ // The root of the instance node tree.
+ NodeInstance* instance_root_;
+ bool status = false;
+ // Import the scene objects, starting at the root.
+ FCDSceneNode* scene = doc->GetVisualSceneInstance();
+ if (scene) {
+ instance_root_ = CreateInstanceTree(scene);
+ if (ImportTreeInstances(doc, instance_root_, options)) {
+ status = true;
+ }
+ delete instance_root_;
+ }
+ return status;
+}
+
+bool Condition(const wchar_t* in_filename, const wchar_t* out_filename,
+ const Options& options) {
+ FCollada::Initialize();
+ FCDocument* doc = FCollada::NewTopDocument();
+ bool retval = false;
+ if (doc) {
+ // Load and parse the COLLADA file.
+ if (FCollada::LoadDocumentFromFile(doc, in_filename)) {
+ doc->SetFileUrl(out_filename);
+
+ // condition it.
+ retval = ConditionDoc(doc, options);
+ if (retval) {
+ FCollada::SaveDocument(doc, out_filename);
+ }
+ } else {
+ printf("Error: couldn't open the input file.\n");
+ }
+ doc->Release();
+ } else {
+ printf("Internal error: Couldn't create FCollada document.\n");
+ }
+ FCollada::Release();
+ return retval;
} \ No newline at end of file
diff --git a/o3d/collada_edge/cross/conditioner.h b/o3d/collada_edge/cross/conditioner.h
index b622610..57c61fabee 100644
--- a/o3d/collada_edge/cross/conditioner.h
+++ b/o3d/collada_edge/cross/conditioner.h
@@ -1,121 +1,121 @@
-/*
- * 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.
- */
+/*
+ * 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.
+ */
#ifndef O3D_COLLADA_EDGE_CONDITIONER_H_
-#define O3D_COLLADA_EDGE_CONDITIONER_H_
-
-#include <vector>
-#include "utility.h"
-
-struct Options {
- // default constructor.
- Options()
- : enable_soften_edge(false),
- soften_edge_threshold(0),
- sharp_edge_color(1, 0, 0) {}
-
- // Add edges with dihedral angle larger than soften_edge_threshold.
- bool enable_soften_edge;
-
- // The threshold of normal angle of edges, if angle of certain
- // edge is larger than this threshold, it will be added into
- // the output file.
- float soften_edge_threshold;
-
- // Color of extra edges.
- Vector3 sharp_edge_color;
-};
-
-// This takes ownership of its children NodeInstances.
-class NodeInstance {
- public:
- typedef std::vector<NodeInstance *> NodeInstanceList;
-
- explicit NodeInstance(FCDSceneNode *node) : node_(node) {}
- ~NodeInstance() {
- for (unsigned int i = 0; i < children_.size(); ++i) {
- delete children_[i];
- }
- }
-
- // Gets the Collada node associated with this node instance.
- FCDSceneNode *node() const { return node_; }
-
- // Gets the list of this node instance's children.
- NodeInstanceList &children() { return children_; }
-
- // Finds the NodeInstance representing a scene node in the direct
- // children of this NodeInstance.
- NodeInstance *FindNodeShallow(FCDSceneNode *node) {
- for (unsigned int i = 0; i < children_.size(); ++i) {
- NodeInstance *child = children_[i];
- if (child->node() == node) return child;
- }
- return NULL;
- }
-
- // Finds the NodeInstance representing a scene node in the sub-tree
- // starting at this NodeInstance.
- NodeInstance *FindNodeInTree(FCDSceneNode *node);
-
- private:
- FCDSceneNode *node_;
- std::vector<NodeInstance *> children_;
-};
-
-// Edge class is used in detect sharp edge process. It stores two points
-// in a specific order, and it serves as key class in edge-triangle map.
-struct Edge {
- Edge(Point3 p1, Point3 p2, uint32 i1, uint32 i2);
- std::vector<Point3> pts;
- std::vector<uint32> indices;
-};
-
-// Triangle class is used in detect sharp edge process.
-struct Triangle {
- Triangle(Point3 p1, Point3 p2, Point3 p3,
- uint32 i1, uint32 i2, uint32 i3) {
- pts.push_back(p1);
- pts.push_back(p2);
- pts.push_back(p3);
- indices.push_back(i1);
- indices.push_back(i2);
- indices.push_back(i3);
- }
- std::vector<Point3> pts;
- std::vector<uint32> indices;
-};
-
-// Conditions the given file to emphasize the sharp edges.
-// Returns false on failure, and writes the relevant erros to stderr.
-bool Condition(const wchar_t* in_filename, const wchar_t* out_filename,
- const Options& options);
-
+#define O3D_COLLADA_EDGE_CONDITIONER_H_
+
+#include <vector>
+#include "utility.h"
+
+struct Options {
+ // default constructor.
+ Options()
+ : enable_soften_edge(false),
+ soften_edge_threshold(0),
+ sharp_edge_color(1, 0, 0) {}
+
+ // Add edges with dihedral angle larger than soften_edge_threshold.
+ bool enable_soften_edge;
+
+ // The threshold of normal angle of edges, if angle of certain
+ // edge is larger than this threshold, it will be added into
+ // the output file.
+ float soften_edge_threshold;
+
+ // Color of extra edges.
+ Vector3 sharp_edge_color;
+};
+
+// This takes ownership of its children NodeInstances.
+class NodeInstance {
+ public:
+ typedef std::vector<NodeInstance *> NodeInstanceList;
+
+ explicit NodeInstance(FCDSceneNode *node) : node_(node) {}
+ ~NodeInstance() {
+ for (unsigned int i = 0; i < children_.size(); ++i) {
+ delete children_[i];
+ }
+ }
+
+ // Gets the Collada node associated with this node instance.
+ FCDSceneNode *node() const { return node_; }
+
+ // Gets the list of this node instance's children.
+ NodeInstanceList &children() { return children_; }
+
+ // Finds the NodeInstance representing a scene node in the direct
+ // children of this NodeInstance.
+ NodeInstance *FindNodeShallow(FCDSceneNode *node) {
+ for (unsigned int i = 0; i < children_.size(); ++i) {
+ NodeInstance *child = children_[i];
+ if (child->node() == node) return child;
+ }
+ return NULL;
+ }
+
+ // Finds the NodeInstance representing a scene node in the sub-tree
+ // starting at this NodeInstance.
+ NodeInstance *FindNodeInTree(FCDSceneNode *node);
+
+ private:
+ FCDSceneNode *node_;
+ std::vector<NodeInstance *> children_;
+};
+
+// Edge class is used in detect sharp edge process. It stores two points
+// in a specific order, and it serves as key class in edge-triangle map.
+struct Edge {
+ Edge(Point3 p1, Point3 p2, uint32 i1, uint32 i2);
+ std::vector<Point3> pts;
+ std::vector<uint32> indices;
+};
+
+// Triangle class is used in detect sharp edge process.
+struct Triangle {
+ Triangle(Point3 p1, Point3 p2, Point3 p3,
+ uint32 i1, uint32 i2, uint32 i3) {
+ pts.push_back(p1);
+ pts.push_back(p2);
+ pts.push_back(p3);
+ indices.push_back(i1);
+ indices.push_back(i2);
+ indices.push_back(i3);
+ }
+ std::vector<Point3> pts;
+ std::vector<uint32> indices;
+};
+
+// Conditions the given file to emphasize the sharp edges.
+// Returns false on failure, and writes the relevant erros to stderr.
+bool Condition(const wchar_t* in_filename, const wchar_t* out_filename,
+ const Options& options);
+
#endif \ No newline at end of file
diff --git a/o3d/collada_edge/cross/precompile.h b/o3d/collada_edge/cross/precompile.h
index e5d1b51..e062271 100644
--- a/o3d/collada_edge/cross/precompile.h
+++ b/o3d/collada_edge/cross/precompile.h
@@ -1,54 +1,54 @@
-/*
- * 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.
- */
-
+/*
+ * 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.
+ */
+
#ifndef O3D_COLLADA_EDGE_PRECOMPILE_H_
-#define O3D_COLLADA_EDGE_PRECOMPILE_H_
-
-#include <stdio.h>
-#include <tchar.h>
-
-#include "FCollada.h"
-#include "FCDocument/FCDocument.h"
-#include "FCDocument/FCDEffect.h"
-#include "FCDocument/FCDEffectStandard.h"
-#include "FCDocument/FCDSceneNode.h"
-#include "FCDocument/FCDGeometry.h"
-#include "FCDocument/FCDGeometryInstance.h"
-#include "FCDocument/FCDGeometryMesh.h"
-#include "FCDocument/FCDGeometryPolygons.h"
-#include "FCDocument/FCDGeometryPolygonsInput.h"
-#include "FCDocument/FCDGeometryPolygonsTools.h"
-#include "FCDocument/FCDGeometrySource.h"
-#include "FCDocument/FCDLibrary.h"
-#include "FCDocument/FCDMaterial.h"
-#include "FCDocument/FCDMaterialInstance.h"
-
+#define O3D_COLLADA_EDGE_PRECOMPILE_H_
+
+#include <stdio.h>
+#include <tchar.h>
+
+#include "FCollada.h"
+#include "FCDocument/FCDocument.h"
+#include "FCDocument/FCDEffect.h"
+#include "FCDocument/FCDEffectStandard.h"
+#include "FCDocument/FCDSceneNode.h"
+#include "FCDocument/FCDGeometry.h"
+#include "FCDocument/FCDGeometryInstance.h"
+#include "FCDocument/FCDGeometryMesh.h"
+#include "FCDocument/FCDGeometryPolygons.h"
+#include "FCDocument/FCDGeometryPolygonsInput.h"
+#include "FCDocument/FCDGeometryPolygonsTools.h"
+#include "FCDocument/FCDGeometrySource.h"
+#include "FCDocument/FCDLibrary.h"
+#include "FCDocument/FCDMaterial.h"
+#include "FCDocument/FCDMaterialInstance.h"
+
#endif \ No newline at end of file
diff --git a/o3d/collada_edge/cross/utility.h b/o3d/collada_edge/cross/utility.h
index 2345338..6fe1bc7 100644
--- a/o3d/collada_edge/cross/utility.h
+++ b/o3d/collada_edge/cross/utility.h
@@ -1,45 +1,45 @@
-/*
- * 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.
- */
-
+/*
+ * 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.
+ */
+
#ifndef O3D_COLLADA_EDGE_UTILITY_H_
-#define O3D_COLLADA_EDGE_UTILITY_H_
-
-#include "..\vectormath\vectormathlibrary\include\vectormath\scalar\cpp\vectormath_aos.h" // NOLINT"
-
-// Point
-//
-typedef Vectormath::Aos::Point3 Point3;
-
-// 3d-vector
-//
-typedef Vectormath::Aos::Vector3 Vector3;
-
+#define O3D_COLLADA_EDGE_UTILITY_H_
+
+#include "..\vectormath\vectormathlibrary\include\vectormath\scalar\cpp\vectormath_aos.h" // NOLINT"
+
+// Point
+//
+typedef Vectormath::Aos::Point3 Point3;
+
+// 3d-vector
+//
+typedef Vectormath::Aos::Vector3 Vector3;
+
#endif \ No newline at end of file
diff --git a/o3d/core/cross/bitmap.h b/o3d/core/cross/bitmap.h
index 9b375bd..96e9b7b 100644
--- a/o3d/core/cross/bitmap.h
+++ b/o3d/core/cross/bitmap.h
@@ -1,404 +1,404 @@
-/*
- * 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 contains the declaration of Bitmap helper class that can load
-// raw 24- and 32-bit bitmaps from popular image formats. The Bitmap class
-// also interprets the file format to record the correct OpenGL buffer format.
-//
-// Trying to keep this class independent from the OpenGL API in case they
-// need retargeting later on.
-
-#ifndef O3D_CORE_CROSS_BITMAP_H_
-#define O3D_CORE_CROSS_BITMAP_H_
-
-#include <stdlib.h>
-#include <vector>
-#include "base/cross/bits.h"
-#include "core/cross/types.h"
-#include "core/cross/texture_base.h"
-#include "core/cross/image_utils.h"
-
-class FilePath;
-
-namespace o3d {
-
-class MemoryReadStream;
-class RawData;
-class Pack;
-
-// Bitmap provides an API for basic image operations on bitmap images,
-// including scale and crop. Bitmaps can be created from a RawData object via
-// LoadFromRawData(), and also can be transfered to mips of a Texure2D or a
-// specific face of TextureCUBE via methods in Texture.
-
-class Bitmap : public ParamObject {
- public:
- typedef SmartPointer<Bitmap> Ref;
- typedef std::vector<Bitmap::Ref> BitmapRefArray;
-
- explicit Bitmap(ServiceLocator* service_locator);
- virtual ~Bitmap() {}
-
- enum Semantic {
- FACE_POSITIVE_X, // NOTE: These must match TextureCUBE::CubeFace
- FACE_NEGATIVE_X,
- FACE_POSITIVE_Y,
- FACE_NEGATIVE_Y,
- FACE_POSITIVE_Z,
- FACE_NEGATIVE_Z,
- IMAGE, // normal 2d image
- SLICE, // a slice of a 3d texture.
- };
-
- // Returns the pitch of the bitmap for a certain level.
- int GetMipPitch(int level) const {
- return image::ComputeMipPitch(format(), level, width());
- }
-
- // Creates a copy of a bitmap, copying the pixels as well.
- // Parameters:
- // source: the source bitmap.
- void CopyDeepFrom(const Bitmap &source) {
- Allocate(source.format_, source.width_, source.height_,
- source.num_mipmaps_, source.semantic_);
- memcpy(image_data(), source.image_data(), GetTotalSize());
- }
-
- // Sets the bitmap parameters from another bitmap, stealing the pixel buffer
- // from the source bitmap.
- // Parameters:
- // source: the source bitmap.
- void SetFrom(Bitmap *source);
-
- // Allocates an uninitialized bitmap with specified parameters.
- // Parameters:
- // format: the format of the pixels.
- // width: the width of the base image.
- // height: the height of the base image.
- // num_mipmaps: the number of mip-maps.
- void Allocate(Texture::Format format,
- unsigned int width,
- unsigned int height,
- unsigned int num_mipmaps,
- Semantic semantic);
-
- // Allocates a bitmap with initialized parameters.
- // data is zero-initialized
- void AllocateData() {
- image_data_.reset(new uint8[GetTotalSize()]);
- memset(image_data_.get(), 0, GetTotalSize());
- }
-
- // Frees the data owned by the bitmap.
- void FreeData() {
- image_data_.reset(NULL);
- }
-
- // Sets a rectangular region of this bitmap.
- // If the bitmap is a DXT format, the only acceptable values
- // for left, top, width and height are 0, 0, bitmap->width, bitmap->height
- //
- // Parameters:
- // level: The mipmap level to modify
- // dst_left: The left edge of the rectangular area to modify.
- // dst_top: The top edge of the rectangular area to modify.
- // width: The width of the rectangular area to modify.
- // height: The of the rectangular area to modify.
- // src_data: The source pixels.
- // src_pitch: If the format is uncompressed this is the number of bytes
- // per row of pixels. If compressed this value is unused.
- void SetRect(int level,
- unsigned dst_left,
- unsigned dst_top,
- unsigned width,
- unsigned height,
- const void* src_data,
- int src_pitch);
-
- // Gets the image data for a given mip-map level.
- // Parameters:
- // level: mip level to get.
- uint8 *GetMipData(unsigned int level) const;
-
- // Gets the address of a particular pixel.
- // Parameters:
- // level: mip level to get.
- uint8 *GetPixelData(unsigned int level, unsigned int x, unsigned int y) const;
-
- // Gets the size of mip.
- size_t GetMipSize(unsigned int level) const;
-
- uint8 *image_data() const { return image_data_.get(); }
- Texture::Format format() const { return format_; }
- unsigned int width() const { return width_; }
- unsigned int height() const { return height_; }
- unsigned int num_mipmaps() const { return num_mipmaps_; }
- Semantic semantic() const {
- return semantic_;
- }
-
- // Returns whether or not the dimensions of the bitmap are power-of-two.
- bool IsPOT() const {
- return image::IsPOT(width_, height_);
- }
-
- // Loads a bitmap from a file.
- // Parameters:
- // filename: the name of the file to load.
- // file_type: the type of file to load. If UNKNOWN, the file type will be
- // determined from the filename extension, and if it is not a
- // known extension, all the loaders will be tried.
- // bitmaps: An array to hold references to the loaded bitmaps.
- static bool LoadFromFile(ServiceLocator* service_locator,
- const FilePath &filepath,
- image::ImageFileType file_type,
- BitmapRefArray* bitmaps);
-
- // Loads a bitmap from a RawData object.
- // Parameters:
- // raw_data: contains the bitmap data in one of the known formats
- // file_type: the format of the bitmap data. If UNKNOWN, the file type
- // will be determined from the extension from raw_data's uri
- // and if it is not a known extension, all the loaders will
- // be tried.
- // bitmaps: An array to hold references to the loaded bitmaps.
- static bool LoadFromRawData(RawData *raw_data,
- image::ImageFileType file_type,
- BitmapRefArray* bitmaps);
-
- // Flips a bitmap vertically in place.
- // This is needed instead of just using DrawImage because flipping DXT formats
- // using generic algorithms would be lossy and extremely slow to reconvert
- // from a flippable format back to a DXT format.
- void FlipVertically();
-
- // Returns the contents of the bitmap as a data URL
- // Returns:
- // A data url that represents the content of the bitmap.
- String ToDataURL();
-
- // Checks that the alpha channel for the entire bitmap is 1.0
- bool CheckAlphaIsOne() const;
-
- // Copy pixels from source bitmap. Scales if the width and height of source
- // and dest do not match.
- // Parameters:
- // source_img: source bitmap which would be drawn.
- // source_level: level to draw.
- // source_x: x-coordinate of the starting pixel in the source image.
- // source_x: y-coordinate of the starting pixel in the source image.
- // source_width: width of the source image to draw.
- // source_height: Height of the source image to draw.
- // dest_level: level to target.
- // dest_x: x-coordinate of the starting pixel in the dest image.
- // dest_y: y-coordinate of the starting pixel in the dest image.
- // dest_width: width of the dest image to draw.
- // dest_height: height of the dest image to draw.
- void DrawImage(const Bitmap& source_img, int source_level,
- int source_x, int source_y,
- int source_width, int source_height,
- int dest_level,
- int dest_x, int dest_y,
- int dest_width, int dest_height);
-
- // Gets the size of the buffer containing a mip-map chain, given a number of
- // mip-map levels.
- size_t GetMipChainSize(unsigned int num_mipmaps) const {
- return image::ComputeMipChainSize(width(), height(), format(), num_mipmaps);
- }
-
- // Generates Mips from the source_level for num_levels
- void GenerateMips(int source_level, int num_levels);
-
- private:
- friend class IClassManager;
- static ObjectBase::Ref Create(ServiceLocator* service_locator);
-
- // Sets the contents of a Bitmap replacing any previous contents.
- // Parameters:
- // format: Format of the bitmap.
- // num_mipmaps: The number of mipmaps.
- // width: width in pixels.
- // height: height in pixels.
- // semantic: the semantic of the bitmap
- // image_data: The image data. The bitmap will take ownership of this data.
- void SetContents(Texture::Format format,
- unsigned int num_mipmaps,
- unsigned int width,
- unsigned int height,
- Semantic semantic,
- scoped_array<uint8>* image_data);
-
- // Loads bitmaps from a MemoryReadStream.
- // Parameters:
- // stream: a stream for the bitmap data in one of the known formats
- // filename: a filename (or uri) of the original bitmap data
- // (may be an empty string)
- // file_type: the format of the bitmap data. If UNKNOWN, the file type
- // will be determined from the extension of |filename|
- // and if it is not a known extension, all the loaders
- // will be tried.
- // bitmaps: An array to hold references to the loaded bitmaps.
- static bool LoadFromStream(ServiceLocator* service_locator,
- MemoryReadStream *stream,
- const String &filename,
- image::ImageFileType file_type,
- BitmapRefArray* bitmaps);
-
- static bool LoadFromPNGStream(ServiceLocator* service_locator,
- MemoryReadStream *stream,
- const String &filename,
- BitmapRefArray* bitmaps);
-
- static bool LoadFromTGAStream(ServiceLocator* service_locator,
- MemoryReadStream *stream,
- const String &filename,
- BitmapRefArray* bitmaps);
-
- static bool LoadFromDDSStream(ServiceLocator* service_locator,
- MemoryReadStream *stream,
- const String &filename,
- BitmapRefArray* bitmaps);
-
- static bool LoadFromJPEGStream(ServiceLocator* service_locator,
- MemoryReadStream *stream,
- const String &filename,
- BitmapRefArray* bitmaps);
-
- bool GenerateMipmaps(unsigned int base_width,
- unsigned int base_height,
- Texture::Format format,
- unsigned int num_mipmaps,
- uint8 *data);
-
- // Gets the total size of the bitmap data, counting all faces and mip levels.
- size_t GetTotalSize() const {
- return GetMipChainSize(image::ComputeMipMapCount(width_, height_));
- }
-
- static size_t ComputeMaxSize(
- unsigned width, unsigned height, Texture::Format format);
-
- // pointer to the raw bitmap data
- // NOTE: image_data_ is either NULL or it has space for the maximum number
- // of mips for the current size bitmap, even if they are not used.
- scoped_array<uint8> image_data_;
- // format of the texture this is meant to represent.
- Texture::Format format_;
- // width of the bitmap in pixels.
- int width_;
- // height of the bitmap in pixels.
- int height_;
- // number of valid mipmap levels in this bitmap.
- unsigned int num_mipmaps_;
- // The purpose of the bitmap
- Semantic semantic_;
-
- O3D_DECL_CLASS(Bitmap, ParamObject);
- DISALLOW_COPY_AND_ASSIGN(Bitmap);
-};
-
-typedef Bitmap::BitmapRefArray BitmapRefArray;
-
-class BitmapUncompressed : public Bitmap {
- public:
- explicit BitmapUncompressed(ServiceLocator* service_locator);
-};
-
-template <typename T>
-class TypedBitmapUncompressed : public BitmapUncompressed {
- public:
- typedef T ComponentType;
- explicit TypedBitmapUncompressed(ServiceLocator* service_locator)
- : BitmapUncompressed(service_locator) {
- }
-};
-
-class Bitmap8 : public TypedBitmapUncompressed<uint8> {
- public:
- explicit Bitmap8(ServiceLocator* service_locator);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Bitmap8);
-};
-
-class Bitmap16F : public TypedBitmapUncompressed<uint16> {
- public:
- explicit Bitmap16F(ServiceLocator* service_locator);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Bitmap16F);
-};
-
-class Bitmap32F : public TypedBitmapUncompressed<float> {
- public:
- explicit Bitmap32F(ServiceLocator* service_locator);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Bitmap32F);
-};
-
-class BitmapCompressed : public Bitmap {
- public:
- explicit BitmapCompressed(ServiceLocator* service_locator);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(BitmapCompressed);
-};
-
-class BitmapDXT1 : public BitmapCompressed {
- public:
- explicit BitmapDXT1(ServiceLocator* service_locator);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(BitmapDXT1);
-};
-
-class BitmapDXT3 : public BitmapCompressed {
- public:
- explicit BitmapDXT3(ServiceLocator* service_locator);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(BitmapDXT3);
-};
-
-class BitmapDXT5 : public BitmapCompressed {
- public:
- explicit BitmapDXT5(ServiceLocator* service_locator);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(BitmapDXT5);
-};
-
-} // namespace o3d
-
-#endif // O3D_CORE_CROSS_BITMAP_H_
+/*
+ * 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 contains the declaration of Bitmap helper class that can load
+// raw 24- and 32-bit bitmaps from popular image formats. The Bitmap class
+// also interprets the file format to record the correct OpenGL buffer format.
+//
+// Trying to keep this class independent from the OpenGL API in case they
+// need retargeting later on.
+
+#ifndef O3D_CORE_CROSS_BITMAP_H_
+#define O3D_CORE_CROSS_BITMAP_H_
+
+#include <stdlib.h>
+#include <vector>
+#include "base/cross/bits.h"
+#include "core/cross/types.h"
+#include "core/cross/texture_base.h"
+#include "core/cross/image_utils.h"
+
+class FilePath;
+
+namespace o3d {
+
+class MemoryReadStream;
+class RawData;
+class Pack;
+
+// Bitmap provides an API for basic image operations on bitmap images,
+// including scale and crop. Bitmaps can be created from a RawData object via
+// LoadFromRawData(), and also can be transfered to mips of a Texure2D or a
+// specific face of TextureCUBE via methods in Texture.
+
+class Bitmap : public ParamObject {
+ public:
+ typedef SmartPointer<Bitmap> Ref;
+ typedef std::vector<Bitmap::Ref> BitmapRefArray;
+
+ explicit Bitmap(ServiceLocator* service_locator);
+ virtual ~Bitmap() {}
+
+ enum Semantic {
+ FACE_POSITIVE_X, // NOTE: These must match TextureCUBE::CubeFace
+ FACE_NEGATIVE_X,
+ FACE_POSITIVE_Y,
+ FACE_NEGATIVE_Y,
+ FACE_POSITIVE_Z,
+ FACE_NEGATIVE_Z,
+ IMAGE, // normal 2d image
+ SLICE, // a slice of a 3d texture.
+ };
+
+ // Returns the pitch of the bitmap for a certain level.
+ int GetMipPitch(int level) const {
+ return image::ComputeMipPitch(format(), level, width());
+ }
+
+ // Creates a copy of a bitmap, copying the pixels as well.
+ // Parameters:
+ // source: the source bitmap.
+ void CopyDeepFrom(const Bitmap &source) {
+ Allocate(source.format_, source.width_, source.height_,
+ source.num_mipmaps_, source.semantic_);
+ memcpy(image_data(), source.image_data(), GetTotalSize());
+ }
+
+ // Sets the bitmap parameters from another bitmap, stealing the pixel buffer
+ // from the source bitmap.
+ // Parameters:
+ // source: the source bitmap.
+ void SetFrom(Bitmap *source);
+
+ // Allocates an uninitialized bitmap with specified parameters.
+ // Parameters:
+ // format: the format of the pixels.
+ // width: the width of the base image.
+ // height: the height of the base image.
+ // num_mipmaps: the number of mip-maps.
+ void Allocate(Texture::Format format,
+ unsigned int width,
+ unsigned int height,
+ unsigned int num_mipmaps,
+ Semantic semantic);
+
+ // Allocates a bitmap with initialized parameters.
+ // data is zero-initialized
+ void AllocateData() {
+ image_data_.reset(new uint8[GetTotalSize()]);
+ memset(image_data_.get(), 0, GetTotalSize());
+ }
+
+ // Frees the data owned by the bitmap.
+ void FreeData() {
+ image_data_.reset(NULL);
+ }
+
+ // Sets a rectangular region of this bitmap.
+ // If the bitmap is a DXT format, the only acceptable values
+ // for left, top, width and height are 0, 0, bitmap->width, bitmap->height
+ //
+ // Parameters:
+ // level: The mipmap level to modify
+ // dst_left: The left edge of the rectangular area to modify.
+ // dst_top: The top edge of the rectangular area to modify.
+ // width: The width of the rectangular area to modify.
+ // height: The of the rectangular area to modify.
+ // src_data: The source pixels.
+ // src_pitch: If the format is uncompressed this is the number of bytes
+ // per row of pixels. If compressed this value is unused.
+ void SetRect(int level,
+ unsigned dst_left,
+ unsigned dst_top,
+ unsigned width,
+ unsigned height,
+ const void* src_data,
+ int src_pitch);
+
+ // Gets the image data for a given mip-map level.
+ // Parameters:
+ // level: mip level to get.
+ uint8 *GetMipData(unsigned int level) const;
+
+ // Gets the address of a particular pixel.
+ // Parameters:
+ // level: mip level to get.
+ uint8 *GetPixelData(unsigned int level, unsigned int x, unsigned int y) const;
+
+ // Gets the size of mip.
+ size_t GetMipSize(unsigned int level) const;
+
+ uint8 *image_data() const { return image_data_.get(); }
+ Texture::Format format() const { return format_; }
+ unsigned int width() const { return width_; }
+ unsigned int height() const { return height_; }
+ unsigned int num_mipmaps() const { return num_mipmaps_; }
+ Semantic semantic() const {
+ return semantic_;
+ }
+
+ // Returns whether or not the dimensions of the bitmap are power-of-two.
+ bool IsPOT() const {
+ return image::IsPOT(width_, height_);
+ }
+
+ // Loads a bitmap from a file.
+ // Parameters:
+ // filename: the name of the file to load.
+ // file_type: the type of file to load. If UNKNOWN, the file type will be
+ // determined from the filename extension, and if it is not a
+ // known extension, all the loaders will be tried.
+ // bitmaps: An array to hold references to the loaded bitmaps.
+ static bool LoadFromFile(ServiceLocator* service_locator,
+ const FilePath &filepath,
+ image::ImageFileType file_type,
+ BitmapRefArray* bitmaps);
+
+ // Loads a bitmap from a RawData object.
+ // Parameters:
+ // raw_data: contains the bitmap data in one of the known formats
+ // file_type: the format of the bitmap data. If UNKNOWN, the file type
+ // will be determined from the extension from raw_data's uri
+ // and if it is not a known extension, all the loaders will
+ // be tried.
+ // bitmaps: An array to hold references to the loaded bitmaps.
+ static bool LoadFromRawData(RawData *raw_data,
+ image::ImageFileType file_type,
+ BitmapRefArray* bitmaps);
+
+ // Flips a bitmap vertically in place.
+ // This is needed instead of just using DrawImage because flipping DXT formats
+ // using generic algorithms would be lossy and extremely slow to reconvert
+ // from a flippable format back to a DXT format.
+ void FlipVertically();
+
+ // Returns the contents of the bitmap as a data URL
+ // Returns:
+ // A data url that represents the content of the bitmap.
+ String ToDataURL();
+
+ // Checks that the alpha channel for the entire bitmap is 1.0
+ bool CheckAlphaIsOne() const;
+
+ // Copy pixels from source bitmap. Scales if the width and height of source
+ // and dest do not match.
+ // Parameters:
+ // source_img: source bitmap which would be drawn.
+ // source_level: level to draw.
+ // source_x: x-coordinate of the starting pixel in the source image.
+ // source_x: y-coordinate of the starting pixel in the source image.
+ // source_width: width of the source image to draw.
+ // source_height: Height of the source image to draw.
+ // dest_level: level to target.
+ // dest_x: x-coordinate of the starting pixel in the dest image.
+ // dest_y: y-coordinate of the starting pixel in the dest image.
+ // dest_width: width of the dest image to draw.
+ // dest_height: height of the dest image to draw.
+ void DrawImage(const Bitmap& source_img, int source_level,
+ int source_x, int source_y,
+ int source_width, int source_height,
+ int dest_level,
+ int dest_x, int dest_y,
+ int dest_width, int dest_height);
+
+ // Gets the size of the buffer containing a mip-map chain, given a number of
+ // mip-map levels.
+ size_t GetMipChainSize(unsigned int num_mipmaps) const {
+ return image::ComputeMipChainSize(width(), height(), format(), num_mipmaps);
+ }
+
+ // Generates Mips from the source_level for num_levels
+ void GenerateMips(int source_level, int num_levels);
+
+ private:
+ friend class IClassManager;
+ static ObjectBase::Ref Create(ServiceLocator* service_locator);
+
+ // Sets the contents of a Bitmap replacing any previous contents.
+ // Parameters:
+ // format: Format of the bitmap.
+ // num_mipmaps: The number of mipmaps.
+ // width: width in pixels.
+ // height: height in pixels.
+ // semantic: the semantic of the bitmap
+ // image_data: The image data. The bitmap will take ownership of this data.
+ void SetContents(Texture::Format format,
+ unsigned int num_mipmaps,
+ unsigned int width,
+ unsigned int height,
+ Semantic semantic,
+ scoped_array<uint8>* image_data);
+
+ // Loads bitmaps from a MemoryReadStream.
+ // Parameters:
+ // stream: a stream for the bitmap data in one of the known formats
+ // filename: a filename (or uri) of the original bitmap data
+ // (may be an empty string)
+ // file_type: the format of the bitmap data. If UNKNOWN, the file type
+ // will be determined from the extension of |filename|
+ // and if it is not a known extension, all the loaders
+ // will be tried.
+ // bitmaps: An array to hold references to the loaded bitmaps.
+ static bool LoadFromStream(ServiceLocator* service_locator,
+ MemoryReadStream *stream,
+ const String &filename,
+ image::ImageFileType file_type,
+ BitmapRefArray* bitmaps);
+
+ static bool LoadFromPNGStream(ServiceLocator* service_locator,
+ MemoryReadStream *stream,
+ const String &filename,
+ BitmapRefArray* bitmaps);
+
+ static bool LoadFromTGAStream(ServiceLocator* service_locator,
+ MemoryReadStream *stream,
+ const String &filename,
+ BitmapRefArray* bitmaps);
+
+ static bool LoadFromDDSStream(ServiceLocator* service_locator,
+ MemoryReadStream *stream,
+ const String &filename,
+ BitmapRefArray* bitmaps);
+
+ static bool LoadFromJPEGStream(ServiceLocator* service_locator,
+ MemoryReadStream *stream,
+ const String &filename,
+ BitmapRefArray* bitmaps);
+
+ bool GenerateMipmaps(unsigned int base_width,
+ unsigned int base_height,
+ Texture::Format format,
+ unsigned int num_mipmaps,
+ uint8 *data);
+
+ // Gets the total size of the bitmap data, counting all faces and mip levels.
+ size_t GetTotalSize() const {
+ return GetMipChainSize(image::ComputeMipMapCount(width_, height_));
+ }
+
+ static size_t ComputeMaxSize(
+ unsigned width, unsigned height, Texture::Format format);
+
+ // pointer to the raw bitmap data
+ // NOTE: image_data_ is either NULL or it has space for the maximum number
+ // of mips for the current size bitmap, even if they are not used.
+ scoped_array<uint8> image_data_;
+ // format of the texture this is meant to represent.
+ Texture::Format format_;
+ // width of the bitmap in pixels.
+ int width_;
+ // height of the bitmap in pixels.
+ int height_;
+ // number of valid mipmap levels in this bitmap.
+ unsigned int num_mipmaps_;
+ // The purpose of the bitmap
+ Semantic semantic_;
+
+ O3D_DECL_CLASS(Bitmap, ParamObject);
+ DISALLOW_COPY_AND_ASSIGN(Bitmap);
+};
+
+typedef Bitmap::BitmapRefArray BitmapRefArray;
+
+class BitmapUncompressed : public Bitmap {
+ public:
+ explicit BitmapUncompressed(ServiceLocator* service_locator);
+};
+
+template <typename T>
+class TypedBitmapUncompressed : public BitmapUncompressed {
+ public:
+ typedef T ComponentType;
+ explicit TypedBitmapUncompressed(ServiceLocator* service_locator)
+ : BitmapUncompressed(service_locator) {
+ }
+};
+
+class Bitmap8 : public TypedBitmapUncompressed<uint8> {
+ public:
+ explicit Bitmap8(ServiceLocator* service_locator);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Bitmap8);
+};
+
+class Bitmap16F : public TypedBitmapUncompressed<uint16> {
+ public:
+ explicit Bitmap16F(ServiceLocator* service_locator);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Bitmap16F);
+};
+
+class Bitmap32F : public TypedBitmapUncompressed<float> {
+ public:
+ explicit Bitmap32F(ServiceLocator* service_locator);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Bitmap32F);
+};
+
+class BitmapCompressed : public Bitmap {
+ public:
+ explicit BitmapCompressed(ServiceLocator* service_locator);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BitmapCompressed);
+};
+
+class BitmapDXT1 : public BitmapCompressed {
+ public:
+ explicit BitmapDXT1(ServiceLocator* service_locator);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BitmapDXT1);
+};
+
+class BitmapDXT3 : public BitmapCompressed {
+ public:
+ explicit BitmapDXT3(ServiceLocator* service_locator);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BitmapDXT3);
+};
+
+class BitmapDXT5 : public BitmapCompressed {
+ public:
+ explicit BitmapDXT5(ServiceLocator* service_locator);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BitmapDXT5);
+};
+
+} // namespace o3d
+
+#endif // O3D_CORE_CROSS_BITMAP_H_
diff --git a/o3d/core/cross/client_info.h b/o3d/core/cross/client_info.h
index 40cda3c..2d2c9b7 100644
--- a/o3d/core/cross/client_info.h
+++ b/o3d/core/cross/client_info.h
@@ -1,135 +1,135 @@
-/*
- * 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 defines the ClientInfo class.
-
-#ifndef O3D_CORE_CROSS_CLIENT_INFO_H_
-#define O3D_CORE_CROSS_CLIENT_INFO_H_
-
-#include "core/cross/types.h"
-#include "core/cross/service_locator.h"
-#include "core/cross/service_implementation.h"
-
-namespace o3d {
-
-// This class is used to report infomation about the client.
-class ClientInfo {
- public:
- ClientInfo();
-
- // The number of objects the client is currently tracking.
- int num_objects() const {
- return num_objects_;
- }
-
- // The amount of texture memory used.
- int texture_memory_used() const {
- return texture_memory_used_;
- };
-
- // The amount of texture memory used.
- int buffer_memory_used() const {
- return buffer_memory_used_;
- }
-
- // Whether or not we are using the software renderer.
- bool software_renderer() const {
- return software_renderer_;
- }
-
- // Whether or not the underlying GPU supports non power of 2 textures.
- // NOTE: O3D always supports non power of 2 textures from a public API
- // point of view and massages the data underneath to make this work.
- // The point of this flag is mostly that if you are doing any kind of
- // dynamic texture updating, like video, then you might want to use a
- // power of two texture so O3D doesn't have to do extra work of converting
- // your NPOT texture into a POT texture behind the scenes.
- bool non_power_of_two_textures() const {
- return non_power_of_two_textures_;
- }
-
- // Gets the O3D version.
- const String& version() const {
- return version_;
- }
-
- private:
- friend class ClientInfoManager;
-
- int num_objects_;
- int texture_memory_used_;
- int buffer_memory_used_;
- bool software_renderer_;
- bool non_power_of_two_textures_;
- String version_;
-};
-
-// A class to manage the client info so other classes can easily look it up.
-class ClientInfoManager {
- public:
- static const InterfaceId kInterfaceId;
-
- explicit ClientInfoManager(ServiceLocator* service_locator);
-
- const ClientInfo& client_info();
-
- // Adds or subtracts from the amount of texture memory used.
- void AdjustTextureMemoryUsed(int amount) {
- client_info_.texture_memory_used_ += amount;
- DCHECK(client_info_.texture_memory_used_ >= 0);
- }
-
- // Adds or subtracts from the amount of texture memory used.
- void AdjustBufferMemoryUsed(int amount) {
- client_info_.buffer_memory_used_ += amount;
- DCHECK(client_info_.buffer_memory_used_ >= 0);
- }
-
- void SetSoftwareRenderer(bool used) {
- client_info_.software_renderer_ = used;
- }
-
- void SetNonPowerOfTwoTextures(bool npot) {
- client_info_.non_power_of_two_textures_ = npot;
- }
-
-private:
- ServiceImplementation<ClientInfoManager> service_;
-
- ClientInfo client_info_;
-
- DISALLOW_COPY_AND_ASSIGN(ClientInfoManager);
-};
-
-} // namespace o3d
-
-#endif // O3D_CORE_CROSS_CLIENT_INFO_H_
+/*
+ * 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 defines the ClientInfo class.
+
+#ifndef O3D_CORE_CROSS_CLIENT_INFO_H_
+#define O3D_CORE_CROSS_CLIENT_INFO_H_
+
+#include "core/cross/types.h"
+#include "core/cross/service_locator.h"
+#include "core/cross/service_implementation.h"
+
+namespace o3d {
+
+// This class is used to report infomation about the client.
+class ClientInfo {
+ public:
+ ClientInfo();
+
+ // The number of objects the client is currently tracking.
+ int num_objects() const {
+ return num_objects_;
+ }
+
+ // The amount of texture memory used.
+ int texture_memory_used() const {
+ return texture_memory_used_;
+ };
+
+ // The amount of texture memory used.
+ int buffer_memory_used() const {
+ return buffer_memory_used_;
+ }
+
+ // Whether or not we are using the software renderer.
+ bool software_renderer() const {
+ return software_renderer_;
+ }
+
+ // Whether or not the underlying GPU supports non power of 2 textures.
+ // NOTE: O3D always supports non power of 2 textures from a public API
+ // point of view and massages the data underneath to make this work.
+ // The point of this flag is mostly that if you are doing any kind of
+ // dynamic texture updating, like video, then you might want to use a
+ // power of two texture so O3D doesn't have to do extra work of converting
+ // your NPOT texture into a POT texture behind the scenes.
+ bool non_power_of_two_textures() const {
+ return non_power_of_two_textures_;
+ }
+
+ // Gets the O3D version.
+ const String& version() const {
+ return version_;
+ }
+
+ private:
+ friend class ClientInfoManager;
+
+ int num_objects_;
+ int texture_memory_used_;
+ int buffer_memory_used_;
+ bool software_renderer_;
+ bool non_power_of_two_textures_;
+ String version_;
+};
+
+// A class to manage the client info so other classes can easily look it up.
+class ClientInfoManager {
+ public:
+ static const InterfaceId kInterfaceId;
+
+ explicit ClientInfoManager(ServiceLocator* service_locator);
+
+ const ClientInfo& client_info();
+
+ // Adds or subtracts from the amount of texture memory used.
+ void AdjustTextureMemoryUsed(int amount) {
+ client_info_.texture_memory_used_ += amount;
+ DCHECK(client_info_.texture_memory_used_ >= 0);
+ }
+
+ // Adds or subtracts from the amount of texture memory used.
+ void AdjustBufferMemoryUsed(int amount) {
+ client_info_.buffer_memory_used_ += amount;
+ DCHECK(client_info_.buffer_memory_used_ >= 0);
+ }
+
+ void SetSoftwareRenderer(bool used) {
+ client_info_.software_renderer_ = used;
+ }
+
+ void SetNonPowerOfTwoTextures(bool npot) {
+ client_info_.non_power_of_two_textures_ = npot;
+ }
+
+private:
+ ServiceImplementation<ClientInfoManager> service_;
+
+ ClientInfo client_info_;
+
+ DISALLOW_COPY_AND_ASSIGN(ClientInfoManager);
+};
+
+} // namespace o3d
+
+#endif // O3D_CORE_CROSS_CLIENT_INFO_H_
diff --git a/o3d/core/cross/gl/gl_headers.h b/o3d/core/cross/gl/gl_headers.h
index e800997..4716c54 100644
--- a/o3d/core/cross/gl/gl_headers.h
+++ b/o3d/core/cross/gl/gl_headers.h
@@ -1,43 +1,43 @@
-/*
- * 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.
- */
-
-#ifndef O3D_CORE_CROSS_GL_GL_HEADERS_H_
-#define O3D_CORE_CROSS_GL_GL_HEADERS_H_
-
-#include <GL/glew.h>
-#if defined(OS_WIN)
-#include <GL/wglew.h>
-#endif
-#include <Cg/cg.h>
-#include <Cg/cgGL.h>
-
-#endif // O3D_CORE_CROSS_GL_GL_HEADERS_H_
-
+/*
+ * 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.
+ */
+
+#ifndef O3D_CORE_CROSS_GL_GL_HEADERS_H_
+#define O3D_CORE_CROSS_GL_GL_HEADERS_H_
+
+#include <GL/glew.h>
+#if defined(OS_WIN)
+#include <GL/wglew.h>
+#endif
+#include <Cg/cg.h>
+#include <Cg/cgGL.h>
+
+#endif // O3D_CORE_CROSS_GL_GL_HEADERS_H_
+
diff --git a/o3d/core/cross/image_utils.h b/o3d/core/cross/image_utils.h
index ef3e75b..c9ee2d4 100644
--- a/o3d/core/cross/image_utils.h
+++ b/o3d/core/cross/image_utils.h
@@ -1,288 +1,288 @@
-/*
- * 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 contains the declaration of functions to help with images.
-
-#ifndef O3D_CORE_CROSS_IMAGE_UTILS_H_
-#define O3D_CORE_CROSS_IMAGE_UTILS_H_
-
-#include "base/cross/bits.h"
-#include "core/cross/types.h"
-#include "core/cross/texture_base.h"
-
-namespace o3d {
-namespace image {
-
-// We will fail to load images that are bigger than 4kx4k to avoid security
-// risks. GPUs don't usually support bigger sizes anyway.
-// The biggest bitmap buffer size with these dimensions is:
-// 4k x 4k x 4xsizeof(float) x6 x4/3 (x6 for cube maps, x4/3 for mipmaps)
-// That makes 2GB, representable in an unsigned int, so we will avoid wraps.
-const unsigned int kMaxImageDimension = 4096u;
-
-enum ImageFileType {
- UNKNOWN,
- TGA,
- JPEG,
- PNG,
- DDS,
-};
-
-unsigned int GetNumComponentsForFormat(Texture::Format format);
-
-inline bool IsPOT(unsigned width, unsigned height) {
- return ((width & (width - 1)) == 0) && ((height & (height - 1)) == 0);
-}
-
-inline bool CheckImageDimensions(unsigned int width, unsigned int height) {
- return width <= kMaxImageDimension && height <= kMaxImageDimension;
-}
-
-// Returns whether or not we can make mips.
-bool CanMakeMips(Texture::Format format);
-
-// Gets the number of mip-maps required for a full chain starting at
-// width x height.
-inline unsigned int ComputeMipMapCount(
- unsigned int width, unsigned int height) {
- return 1 + base::bits::Log2Floor(std::max(width, height));
-}
-
-// Gets the smallest power-of-two value that is at least as high as
-// dimension. This is the POT dimension used in ScaleUpToPOT.
-inline unsigned int ComputePOTSize(unsigned int dimension) {
- return 1 << base::bits::Log2Ceiling(dimension);
-}
-
-// Computes one dimension of a mip.
-inline unsigned ComputeMipDimension(int level, unsigned dimension) {
- unsigned v = dimension >> level;
- return v > 0 ? v : 1u;
-}
-
-// Computes the size of the buffer containing a mip-map chain, given its base
-// width, height, format and number of mip-map levels.
-size_t ComputeMipChainSize(unsigned int base_width,
- unsigned int base_height,
- Texture::Format format,
- unsigned int num_mipmaps);
-
-inline int ComputePitch(Texture::Format format, unsigned width) {
- if (Texture::IsCompressedFormat(format)) {
- unsigned blocks_across = (width + 3u) / 4u;
- unsigned bytes_per_block = format == Texture::DXT1 ? 8u : 16u;
- return bytes_per_block * blocks_across;
- } else {
- return static_cast<int>(ComputeMipChainSize(width, 1u, format, 1u));
- }
-}
-
-// Computes the pitch for a bitmap.
-// NOTE: For textures you must get the pitch from the OS.
-inline int ComputeMipPitch(Texture::Format format,
- int level,
- unsigned width) {
- return ComputePitch(format, ComputeMipDimension(level, width));
-}
-
-// Computes the number of bytes of a bitmap pixel buffer.
-size_t ComputeBufferSize(unsigned int width,
- unsigned int height,
- Texture::Format format);
-
-// Crop part of an image from src, scale it to an arbitrary size
-// and paste in dest image. Utility function for all DrawImage
-// function in bitmap and textures. Scale operation is based on
-// Lanczos resampling.
-// Note: this doesn't work for DXTC.
-//
-// Parameters:
-// format: The format of the images.
-// src: source image which would be copied from.
-// src_pitch: The number of bytes per row in the src image.
-// src_x: x-coordinate of the starting pixel in the src image.
-// src_y: y-coordinate of the starting pixel in the src image.
-// src_width: width of the part in src image to be croped.
-// src_height: height of the part in src image to be croped.
-// dest: dest image which would be copied to.
-// dest_pitch: The number of bytes per row in the dest image.
-// dest_x: x-coordinate of the starting pixel in the dest image.
-// dest_y: y-coordinate of the starting pixel in the dest image.
-// dest_width: width of the part in dest image to be pasted to.
-// dest_height: height of the part in dest image to be pasted to.
-// components: number of components per pixel.
-void LanczosScale(Texture::Format format,
- const void* src, int src_pitch,
- int src_x, int src_y,
- int src_width, int src_height,
- void* dest, int dest_pitch,
- int dest_x, int dest_y,
- int dest_width, int dest_height,
- int components);
-
-// Detects the type of image file based on the filename.
-ImageFileType GetFileTypeFromFilename(const char *filename);
-//
-// Detects the type of image file based on the mime-type.
-ImageFileType GetFileTypeFromMimeType(const char *mime_type);
-
-// Adds filler alpha byte (0xff) after every pixel. Assumes buffer was
-// allocated with enough storage)
-// can convert RGB -> RGBA, BGR -> BGRA, etc.
-void XYZToXYZA(uint8 *image_data, int pixel_count);
-
-// Swaps Red and Blue components in the image.
-void RGBAToBGRA(uint8 *image_data, int pixel_count);
-
-// Generates a mip-map for 1 level.
-// NOTE: this doesn't work for DXTC images.
-//
-// Parameters:
-// src_width: the width of the source image.
-// src_height: the height of the source image.
-// format: the format of the data.
-// src_data: the data containing the src image.
-// src_pitch: If the format is uncompressed this is the number of bytes
-// per row of pixels. If compressed this value is unused.
-// dst_data: memory for a mip one level smaller then the source.
-// dst_pitch: If the format is uncompressed this is the number of bytes
-// per row of pixels. If compressed this value is unused.
-bool GenerateMipmap(unsigned int src_width,
- unsigned int src_height,
- Texture::Format format,
- const void *src_data,
- int src_pitch,
- void *dst_data,
- int dst_pitch);
-
-// Scales an image up to power-of-two textures, using point filtering.
-// NOTE: this doesn't work for DXTC images.
-//
-// Parameters:
-// width: the non-power-of-two width of the original image.
-// height: the non-power-of-two height of the original image.
-// format: the format of the data.
-// src: the data containing the source data of the original image.
-// dst: a buffer with enough space for the power-of-two version. Pixels are
-// written from the end to the beginning so dst can be the same buffer
-// as src.
-// dst_pitch: Number of bytes across 1 row of pixels.
-bool ScaleUpToPOT(unsigned int width,
- unsigned int height,
- Texture::Format format,
- const void *src,
- void *dst,
- int dst_pitch);
-
-// Scales an image to an arbitrary size, using point filtering.
-// NOTE: this doesn't work for DXTC images.
-//
-// Parameters:
-// src_width: the width of the original image.
-// src_height: the height of the original image.
-// format: the format of the data.
-// src: the data containing the source data of the original image.
-// dst_width: the width of the target image.
-// dst_height: the height of the target image.
-// dst: a buffer with enough space for the target version. Pixels are
-// written from the end to the beginning so dst can be the same buffer
-// as src if the transformation is an upscaling.
-// dst_pitch: Number of bytes across 1 row of pixels.
-bool Scale(unsigned int src_width,
- unsigned int src_height,
- Texture::Format format,
- const void *src,
- unsigned int dst_width,
- unsigned int dst_height,
- void *dst,
- int dst_pitch);
-
-// adjust start points and boundaries when using DrawImage data
-// in bitmap and textures.
-// Parameters:
-// src_x: x-coordinate of the starting pixel in the source image.
-// src_y: y-coordinate of the starting pixel in the source image.
-// src_width: width of the source image to draw.
-// src_height: height of the source image to draw.
-// src_bmp_level: which mip in source.
-// src_bmp_width: original width of source bitmap.
-// src_bmp_height: original height of source bitmap.
-// dest_x: x-coordinate of the starting pixel in the dest image.
-// dest_y: y-coordinate of the starting pixel in the dest image.
-// dest_width: width of the dest image to draw.
-// dest_height: height of the dest image to draw.
-// dest_bmp_level: which mip in dest.
-// dest_bmp_width: original width of dest bitmap.
-// dest_bmp_height: original height of dest bitmap.
-// Returns:
-// false if src or dest rectangle is out of boundaries.
-bool AdjustDrawImageBoundary(int* src_x, int* src_y,
- int* src_width, int* src_height,
- int src_level,
- int src_bmp_width, int src_bmp_height,
- int* dest_x, int* dest_y,
- int* dest_width, int* dest_height,
- int dest_level,
- int dest_bmp_width, int dest_bmp_height);
-
-// Checks whether or not we can call SetRect and adjust the inputs
-// accordingly so SetRect will work.
-//
-// Assumes that both the source and destination rectangles are within the
-// bounds of their respective images.
-//
-// Parameters:
-// src_y: A pointer to an int holding the Y position of the source
-// rect. Will be adjusted if SetRect can be called.
-// src_width: The width of the source rect.
-// src_height: The height of the source rect.
-// src_pitch: A pointer to an int holding the pitch of the source. Will be
-// adjusted if SetRect can be called.
-// dst_y: A pointer to an int holding the Y position of the dest rect. Will be
-// adjusted if SetRect can be called.
-// dst_width: The width of the dest rect.
-// dst_height: A pointer to an int holding the height of the dest rect. Will
-// adjusted if SetRect can be called.
-// Returns:
-// True if SetRect can be called.
-bool AdjustForSetRect(int* src_y,
- int src_width,
- int src_height,
- int* src_pitch,
- int* dst_y,
- int dst_width,
- int* dst_height);
-
-} // namespace image
-} // namespace o3d
-
-#endif // O3D_CORE_CROSS_IMAGE_UTILS_H_
-
+/*
+ * 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 contains the declaration of functions to help with images.
+
+#ifndef O3D_CORE_CROSS_IMAGE_UTILS_H_
+#define O3D_CORE_CROSS_IMAGE_UTILS_H_
+
+#include "base/cross/bits.h"
+#include "core/cross/types.h"
+#include "core/cross/texture_base.h"
+
+namespace o3d {
+namespace image {
+
+// We will fail to load images that are bigger than 4kx4k to avoid security
+// risks. GPUs don't usually support bigger sizes anyway.
+// The biggest bitmap buffer size with these dimensions is:
+// 4k x 4k x 4xsizeof(float) x6 x4/3 (x6 for cube maps, x4/3 for mipmaps)
+// That makes 2GB, representable in an unsigned int, so we will avoid wraps.
+const unsigned int kMaxImageDimension = 4096u;
+
+enum ImageFileType {
+ UNKNOWN,
+ TGA,
+ JPEG,
+ PNG,
+ DDS,
+};
+
+unsigned int GetNumComponentsForFormat(Texture::Format format);
+
+inline bool IsPOT(unsigned width, unsigned height) {
+ return ((width & (width - 1)) == 0) && ((height & (height - 1)) == 0);
+}
+
+inline bool CheckImageDimensions(unsigned int width, unsigned int height) {
+ return width <= kMaxImageDimension && height <= kMaxImageDimension;
+}
+
+// Returns whether or not we can make mips.
+bool CanMakeMips(Texture::Format format);
+
+// Gets the number of mip-maps required for a full chain starting at
+// width x height.
+inline unsigned int ComputeMipMapCount(
+ unsigned int width, unsigned int height) {
+ return 1 + base::bits::Log2Floor(std::max(width, height));
+}
+
+// Gets the smallest power-of-two value that is at least as high as
+// dimension. This is the POT dimension used in ScaleUpToPOT.
+inline unsigned int ComputePOTSize(unsigned int dimension) {
+ return 1 << base::bits::Log2Ceiling(dimension);
+}
+
+// Computes one dimension of a mip.
+inline unsigned ComputeMipDimension(int level, unsigned dimension) {
+ unsigned v = dimension >> level;
+ return v > 0 ? v : 1u;
+}
+
+// Computes the size of the buffer containing a mip-map chain, given its base
+// width, height, format and number of mip-map levels.
+size_t ComputeMipChainSize(unsigned int base_width,
+ unsigned int base_height,
+ Texture::Format format,
+ unsigned int num_mipmaps);
+
+inline int ComputePitch(Texture::Format format, unsigned width) {
+ if (Texture::IsCompressedFormat(format)) {
+ unsigned blocks_across = (width + 3u) / 4u;
+ unsigned bytes_per_block = format == Texture::DXT1 ? 8u : 16u;
+ return bytes_per_block * blocks_across;
+ } else {
+ return static_cast<int>(ComputeMipChainSize(width, 1u, format, 1u));
+ }
+}
+
+// Computes the pitch for a bitmap.
+// NOTE: For textures you must get the pitch from the OS.
+inline int ComputeMipPitch(Texture::Format format,
+ int level,
+ unsigned width) {
+ return ComputePitch(format, ComputeMipDimension(level, width));
+}
+
+// Computes the number of bytes of a bitmap pixel buffer.
+size_t ComputeBufferSize(unsigned int width,
+ unsigned int height,
+ Texture::Format format);
+
+// Crop part of an image from src, scale it to an arbitrary size
+// and paste in dest image. Utility function for all DrawImage
+// function in bitmap and textures. Scale operation is based on
+// Lanczos resampling.
+// Note: this doesn't work for DXTC.
+//
+// Parameters:
+// format: The format of the images.
+// src: source image which would be copied from.
+// src_pitch: The number of bytes per row in the src image.
+// src_x: x-coordinate of the starting pixel in the src image.
+// src_y: y-coordinate of the starting pixel in the src image.
+// src_width: width of the part in src image to be croped.
+// src_height: height of the part in src image to be croped.
+// dest: dest image which would be copied to.
+// dest_pitch: The number of bytes per row in the dest image.
+// dest_x: x-coordinate of the starting pixel in the dest image.
+// dest_y: y-coordinate of the starting pixel in the dest image.
+// dest_width: width of the part in dest image to be pasted to.
+// dest_height: height of the part in dest image to be pasted to.
+// components: number of components per pixel.
+void LanczosScale(Texture::Format format,
+ const void* src, int src_pitch,
+ int src_x, int src_y,
+ int src_width, int src_height,
+ void* dest, int dest_pitch,
+ int dest_x, int dest_y,
+ int dest_width, int dest_height,
+ int components);
+
+// Detects the type of image file based on the filename.
+ImageFileType GetFileTypeFromFilename(const char *filename);
+//
+// Detects the type of image file based on the mime-type.
+ImageFileType GetFileTypeFromMimeType(const char *mime_type);
+
+// Adds filler alpha byte (0xff) after every pixel. Assumes buffer was
+// allocated with enough storage)
+// can convert RGB -> RGBA, BGR -> BGRA, etc.
+void XYZToXYZA(uint8 *image_data, int pixel_count);
+
+// Swaps Red and Blue components in the image.
+void RGBAToBGRA(uint8 *image_data, int pixel_count);
+
+// Generates a mip-map for 1 level.
+// NOTE: this doesn't work for DXTC images.
+//
+// Parameters:
+// src_width: the width of the source image.
+// src_height: the height of the source image.
+// format: the format of the data.
+// src_data: the data containing the src image.
+// src_pitch: If the format is uncompressed this is the number of bytes
+// per row of pixels. If compressed this value is unused.
+// dst_data: memory for a mip one level smaller then the source.
+// dst_pitch: If the format is uncompressed this is the number of bytes
+// per row of pixels. If compressed this value is unused.
+bool GenerateMipmap(unsigned int src_width,
+ unsigned int src_height,
+ Texture::Format format,
+ const void *src_data,
+ int src_pitch,
+ void *dst_data,
+ int dst_pitch);
+
+// Scales an image up to power-of-two textures, using point filtering.
+// NOTE: this doesn't work for DXTC images.
+//
+// Parameters:
+// width: the non-power-of-two width of the original image.
+// height: the non-power-of-two height of the original image.
+// format: the format of the data.
+// src: the data containing the source data of the original image.
+// dst: a buffer with enough space for the power-of-two version. Pixels are
+// written from the end to the beginning so dst can be the same buffer
+// as src.
+// dst_pitch: Number of bytes across 1 row of pixels.
+bool ScaleUpToPOT(unsigned int width,
+ unsigned int height,
+ Texture::Format format,
+ const void *src,
+ void *dst,
+ int dst_pitch);
+
+// Scales an image to an arbitrary size, using point filtering.
+// NOTE: this doesn't work for DXTC images.
+//
+// Parameters:
+// src_width: the width of the original image.
+// src_height: the height of the original image.
+// format: the format of the data.
+// src: the data containing the source data of the original image.
+// dst_width: the width of the target image.
+// dst_height: the height of the target image.
+// dst: a buffer with enough space for the target version. Pixels are
+// written from the end to the beginning so dst can be the same buffer
+// as src if the transformation is an upscaling.
+// dst_pitch: Number of bytes across 1 row of pixels.
+bool Scale(unsigned int src_width,
+ unsigned int src_height,
+ Texture::Format format,
+ const void *src,
+ unsigned int dst_width,
+ unsigned int dst_height,
+ void *dst,
+ int dst_pitch);
+
+// adjust start points and boundaries when using DrawImage data
+// in bitmap and textures.
+// Parameters:
+// src_x: x-coordinate of the starting pixel in the source image.
+// src_y: y-coordinate of the starting pixel in the source image.
+// src_width: width of the source image to draw.
+// src_height: height of the source image to draw.
+// src_bmp_level: which mip in source.
+// src_bmp_width: original width of source bitmap.
+// src_bmp_height: original height of source bitmap.
+// dest_x: x-coordinate of the starting pixel in the dest image.
+// dest_y: y-coordinate of the starting pixel in the dest image.
+// dest_width: width of the dest image to draw.
+// dest_height: height of the dest image to draw.
+// dest_bmp_level: which mip in dest.
+// dest_bmp_width: original width of dest bitmap.
+// dest_bmp_height: original height of dest bitmap.
+// Returns:
+// false if src or dest rectangle is out of boundaries.
+bool AdjustDrawImageBoundary(int* src_x, int* src_y,
+ int* src_width, int* src_height,
+ int src_level,
+ int src_bmp_width, int src_bmp_height,
+ int* dest_x, int* dest_y,
+ int* dest_width, int* dest_height,
+ int dest_level,
+ int dest_bmp_width, int dest_bmp_height);
+
+// Checks whether or not we can call SetRect and adjust the inputs
+// accordingly so SetRect will work.
+//
+// Assumes that both the source and destination rectangles are within the
+// bounds of their respective images.
+//
+// Parameters:
+// src_y: A pointer to an int holding the Y position of the source
+// rect. Will be adjusted if SetRect can be called.
+// src_width: The width of the source rect.
+// src_height: The height of the source rect.
+// src_pitch: A pointer to an int holding the pitch of the source. Will be
+// adjusted if SetRect can be called.
+// dst_y: A pointer to an int holding the Y position of the dest rect. Will be
+// adjusted if SetRect can be called.
+// dst_width: The width of the dest rect.
+// dst_height: A pointer to an int holding the height of the dest rect. Will
+// adjusted if SetRect can be called.
+// Returns:
+// True if SetRect can be called.
+bool AdjustForSetRect(int* src_y,
+ int src_width,
+ int src_height,
+ int* src_pitch,
+ int* dst_y,
+ int dst_width,
+ int* dst_height);
+
+} // namespace image
+} // namespace o3d
+
+#endif // O3D_CORE_CROSS_IMAGE_UTILS_H_
+
diff --git a/o3d/core/cross/pointer_utils.h b/o3d/core/cross/pointer_utils.h
index e246deb..b94bff9 100644
--- a/o3d/core/cross/pointer_utils.h
+++ b/o3d/core/cross/pointer_utils.h
@@ -1,58 +1,58 @@
-/*
- * 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 contains the declaration for a few templated function to help with
-// pointers.
-
-#ifndef O3D_CORE_CROSS_POINTER_UTILS_H_
-#define O3D_CORE_CROSS_POINTER_UTILS_H_
-
-#include "core/cross/types.h"
-
-namespace o3d {
-
-// Adds an arbitrary byte offset to a typed pointer.
-template <typename T>
-T AddPointerOffset(T pointer, int offset) {
- return reinterpret_cast<T>(
- const_cast<uint8*>(reinterpret_cast<const uint8*>(pointer) + offset));
-}
-
-// Creates a typed pointer from a void pointer and an offset.
-template <typename T>
-T PointerFromVoidPointer(const void* pointer, int offset) {
- return reinterpret_cast<T>(
- const_cast<uint8*>(reinterpret_cast<const uint8*>(pointer) + offset));
-}
-
-} // namespace o3d
-
-#endif // O3D_CORE_CROSS_POINTER_UTILS_H_
+/*
+ * 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 contains the declaration for a few templated function to help with
+// pointers.
+
+#ifndef O3D_CORE_CROSS_POINTER_UTILS_H_
+#define O3D_CORE_CROSS_POINTER_UTILS_H_
+
+#include "core/cross/types.h"
+
+namespace o3d {
+
+// Adds an arbitrary byte offset to a typed pointer.
+template <typename T>
+T AddPointerOffset(T pointer, int offset) {
+ return reinterpret_cast<T>(
+ const_cast<uint8*>(reinterpret_cast<const uint8*>(pointer) + offset));
+}
+
+// Creates a typed pointer from a void pointer and an offset.
+template <typename T>
+T PointerFromVoidPointer(const void* pointer, int offset) {
+ return reinterpret_cast<T>(
+ const_cast<uint8*>(reinterpret_cast<const uint8*>(pointer) + offset));
+}
+
+} // namespace o3d
+
+#endif // O3D_CORE_CROSS_POINTER_UTILS_H_
diff --git a/o3d/core/win/d3d9/software_renderer_d3d9.h b/o3d/core/win/d3d9/software_renderer_d3d9.h
index fcfa8ef..5c7cdfc 100644
--- a/o3d/core/win/d3d9/software_renderer_d3d9.h
+++ b/o3d/core/win/d3d9/software_renderer_d3d9.h
@@ -38,7 +38,7 @@ namespace o3d {
// Not implemented.
inline bool SetupSoftwareRenderer(IDirect3D9* d3d) {
- return false;
+ return false;
}
} // namespace o3d
diff --git a/o3d/documentation/externs/o3d-extra-externs.js b/o3d/documentation/externs/o3d-extra-externs.js
index d9ce0f6..712b568 100755
--- a/o3d/documentation/externs/o3d-extra-externs.js
+++ b/o3d/documentation/externs/o3d-extra-externs.js
@@ -1,48 +1,48 @@
-
-/**
- * Special global variable for V8 instances.
- */
-var plugin;
-
-/**
- * The main namespace for the o3d plugin.
- * @constructor
- */
-var o3d;
-
-/**
- * @type {!Object}
- */
-var Exception = goog.typedef;
-
-/**
- * A namespace for the Cursor.
- * @namespace
- */
-o3d.Cursor = o3d.Cursor || { };
-
-/**
- * A namespace for the VectorMath.
- * @namespace
- */
-var Vectormath;
-
-/**
- * A namespace for the VectorMath.Aos
- * @namespace
- */
-Vectormath.Aos = Vectormath.Aos || { };
-
-/**
- * A 4x4 Matrix of floats
- * @type {!Array.<!Array.<number>>}
- */
-o3d.Matrix4 = goog.typedef;
-
-/**
- * RangeError.
- * why is this sometimes needed and sometimes not?
- * @exception
- */
-var RangeError;
-
+
+/**
+ * Special global variable for V8 instances.
+ */
+var plugin;
+
+/**
+ * The main namespace for the o3d plugin.
+ * @constructor
+ */
+var o3d;
+
+/**
+ * @type {!Object}
+ */
+var Exception = goog.typedef;
+
+/**
+ * A namespace for the Cursor.
+ * @namespace
+ */
+o3d.Cursor = o3d.Cursor || { };
+
+/**
+ * A namespace for the VectorMath.
+ * @namespace
+ */
+var Vectormath;
+
+/**
+ * A namespace for the VectorMath.Aos
+ * @namespace
+ */
+Vectormath.Aos = Vectormath.Aos || { };
+
+/**
+ * A 4x4 Matrix of floats
+ * @type {!Array.<!Array.<number>>}
+ */
+o3d.Matrix4 = goog.typedef;
+
+/**
+ * RangeError.
+ * why is this sometimes needed and sometimes not?
+ * @exception
+ */
+var RangeError;
+
diff --git a/o3d/documentation/get_docs_files.py b/o3d/documentation/get_docs_files.py
index c138bc1..dd4bf3d 100644
--- a/o3d/documentation/get_docs_files.py
+++ b/o3d/documentation/get_docs_files.py
@@ -1,52 +1,52 @@
-#!/usr/bin/env python
-# Copyright (c) 2009 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Helper script to generate file lists for documentation.gyp."""
-
-import os
-import sys
-import types
-
-
-def AppendBasePath(folder, filenames):
- """Appends a base path to a ist of files"""
- return [os.path.join(folder, filename) for filename in filenames]
-
-
-def GetIdlFiles():
- idl_list_filename = os.path.join('..', 'plugin', 'idl_list.manifest')
- idl_list_basepath = os.path.dirname(idl_list_filename)
- files = eval(open(idl_list_filename, "r").read())
- idl_files = AppendBasePath(idl_list_basepath, files)
- return idl_files
-
-
-def GetJsFiles():
- js_list_filename = os.path.join('..', 'samples', 'o3djs', 'js_list.manifest')
- js_list_basepath = os.path.dirname(js_list_filename)
- files = eval(open(js_list_filename, "r").read())
- o3djs_files = AppendBasePath(js_list_basepath, files)
- return o3djs_files
-
-
-# Read in the manifest files (which are just really simple python files),
-# and scrape out the file lists.
-# TODO(gspencer): Since we no longer use the scons build, we should
-# rework this so that the lists are just python lists so we can just
-# do a simple eval instead of having to emulate scons import.
-def main(argv):
- files = []
- if argv[0] == '--js':
- files = GetJsFiles()
- if argv[0] == '--idl':
- files = GetIdlFiles()
- files.sort()
- for file in files:
- # gyp wants paths with slashes, not backslashes.
- print file.replace("\\", "/")
-
-
-if __name__ == "__main__":
- main(sys.argv[1:])
+#!/usr/bin/env python
+# Copyright (c) 2009 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Helper script to generate file lists for documentation.gyp."""
+
+import os
+import sys
+import types
+
+
+def AppendBasePath(folder, filenames):
+ """Appends a base path to a ist of files"""
+ return [os.path.join(folder, filename) for filename in filenames]
+
+
+def GetIdlFiles():
+ idl_list_filename = os.path.join('..', 'plugin', 'idl_list.manifest')
+ idl_list_basepath = os.path.dirname(idl_list_filename)
+ files = eval(open(idl_list_filename, "r").read())
+ idl_files = AppendBasePath(idl_list_basepath, files)
+ return idl_files
+
+
+def GetJsFiles():
+ js_list_filename = os.path.join('..', 'samples', 'o3djs', 'js_list.manifest')
+ js_list_basepath = os.path.dirname(js_list_filename)
+ files = eval(open(js_list_filename, "r").read())
+ o3djs_files = AppendBasePath(js_list_basepath, files)
+ return o3djs_files
+
+
+# Read in the manifest files (which are just really simple python files),
+# and scrape out the file lists.
+# TODO(gspencer): Since we no longer use the scons build, we should
+# rework this so that the lists are just python lists so we can just
+# do a simple eval instead of having to emulate scons import.
+def main(argv):
+ files = []
+ if argv[0] == '--js':
+ files = GetJsFiles()
+ if argv[0] == '--idl':
+ files = GetIdlFiles()
+ files.sort()
+ for file in files:
+ # gyp wants paths with slashes, not backslashes.
+ print file.replace("\\", "/")
+
+
+if __name__ == "__main__":
+ main(sys.argv[1:])
diff --git a/o3d/documentation/jsdoc-toolkit-templates/static/prettify.css b/o3d/documentation/jsdoc-toolkit-templates/static/prettify.css
index 69d11f7..1b4954b 100644
--- a/o3d/documentation/jsdoc-toolkit-templates/static/prettify.css
+++ b/o3d/documentation/jsdoc-toolkit-templates/static/prettify.css
@@ -1,34 +1,34 @@
-.str{ color: #008 }
-.kwd{ color: #808 }
-.com{ color: #800 }
-.typ{ color: #606 }
-.lit{ color: #066 }
-.pun{ color: #660 }
-.pln{ color: #060 }
-.tag{ color: #008 }
-.atn{ color: #606 }
-.atv{ color: #080 }
-.dec{ color: #606 }
-.prettyprint{
- font-family: Fixed, monospace;
- font-size: 95%;
- margin: 4px 8px 4px 2px;
- padding: 4px 6px;
- border: 1px solid #CCC;
- background-color: #f5f5f5;
-}
-.re.prettyprint{
-}
-@media print {
- .str{ color: #060 }
- .kwd{ color: #006; font-weight: bold }
- .com{ color: #600; font-style: italic }
- .typ{ color: #404; font-weight: bold }
- .lit{ color: #044 }
- .pun{ color: #440 }
- .pln{ color: #000 }
- .tag{ color: #006;font-weight: bold }
- .atn{ color: #404 }
- .atv{ color: #060 }
-}
-
+.str{ color: #008 }
+.kwd{ color: #808 }
+.com{ color: #800 }
+.typ{ color: #606 }
+.lit{ color: #066 }
+.pun{ color: #660 }
+.pln{ color: #060 }
+.tag{ color: #008 }
+.atn{ color: #606 }
+.atv{ color: #080 }
+.dec{ color: #606 }
+.prettyprint{
+ font-family: Fixed, monospace;
+ font-size: 95%;
+ margin: 4px 8px 4px 2px;
+ padding: 4px 6px;
+ border: 1px solid #CCC;
+ background-color: #f5f5f5;
+}
+.re.prettyprint{
+}
+@media print {
+ .str{ color: #060 }
+ .kwd{ color: #006; font-weight: bold }
+ .com{ color: #600; font-style: italic }
+ .typ{ color: #404; font-weight: bold }
+ .lit{ color: #044 }
+ .pun{ color: #440 }
+ .pln{ color: #000 }
+ .tag{ color: #006;font-weight: bold }
+ .atn{ color: #404 }
+ .atv{ color: #060 }
+}
+
diff --git a/o3d/gypbuild.py b/o3d/gypbuild.py
index a8de01c..86ff0cd 100755
--- a/o3d/gypbuild.py
+++ b/o3d/gypbuild.py
@@ -1,296 +1,296 @@
-#! /usr/bin/env python
-# Copyright 2009 Google Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Builds a particlar platform so the user does not have to know platform
-# specific build commands for every single platform.
-
-# TODO(gman): Add help.
-# TODO(gman): Add cross platform modes like "debug", "opt", "test", "docs"
-# TODO(gman): Add cross platform switches like "-clean" and "-rebuild".
-# TODO(gman): Add cross platform options like "-verbose".
-# TODO(gman): Add cross platform options like "-presubmit", "-selenium",
-# "-unit_tests"
-
-import os
-import os.path
-import sys
-import re
-import subprocess
-import platform
-sys.path.append('build')
-import is_admin
-from optparse import OptionParser
-
-
-class GypBuilder(object):
- """A class to help build gyp projects in a cross platform way"""
-
- class Builder(object):
- """Base Class for building."""
-
- def __init__(self, builder):
- self.builder = builder
-
- def Log(self, *args):
- """Prints something if verbose is true."""
- self.builder.Log(args)
-
- def Execute(self, args):
- """Executes an external program if execute is true."""
- self.builder.Execute(args)
-
- def Dopresubmit(self, targets, options):
- """Builds and runs both the unit tests and selenium."""
- self.Dounit_tests(targets, options)
- self.Doselenium(targets, options)
-
- def Doselenium(self, targets, options):
- """Builds and runs the selenium tests."""
- print "selenium not yet implemented."
-
- def Dounit_tests(self, targets, options):
- """Builds and runs the unit tests."""
- print "unit_tests not yet implemented."
-
- def CleanTargets(self, targets, options):
- """Cleans the targets."""
- print "clean not implemented for this platform."
-
-
- class OSXBuilder(Builder):
- """Class for building on OSX."""
-
- def __init__(self, builder):
- GypBuilder.Builder.__init__(self, builder)
-
- def GetSolutionPath(self):
- """Gets the solution path."""
- return '%s.xcodeproj' % GypBuilder.base_name
-
- def CleanTargets(self, targets, options):
- """Cleans the specifed targets."""
- solution = self.GetSolutionPath()
- self.Execute(['xcodebuild',
- '-project', solution,
- 'clean'])
-
- def Dobuild(self, targets, options):
- """Builds the specifed targets."""
- solution = self.GetSolutionPath()
- self.Execute(['xcodebuild',
- '-project', solution])
-
- class WinBuilder(Builder):
- """Class for building on Windows."""
-
- def __init__(self, builder):
- GypBuilder.Builder.__init__(self, builder)
-
- def GetSolutionPath(self):
- """Gets the solution path."""
- return os.path.abspath('%s.sln' % GypBuilder.base_name)
-
- def CheckVisualStudioVersionVsSolution(self, solution):
- """Checks the solution matches the cl version."""
- f = open(solution, "r")
- line = f.readline()
- f.close()
- m = re.search(r'Format Version (\d+)\.', line)
- if m:
- solution_version = int(m.group(1))
- else:
- print "FAILURE: Unknown solution version in %s" % solution
- sys.exit(1)
-
- output = subprocess.Popen(['cl.exe'],
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE).communicate()[1]
- m = re.search(r'Compiler Version (\d+)\.', output)
- if m:
- compiler_version = int(m.group(1))
- else:
- print "FAILURE: Unknown cl.exe version."
- sys.exit(1)
-
- # Compiler Solution
- # Visual Studio .NET 2005 14 9
- # Visual Studio .NET 2008 15 10
- # Visual Studio .NET 2010 ?? ??
- if (compiler_version - 14) > (solution_version - 9):
- vs_map = {
- 14: '2005',
- 15: '2008',
- 16: '2010',
- }
- sln_map = {
- 9: '2005',
- 10: '2008',
- 11: '2010',
- }
- vs_version = vs_map[compiler_version]
- print ("ERROR: solution (%s) version does not match "
- "Visual Studio version (%s)" %
- (sln_map[solution_version], vs_version))
- print "You should 'set GYP_MSVS_VERSION=auto'"
- print "and run 'gclient runhooks --force'"
- sys.exit(1)
-
- def CleanTargets(self, targets, options):
- """Cleans the targets."""
- solution = self.GetSolutionPath()
- self.Execute(['devenv.com',
- solution,
- '/clean',
- options.version])
-
- def Dobuild(self, targets, options):
- """Builds the specifed targets."""
- solution = self.GetSolutionPath()
- if not is_admin.IsAdmin():
- print ("WARNING: selenium_ie will not run unless you run as admin "
- "or turn off UAC.\nAfter switching to admin run "
- "'gclient runhooks --force'")
- self.CheckVisualStudioVersionVsSolution(solution)
- self.Execute(['devenv.com',
- solution,
- '/build',
- options.version])
- # TODO(gman): Should I check for devenv and if it does not exist
- # use msbuild? Msbuild is significantly slower than devenv.
- #self.Execute(['msbuild',
- # solution,
- # '/p:Configuration=%s' % options.version])
-
- class LinuxBuilder(Builder):
- """Class for building on Linux."""
-
- def __init__(self, builder):
- GypBuilder.Builder.__init__(self, builder)
-
- def GetSolutionPath(self):
- """Gets the solution path."""
- return '%s_main.scons' % GypBuilder.base_name
-
- def CleanTargets(self, targets, options):
- """Cleans the targets."""
- solution = self.GetSolutionPath()
- self.Execute(['hammer',
- '-f', solution,
- '--clean'])
-
- def Dobuild(self, targets, options):
- """Builds the specifed targets."""
- solution = self.GetSolutionPath()
- self.Execute(['hammer',
- '-f', solution])
-
- # Use "o3d" for chrome only build?
- base_name = "o3d_all"
-
- def __init__(self, args):
- self.execute = True
- self.verbose = False
-
- modes = ["build", "presubmit", "selenium", "unit_tests"]
- versions = ["Debug", "Release"]
-
- parser = OptionParser()
- parser.add_option(
- "--list-targets", action="store_true",
- help="lists all available targets.")
- parser.add_option(
- "--no-execute", action="store_true", default=False,
- help="just prints commands that would get executed.")
- parser.add_option(
- "--verbose", action="store_true",
- help="prints more output.")
- parser.add_option(
- "--targets", action="append",
- help="targets to build separated by commas.")
- parser.add_option(
- "--clean", action="store_true",
- help="cleans the targets.")
- parser.add_option(
- "--rebuild", action="store_true",
- help="cleans, then builds targets")
- parser.add_option(
- "--version", choices=versions, default="Debug",
- help="version to build. Versions are '%s'. Default='Debug' " %
- "', '".join(versions))
- parser.add_option(
- "--mode", choices=modes, default="build",
- help="mode to use. Valid modes are '%s'. Default='build' " %
- "', '".join(modes))
-
- (options, args) = parser.parse_args(args=args)
-
- self.verbose = options.verbose
- self.execute = not options.no_execute
-
- if options.list_targets:
- print "Not yet implemented"
- sys.exit(0)
-
- self.Log("mode:", options.mode)
-
- targets = options.targets
- if targets:
- # flatten the targets.
- targets = sum([t.split(",") for t in targets], [])
-
- os.chdir("build")
-
- # Create a platform specific builder.
- if os.name == 'nt':
- builder = self.WinBuilder(self)
- elif platform.system() == 'Darwin':
- builder = self.OSXBuilder(self)
- elif platform.system() == 'Linux':
- builder = self.LinuxBuilder(self)
- else:
- print "ERROR: Unknown platform."
- sys.exit(1)
-
- # clean if asked.
- if options.clean or options.rebuild:
- builder.CleanTargets(targets, options)
- if not options.rebuild:
- return
-
- # call a Do method based on the mode.
- func = getattr(builder, "Do%s" % options.mode)
- func(targets, options)
-
- def Log(self, *args):
- """Prints something if verbose is true."""
- if self.verbose:
- print args
-
- def Execute(self, args):
- """Executes an external program if execute is true."""
- if self.execute:
- self.Log(" ".join(args))
- if subprocess.call(args) > 0:
- raise RuntimeError("FAILED: " + " ".join(args))
- else:
- print " ".join(args)
-
-
-def main(args):
- GypBuilder(args[1:])
-
-if __name__ == "__main__":
- main(sys.argv)
-
+#! /usr/bin/env python
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Builds a particlar platform so the user does not have to know platform
+# specific build commands for every single platform.
+
+# TODO(gman): Add help.
+# TODO(gman): Add cross platform modes like "debug", "opt", "test", "docs"
+# TODO(gman): Add cross platform switches like "-clean" and "-rebuild".
+# TODO(gman): Add cross platform options like "-verbose".
+# TODO(gman): Add cross platform options like "-presubmit", "-selenium",
+# "-unit_tests"
+
+import os
+import os.path
+import sys
+import re
+import subprocess
+import platform
+sys.path.append('build')
+import is_admin
+from optparse import OptionParser
+
+
+class GypBuilder(object):
+ """A class to help build gyp projects in a cross platform way"""
+
+ class Builder(object):
+ """Base Class for building."""
+
+ def __init__(self, builder):
+ self.builder = builder
+
+ def Log(self, *args):
+ """Prints something if verbose is true."""
+ self.builder.Log(args)
+
+ def Execute(self, args):
+ """Executes an external program if execute is true."""
+ self.builder.Execute(args)
+
+ def Dopresubmit(self, targets, options):
+ """Builds and runs both the unit tests and selenium."""
+ self.Dounit_tests(targets, options)
+ self.Doselenium(targets, options)
+
+ def Doselenium(self, targets, options):
+ """Builds and runs the selenium tests."""
+ print "selenium not yet implemented."
+
+ def Dounit_tests(self, targets, options):
+ """Builds and runs the unit tests."""
+ print "unit_tests not yet implemented."
+
+ def CleanTargets(self, targets, options):
+ """Cleans the targets."""
+ print "clean not implemented for this platform."
+
+
+ class OSXBuilder(Builder):
+ """Class for building on OSX."""
+
+ def __init__(self, builder):
+ GypBuilder.Builder.__init__(self, builder)
+
+ def GetSolutionPath(self):
+ """Gets the solution path."""
+ return '%s.xcodeproj' % GypBuilder.base_name
+
+ def CleanTargets(self, targets, options):
+ """Cleans the specifed targets."""
+ solution = self.GetSolutionPath()
+ self.Execute(['xcodebuild',
+ '-project', solution,
+ 'clean'])
+
+ def Dobuild(self, targets, options):
+ """Builds the specifed targets."""
+ solution = self.GetSolutionPath()
+ self.Execute(['xcodebuild',
+ '-project', solution])
+
+ class WinBuilder(Builder):
+ """Class for building on Windows."""
+
+ def __init__(self, builder):
+ GypBuilder.Builder.__init__(self, builder)
+
+ def GetSolutionPath(self):
+ """Gets the solution path."""
+ return os.path.abspath('%s.sln' % GypBuilder.base_name)
+
+ def CheckVisualStudioVersionVsSolution(self, solution):
+ """Checks the solution matches the cl version."""
+ f = open(solution, "r")
+ line = f.readline()
+ f.close()
+ m = re.search(r'Format Version (\d+)\.', line)
+ if m:
+ solution_version = int(m.group(1))
+ else:
+ print "FAILURE: Unknown solution version in %s" % solution
+ sys.exit(1)
+
+ output = subprocess.Popen(['cl.exe'],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE).communicate()[1]
+ m = re.search(r'Compiler Version (\d+)\.', output)
+ if m:
+ compiler_version = int(m.group(1))
+ else:
+ print "FAILURE: Unknown cl.exe version."
+ sys.exit(1)
+
+ # Compiler Solution
+ # Visual Studio .NET 2005 14 9
+ # Visual Studio .NET 2008 15 10
+ # Visual Studio .NET 2010 ?? ??
+ if (compiler_version - 14) > (solution_version - 9):
+ vs_map = {
+ 14: '2005',
+ 15: '2008',
+ 16: '2010',
+ }
+ sln_map = {
+ 9: '2005',
+ 10: '2008',
+ 11: '2010',
+ }
+ vs_version = vs_map[compiler_version]
+ print ("ERROR: solution (%s) version does not match "
+ "Visual Studio version (%s)" %
+ (sln_map[solution_version], vs_version))
+ print "You should 'set GYP_MSVS_VERSION=auto'"
+ print "and run 'gclient runhooks --force'"
+ sys.exit(1)
+
+ def CleanTargets(self, targets, options):
+ """Cleans the targets."""
+ solution = self.GetSolutionPath()
+ self.Execute(['devenv.com',
+ solution,
+ '/clean',
+ options.version])
+
+ def Dobuild(self, targets, options):
+ """Builds the specifed targets."""
+ solution = self.GetSolutionPath()
+ if not is_admin.IsAdmin():
+ print ("WARNING: selenium_ie will not run unless you run as admin "
+ "or turn off UAC.\nAfter switching to admin run "
+ "'gclient runhooks --force'")
+ self.CheckVisualStudioVersionVsSolution(solution)
+ self.Execute(['devenv.com',
+ solution,
+ '/build',
+ options.version])
+ # TODO(gman): Should I check for devenv and if it does not exist
+ # use msbuild? Msbuild is significantly slower than devenv.
+ #self.Execute(['msbuild',
+ # solution,
+ # '/p:Configuration=%s' % options.version])
+
+ class LinuxBuilder(Builder):
+ """Class for building on Linux."""
+
+ def __init__(self, builder):
+ GypBuilder.Builder.__init__(self, builder)
+
+ def GetSolutionPath(self):
+ """Gets the solution path."""
+ return '%s_main.scons' % GypBuilder.base_name
+
+ def CleanTargets(self, targets, options):
+ """Cleans the targets."""
+ solution = self.GetSolutionPath()
+ self.Execute(['hammer',
+ '-f', solution,
+ '--clean'])
+
+ def Dobuild(self, targets, options):
+ """Builds the specifed targets."""
+ solution = self.GetSolutionPath()
+ self.Execute(['hammer',
+ '-f', solution])
+
+ # Use "o3d" for chrome only build?
+ base_name = "o3d_all"
+
+ def __init__(self, args):
+ self.execute = True
+ self.verbose = False
+
+ modes = ["build", "presubmit", "selenium", "unit_tests"]
+ versions = ["Debug", "Release"]
+
+ parser = OptionParser()
+ parser.add_option(
+ "--list-targets", action="store_true",
+ help="lists all available targets.")
+ parser.add_option(
+ "--no-execute", action="store_true", default=False,
+ help="just prints commands that would get executed.")
+ parser.add_option(
+ "--verbose", action="store_true",
+ help="prints more output.")
+ parser.add_option(
+ "--targets", action="append",
+ help="targets to build separated by commas.")
+ parser.add_option(
+ "--clean", action="store_true",
+ help="cleans the targets.")
+ parser.add_option(
+ "--rebuild", action="store_true",
+ help="cleans, then builds targets")
+ parser.add_option(
+ "--version", choices=versions, default="Debug",
+ help="version to build. Versions are '%s'. Default='Debug' " %
+ "', '".join(versions))
+ parser.add_option(
+ "--mode", choices=modes, default="build",
+ help="mode to use. Valid modes are '%s'. Default='build' " %
+ "', '".join(modes))
+
+ (options, args) = parser.parse_args(args=args)
+
+ self.verbose = options.verbose
+ self.execute = not options.no_execute
+
+ if options.list_targets:
+ print "Not yet implemented"
+ sys.exit(0)
+
+ self.Log("mode:", options.mode)
+
+ targets = options.targets
+ if targets:
+ # flatten the targets.
+ targets = sum([t.split(",") for t in targets], [])
+
+ os.chdir("build")
+
+ # Create a platform specific builder.
+ if os.name == 'nt':
+ builder = self.WinBuilder(self)
+ elif platform.system() == 'Darwin':
+ builder = self.OSXBuilder(self)
+ elif platform.system() == 'Linux':
+ builder = self.LinuxBuilder(self)
+ else:
+ print "ERROR: Unknown platform."
+ sys.exit(1)
+
+ # clean if asked.
+ if options.clean or options.rebuild:
+ builder.CleanTargets(targets, options)
+ if not options.rebuild:
+ return
+
+ # call a Do method based on the mode.
+ func = getattr(builder, "Do%s" % options.mode)
+ func(targets, options)
+
+ def Log(self, *args):
+ """Prints something if verbose is true."""
+ if self.verbose:
+ print args
+
+ def Execute(self, args):
+ """Executes an external program if execute is true."""
+ if self.execute:
+ self.Log(" ".join(args))
+ if subprocess.call(args) > 0:
+ raise RuntimeError("FAILED: " + " ".join(args))
+ else:
+ print " ".join(args)
+
+
+def main(args):
+ GypBuilder(args[1:])
+
+if __name__ == "__main__":
+ main(sys.argv)
+
diff --git a/o3d/import/cross/camera_info.h b/o3d/import/cross/camera_info.h
index a221fbb..94c88a6 100644
--- a/o3d/import/cross/camera_info.h
+++ b/o3d/import/cross/camera_info.h
@@ -1,221 +1,221 @@
-/*
- * 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 declares the CameraInfo class.
-
-#ifndef O3D_IMPORT_CROSS_CAMERA_INFO_H_
-#define O3D_IMPORT_CROSS_CAMERA_INFO_H_
-
-#include "import/cross/json_object.h"
-
-namespace o3d {
-
-// CameraInfo is a used for serialization only and is not part of the
-// normal O3D plugin. It is used for information about the camera.
-class CameraInfo : public JSONObject {
- public:
- typedef SmartPointer<CameraInfo> Ref;
-
- static const char* kAspectRatioParamName;
- static const char* kNearZParamName;
- static const char* kFarZParamName;
- static const char* kTransformValueName;
- static const char* kEyeValueName;
- static const char* kTargetValueName;
- static const char* kUpValueName;
-
- // Gets the near_z.
- float near_z() const {
- return near_z_param_->value();
- }
-
- // Sets the near_z.
- void set_near_z(float value) {
- near_z_param_->set_value(value);
- }
-
- // Gets the far_z.
- float far_z() const {
- return far_z_param_->value();
- }
-
- // Sets the far_z.
- void set_far_z(float value) {
- far_z_param_->set_value(value);
- }
-
- // Gets the aspect_ratio.
- float aspect_ratio() const {
- return aspect_ratio_param_->value();
- }
-
- // Sets the aspect_ratio.
- void set_aspect_ratio(float value) {
- aspect_ratio_param_->set_value(value);
- }
-
- // Gets the transform.
- Transform* transform() const {
- return transform_value_->value();
- }
-
- // Sets the transform.
- void set_transform(Transform* value) {
- transform_value_->set_value(value);
- }
-
- // Gets the eye.
- Float3 eye() const {
- return eye_value_->value();
- }
-
- // Sets the eye.
- void set_eye(const Float3& value) {
- eye_value_->set_value(value);
- }
-
- // Gets the target.
- Float3 target() const {
- return target_value_->value();
- }
-
- // Sets the target.
- void set_target(const Float3& value) {
- target_value_->set_value(value);
- }
-
- // Gets the up.
- Float3 up() const {
- return up_value_->value();
- }
-
- // Sets the up.
- void set_up(const Float3& value) {
- up_value_->set_value(value);
- }
-
- protected:
- explicit CameraInfo(ServiceLocator* service_locator);
-
- private:
- // We make these params so we can easily attach animation to the camera's
- // parameters.
- ParamFloat::Ref aspect_ratio_param_;
- ParamFloat::Ref near_z_param_;
- ParamFloat::Ref far_z_param_;
-
- // These are not params, just JSON values.
- JSONTransform::Ref transform_value_;
- JSONOptionalFloat3::Ref eye_value_;
- JSONOptionalFloat3::Ref target_value_;
- JSONOptionalFloat3::Ref up_value_;
-
- O3D_OBJECT_BASE_DECL_CLASS(CameraInfo, JSONObject);
- DISALLOW_COPY_AND_ASSIGN(CameraInfo);
-};
-
-class OrthographicCameraInfo : public CameraInfo {
- public:
- typedef SmartPointer<OrthographicCameraInfo> Ref;
-
- static const char* kMagXParamName;
- static const char* kMagYParamName;
-
- // Gets the mag_x.
- float mag_x() const {
- return mag_x_param_->value();
- }
-
- // Sets the mag_x.
- void set_mag_x(float value) {
- mag_x_param_->set_value(value);
- }
-
- // Gets the mag_y.
- float mag_y() const {
- return mag_y_param_->value();
- }
-
- // Sets the mag_y.
- void set_mag_y(float value) {
- mag_y_param_->set_value(value);
- }
-
- private:
- explicit OrthographicCameraInfo(ServiceLocator* service_locator);
-
- friend class IClassManager;
- static ObjectBase::Ref Create(ServiceLocator* service_locator);
-
- // We make these params so we can easily attach animation to the camera's
- // parameters.
- ParamFloat::Ref mag_x_param_;
- ParamFloat::Ref mag_y_param_;
-
- O3D_OBJECT_BASE_DECL_CLASS(OrthographicCameraInfo, CameraInfo);
- DISALLOW_COPY_AND_ASSIGN(OrthographicCameraInfo);
-};
-
-class PerspectiveCameraInfo : public CameraInfo {
- public:
- typedef SmartPointer<PerspectiveCameraInfo> Ref;
-
- static const char* kFieldOfViewYParamName;
-
- // Gets the field_of_view_y.
- float field_of_view_y() const {
- return field_of_view_y_param_->value();
- }
-
- // Sets the field_of_view_y.
- void set_field_of_view_y(float value) {
- field_of_view_y_param_->set_value(value);
- }
-
- private:
- explicit PerspectiveCameraInfo(ServiceLocator* service_locator);
-
- friend class IClassManager;
- static ObjectBase::Ref Create(ServiceLocator* service_locator);
-
- // We make these params so we can easily attach animation to the camera's
- // parameters.
- ParamFloat::Ref field_of_view_y_param_;
-
- O3D_OBJECT_BASE_DECL_CLASS(PerspectiveCameraInfo, CameraInfo);
- DISALLOW_COPY_AND_ASSIGN(PerspectiveCameraInfo);
-};
-
-} // namespace o3d
-
-#endif // O3D_IMPORT_CROSS_CAMERA_INFO_H_
-
+/*
+ * 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 declares the CameraInfo class.
+
+#ifndef O3D_IMPORT_CROSS_CAMERA_INFO_H_
+#define O3D_IMPORT_CROSS_CAMERA_INFO_H_
+
+#include "import/cross/json_object.h"
+
+namespace o3d {
+
+// CameraInfo is a used for serialization only and is not part of the
+// normal O3D plugin. It is used for information about the camera.
+class CameraInfo : public JSONObject {
+ public:
+ typedef SmartPointer<CameraInfo> Ref;
+
+ static const char* kAspectRatioParamName;
+ static const char* kNearZParamName;
+ static const char* kFarZParamName;
+ static const char* kTransformValueName;
+ static const char* kEyeValueName;
+ static const char* kTargetValueName;
+ static const char* kUpValueName;
+
+ // Gets the near_z.
+ float near_z() const {
+ return near_z_param_->value();
+ }
+
+ // Sets the near_z.
+ void set_near_z(float value) {
+ near_z_param_->set_value(value);
+ }
+
+ // Gets the far_z.
+ float far_z() const {
+ return far_z_param_->value();
+ }
+
+ // Sets the far_z.
+ void set_far_z(float value) {
+ far_z_param_->set_value(value);
+ }
+
+ // Gets the aspect_ratio.
+ float aspect_ratio() const {
+ return aspect_ratio_param_->value();
+ }
+
+ // Sets the aspect_ratio.
+ void set_aspect_ratio(float value) {
+ aspect_ratio_param_->set_value(value);
+ }
+
+ // Gets the transform.
+ Transform* transform() const {
+ return transform_value_->value();
+ }
+
+ // Sets the transform.
+ void set_transform(Transform* value) {
+ transform_value_->set_value(value);
+ }
+
+ // Gets the eye.
+ Float3 eye() const {
+ return eye_value_->value();
+ }
+
+ // Sets the eye.
+ void set_eye(const Float3& value) {
+ eye_value_->set_value(value);
+ }
+
+ // Gets the target.
+ Float3 target() const {
+ return target_value_->value();
+ }
+
+ // Sets the target.
+ void set_target(const Float3& value) {
+ target_value_->set_value(value);
+ }
+
+ // Gets the up.
+ Float3 up() const {
+ return up_value_->value();
+ }
+
+ // Sets the up.
+ void set_up(const Float3& value) {
+ up_value_->set_value(value);
+ }
+
+ protected:
+ explicit CameraInfo(ServiceLocator* service_locator);
+
+ private:
+ // We make these params so we can easily attach animation to the camera's
+ // parameters.
+ ParamFloat::Ref aspect_ratio_param_;
+ ParamFloat::Ref near_z_param_;
+ ParamFloat::Ref far_z_param_;
+
+ // These are not params, just JSON values.
+ JSONTransform::Ref transform_value_;
+ JSONOptionalFloat3::Ref eye_value_;
+ JSONOptionalFloat3::Ref target_value_;
+ JSONOptionalFloat3::Ref up_value_;
+
+ O3D_OBJECT_BASE_DECL_CLASS(CameraInfo, JSONObject);
+ DISALLOW_COPY_AND_ASSIGN(CameraInfo);
+};
+
+class OrthographicCameraInfo : public CameraInfo {
+ public:
+ typedef SmartPointer<OrthographicCameraInfo> Ref;
+
+ static const char* kMagXParamName;
+ static const char* kMagYParamName;
+
+ // Gets the mag_x.
+ float mag_x() const {
+ return mag_x_param_->value();
+ }
+
+ // Sets the mag_x.
+ void set_mag_x(float value) {
+ mag_x_param_->set_value(value);
+ }
+
+ // Gets the mag_y.
+ float mag_y() const {
+ return mag_y_param_->value();
+ }
+
+ // Sets the mag_y.
+ void set_mag_y(float value) {
+ mag_y_param_->set_value(value);
+ }
+
+ private:
+ explicit OrthographicCameraInfo(ServiceLocator* service_locator);
+
+ friend class IClassManager;
+ static ObjectBase::Ref Create(ServiceLocator* service_locator);
+
+ // We make these params so we can easily attach animation to the camera's
+ // parameters.
+ ParamFloat::Ref mag_x_param_;
+ ParamFloat::Ref mag_y_param_;
+
+ O3D_OBJECT_BASE_DECL_CLASS(OrthographicCameraInfo, CameraInfo);
+ DISALLOW_COPY_AND_ASSIGN(OrthographicCameraInfo);
+};
+
+class PerspectiveCameraInfo : public CameraInfo {
+ public:
+ typedef SmartPointer<PerspectiveCameraInfo> Ref;
+
+ static const char* kFieldOfViewYParamName;
+
+ // Gets the field_of_view_y.
+ float field_of_view_y() const {
+ return field_of_view_y_param_->value();
+ }
+
+ // Sets the field_of_view_y.
+ void set_field_of_view_y(float value) {
+ field_of_view_y_param_->set_value(value);
+ }
+
+ private:
+ explicit PerspectiveCameraInfo(ServiceLocator* service_locator);
+
+ friend class IClassManager;
+ static ObjectBase::Ref Create(ServiceLocator* service_locator);
+
+ // We make these params so we can easily attach animation to the camera's
+ // parameters.
+ ParamFloat::Ref field_of_view_y_param_;
+
+ O3D_OBJECT_BASE_DECL_CLASS(PerspectiveCameraInfo, CameraInfo);
+ DISALLOW_COPY_AND_ASSIGN(PerspectiveCameraInfo);
+};
+
+} // namespace o3d
+
+#endif // O3D_IMPORT_CROSS_CAMERA_INFO_H_
+
diff --git a/o3d/import/cross/destination_buffer.h b/o3d/import/cross/destination_buffer.h
index 5b12e34..8b4b5d2 100644
--- a/o3d/import/cross/destination_buffer.h
+++ b/o3d/import/cross/destination_buffer.h
@@ -1,83 +1,83 @@
-/*
- * 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 declares the DestinationBuffer class.
-
-#ifndef O3D_IMPORT_CROSS_DESTINATION_BUFFER_H_
-#define O3D_IMPORT_CROSS_DESTINATION_BUFFER_H_
-
-#include "core/cross/buffer.h"
-
-namespace o3d {
-
-// DestinationBuffer is a used for serialization only and is not part of the
-// normal O3D plugin. It is used for Skinning to distinguish between a normal
-// VertexBuffer that needs to have its contents serialized and a
-// DestinationBuffer that only needs to know its structure but not its
-// contents.
-class DestinationBuffer : public VertexBuffer {
- public:
- typedef SmartPointer<DestinationBuffer> Ref;
-
- ~DestinationBuffer();
-
- protected:
- // Overridden from Buffer.
- virtual bool ConcreteAllocate(size_t size_in_bytes);
-
- // Overridden from Buffer.
- virtual bool ConcreteLock(AccessMode access_mode, void **buffer_data);
-
- // Overridden from Buffer.
- virtual bool ConcreteUnlock();
-
- explicit DestinationBuffer(ServiceLocator* service_locator);
-
- protected:
- // Frees the buffer if it exists.
- void ConcreteFree();
-
- private:
- friend class IClassManager;
- static ObjectBase::Ref Create(ServiceLocator* service_locator);
-
- scoped_array<char> buffer_; // The actual data for this buffer.
-
- O3D_OBJECT_BASE_DECL_CLASS(DestinationBuffer, VertexBuffer);
- DISALLOW_COPY_AND_ASSIGN(DestinationBuffer);
-};
-
-
-} // namespace o3d
-
-#endif // O3D_IMPORT_CROSS_DESTINATION_BUFFER_H_
-
+/*
+ * 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 declares the DestinationBuffer class.
+
+#ifndef O3D_IMPORT_CROSS_DESTINATION_BUFFER_H_
+#define O3D_IMPORT_CROSS_DESTINATION_BUFFER_H_
+
+#include "core/cross/buffer.h"
+
+namespace o3d {
+
+// DestinationBuffer is a used for serialization only and is not part of the
+// normal O3D plugin. It is used for Skinning to distinguish between a normal
+// VertexBuffer that needs to have its contents serialized and a
+// DestinationBuffer that only needs to know its structure but not its
+// contents.
+class DestinationBuffer : public VertexBuffer {
+ public:
+ typedef SmartPointer<DestinationBuffer> Ref;
+
+ ~DestinationBuffer();
+
+ protected:
+ // Overridden from Buffer.
+ virtual bool ConcreteAllocate(size_t size_in_bytes);
+
+ // Overridden from Buffer.
+ virtual bool ConcreteLock(AccessMode access_mode, void **buffer_data);
+
+ // Overridden from Buffer.
+ virtual bool ConcreteUnlock();
+
+ explicit DestinationBuffer(ServiceLocator* service_locator);
+
+ protected:
+ // Frees the buffer if it exists.
+ void ConcreteFree();
+
+ private:
+ friend class IClassManager;
+ static ObjectBase::Ref Create(ServiceLocator* service_locator);
+
+ scoped_array<char> buffer_; // The actual data for this buffer.
+
+ O3D_OBJECT_BASE_DECL_CLASS(DestinationBuffer, VertexBuffer);
+ DISALLOW_COPY_AND_ASSIGN(DestinationBuffer);
+};
+
+
+} // namespace o3d
+
+#endif // O3D_IMPORT_CROSS_DESTINATION_BUFFER_H_
+
diff --git a/o3d/import/cross/json_object.h b/o3d/import/cross/json_object.h
index 3cf2815..a4c153a 100644
--- a/o3d/import/cross/json_object.h
+++ b/o3d/import/cross/json_object.h
@@ -1,289 +1,289 @@
-/*
- * 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 declares the JSONObject class.
-
-#ifndef O3D_IMPORT_CROSS_JSON_OBJECT_H_
-#define O3D_IMPORT_CROSS_JSON_OBJECT_H_
-
-#include <map>
-#include "core/cross/param_object.h"
-#include "core/cross/material.h"
-#include "core/cross/transform.h"
-#include "serializer/cross/serializer.h"
-
-namespace o3d {
-
-class StructuredWriter;
-
-// A JSONValue is a base class for all JSON values stored in a JSONObject.
-class JSONValue : public RefCounted {
- public:
- typedef SmartPointer<JSONValue> Ref;
-
- virtual ~JSONValue() {
- }
-
- // Whether or not this value exists.
- bool exists() const {
- return exists_;
- }
-
- // Sets the existence of this value.
- void set_exists(bool exists) {
- exists_ = exists;
- }
-
- // Function to serialize the value of this JSON value.
- virtual void Serialize(StructuredWriter* writer) const = 0;
-
- protected:
- // optional means the value is optional. If true the value defaults to
- // not existing. If false the value defaults to existing.
- explicit JSONValue(bool optional)
- : optional_(optional), exists_(!optional) {
- }
-
- private:
- bool optional_;
- bool exists_; // used for optional values.
-};
-
-// A Template for optional typed non-ref JSON values.
-template<class T, bool optional>
-class TypedJSONValue : public JSONValue {
- public:
- typedef T DataType;
- TypedJSONValue()
- : JSONValue(optional) {
- }
- virtual ~TypedJSONValue() {}
-
- // Sets the value stored in the JSONValue.
- void set_value(const DataType& value) {
- set_exists(true);
- value_ = value;
- }
-
- // Returns the current value stored in the JSONValue.
- DataType value() const {
- DCHECK(exists());
- return value_;
- }
-
- // Overridden from JSONValue.
- virtual void Serialize(StructuredWriter* writer) const {
- DCHECK(exists());
- o3d::Serialize(writer, value());
- }
-
- private:
- // The value stored in the JSONValue.
- DataType value_;
-
- DISALLOW_COPY_AND_ASSIGN(TypedJSONValue);
-};
-
-// A Template for typed ref JSON values.
-template<typename T>
-class TypedRefJSONValue : public JSONValue {
- public:
- typedef T* Pointer;
- typedef T DataType;
-
- TypedRefJSONValue()
- : JSONValue(false) {
- }
-
- virtual ~TypedRefJSONValue() {
- }
-
- // Set the value stored in the.
- void set_value(Pointer const value) {
- value_ = typename T::Ref(value);
- }
-
- // Returns the current value stored in the Param.
- Pointer value() const {
- return value_.Get();
- }
-
- // Overridden from JSONValue.
- virtual void Serialize(StructuredWriter* writer) const {
- o3d::Serialize(writer, static_cast<ObjectBase*>(value()));
- }
-
- protected:
- typename T::Ref value_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(TypedRefJSONValue);
-};
-
-// Classes for various types of JSON Data.
-class JSONFloat : public TypedJSONValue<float, false> {
- public:
- typedef SmartPointer<JSONFloat> Ref;
- JSONFloat() {
- set_value(0.0f);
- }
-};
-class JSONFloat2 : public TypedJSONValue<Float2, false> {
- public:
- typedef SmartPointer<JSONFloat2> Ref;
- JSONFloat2() {
- set_value(Float2(0.0f, 0.0f));
- }
-};
-class JSONFloat3 : public TypedJSONValue<Float3, false> {
- public:
- typedef SmartPointer<JSONFloat3> Ref;
- JSONFloat3() {
- set_value(Float3(0.0f, 0.0f, 0.0f));
- }
-};
-class JSONFloat4 : public TypedJSONValue<Float4, false> {
- public:
- typedef SmartPointer<JSONFloat4> Ref;
- JSONFloat4() {
- set_value(Float4(0.0f, 0.0f, 0.0f, 0.0f));
- }
-};
-class JSONMatrix4 : public TypedJSONValue<Matrix4, false> {
- public:
- typedef SmartPointer<JSONMatrix4> Ref;
- JSONMatrix4() {
- set_value(Matrix4::identity());
- }
-};
-class JSONInteger : public TypedJSONValue<int, false> {
- public:
- typedef SmartPointer<JSONInteger> Ref;
- JSONInteger() {
- set_value(0);
- }
-};
-class JSONBoolean : public TypedJSONValue<bool, false> {
- public:
- typedef SmartPointer<JSONBoolean> Ref;
- JSONBoolean() {
- set_value(false);
- }
-};
-class JSONString : public TypedJSONValue<String, false> {
- public:
- typedef SmartPointer<JSONString> Ref;
-};
-class JSONTransform : public TypedRefJSONValue<Transform> {
- public:
- typedef SmartPointer<JSONTransform> Ref;
-};
-class JSONMaterial : public TypedRefJSONValue<Material> {
- public:
- typedef SmartPointer<JSONMaterial> Ref;
-};
-class JSONOptionalFloat : public TypedJSONValue<float, true> {
- public:
- typedef SmartPointer<JSONOptionalFloat> Ref;
-};
-class JSONOptionalFloat2 : public TypedJSONValue<Float2, true> {
- public:
- typedef SmartPointer<JSONOptionalFloat2> Ref;
-};
-class JSONOptionalFloat3 : public TypedJSONValue<Float3, true> {
- public:
- typedef SmartPointer<JSONOptionalFloat3> Ref;
-};
-class JSONOptionalFloat4 : public TypedJSONValue<Float4, true> {
- public:
- typedef SmartPointer<JSONOptionalFloat4> Ref;
-};
-class JSONOptionalMatrix4 : public TypedJSONValue<Matrix4, true> {
- public:
- typedef SmartPointer<JSONOptionalMatrix4> Ref;
-};
-class JSONOptionalInteger : public TypedJSONValue<int, true> {
- public:
- typedef SmartPointer<JSONOptionalInteger> Ref;
-};
-class JSONOptionalBoolean : public TypedJSONValue<bool, true> {
- public:
- typedef SmartPointer<JSONOptionalBoolean> Ref;
-};
-class JSONOptionalString : public TypedJSONValue<String, true> {
- public:
- typedef SmartPointer<JSONOptionalString> Ref;
-};
-
-// A JSONObject is a used for serialization only and is not part of the normal
-// O3D plugin. It is used to easily add name/value pairs to be serialized by the
-// serializer as JSON objects. Being that it's ParamObject you have 2 choices
-// for getting data serialized. As O3D Params or as JSONValues. The reason to
-// use one over the other... Params can be animated but are relatively heavy.
-// JSONValues become plane JavaScript when deserialized.
-// To add a Param use RegisterParamRef, to add a JSONValue use
-// RegisterJSONValue.
-class JSONObject : public ParamObject {
- public:
- typedef SmartPointer<JSONObject> Ref;
- typedef std::map<String, JSONValue::Ref> NameValueMap;
-
- // Seralizes the JSONObject.
- void Serialize(StructuredWriter* writer) const;
-
- protected:
- explicit JSONObject(ServiceLocator* service_locator);
-
- // Registers a pointer to a reference to a JSONValue.
- // Parameters:
- // name: name of JSONValue
- // ref_pointer: Pointer to typed reference to JSONValue.
- template<typename T>
- void RegisterJSONValue(const String& name, T* ref_pointer) {
- *ref_pointer = T(new typename T::ClassType());
- AddProperty(name, ref_pointer->Get());
- }
-
- private:
- // Adds a property to this JSON Object.
- void AddProperty(const String& name, JSONValue* value);
-
- NameValueMap properties_;
-
- O3D_OBJECT_BASE_DECL_CLASS(JSONObject, ParamObject);
- DISALLOW_COPY_AND_ASSIGN(JSONObject);
-};
-
-} // namespace o3d
-
-#endif // O3D_IMPORT_CROSS_JSON_OBJECT_H_
-
-
+/*
+ * 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 declares the JSONObject class.
+
+#ifndef O3D_IMPORT_CROSS_JSON_OBJECT_H_
+#define O3D_IMPORT_CROSS_JSON_OBJECT_H_
+
+#include <map>
+#include "core/cross/param_object.h"
+#include "core/cross/material.h"
+#include "core/cross/transform.h"
+#include "serializer/cross/serializer.h"
+
+namespace o3d {
+
+class StructuredWriter;
+
+// A JSONValue is a base class for all JSON values stored in a JSONObject.
+class JSONValue : public RefCounted {
+ public:
+ typedef SmartPointer<JSONValue> Ref;
+
+ virtual ~JSONValue() {
+ }
+
+ // Whether or not this value exists.
+ bool exists() const {
+ return exists_;
+ }
+
+ // Sets the existence of this value.
+ void set_exists(bool exists) {
+ exists_ = exists;
+ }
+
+ // Function to serialize the value of this JSON value.
+ virtual void Serialize(StructuredWriter* writer) const = 0;
+
+ protected:
+ // optional means the value is optional. If true the value defaults to
+ // not existing. If false the value defaults to existing.
+ explicit JSONValue(bool optional)
+ : optional_(optional), exists_(!optional) {
+ }
+
+ private:
+ bool optional_;
+ bool exists_; // used for optional values.
+};
+
+// A Template for optional typed non-ref JSON values.
+template<class T, bool optional>
+class TypedJSONValue : public JSONValue {
+ public:
+ typedef T DataType;
+ TypedJSONValue()
+ : JSONValue(optional) {
+ }
+ virtual ~TypedJSONValue() {}
+
+ // Sets the value stored in the JSONValue.
+ void set_value(const DataType& value) {
+ set_exists(true);
+ value_ = value;
+ }
+
+ // Returns the current value stored in the JSONValue.
+ DataType value() const {
+ DCHECK(exists());
+ return value_;
+ }
+
+ // Overridden from JSONValue.
+ virtual void Serialize(StructuredWriter* writer) const {
+ DCHECK(exists());
+ o3d::Serialize(writer, value());
+ }
+
+ private:
+ // The value stored in the JSONValue.
+ DataType value_;
+
+ DISALLOW_COPY_AND_ASSIGN(TypedJSONValue);
+};
+
+// A Template for typed ref JSON values.
+template<typename T>
+class TypedRefJSONValue : public JSONValue {
+ public:
+ typedef T* Pointer;
+ typedef T DataType;
+
+ TypedRefJSONValue()
+ : JSONValue(false) {
+ }
+
+ virtual ~TypedRefJSONValue() {
+ }
+
+ // Set the value stored in the.
+ void set_value(Pointer const value) {
+ value_ = typename T::Ref(value);
+ }
+
+ // Returns the current value stored in the Param.
+ Pointer value() const {
+ return value_.Get();
+ }
+
+ // Overridden from JSONValue.
+ virtual void Serialize(StructuredWriter* writer) const {
+ o3d::Serialize(writer, static_cast<ObjectBase*>(value()));
+ }
+
+ protected:
+ typename T::Ref value_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TypedRefJSONValue);
+};
+
+// Classes for various types of JSON Data.
+class JSONFloat : public TypedJSONValue<float, false> {
+ public:
+ typedef SmartPointer<JSONFloat> Ref;
+ JSONFloat() {
+ set_value(0.0f);
+ }
+};
+class JSONFloat2 : public TypedJSONValue<Float2, false> {
+ public:
+ typedef SmartPointer<JSONFloat2> Ref;
+ JSONFloat2() {
+ set_value(Float2(0.0f, 0.0f));
+ }
+};
+class JSONFloat3 : public TypedJSONValue<Float3, false> {
+ public:
+ typedef SmartPointer<JSONFloat3> Ref;
+ JSONFloat3() {
+ set_value(Float3(0.0f, 0.0f, 0.0f));
+ }
+};
+class JSONFloat4 : public TypedJSONValue<Float4, false> {
+ public:
+ typedef SmartPointer<JSONFloat4> Ref;
+ JSONFloat4() {
+ set_value(Float4(0.0f, 0.0f, 0.0f, 0.0f));
+ }
+};
+class JSONMatrix4 : public TypedJSONValue<Matrix4, false> {
+ public:
+ typedef SmartPointer<JSONMatrix4> Ref;
+ JSONMatrix4() {
+ set_value(Matrix4::identity());
+ }
+};
+class JSONInteger : public TypedJSONValue<int, false> {
+ public:
+ typedef SmartPointer<JSONInteger> Ref;
+ JSONInteger() {
+ set_value(0);
+ }
+};
+class JSONBoolean : public TypedJSONValue<bool, false> {
+ public:
+ typedef SmartPointer<JSONBoolean> Ref;
+ JSONBoolean() {
+ set_value(false);
+ }
+};
+class JSONString : public TypedJSONValue<String, false> {
+ public:
+ typedef SmartPointer<JSONString> Ref;
+};
+class JSONTransform : public TypedRefJSONValue<Transform> {
+ public:
+ typedef SmartPointer<JSONTransform> Ref;
+};
+class JSONMaterial : public TypedRefJSONValue<Material> {
+ public:
+ typedef SmartPointer<JSONMaterial> Ref;
+};
+class JSONOptionalFloat : public TypedJSONValue<float, true> {
+ public:
+ typedef SmartPointer<JSONOptionalFloat> Ref;
+};
+class JSONOptionalFloat2 : public TypedJSONValue<Float2, true> {
+ public:
+ typedef SmartPointer<JSONOptionalFloat2> Ref;
+};
+class JSONOptionalFloat3 : public TypedJSONValue<Float3, true> {
+ public:
+ typedef SmartPointer<JSONOptionalFloat3> Ref;
+};
+class JSONOptionalFloat4 : public TypedJSONValue<Float4, true> {
+ public:
+ typedef SmartPointer<JSONOptionalFloat4> Ref;
+};
+class JSONOptionalMatrix4 : public TypedJSONValue<Matrix4, true> {
+ public:
+ typedef SmartPointer<JSONOptionalMatrix4> Ref;
+};
+class JSONOptionalInteger : public TypedJSONValue<int, true> {
+ public:
+ typedef SmartPointer<JSONOptionalInteger> Ref;
+};
+class JSONOptionalBoolean : public TypedJSONValue<bool, true> {
+ public:
+ typedef SmartPointer<JSONOptionalBoolean> Ref;
+};
+class JSONOptionalString : public TypedJSONValue<String, true> {
+ public:
+ typedef SmartPointer<JSONOptionalString> Ref;
+};
+
+// A JSONObject is a used for serialization only and is not part of the normal
+// O3D plugin. It is used to easily add name/value pairs to be serialized by the
+// serializer as JSON objects. Being that it's ParamObject you have 2 choices
+// for getting data serialized. As O3D Params or as JSONValues. The reason to
+// use one over the other... Params can be animated but are relatively heavy.
+// JSONValues become plane JavaScript when deserialized.
+// To add a Param use RegisterParamRef, to add a JSONValue use
+// RegisterJSONValue.
+class JSONObject : public ParamObject {
+ public:
+ typedef SmartPointer<JSONObject> Ref;
+ typedef std::map<String, JSONValue::Ref> NameValueMap;
+
+ // Seralizes the JSONObject.
+ void Serialize(StructuredWriter* writer) const;
+
+ protected:
+ explicit JSONObject(ServiceLocator* service_locator);
+
+ // Registers a pointer to a reference to a JSONValue.
+ // Parameters:
+ // name: name of JSONValue
+ // ref_pointer: Pointer to typed reference to JSONValue.
+ template<typename T>
+ void RegisterJSONValue(const String& name, T* ref_pointer) {
+ *ref_pointer = T(new typename T::ClassType());
+ AddProperty(name, ref_pointer->Get());
+ }
+
+ private:
+ // Adds a property to this JSON Object.
+ void AddProperty(const String& name, JSONValue* value);
+
+ NameValueMap properties_;
+
+ O3D_OBJECT_BASE_DECL_CLASS(JSONObject, ParamObject);
+ DISALLOW_COPY_AND_ASSIGN(JSONObject);
+};
+
+} // namespace o3d
+
+#endif // O3D_IMPORT_CROSS_JSON_OBJECT_H_
+
+
diff --git a/o3d/plugin/idl/bitmap.idl b/o3d/plugin/idl/bitmap.idl
index b2fd6b6..7eb07f2 100644
--- a/o3d/plugin/idl/bitmap.idl
+++ b/o3d/plugin/idl/bitmap.idl
@@ -1,112 +1,112 @@
-/*
- * 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.
- */
-
-
-namespace o3d {
-
-%[
- Bitmap provides an interface for basic image operations on bitmap,
- including scale and crop. A Bitmap can be created from RawData via
- pack.createBitmapsFromRawData(), and also can be transferred to mip of a
- Texure2D or a specific face of TextureCUBE via methods in Texture.
-%]
-
-[nocpp, include="core/cross/bitmap.h"]
-class Bitmap : ParamObject {
- %[
- After loading an array of Bitmaps with pack.createBitmapsFromRawData
- you can inspect their semantic to see what they were intended for. This is
- mostly to distinguish between 6 bitmaps that are faces of a cubemap and 6
- bitmaps that are slices of a 3d texture.
-
- \li FACE_POSITIVE_X, 1 face of a cubemap
- \li FACE_NEGATIVE_X, 1 face of a cubemap
- \li FACE_POSITIVE_Y, 1 face of a cubemap
- \li FACE_NEGATIVE_Y, 1 face of a cubemap
- \li FACE_POSITIVE_Z, 1 face of a cubemap
- \li FACE_NEGATIVE_Z, 1 face of a cubemap
- \li IMAGE, normal 2d image
- \li SLICE, a slice of a 3d texture.
- %]
- enum Semantic {
- FACE_POSITIVE_X,
- FACE_NEGATIVE_X,
- FACE_POSITIVE_Y,
- FACE_NEGATIVE_Y,
- FACE_POSITIVE_Z,
- FACE_NEGATIVE_Z,
- IMAGE,
- SLICE
- };
-
- %[
- Flips a bitmap vertically in place.
- %]
- void FlipVertically();
-
- %[
- Generates mip maps from the source level to lower levels.
-
- You can not currently generate mips for DXT textures although you can load
- them from dds files.
-
- \param source_level The level to use as the source of the mips.
- \param num_levels The number of levels to generate below the source level.
- %]
- void GenerateMips(int source_level, int num_levels);
-
- %[
- The width of the bitmap (read only).
- %]
- [getter] int width_;
-
- %[
- The height of the bitmap (read only).
- %]
- [getter] int height_;
-
- %[
- The format of the bitmap (read only).
- %]
- [getter] Texture::Format format_;
-
- %[
- Number mip-maps (read only)
- %]
- [getter] int num_mipmaps_;
-
- %[
- The Semantic of the bitmap.
- %]
- [getter] Semantic semantic_;
-}; // Bitmap
-
-} // namespace o3d
+/*
+ * 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.
+ */
+
+
+namespace o3d {
+
+%[
+ Bitmap provides an interface for basic image operations on bitmap,
+ including scale and crop. A Bitmap can be created from RawData via
+ pack.createBitmapsFromRawData(), and also can be transferred to mip of a
+ Texure2D or a specific face of TextureCUBE via methods in Texture.
+%]
+
+[nocpp, include="core/cross/bitmap.h"]
+class Bitmap : ParamObject {
+ %[
+ After loading an array of Bitmaps with pack.createBitmapsFromRawData
+ you can inspect their semantic to see what they were intended for. This is
+ mostly to distinguish between 6 bitmaps that are faces of a cubemap and 6
+ bitmaps that are slices of a 3d texture.
+
+ \li FACE_POSITIVE_X, 1 face of a cubemap
+ \li FACE_NEGATIVE_X, 1 face of a cubemap
+ \li FACE_POSITIVE_Y, 1 face of a cubemap
+ \li FACE_NEGATIVE_Y, 1 face of a cubemap
+ \li FACE_POSITIVE_Z, 1 face of a cubemap
+ \li FACE_NEGATIVE_Z, 1 face of a cubemap
+ \li IMAGE, normal 2d image
+ \li SLICE, a slice of a 3d texture.
+ %]
+ enum Semantic {
+ FACE_POSITIVE_X,
+ FACE_NEGATIVE_X,
+ FACE_POSITIVE_Y,
+ FACE_NEGATIVE_Y,
+ FACE_POSITIVE_Z,
+ FACE_NEGATIVE_Z,
+ IMAGE,
+ SLICE
+ };
+
+ %[
+ Flips a bitmap vertically in place.
+ %]
+ void FlipVertically();
+
+ %[
+ Generates mip maps from the source level to lower levels.
+
+ You can not currently generate mips for DXT textures although you can load
+ them from dds files.
+
+ \param source_level The level to use as the source of the mips.
+ \param num_levels The number of levels to generate below the source level.
+ %]
+ void GenerateMips(int source_level, int num_levels);
+
+ %[
+ The width of the bitmap (read only).
+ %]
+ [getter] int width_;
+
+ %[
+ The height of the bitmap (read only).
+ %]
+ [getter] int height_;
+
+ %[
+ The format of the bitmap (read only).
+ %]
+ [getter] Texture::Format format_;
+
+ %[
+ Number mip-maps (read only)
+ %]
+ [getter] int num_mipmaps_;
+
+ %[
+ The Semantic of the bitmap.
+ %]
+ [getter] Semantic semantic_;
+}; // Bitmap
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/get_idl_files.py b/o3d/plugin/idl/get_idl_files.py
index b0cbbcb..bf330b6 100644
--- a/o3d/plugin/idl/get_idl_files.py
+++ b/o3d/plugin/idl/get_idl_files.py
@@ -1,26 +1,26 @@
-#!/usr/bin/env python
-# Copyright (c) 2009 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Helper script to generate file lists for idl.gyp."""
-
-import os.path
-import sys
-import types
-
-
-# Read in the manifest files (which are just really simple python files),
-# and scrape out the file lists.
-def main(argv):
- idl_list_filename = os.path.join('..', 'idl_list.manifest')
- files = eval(open(idl_list_filename, "r").read())
- files = [os.path.basename(f) for f in files]
- files.sort()
- for file in files:
- # gyp wants paths with slashes, not backslashes.
- print file.replace("\\", "/")
-
-
-if __name__ == "__main__":
- main(sys.argv[1:])
+#!/usr/bin/env python
+# Copyright (c) 2009 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Helper script to generate file lists for idl.gyp."""
+
+import os.path
+import sys
+import types
+
+
+# Read in the manifest files (which are just really simple python files),
+# and scrape out the file lists.
+def main(argv):
+ idl_list_filename = os.path.join('..', 'idl_list.manifest')
+ files = eval(open(idl_list_filename, "r").read())
+ files = [os.path.basename(f) for f in files]
+ files.sort()
+ for file in files:
+ # gyp wants paths with slashes, not backslashes.
+ print file.replace("\\", "/")
+
+
+if __name__ == "__main__":
+ main(sys.argv[1:])
diff --git a/o3d/samples/GoogleIO-2009/assets/style.css b/o3d/samples/GoogleIO-2009/assets/style.css
index 71fc441..2c4a145 100644
--- a/o3d/samples/GoogleIO-2009/assets/style.css
+++ b/o3d/samples/GoogleIO-2009/assets/style.css
@@ -1,8 +1,8 @@
-html, body {
- height: 100%;
- margin: 0;
- padding: 0;
- border: none;
- font-family: Arial, sans-serif;
-}
-
+html, body {
+ height: 100%;
+ margin: 0;
+ padding: 0;
+ border: none;
+ font-family: Arial, sans-serif;
+}
+
diff --git a/o3d/samples/bitmap-draw-image.html b/o3d/samples/bitmap-draw-image.html
index 0a05b73..e4daea6 100644
--- a/o3d/samples/bitmap-draw-image.html
+++ b/o3d/samples/bitmap-draw-image.html
@@ -1,247 +1,247 @@
-<!--
-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.
--->
-
-<!--
-In this tutorial, we show how to create bitmaps and how to draw
-images on both bitmaps and textures.
--->
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
- "http://www.w3.org/TR/html4/loose.dtd">
-<html>
-<head>
-<meta http-equiv="content-type" content="text/html; charset=UTF-8">
-<title>
-Bitmap Draw Image Demo
-</title>
-<script type="text/javascript" src="o3djs/base.js"></script>
-<script type="text/javascript" id="o3dscript">
-o3djs.require('o3djs.util');
-o3djs.require('o3djs.math');
-o3djs.require('o3djs.loader');
-o3djs.require('o3djs.rendergraph');
-o3djs.require('o3djs.primitives');
-o3djs.require('o3djs.material');
-
-// Events
-// Run the init() once the page has finished loading.
-window.onload = init;
-
-// global variables
-var g_o3d;
-var g_math;
-var g_client;
-var g_pack;
-var g_viewInfo;
-var g_finished = false; // for selenium testing
-var g_eye;
-var g_target;
-var g_up;
-var g_bitmaps = []; // bitmaps by URL.
-
-function makeShape(texture) {
- // Create a material.
- var myMaterial = o3djs.material.createMaterialFromFile(
- g_pack,
- 'shaders/texture-only.shader',
- g_viewInfo.performanceDrawList);
-
- // Creates a quad.
- var myShape = o3djs.primitives.createPlane(g_pack,
- myMaterial,
- 3, // width
- 3, // height
- 1, // quads across
- 1); // quads down
-
- // Get the material's sampler parameter, get the sampler on it and set its
- // texture.
- var sampler_param = myMaterial.getParam('texSampler0');
- var sampler = sampler_param.value;
-
- // Set the texture to use.
- sampler.texture = texture;
-
- // adjust the scale of our transform to match the aspect ratio of
- // the texture. Of course we could also have waited until now to build
- // our plane and set its width and height to match instead of scaling
- // here.
- var textureWidth = texture.width;
- var textureHeight = texture.height;
- var hScale = 1;
- var vScale = 1;
- if (textureWidth > textureHeight) {
- vScale = textureHeight / textureWidth;
- } else if (textureHeight > textureWidth) {
- hScale = textureWidth / textureHeight;
- }
- // We now attach our quad to the root of the transform graph.
- // We do this after the texture has loaded, otherwise we'd be attempting
- // to display something invalid.
-
- // Make a transform for each quad.
- var transform = g_pack.createObject('Transform');
- transform.scale(hScale, 1, vScale);
- transform.addShape(myShape);
- transform.parent = g_client.root;
- g_finished = true;
- return myShape;
-}
-
-function loadBitmap(loader, url) {
- loader.loadBitmaps(g_pack, o3djs.util.getAbsoluteURI('assets/' + url),
- function(bitmaps, exception) {
- if (!exception) {
- // We know we are only loading 2D images so there will only be 1 bitmap.
- g_bitmaps[url] = bitmaps[0];
- } else {
- alert(exception);
- }
- });
-
-}
-
-/**
- * Creates the client area.
- */
-function init() {
- o3djs.util.makeClients(initStep2, 'NotAntiAliased');
-}
-
-/**
- * Initializes O3D, loads the effect, and loads a tar.gz archive containing
- * a bunch of image files. We'll create bitmaps from them.
- * And use drawImage function to create texture as well as mipmaps.
- */
-function initStep2(clientElements) {
- // Initialize global variables and libraries.
- var o3dElement = clientElements[0];
- g_o3d = o3dElement.o3d;
- g_math = o3djs.math;
- g_client = o3dElement.client;
-
- // Create a pack to manage our resources/assets
- g_pack = g_client.createPack();
-
- // Create the render graph for a view.
- g_viewInfo = o3djs.rendergraph.createBasicView(
- g_pack,
- g_client.root,
- g_client.renderGraphRoot);
-
- // Set up an perspective projection.
- var proj_matrix = g_math.matrix4.perspective(
- g_math.degToRad(90),
- g_client.width / g_client.height,
- 0.1,
- 100);
-
- // Create the view matrix which tells the camera which way to point to.
- g_eye = [0, 1.5, 0];
- g_target = [0, 0, 0];
- g_up = [0, 0, -1];
- var view_matrix = g_math.matrix4.lookAt(g_eye, g_target, g_up);
-
- g_viewInfo.drawContext.view = view_matrix;
- g_viewInfo.drawContext.projection = proj_matrix;
-
- var loader = o3djs.loader.createLoader(callback);
- loadBitmap(loader, 'shaving_cream_300x300.jpg');
- loadBitmap(loader, 'four_pixel.png');
- loadBitmap(loader, 'hi.jpg');
- loader.finish();
-
- // Callback that happens when loader.finish() is called and all of
- // our textures have finished loading.
- function callback() {
- // Because bitmaps have their origin at the upper left, and in
- // this sample our plane is oriented with the texture coordinate
- // origin on the lower left, we need to flip all the bitmaps
- // vertically to match coordinate systems.
- var kids = g_bitmaps['shaving_cream_300x300.jpg'];
- kids.flipVertically();
- var four_square = g_bitmaps['four_pixel.png'];
- four_square.flipVertically();
- var label = g_bitmaps['hi.jpg'];
- label.flipVertically();
-
- var texture = g_pack.createTexture2D(300, 300, g_o3d.Texture.XRGB8, 0,
- false);
- // Draw bitmaps on the texture.
- // Scale down entire image into on lower left corner.
- texture.drawImage(kids, 0, 0, 0, 300, 300, 0, 0, 0, 150, 150);
-
- // Crop and scale up into the lower right corner.
- texture.drawImage(kids, 0, 0, 156, 100, 100, 0, 150, 0, 150, 150);
-
- // Flip and draw part of the image in the top left corner (and
- // texture coords are not inclusive -- they go from 0-299 for a
- // 300 pixel texture).
- texture.drawImage(kids, 0, 150, 150, 150, 150, 0, 149, 299, -150, -150);
-
- // Crop and draw cropped area in upper right corner, but we're
- // using a width and height that go beyond the edges of the image.
- texture.drawImage(kids, 0, 150, 150, 400, 400, 0, 150, 150, 400, 400);
-
- // Draw "O3D" label.
- texture.drawImage(label, 0, 0, 0, 100, 50, 0, 100, 125, 100, 50);
-
- // Fill in different mip-map levels with images that show at
- // different distances. (Scroll the mouse wheel to see).
-
- // Fill in medium level with whole image.
- texture.drawImage(kids, 0, 0, 0, 300, 300, 1, 0, 0, 150, 150);
-
- // Fill in smaller level with four pixel image.
- texture.drawImage(four_square, 0, 0, 0, 2, 2, 2, 0, 0, 75, 75);
-
- makeShape(texture);
- }
- o3djs.event.addEventListener(o3dElement, 'wheel', scrollMe);
-}
-
-function scrollMe(e) {
- g_eye = g_math.mulScalarVector((e.deltaY < 0 ? 11 : 13) / 12, g_eye);
- g_viewInfo.drawContext.view = g_math.matrix4.lookAt(g_eye, g_target, g_up);
-}
-</script>
-</head>
-<body>
-<h1>Bitmap Draw Image Demo</h1>
-This tutorial shows how to create bitmaps and how to draw images
-on both bitmaps and texture mipmaps.
-<br/>
-Scroll wheel to see different mipmaps.
-<br/>
-<!-- Start of O3D plugin -->
-<div id="o3d" style="width: 600px; height: 600px"></div>
-<!-- End of O3D plugin -->
-</body>
+<!--
+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.
+-->
+
+<!--
+In this tutorial, we show how to create bitmaps and how to draw
+images on both bitmaps and textures.
+-->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<title>
+Bitmap Draw Image Demo
+</title>
+<script type="text/javascript" src="o3djs/base.js"></script>
+<script type="text/javascript" id="o3dscript">
+o3djs.require('o3djs.util');
+o3djs.require('o3djs.math');
+o3djs.require('o3djs.loader');
+o3djs.require('o3djs.rendergraph');
+o3djs.require('o3djs.primitives');
+o3djs.require('o3djs.material');
+
+// Events
+// Run the init() once the page has finished loading.
+window.onload = init;
+
+// global variables
+var g_o3d;
+var g_math;
+var g_client;
+var g_pack;
+var g_viewInfo;
+var g_finished = false; // for selenium testing
+var g_eye;
+var g_target;
+var g_up;
+var g_bitmaps = []; // bitmaps by URL.
+
+function makeShape(texture) {
+ // Create a material.
+ var myMaterial = o3djs.material.createMaterialFromFile(
+ g_pack,
+ 'shaders/texture-only.shader',
+ g_viewInfo.performanceDrawList);
+
+ // Creates a quad.
+ var myShape = o3djs.primitives.createPlane(g_pack,
+ myMaterial,
+ 3, // width
+ 3, // height
+ 1, // quads across
+ 1); // quads down
+
+ // Get the material's sampler parameter, get the sampler on it and set its
+ // texture.
+ var sampler_param = myMaterial.getParam('texSampler0');
+ var sampler = sampler_param.value;
+
+ // Set the texture to use.
+ sampler.texture = texture;
+
+ // adjust the scale of our transform to match the aspect ratio of
+ // the texture. Of course we could also have waited until now to build
+ // our plane and set its width and height to match instead of scaling
+ // here.
+ var textureWidth = texture.width;
+ var textureHeight = texture.height;
+ var hScale = 1;
+ var vScale = 1;
+ if (textureWidth > textureHeight) {
+ vScale = textureHeight / textureWidth;
+ } else if (textureHeight > textureWidth) {
+ hScale = textureWidth / textureHeight;
+ }
+ // We now attach our quad to the root of the transform graph.
+ // We do this after the texture has loaded, otherwise we'd be attempting
+ // to display something invalid.
+
+ // Make a transform for each quad.
+ var transform = g_pack.createObject('Transform');
+ transform.scale(hScale, 1, vScale);
+ transform.addShape(myShape);
+ transform.parent = g_client.root;
+ g_finished = true;
+ return myShape;
+}
+
+function loadBitmap(loader, url) {
+ loader.loadBitmaps(g_pack, o3djs.util.getAbsoluteURI('assets/' + url),
+ function(bitmaps, exception) {
+ if (!exception) {
+ // We know we are only loading 2D images so there will only be 1 bitmap.
+ g_bitmaps[url] = bitmaps[0];
+ } else {
+ alert(exception);
+ }
+ });
+
+}
+
+/**
+ * Creates the client area.
+ */
+function init() {
+ o3djs.util.makeClients(initStep2, 'NotAntiAliased');
+}
+
+/**
+ * Initializes O3D, loads the effect, and loads a tar.gz archive containing
+ * a bunch of image files. We'll create bitmaps from them.
+ * And use drawImage function to create texture as well as mipmaps.
+ */
+function initStep2(clientElements) {
+ // Initialize global variables and libraries.
+ var o3dElement = clientElements[0];
+ g_o3d = o3dElement.o3d;
+ g_math = o3djs.math;
+ g_client = o3dElement.client;
+
+ // Create a pack to manage our resources/assets
+ g_pack = g_client.createPack();
+
+ // Create the render graph for a view.
+ g_viewInfo = o3djs.rendergraph.createBasicView(
+ g_pack,
+ g_client.root,
+ g_client.renderGraphRoot);
+
+ // Set up an perspective projection.
+ var proj_matrix = g_math.matrix4.perspective(
+ g_math.degToRad(90),
+ g_client.width / g_client.height,
+ 0.1,
+ 100);
+
+ // Create the view matrix which tells the camera which way to point to.
+ g_eye = [0, 1.5, 0];
+ g_target = [0, 0, 0];
+ g_up = [0, 0, -1];
+ var view_matrix = g_math.matrix4.lookAt(g_eye, g_target, g_up);
+
+ g_viewInfo.drawContext.view = view_matrix;
+ g_viewInfo.drawContext.projection = proj_matrix;
+
+ var loader = o3djs.loader.createLoader(callback);
+ loadBitmap(loader, 'shaving_cream_300x300.jpg');
+ loadBitmap(loader, 'four_pixel.png');
+ loadBitmap(loader, 'hi.jpg');
+ loader.finish();
+
+ // Callback that happens when loader.finish() is called and all of
+ // our textures have finished loading.
+ function callback() {
+ // Because bitmaps have their origin at the upper left, and in
+ // this sample our plane is oriented with the texture coordinate
+ // origin on the lower left, we need to flip all the bitmaps
+ // vertically to match coordinate systems.
+ var kids = g_bitmaps['shaving_cream_300x300.jpg'];
+ kids.flipVertically();
+ var four_square = g_bitmaps['four_pixel.png'];
+ four_square.flipVertically();
+ var label = g_bitmaps['hi.jpg'];
+ label.flipVertically();
+
+ var texture = g_pack.createTexture2D(300, 300, g_o3d.Texture.XRGB8, 0,
+ false);
+ // Draw bitmaps on the texture.
+ // Scale down entire image into on lower left corner.
+ texture.drawImage(kids, 0, 0, 0, 300, 300, 0, 0, 0, 150, 150);
+
+ // Crop and scale up into the lower right corner.
+ texture.drawImage(kids, 0, 0, 156, 100, 100, 0, 150, 0, 150, 150);
+
+ // Flip and draw part of the image in the top left corner (and
+ // texture coords are not inclusive -- they go from 0-299 for a
+ // 300 pixel texture).
+ texture.drawImage(kids, 0, 150, 150, 150, 150, 0, 149, 299, -150, -150);
+
+ // Crop and draw cropped area in upper right corner, but we're
+ // using a width and height that go beyond the edges of the image.
+ texture.drawImage(kids, 0, 150, 150, 400, 400, 0, 150, 150, 400, 400);
+
+ // Draw "O3D" label.
+ texture.drawImage(label, 0, 0, 0, 100, 50, 0, 100, 125, 100, 50);
+
+ // Fill in different mip-map levels with images that show at
+ // different distances. (Scroll the mouse wheel to see).
+
+ // Fill in medium level with whole image.
+ texture.drawImage(kids, 0, 0, 0, 300, 300, 1, 0, 0, 150, 150);
+
+ // Fill in smaller level with four pixel image.
+ texture.drawImage(four_square, 0, 0, 0, 2, 2, 2, 0, 0, 75, 75);
+
+ makeShape(texture);
+ }
+ o3djs.event.addEventListener(o3dElement, 'wheel', scrollMe);
+}
+
+function scrollMe(e) {
+ g_eye = g_math.mulScalarVector((e.deltaY < 0 ? 11 : 13) / 12, g_eye);
+ g_viewInfo.drawContext.view = g_math.matrix4.lookAt(g_eye, g_target, g_up);
+}
+</script>
+</head>
+<body>
+<h1>Bitmap Draw Image Demo</h1>
+This tutorial shows how to create bitmaps and how to draw images
+on both bitmaps and texture mipmaps.
+<br/>
+Scroll wheel to see different mipmaps.
+<br/>
+<!-- Start of O3D plugin -->
+<div id="o3d" style="width: 600px; height: 600px"></div>
+<!-- End of O3D plugin -->
+</body>
</html> \ No newline at end of file
diff --git a/o3d/samples/box2d-3d/third_party/box2d/box2d.js b/o3d/samples/box2d-3d/third_party/box2d/box2d.js
index e55e449..8b84f83 100644
--- a/o3d/samples/box2d-3d/third_party/box2d/box2d.js
+++ b/o3d/samples/box2d-3d/third_party/box2d/box2d.js
@@ -1,1037 +1,1037 @@
-/*
- * Box2Djs (port of Box2DFlash 1.4.3.1) - http://box2d-js.sourceforge.net/
- * Single-filed and jsmined ( http://code.google.com/p/jsmin-php/ ) by Mr.doob
- */
-
-var b2Settings=Class.create();b2Settings.prototype={initialize:function(){}}
-b2Settings.USHRT_MAX=0x0000ffff;b2Settings.b2_pi=Math.PI;b2Settings.b2_massUnitsPerKilogram=1.0;b2Settings.b2_timeUnitsPerSecond=1.0;b2Settings.b2_lengthUnitsPerMeter=30.0;b2Settings.b2_maxManifoldPoints=2;b2Settings.b2_maxShapesPerBody=64;b2Settings.b2_maxPolyVertices=8;b2Settings.b2_maxProxies=1024;b2Settings.b2_maxPairs=8*b2Settings.b2_maxProxies;b2Settings.b2_linearSlop=0.005*b2Settings.b2_lengthUnitsPerMeter;b2Settings.b2_angularSlop=2.0/180.0*b2Settings.b2_pi;b2Settings.b2_velocityThreshold=1.0*b2Settings.b2_lengthUnitsPerMeter/b2Settings.b2_timeUnitsPerSecond;b2Settings.b2_maxLinearCorrection=0.2*b2Settings.b2_lengthUnitsPerMeter;b2Settings.b2_maxAngularCorrection=8.0/180.0*b2Settings.b2_pi;b2Settings.b2_contactBaumgarte=0.2;b2Settings.b2_timeToSleep=0.5*b2Settings.b2_timeUnitsPerSecond;b2Settings.b2_linearSleepTolerance=0.01*b2Settings.b2_lengthUnitsPerMeter/b2Settings.b2_timeUnitsPerSecond;b2Settings.b2_angularSleepTolerance=2.0/180.0/b2Settings.b2_timeUnitsPerSecond;b2Settings.b2Assert=function(a)
-{if(!a){var nullVec;nullVec.x++;}};
-var b2Vec2=Class.create();b2Vec2.prototype={initialize:function(x_,y_){this.x=x_;this.y=y_;},SetZero:function(){this.x=0.0;this.y=0.0;},Set:function(x_,y_){this.x=x_;this.y=y_;},SetV:function(v){this.x=v.x;this.y=v.y;},Negative:function(){return new b2Vec2(-this.x,-this.y);},Copy:function(){return new b2Vec2(this.x,this.y);},Add:function(v)
-{this.x+=v.x;this.y+=v.y;},Subtract:function(v)
-{this.x-=v.x;this.y-=v.y;},Multiply:function(a)
-{this.x*=a;this.y*=a;},MulM:function(A)
-{var tX=this.x;this.x=A.col1.x*tX+A.col2.x*this.y;this.y=A.col1.y*tX+A.col2.y*this.y;},MulTM:function(A)
-{var tX=b2Math.b2Dot(this,A.col1);this.y=b2Math.b2Dot(this,A.col2);this.x=tX;},CrossVF:function(s)
-{var tX=this.x;this.x=s*this.y;this.y=-s*tX;},CrossFV:function(s)
-{var tX=this.x;this.x=-s*this.y;this.y=s*tX;},MinV:function(b)
-{this.x=this.x<b.x?this.x:b.x;this.y=this.y<b.y?this.y:b.y;},MaxV:function(b)
-{this.x=this.x>b.x?this.x:b.x;this.y=this.y>b.y?this.y:b.y;},Abs:function()
-{this.x=Math.abs(this.x);this.y=Math.abs(this.y);},Length:function()
-{return Math.sqrt(this.x*this.x+this.y*this.y);},Normalize:function()
-{var length=this.Length();if(length<Number.MIN_VALUE)
-{return 0.0;}
-var invLength=1.0/length;this.x*=invLength;this.y*=invLength;return length;},IsValid:function()
-{return b2Math.b2IsValid(this.x)&&b2Math.b2IsValid(this.y);},x:null,y:null};b2Vec2.Make=function(x_,y_)
-{return new b2Vec2(x_,y_);};
-var b2Mat22=Class.create();b2Mat22.prototype={initialize:function(angle,c1,c2)
-{if(angle==null)angle=0;this.col1=new b2Vec2();this.col2=new b2Vec2();if(c1!=null&&c2!=null){this.col1.SetV(c1);this.col2.SetV(c2);}
-else{var c=Math.cos(angle);var s=Math.sin(angle);this.col1.x=c;this.col2.x=-s;this.col1.y=s;this.col2.y=c;}},Set:function(angle)
-{var c=Math.cos(angle);var s=Math.sin(angle);this.col1.x=c;this.col2.x=-s;this.col1.y=s;this.col2.y=c;},SetVV:function(c1,c2)
-{this.col1.SetV(c1);this.col2.SetV(c2);},Copy:function(){return new b2Mat22(0,this.col1,this.col2);},SetM:function(m)
-{this.col1.SetV(m.col1);this.col2.SetV(m.col2);},AddM:function(m)
-{this.col1.x+=m.col1.x;this.col1.y+=m.col1.y;this.col2.x+=m.col2.x;this.col2.y+=m.col2.y;},SetIdentity:function()
-{this.col1.x=1.0;this.col2.x=0.0;this.col1.y=0.0;this.col2.y=1.0;},SetZero:function()
-{this.col1.x=0.0;this.col2.x=0.0;this.col1.y=0.0;this.col2.y=0.0;},Invert:function(out)
-{var a=this.col1.x;var b=this.col2.x;var c=this.col1.y;var d=this.col2.y;var det=a*d-b*c;det=1.0/det;out.col1.x=det*d;out.col2.x=-det*b;out.col1.y=-det*c;out.col2.y=det*a;return out;},Solve:function(out,bX,bY)
-{var a11=this.col1.x;var a12=this.col2.x;var a21=this.col1.y;var a22=this.col2.y;var det=a11*a22-a12*a21;det=1.0/det;out.x=det*(a22*bX-a12*bY);out.y=det*(a11*bY-a21*bX);return out;},Abs:function()
-{this.col1.Abs();this.col2.Abs();},col1:new b2Vec2(),col2:new b2Vec2()};
-var b2Math=Class.create();b2Math.prototype={initialize:function(){}}
-b2Math.b2IsValid=function(x)
-{return isFinite(x);};b2Math.b2Dot=function(a,b)
-{return a.x*b.x+a.y*b.y;};b2Math.b2CrossVV=function(a,b)
-{return a.x*b.y-a.y*b.x;};b2Math.b2CrossVF=function(a,s)
-{var v=new b2Vec2(s*a.y,-s*a.x);return v;};b2Math.b2CrossFV=function(s,a)
-{var v=new b2Vec2(-s*a.y,s*a.x);return v;};b2Math.b2MulMV=function(A,v)
-{var u=new b2Vec2(A.col1.x*v.x+A.col2.x*v.y,A.col1.y*v.x+A.col2.y*v.y);return u;};b2Math.b2MulTMV=function(A,v)
-{var u=new b2Vec2(b2Math.b2Dot(v,A.col1),b2Math.b2Dot(v,A.col2));return u;};b2Math.AddVV=function(a,b)
-{var v=new b2Vec2(a.x+b.x,a.y+b.y);return v;};b2Math.SubtractVV=function(a,b)
-{var v=new b2Vec2(a.x-b.x,a.y-b.y);return v;};b2Math.MulFV=function(s,a)
-{var v=new b2Vec2(s*a.x,s*a.y);return v;};b2Math.AddMM=function(A,B)
-{var C=new b2Mat22(0,b2Math.AddVV(A.col1,B.col1),b2Math.AddVV(A.col2,B.col2));return C;};b2Math.b2MulMM=function(A,B)
-{var C=new b2Mat22(0,b2Math.b2MulMV(A,B.col1),b2Math.b2MulMV(A,B.col2));return C;};b2Math.b2MulTMM=function(A,B)
-{var c1=new b2Vec2(b2Math.b2Dot(A.col1,B.col1),b2Math.b2Dot(A.col2,B.col1));var c2=new b2Vec2(b2Math.b2Dot(A.col1,B.col2),b2Math.b2Dot(A.col2,B.col2));var C=new b2Mat22(0,c1,c2);return C;};b2Math.b2Abs=function(a)
-{return a>0.0?a:-a;};b2Math.b2AbsV=function(a)
-{var b=new b2Vec2(b2Math.b2Abs(a.x),b2Math.b2Abs(a.y));return b;};b2Math.b2AbsM=function(A)
-{var B=new b2Mat22(0,b2Math.b2AbsV(A.col1),b2Math.b2AbsV(A.col2));return B;};b2Math.b2Min=function(a,b)
-{return a<b?a:b;};b2Math.b2MinV=function(a,b)
-{var c=new b2Vec2(b2Math.b2Min(a.x,b.x),b2Math.b2Min(a.y,b.y));return c;};b2Math.b2Max=function(a,b)
-{return a>b?a:b;};b2Math.b2MaxV=function(a,b)
-{var c=new b2Vec2(b2Math.b2Max(a.x,b.x),b2Math.b2Max(a.y,b.y));return c;};b2Math.b2Clamp=function(a,low,high)
-{return b2Math.b2Max(low,b2Math.b2Min(a,high));};b2Math.b2ClampV=function(a,low,high)
-{return b2Math.b2MaxV(low,b2Math.b2MinV(a,high));};b2Math.b2Swap=function(a,b)
-{var tmp=a[0];a[0]=b[0];b[0]=tmp;};b2Math.b2Random=function()
-{return Math.random()*2-1;};b2Math.b2NextPowerOfTwo=function(x)
-{x|=(x>>1)&0x7FFFFFFF;x|=(x>>2)&0x3FFFFFFF;x|=(x>>4)&0x0FFFFFFF;x|=(x>>8)&0x00FFFFFF;x|=(x>>16)&0x0000FFFF;return x+1;};b2Math.b2IsPowerOfTwo=function(x)
-{var result=x>0&&(x&(x-1))==0;return result;};b2Math.tempVec2=new b2Vec2();b2Math.tempVec3=new b2Vec2();b2Math.tempVec4=new b2Vec2();b2Math.tempVec5=new b2Vec2();b2Math.tempMat=new b2Mat22();
-var b2AABB=Class.create();b2AABB.prototype={IsValid:function(){var dX=this.maxVertex.x;var dY=this.maxVertex.y;dX=this.maxVertex.x;dY=this.maxVertex.y;dX-=this.minVertex.x;dY-=this.minVertex.y;var valid=dX>=0.0&&dY>=0.0;valid=valid&&this.minVertex.IsValid()&&this.maxVertex.IsValid();return valid;},minVertex:new b2Vec2(),maxVertex:new b2Vec2(),initialize:function(){this.minVertex=new b2Vec2();this.maxVertex=new b2Vec2();}};
-var b2Bound=Class.create();b2Bound.prototype={IsLower:function(){return(this.value&1)==0;},IsUpper:function(){return(this.value&1)==1;},Swap:function(b){var tempValue=this.value;var tempProxyId=this.proxyId;var tempStabbingCount=this.stabbingCount;this.value=b.value;this.proxyId=b.proxyId;this.stabbingCount=b.stabbingCount;b.value=tempValue;b.proxyId=tempProxyId;b.stabbingCount=tempStabbingCount;},value:0,proxyId:0,stabbingCount:0,initialize:function(){}}
-
-var b2BoundValues=Class.create();b2BoundValues.prototype={lowerValues:[0,0],upperValues:[0,0],initialize:function(){this.lowerValues=[0,0];this.upperValues=[0,0];}}
-
-var b2Pair=Class.create();b2Pair.prototype={SetBuffered:function(){this.status|=b2Pair.e_pairBuffered;},ClearBuffered:function(){this.status&=~b2Pair.e_pairBuffered;},IsBuffered:function(){return(this.status&b2Pair.e_pairBuffered)==b2Pair.e_pairBuffered;},SetRemoved:function(){this.status|=b2Pair.e_pairRemoved;},ClearRemoved:function(){this.status&=~b2Pair.e_pairRemoved;},IsRemoved:function(){return(this.status&b2Pair.e_pairRemoved)==b2Pair.e_pairRemoved;},SetFinal:function(){this.status|=b2Pair.e_pairFinal;},IsFinal:function(){return(this.status&b2Pair.e_pairFinal)==b2Pair.e_pairFinal;},userData:null,proxyId1:0,proxyId2:0,next:0,status:0,initialize:function(){}};b2Pair.b2_nullPair=b2Settings.USHRT_MAX;b2Pair.b2_nullProxy=b2Settings.USHRT_MAX;b2Pair.b2_tableCapacity=b2Settings.b2_maxPairs;b2Pair.b2_tableMask=b2Pair.b2_tableCapacity-1;b2Pair.e_pairBuffered=0x0001;b2Pair.e_pairRemoved=0x0002;b2Pair.e_pairFinal=0x0004;
-var b2PairCallback=Class.create();b2PairCallback.prototype={PairAdded:function(proxyUserData1,proxyUserData2){return null},PairRemoved:function(proxyUserData1,proxyUserData2,pairUserData){},initialize:function(){}};
-var b2BufferedPair=Class.create();b2BufferedPair.prototype={proxyId1:0,proxyId2:0,initialize:function(){}}
-
-var b2PairManager=Class.create();b2PairManager.prototype={initialize:function(){var i=0;this.m_hashTable=new Array(b2Pair.b2_tableCapacity);for(i=0;i<b2Pair.b2_tableCapacity;++i)
-{this.m_hashTable[i]=b2Pair.b2_nullPair;}
-this.m_pairs=new Array(b2Settings.b2_maxPairs);for(i=0;i<b2Settings.b2_maxPairs;++i)
-{this.m_pairs[i]=new b2Pair();}
-this.m_pairBuffer=new Array(b2Settings.b2_maxPairs);for(i=0;i<b2Settings.b2_maxPairs;++i)
-{this.m_pairBuffer[i]=new b2BufferedPair();}
-for(i=0;i<b2Settings.b2_maxPairs;++i)
-{this.m_pairs[i].proxyId1=b2Pair.b2_nullProxy;this.m_pairs[i].proxyId2=b2Pair.b2_nullProxy;this.m_pairs[i].userData=null;this.m_pairs[i].status=0;this.m_pairs[i].next=(i+1);}
-this.m_pairs[b2Settings.b2_maxPairs-1].next=b2Pair.b2_nullPair;this.m_pairCount=0;},Initialize:function(broadPhase,callback){this.m_broadPhase=broadPhase;this.m_callback=callback;},AddBufferedPair:function(proxyId1,proxyId2){var pair=this.AddPair(proxyId1,proxyId2);if(pair.IsBuffered()==false)
-{pair.SetBuffered();this.m_pairBuffer[this.m_pairBufferCount].proxyId1=pair.proxyId1;this.m_pairBuffer[this.m_pairBufferCount].proxyId2=pair.proxyId2;++this.m_pairBufferCount;}
-pair.ClearRemoved();if(b2BroadPhase.s_validate)
-{this.ValidateBuffer();}},RemoveBufferedPair:function(proxyId1,proxyId2){var pair=this.Find(proxyId1,proxyId2);if(pair==null)
-{return;}
-if(pair.IsBuffered()==false)
-{pair.SetBuffered();this.m_pairBuffer[this.m_pairBufferCount].proxyId1=pair.proxyId1;this.m_pairBuffer[this.m_pairBufferCount].proxyId2=pair.proxyId2;++this.m_pairBufferCount;}
-pair.SetRemoved();if(b2BroadPhase.s_validate)
-{this.ValidateBuffer();}},Commit:function(){var i=0;var removeCount=0;var proxies=this.m_broadPhase.m_proxyPool;for(i=0;i<this.m_pairBufferCount;++i)
-{var pair=this.Find(this.m_pairBuffer[i].proxyId1,this.m_pairBuffer[i].proxyId2);pair.ClearBuffered();var proxy1=proxies[pair.proxyId1];var proxy2=proxies[pair.proxyId2];if(pair.IsRemoved())
-{if(pair.IsFinal()==true)
-{this.m_callback.PairRemoved(proxy1.userData,proxy2.userData,pair.userData);}
-this.m_pairBuffer[removeCount].proxyId1=pair.proxyId1;this.m_pairBuffer[removeCount].proxyId2=pair.proxyId2;++removeCount;}
-else
-{if(pair.IsFinal()==false)
-{pair.userData=this.m_callback.PairAdded(proxy1.userData,proxy2.userData);pair.SetFinal();}}}
-for(i=0;i<removeCount;++i)
-{this.RemovePair(this.m_pairBuffer[i].proxyId1,this.m_pairBuffer[i].proxyId2);}
-this.m_pairBufferCount=0;if(b2BroadPhase.s_validate)
-{this.ValidateTable();}},AddPair:function(proxyId1,proxyId2){if(proxyId1>proxyId2){var temp=proxyId1;proxyId1=proxyId2;proxyId2=temp;}
-var hash=b2PairManager.Hash(proxyId1,proxyId2)&b2Pair.b2_tableMask;var pair=pair=this.FindHash(proxyId1,proxyId2,hash);if(pair!=null)
-{return pair;}
-var pIndex=this.m_freePair;pair=this.m_pairs[pIndex];this.m_freePair=pair.next;pair.proxyId1=proxyId1;pair.proxyId2=proxyId2;pair.status=0;pair.userData=null;pair.next=this.m_hashTable[hash];this.m_hashTable[hash]=pIndex;++this.m_pairCount;return pair;},RemovePair:function(proxyId1,proxyId2){if(proxyId1>proxyId2){var temp=proxyId1;proxyId1=proxyId2;proxyId2=temp;}
-var hash=b2PairManager.Hash(proxyId1,proxyId2)&b2Pair.b2_tableMask;var node=this.m_hashTable[hash];var pNode=null;while(node!=b2Pair.b2_nullPair)
-{if(b2PairManager.Equals(this.m_pairs[node],proxyId1,proxyId2))
-{var index=node;if(pNode){pNode.next=this.m_pairs[node].next;}
-else{this.m_hashTable[hash]=this.m_pairs[node].next;}
-var pair=this.m_pairs[index];var userData=pair.userData;pair.next=this.m_freePair;pair.proxyId1=b2Pair.b2_nullProxy;pair.proxyId2=b2Pair.b2_nullProxy;pair.userData=null;pair.status=0;this.m_freePair=index;--this.m_pairCount;return userData;}
-else
-{pNode=this.m_pairs[node];node=pNode.next;}}
-return null;},Find:function(proxyId1,proxyId2){if(proxyId1>proxyId2){var temp=proxyId1;proxyId1=proxyId2;proxyId2=temp;}
-var hash=b2PairManager.Hash(proxyId1,proxyId2)&b2Pair.b2_tableMask;return this.FindHash(proxyId1,proxyId2,hash);},FindHash:function(proxyId1,proxyId2,hash){var index=this.m_hashTable[hash];while(index!=b2Pair.b2_nullPair&&b2PairManager.Equals(this.m_pairs[index],proxyId1,proxyId2)==false)
-{index=this.m_pairs[index].next;}
-if(index==b2Pair.b2_nullPair)
-{return null;}
-return this.m_pairs[index];},ValidateBuffer:function(){},ValidateTable:function(){},m_broadPhase:null,m_callback:null,m_pairs:null,m_freePair:0,m_pairCount:0,m_pairBuffer:null,m_pairBufferCount:0,m_hashTable:null};b2PairManager.Hash=function(proxyId1,proxyId2)
-{var key=((proxyId2<<16)&0xffff0000)|proxyId1;key=~key+((key<<15)&0xFFFF8000);key=key^((key>>12)&0x000fffff);key=key+((key<<2)&0xFFFFFFFC);key=key^((key>>4)&0x0fffffff);key=key*2057;key=key^((key>>16)&0x0000ffff);return key;};b2PairManager.Equals=function(pair,proxyId1,proxyId2)
-{return(pair.proxyId1==proxyId1&&pair.proxyId2==proxyId2);};b2PairManager.EqualsPair=function(pair1,pair2)
-{return pair1.proxyId1==pair2.proxyId1&&pair1.proxyId2==pair2.proxyId2;};
-var b2BroadPhase=Class.create();b2BroadPhase.prototype={initialize:function(worldAABB,callback){this.m_pairManager=new b2PairManager();this.m_proxyPool=new Array(b2Settings.b2_maxPairs);this.m_bounds=new Array(2*b2Settings.b2_maxProxies);this.m_queryResults=new Array(b2Settings.b2_maxProxies);this.m_quantizationFactor=new b2Vec2();var i=0;this.m_pairManager.Initialize(this,callback);this.m_worldAABB=worldAABB;this.m_proxyCount=0;for(i=0;i<b2Settings.b2_maxProxies;i++){this.m_queryResults[i]=0;}
-this.m_bounds=new Array(2);for(i=0;i<2;i++){this.m_bounds[i]=new Array(2*b2Settings.b2_maxProxies);for(var j=0;j<2*b2Settings.b2_maxProxies;j++){this.m_bounds[i][j]=new b2Bound();}}
-var dX=worldAABB.maxVertex.x;var dY=worldAABB.maxVertex.y;dX-=worldAABB.minVertex.x;dY-=worldAABB.minVertex.y;this.m_quantizationFactor.x=b2Settings.USHRT_MAX/dX;this.m_quantizationFactor.y=b2Settings.USHRT_MAX/dY;var tProxy;for(i=0;i<b2Settings.b2_maxProxies-1;++i)
-{tProxy=new b2Proxy();this.m_proxyPool[i]=tProxy;tProxy.SetNext(i+1);tProxy.timeStamp=0;tProxy.overlapCount=b2BroadPhase.b2_invalid;tProxy.userData=null;}
-tProxy=new b2Proxy();this.m_proxyPool[b2Settings.b2_maxProxies-1]=tProxy;tProxy.SetNext(b2Pair.b2_nullProxy);tProxy.timeStamp=0;tProxy.overlapCount=b2BroadPhase.b2_invalid;tProxy.userData=null;this.m_freeProxy=0;this.m_timeStamp=1;this.m_queryResultCount=0;},InRange:function(aabb){var dX;var dY;var d2X;var d2Y;dX=aabb.minVertex.x;dY=aabb.minVertex.y;dX-=this.m_worldAABB.maxVertex.x;dY-=this.m_worldAABB.maxVertex.y;d2X=this.m_worldAABB.minVertex.x;d2Y=this.m_worldAABB.minVertex.y;d2X-=aabb.maxVertex.x;d2Y-=aabb.maxVertex.y;dX=b2Math.b2Max(dX,d2X);dY=b2Math.b2Max(dY,d2Y);return b2Math.b2Max(dX,dY)<0.0;},GetProxy:function(proxyId){if(proxyId==b2Pair.b2_nullProxy||this.m_proxyPool[proxyId].IsValid()==false)
-{return null;}
-return this.m_proxyPool[proxyId];},CreateProxy:function(aabb,userData){var index=0;var proxy;var proxyId=this.m_freeProxy;proxy=this.m_proxyPool[proxyId];this.m_freeProxy=proxy.GetNext();proxy.overlapCount=0;proxy.userData=userData;var boundCount=2*this.m_proxyCount;var lowerValues=new Array();var upperValues=new Array();this.ComputeBounds(lowerValues,upperValues,aabb);for(var axis=0;axis<2;++axis)
-{var bounds=this.m_bounds[axis];var lowerIndex=0;var upperIndex=0;var lowerIndexOut=[lowerIndex];var upperIndexOut=[upperIndex];this.Query(lowerIndexOut,upperIndexOut,lowerValues[axis],upperValues[axis],bounds,boundCount,axis);lowerIndex=lowerIndexOut[0];upperIndex=upperIndexOut[0];var tArr=new Array();var j=0;var tEnd=boundCount-upperIndex
-var tBound1;var tBound2;for(j=0;j<tEnd;j++){tArr[j]=new b2Bound();tBound1=tArr[j];tBound2=bounds[upperIndex+j];tBound1.value=tBound2.value;tBound1.proxyId=tBound2.proxyId;tBound1.stabbingCount=tBound2.stabbingCount;}
-tEnd=tArr.length;var tIndex=upperIndex+2;for(j=0;j<tEnd;j++){tBound2=tArr[j];tBound1=bounds[tIndex+j]
-tBound1.value=tBound2.value;tBound1.proxyId=tBound2.proxyId;tBound1.stabbingCount=tBound2.stabbingCount;}
-tArr=new Array();tEnd=upperIndex-lowerIndex;for(j=0;j<tEnd;j++){tArr[j]=new b2Bound();tBound1=tArr[j];tBound2=bounds[lowerIndex+j];tBound1.value=tBound2.value;tBound1.proxyId=tBound2.proxyId;tBound1.stabbingCount=tBound2.stabbingCount;}
-tEnd=tArr.length;tIndex=lowerIndex+1;for(j=0;j<tEnd;j++){tBound2=tArr[j];tBound1=bounds[tIndex+j]
-tBound1.value=tBound2.value;tBound1.proxyId=tBound2.proxyId;tBound1.stabbingCount=tBound2.stabbingCount;}
-++upperIndex;bounds[lowerIndex].value=lowerValues[axis];bounds[lowerIndex].proxyId=proxyId;bounds[upperIndex].value=upperValues[axis];bounds[upperIndex].proxyId=proxyId;bounds[lowerIndex].stabbingCount=lowerIndex==0?0:bounds[lowerIndex-1].stabbingCount;bounds[upperIndex].stabbingCount=bounds[upperIndex-1].stabbingCount;for(index=lowerIndex;index<upperIndex;++index)
-{bounds[index].stabbingCount++;}
-for(index=lowerIndex;index<boundCount+2;++index)
-{var proxy2=this.m_proxyPool[bounds[index].proxyId];if(bounds[index].IsLower())
-{proxy2.lowerBounds[axis]=index;}
-else
-{proxy2.upperBounds[axis]=index;}}}
-++this.m_proxyCount;for(var i=0;i<this.m_queryResultCount;++i)
-{this.m_pairManager.AddBufferedPair(proxyId,this.m_queryResults[i]);}
-this.m_pairManager.Commit();this.m_queryResultCount=0;this.IncrementTimeStamp();return proxyId;},DestroyProxy:function(proxyId){var proxy=this.m_proxyPool[proxyId];var boundCount=2*this.m_proxyCount;for(var axis=0;axis<2;++axis)
-{var bounds=this.m_bounds[axis];var lowerIndex=proxy.lowerBounds[axis];var upperIndex=proxy.upperBounds[axis];var lowerValue=bounds[lowerIndex].value;var upperValue=bounds[upperIndex].value;var tArr=new Array();var j=0;var tEnd=upperIndex-lowerIndex-1;var tBound1;var tBound2;for(j=0;j<tEnd;j++){tArr[j]=new b2Bound();tBound1=tArr[j];tBound2=bounds[lowerIndex+1+j];tBound1.value=tBound2.value;tBound1.proxyId=tBound2.proxyId;tBound1.stabbingCount=tBound2.stabbingCount;}
-tEnd=tArr.length;var tIndex=lowerIndex;for(j=0;j<tEnd;j++){tBound2=tArr[j];tBound1=bounds[tIndex+j]
-tBound1.value=tBound2.value;tBound1.proxyId=tBound2.proxyId;tBound1.stabbingCount=tBound2.stabbingCount;}
-tArr=new Array();tEnd=boundCount-upperIndex-1;for(j=0;j<tEnd;j++){tArr[j]=new b2Bound();tBound1=tArr[j];tBound2=bounds[upperIndex+1+j];tBound1.value=tBound2.value;tBound1.proxyId=tBound2.proxyId;tBound1.stabbingCount=tBound2.stabbingCount;}
-tEnd=tArr.length;tIndex=upperIndex-1;for(j=0;j<tEnd;j++){tBound2=tArr[j];tBound1=bounds[tIndex+j]
-tBound1.value=tBound2.value;tBound1.proxyId=tBound2.proxyId;tBound1.stabbingCount=tBound2.stabbingCount;}
-tEnd=boundCount-2;for(var index=lowerIndex;index<tEnd;++index)
-{var proxy2=this.m_proxyPool[bounds[index].proxyId];if(bounds[index].IsLower())
-{proxy2.lowerBounds[axis]=index;}
-else
-{proxy2.upperBounds[axis]=index;}}
-tEnd=upperIndex-1;for(var index2=lowerIndex;index2<tEnd;++index2)
-{bounds[index2].stabbingCount--;}
-this.Query([0],[0],lowerValue,upperValue,bounds,boundCount-2,axis);}
-for(var i=0;i<this.m_queryResultCount;++i)
-{this.m_pairManager.RemoveBufferedPair(proxyId,this.m_queryResults[i]);}
-this.m_pairManager.Commit();this.m_queryResultCount=0;this.IncrementTimeStamp();proxy.userData=null;proxy.overlapCount=b2BroadPhase.b2_invalid;proxy.lowerBounds[0]=b2BroadPhase.b2_invalid;proxy.lowerBounds[1]=b2BroadPhase.b2_invalid;proxy.upperBounds[0]=b2BroadPhase.b2_invalid;proxy.upperBounds[1]=b2BroadPhase.b2_invalid;proxy.SetNext(this.m_freeProxy);this.m_freeProxy=proxyId;--this.m_proxyCount;},MoveProxy:function(proxyId,aabb){var axis=0;var index=0;var bound;var prevBound
-var nextBound
-var nextProxyId=0;var nextProxy;if(proxyId==b2Pair.b2_nullProxy||b2Settings.b2_maxProxies<=proxyId)
-{return;}
-if(aabb.IsValid()==false)
-{return;}
-var boundCount=2*this.m_proxyCount;var proxy=this.m_proxyPool[proxyId];var newValues=new b2BoundValues();this.ComputeBounds(newValues.lowerValues,newValues.upperValues,aabb);var oldValues=new b2BoundValues();for(axis=0;axis<2;++axis)
-{oldValues.lowerValues[axis]=this.m_bounds[axis][proxy.lowerBounds[axis]].value;oldValues.upperValues[axis]=this.m_bounds[axis][proxy.upperBounds[axis]].value;}
-for(axis=0;axis<2;++axis)
-{var bounds=this.m_bounds[axis];var lowerIndex=proxy.lowerBounds[axis];var upperIndex=proxy.upperBounds[axis];var lowerValue=newValues.lowerValues[axis];var upperValue=newValues.upperValues[axis];var deltaLower=lowerValue-bounds[lowerIndex].value;var deltaUpper=upperValue-bounds[upperIndex].value;bounds[lowerIndex].value=lowerValue;bounds[upperIndex].value=upperValue;if(deltaLower<0)
-{index=lowerIndex;while(index>0&&lowerValue<bounds[index-1].value)
-{bound=bounds[index];prevBound=bounds[index-1];var prevProxyId=prevBound.proxyId;var prevProxy=this.m_proxyPool[prevBound.proxyId];prevBound.stabbingCount++;if(prevBound.IsUpper()==true)
-{if(this.TestOverlap(newValues,prevProxy))
-{this.m_pairManager.AddBufferedPair(proxyId,prevProxyId);}
-prevProxy.upperBounds[axis]++;bound.stabbingCount++;}
-else
-{prevProxy.lowerBounds[axis]++;bound.stabbingCount--;}
-proxy.lowerBounds[axis]--;bound.Swap(prevBound);--index;}}
-if(deltaUpper>0)
-{index=upperIndex;while(index<boundCount-1&&bounds[index+1].value<=upperValue)
-{bound=bounds[index];nextBound=bounds[index+1];nextProxyId=nextBound.proxyId;nextProxy=this.m_proxyPool[nextProxyId];nextBound.stabbingCount++;if(nextBound.IsLower()==true)
-{if(this.TestOverlap(newValues,nextProxy))
-{this.m_pairManager.AddBufferedPair(proxyId,nextProxyId);}
-nextProxy.lowerBounds[axis]--;bound.stabbingCount++;}
-else
-{nextProxy.upperBounds[axis]--;bound.stabbingCount--;}
-proxy.upperBounds[axis]++;bound.Swap(nextBound);index++;}}
-if(deltaLower>0)
-{index=lowerIndex;while(index<boundCount-1&&bounds[index+1].value<=lowerValue)
-{bound=bounds[index];nextBound=bounds[index+1];nextProxyId=nextBound.proxyId;nextProxy=this.m_proxyPool[nextProxyId];nextBound.stabbingCount--;if(nextBound.IsUpper())
-{if(this.TestOverlap(oldValues,nextProxy))
-{this.m_pairManager.RemoveBufferedPair(proxyId,nextProxyId);}
-nextProxy.upperBounds[axis]--;bound.stabbingCount--;}
-else
-{nextProxy.lowerBounds[axis]--;bound.stabbingCount++;}
-proxy.lowerBounds[axis]++;bound.Swap(nextBound);index++;}}
-if(deltaUpper<0)
-{index=upperIndex;while(index>0&&upperValue<bounds[index-1].value)
-{bound=bounds[index];prevBound=bounds[index-1];prevProxyId=prevBound.proxyId;prevProxy=this.m_proxyPool[prevProxyId];prevBound.stabbingCount--;if(prevBound.IsLower()==true)
-{if(this.TestOverlap(oldValues,prevProxy))
-{this.m_pairManager.RemoveBufferedPair(proxyId,prevProxyId);}
-prevProxy.lowerBounds[axis]++;bound.stabbingCount--;}
-else
-{prevProxy.upperBounds[axis]++;bound.stabbingCount++;}
-proxy.upperBounds[axis]--;bound.Swap(prevBound);index--;}}}},Commit:function(){this.m_pairManager.Commit();},QueryAABB:function(aabb,userData,maxCount){var lowerValues=new Array();var upperValues=new Array();this.ComputeBounds(lowerValues,upperValues,aabb);var lowerIndex=0;var upperIndex=0;var lowerIndexOut=[lowerIndex];var upperIndexOut=[upperIndex];this.Query(lowerIndexOut,upperIndexOut,lowerValues[0],upperValues[0],this.m_bounds[0],2*this.m_proxyCount,0);this.Query(lowerIndexOut,upperIndexOut,lowerValues[1],upperValues[1],this.m_bounds[1],2*this.m_proxyCount,1);var count=0;for(var i=0;i<this.m_queryResultCount&&count<maxCount;++i,++count)
-{var proxy=this.m_proxyPool[this.m_queryResults[i]];userData[i]=proxy.userData;}
-this.m_queryResultCount=0;this.IncrementTimeStamp();return count;},Validate:function(){var pair;var proxy1;var proxy2;var overlap;for(var axis=0;axis<2;++axis)
-{var bounds=this.m_bounds[axis];var boundCount=2*this.m_proxyCount;var stabbingCount=0;for(var i=0;i<boundCount;++i)
-{var bound=bounds[i];if(bound.IsLower()==true)
-{stabbingCount++;}
-else
-{stabbingCount--;}}}},ComputeBounds:function(lowerValues,upperValues,aabb)
-{var minVertexX=aabb.minVertex.x;var minVertexY=aabb.minVertex.y;minVertexX=b2Math.b2Min(minVertexX,this.m_worldAABB.maxVertex.x);minVertexY=b2Math.b2Min(minVertexY,this.m_worldAABB.maxVertex.y);minVertexX=b2Math.b2Max(minVertexX,this.m_worldAABB.minVertex.x);minVertexY=b2Math.b2Max(minVertexY,this.m_worldAABB.minVertex.y);var maxVertexX=aabb.maxVertex.x;var maxVertexY=aabb.maxVertex.y;maxVertexX=b2Math.b2Min(maxVertexX,this.m_worldAABB.maxVertex.x);maxVertexY=b2Math.b2Min(maxVertexY,this.m_worldAABB.maxVertex.y);maxVertexX=b2Math.b2Max(maxVertexX,this.m_worldAABB.minVertex.x);maxVertexY=b2Math.b2Max(maxVertexY,this.m_worldAABB.minVertex.y);lowerValues[0]=(this.m_quantizationFactor.x*(minVertexX-this.m_worldAABB.minVertex.x))&(b2Settings.USHRT_MAX-1);upperValues[0]=((this.m_quantizationFactor.x*(maxVertexX-this.m_worldAABB.minVertex.x))&0x0000ffff)|1;lowerValues[1]=(this.m_quantizationFactor.y*(minVertexY-this.m_worldAABB.minVertex.y))&(b2Settings.USHRT_MAX-1);upperValues[1]=((this.m_quantizationFactor.y*(maxVertexY-this.m_worldAABB.minVertex.y))&0x0000ffff)|1;},TestOverlapValidate:function(p1,p2){for(var axis=0;axis<2;++axis)
-{var bounds=this.m_bounds[axis];if(bounds[p1.lowerBounds[axis]].value>bounds[p2.upperBounds[axis]].value)
-return false;if(bounds[p1.upperBounds[axis]].value<bounds[p2.lowerBounds[axis]].value)
-return false;}
-return true;},TestOverlap:function(b,p)
-{for(var axis=0;axis<2;++axis)
-{var bounds=this.m_bounds[axis];if(b.lowerValues[axis]>bounds[p.upperBounds[axis]].value)
-return false;if(b.upperValues[axis]<bounds[p.lowerBounds[axis]].value)
-return false;}
-return true;},Query:function(lowerQueryOut,upperQueryOut,lowerValue,upperValue,bounds,boundCount,axis){var lowerQuery=b2BroadPhase.BinarySearch(bounds,boundCount,lowerValue);var upperQuery=b2BroadPhase.BinarySearch(bounds,boundCount,upperValue);for(var j=lowerQuery;j<upperQuery;++j)
-{if(bounds[j].IsLower())
-{this.IncrementOverlapCount(bounds[j].proxyId);}}
-if(lowerQuery>0)
-{var i=lowerQuery-1;var s=bounds[i].stabbingCount;while(s)
-{if(bounds[i].IsLower())
-{var proxy=this.m_proxyPool[bounds[i].proxyId];if(lowerQuery<=proxy.upperBounds[axis])
-{this.IncrementOverlapCount(bounds[i].proxyId);--s;}}
---i;}}
-lowerQueryOut[0]=lowerQuery;upperQueryOut[0]=upperQuery;},IncrementOverlapCount:function(proxyId){var proxy=this.m_proxyPool[proxyId];if(proxy.timeStamp<this.m_timeStamp)
-{proxy.timeStamp=this.m_timeStamp;proxy.overlapCount=1;}
-else
-{proxy.overlapCount=2;this.m_queryResults[this.m_queryResultCount]=proxyId;++this.m_queryResultCount;}},IncrementTimeStamp:function(){if(this.m_timeStamp==b2Settings.USHRT_MAX)
-{for(var i=0;i<b2Settings.b2_maxProxies;++i)
-{this.m_proxyPool[i].timeStamp=0;}
-this.m_timeStamp=1;}
-else
-{++this.m_timeStamp;}},m_pairManager:new b2PairManager(),m_proxyPool:new Array(b2Settings.b2_maxPairs),m_freeProxy:0,m_bounds:new Array(2*b2Settings.b2_maxProxies),m_queryResults:new Array(b2Settings.b2_maxProxies),m_queryResultCount:0,m_worldAABB:null,m_quantizationFactor:new b2Vec2(),m_proxyCount:0,m_timeStamp:0};b2BroadPhase.s_validate=false;b2BroadPhase.b2_invalid=b2Settings.USHRT_MAX;b2BroadPhase.b2_nullEdge=b2Settings.USHRT_MAX;b2BroadPhase.BinarySearch=function(bounds,count,value)
-{var low=0;var high=count-1;while(low<=high)
-{var mid=Math.floor((low+high)/2);if(bounds[mid].value>value)
-{high=mid-1;}
-else if(bounds[mid].value<value)
-{low=mid+1;}
-else
-{return(mid);}}
-return(low);};
-var b2Collision=Class.create();b2Collision.prototype={initialize:function(){}}
-b2Collision.b2_nullFeature=0x000000ff;b2Collision.ClipSegmentToLine=function(vOut,vIn,normal,offset)
-{var numOut=0;var vIn0=vIn[0].v;var vIn1=vIn[1].v;var distance0=b2Math.b2Dot(normal,vIn[0].v)-offset;var distance1=b2Math.b2Dot(normal,vIn[1].v)-offset;if(distance0<=0.0)vOut[numOut++]=vIn[0];if(distance1<=0.0)vOut[numOut++]=vIn[1];if(distance0*distance1<0.0)
-{var interp=distance0/(distance0-distance1);var tVec=vOut[numOut].v;tVec.x=vIn0.x+interp*(vIn1.x-vIn0.x);tVec.y=vIn0.y+interp*(vIn1.y-vIn0.y);if(distance0>0.0)
-{vOut[numOut].id=vIn[0].id;}
-else
-{vOut[numOut].id=vIn[1].id;}
-++numOut;}
-return numOut;};b2Collision.EdgeSeparation=function(poly1,edge1,poly2)
-{var vert1s=poly1.m_vertices;var count2=poly2.m_vertexCount;var vert2s=poly2.m_vertices;var normalX=poly1.m_normals[edge1].x;var normalY=poly1.m_normals[edge1].y;var tX=normalX;var tMat=poly1.m_R;normalX=tMat.col1.x*tX+tMat.col2.x*normalY;normalY=tMat.col1.y*tX+tMat.col2.y*normalY;var normalLocal2X=normalX;var normalLocal2Y=normalY;tMat=poly2.m_R;tX=normalLocal2X*tMat.col1.x+normalLocal2Y*tMat.col1.y;normalLocal2Y=normalLocal2X*tMat.col2.x+normalLocal2Y*tMat.col2.y;normalLocal2X=tX;var vertexIndex2=0;var minDot=Number.MAX_VALUE;for(var i=0;i<count2;++i)
-{var tVec=vert2s[i];var dot=tVec.x*normalLocal2X+tVec.y*normalLocal2Y;if(dot<minDot)
-{minDot=dot;vertexIndex2=i;}}
-tMat=poly1.m_R;var v1X=poly1.m_position.x+(tMat.col1.x*vert1s[edge1].x+tMat.col2.x*vert1s[edge1].y)
-var v1Y=poly1.m_position.y+(tMat.col1.y*vert1s[edge1].x+tMat.col2.y*vert1s[edge1].y)
-tMat=poly2.m_R;var v2X=poly2.m_position.x+(tMat.col1.x*vert2s[vertexIndex2].x+tMat.col2.x*vert2s[vertexIndex2].y)
-var v2Y=poly2.m_position.y+(tMat.col1.y*vert2s[vertexIndex2].x+tMat.col2.y*vert2s[vertexIndex2].y)
-v2X-=v1X;v2Y-=v1Y;var separation=v2X*normalX+v2Y*normalY;return separation;};b2Collision.FindMaxSeparation=function(edgeIndex,poly1,poly2,conservative)
-{var count1=poly1.m_vertexCount;var dX=poly2.m_position.x-poly1.m_position.x;var dY=poly2.m_position.y-poly1.m_position.y;var dLocal1X=(dX*poly1.m_R.col1.x+dY*poly1.m_R.col1.y);var dLocal1Y=(dX*poly1.m_R.col2.x+dY*poly1.m_R.col2.y);var edge=0;var maxDot=-Number.MAX_VALUE;for(var i=0;i<count1;++i)
-{var dot=(poly1.m_normals[i].x*dLocal1X+poly1.m_normals[i].y*dLocal1Y);if(dot>maxDot)
-{maxDot=dot;edge=i;}}
-var s=b2Collision.EdgeSeparation(poly1,edge,poly2);if(s>0.0&&conservative==false)
-{return s;}
-var prevEdge=edge-1>=0?edge-1:count1-1;var sPrev=b2Collision.EdgeSeparation(poly1,prevEdge,poly2);if(sPrev>0.0&&conservative==false)
-{return sPrev;}
-var nextEdge=edge+1<count1?edge+1:0;var sNext=b2Collision.EdgeSeparation(poly1,nextEdge,poly2);if(sNext>0.0&&conservative==false)
-{return sNext;}
-var bestEdge=0;var bestSeparation;var increment=0;if(sPrev>s&&sPrev>sNext)
-{increment=-1;bestEdge=prevEdge;bestSeparation=sPrev;}
-else if(sNext>s)
-{increment=1;bestEdge=nextEdge;bestSeparation=sNext;}
-else
-{edgeIndex[0]=edge;return s;}
-while(true)
-{if(increment==-1)
-edge=bestEdge-1>=0?bestEdge-1:count1-1;else
-edge=bestEdge+1<count1?bestEdge+1:0;s=b2Collision.EdgeSeparation(poly1,edge,poly2);if(s>0.0&&conservative==false)
-{return s;}
-if(s>bestSeparation)
-{bestEdge=edge;bestSeparation=s;}
-else
-{break;}}
-edgeIndex[0]=bestEdge;return bestSeparation;};b2Collision.FindIncidentEdge=function(c,poly1,edge1,poly2)
-{var count1=poly1.m_vertexCount;var vert1s=poly1.m_vertices;var count2=poly2.m_vertexCount;var vert2s=poly2.m_vertices;var vertex11=edge1;var vertex12=edge1+1==count1?0:edge1+1;var tVec=vert1s[vertex12];var normal1Local1X=tVec.x;var normal1Local1Y=tVec.y;tVec=vert1s[vertex11];normal1Local1X-=tVec.x;normal1Local1Y-=tVec.y;var tX=normal1Local1X;normal1Local1X=normal1Local1Y;normal1Local1Y=-tX;var invLength=1.0/Math.sqrt(normal1Local1X*normal1Local1X+normal1Local1Y*normal1Local1Y);normal1Local1X*=invLength;normal1Local1Y*=invLength;var normal1X=normal1Local1X;var normal1Y=normal1Local1Y;tX=normal1X;var tMat=poly1.m_R;normal1X=tMat.col1.x*tX+tMat.col2.x*normal1Y;normal1Y=tMat.col1.y*tX+tMat.col2.y*normal1Y;var normal1Local2X=normal1X;var normal1Local2Y=normal1Y;tMat=poly2.m_R;tX=normal1Local2X*tMat.col1.x+normal1Local2Y*tMat.col1.y;normal1Local2Y=normal1Local2X*tMat.col2.x+normal1Local2Y*tMat.col2.y;normal1Local2X=tX;var vertex21=0;var vertex22=0;var minDot=Number.MAX_VALUE;for(var i=0;i<count2;++i)
-{var i1=i;var i2=i+1<count2?i+1:0;tVec=vert2s[i2];var normal2Local2X=tVec.x;var normal2Local2Y=tVec.y;tVec=vert2s[i1];normal2Local2X-=tVec.x;normal2Local2Y-=tVec.y;tX=normal2Local2X;normal2Local2X=normal2Local2Y;normal2Local2Y=-tX;invLength=1.0/Math.sqrt(normal2Local2X*normal2Local2X+normal2Local2Y*normal2Local2Y);normal2Local2X*=invLength;normal2Local2Y*=invLength;var dot=normal2Local2X*normal1Local2X+normal2Local2Y*normal1Local2Y;if(dot<minDot)
-{minDot=dot;vertex21=i1;vertex22=i2;}}
-var tClip;tClip=c[0];tVec=tClip.v;tVec.SetV(vert2s[vertex21]);tVec.MulM(poly2.m_R);tVec.Add(poly2.m_position);tClip.id.features.referenceFace=edge1;tClip.id.features.incidentEdge=vertex21;tClip.id.features.incidentVertex=vertex21;tClip=c[1];tVec=tClip.v;tVec.SetV(vert2s[vertex22]);tVec.MulM(poly2.m_R);tVec.Add(poly2.m_position);tClip.id.features.referenceFace=edge1;tClip.id.features.incidentEdge=vertex21;tClip.id.features.incidentVertex=vertex22;};b2Collision.b2CollidePolyTempVec=new b2Vec2();b2Collision.b2CollidePoly=function(manifold,polyA,polyB,conservative)
-{manifold.pointCount=0;var edgeA=0;var edgeAOut=[edgeA];var separationA=b2Collision.FindMaxSeparation(edgeAOut,polyA,polyB,conservative);edgeA=edgeAOut[0];if(separationA>0.0&&conservative==false)
-return;var edgeB=0;var edgeBOut=[edgeB];var separationB=b2Collision.FindMaxSeparation(edgeBOut,polyB,polyA,conservative);edgeB=edgeBOut[0];if(separationB>0.0&&conservative==false)
-return;var poly1;var poly2;var edge1=0;var flip=0;var k_relativeTol=0.98;var k_absoluteTol=0.001;if(separationB>k_relativeTol*separationA+k_absoluteTol)
-{poly1=polyB;poly2=polyA;edge1=edgeB;flip=1;}
-else
-{poly1=polyA;poly2=polyB;edge1=edgeA;flip=0;}
-var incidentEdge=[new ClipVertex(),new ClipVertex()];b2Collision.FindIncidentEdge(incidentEdge,poly1,edge1,poly2);var count1=poly1.m_vertexCount;var vert1s=poly1.m_vertices;var v11=vert1s[edge1];var v12=edge1+1<count1?vert1s[edge1+1]:vert1s[0];var dvX=v12.x-v11.x;var dvY=v12.y-v11.y;var sideNormalX=v12.x-v11.x;var sideNormalY=v12.y-v11.y;var tX=sideNormalX;var tMat=poly1.m_R;sideNormalX=tMat.col1.x*tX+tMat.col2.x*sideNormalY;sideNormalY=tMat.col1.y*tX+tMat.col2.y*sideNormalY;var invLength=1.0/Math.sqrt(sideNormalX*sideNormalX+sideNormalY*sideNormalY);sideNormalX*=invLength;sideNormalY*=invLength;var frontNormalX=sideNormalX;var frontNormalY=sideNormalY;tX=frontNormalX;frontNormalX=frontNormalY;frontNormalY=-tX;var v11X=v11.x;var v11Y=v11.y;tX=v11X;tMat=poly1.m_R;v11X=tMat.col1.x*tX+tMat.col2.x*v11Y;v11Y=tMat.col1.y*tX+tMat.col2.y*v11Y;v11X+=poly1.m_position.x;v11Y+=poly1.m_position.y;var v12X=v12.x;var v12Y=v12.y;tX=v12X;tMat=poly1.m_R;v12X=tMat.col1.x*tX+tMat.col2.x*v12Y;v12Y=tMat.col1.y*tX+tMat.col2.y*v12Y;v12X+=poly1.m_position.x;v12Y+=poly1.m_position.y;var frontOffset=frontNormalX*v11X+frontNormalY*v11Y;var sideOffset1=-(sideNormalX*v11X+sideNormalY*v11Y);var sideOffset2=sideNormalX*v12X+sideNormalY*v12Y;var clipPoints1=[new ClipVertex(),new ClipVertex()];var clipPoints2=[new ClipVertex(),new ClipVertex()];var np=0;b2Collision.b2CollidePolyTempVec.Set(-sideNormalX,-sideNormalY);np=b2Collision.ClipSegmentToLine(clipPoints1,incidentEdge,b2Collision.b2CollidePolyTempVec,sideOffset1);if(np<2)
-return;b2Collision.b2CollidePolyTempVec.Set(sideNormalX,sideNormalY);np=b2Collision.ClipSegmentToLine(clipPoints2,clipPoints1,b2Collision.b2CollidePolyTempVec,sideOffset2);if(np<2)
-return;if(flip){manifold.normal.Set(-frontNormalX,-frontNormalY);}
-else{manifold.normal.Set(frontNormalX,frontNormalY);}
-var pointCount=0;for(var i=0;i<b2Settings.b2_maxManifoldPoints;++i)
-{var tVec=clipPoints2[i].v;var separation=(frontNormalX*tVec.x+frontNormalY*tVec.y)-frontOffset;if(separation<=0.0||conservative==true)
-{var cp=manifold.points[pointCount];cp.separation=separation;cp.position.SetV(clipPoints2[i].v);cp.id.Set(clipPoints2[i].id);cp.id.features.flip=flip;++pointCount;}}
-manifold.pointCount=pointCount;};b2Collision.b2CollideCircle=function(manifold,circle1,circle2,conservative)
-{manifold.pointCount=0;var dX=circle2.m_position.x-circle1.m_position.x;var dY=circle2.m_position.y-circle1.m_position.y;var distSqr=dX*dX+dY*dY;var radiusSum=circle1.m_radius+circle2.m_radius;if(distSqr>radiusSum*radiusSum&&conservative==false)
-{return;}
-var separation;if(distSqr<Number.MIN_VALUE)
-{separation=-radiusSum;manifold.normal.Set(0.0,1.0);}
-else
-{var dist=Math.sqrt(distSqr);separation=dist-radiusSum;var a=1.0/dist;manifold.normal.x=a*dX;manifold.normal.y=a*dY;}
-manifold.pointCount=1;var tPoint=manifold.points[0];tPoint.id.set_key(0);tPoint.separation=separation;tPoint.position.x=circle2.m_position.x-(circle2.m_radius*manifold.normal.x);tPoint.position.y=circle2.m_position.y-(circle2.m_radius*manifold.normal.y);};b2Collision.b2CollidePolyAndCircle=function(manifold,poly,circle,conservative)
-{manifold.pointCount=0;var tPoint;var dX;var dY;var xLocalX=circle.m_position.x-poly.m_position.x;var xLocalY=circle.m_position.y-poly.m_position.y;var tMat=poly.m_R;var tX=xLocalX*tMat.col1.x+xLocalY*tMat.col1.y;xLocalY=xLocalX*tMat.col2.x+xLocalY*tMat.col2.y;xLocalX=tX;var dist;var normalIndex=0;var separation=-Number.MAX_VALUE;var radius=circle.m_radius;for(var i=0;i<poly.m_vertexCount;++i)
-{var s=poly.m_normals[i].x*(xLocalX-poly.m_vertices[i].x)+poly.m_normals[i].y*(xLocalY-poly.m_vertices[i].y);if(s>radius)
-{return;}
-if(s>separation)
-{separation=s;normalIndex=i;}}
-if(separation<Number.MIN_VALUE)
-{manifold.pointCount=1;var tVec=poly.m_normals[normalIndex];manifold.normal.x=tMat.col1.x*tVec.x+tMat.col2.x*tVec.y;manifold.normal.y=tMat.col1.y*tVec.x+tMat.col2.y*tVec.y;tPoint=manifold.points[0];tPoint.id.features.incidentEdge=normalIndex;tPoint.id.features.incidentVertex=b2Collision.b2_nullFeature;tPoint.id.features.referenceFace=b2Collision.b2_nullFeature;tPoint.id.features.flip=0;tPoint.position.x=circle.m_position.x-radius*manifold.normal.x;tPoint.position.y=circle.m_position.y-radius*manifold.normal.y;tPoint.separation=separation-radius;return;}
-var vertIndex1=normalIndex;var vertIndex2=vertIndex1+1<poly.m_vertexCount?vertIndex1+1:0;var eX=poly.m_vertices[vertIndex2].x-poly.m_vertices[vertIndex1].x;var eY=poly.m_vertices[vertIndex2].y-poly.m_vertices[vertIndex1].y;var length=Math.sqrt(eX*eX+eY*eY);eX/=length;eY/=length;if(length<Number.MIN_VALUE)
-{dX=xLocalX-poly.m_vertices[vertIndex1].x;dY=xLocalY-poly.m_vertices[vertIndex1].y;dist=Math.sqrt(dX*dX+dY*dY);dX/=dist;dY/=dist;if(dist>radius)
-{return;}
-manifold.pointCount=1;manifold.normal.Set(tMat.col1.x*dX+tMat.col2.x*dY,tMat.col1.y*dX+tMat.col2.y*dY);tPoint=manifold.points[0];tPoint.id.features.incidentEdge=b2Collision.b2_nullFeature;tPoint.id.features.incidentVertex=vertIndex1;tPoint.id.features.referenceFace=b2Collision.b2_nullFeature;tPoint.id.features.flip=0;tPoint.position.x=circle.m_position.x-radius*manifold.normal.x;tPoint.position.y=circle.m_position.y-radius*manifold.normal.y;tPoint.separation=dist-radius;return;}
-var u=(xLocalX-poly.m_vertices[vertIndex1].x)*eX+(xLocalY-poly.m_vertices[vertIndex1].y)*eY;tPoint=manifold.points[0];tPoint.id.features.incidentEdge=b2Collision.b2_nullFeature;tPoint.id.features.incidentVertex=b2Collision.b2_nullFeature;tPoint.id.features.referenceFace=b2Collision.b2_nullFeature;tPoint.id.features.flip=0;var pX,pY;if(u<=0.0)
-{pX=poly.m_vertices[vertIndex1].x;pY=poly.m_vertices[vertIndex1].y;tPoint.id.features.incidentVertex=vertIndex1;}
-else if(u>=length)
-{pX=poly.m_vertices[vertIndex2].x;pY=poly.m_vertices[vertIndex2].y;tPoint.id.features.incidentVertex=vertIndex2;}
-else
-{pX=eX*u+poly.m_vertices[vertIndex1].x;pY=eY*u+poly.m_vertices[vertIndex1].y;tPoint.id.features.incidentEdge=vertIndex1;}
-dX=xLocalX-pX;dY=xLocalY-pY;dist=Math.sqrt(dX*dX+dY*dY);dX/=dist;dY/=dist;if(dist>radius)
-{return;}
-manifold.pointCount=1;manifold.normal.Set(tMat.col1.x*dX+tMat.col2.x*dY,tMat.col1.y*dX+tMat.col2.y*dY);tPoint.position.x=circle.m_position.x-radius*manifold.normal.x;tPoint.position.y=circle.m_position.y-radius*manifold.normal.y;tPoint.separation=dist-radius;};b2Collision.b2TestOverlap=function(a,b)
-{var t1=b.minVertex;var t2=a.maxVertex;var d1X=t1.x-t2.x;var d1Y=t1.y-t2.y;t1=a.minVertex;t2=b.maxVertex;var d2X=t1.x-t2.x;var d2Y=t1.y-t2.y;if(d1X>0.0||d1Y>0.0)
-return false;if(d2X>0.0||d2Y>0.0)
-return false;return true;};
-var Features=Class.create();Features.prototype={set_referenceFace:function(value){this._referenceFace=value;this._m_id._key=(this._m_id._key&0xffffff00)|(this._referenceFace&0x000000ff)},get_referenceFace:function(){return this._referenceFace;},_referenceFace:0,set_incidentEdge:function(value){this._incidentEdge=value;this._m_id._key=(this._m_id._key&0xffff00ff)|((this._incidentEdge<<8)&0x0000ff00)},get_incidentEdge:function(){return this._incidentEdge;},_incidentEdge:0,set_incidentVertex:function(value){this._incidentVertex=value;this._m_id._key=(this._m_id._key&0xff00ffff)|((this._incidentVertex<<16)&0x00ff0000)},get_incidentVertex:function(){return this._incidentVertex;},_incidentVertex:0,set_flip:function(value){this._flip=value;this._m_id._key=(this._m_id._key&0x00ffffff)|((this._flip<<24)&0xff000000)},get_flip:function(){return this._flip;},_flip:0,_m_id:null,initialize:function(){}};
-var b2ContactID=Class.create();b2ContactID.prototype={initialize:function(){this.features=new Features();this.features._m_id=this;},Set:function(id){this.set_key(id._key);},Copy:function(){var id=new b2ContactID();id.set_key(this._key);return id;},get_key:function(){return this._key;},set_key:function(value){this._key=value;this.features._referenceFace=this._key&0x000000ff;this.features._incidentEdge=((this._key&0x0000ff00)>>8)&0x000000ff;this.features._incidentVertex=((this._key&0x00ff0000)>>16)&0x000000ff;this.features._flip=((this._key&0xff000000)>>24)&0x000000ff;},features:new Features(),_key:0};
-var b2ContactPoint=Class.create();b2ContactPoint.prototype={position:new b2Vec2(),separation:null,normalImpulse:null,tangentImpulse:null,id:new b2ContactID(),initialize:function(){this.position=new b2Vec2();this.id=new b2ContactID();}};var b2Distance=Class.create();b2Distance.prototype={initialize:function(){}};b2Distance.ProcessTwo=function(p1Out,p2Out,p1s,p2s,points)
-{var rX=-points[1].x;var rY=-points[1].y;var dX=points[0].x-points[1].x;var dY=points[0].y-points[1].y;var length=Math.sqrt(dX*dX+dY*dY);dX/=length;dY/=length;var lambda=rX*dX+rY*dY;if(lambda<=0.0||length<Number.MIN_VALUE)
-{p1Out.SetV(p1s[1]);p2Out.SetV(p2s[1]);p1s[0].SetV(p1s[1]);p2s[0].SetV(p2s[1]);points[0].SetV(points[1]);return 1;}
-lambda/=length;p1Out.x=p1s[1].x+lambda*(p1s[0].x-p1s[1].x);p1Out.y=p1s[1].y+lambda*(p1s[0].y-p1s[1].y);p2Out.x=p2s[1].x+lambda*(p2s[0].x-p2s[1].x);p2Out.y=p2s[1].y+lambda*(p2s[0].y-p2s[1].y);return 2;};b2Distance.ProcessThree=function(p1Out,p2Out,p1s,p2s,points)
-{var aX=points[0].x;var aY=points[0].y;var bX=points[1].x;var bY=points[1].y;var cX=points[2].x;var cY=points[2].y;var abX=bX-aX;var abY=bY-aY;var acX=cX-aX;var acY=cY-aY;var bcX=cX-bX;var bcY=cY-bY;var sn=-(aX*abX+aY*abY);var sd=(bX*abX+bY*abY);var tn=-(aX*acX+aY*acY);var td=(cX*acX+cY*acY);var un=-(bX*bcX+bY*bcY);var ud=(cX*bcX+cY*bcY);if(td<=0.0&&ud<=0.0)
-{p1Out.SetV(p1s[2]);p2Out.SetV(p2s[2]);p1s[0].SetV(p1s[2]);p2s[0].SetV(p2s[2]);points[0].SetV(points[2]);return 1;}
-var n=abX*acY-abY*acX;var vc=n*(aX*bY-aY*bX);var va=n*(bX*cY-bY*cX);if(va<=0.0&&un>=0.0&&ud>=0.0)
-{var lambda=un/(un+ud);p1Out.x=p1s[1].x+lambda*(p1s[2].x-p1s[1].x);p1Out.y=p1s[1].y+lambda*(p1s[2].y-p1s[1].y);p2Out.x=p2s[1].x+lambda*(p2s[2].x-p2s[1].x);p2Out.y=p2s[1].y+lambda*(p2s[2].y-p2s[1].y);p1s[0].SetV(p1s[2]);p2s[0].SetV(p2s[2]);points[0].SetV(points[2]);return 2;}
-var vb=n*(cX*aY-cY*aX);if(vb<=0.0&&tn>=0.0&&td>=0.0)
-{var lambda=tn/(tn+td);p1Out.x=p1s[0].x+lambda*(p1s[2].x-p1s[0].x);p1Out.y=p1s[0].y+lambda*(p1s[2].y-p1s[0].y);p2Out.x=p2s[0].x+lambda*(p2s[2].x-p2s[0].x);p2Out.y=p2s[0].y+lambda*(p2s[2].y-p2s[0].y);p1s[1].SetV(p1s[2]);p2s[1].SetV(p2s[2]);points[1].SetV(points[2]);return 2;}
-var denom=va+vb+vc;denom=1.0/denom;var u=va*denom;var v=vb*denom;var w=1.0-u-v;p1Out.x=u*p1s[0].x+v*p1s[1].x+w*p1s[2].x;p1Out.y=u*p1s[0].y+v*p1s[1].y+w*p1s[2].y;p2Out.x=u*p2s[0].x+v*p2s[1].x+w*p2s[2].x;p2Out.y=u*p2s[0].y+v*p2s[1].y+w*p2s[2].y;return 3;};b2Distance.InPoinsts=function(w,points,pointCount)
-{for(var i=0;i<pointCount;++i)
-{if(w.x==points[i].x&&w.y==points[i].y)
-{return true;}}
-return false;};b2Distance.Distance=function(p1Out,p2Out,shape1,shape2)
-{var p1s=new Array(3);var p2s=new Array(3);var points=new Array(3);var pointCount=0;p1Out.SetV(shape1.m_position);p2Out.SetV(shape2.m_position);var vSqr=0.0;var maxIterations=20;for(var iter=0;iter<maxIterations;++iter)
-{var vX=p2Out.x-p1Out.x;var vY=p2Out.y-p1Out.y;var w1=shape1.Support(vX,vY);var w2=shape2.Support(-vX,-vY);vSqr=(vX*vX+vY*vY);var wX=w2.x-w1.x;var wY=w2.y-w1.y;var vw=(vX*wX+vY*wY);if(vSqr-b2Dot(vX*wX+vY*wY)<=0.01*vSqr)
-{if(pointCount==0)
-{p1Out.SetV(w1);p2Out.SetV(w2);}
-b2Distance.g_GJK_Iterations=iter;return Math.sqrt(vSqr);}
-switch(pointCount)
-{case 0:p1s[0].SetV(w1);p2s[0].SetV(w2);points[0]=w;p1Out.SetV(p1s[0]);p2Out.SetV(p2s[0]);++pointCount;break;case 1:p1s[1].SetV(w1);p2s[1].SetV(w2);points[1].x=wX;points[1].y=wY;pointCount=b2Distance.ProcessTwo(p1Out,p2Out,p1s,p2s,points);break;case 2:p1s[2].SetV(w1);p2s[2].SetV(w2);points[2].x=wX;points[2].y=wY;pointCount=b2Distance.ProcessThree(p1Out,p2Out,p1s,p2s,points);break;}
-if(pointCount==3)
-{b2Distance.g_GJK_Iterations=iter;return 0.0;}
-var maxSqr=-Number.MAX_VALUE;for(var i=0;i<pointCount;++i)
-{maxSqr=b2Math.b2Max(maxSqr,(points[i].x*points[i].x+points[i].y*points[i].y));}
-if(pointCount==3||vSqr<=100.0*Number.MIN_VALUE*maxSqr)
-{b2Distance.g_GJK_Iterations=iter;return Math.sqrt(vSqr);}}
-b2Distance.g_GJK_Iterations=maxIterations;return Math.sqrt(vSqr);};b2Distance.g_GJK_Iterations=0;
-var b2Manifold=Class.create();b2Manifold.prototype={initialize:function(){this.points=new Array(b2Settings.b2_maxManifoldPoints);for(var i=0;i<b2Settings.b2_maxManifoldPoints;i++){this.points[i]=new b2ContactPoint();}
-this.normal=new b2Vec2();},points:null,normal:null,pointCount:0};
-var b2OBB=Class.create();b2OBB.prototype={R:new b2Mat22(),center:new b2Vec2(),extents:new b2Vec2(),initialize:function(){this.R=new b2Mat22();this.center=new b2Vec2();this.extents=new b2Vec2();}};
-var b2Proxy=Class.create();b2Proxy.prototype={GetNext:function(){return this.lowerBounds[0];},SetNext:function(next){this.lowerBounds[0]=next;},IsValid:function(){return this.overlapCount!=b2BroadPhase.b2_invalid;},lowerBounds:[(0),(0)],upperBounds:[(0),(0)],overlapCount:0,timeStamp:0,userData:null,initialize:function(){this.lowerBounds=[(0),(0)];this.upperBounds=[(0),(0)];}}
-
-var ClipVertex=Class.create();ClipVertex.prototype={v:new b2Vec2(),id:new b2ContactID(),initialize:function(){this.v=new b2Vec2();this.id=new b2ContactID();}};var b2Shape=Class.create();b2Shape.prototype={TestPoint:function(p){return false},GetUserData:function(){return this.m_userData;},GetType:function(){return this.m_type;},GetBody:function(){return this.m_body;},GetPosition:function(){return this.m_position;},GetRotationMatrix:function(){return this.m_R;},ResetProxy:function(broadPhase){},GetNext:function(){return this.m_next;},initialize:function(def,body){this.m_R=new b2Mat22();this.m_position=new b2Vec2();this.m_userData=def.userData;this.m_friction=def.friction;this.m_restitution=def.restitution;this.m_body=body;this.m_proxyId=b2Pair.b2_nullProxy;this.m_maxRadius=0.0;this.m_categoryBits=def.categoryBits;this.m_maskBits=def.maskBits;this.m_groupIndex=def.groupIndex;},DestroyProxy:function()
-{if(this.m_proxyId!=b2Pair.b2_nullProxy)
-{this.m_body.m_world.m_broadPhase.DestroyProxy(this.m_proxyId);this.m_proxyId=b2Pair.b2_nullProxy;}},Synchronize:function(position1,R1,position2,R2){},QuickSync:function(position,R){},Support:function(dX,dY,out){},GetMaxRadius:function(){return this.m_maxRadius;},m_next:null,m_R:new b2Mat22(),m_position:new b2Vec2(),m_type:0,m_userData:null,m_body:null,m_friction:null,m_restitution:null,m_maxRadius:null,m_proxyId:0,m_categoryBits:0,m_maskBits:0,m_groupIndex:0};b2Shape.Create=function(def,body,center){switch(def.type)
-{case b2Shape.e_circleShape:{return new b2CircleShape(def,body,center);}
-case b2Shape.e_boxShape:case b2Shape.e_polyShape:{return new b2PolyShape(def,body,center);}}
-return null;};b2Shape.Destroy=function(shape)
-{if(shape.m_proxyId!=b2Pair.b2_nullProxy)
-shape.m_body.m_world.m_broadPhase.DestroyProxy(shape.m_proxyId);};b2Shape.e_unknownShape=-1;b2Shape.e_circleShape=0;b2Shape.e_boxShape=1;b2Shape.e_polyShape=2;b2Shape.e_meshShape=3;b2Shape.e_shapeTypeCount=4;b2Shape.PolyMass=function(massData,vs,count,rho)
-{var center=new b2Vec2();center.SetZero();var area=0.0;var I=0.0;var pRef=new b2Vec2(0.0,0.0);var inv3=1.0/3.0;for(var i=0;i<count;++i)
-{var p1=pRef;var p2=vs[i];var p3=i+1<count?vs[i+1]:vs[0];var e1=b2Math.SubtractVV(p2,p1);var e2=b2Math.SubtractVV(p3,p1);var D=b2Math.b2CrossVV(e1,e2);var triangleArea=0.5*D;area+=triangleArea;var tVec=new b2Vec2();tVec.SetV(p1);tVec.Add(p2);tVec.Add(p3);tVec.Multiply(inv3*triangleArea);center.Add(tVec);var px=p1.x;var py=p1.y;var ex1=e1.x;var ey1=e1.y;var ex2=e2.x;var ey2=e2.y;var intx2=inv3*(0.25*(ex1*ex1+ex2*ex1+ex2*ex2)+(px*ex1+px*ex2))+0.5*px*px;var inty2=inv3*(0.25*(ey1*ey1+ey2*ey1+ey2*ey2)+(py*ey1+py*ey2))+0.5*py*py;I+=D*(intx2+inty2);}
-massData.mass=rho*area;center.Multiply(1.0/area);massData.center=center;I=rho*(I-area*b2Math.b2Dot(center,center));massData.I=I;};b2Shape.PolyCentroid=function(vs,count,out)
-{var cX=0.0;var cY=0.0;var area=0.0;var pRefX=0.0;var pRefY=0.0;var inv3=1.0/3.0;for(var i=0;i<count;++i)
-{var p1X=pRefX;var p1Y=pRefY;var p2X=vs[i].x;var p2Y=vs[i].y;var p3X=i+1<count?vs[i+1].x:vs[0].x;var p3Y=i+1<count?vs[i+1].y:vs[0].y;var e1X=p2X-p1X;var e1Y=p2Y-p1Y;var e2X=p3X-p1X;var e2Y=p3Y-p1Y;var D=(e1X*e2Y-e1Y*e2X);var triangleArea=0.5*D;area+=triangleArea;cX+=triangleArea*inv3*(p1X+p2X+p3X);cY+=triangleArea*inv3*(p1Y+p2Y+p3Y);}
-cX*=1.0/area;cY*=1.0/area;out.Set(cX,cY);};
-var b2ShapeDef=Class.create();b2ShapeDef.prototype={initialize:function()
-{this.type=b2Shape.e_unknownShape;this.userData=null;this.localPosition=new b2Vec2(0.0,0.0);this.localRotation=0.0;this.friction=0.2;this.restitution=0.0;this.density=0.0;this.categoryBits=0x0001;this.maskBits=0xFFFF;this.groupIndex=0;},ComputeMass:function(massData)
-{massData.center=new b2Vec2(0.0,0.0)
-if(this.density==0.0)
-{massData.mass=0.0;massData.center.Set(0.0,0.0);massData.I=0.0;};switch(this.type)
-{case b2Shape.e_circleShape:{var circle=this;massData.mass=this.density*b2Settings.b2_pi*circle.radius*circle.radius;massData.center.Set(0.0,0.0);massData.I=0.5*(massData.mass)*circle.radius*circle.radius;}
-break;case b2Shape.e_boxShape:{var box=this;massData.mass=4.0*this.density*box.extents.x*box.extents.y;massData.center.Set(0.0,0.0);massData.I=massData.mass/3.0*b2Math.b2Dot(box.extents,box.extents);}
-break;case b2Shape.e_polyShape:{var poly=this;b2Shape.PolyMass(massData,poly.vertices,poly.vertexCount,this.density);}
-break;default:massData.mass=0.0;massData.center.Set(0.0,0.0);massData.I=0.0;break;}},type:0,userData:null,localPosition:null,localRotation:null,friction:null,restitution:null,density:null,categoryBits:0,maskBits:0,groupIndex:0};
-var b2BoxDef=Class.create();Object.extend(b2BoxDef.prototype,b2ShapeDef.prototype);Object.extend(b2BoxDef.prototype,{initialize:function()
-{this.type=b2Shape.e_unknownShape;this.userData=null;this.localPosition=new b2Vec2(0.0,0.0);this.localRotation=0.0;this.friction=0.2;this.restitution=0.0;this.density=0.0;this.categoryBits=0x0001;this.maskBits=0xFFFF;this.groupIndex=0;this.type=b2Shape.e_boxShape;this.extents=new b2Vec2(1.0,1.0);},extents:null});
-var b2CircleDef=Class.create();Object.extend(b2CircleDef.prototype,b2ShapeDef.prototype);Object.extend(b2CircleDef.prototype,{initialize:function()
-{this.type=b2Shape.e_unknownShape;this.userData=null;this.localPosition=new b2Vec2(0.0,0.0);this.localRotation=0.0;this.friction=0.2;this.restitution=0.0;this.density=0.0;this.categoryBits=0x0001;this.maskBits=0xFFFF;this.groupIndex=0;this.type=b2Shape.e_circleShape;this.radius=1.0;},radius:null});var b2CircleShape=Class.create();Object.extend(b2CircleShape.prototype,b2Shape.prototype);Object.extend(b2CircleShape.prototype,{TestPoint:function(p){var d=new b2Vec2();d.SetV(p);d.Subtract(this.m_position);return b2Math.b2Dot(d,d)<=this.m_radius*this.m_radius;},initialize:function(def,body,localCenter){this.m_R=new b2Mat22();this.m_position=new b2Vec2();this.m_userData=def.userData;this.m_friction=def.friction;this.m_restitution=def.restitution;this.m_body=body;this.m_proxyId=b2Pair.b2_nullProxy;this.m_maxRadius=0.0;this.m_categoryBits=def.categoryBits;this.m_maskBits=def.maskBits;this.m_groupIndex=def.groupIndex;this.m_localPosition=new b2Vec2();var circle=def;this.m_localPosition.Set(def.localPosition.x-localCenter.x,def.localPosition.y-localCenter.y);this.m_type=b2Shape.e_circleShape;this.m_radius=circle.radius;this.m_R.SetM(this.m_body.m_R);var rX=this.m_R.col1.x*this.m_localPosition.x+this.m_R.col2.x*this.m_localPosition.y;var rY=this.m_R.col1.y*this.m_localPosition.x+this.m_R.col2.y*this.m_localPosition.y;this.m_position.x=this.m_body.m_position.x+rX;this.m_position.y=this.m_body.m_position.y+rY;this.m_maxRadius=Math.sqrt(rX*rX+rY*rY)+this.m_radius;var aabb=new b2AABB();aabb.minVertex.Set(this.m_position.x-this.m_radius,this.m_position.y-this.m_radius);aabb.maxVertex.Set(this.m_position.x+this.m_radius,this.m_position.y+this.m_radius);var broadPhase=this.m_body.m_world.m_broadPhase;if(broadPhase.InRange(aabb))
-{this.m_proxyId=broadPhase.CreateProxy(aabb,this);}
-else
-{this.m_proxyId=b2Pair.b2_nullProxy;}
-if(this.m_proxyId==b2Pair.b2_nullProxy)
-{this.m_body.Freeze();}},Synchronize:function(position1,R1,position2,R2){this.m_R.SetM(R2);this.m_position.x=(R2.col1.x*this.m_localPosition.x+R2.col2.x*this.m_localPosition.y)+position2.x;this.m_position.y=(R2.col1.y*this.m_localPosition.x+R2.col2.y*this.m_localPosition.y)+position2.y;if(this.m_proxyId==b2Pair.b2_nullProxy)
-{return;}
-var p1X=position1.x+(R1.col1.x*this.m_localPosition.x+R1.col2.x*this.m_localPosition.y);var p1Y=position1.y+(R1.col1.y*this.m_localPosition.x+R1.col2.y*this.m_localPosition.y);var lowerX=Math.min(p1X,this.m_position.x);var lowerY=Math.min(p1Y,this.m_position.y);var upperX=Math.max(p1X,this.m_position.x);var upperY=Math.max(p1Y,this.m_position.y);var aabb=new b2AABB();aabb.minVertex.Set(lowerX-this.m_radius,lowerY-this.m_radius);aabb.maxVertex.Set(upperX+this.m_radius,upperY+this.m_radius);var broadPhase=this.m_body.m_world.m_broadPhase;if(broadPhase.InRange(aabb))
-{broadPhase.MoveProxy(this.m_proxyId,aabb);}
-else
-{this.m_body.Freeze();}},QuickSync:function(position,R){this.m_R.SetM(R);this.m_position.x=(R.col1.x*this.m_localPosition.x+R.col2.x*this.m_localPosition.y)+position.x;this.m_position.y=(R.col1.y*this.m_localPosition.x+R.col2.y*this.m_localPosition.y)+position.y;},ResetProxy:function(broadPhase)
-{if(this.m_proxyId==b2Pair.b2_nullProxy)
-{return;}
-var proxy=broadPhase.GetProxy(this.m_proxyId);broadPhase.DestroyProxy(this.m_proxyId);proxy=null;var aabb=new b2AABB();aabb.minVertex.Set(this.m_position.x-this.m_radius,this.m_position.y-this.m_radius);aabb.maxVertex.Set(this.m_position.x+this.m_radius,this.m_position.y+this.m_radius);if(broadPhase.InRange(aabb))
-{this.m_proxyId=broadPhase.CreateProxy(aabb,this);}
-else
-{this.m_proxyId=b2Pair.b2_nullProxy;}
-if(this.m_proxyId==b2Pair.b2_nullProxy)
-{this.m_body.Freeze();}},Support:function(dX,dY,out)
-{var len=Math.sqrt(dX*dX+dY*dY);dX/=len;dY/=len;out.Set(this.m_position.x+this.m_radius*dX,this.m_position.y+this.m_radius*dY);},m_localPosition:new b2Vec2(),m_radius:null});
-var b2MassData=Class.create();b2MassData.prototype={mass:0.0,center:new b2Vec2(0,0),I:0.0,initialize:function(){this.center=new b2Vec2(0,0);}}
-
-var b2PolyDef=Class.create();Object.extend(b2PolyDef.prototype,b2ShapeDef.prototype);Object.extend(b2PolyDef.prototype,{initialize:function()
-{this.type=b2Shape.e_unknownShape;this.userData=null;this.localPosition=new b2Vec2(0.0,0.0);this.localRotation=0.0;this.friction=0.2;this.restitution=0.0;this.density=0.0;this.categoryBits=0x0001;this.maskBits=0xFFFF;this.groupIndex=0;this.vertices=new Array(b2Settings.b2_maxPolyVertices);this.type=b2Shape.e_polyShape;this.vertexCount=0;for(var i=0;i<b2Settings.b2_maxPolyVertices;i++){this.vertices[i]=new b2Vec2();}},vertices:new Array(b2Settings.b2_maxPolyVertices),vertexCount:0});var b2PolyShape=Class.create();Object.extend(b2PolyShape.prototype,b2Shape.prototype);Object.extend(b2PolyShape.prototype,{TestPoint:function(p){var pLocal=new b2Vec2();pLocal.SetV(p);pLocal.Subtract(this.m_position);pLocal.MulTM(this.m_R);for(var i=0;i<this.m_vertexCount;++i)
-{var tVec=new b2Vec2();tVec.SetV(pLocal);tVec.Subtract(this.m_vertices[i]);var dot=b2Math.b2Dot(this.m_normals[i],tVec);if(dot>0.0)
-{return false;}}
-return true;},initialize:function(def,body,newOrigin){this.m_R=new b2Mat22();this.m_position=new b2Vec2();this.m_userData=def.userData;this.m_friction=def.friction;this.m_restitution=def.restitution;this.m_body=body;this.m_proxyId=b2Pair.b2_nullProxy;this.m_maxRadius=0.0;this.m_categoryBits=def.categoryBits;this.m_maskBits=def.maskBits;this.m_groupIndex=def.groupIndex;this.syncAABB=new b2AABB();this.syncMat=new b2Mat22();this.m_localCentroid=new b2Vec2();this.m_localOBB=new b2OBB();var i=0;var hX;var hY;var tVec;var aabb=new b2AABB();this.m_vertices=new Array(b2Settings.b2_maxPolyVertices);this.m_coreVertices=new Array(b2Settings.b2_maxPolyVertices);this.m_normals=new Array(b2Settings.b2_maxPolyVertices);this.m_type=b2Shape.e_polyShape;var localR=new b2Mat22(def.localRotation);if(def.type==b2Shape.e_boxShape)
-{this.m_localCentroid.x=def.localPosition.x-newOrigin.x;this.m_localCentroid.y=def.localPosition.y-newOrigin.y;var box=def;this.m_vertexCount=4;hX=box.extents.x;hY=box.extents.y;var hcX=Math.max(0.0,hX-2.0*b2Settings.b2_linearSlop);var hcY=Math.max(0.0,hY-2.0*b2Settings.b2_linearSlop);tVec=this.m_vertices[0]=new b2Vec2();tVec.x=localR.col1.x*hX+localR.col2.x*hY;tVec.y=localR.col1.y*hX+localR.col2.y*hY;tVec=this.m_vertices[1]=new b2Vec2();tVec.x=localR.col1.x*-hX+localR.col2.x*hY;tVec.y=localR.col1.y*-hX+localR.col2.y*hY;tVec=this.m_vertices[2]=new b2Vec2();tVec.x=localR.col1.x*-hX+localR.col2.x*-hY;tVec.y=localR.col1.y*-hX+localR.col2.y*-hY;tVec=this.m_vertices[3]=new b2Vec2();tVec.x=localR.col1.x*hX+localR.col2.x*-hY;tVec.y=localR.col1.y*hX+localR.col2.y*-hY;tVec=this.m_coreVertices[0]=new b2Vec2();tVec.x=localR.col1.x*hcX+localR.col2.x*hcY;tVec.y=localR.col1.y*hcX+localR.col2.y*hcY;tVec=this.m_coreVertices[1]=new b2Vec2();tVec.x=localR.col1.x*-hcX+localR.col2.x*hcY;tVec.y=localR.col1.y*-hcX+localR.col2.y*hcY;tVec=this.m_coreVertices[2]=new b2Vec2();tVec.x=localR.col1.x*-hcX+localR.col2.x*-hcY;tVec.y=localR.col1.y*-hcX+localR.col2.y*-hcY;tVec=this.m_coreVertices[3]=new b2Vec2();tVec.x=localR.col1.x*hcX+localR.col2.x*-hcY;tVec.y=localR.col1.y*hcX+localR.col2.y*-hcY;}
-else
-{var poly=def;this.m_vertexCount=poly.vertexCount;b2Shape.PolyCentroid(poly.vertices,poly.vertexCount,b2PolyShape.tempVec);var centroidX=b2PolyShape.tempVec.x;var centroidY=b2PolyShape.tempVec.y;this.m_localCentroid.x=def.localPosition.x+(localR.col1.x*centroidX+localR.col2.x*centroidY)-newOrigin.x;this.m_localCentroid.y=def.localPosition.y+(localR.col1.y*centroidX+localR.col2.y*centroidY)-newOrigin.y;for(i=0;i<this.m_vertexCount;++i)
-{this.m_vertices[i]=new b2Vec2();this.m_coreVertices[i]=new b2Vec2();hX=poly.vertices[i].x-centroidX;hY=poly.vertices[i].y-centroidY;this.m_vertices[i].x=localR.col1.x*hX+localR.col2.x*hY;this.m_vertices[i].y=localR.col1.y*hX+localR.col2.y*hY;var uX=this.m_vertices[i].x;var uY=this.m_vertices[i].y;var length=Math.sqrt(uX*uX+uY*uY);if(length>Number.MIN_VALUE)
-{uX*=1.0/length;uY*=1.0/length;}
-this.m_coreVertices[i].x=this.m_vertices[i].x-2.0*b2Settings.b2_linearSlop*uX;this.m_coreVertices[i].y=this.m_vertices[i].y-2.0*b2Settings.b2_linearSlop*uY;}}
-var minVertexX=Number.MAX_VALUE;var minVertexY=Number.MAX_VALUE;var maxVertexX=-Number.MAX_VALUE;var maxVertexY=-Number.MAX_VALUE;this.m_maxRadius=0.0;for(i=0;i<this.m_vertexCount;++i)
-{var v=this.m_vertices[i];minVertexX=Math.min(minVertexX,v.x);minVertexY=Math.min(minVertexY,v.y);maxVertexX=Math.max(maxVertexX,v.x);maxVertexY=Math.max(maxVertexY,v.y);this.m_maxRadius=Math.max(this.m_maxRadius,v.Length());}
-this.m_localOBB.R.SetIdentity();this.m_localOBB.center.Set((minVertexX+maxVertexX)*0.5,(minVertexY+maxVertexY)*0.5);this.m_localOBB.extents.Set((maxVertexX-minVertexX)*0.5,(maxVertexY-minVertexY)*0.5);var i1=0;var i2=0;for(i=0;i<this.m_vertexCount;++i)
-{this.m_normals[i]=new b2Vec2();i1=i;i2=i+1<this.m_vertexCount?i+1:0;this.m_normals[i].x=this.m_vertices[i2].y-this.m_vertices[i1].y;this.m_normals[i].y=-(this.m_vertices[i2].x-this.m_vertices[i1].x);this.m_normals[i].Normalize();}
-for(i=0;i<this.m_vertexCount;++i)
-{i1=i;i2=i+1<this.m_vertexCount?i+1:0;}
-this.m_R.SetM(this.m_body.m_R);this.m_position.x=this.m_body.m_position.x+(this.m_R.col1.x*this.m_localCentroid.x+this.m_R.col2.x*this.m_localCentroid.y);this.m_position.y=this.m_body.m_position.y+(this.m_R.col1.y*this.m_localCentroid.x+this.m_R.col2.y*this.m_localCentroid.y);b2PolyShape.tAbsR.col1.x=this.m_R.col1.x*this.m_localOBB.R.col1.x+this.m_R.col2.x*this.m_localOBB.R.col1.y;b2PolyShape.tAbsR.col1.y=this.m_R.col1.y*this.m_localOBB.R.col1.x+this.m_R.col2.y*this.m_localOBB.R.col1.y;b2PolyShape.tAbsR.col2.x=this.m_R.col1.x*this.m_localOBB.R.col2.x+this.m_R.col2.x*this.m_localOBB.R.col2.y;b2PolyShape.tAbsR.col2.y=this.m_R.col1.y*this.m_localOBB.R.col2.x+this.m_R.col2.y*this.m_localOBB.R.col2.y;b2PolyShape.tAbsR.Abs()
-hX=b2PolyShape.tAbsR.col1.x*this.m_localOBB.extents.x+b2PolyShape.tAbsR.col2.x*this.m_localOBB.extents.y;hY=b2PolyShape.tAbsR.col1.y*this.m_localOBB.extents.x+b2PolyShape.tAbsR.col2.y*this.m_localOBB.extents.y;var positionX=this.m_position.x+(this.m_R.col1.x*this.m_localOBB.center.x+this.m_R.col2.x*this.m_localOBB.center.y);var positionY=this.m_position.y+(this.m_R.col1.y*this.m_localOBB.center.x+this.m_R.col2.y*this.m_localOBB.center.y);aabb.minVertex.x=positionX-hX;aabb.minVertex.y=positionY-hY;aabb.maxVertex.x=positionX+hX;aabb.maxVertex.y=positionY+hY;var broadPhase=this.m_body.m_world.m_broadPhase;if(broadPhase.InRange(aabb))
-{this.m_proxyId=broadPhase.CreateProxy(aabb,this);}
-else
-{this.m_proxyId=b2Pair.b2_nullProxy;}
-if(this.m_proxyId==b2Pair.b2_nullProxy)
-{this.m_body.Freeze();}},syncAABB:new b2AABB(),syncMat:new b2Mat22(),Synchronize:function(position1,R1,position2,R2){this.m_R.SetM(R2);this.m_position.x=this.m_body.m_position.x+(R2.col1.x*this.m_localCentroid.x+R2.col2.x*this.m_localCentroid.y);this.m_position.y=this.m_body.m_position.y+(R2.col1.y*this.m_localCentroid.x+R2.col2.y*this.m_localCentroid.y);if(this.m_proxyId==b2Pair.b2_nullProxy)
-{return;}
-var hX;var hY;var v1=R1.col1;var v2=R1.col2;var v3=this.m_localOBB.R.col1;var v4=this.m_localOBB.R.col2;this.syncMat.col1.x=v1.x*v3.x+v2.x*v3.y;this.syncMat.col1.y=v1.y*v3.x+v2.y*v3.y;this.syncMat.col2.x=v1.x*v4.x+v2.x*v4.y;this.syncMat.col2.y=v1.y*v4.x+v2.y*v4.y;this.syncMat.Abs();hX=this.m_localCentroid.x+this.m_localOBB.center.x;hY=this.m_localCentroid.y+this.m_localOBB.center.y;var centerX=position1.x+(R1.col1.x*hX+R1.col2.x*hY);var centerY=position1.y+(R1.col1.y*hX+R1.col2.y*hY);hX=this.syncMat.col1.x*this.m_localOBB.extents.x+this.syncMat.col2.x*this.m_localOBB.extents.y;hY=this.syncMat.col1.y*this.m_localOBB.extents.x+this.syncMat.col2.y*this.m_localOBB.extents.y;this.syncAABB.minVertex.x=centerX-hX;this.syncAABB.minVertex.y=centerY-hY;this.syncAABB.maxVertex.x=centerX+hX;this.syncAABB.maxVertex.y=centerY+hY;v1=R2.col1;v2=R2.col2;v3=this.m_localOBB.R.col1;v4=this.m_localOBB.R.col2;this.syncMat.col1.x=v1.x*v3.x+v2.x*v3.y;this.syncMat.col1.y=v1.y*v3.x+v2.y*v3.y;this.syncMat.col2.x=v1.x*v4.x+v2.x*v4.y;this.syncMat.col2.y=v1.y*v4.x+v2.y*v4.y;this.syncMat.Abs();hX=this.m_localCentroid.x+this.m_localOBB.center.x;hY=this.m_localCentroid.y+this.m_localOBB.center.y;centerX=position2.x+(R2.col1.x*hX+R2.col2.x*hY);centerY=position2.y+(R2.col1.y*hX+R2.col2.y*hY);hX=this.syncMat.col1.x*this.m_localOBB.extents.x+this.syncMat.col2.x*this.m_localOBB.extents.y;hY=this.syncMat.col1.y*this.m_localOBB.extents.x+this.syncMat.col2.y*this.m_localOBB.extents.y;this.syncAABB.minVertex.x=Math.min(this.syncAABB.minVertex.x,centerX-hX);this.syncAABB.minVertex.y=Math.min(this.syncAABB.minVertex.y,centerY-hY);this.syncAABB.maxVertex.x=Math.max(this.syncAABB.maxVertex.x,centerX+hX);this.syncAABB.maxVertex.y=Math.max(this.syncAABB.maxVertex.y,centerY+hY);var broadPhase=this.m_body.m_world.m_broadPhase;if(broadPhase.InRange(this.syncAABB))
-{broadPhase.MoveProxy(this.m_proxyId,this.syncAABB);}
-else
-{this.m_body.Freeze();}},QuickSync:function(position,R){this.m_R.SetM(R);this.m_position.x=position.x+(R.col1.x*this.m_localCentroid.x+R.col2.x*this.m_localCentroid.y);this.m_position.y=position.y+(R.col1.y*this.m_localCentroid.x+R.col2.y*this.m_localCentroid.y);},ResetProxy:function(broadPhase){if(this.m_proxyId==b2Pair.b2_nullProxy)
-{return;}
-var proxy=broadPhase.GetProxy(this.m_proxyId);broadPhase.DestroyProxy(this.m_proxyId);proxy=null;var R=b2Math.b2MulMM(this.m_R,this.m_localOBB.R);var absR=b2Math.b2AbsM(R);var h=b2Math.b2MulMV(absR,this.m_localOBB.extents);var position=b2Math.b2MulMV(this.m_R,this.m_localOBB.center);position.Add(this.m_position);var aabb=new b2AABB();aabb.minVertex.SetV(position);aabb.minVertex.Subtract(h);aabb.maxVertex.SetV(position);aabb.maxVertex.Add(h);if(broadPhase.InRange(aabb))
-{this.m_proxyId=broadPhase.CreateProxy(aabb,this);}
-else
-{this.m_proxyId=b2Pair.b2_nullProxy;}
-if(this.m_proxyId==b2Pair.b2_nullProxy)
-{this.m_body.Freeze();}},Support:function(dX,dY,out)
-{var dLocalX=(dX*this.m_R.col1.x+dY*this.m_R.col1.y);var dLocalY=(dX*this.m_R.col2.x+dY*this.m_R.col2.y);var bestIndex=0;var bestValue=(this.m_coreVertices[0].x*dLocalX+this.m_coreVertices[0].y*dLocalY);for(var i=1;i<this.m_vertexCount;++i)
-{var value=(this.m_coreVertices[i].x*dLocalX+this.m_coreVertices[i].y*dLocalY);if(value>bestValue)
-{bestIndex=i;bestValue=value;}}
-out.Set(this.m_position.x+(this.m_R.col1.x*this.m_coreVertices[bestIndex].x+this.m_R.col2.x*this.m_coreVertices[bestIndex].y),this.m_position.y+(this.m_R.col1.y*this.m_coreVertices[bestIndex].x+this.m_R.col2.y*this.m_coreVertices[bestIndex].y));},m_localCentroid:new b2Vec2(),m_localOBB:new b2OBB(),m_vertices:null,m_coreVertices:null,m_vertexCount:0,m_normals:null});b2PolyShape.tempVec=new b2Vec2();b2PolyShape.tAbsR=new b2Mat22();
-var b2Body=Class.create();b2Body.prototype={SetOriginPosition:function(position,rotation){if(this.IsFrozen())
-{return;}
-this.m_rotation=rotation;this.m_R.Set(this.m_rotation);this.m_position=b2Math.AddVV(position,b2Math.b2MulMV(this.m_R,this.m_center));this.m_position0.SetV(this.m_position);this.m_rotation0=this.m_rotation;for(var s=this.m_shapeList;s!=null;s=s.m_next)
-{s.Synchronize(this.m_position,this.m_R,this.m_position,this.m_R);}
-this.m_world.m_broadPhase.Commit();},GetOriginPosition:function(){return b2Math.SubtractVV(this.m_position,b2Math.b2MulMV(this.m_R,this.m_center));},SetCenterPosition:function(position,rotation){if(this.IsFrozen())
-{return;}
-this.m_rotation=rotation;this.m_R.Set(this.m_rotation);this.m_position.SetV(position);this.m_position0.SetV(this.m_position);this.m_rotation0=this.m_rotation;for(var s=this.m_shapeList;s!=null;s=s.m_next)
-{s.Synchronize(this.m_position,this.m_R,this.m_position,this.m_R);}
-this.m_world.m_broadPhase.Commit();},GetCenterPosition:function(){return this.m_position;},GetRotation:function(){return this.m_rotation;},GetRotationMatrix:function(){return this.m_R;},SetLinearVelocity:function(v){this.m_linearVelocity.SetV(v);},GetLinearVelocity:function(){return this.m_linearVelocity;},SetAngularVelocity:function(w){this.m_angularVelocity=w;},GetAngularVelocity:function(){return this.m_angularVelocity;},ApplyForce:function(force,point)
-{if(this.IsSleeping()==false)
-{this.m_force.Add(force);this.m_torque+=b2Math.b2CrossVV(b2Math.SubtractVV(point,this.m_position),force);}},ApplyTorque:function(torque)
-{if(this.IsSleeping()==false)
-{this.m_torque+=torque;}},ApplyImpulse:function(impulse,point)
-{if(this.IsSleeping()==false)
-{this.m_linearVelocity.Add(b2Math.MulFV(this.m_invMass,impulse));this.m_angularVelocity+=(this.m_invI*b2Math.b2CrossVV(b2Math.SubtractVV(point,this.m_position),impulse));}},GetMass:function(){return this.m_mass;},GetInertia:function(){return this.m_I;},GetWorldPoint:function(localPoint){return b2Math.AddVV(this.m_position,b2Math.b2MulMV(this.m_R,localPoint));},GetWorldVector:function(localVector){return b2Math.b2MulMV(this.m_R,localVector);},GetLocalPoint:function(worldPoint){return b2Math.b2MulTMV(this.m_R,b2Math.SubtractVV(worldPoint,this.m_position));},GetLocalVector:function(worldVector){return b2Math.b2MulTMV(this.m_R,worldVector);},IsStatic:function(){return(this.m_flags&b2Body.e_staticFlag)==b2Body.e_staticFlag;},IsFrozen:function()
-{return(this.m_flags&b2Body.e_frozenFlag)==b2Body.e_frozenFlag;},IsSleeping:function(){return(this.m_flags&b2Body.e_sleepFlag)==b2Body.e_sleepFlag;},AllowSleeping:function(flag)
-{if(flag)
-{this.m_flags|=b2Body.e_allowSleepFlag;}
-else
-{this.m_flags&=~b2Body.e_allowSleepFlag;this.WakeUp();}},WakeUp:function(){this.m_flags&=~b2Body.e_sleepFlag;this.m_sleepTime=0.0;},GetShapeList:function(){return this.m_shapeList;},GetContactList:function()
-{return this.m_contactList;},GetJointList:function()
-{return this.m_jointList;},GetNext:function(){return this.m_next;},GetUserData:function(){return this.m_userData;},initialize:function(bd,world){this.sMat0=new b2Mat22();this.m_position=new b2Vec2();this.m_R=new b2Mat22(0);this.m_position0=new b2Vec2();var i=0;var sd;var massData;this.m_flags=0;this.m_position.SetV(bd.position);this.m_rotation=bd.rotation;this.m_R.Set(this.m_rotation);this.m_position0.SetV(this.m_position);this.m_rotation0=this.m_rotation;this.m_world=world;this.m_linearDamping=b2Math.b2Clamp(1.0-bd.linearDamping,0.0,1.0);this.m_angularDamping=b2Math.b2Clamp(1.0-bd.angularDamping,0.0,1.0);this.m_force=new b2Vec2(0.0,0.0);this.m_torque=0.0;this.m_mass=0.0;var massDatas=new Array(b2Settings.b2_maxShapesPerBody);for(i=0;i<b2Settings.b2_maxShapesPerBody;i++){massDatas[i]=new b2MassData();}
-this.m_shapeCount=0;this.m_center=new b2Vec2(0.0,0.0);for(i=0;i<b2Settings.b2_maxShapesPerBody;++i)
-{sd=bd.shapes[i];if(sd==null)break;massData=massDatas[i];sd.ComputeMass(massData);this.m_mass+=massData.mass;this.m_center.x+=massData.mass*(sd.localPosition.x+massData.center.x);this.m_center.y+=massData.mass*(sd.localPosition.y+massData.center.y);++this.m_shapeCount;}
-if(this.m_mass>0.0)
-{this.m_center.Multiply(1.0/this.m_mass);this.m_position.Add(b2Math.b2MulMV(this.m_R,this.m_center));}
-else
-{this.m_flags|=b2Body.e_staticFlag;}
-this.m_I=0.0;for(i=0;i<this.m_shapeCount;++i)
-{sd=bd.shapes[i];massData=massDatas[i];this.m_I+=massData.I;var r=b2Math.SubtractVV(b2Math.AddVV(sd.localPosition,massData.center),this.m_center);this.m_I+=massData.mass*b2Math.b2Dot(r,r);}
-if(this.m_mass>0.0)
-{this.m_invMass=1.0/this.m_mass;}
-else
-{this.m_invMass=0.0;}
-if(this.m_I>0.0&&bd.preventRotation==false)
-{this.m_invI=1.0/this.m_I;}
-else
-{this.m_I=0.0;this.m_invI=0.0;}
-this.m_linearVelocity=b2Math.AddVV(bd.linearVelocity,b2Math.b2CrossFV(bd.angularVelocity,this.m_center));this.m_angularVelocity=bd.angularVelocity;this.m_jointList=null;this.m_contactList=null;this.m_prev=null;this.m_next=null;this.m_shapeList=null;for(i=0;i<this.m_shapeCount;++i)
-{sd=bd.shapes[i];var shape=b2Shape.Create(sd,this,this.m_center);shape.m_next=this.m_shapeList;this.m_shapeList=shape;}
-this.m_sleepTime=0.0;if(bd.allowSleep)
-{this.m_flags|=b2Body.e_allowSleepFlag;}
-if(bd.isSleeping)
-{this.m_flags|=b2Body.e_sleepFlag;}
-if((this.m_flags&b2Body.e_sleepFlag)||this.m_invMass==0.0)
-{this.m_linearVelocity.Set(0.0,0.0);this.m_angularVelocity=0.0;}
-this.m_userData=bd.userData;},Destroy:function(){var s=this.m_shapeList;while(s)
-{var s0=s;s=s.m_next;b2Shape.Destroy(s0);}},sMat0:new b2Mat22(),SynchronizeShapes:function(){this.sMat0.Set(this.m_rotation0);for(var s=this.m_shapeList;s!=null;s=s.m_next)
-{s.Synchronize(this.m_position0,this.sMat0,this.m_position,this.m_R);}},QuickSyncShapes:function(){for(var s=this.m_shapeList;s!=null;s=s.m_next)
-{s.QuickSync(this.m_position,this.m_R);}},IsConnected:function(other){for(var jn=this.m_jointList;jn!=null;jn=jn.next)
-{if(jn.other==other)
-return jn.joint.m_collideConnected==false;}
-return false;},Freeze:function(){this.m_flags|=b2Body.e_frozenFlag;this.m_linearVelocity.SetZero();this.m_angularVelocity=0.0;for(var s=this.m_shapeList;s!=null;s=s.m_next)
-{s.DestroyProxy();}},m_flags:0,m_position:new b2Vec2(),m_rotation:null,m_R:new b2Mat22(0),m_position0:new b2Vec2(),m_rotation0:null,m_linearVelocity:null,m_angularVelocity:null,m_force:null,m_torque:null,m_center:null,m_world:null,m_prev:null,m_next:null,m_shapeList:null,m_shapeCount:0,m_jointList:null,m_contactList:null,m_mass:null,m_invMass:null,m_I:null,m_invI:null,m_linearDamping:null,m_angularDamping:null,m_sleepTime:null,m_userData:null};b2Body.e_staticFlag=0x0001;b2Body.e_frozenFlag=0x0002;b2Body.e_islandFlag=0x0004;b2Body.e_sleepFlag=0x0008;b2Body.e_allowSleepFlag=0x0010;b2Body.e_destroyFlag=0x0020;
-var b2BodyDef=Class.create();b2BodyDef.prototype={initialize:function()
-{this.shapes=new Array();this.userData=null;for(var i=0;i<b2Settings.b2_maxShapesPerBody;i++){this.shapes[i]=null;}
-this.position=new b2Vec2(0.0,0.0);this.rotation=0.0;this.linearVelocity=new b2Vec2(0.0,0.0);this.angularVelocity=0.0;this.linearDamping=0.0;this.angularDamping=0.0;this.allowSleep=true;this.isSleeping=false;this.preventRotation=false;},userData:null,shapes:new Array(),position:null,rotation:null,linearVelocity:null,angularVelocity:null,linearDamping:null,angularDamping:null,allowSleep:null,isSleeping:null,preventRotation:null,AddShape:function(shape)
-{for(var i=0;i<b2Settings.b2_maxShapesPerBody;++i)
-{if(this.shapes[i]==null)
-{this.shapes[i]=shape;break;}}}};
-var b2CollisionFilter=Class.create();b2CollisionFilter.prototype={ShouldCollide:function(shape1,shape2){if(shape1.m_groupIndex==shape2.m_groupIndex&&shape1.m_groupIndex!=0)
-{return shape1.m_groupIndex>0;}
-var collide=(shape1.m_maskBits&shape2.m_categoryBits)!=0&&(shape1.m_categoryBits&shape2.m_maskBits)!=0;return collide;},initialize:function(){}};b2CollisionFilter.b2_defaultFilter=new b2CollisionFilter;
-var b2Island=Class.create();b2Island.prototype={initialize:function(bodyCapacity,contactCapacity,jointCapacity,allocator)
-{var i=0;this.m_bodyCapacity=bodyCapacity;this.m_contactCapacity=contactCapacity;this.m_jointCapacity=jointCapacity;this.m_bodyCount=0;this.m_contactCount=0;this.m_jointCount=0;this.m_bodies=new Array(bodyCapacity);for(i=0;i<bodyCapacity;i++)
-this.m_bodies[i]=null;this.m_contacts=new Array(contactCapacity);for(i=0;i<contactCapacity;i++)
-this.m_contacts[i]=null;this.m_joints=new Array(jointCapacity);for(i=0;i<jointCapacity;i++)
-this.m_joints[i]=null;this.m_allocator=allocator;},Clear:function()
-{this.m_bodyCount=0;this.m_contactCount=0;this.m_jointCount=0;},Solve:function(step,gravity)
-{var i=0;var b;for(i=0;i<this.m_bodyCount;++i)
-{b=this.m_bodies[i];if(b.m_invMass==0.0)
-continue;b.m_linearVelocity.Add(b2Math.MulFV(step.dt,b2Math.AddVV(gravity,b2Math.MulFV(b.m_invMass,b.m_force))));b.m_angularVelocity+=step.dt*b.m_invI*b.m_torque;b.m_linearVelocity.Multiply(b.m_linearDamping);b.m_angularVelocity*=b.m_angularDamping;b.m_position0.SetV(b.m_position);b.m_rotation0=b.m_rotation;}
-var contactSolver=new b2ContactSolver(this.m_contacts,this.m_contactCount,this.m_allocator);contactSolver.PreSolve();for(i=0;i<this.m_jointCount;++i)
-{this.m_joints[i].PrepareVelocitySolver();}
-for(i=0;i<step.iterations;++i)
-{contactSolver.SolveVelocityConstraints();for(var j=0;j<this.m_jointCount;++j)
-{this.m_joints[j].SolveVelocityConstraints(step);}}
-for(i=0;i<this.m_bodyCount;++i)
-{b=this.m_bodies[i];if(b.m_invMass==0.0)
-continue;b.m_position.x+=step.dt*b.m_linearVelocity.x;b.m_position.y+=step.dt*b.m_linearVelocity.y;b.m_rotation+=step.dt*b.m_angularVelocity;b.m_R.Set(b.m_rotation);}
-for(i=0;i<this.m_jointCount;++i)
-{this.m_joints[i].PreparePositionSolver();}
-if(b2World.s_enablePositionCorrection)
-{for(b2Island.m_positionIterationCount=0;b2Island.m_positionIterationCount<step.iterations;++b2Island.m_positionIterationCount)
-{var contactsOkay=contactSolver.SolvePositionConstraints(b2Settings.b2_contactBaumgarte);var jointsOkay=true;for(i=0;i<this.m_jointCount;++i)
-{var jointOkay=this.m_joints[i].SolvePositionConstraints();jointsOkay=jointsOkay&&jointOkay;}
-if(contactsOkay&&jointsOkay)
-{break;}}}
-contactSolver.PostSolve();for(i=0;i<this.m_bodyCount;++i)
-{b=this.m_bodies[i];if(b.m_invMass==0.0)
-continue;b.m_R.Set(b.m_rotation);b.SynchronizeShapes();b.m_force.Set(0.0,0.0);b.m_torque=0.0;}},UpdateSleep:function(dt)
-{var i=0;var b;var minSleepTime=Number.MAX_VALUE;var linTolSqr=b2Settings.b2_linearSleepTolerance*b2Settings.b2_linearSleepTolerance;var angTolSqr=b2Settings.b2_angularSleepTolerance*b2Settings.b2_angularSleepTolerance;for(i=0;i<this.m_bodyCount;++i)
-{b=this.m_bodies[i];if(b.m_invMass==0.0)
-{continue;}
-if((b.m_flags&b2Body.e_allowSleepFlag)==0)
-{b.m_sleepTime=0.0;minSleepTime=0.0;}
-if((b.m_flags&b2Body.e_allowSleepFlag)==0||b.m_angularVelocity*b.m_angularVelocity>angTolSqr||b2Math.b2Dot(b.m_linearVelocity,b.m_linearVelocity)>linTolSqr)
-{b.m_sleepTime=0.0;minSleepTime=0.0;}
-else
-{b.m_sleepTime+=dt;minSleepTime=b2Math.b2Min(minSleepTime,b.m_sleepTime);}}
-if(minSleepTime>=b2Settings.b2_timeToSleep)
-{for(i=0;i<this.m_bodyCount;++i)
-{b=this.m_bodies[i];b.m_flags|=b2Body.e_sleepFlag;}}},AddBody:function(body)
-{this.m_bodies[this.m_bodyCount++]=body;},AddContact:function(contact)
-{this.m_contacts[this.m_contactCount++]=contact;},AddJoint:function(joint)
-{this.m_joints[this.m_jointCount++]=joint;},m_allocator:null,m_bodies:null,m_contacts:null,m_joints:null,m_bodyCount:0,m_jointCount:0,m_contactCount:0,m_bodyCapacity:0,m_contactCapacity:0,m_jointCapacity:0,m_positionError:null};b2Island.m_positionIterationCount=0;
-var b2TimeStep=Class.create();b2TimeStep.prototype={dt:null,inv_dt:null,iterations:0,initialize:function(){}};
-var b2ContactNode=Class.create();b2ContactNode.prototype={other:null,contact:null,prev:null,next:null,initialize:function(){}};
-var b2Contact=Class.create();b2Contact.prototype={GetManifolds:function(){return null},GetManifoldCount:function()
-{return this.m_manifoldCount;},GetNext:function(){return this.m_next;},GetShape1:function(){return this.m_shape1;},GetShape2:function(){return this.m_shape2;},initialize:function(s1,s2)
-{this.m_node1=new b2ContactNode();this.m_node2=new b2ContactNode();this.m_flags=0;if(!s1||!s2){this.m_shape1=null;this.m_shape2=null;return;}
-this.m_shape1=s1;this.m_shape2=s2;this.m_manifoldCount=0;this.m_friction=Math.sqrt(this.m_shape1.m_friction*this.m_shape2.m_friction);this.m_restitution=b2Math.b2Max(this.m_shape1.m_restitution,this.m_shape2.m_restitution);this.m_prev=null;this.m_next=null;this.m_node1.contact=null;this.m_node1.prev=null;this.m_node1.next=null;this.m_node1.other=null;this.m_node2.contact=null;this.m_node2.prev=null;this.m_node2.next=null;this.m_node2.other=null;},Evaluate:function(){},m_flags:0,m_prev:null,m_next:null,m_node1:new b2ContactNode(),m_node2:new b2ContactNode(),m_shape1:null,m_shape2:null,m_manifoldCount:0,m_friction:null,m_restitution:null};b2Contact.e_islandFlag=0x0001;b2Contact.e_destroyFlag=0x0002;b2Contact.AddType=function(createFcn,destroyFcn,type1,type2)
-{b2Contact.s_registers[type1][type2].createFcn=createFcn;b2Contact.s_registers[type1][type2].destroyFcn=destroyFcn;b2Contact.s_registers[type1][type2].primary=true;if(type1!=type2)
-{b2Contact.s_registers[type2][type1].createFcn=createFcn;b2Contact.s_registers[type2][type1].destroyFcn=destroyFcn;b2Contact.s_registers[type2][type1].primary=false;}};b2Contact.InitializeRegisters=function(){b2Contact.s_registers=new Array(b2Shape.e_shapeTypeCount);for(var i=0;i<b2Shape.e_shapeTypeCount;i++){b2Contact.s_registers[i]=new Array(b2Shape.e_shapeTypeCount);for(var j=0;j<b2Shape.e_shapeTypeCount;j++){b2Contact.s_registers[i][j]=new b2ContactRegister();}}
-b2Contact.AddType(b2CircleContact.Create,b2CircleContact.Destroy,b2Shape.e_circleShape,b2Shape.e_circleShape);b2Contact.AddType(b2PolyAndCircleContact.Create,b2PolyAndCircleContact.Destroy,b2Shape.e_polyShape,b2Shape.e_circleShape);b2Contact.AddType(b2PolyContact.Create,b2PolyContact.Destroy,b2Shape.e_polyShape,b2Shape.e_polyShape);};b2Contact.Create=function(shape1,shape2,allocator){if(b2Contact.s_initialized==false)
-{b2Contact.InitializeRegisters();b2Contact.s_initialized=true;}
-var type1=shape1.m_type;var type2=shape2.m_type;var createFcn=b2Contact.s_registers[type1][type2].createFcn;if(createFcn)
-{if(b2Contact.s_registers[type1][type2].primary)
-{return createFcn(shape1,shape2,allocator);}
-else
-{var c=createFcn(shape2,shape1,allocator);for(var i=0;i<c.GetManifoldCount();++i)
-{var m=c.GetManifolds()[i];m.normal=m.normal.Negative();}
-return c;}}
-else
-{return null;}};b2Contact.Destroy=function(contact,allocator){if(contact.GetManifoldCount()>0)
-{contact.m_shape1.m_body.WakeUp();contact.m_shape2.m_body.WakeUp();}
-var type1=contact.m_shape1.m_type;var type2=contact.m_shape2.m_type;var destroyFcn=b2Contact.s_registers[type1][type2].destroyFcn;destroyFcn(contact,allocator);};b2Contact.s_registers=null;b2Contact.s_initialized=false;
-var b2ContactConstraint=Class.create();b2ContactConstraint.prototype={initialize:function(){this.normal=new b2Vec2();this.points=new Array(b2Settings.b2_maxManifoldPoints);for(var i=0;i<b2Settings.b2_maxManifoldPoints;i++){this.points[i]=new b2ContactConstraintPoint();}},points:null,normal:new b2Vec2(),manifold:null,body1:null,body2:null,friction:null,restitution:null,pointCount:0};
-var b2ContactConstraintPoint=Class.create();b2ContactConstraintPoint.prototype={localAnchor1:new b2Vec2(),localAnchor2:new b2Vec2(),normalImpulse:null,tangentImpulse:null,positionImpulse:null,normalMass:null,tangentMass:null,separation:null,velocityBias:null,initialize:function(){this.localAnchor1=new b2Vec2();this.localAnchor2=new b2Vec2();}};
-var b2ContactRegister=Class.create();b2ContactRegister.prototype={createFcn:null,destroyFcn:null,primary:null,initialize:function(){}};
-var b2ContactSolver=Class.create();b2ContactSolver.prototype={initialize:function(contacts,contactCount,allocator){this.m_constraints=new Array();this.m_allocator=allocator;var i=0;var tVec;var tMat;this.m_constraintCount=0;for(i=0;i<contactCount;++i)
-{this.m_constraintCount+=contacts[i].GetManifoldCount();}
-for(i=0;i<this.m_constraintCount;i++){this.m_constraints[i]=new b2ContactConstraint();}
-var count=0;for(i=0;i<contactCount;++i)
-{var contact=contacts[i];var b1=contact.m_shape1.m_body;var b2=contact.m_shape2.m_body;var manifoldCount=contact.GetManifoldCount();var manifolds=contact.GetManifolds();var friction=contact.m_friction;var restitution=contact.m_restitution;var v1X=b1.m_linearVelocity.x;var v1Y=b1.m_linearVelocity.y;var v2X=b2.m_linearVelocity.x;var v2Y=b2.m_linearVelocity.y;var w1=b1.m_angularVelocity;var w2=b2.m_angularVelocity;for(var j=0;j<manifoldCount;++j)
-{var manifold=manifolds[j];var normalX=manifold.normal.x;var normalY=manifold.normal.y;var c=this.m_constraints[count];c.body1=b1;c.body2=b2;c.manifold=manifold;c.normal.x=normalX;c.normal.y=normalY;c.pointCount=manifold.pointCount;c.friction=friction;c.restitution=restitution;for(var k=0;k<c.pointCount;++k)
-{var cp=manifold.points[k];var ccp=c.points[k];ccp.normalImpulse=cp.normalImpulse;ccp.tangentImpulse=cp.tangentImpulse;ccp.separation=cp.separation;var r1X=cp.position.x-b1.m_position.x;var r1Y=cp.position.y-b1.m_position.y;var r2X=cp.position.x-b2.m_position.x;var r2Y=cp.position.y-b2.m_position.y;tVec=ccp.localAnchor1;tMat=b1.m_R;tVec.x=r1X*tMat.col1.x+r1Y*tMat.col1.y;tVec.y=r1X*tMat.col2.x+r1Y*tMat.col2.y;tVec=ccp.localAnchor2;tMat=b2.m_R;tVec.x=r2X*tMat.col1.x+r2Y*tMat.col1.y;tVec.y=r2X*tMat.col2.x+r2Y*tMat.col2.y;var r1Sqr=r1X*r1X+r1Y*r1Y;var r2Sqr=r2X*r2X+r2Y*r2Y;var rn1=r1X*normalX+r1Y*normalY;var rn2=r2X*normalX+r2Y*normalY;var kNormal=b1.m_invMass+b2.m_invMass;kNormal+=b1.m_invI*(r1Sqr-rn1*rn1)+b2.m_invI*(r2Sqr-rn2*rn2);ccp.normalMass=1.0/kNormal;var tangentX=normalY
-var tangentY=-normalX;var rt1=r1X*tangentX+r1Y*tangentY;var rt2=r2X*tangentX+r2Y*tangentY;var kTangent=b1.m_invMass+b2.m_invMass;kTangent+=b1.m_invI*(r1Sqr-rt1*rt1)+b2.m_invI*(r2Sqr-rt2*rt2);ccp.tangentMass=1.0/kTangent;ccp.velocityBias=0.0;if(ccp.separation>0.0)
-{ccp.velocityBias=-60.0*ccp.separation;}
-var tX=v2X+(-w2*r2Y)-v1X-(-w1*r1Y);var tY=v2Y+(w2*r2X)-v1Y-(w1*r1X);var vRel=c.normal.x*tX+c.normal.y*tY;if(vRel<-b2Settings.b2_velocityThreshold)
-{ccp.velocityBias+=-c.restitution*vRel;}}
-++count;}}},PreSolve:function(){var tVec;var tVec2;var tMat;for(var i=0;i<this.m_constraintCount;++i)
-{var c=this.m_constraints[i];var b1=c.body1;var b2=c.body2;var invMass1=b1.m_invMass;var invI1=b1.m_invI;var invMass2=b2.m_invMass;var invI2=b2.m_invI;var normalX=c.normal.x;var normalY=c.normal.y;var tangentX=normalY;var tangentY=-normalX;var j=0;var tCount=0;if(b2World.s_enableWarmStarting)
-{tCount=c.pointCount;for(j=0;j<tCount;++j)
-{var ccp=c.points[j];var PX=ccp.normalImpulse*normalX+ccp.tangentImpulse*tangentX;var PY=ccp.normalImpulse*normalY+ccp.tangentImpulse*tangentY;tMat=b1.m_R;tVec=ccp.localAnchor1;var r1X=tMat.col1.x*tVec.x+tMat.col2.x*tVec.y;var r1Y=tMat.col1.y*tVec.x+tMat.col2.y*tVec.y;tMat=b2.m_R;tVec=ccp.localAnchor2;var r2X=tMat.col1.x*tVec.x+tMat.col2.x*tVec.y;var r2Y=tMat.col1.y*tVec.x+tMat.col2.y*tVec.y;b1.m_angularVelocity-=invI1*(r1X*PY-r1Y*PX);b1.m_linearVelocity.x-=invMass1*PX;b1.m_linearVelocity.y-=invMass1*PY;b2.m_angularVelocity+=invI2*(r2X*PY-r2Y*PX);b2.m_linearVelocity.x+=invMass2*PX;b2.m_linearVelocity.y+=invMass2*PY;ccp.positionImpulse=0.0;}}
-else{tCount=c.pointCount;for(j=0;j<tCount;++j)
-{var ccp2=c.points[j];ccp2.normalImpulse=0.0;ccp2.tangentImpulse=0.0;ccp2.positionImpulse=0.0;}}}},SolveVelocityConstraints:function(){var j=0;var ccp;var r1X;var r1Y;var r2X;var r2Y;var dvX;var dvY;var lambda;var newImpulse;var PX;var PY;var tMat;var tVec;for(var i=0;i<this.m_constraintCount;++i)
-{var c=this.m_constraints[i];var b1=c.body1;var b2=c.body2;var b1_angularVelocity=b1.m_angularVelocity;var b1_linearVelocity=b1.m_linearVelocity;var b2_angularVelocity=b2.m_angularVelocity;var b2_linearVelocity=b2.m_linearVelocity;var invMass1=b1.m_invMass;var invI1=b1.m_invI;var invMass2=b2.m_invMass;var invI2=b2.m_invI;var normalX=c.normal.x;var normalY=c.normal.y;var tangentX=normalY;var tangentY=-normalX;var tCount=c.pointCount;for(j=0;j<tCount;++j)
-{ccp=c.points[j];tMat=b1.m_R;tVec=ccp.localAnchor1;r1X=tMat.col1.x*tVec.x+tMat.col2.x*tVec.y
-r1Y=tMat.col1.y*tVec.x+tMat.col2.y*tVec.y
-tMat=b2.m_R;tVec=ccp.localAnchor2;r2X=tMat.col1.x*tVec.x+tMat.col2.x*tVec.y
-r2Y=tMat.col1.y*tVec.x+tMat.col2.y*tVec.y
-dvX=b2_linearVelocity.x+(-b2_angularVelocity*r2Y)-b1_linearVelocity.x-(-b1_angularVelocity*r1Y);dvY=b2_linearVelocity.y+(b2_angularVelocity*r2X)-b1_linearVelocity.y-(b1_angularVelocity*r1X);var vn=dvX*normalX+dvY*normalY;lambda=-ccp.normalMass*(vn-ccp.velocityBias);newImpulse=b2Math.b2Max(ccp.normalImpulse+lambda,0.0);lambda=newImpulse-ccp.normalImpulse;PX=lambda*normalX;PY=lambda*normalY;b1_linearVelocity.x-=invMass1*PX;b1_linearVelocity.y-=invMass1*PY;b1_angularVelocity-=invI1*(r1X*PY-r1Y*PX);b2_linearVelocity.x+=invMass2*PX;b2_linearVelocity.y+=invMass2*PY;b2_angularVelocity+=invI2*(r2X*PY-r2Y*PX);ccp.normalImpulse=newImpulse;dvX=b2_linearVelocity.x+(-b2_angularVelocity*r2Y)-b1_linearVelocity.x-(-b1_angularVelocity*r1Y);dvY=b2_linearVelocity.y+(b2_angularVelocity*r2X)-b1_linearVelocity.y-(b1_angularVelocity*r1X);var vt=dvX*tangentX+dvY*tangentY;lambda=ccp.tangentMass*(-vt);var maxFriction=c.friction*ccp.normalImpulse;newImpulse=b2Math.b2Clamp(ccp.tangentImpulse+lambda,-maxFriction,maxFriction);lambda=newImpulse-ccp.tangentImpulse;PX=lambda*tangentX;PY=lambda*tangentY;b1_linearVelocity.x-=invMass1*PX;b1_linearVelocity.y-=invMass1*PY;b1_angularVelocity-=invI1*(r1X*PY-r1Y*PX);b2_linearVelocity.x+=invMass2*PX;b2_linearVelocity.y+=invMass2*PY;b2_angularVelocity+=invI2*(r2X*PY-r2Y*PX);ccp.tangentImpulse=newImpulse;}
-b1.m_angularVelocity=b1_angularVelocity;b2.m_angularVelocity=b2_angularVelocity;}},SolvePositionConstraints:function(beta){var minSeparation=0.0;var tMat;var tVec;for(var i=0;i<this.m_constraintCount;++i)
-{var c=this.m_constraints[i];var b1=c.body1;var b2=c.body2;var b1_position=b1.m_position;var b1_rotation=b1.m_rotation;var b2_position=b2.m_position;var b2_rotation=b2.m_rotation;var invMass1=b1.m_invMass;var invI1=b1.m_invI;var invMass2=b2.m_invMass;var invI2=b2.m_invI;var normalX=c.normal.x;var normalY=c.normal.y;var tangentX=normalY;var tangentY=-normalX;var tCount=c.pointCount;for(var j=0;j<tCount;++j)
-{var ccp=c.points[j];tMat=b1.m_R;tVec=ccp.localAnchor1;var r1X=tMat.col1.x*tVec.x+tMat.col2.x*tVec.y
-var r1Y=tMat.col1.y*tVec.x+tMat.col2.y*tVec.y
-tMat=b2.m_R;tVec=ccp.localAnchor2;var r2X=tMat.col1.x*tVec.x+tMat.col2.x*tVec.y
-var r2Y=tMat.col1.y*tVec.x+tMat.col2.y*tVec.y
-var p1X=b1_position.x+r1X;var p1Y=b1_position.y+r1Y;var p2X=b2_position.x+r2X;var p2Y=b2_position.y+r2Y;var dpX=p2X-p1X;var dpY=p2Y-p1Y;var separation=(dpX*normalX+dpY*normalY)+ccp.separation;minSeparation=b2Math.b2Min(minSeparation,separation);var C=beta*b2Math.b2Clamp(separation+b2Settings.b2_linearSlop,-b2Settings.b2_maxLinearCorrection,0.0);var dImpulse=-ccp.normalMass*C;var impulse0=ccp.positionImpulse;ccp.positionImpulse=b2Math.b2Max(impulse0+dImpulse,0.0);dImpulse=ccp.positionImpulse-impulse0;var impulseX=dImpulse*normalX;var impulseY=dImpulse*normalY;b1_position.x-=invMass1*impulseX;b1_position.y-=invMass1*impulseY;b1_rotation-=invI1*(r1X*impulseY-r1Y*impulseX);b1.m_R.Set(b1_rotation);b2_position.x+=invMass2*impulseX;b2_position.y+=invMass2*impulseY;b2_rotation+=invI2*(r2X*impulseY-r2Y*impulseX);b2.m_R.Set(b2_rotation);}
-b1.m_rotation=b1_rotation;b2.m_rotation=b2_rotation;}
-return minSeparation>=-b2Settings.b2_linearSlop;},PostSolve:function(){for(var i=0;i<this.m_constraintCount;++i)
-{var c=this.m_constraints[i];var m=c.manifold;for(var j=0;j<c.pointCount;++j)
-{var mPoint=m.points[j];var cPoint=c.points[j];mPoint.normalImpulse=cPoint.normalImpulse;mPoint.tangentImpulse=cPoint.tangentImpulse;}}},m_allocator:null,m_constraints:new Array(),m_constraintCount:0};
-var b2CircleContact=Class.create();Object.extend(b2CircleContact.prototype,b2Contact.prototype);Object.extend(b2CircleContact.prototype,{initialize:function(s1,s2){this.m_node1=new b2ContactNode();this.m_node2=new b2ContactNode();this.m_flags=0;if(!s1||!s2){this.m_shape1=null;this.m_shape2=null;return;}
-this.m_shape1=s1;this.m_shape2=s2;this.m_manifoldCount=0;this.m_friction=Math.sqrt(this.m_shape1.m_friction*this.m_shape2.m_friction);this.m_restitution=b2Math.b2Max(this.m_shape1.m_restitution,this.m_shape2.m_restitution);this.m_prev=null;this.m_next=null;this.m_node1.contact=null;this.m_node1.prev=null;this.m_node1.next=null;this.m_node1.other=null;this.m_node2.contact=null;this.m_node2.prev=null;this.m_node2.next=null;this.m_node2.other=null;this.m_manifold=[new b2Manifold()];this.m_manifold[0].pointCount=0;this.m_manifold[0].points[0].normalImpulse=0.0;this.m_manifold[0].points[0].tangentImpulse=0.0;},Evaluate:function(){b2Collision.b2CollideCircle(this.m_manifold[0],this.m_shape1,this.m_shape2,false);if(this.m_manifold[0].pointCount>0)
-{this.m_manifoldCount=1;}
-else
-{this.m_manifoldCount=0;}},GetManifolds:function()
-{return this.m_manifold;},m_manifold:[new b2Manifold()]});b2CircleContact.Create=function(shape1,shape2,allocator){return new b2CircleContact(shape1,shape2);};b2CircleContact.Destroy=function(contact,allocator){};
-var b2Conservative=Class.create();b2Conservative.prototype={initialize:function(){}}
-b2Conservative.R1=new b2Mat22();b2Conservative.R2=new b2Mat22();b2Conservative.x1=new b2Vec2();b2Conservative.x2=new b2Vec2();b2Conservative.Conservative=function(shape1,shape2){var body1=shape1.GetBody();var body2=shape2.GetBody();var v1X=body1.m_position.x-body1.m_position0.x;var v1Y=body1.m_position.y-body1.m_position0.y;var omega1=body1.m_rotation-body1.m_rotation0;var v2X=body2.m_position.x-body2.m_position0.x;var v2Y=body2.m_position.y-body2.m_position0.y;var omega2=body2.m_rotation-body2.m_rotation0;var r1=shape1.GetMaxRadius();var r2=shape2.GetMaxRadius();var p1StartX=body1.m_position0.x;var p1StartY=body1.m_position0.y;var a1Start=body1.m_rotation0;var p2StartX=body2.m_position0.x;var p2StartY=body2.m_position0.y;var a2Start=body2.m_rotation0;var p1X=p1StartX;var p1Y=p1StartY;var a1=a1Start;var p2X=p2StartX;var p2Y=p2StartY;var a2=a2Start;b2Conservative.R1.Set(a1);b2Conservative.R2.Set(a2);shape1.QuickSync(p1,b2Conservative.R1);shape2.QuickSync(p2,b2Conservative.R2);var s1=0.0;var maxIterations=10;var dX;var dY;var invRelativeVelocity=0.0;var hit=true;for(var iter=0;iter<maxIterations;++iter)
-{var distance=b2Distance.Distance(b2Conservative.x1,b2Conservative.x2,shape1,shape2);if(distance<b2Settings.b2_linearSlop)
-{if(iter==0)
-{hit=false;}
-else
-{hit=true;}
-break;}
-if(iter==0)
-{dX=b2Conservative.x2.x-b2Conservative.x1.x;dY=b2Conservative.x2.y-b2Conservative.x1.y;var dLen=Math.sqrt(dX*dX+dY*dY);var relativeVelocity=(dX*(v1X-v2X)+dY*(v1Y-v2Y))+Math.abs(omega1)*r1+Math.abs(omega2)*r2;if(Math.abs(relativeVelocity)<Number.MIN_VALUE)
-{hit=false;break;}
-invRelativeVelocity=1.0/relativeVelocity;}
-var ds=distance*invRelativeVelocity;var s2=s1+ds;if(s2<0.0||1.0<s2)
-{hit=false;break;}
-if(s2<(1.0+100.0*Number.MIN_VALUE)*s1)
-{hit=true;break;}
-s1=s2;p1X=p1StartX+s1*v1.x;p1Y=p1StartY+s1*v1.y;a1=a1Start+s1*omega1;p2X=p2StartX+s1*v2.x;p2Y=p2StartY+s1*v2.y;a2=a2Start+s1*omega2;b2Conservative.R1.Set(a1);b2Conservative.R2.Set(a2);shape1.QuickSync(p1,b2Conservative.R1);shape2.QuickSync(p2,b2Conservative.R2);}
-if(hit)
-{dX=b2Conservative.x2.x-b2Conservative.x1.x;dY=b2Conservative.x2.y-b2Conservative.x1.y;var length=Math.sqrt(dX*dX+dY*dY);if(length>FLT_EPSILON)
-{d*=b2_linearSlop/length;}
-if(body1.IsStatic())
-{body1.m_position.x=p1X;body1.m_position.y=p1Y;}
-else
-{body1.m_position.x=p1X-dX;body1.m_position.y=p1Y-dY;}
-body1.m_rotation=a1;body1.m_R.Set(a1);body1.QuickSyncShapes();if(body2.IsStatic())
-{body2.m_position.x=p2X;body2.m_position.y=p2Y;}
-else
-{body2.m_position.x=p2X+dX;body2.m_position.y=p2Y+dY;}
-body2.m_position.x=p2X+dX;body2.m_position.y=p2Y+dY;body2.m_rotation=a2;body2.m_R.Set(a2);body2.QuickSyncShapes();return true;}
-shape1.QuickSync(body1.m_position,body1.m_R);shape2.QuickSync(body2.m_position,body2.m_R);return false;};
-var b2NullContact=Class.create();Object.extend(b2NullContact.prototype,b2Contact.prototype);Object.extend(b2NullContact.prototype,{initialize:function(s1,s2){this.m_node1=new b2ContactNode();this.m_node2=new b2ContactNode();this.m_flags=0;if(!s1||!s2){this.m_shape1=null;this.m_shape2=null;return;}
-this.m_shape1=s1;this.m_shape2=s2;this.m_manifoldCount=0;this.m_friction=Math.sqrt(this.m_shape1.m_friction*this.m_shape2.m_friction);this.m_restitution=b2Math.b2Max(this.m_shape1.m_restitution,this.m_shape2.m_restitution);this.m_prev=null;this.m_next=null;this.m_node1.contact=null;this.m_node1.prev=null;this.m_node1.next=null;this.m_node1.other=null;this.m_node2.contact=null;this.m_node2.prev=null;this.m_node2.next=null;this.m_node2.other=null;},Evaluate:function(){},GetManifolds:function(){return null;}});
-var b2PolyAndCircleContact=Class.create();Object.extend(b2PolyAndCircleContact.prototype,b2Contact.prototype);Object.extend(b2PolyAndCircleContact.prototype,{initialize:function(s1,s2){this.m_node1=new b2ContactNode();this.m_node2=new b2ContactNode();this.m_flags=0;if(!s1||!s2){this.m_shape1=null;this.m_shape2=null;return;}
-this.m_shape1=s1;this.m_shape2=s2;this.m_manifoldCount=0;this.m_friction=Math.sqrt(this.m_shape1.m_friction*this.m_shape2.m_friction);this.m_restitution=b2Math.b2Max(this.m_shape1.m_restitution,this.m_shape2.m_restitution);this.m_prev=null;this.m_next=null;this.m_node1.contact=null;this.m_node1.prev=null;this.m_node1.next=null;this.m_node1.other=null;this.m_node2.contact=null;this.m_node2.prev=null;this.m_node2.next=null;this.m_node2.other=null;this.m_manifold=[new b2Manifold()];b2Settings.b2Assert(this.m_shape1.m_type==b2Shape.e_polyShape);b2Settings.b2Assert(this.m_shape2.m_type==b2Shape.e_circleShape);this.m_manifold[0].pointCount=0;this.m_manifold[0].points[0].normalImpulse=0.0;this.m_manifold[0].points[0].tangentImpulse=0.0;},Evaluate:function(){b2Collision.b2CollidePolyAndCircle(this.m_manifold[0],this.m_shape1,this.m_shape2,false);if(this.m_manifold[0].pointCount>0)
-{this.m_manifoldCount=1;}
-else
-{this.m_manifoldCount=0;}},GetManifolds:function()
-{return this.m_manifold;},m_manifold:[new b2Manifold()]})
-b2PolyAndCircleContact.Create=function(shape1,shape2,allocator){return new b2PolyAndCircleContact(shape1,shape2);};b2PolyAndCircleContact.Destroy=function(contact,allocator){};
-var b2PolyContact=Class.create();Object.extend(b2PolyContact.prototype,b2Contact.prototype);Object.extend(b2PolyContact.prototype,{initialize:function(s1,s2){this.m_node1=new b2ContactNode();this.m_node2=new b2ContactNode();this.m_flags=0;if(!s1||!s2){this.m_shape1=null;this.m_shape2=null;return;}
-this.m_shape1=s1;this.m_shape2=s2;this.m_manifoldCount=0;this.m_friction=Math.sqrt(this.m_shape1.m_friction*this.m_shape2.m_friction);this.m_restitution=b2Math.b2Max(this.m_shape1.m_restitution,this.m_shape2.m_restitution);this.m_prev=null;this.m_next=null;this.m_node1.contact=null;this.m_node1.prev=null;this.m_node1.next=null;this.m_node1.other=null;this.m_node2.contact=null;this.m_node2.prev=null;this.m_node2.next=null;this.m_node2.other=null;this.m0=new b2Manifold();this.m_manifold=[new b2Manifold()];this.m_manifold[0].pointCount=0;},m0:new b2Manifold(),Evaluate:function(){var tMani=this.m_manifold[0];var tPoints=this.m0.points;for(var k=0;k<tMani.pointCount;k++){var tPoint=tPoints[k];var tPoint0=tMani.points[k];tPoint.normalImpulse=tPoint0.normalImpulse;tPoint.tangentImpulse=tPoint0.tangentImpulse;tPoint.id=tPoint0.id.Copy();}
-this.m0.pointCount=tMani.pointCount;b2Collision.b2CollidePoly(tMani,this.m_shape1,this.m_shape2,false);if(tMani.pointCount>0)
-{var match=[false,false];for(var i=0;i<tMani.pointCount;++i)
-{var cp=tMani.points[i];cp.normalImpulse=0.0;cp.tangentImpulse=0.0;var idKey=cp.id.key;for(var j=0;j<this.m0.pointCount;++j)
-{if(match[j]==true)
-continue;var cp0=this.m0.points[j];var id0=cp0.id;if(id0.key==idKey)
-{match[j]=true;cp.normalImpulse=cp0.normalImpulse;cp.tangentImpulse=cp0.tangentImpulse;break;}}}
-this.m_manifoldCount=1;}
-else
-{this.m_manifoldCount=0;}},GetManifolds:function()
-{return this.m_manifold;},m_manifold:[new b2Manifold()]});b2PolyContact.Create=function(shape1,shape2,allocator){return new b2PolyContact(shape1,shape2);};b2PolyContact.Destroy=function(contact,allocator){};
-var b2ContactManager=Class.create();Object.extend(b2ContactManager.prototype,b2PairCallback.prototype);Object.extend(b2ContactManager.prototype,{initialize:function(){this.m_nullContact=new b2NullContact();this.m_world=null;this.m_destroyImmediate=false;},PairAdded:function(proxyUserData1,proxyUserData2){var shape1=proxyUserData1;var shape2=proxyUserData2;var body1=shape1.m_body;var body2=shape2.m_body;if(body1.IsStatic()&&body2.IsStatic())
-{return this.m_nullContact;}
-if(shape1.m_body==shape2.m_body)
-{return this.m_nullContact;}
-if(body2.IsConnected(body1))
-{return this.m_nullContact;}
-if(this.m_world.m_filter!=null&&this.m_world.m_filter.ShouldCollide(shape1,shape2)==false)
-{return this.m_nullContact;}
-if(body2.m_invMass==0.0)
-{var tempShape=shape1;shape1=shape2;shape2=tempShape;var tempBody=body1;body1=body2;body2=tempBody;}
-var contact=b2Contact.Create(shape1,shape2,this.m_world.m_blockAllocator);if(contact==null)
-{return this.m_nullContact;}
-else
-{contact.m_prev=null;contact.m_next=this.m_world.m_contactList;if(this.m_world.m_contactList!=null)
-{this.m_world.m_contactList.m_prev=contact;}
-this.m_world.m_contactList=contact;this.m_world.m_contactCount++;}
-return contact;},PairRemoved:function(proxyUserData1,proxyUserData2,pairUserData){if(pairUserData==null)
-{return;}
-var c=pairUserData;if(c!=this.m_nullContact)
-{if(this.m_destroyImmediate==true)
-{this.DestroyContact(c);c=null;}
-else
-{c.m_flags|=b2Contact.e_destroyFlag;}}},DestroyContact:function(c)
-{if(c.m_prev)
-{c.m_prev.m_next=c.m_next;}
-if(c.m_next)
-{c.m_next.m_prev=c.m_prev;}
-if(c==this.m_world.m_contactList)
-{this.m_world.m_contactList=c.m_next;}
-if(c.GetManifoldCount()>0)
-{var body1=c.m_shape1.m_body;var body2=c.m_shape2.m_body;var node1=c.m_node1;var node2=c.m_node2;body1.WakeUp();body2.WakeUp();if(node1.prev)
-{node1.prev.next=node1.next;}
-if(node1.next)
-{node1.next.prev=node1.prev;}
-if(node1==body1.m_contactList)
-{body1.m_contactList=node1.next;}
-node1.prev=null;node1.next=null;if(node2.prev)
-{node2.prev.next=node2.next;}
-if(node2.next)
-{node2.next.prev=node2.prev;}
-if(node2==body2.m_contactList)
-{body2.m_contactList=node2.next;}
-node2.prev=null;node2.next=null;}
-b2Contact.Destroy(c,this.m_world.m_blockAllocator);--this.m_world.m_contactCount;},CleanContactList:function()
-{var c=this.m_world.m_contactList;while(c!=null)
-{var c0=c;c=c.m_next;if(c0.m_flags&b2Contact.e_destroyFlag)
-{this.DestroyContact(c0);c0=null;}}},Collide:function()
-{var body1;var body2;var node1;var node2;for(var c=this.m_world.m_contactList;c!=null;c=c.m_next)
-{if(c.m_shape1.m_body.IsSleeping()&&c.m_shape2.m_body.IsSleeping())
-{continue;}
-var oldCount=c.GetManifoldCount();c.Evaluate();var newCount=c.GetManifoldCount();if(oldCount==0&&newCount>0)
-{body1=c.m_shape1.m_body;body2=c.m_shape2.m_body;node1=c.m_node1;node2=c.m_node2;node1.contact=c;node1.other=body2;node1.prev=null;node1.next=body1.m_contactList;if(node1.next!=null)
-{node1.next.prev=c.m_node1;}
-body1.m_contactList=c.m_node1;node2.contact=c;node2.other=body1;node2.prev=null;node2.next=body2.m_contactList;if(node2.next!=null)
-{node2.next.prev=node2;}
-body2.m_contactList=node2;}
-else if(oldCount>0&&newCount==0)
-{body1=c.m_shape1.m_body;body2=c.m_shape2.m_body;node1=c.m_node1;node2=c.m_node2;if(node1.prev)
-{node1.prev.next=node1.next;}
-if(node1.next)
-{node1.next.prev=node1.prev;}
-if(node1==body1.m_contactList)
-{body1.m_contactList=node1.next;}
-node1.prev=null;node1.next=null;if(node2.prev)
-{node2.prev.next=node2.next;}
-if(node2.next)
-{node2.next.prev=node2.prev;}
-if(node2==body2.m_contactList)
-{body2.m_contactList=node2.next;}
-node2.prev=null;node2.next=null;}}},m_world:null,m_nullContact:new b2NullContact(),m_destroyImmediate:null});
-var b2World=Class.create();b2World.prototype={initialize:function(worldAABB,gravity,doSleep){this.step=new b2TimeStep();this.m_contactManager=new b2ContactManager();this.m_listener=null;this.m_filter=b2CollisionFilter.b2_defaultFilter;this.m_bodyList=null;this.m_contactList=null;this.m_jointList=null;this.m_bodyCount=0;this.m_contactCount=0;this.m_jointCount=0;this.m_bodyDestroyList=null;this.m_allowSleep=doSleep;this.m_gravity=gravity;this.m_contactManager.m_world=this;this.m_broadPhase=new b2BroadPhase(worldAABB,this.m_contactManager);var bd=new b2BodyDef();this.m_groundBody=this.CreateBody(bd);},SetListener:function(listener){this.m_listener=listener;},SetFilter:function(filter){this.m_filter=filter;},CreateBody:function(def){var b=new b2Body(def,this);b.m_prev=null;b.m_next=this.m_bodyList;if(this.m_bodyList)
-{this.m_bodyList.m_prev=b;}
-this.m_bodyList=b;++this.m_bodyCount;return b;},DestroyBody:function(b)
-{if(b.m_flags&b2Body.e_destroyFlag)
-{return;}
-if(b.m_prev)
-{b.m_prev.m_next=b.m_next;}
-if(b.m_next)
-{b.m_next.m_prev=b.m_prev;}
-if(b==this.m_bodyList)
-{this.m_bodyList=b.m_next;}
-b.m_flags|=b2Body.e_destroyFlag;--this.m_bodyCount;b.m_prev=null;b.m_next=this.m_bodyDestroyList;this.m_bodyDestroyList=b;},CleanBodyList:function()
-{this.m_contactManager.m_destroyImmediate=true;var b=this.m_bodyDestroyList;while(b)
-{var b0=b;b=b.m_next;var jn=b0.m_jointList;while(jn)
-{var jn0=jn;jn=jn.next;if(this.m_listener)
-{this.m_listener.NotifyJointDestroyed(jn0.joint);}
-this.DestroyJoint(jn0.joint);}
-b0.Destroy();}
-this.m_bodyDestroyList=null;this.m_contactManager.m_destroyImmediate=false;},CreateJoint:function(def){var j=b2Joint.Create(def,this.m_blockAllocator);j.m_prev=null;j.m_next=this.m_jointList;if(this.m_jointList)
-{this.m_jointList.m_prev=j;}
-this.m_jointList=j;++this.m_jointCount;j.m_node1.joint=j;j.m_node1.other=j.m_body2;j.m_node1.prev=null;j.m_node1.next=j.m_body1.m_jointList;if(j.m_body1.m_jointList)j.m_body1.m_jointList.prev=j.m_node1;j.m_body1.m_jointList=j.m_node1;j.m_node2.joint=j;j.m_node2.other=j.m_body1;j.m_node2.prev=null;j.m_node2.next=j.m_body2.m_jointList;if(j.m_body2.m_jointList)j.m_body2.m_jointList.prev=j.m_node2;j.m_body2.m_jointList=j.m_node2;if(def.collideConnected==false)
-{var b=def.body1.m_shapeCount<def.body2.m_shapeCount?def.body1:def.body2;for(var s=b.m_shapeList;s;s=s.m_next)
-{s.ResetProxy(this.m_broadPhase);}}
-return j;},DestroyJoint:function(j)
-{var collideConnected=j.m_collideConnected;if(j.m_prev)
-{j.m_prev.m_next=j.m_next;}
-if(j.m_next)
-{j.m_next.m_prev=j.m_prev;}
-if(j==this.m_jointList)
-{this.m_jointList=j.m_next;}
-var body1=j.m_body1;var body2=j.m_body2;body1.WakeUp();body2.WakeUp();if(j.m_node1.prev)
-{j.m_node1.prev.next=j.m_node1.next;}
-if(j.m_node1.next)
-{j.m_node1.next.prev=j.m_node1.prev;}
-if(j.m_node1==body1.m_jointList)
-{body1.m_jointList=j.m_node1.next;}
-j.m_node1.prev=null;j.m_node1.next=null;if(j.m_node2.prev)
-{j.m_node2.prev.next=j.m_node2.next;}
-if(j.m_node2.next)
-{j.m_node2.next.prev=j.m_node2.prev;}
-if(j.m_node2==body2.m_jointList)
-{body2.m_jointList=j.m_node2.next;}
-j.m_node2.prev=null;j.m_node2.next=null;b2Joint.Destroy(j,this.m_blockAllocator);--this.m_jointCount;if(collideConnected==false)
-{var b=body1.m_shapeCount<body2.m_shapeCount?body1:body2;for(var s=b.m_shapeList;s;s=s.m_next)
-{s.ResetProxy(this.m_broadPhase);}}},GetGroundBody:function(){return this.m_groundBody;},step:new b2TimeStep(),Step:function(dt,iterations){var b;var other;this.step.dt=dt;this.step.iterations=iterations;if(dt>0.0)
-{this.step.inv_dt=1.0/dt;}
-else
-{this.step.inv_dt=0.0;}
-this.m_positionIterationCount=0;this.m_contactManager.CleanContactList();this.CleanBodyList();this.m_contactManager.Collide();var island=new b2Island(this.m_bodyCount,this.m_contactCount,this.m_jointCount,this.m_stackAllocator);for(b=this.m_bodyList;b!=null;b=b.m_next)
-{b.m_flags&=~b2Body.e_islandFlag;}
-for(var c=this.m_contactList;c!=null;c=c.m_next)
-{c.m_flags&=~b2Contact.e_islandFlag;}
-for(var j=this.m_jointList;j!=null;j=j.m_next)
-{j.m_islandFlag=false;}
-var stackSize=this.m_bodyCount;var stack=new Array(this.m_bodyCount);for(var k=0;k<this.m_bodyCount;k++)
-stack[k]=null;for(var seed=this.m_bodyList;seed!=null;seed=seed.m_next)
-{if(seed.m_flags&(b2Body.e_staticFlag|b2Body.e_islandFlag|b2Body.e_sleepFlag|b2Body.e_frozenFlag))
-{continue;}
-island.Clear();var stackCount=0;stack[stackCount++]=seed;seed.m_flags|=b2Body.e_islandFlag;;while(stackCount>0)
-{b=stack[--stackCount];island.AddBody(b);b.m_flags&=~b2Body.e_sleepFlag;if(b.m_flags&b2Body.e_staticFlag)
-{continue;}
-for(var cn=b.m_contactList;cn!=null;cn=cn.next)
-{if(cn.contact.m_flags&b2Contact.e_islandFlag)
-{continue;}
-island.AddContact(cn.contact);cn.contact.m_flags|=b2Contact.e_islandFlag;other=cn.other;if(other.m_flags&b2Body.e_islandFlag)
-{continue;}
-stack[stackCount++]=other;other.m_flags|=b2Body.e_islandFlag;}
-for(var jn=b.m_jointList;jn!=null;jn=jn.next)
-{if(jn.joint.m_islandFlag==true)
-{continue;}
-island.AddJoint(jn.joint);jn.joint.m_islandFlag=true;other=jn.other;if(other.m_flags&b2Body.e_islandFlag)
-{continue;}
-stack[stackCount++]=other;other.m_flags|=b2Body.e_islandFlag;}}
-island.Solve(this.step,this.m_gravity);this.m_positionIterationCount=b2Math.b2Max(this.m_positionIterationCount,b2Island.m_positionIterationCount);if(this.m_allowSleep)
-{island.UpdateSleep(dt);}
-for(var i=0;i<island.m_bodyCount;++i)
-{b=island.m_bodies[i];if(b.m_flags&b2Body.e_staticFlag)
-{b.m_flags&=~b2Body.e_islandFlag;}
-if(b.IsFrozen()&&this.m_listener)
-{var response=this.m_listener.NotifyBoundaryViolated(b);if(response==b2WorldListener.b2_destroyBody)
-{this.DestroyBody(b);b=null;island.m_bodies[i]=null;}}}}
-this.m_broadPhase.Commit();},Query:function(aabb,shapes,maxCount){var results=new Array();var count=this.m_broadPhase.QueryAABB(aabb,results,maxCount);for(var i=0;i<count;++i)
-{shapes[i]=results[i];}
-return count;},GetBodyList:function(){return this.m_bodyList;},GetJointList:function(){return this.m_jointList;},GetContactList:function(){return this.m_contactList;},m_blockAllocator:null,m_stackAllocator:null,m_broadPhase:null,m_contactManager:new b2ContactManager(),m_bodyList:null,m_contactList:null,m_jointList:null,m_bodyCount:0,m_contactCount:0,m_jointCount:0,m_bodyDestroyList:null,m_gravity:null,m_allowSleep:null,m_groundBody:null,m_listener:null,m_filter:null,m_positionIterationCount:0};b2World.s_enablePositionCorrection=1;b2World.s_enableWarmStarting=1;
-var b2WorldListener=Class.create();b2WorldListener.prototype={NotifyJointDestroyed:function(joint){},NotifyBoundaryViolated:function(body)
-{return b2WorldListener.b2_freezeBody;},initialize:function(){}};b2WorldListener.b2_freezeBody=0;b2WorldListener.b2_destroyBody=1;
-var b2JointNode=Class.create();b2JointNode.prototype={other:null,joint:null,prev:null,next:null,initialize:function(){}}
-
-var b2Joint=Class.create();b2Joint.prototype={GetType:function(){return this.m_type;},GetAnchor1:function(){return null},GetAnchor2:function(){return null},GetReactionForce:function(invTimeStep){return null},GetReactionTorque:function(invTimeStep){return 0.0},GetBody1:function()
-{return this.m_body1;},GetBody2:function()
-{return this.m_body2;},GetNext:function(){return this.m_next;},GetUserData:function(){return this.m_userData;},initialize:function(def){this.m_node1=new b2JointNode();this.m_node2=new b2JointNode();this.m_type=def.type;this.m_prev=null;this.m_next=null;this.m_body1=def.body1;this.m_body2=def.body2;this.m_collideConnected=def.collideConnected;this.m_islandFlag=false;this.m_userData=def.userData;},PrepareVelocitySolver:function(){},SolveVelocityConstraints:function(step){},PreparePositionSolver:function(){},SolvePositionConstraints:function(){return false},m_type:0,m_prev:null,m_next:null,m_node1:new b2JointNode(),m_node2:new b2JointNode(),m_body1:null,m_body2:null,m_islandFlag:null,m_collideConnected:null,m_userData:null};b2Joint.Create=function(def,allocator){var joint=null;switch(def.type)
-{case b2Joint.e_distanceJoint:{joint=new b2DistanceJoint(def);}
-break;case b2Joint.e_mouseJoint:{joint=new b2MouseJoint(def);}
-break;case b2Joint.e_prismaticJoint:{joint=new b2PrismaticJoint(def);}
-break;case b2Joint.e_revoluteJoint:{joint=new b2RevoluteJoint(def);}
-break;case b2Joint.e_pulleyJoint:{joint=new b2PulleyJoint(def);}
-break;case b2Joint.e_gearJoint:{joint=new b2GearJoint(def);}
-break;default:break;}
-return joint;};b2Joint.Destroy=function(joint,allocator){};b2Joint.e_unknownJoint=0;b2Joint.e_revoluteJoint=1;b2Joint.e_prismaticJoint=2;b2Joint.e_distanceJoint=3;b2Joint.e_pulleyJoint=4;b2Joint.e_mouseJoint=5;b2Joint.e_gearJoint=6;b2Joint.e_inactiveLimit=0;b2Joint.e_atLowerLimit=1;b2Joint.e_atUpperLimit=2;b2Joint.e_equalLimits=3;
-var b2JointDef=Class.create();b2JointDef.prototype={initialize:function()
-{this.type=b2Joint.e_unknownJoint;this.userData=null;this.body1=null;this.body2=null;this.collideConnected=false;},type:0,userData:null,body1:null,body2:null,collideConnected:null}
-
-var b2DistanceJoint=Class.create();Object.extend(b2DistanceJoint.prototype,b2Joint.prototype);Object.extend(b2DistanceJoint.prototype,{initialize:function(def){this.m_node1=new b2JointNode();this.m_node2=new b2JointNode();this.m_type=def.type;this.m_prev=null;this.m_next=null;this.m_body1=def.body1;this.m_body2=def.body2;this.m_collideConnected=def.collideConnected;this.m_islandFlag=false;this.m_userData=def.userData;this.m_localAnchor1=new b2Vec2();this.m_localAnchor2=new b2Vec2();this.m_u=new b2Vec2();var tMat;var tX;var tY;tMat=this.m_body1.m_R;tX=def.anchorPoint1.x-this.m_body1.m_position.x;tY=def.anchorPoint1.y-this.m_body1.m_position.y;this.m_localAnchor1.x=tX*tMat.col1.x+tY*tMat.col1.y;this.m_localAnchor1.y=tX*tMat.col2.x+tY*tMat.col2.y;tMat=this.m_body2.m_R;tX=def.anchorPoint2.x-this.m_body2.m_position.x;tY=def.anchorPoint2.y-this.m_body2.m_position.y;this.m_localAnchor2.x=tX*tMat.col1.x+tY*tMat.col1.y;this.m_localAnchor2.y=tX*tMat.col2.x+tY*tMat.col2.y;tX=def.anchorPoint2.x-def.anchorPoint1.x;tY=def.anchorPoint2.y-def.anchorPoint1.y;this.m_length=Math.sqrt(tX*tX+tY*tY);this.m_impulse=0.0;},PrepareVelocitySolver:function(){var tMat;tMat=this.m_body1.m_R;var r1X=tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y;var r1Y=tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y;tMat=this.m_body2.m_R;var r2X=tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y;var r2Y=tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y;this.m_u.x=this.m_body2.m_position.x+r2X-this.m_body1.m_position.x-r1X;this.m_u.y=this.m_body2.m_position.y+r2Y-this.m_body1.m_position.y-r1Y;var length=Math.sqrt(this.m_u.x*this.m_u.x+this.m_u.y*this.m_u.y);if(length>b2Settings.b2_linearSlop)
-{this.m_u.Multiply(1.0/length);}
-else
-{this.m_u.SetZero();}
-var cr1u=(r1X*this.m_u.y-r1Y*this.m_u.x);var cr2u=(r2X*this.m_u.y-r2Y*this.m_u.x);this.m_mass=this.m_body1.m_invMass+this.m_body1.m_invI*cr1u*cr1u+this.m_body2.m_invMass+this.m_body2.m_invI*cr2u*cr2u;this.m_mass=1.0/this.m_mass;if(b2World.s_enableWarmStarting)
-{var PX=this.m_impulse*this.m_u.x;var PY=this.m_impulse*this.m_u.y;this.m_body1.m_linearVelocity.x-=this.m_body1.m_invMass*PX;this.m_body1.m_linearVelocity.y-=this.m_body1.m_invMass*PY;this.m_body1.m_angularVelocity-=this.m_body1.m_invI*(r1X*PY-r1Y*PX);this.m_body2.m_linearVelocity.x+=this.m_body2.m_invMass*PX;this.m_body2.m_linearVelocity.y+=this.m_body2.m_invMass*PY;this.m_body2.m_angularVelocity+=this.m_body2.m_invI*(r2X*PY-r2Y*PX);}
-else
-{this.m_impulse=0.0;}},SolveVelocityConstraints:function(step){var tMat;tMat=this.m_body1.m_R;var r1X=tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y;var r1Y=tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y;tMat=this.m_body2.m_R;var r2X=tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y;var r2Y=tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y;var v1X=this.m_body1.m_linearVelocity.x+(-this.m_body1.m_angularVelocity*r1Y);var v1Y=this.m_body1.m_linearVelocity.y+(this.m_body1.m_angularVelocity*r1X);var v2X=this.m_body2.m_linearVelocity.x+(-this.m_body2.m_angularVelocity*r2Y);var v2Y=this.m_body2.m_linearVelocity.y+(this.m_body2.m_angularVelocity*r2X);var Cdot=(this.m_u.x*(v2X-v1X)+this.m_u.y*(v2Y-v1Y));var impulse=-this.m_mass*Cdot;this.m_impulse+=impulse;var PX=impulse*this.m_u.x;var PY=impulse*this.m_u.y;this.m_body1.m_linearVelocity.x-=this.m_body1.m_invMass*PX;this.m_body1.m_linearVelocity.y-=this.m_body1.m_invMass*PY;this.m_body1.m_angularVelocity-=this.m_body1.m_invI*(r1X*PY-r1Y*PX);this.m_body2.m_linearVelocity.x+=this.m_body2.m_invMass*PX;this.m_body2.m_linearVelocity.y+=this.m_body2.m_invMass*PY;this.m_body2.m_angularVelocity+=this.m_body2.m_invI*(r2X*PY-r2Y*PX);},SolvePositionConstraints:function(){var tMat;tMat=this.m_body1.m_R;var r1X=tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y;var r1Y=tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y;tMat=this.m_body2.m_R;var r2X=tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y;var r2Y=tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y;var dX=this.m_body2.m_position.x+r2X-this.m_body1.m_position.x-r1X;var dY=this.m_body2.m_position.y+r2Y-this.m_body1.m_position.y-r1Y;var length=Math.sqrt(dX*dX+dY*dY);dX/=length;dY/=length;var C=length-this.m_length;C=b2Math.b2Clamp(C,-b2Settings.b2_maxLinearCorrection,b2Settings.b2_maxLinearCorrection);var impulse=-this.m_mass*C;this.m_u.Set(dX,dY);var PX=impulse*this.m_u.x;var PY=impulse*this.m_u.y;this.m_body1.m_position.x-=this.m_body1.m_invMass*PX;this.m_body1.m_position.y-=this.m_body1.m_invMass*PY;this.m_body1.m_rotation-=this.m_body1.m_invI*(r1X*PY-r1Y*PX);this.m_body2.m_position.x+=this.m_body2.m_invMass*PX;this.m_body2.m_position.y+=this.m_body2.m_invMass*PY;this.m_body2.m_rotation+=this.m_body2.m_invI*(r2X*PY-r2Y*PX);this.m_body1.m_R.Set(this.m_body1.m_rotation);this.m_body2.m_R.Set(this.m_body2.m_rotation);return b2Math.b2Abs(C)<b2Settings.b2_linearSlop;},GetAnchor1:function(){return b2Math.AddVV(this.m_body1.m_position,b2Math.b2MulMV(this.m_body1.m_R,this.m_localAnchor1));},GetAnchor2:function(){return b2Math.AddVV(this.m_body2.m_position,b2Math.b2MulMV(this.m_body2.m_R,this.m_localAnchor2));},GetReactionForce:function(invTimeStep)
-{var F=new b2Vec2();F.SetV(this.m_u);F.Multiply(this.m_impulse*invTimeStep);return F;},GetReactionTorque:function(invTimeStep)
-{return 0.0;},m_localAnchor1:new b2Vec2(),m_localAnchor2:new b2Vec2(),m_u:new b2Vec2(),m_impulse:null,m_mass:null,m_length:null});
-var b2DistanceJointDef=Class.create();Object.extend(b2DistanceJointDef.prototype,b2JointDef.prototype);Object.extend(b2DistanceJointDef.prototype,{initialize:function()
-{this.type=b2Joint.e_unknownJoint;this.userData=null;this.body1=null;this.body2=null;this.collideConnected=false;this.anchorPoint1=new b2Vec2();this.anchorPoint2=new b2Vec2();this.type=b2Joint.e_distanceJoint;},anchorPoint1:new b2Vec2(),anchorPoint2:new b2Vec2()});
-var b2Jacobian=Class.create();b2Jacobian.prototype={linear1:new b2Vec2(),angular1:null,linear2:new b2Vec2(),angular2:null,SetZero:function(){this.linear1.SetZero();this.angular1=0.0;this.linear2.SetZero();this.angular2=0.0;},Set:function(x1,a1,x2,a2){this.linear1.SetV(x1);this.angular1=a1;this.linear2.SetV(x2);this.angular2=a2;},Compute:function(x1,a1,x2,a2){return(this.linear1.x*x1.x+this.linear1.y*x1.y)+this.angular1*a1+(this.linear2.x*x2.x+this.linear2.y*x2.y)+this.angular2*a2;},initialize:function(){this.linear1=new b2Vec2();this.linear2=new b2Vec2();}};
-var b2GearJoint=Class.create();Object.extend(b2GearJoint.prototype,b2Joint.prototype);Object.extend(b2GearJoint.prototype,{GetAnchor1:function(){var tMat=this.m_body1.m_R;return new b2Vec2(this.m_body1.m_position.x+(tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y),this.m_body1.m_position.y+(tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y));},GetAnchor2:function(){var tMat=this.m_body2.m_R;return new b2Vec2(this.m_body2.m_position.x+(tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y),this.m_body2.m_position.y+(tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y));},GetReactionForce:function(invTimeStep){return new b2Vec2();},GetReactionTorque:function(invTimeStep){return 0.0;},GetRatio:function(){return this.m_ratio;},initialize:function(def){this.m_node1=new b2JointNode();this.m_node2=new b2JointNode();this.m_type=def.type;this.m_prev=null;this.m_next=null;this.m_body1=def.body1;this.m_body2=def.body2;this.m_collideConnected=def.collideConnected;this.m_islandFlag=false;this.m_userData=def.userData;this.m_groundAnchor1=new b2Vec2();this.m_groundAnchor2=new b2Vec2();this.m_localAnchor1=new b2Vec2();this.m_localAnchor2=new b2Vec2();this.m_J=new b2Jacobian();this.m_revolute1=null;this.m_prismatic1=null;this.m_revolute2=null;this.m_prismatic2=null;var coordinate1;var coordinate2;this.m_ground1=def.joint1.m_body1;this.m_body1=def.joint1.m_body2;if(def.joint1.m_type==b2Joint.e_revoluteJoint)
-{this.m_revolute1=def.joint1;this.m_groundAnchor1.SetV(this.m_revolute1.m_localAnchor1);this.m_localAnchor1.SetV(this.m_revolute1.m_localAnchor2);coordinate1=this.m_revolute1.GetJointAngle();}
-else
-{this.m_prismatic1=def.joint1;this.m_groundAnchor1.SetV(this.m_prismatic1.m_localAnchor1);this.m_localAnchor1.SetV(this.m_prismatic1.m_localAnchor2);coordinate1=this.m_prismatic1.GetJointTranslation();}
-this.m_ground2=def.joint2.m_body1;this.m_body2=def.joint2.m_body2;if(def.joint2.m_type==b2Joint.e_revoluteJoint)
-{this.m_revolute2=def.joint2;this.m_groundAnchor2.SetV(this.m_revolute2.m_localAnchor1);this.m_localAnchor2.SetV(this.m_revolute2.m_localAnchor2);coordinate2=this.m_revolute2.GetJointAngle();}
-else
-{this.m_prismatic2=def.joint2;this.m_groundAnchor2.SetV(this.m_prismatic2.m_localAnchor1);this.m_localAnchor2.SetV(this.m_prismatic2.m_localAnchor2);coordinate2=this.m_prismatic2.GetJointTranslation();}
-this.m_ratio=def.ratio;this.m_constant=coordinate1+this.m_ratio*coordinate2;this.m_impulse=0.0;},PrepareVelocitySolver:function(){var g1=this.m_ground1;var g2=this.m_ground2;var b1=this.m_body1;var b2=this.m_body2;var ugX;var ugY;var rX;var rY;var tMat;var tVec;var crug;var K=0.0;this.m_J.SetZero();if(this.m_revolute1)
-{this.m_J.angular1=-1.0;K+=b1.m_invI;}
-else
-{tMat=g1.m_R;tVec=this.m_prismatic1.m_localXAxis1;ugX=tMat.col1.x*tVec.x+tMat.col2.x*tVec.y;ugY=tMat.col1.y*tVec.x+tMat.col2.y*tVec.y;tMat=b1.m_R;rX=tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y;rY=tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y;crug=rX*ugY-rY*ugX;this.m_J.linear1.Set(-ugX,-ugY);this.m_J.angular1=-crug;K+=b1.m_invMass+b1.m_invI*crug*crug;}
-if(this.m_revolute2)
-{this.m_J.angular2=-this.m_ratio;K+=this.m_ratio*this.m_ratio*b2.m_invI;}
-else
-{tMat=g2.m_R;tVec=this.m_prismatic2.m_localXAxis1;ugX=tMat.col1.x*tVec.x+tMat.col2.x*tVec.y;ugY=tMat.col1.y*tVec.x+tMat.col2.y*tVec.y;tMat=b2.m_R;rX=tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y;rY=tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y;crug=rX*ugY-rY*ugX;this.m_J.linear2.Set(-this.m_ratio*ugX,-this.m_ratio*ugY);this.m_J.angular2=-this.m_ratio*crug;K+=this.m_ratio*this.m_ratio*(b2.m_invMass+b2.m_invI*crug*crug);}
-this.m_mass=1.0/K;b1.m_linearVelocity.x+=b1.m_invMass*this.m_impulse*this.m_J.linear1.x;b1.m_linearVelocity.y+=b1.m_invMass*this.m_impulse*this.m_J.linear1.y;b1.m_angularVelocity+=b1.m_invI*this.m_impulse*this.m_J.angular1;b2.m_linearVelocity.x+=b2.m_invMass*this.m_impulse*this.m_J.linear2.x;b2.m_linearVelocity.y+=b2.m_invMass*this.m_impulse*this.m_J.linear2.y;b2.m_angularVelocity+=b2.m_invI*this.m_impulse*this.m_J.angular2;},SolveVelocityConstraints:function(step){var b1=this.m_body1;var b2=this.m_body2;var Cdot=this.m_J.Compute(b1.m_linearVelocity,b1.m_angularVelocity,b2.m_linearVelocity,b2.m_angularVelocity);var impulse=-this.m_mass*Cdot;this.m_impulse+=impulse;b1.m_linearVelocity.x+=b1.m_invMass*impulse*this.m_J.linear1.x;b1.m_linearVelocity.y+=b1.m_invMass*impulse*this.m_J.linear1.y;b1.m_angularVelocity+=b1.m_invI*impulse*this.m_J.angular1;b2.m_linearVelocity.x+=b2.m_invMass*impulse*this.m_J.linear2.x;b2.m_linearVelocity.y+=b2.m_invMass*impulse*this.m_J.linear2.y;b2.m_angularVelocity+=b2.m_invI*impulse*this.m_J.angular2;},SolvePositionConstraints:function(){var linearError=0.0;var b1=this.m_body1;var b2=this.m_body2;var coordinate1;var coordinate2;if(this.m_revolute1)
-{coordinate1=this.m_revolute1.GetJointAngle();}
-else
-{coordinate1=this.m_prismatic1.GetJointTranslation();}
-if(this.m_revolute2)
-{coordinate2=this.m_revolute2.GetJointAngle();}
-else
-{coordinate2=this.m_prismatic2.GetJointTranslation();}
-var C=this.m_constant-(coordinate1+this.m_ratio*coordinate2);var impulse=-this.m_mass*C;b1.m_position.x+=b1.m_invMass*impulse*this.m_J.linear1.x;b1.m_position.y+=b1.m_invMass*impulse*this.m_J.linear1.y;b1.m_rotation+=b1.m_invI*impulse*this.m_J.angular1;b2.m_position.x+=b2.m_invMass*impulse*this.m_J.linear2.x;b2.m_position.y+=b2.m_invMass*impulse*this.m_J.linear2.y;b2.m_rotation+=b2.m_invI*impulse*this.m_J.angular2;b1.m_R.Set(b1.m_rotation);b2.m_R.Set(b2.m_rotation);return linearError<b2Settings.b2_linearSlop;},m_ground1:null,m_ground2:null,m_revolute1:null,m_prismatic1:null,m_revolute2:null,m_prismatic2:null,m_groundAnchor1:new b2Vec2(),m_groundAnchor2:new b2Vec2(),m_localAnchor1:new b2Vec2(),m_localAnchor2:new b2Vec2(),m_J:new b2Jacobian(),m_constant:null,m_ratio:null,m_mass:null,m_impulse:null});
-var b2GearJointDef=Class.create();Object.extend(b2GearJointDef.prototype,b2JointDef.prototype);Object.extend(b2GearJointDef.prototype,{initialize:function()
-{this.type=b2Joint.e_gearJoint;this.joint1=null;this.joint2=null;this.ratio=1.0;},joint1:null,joint2:null,ratio:null});
-var b2MouseJoint=Class.create();Object.extend(b2MouseJoint.prototype,b2Joint.prototype);Object.extend(b2MouseJoint.prototype,{GetAnchor1:function(){return this.m_target;},GetAnchor2:function(){var tVec=b2Math.b2MulMV(this.m_body2.m_R,this.m_localAnchor);tVec.Add(this.m_body2.m_position);return tVec;},GetReactionForce:function(invTimeStep)
-{var F=new b2Vec2();F.SetV(this.m_impulse);F.Multiply(invTimeStep);return F;},GetReactionTorque:function(invTimeStep)
-{return 0.0;},SetTarget:function(target){this.m_body2.WakeUp();this.m_target=target;},initialize:function(def){this.m_node1=new b2JointNode();this.m_node2=new b2JointNode();this.m_type=def.type;this.m_prev=null;this.m_next=null;this.m_body1=def.body1;this.m_body2=def.body2;this.m_collideConnected=def.collideConnected;this.m_islandFlag=false;this.m_userData=def.userData;this.K=new b2Mat22();this.K1=new b2Mat22();this.K2=new b2Mat22();this.m_localAnchor=new b2Vec2();this.m_target=new b2Vec2();this.m_impulse=new b2Vec2();this.m_ptpMass=new b2Mat22();this.m_C=new b2Vec2();this.m_target.SetV(def.target);var tX=this.m_target.x-this.m_body2.m_position.x;var tY=this.m_target.y-this.m_body2.m_position.y;this.m_localAnchor.x=(tX*this.m_body2.m_R.col1.x+tY*this.m_body2.m_R.col1.y);this.m_localAnchor.y=(tX*this.m_body2.m_R.col2.x+tY*this.m_body2.m_R.col2.y);this.m_maxForce=def.maxForce;this.m_impulse.SetZero();var mass=this.m_body2.m_mass;var omega=2.0*b2Settings.b2_pi*def.frequencyHz;var d=2.0*mass*def.dampingRatio*omega;var k=mass*omega*omega;this.m_gamma=1.0/(d+def.timeStep*k);this.m_beta=def.timeStep*k/(d+def.timeStep*k);},K:new b2Mat22(),K1:new b2Mat22(),K2:new b2Mat22(),PrepareVelocitySolver:function(){var b=this.m_body2;var tMat;tMat=b.m_R;var rX=tMat.col1.x*this.m_localAnchor.x+tMat.col2.x*this.m_localAnchor.y;var rY=tMat.col1.y*this.m_localAnchor.x+tMat.col2.y*this.m_localAnchor.y;var invMass=b.m_invMass;var invI=b.m_invI;this.K1.col1.x=invMass;this.K1.col2.x=0.0;this.K1.col1.y=0.0;this.K1.col2.y=invMass;this.K2.col1.x=invI*rY*rY;this.K2.col2.x=-invI*rX*rY;this.K2.col1.y=-invI*rX*rY;this.K2.col2.y=invI*rX*rX;this.K.SetM(this.K1);this.K.AddM(this.K2);this.K.col1.x+=this.m_gamma;this.K.col2.y+=this.m_gamma;this.K.Invert(this.m_ptpMass);this.m_C.x=b.m_position.x+rX-this.m_target.x;this.m_C.y=b.m_position.y+rY-this.m_target.y;b.m_angularVelocity*=0.98;var PX=this.m_impulse.x;var PY=this.m_impulse.y;b.m_linearVelocity.x+=invMass*PX;b.m_linearVelocity.y+=invMass*PY;b.m_angularVelocity+=invI*(rX*PY-rY*PX);},SolveVelocityConstraints:function(step){var body=this.m_body2;var tMat;tMat=body.m_R;var rX=tMat.col1.x*this.m_localAnchor.x+tMat.col2.x*this.m_localAnchor.y;var rY=tMat.col1.y*this.m_localAnchor.x+tMat.col2.y*this.m_localAnchor.y;var CdotX=body.m_linearVelocity.x+(-body.m_angularVelocity*rY);var CdotY=body.m_linearVelocity.y+(body.m_angularVelocity*rX);tMat=this.m_ptpMass;var tX=CdotX+(this.m_beta*step.inv_dt)*this.m_C.x+this.m_gamma*this.m_impulse.x;var tY=CdotY+(this.m_beta*step.inv_dt)*this.m_C.y+this.m_gamma*this.m_impulse.y;var impulseX=-(tMat.col1.x*tX+tMat.col2.x*tY);var impulseY=-(tMat.col1.y*tX+tMat.col2.y*tY);var oldImpulseX=this.m_impulse.x;var oldImpulseY=this.m_impulse.y;this.m_impulse.x+=impulseX;this.m_impulse.y+=impulseY;var length=this.m_impulse.Length();if(length>step.dt*this.m_maxForce)
-{this.m_impulse.Multiply(step.dt*this.m_maxForce/length);}
-impulseX=this.m_impulse.x-oldImpulseX;impulseY=this.m_impulse.y-oldImpulseY;body.m_linearVelocity.x+=body.m_invMass*impulseX;body.m_linearVelocity.y+=body.m_invMass*impulseY;body.m_angularVelocity+=body.m_invI*(rX*impulseY-rY*impulseX);},SolvePositionConstraints:function(){return true;},m_localAnchor:new b2Vec2(),m_target:new b2Vec2(),m_impulse:new b2Vec2(),m_ptpMass:new b2Mat22(),m_C:new b2Vec2(),m_maxForce:null,m_beta:null,m_gamma:null});
-var b2MouseJointDef=Class.create();Object.extend(b2MouseJointDef.prototype,b2JointDef.prototype);Object.extend(b2MouseJointDef.prototype,{initialize:function()
-{this.type=b2Joint.e_unknownJoint;this.userData=null;this.body1=null;this.body2=null;this.collideConnected=false;this.target=new b2Vec2();this.type=b2Joint.e_mouseJoint;this.maxForce=0.0;this.frequencyHz=5.0;this.dampingRatio=0.7;this.timeStep=1.0/60.0;},target:new b2Vec2(),maxForce:null,frequencyHz:null,dampingRatio:null,timeStep:null});
-var b2PrismaticJoint=Class.create();Object.extend(b2PrismaticJoint.prototype,b2Joint.prototype);Object.extend(b2PrismaticJoint.prototype,{GetAnchor1:function(){var b1=this.m_body1;var tVec=new b2Vec2();tVec.SetV(this.m_localAnchor1);tVec.MulM(b1.m_R);tVec.Add(b1.m_position);return tVec;},GetAnchor2:function(){var b2=this.m_body2;var tVec=new b2Vec2();tVec.SetV(this.m_localAnchor2);tVec.MulM(b2.m_R);tVec.Add(b2.m_position);return tVec;},GetJointTranslation:function(){var b1=this.m_body1;var b2=this.m_body2;var tMat;tMat=b1.m_R;var r1X=tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y;var r1Y=tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y;tMat=b2.m_R;var r2X=tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y;var r2Y=tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y;var p1X=b1.m_position.x+r1X;var p1Y=b1.m_position.y+r1Y;var p2X=b2.m_position.x+r2X;var p2Y=b2.m_position.y+r2Y;var dX=p2X-p1X;var dY=p2Y-p1Y;tMat=b1.m_R;var ax1X=tMat.col1.x*this.m_localXAxis1.x+tMat.col2.x*this.m_localXAxis1.y;var ax1Y=tMat.col1.y*this.m_localXAxis1.x+tMat.col2.y*this.m_localXAxis1.y;var translation=ax1X*dX+ax1Y*dY;return translation;},GetJointSpeed:function(){var b1=this.m_body1;var b2=this.m_body2;var tMat;tMat=b1.m_R;var r1X=tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y;var r1Y=tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y;tMat=b2.m_R;var r2X=tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y;var r2Y=tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y;var p1X=b1.m_position.x+r1X;var p1Y=b1.m_position.y+r1Y;var p2X=b2.m_position.x+r2X;var p2Y=b2.m_position.y+r2Y;var dX=p2X-p1X;var dY=p2Y-p1Y;tMat=b1.m_R;var ax1X=tMat.col1.x*this.m_localXAxis1.x+tMat.col2.x*this.m_localXAxis1.y;var ax1Y=tMat.col1.y*this.m_localXAxis1.x+tMat.col2.y*this.m_localXAxis1.y;var v1=b1.m_linearVelocity;var v2=b2.m_linearVelocity;var w1=b1.m_angularVelocity;var w2=b2.m_angularVelocity;var speed=(dX*(-w1*ax1Y)+dY*(w1*ax1X))+(ax1X*(((v2.x+(-w2*r2Y))-v1.x)-(-w1*r1Y))+ax1Y*(((v2.y+(w2*r2X))-v1.y)-(w1*r1X)));return speed;},GetMotorForce:function(invTimeStep){return invTimeStep*this.m_motorImpulse;},SetMotorSpeed:function(speed)
-{this.m_motorSpeed=speed;},SetMotorForce:function(force)
-{this.m_maxMotorForce=force;},GetReactionForce:function(invTimeStep)
-{var tImp=invTimeStep*this.m_limitImpulse;var tMat;tMat=this.m_body1.m_R;var ax1X=tImp*(tMat.col1.x*this.m_localXAxis1.x+tMat.col2.x*this.m_localXAxis1.y);var ax1Y=tImp*(tMat.col1.y*this.m_localXAxis1.x+tMat.col2.y*this.m_localXAxis1.y);var ay1X=tImp*(tMat.col1.x*this.m_localYAxis1.x+tMat.col2.x*this.m_localYAxis1.y);var ay1Y=tImp*(tMat.col1.y*this.m_localYAxis1.x+tMat.col2.y*this.m_localYAxis1.y);return new b2Vec2(ax1X+ay1X,ax1Y+ay1Y);},GetReactionTorque:function(invTimeStep)
-{return invTimeStep*this.m_angularImpulse;},initialize:function(def){this.m_node1=new b2JointNode();this.m_node2=new b2JointNode();this.m_type=def.type;this.m_prev=null;this.m_next=null;this.m_body1=def.body1;this.m_body2=def.body2;this.m_collideConnected=def.collideConnected;this.m_islandFlag=false;this.m_userData=def.userData;this.m_localAnchor1=new b2Vec2();this.m_localAnchor2=new b2Vec2();this.m_localXAxis1=new b2Vec2();this.m_localYAxis1=new b2Vec2();this.m_linearJacobian=new b2Jacobian();this.m_motorJacobian=new b2Jacobian();var tMat;var tX;var tY;tMat=this.m_body1.m_R;tX=(def.anchorPoint.x-this.m_body1.m_position.x);tY=(def.anchorPoint.y-this.m_body1.m_position.y);this.m_localAnchor1.Set((tX*tMat.col1.x+tY*tMat.col1.y),(tX*tMat.col2.x+tY*tMat.col2.y));tMat=this.m_body2.m_R;tX=(def.anchorPoint.x-this.m_body2.m_position.x);tY=(def.anchorPoint.y-this.m_body2.m_position.y);this.m_localAnchor2.Set((tX*tMat.col1.x+tY*tMat.col1.y),(tX*tMat.col2.x+tY*tMat.col2.y));tMat=this.m_body1.m_R;tX=def.axis.x;tY=def.axis.y;this.m_localXAxis1.Set((tX*tMat.col1.x+tY*tMat.col1.y),(tX*tMat.col2.x+tY*tMat.col2.y));this.m_localYAxis1.x=-this.m_localXAxis1.y;this.m_localYAxis1.y=this.m_localXAxis1.x;this.m_initialAngle=this.m_body2.m_rotation-this.m_body1.m_rotation;this.m_linearJacobian.SetZero();this.m_linearMass=0.0;this.m_linearImpulse=0.0;this.m_angularMass=0.0;this.m_angularImpulse=0.0;this.m_motorJacobian.SetZero();this.m_motorMass=0.0;this.m_motorImpulse=0.0;this.m_limitImpulse=0.0;this.m_limitPositionImpulse=0.0;this.m_lowerTranslation=def.lowerTranslation;this.m_upperTranslation=def.upperTranslation;this.m_maxMotorForce=def.motorForce;this.m_motorSpeed=def.motorSpeed;this.m_enableLimit=def.enableLimit;this.m_enableMotor=def.enableMotor;},PrepareVelocitySolver:function(){var b1=this.m_body1;var b2=this.m_body2;var tMat;tMat=b1.m_R;var r1X=tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y;var r1Y=tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y;tMat=b2.m_R;var r2X=tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y;var r2Y=tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y;var invMass1=b1.m_invMass;var invMass2=b2.m_invMass;var invI1=b1.m_invI;var invI2=b2.m_invI;tMat=b1.m_R;var ay1X=tMat.col1.x*this.m_localYAxis1.x+tMat.col2.x*this.m_localYAxis1.y;var ay1Y=tMat.col1.y*this.m_localYAxis1.x+tMat.col2.y*this.m_localYAxis1.y;var eX=b2.m_position.x+r2X-b1.m_position.x;var eY=b2.m_position.y+r2Y-b1.m_position.y;this.m_linearJacobian.linear1.x=-ay1X;this.m_linearJacobian.linear1.y=-ay1Y;this.m_linearJacobian.linear2.x=ay1X;this.m_linearJacobian.linear2.y=ay1Y;this.m_linearJacobian.angular1=-(eX*ay1Y-eY*ay1X);this.m_linearJacobian.angular2=r2X*ay1Y-r2Y*ay1X;this.m_linearMass=invMass1+invI1*this.m_linearJacobian.angular1*this.m_linearJacobian.angular1+
-invMass2+invI2*this.m_linearJacobian.angular2*this.m_linearJacobian.angular2;this.m_linearMass=1.0/this.m_linearMass;this.m_angularMass=1.0/(invI1+invI2);if(this.m_enableLimit||this.m_enableMotor)
-{tMat=b1.m_R;var ax1X=tMat.col1.x*this.m_localXAxis1.x+tMat.col2.x*this.m_localXAxis1.y;var ax1Y=tMat.col1.y*this.m_localXAxis1.x+tMat.col2.y*this.m_localXAxis1.y;this.m_motorJacobian.linear1.x=-ax1X;this.m_motorJacobian.linear1.y=-ax1Y;this.m_motorJacobian.linear2.x=ax1X;this.m_motorJacobian.linear2.y=ax1Y;this.m_motorJacobian.angular1=-(eX*ax1Y-eY*ax1X);this.m_motorJacobian.angular2=r2X*ax1Y-r2Y*ax1X;this.m_motorMass=invMass1+invI1*this.m_motorJacobian.angular1*this.m_motorJacobian.angular1+
-invMass2+invI2*this.m_motorJacobian.angular2*this.m_motorJacobian.angular2;this.m_motorMass=1.0/this.m_motorMass;if(this.m_enableLimit)
-{var dX=eX-r1X;var dY=eY-r1Y;var jointTranslation=ax1X*dX+ax1Y*dY;if(b2Math.b2Abs(this.m_upperTranslation-this.m_lowerTranslation)<2.0*b2Settings.b2_linearSlop)
-{this.m_limitState=b2Joint.e_equalLimits;}
-else if(jointTranslation<=this.m_lowerTranslation)
-{if(this.m_limitState!=b2Joint.e_atLowerLimit)
-{this.m_limitImpulse=0.0;}
-this.m_limitState=b2Joint.e_atLowerLimit;}
-else if(jointTranslation>=this.m_upperTranslation)
-{if(this.m_limitState!=b2Joint.e_atUpperLimit)
-{this.m_limitImpulse=0.0;}
-this.m_limitState=b2Joint.e_atUpperLimit;}
-else
-{this.m_limitState=b2Joint.e_inactiveLimit;this.m_limitImpulse=0.0;}}}
-if(this.m_enableMotor==false)
-{this.m_motorImpulse=0.0;}
-if(this.m_enableLimit==false)
-{this.m_limitImpulse=0.0;}
-if(b2World.s_enableWarmStarting)
-{var P1X=this.m_linearImpulse*this.m_linearJacobian.linear1.x+(this.m_motorImpulse+this.m_limitImpulse)*this.m_motorJacobian.linear1.x;var P1Y=this.m_linearImpulse*this.m_linearJacobian.linear1.y+(this.m_motorImpulse+this.m_limitImpulse)*this.m_motorJacobian.linear1.y;var P2X=this.m_linearImpulse*this.m_linearJacobian.linear2.x+(this.m_motorImpulse+this.m_limitImpulse)*this.m_motorJacobian.linear2.x;var P2Y=this.m_linearImpulse*this.m_linearJacobian.linear2.y+(this.m_motorImpulse+this.m_limitImpulse)*this.m_motorJacobian.linear2.y;var L1=this.m_linearImpulse*this.m_linearJacobian.angular1-this.m_angularImpulse+(this.m_motorImpulse+this.m_limitImpulse)*this.m_motorJacobian.angular1;var L2=this.m_linearImpulse*this.m_linearJacobian.angular2+this.m_angularImpulse+(this.m_motorImpulse+this.m_limitImpulse)*this.m_motorJacobian.angular2;b1.m_linearVelocity.x+=invMass1*P1X;b1.m_linearVelocity.y+=invMass1*P1Y;b1.m_angularVelocity+=invI1*L1;b2.m_linearVelocity.x+=invMass2*P2X;b2.m_linearVelocity.y+=invMass2*P2Y;b2.m_angularVelocity+=invI2*L2;}
-else
-{this.m_linearImpulse=0.0;this.m_angularImpulse=0.0;this.m_limitImpulse=0.0;this.m_motorImpulse=0.0;}
-this.m_limitPositionImpulse=0.0;},SolveVelocityConstraints:function(step){var b1=this.m_body1;var b2=this.m_body2;var invMass1=b1.m_invMass;var invMass2=b2.m_invMass;var invI1=b1.m_invI;var invI2=b2.m_invI;var oldLimitImpulse;var linearCdot=this.m_linearJacobian.Compute(b1.m_linearVelocity,b1.m_angularVelocity,b2.m_linearVelocity,b2.m_angularVelocity);var linearImpulse=-this.m_linearMass*linearCdot;this.m_linearImpulse+=linearImpulse;b1.m_linearVelocity.x+=(invMass1*linearImpulse)*this.m_linearJacobian.linear1.x;b1.m_linearVelocity.y+=(invMass1*linearImpulse)*this.m_linearJacobian.linear1.y;b1.m_angularVelocity+=invI1*linearImpulse*this.m_linearJacobian.angular1;b2.m_linearVelocity.x+=(invMass2*linearImpulse)*this.m_linearJacobian.linear2.x;b2.m_linearVelocity.y+=(invMass2*linearImpulse)*this.m_linearJacobian.linear2.y;b2.m_angularVelocity+=invI2*linearImpulse*this.m_linearJacobian.angular2;var angularCdot=b2.m_angularVelocity-b1.m_angularVelocity;var angularImpulse=-this.m_angularMass*angularCdot;this.m_angularImpulse+=angularImpulse;b1.m_angularVelocity-=invI1*angularImpulse;b2.m_angularVelocity+=invI2*angularImpulse;if(this.m_enableMotor&&this.m_limitState!=b2Joint.e_equalLimits)
-{var motorCdot=this.m_motorJacobian.Compute(b1.m_linearVelocity,b1.m_angularVelocity,b2.m_linearVelocity,b2.m_angularVelocity)-this.m_motorSpeed;var motorImpulse=-this.m_motorMass*motorCdot;var oldMotorImpulse=this.m_motorImpulse;this.m_motorImpulse=b2Math.b2Clamp(this.m_motorImpulse+motorImpulse,-step.dt*this.m_maxMotorForce,step.dt*this.m_maxMotorForce);motorImpulse=this.m_motorImpulse-oldMotorImpulse;b1.m_linearVelocity.x+=(invMass1*motorImpulse)*this.m_motorJacobian.linear1.x;b1.m_linearVelocity.y+=(invMass1*motorImpulse)*this.m_motorJacobian.linear1.y;b1.m_angularVelocity+=invI1*motorImpulse*this.m_motorJacobian.angular1;b2.m_linearVelocity.x+=(invMass2*motorImpulse)*this.m_motorJacobian.linear2.x;b2.m_linearVelocity.y+=(invMass2*motorImpulse)*this.m_motorJacobian.linear2.y;b2.m_angularVelocity+=invI2*motorImpulse*this.m_motorJacobian.angular2;}
-if(this.m_enableLimit&&this.m_limitState!=b2Joint.e_inactiveLimit)
-{var limitCdot=this.m_motorJacobian.Compute(b1.m_linearVelocity,b1.m_angularVelocity,b2.m_linearVelocity,b2.m_angularVelocity);var limitImpulse=-this.m_motorMass*limitCdot;if(this.m_limitState==b2Joint.e_equalLimits)
-{this.m_limitImpulse+=limitImpulse;}
-else if(this.m_limitState==b2Joint.e_atLowerLimit)
-{oldLimitImpulse=this.m_limitImpulse;this.m_limitImpulse=b2Math.b2Max(this.m_limitImpulse+limitImpulse,0.0);limitImpulse=this.m_limitImpulse-oldLimitImpulse;}
-else if(this.m_limitState==b2Joint.e_atUpperLimit)
-{oldLimitImpulse=this.m_limitImpulse;this.m_limitImpulse=b2Math.b2Min(this.m_limitImpulse+limitImpulse,0.0);limitImpulse=this.m_limitImpulse-oldLimitImpulse;}
-b1.m_linearVelocity.x+=(invMass1*limitImpulse)*this.m_motorJacobian.linear1.x;b1.m_linearVelocity.y+=(invMass1*limitImpulse)*this.m_motorJacobian.linear1.y;b1.m_angularVelocity+=invI1*limitImpulse*this.m_motorJacobian.angular1;b2.m_linearVelocity.x+=(invMass2*limitImpulse)*this.m_motorJacobian.linear2.x;b2.m_linearVelocity.y+=(invMass2*limitImpulse)*this.m_motorJacobian.linear2.y;b2.m_angularVelocity+=invI2*limitImpulse*this.m_motorJacobian.angular2;}},SolvePositionConstraints:function(){var limitC;var oldLimitImpulse;var b1=this.m_body1;var b2=this.m_body2;var invMass1=b1.m_invMass;var invMass2=b2.m_invMass;var invI1=b1.m_invI;var invI2=b2.m_invI;var tMat;tMat=b1.m_R;var r1X=tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y;var r1Y=tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y;tMat=b2.m_R;var r2X=tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y;var r2Y=tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y;var p1X=b1.m_position.x+r1X;var p1Y=b1.m_position.y+r1Y;var p2X=b2.m_position.x+r2X;var p2Y=b2.m_position.y+r2Y;var dX=p2X-p1X;var dY=p2Y-p1Y;tMat=b1.m_R;var ay1X=tMat.col1.x*this.m_localYAxis1.x+tMat.col2.x*this.m_localYAxis1.y;var ay1Y=tMat.col1.y*this.m_localYAxis1.x+tMat.col2.y*this.m_localYAxis1.y;var linearC=ay1X*dX+ay1Y*dY;linearC=b2Math.b2Clamp(linearC,-b2Settings.b2_maxLinearCorrection,b2Settings.b2_maxLinearCorrection);var linearImpulse=-this.m_linearMass*linearC;b1.m_position.x+=(invMass1*linearImpulse)*this.m_linearJacobian.linear1.x;b1.m_position.y+=(invMass1*linearImpulse)*this.m_linearJacobian.linear1.y;b1.m_rotation+=invI1*linearImpulse*this.m_linearJacobian.angular1;b2.m_position.x+=(invMass2*linearImpulse)*this.m_linearJacobian.linear2.x;b2.m_position.y+=(invMass2*linearImpulse)*this.m_linearJacobian.linear2.y;b2.m_rotation+=invI2*linearImpulse*this.m_linearJacobian.angular2;var positionError=b2Math.b2Abs(linearC);var angularC=b2.m_rotation-b1.m_rotation-this.m_initialAngle;angularC=b2Math.b2Clamp(angularC,-b2Settings.b2_maxAngularCorrection,b2Settings.b2_maxAngularCorrection);var angularImpulse=-this.m_angularMass*angularC;b1.m_rotation-=b1.m_invI*angularImpulse;b1.m_R.Set(b1.m_rotation);b2.m_rotation+=b2.m_invI*angularImpulse;b2.m_R.Set(b2.m_rotation);var angularError=b2Math.b2Abs(angularC);if(this.m_enableLimit&&this.m_limitState!=b2Joint.e_inactiveLimit)
-{tMat=b1.m_R;r1X=tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y;r1Y=tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y;tMat=b2.m_R;r2X=tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y;r2Y=tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y;p1X=b1.m_position.x+r1X;p1Y=b1.m_position.y+r1Y;p2X=b2.m_position.x+r2X;p2Y=b2.m_position.y+r2Y;dX=p2X-p1X;dY=p2Y-p1Y;tMat=b1.m_R;var ax1X=tMat.col1.x*this.m_localXAxis1.x+tMat.col2.x*this.m_localXAxis1.y;var ax1Y=tMat.col1.y*this.m_localXAxis1.x+tMat.col2.y*this.m_localXAxis1.y;var translation=(ax1X*dX+ax1Y*dY);var limitImpulse=0.0;if(this.m_limitState==b2Joint.e_equalLimits)
-{limitC=b2Math.b2Clamp(translation,-b2Settings.b2_maxLinearCorrection,b2Settings.b2_maxLinearCorrection);limitImpulse=-this.m_motorMass*limitC;positionError=b2Math.b2Max(positionError,b2Math.b2Abs(angularC));}
-else if(this.m_limitState==b2Joint.e_atLowerLimit)
-{limitC=translation-this.m_lowerTranslation;positionError=b2Math.b2Max(positionError,-limitC);limitC=b2Math.b2Clamp(limitC+b2Settings.b2_linearSlop,-b2Settings.b2_maxLinearCorrection,0.0);limitImpulse=-this.m_motorMass*limitC;oldLimitImpulse=this.m_limitPositionImpulse;this.m_limitPositionImpulse=b2Math.b2Max(this.m_limitPositionImpulse+limitImpulse,0.0);limitImpulse=this.m_limitPositionImpulse-oldLimitImpulse;}
-else if(this.m_limitState==b2Joint.e_atUpperLimit)
-{limitC=translation-this.m_upperTranslation;positionError=b2Math.b2Max(positionError,limitC);limitC=b2Math.b2Clamp(limitC-b2Settings.b2_linearSlop,0.0,b2Settings.b2_maxLinearCorrection);limitImpulse=-this.m_motorMass*limitC;oldLimitImpulse=this.m_limitPositionImpulse;this.m_limitPositionImpulse=b2Math.b2Min(this.m_limitPositionImpulse+limitImpulse,0.0);limitImpulse=this.m_limitPositionImpulse-oldLimitImpulse;}
-b1.m_position.x+=(invMass1*limitImpulse)*this.m_motorJacobian.linear1.x;b1.m_position.y+=(invMass1*limitImpulse)*this.m_motorJacobian.linear1.y;b1.m_rotation+=invI1*limitImpulse*this.m_motorJacobian.angular1;b1.m_R.Set(b1.m_rotation);b2.m_position.x+=(invMass2*limitImpulse)*this.m_motorJacobian.linear2.x;b2.m_position.y+=(invMass2*limitImpulse)*this.m_motorJacobian.linear2.y;b2.m_rotation+=invI2*limitImpulse*this.m_motorJacobian.angular2;b2.m_R.Set(b2.m_rotation);}
-return positionError<=b2Settings.b2_linearSlop&&angularError<=b2Settings.b2_angularSlop;},m_localAnchor1:new b2Vec2(),m_localAnchor2:new b2Vec2(),m_localXAxis1:new b2Vec2(),m_localYAxis1:new b2Vec2(),m_initialAngle:null,m_linearJacobian:new b2Jacobian(),m_linearMass:null,m_linearImpulse:null,m_angularMass:null,m_angularImpulse:null,m_motorJacobian:new b2Jacobian(),m_motorMass:null,m_motorImpulse:null,m_limitImpulse:null,m_limitPositionImpulse:null,m_lowerTranslation:null,m_upperTranslation:null,m_maxMotorForce:null,m_motorSpeed:null,m_enableLimit:null,m_enableMotor:null,m_limitState:0});
-var b2PrismaticJointDef=Class.create();Object.extend(b2PrismaticJointDef.prototype,b2JointDef.prototype);Object.extend(b2PrismaticJointDef.prototype,{initialize:function()
-{this.type=b2Joint.e_unknownJoint;this.userData=null;this.body1=null;this.body2=null;this.collideConnected=false;this.type=b2Joint.e_prismaticJoint;this.anchorPoint=new b2Vec2(0.0,0.0);this.axis=new b2Vec2(0.0,0.0);this.lowerTranslation=0.0;this.upperTranslation=0.0;this.motorForce=0.0;this.motorSpeed=0.0;this.enableLimit=false;this.enableMotor=false;},anchorPoint:null,axis:null,lowerTranslation:null,upperTranslation:null,motorForce:null,motorSpeed:null,enableLimit:null,enableMotor:null});
-var b2PulleyJoint=Class.create();Object.extend(b2PulleyJoint.prototype,b2Joint.prototype);Object.extend(b2PulleyJoint.prototype,{GetAnchor1:function(){var tMat=this.m_body1.m_R;return new b2Vec2(this.m_body1.m_position.x+(tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y),this.m_body1.m_position.y+(tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y));},GetAnchor2:function(){var tMat=this.m_body2.m_R;return new b2Vec2(this.m_body2.m_position.x+(tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y),this.m_body2.m_position.y+(tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y));},GetGroundPoint1:function(){return new b2Vec2(this.m_ground.m_position.x+this.m_groundAnchor1.x,this.m_ground.m_position.y+this.m_groundAnchor1.y);},GetGroundPoint2:function(){return new b2Vec2(this.m_ground.m_position.x+this.m_groundAnchor2.x,this.m_ground.m_position.y+this.m_groundAnchor2.y);},GetReactionForce:function(invTimeStep){return new b2Vec2();},GetReactionTorque:function(invTimeStep){return 0.0;},GetLength1:function(){var tMat;tMat=this.m_body1.m_R;var pX=this.m_body1.m_position.x+(tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y);var pY=this.m_body1.m_position.y+(tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y);var dX=pX-(this.m_ground.m_position.x+this.m_groundAnchor1.x);var dY=pY-(this.m_ground.m_position.y+this.m_groundAnchor1.y);return Math.sqrt(dX*dX+dY*dY);},GetLength2:function(){var tMat;tMat=this.m_body2.m_R;var pX=this.m_body2.m_position.x+(tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y);var pY=this.m_body2.m_position.y+(tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y);var dX=pX-(this.m_ground.m_position.x+this.m_groundAnchor2.x);var dY=pY-(this.m_ground.m_position.y+this.m_groundAnchor2.y);return Math.sqrt(dX*dX+dY*dY);},GetRatio:function(){return this.m_ratio;},initialize:function(def){this.m_node1=new b2JointNode();this.m_node2=new b2JointNode();this.m_type=def.type;this.m_prev=null;this.m_next=null;this.m_body1=def.body1;this.m_body2=def.body2;this.m_collideConnected=def.collideConnected;this.m_islandFlag=false;this.m_userData=def.userData;this.m_groundAnchor1=new b2Vec2();this.m_groundAnchor2=new b2Vec2();this.m_localAnchor1=new b2Vec2();this.m_localAnchor2=new b2Vec2();this.m_u1=new b2Vec2();this.m_u2=new b2Vec2();var tMat;var tX;var tY;this.m_ground=this.m_body1.m_world.m_groundBody;this.m_groundAnchor1.x=def.groundPoint1.x-this.m_ground.m_position.x;this.m_groundAnchor1.y=def.groundPoint1.y-this.m_ground.m_position.y;this.m_groundAnchor2.x=def.groundPoint2.x-this.m_ground.m_position.x;this.m_groundAnchor2.y=def.groundPoint2.y-this.m_ground.m_position.y;tMat=this.m_body1.m_R;tX=def.anchorPoint1.x-this.m_body1.m_position.x;tY=def.anchorPoint1.y-this.m_body1.m_position.y;this.m_localAnchor1.x=tX*tMat.col1.x+tY*tMat.col1.y;this.m_localAnchor1.y=tX*tMat.col2.x+tY*tMat.col2.y;tMat=this.m_body2.m_R;tX=def.anchorPoint2.x-this.m_body2.m_position.x;tY=def.anchorPoint2.y-this.m_body2.m_position.y;this.m_localAnchor2.x=tX*tMat.col1.x+tY*tMat.col1.y;this.m_localAnchor2.y=tX*tMat.col2.x+tY*tMat.col2.y;this.m_ratio=def.ratio;tX=def.groundPoint1.x-def.anchorPoint1.x;tY=def.groundPoint1.y-def.anchorPoint1.y;var d1Len=Math.sqrt(tX*tX+tY*tY);tX=def.groundPoint2.x-def.anchorPoint2.x;tY=def.groundPoint2.y-def.anchorPoint2.y;var d2Len=Math.sqrt(tX*tX+tY*tY);var length1=b2Math.b2Max(0.5*b2PulleyJoint.b2_minPulleyLength,d1Len);var length2=b2Math.b2Max(0.5*b2PulleyJoint.b2_minPulleyLength,d2Len);this.m_constant=length1+this.m_ratio*length2;this.m_maxLength1=b2Math.b2Clamp(def.maxLength1,length1,this.m_constant-this.m_ratio*b2PulleyJoint.b2_minPulleyLength);this.m_maxLength2=b2Math.b2Clamp(def.maxLength2,length2,(this.m_constant-b2PulleyJoint.b2_minPulleyLength)/this.m_ratio);this.m_pulleyImpulse=0.0;this.m_limitImpulse1=0.0;this.m_limitImpulse2=0.0;},PrepareVelocitySolver:function(){var b1=this.m_body1;var b2=this.m_body2;var tMat;tMat=b1.m_R;var r1X=tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y;var r1Y=tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y;tMat=b2.m_R;var r2X=tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y;var r2Y=tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y;var p1X=b1.m_position.x+r1X;var p1Y=b1.m_position.y+r1Y;var p2X=b2.m_position.x+r2X;var p2Y=b2.m_position.y+r2Y;var s1X=this.m_ground.m_position.x+this.m_groundAnchor1.x;var s1Y=this.m_ground.m_position.y+this.m_groundAnchor1.y;var s2X=this.m_ground.m_position.x+this.m_groundAnchor2.x;var s2Y=this.m_ground.m_position.y+this.m_groundAnchor2.y;this.m_u1.Set(p1X-s1X,p1Y-s1Y);this.m_u2.Set(p2X-s2X,p2Y-s2Y);var length1=this.m_u1.Length();var length2=this.m_u2.Length();if(length1>b2Settings.b2_linearSlop)
-{this.m_u1.Multiply(1.0/length1);}
-else
-{this.m_u1.SetZero();}
-if(length2>b2Settings.b2_linearSlop)
-{this.m_u2.Multiply(1.0/length2);}
-else
-{this.m_u2.SetZero();}
-if(length1<this.m_maxLength1)
-{this.m_limitState1=b2Joint.e_inactiveLimit;this.m_limitImpulse1=0.0;}
-else
-{this.m_limitState1=b2Joint.e_atUpperLimit;this.m_limitPositionImpulse1=0.0;}
-if(length2<this.m_maxLength2)
-{this.m_limitState2=b2Joint.e_inactiveLimit;this.m_limitImpulse2=0.0;}
-else
-{this.m_limitState2=b2Joint.e_atUpperLimit;this.m_limitPositionImpulse2=0.0;}
-var cr1u1=r1X*this.m_u1.y-r1Y*this.m_u1.x;var cr2u2=r2X*this.m_u2.y-r2Y*this.m_u2.x;this.m_limitMass1=b1.m_invMass+b1.m_invI*cr1u1*cr1u1;this.m_limitMass2=b2.m_invMass+b2.m_invI*cr2u2*cr2u2;this.m_pulleyMass=this.m_limitMass1+this.m_ratio*this.m_ratio*this.m_limitMass2;this.m_limitMass1=1.0/this.m_limitMass1;this.m_limitMass2=1.0/this.m_limitMass2;this.m_pulleyMass=1.0/this.m_pulleyMass;var P1X=(-this.m_pulleyImpulse-this.m_limitImpulse1)*this.m_u1.x;var P1Y=(-this.m_pulleyImpulse-this.m_limitImpulse1)*this.m_u1.y;var P2X=(-this.m_ratio*this.m_pulleyImpulse-this.m_limitImpulse2)*this.m_u2.x;var P2Y=(-this.m_ratio*this.m_pulleyImpulse-this.m_limitImpulse2)*this.m_u2.y;b1.m_linearVelocity.x+=b1.m_invMass*P1X;b1.m_linearVelocity.y+=b1.m_invMass*P1Y;b1.m_angularVelocity+=b1.m_invI*(r1X*P1Y-r1Y*P1X);b2.m_linearVelocity.x+=b2.m_invMass*P2X;b2.m_linearVelocity.y+=b2.m_invMass*P2Y;b2.m_angularVelocity+=b2.m_invI*(r2X*P2Y-r2Y*P2X);},SolveVelocityConstraints:function(step){var b1=this.m_body1;var b2=this.m_body2;var tMat;tMat=b1.m_R;var r1X=tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y;var r1Y=tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y;tMat=b2.m_R;var r2X=tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y;var r2Y=tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y;var v1X;var v1Y;var v2X;var v2Y;var P1X;var P1Y;var P2X;var P2Y;var Cdot;var impulse;var oldLimitImpulse;v1X=b1.m_linearVelocity.x+(-b1.m_angularVelocity*r1Y);v1Y=b1.m_linearVelocity.y+(b1.m_angularVelocity*r1X);v2X=b2.m_linearVelocity.x+(-b2.m_angularVelocity*r2Y);v2Y=b2.m_linearVelocity.y+(b2.m_angularVelocity*r2X);Cdot=-(this.m_u1.x*v1X+this.m_u1.y*v1Y)-this.m_ratio*(this.m_u2.x*v2X+this.m_u2.y*v2Y);impulse=-this.m_pulleyMass*Cdot;this.m_pulleyImpulse+=impulse;P1X=-impulse*this.m_u1.x;P1Y=-impulse*this.m_u1.y;P2X=-this.m_ratio*impulse*this.m_u2.x;P2Y=-this.m_ratio*impulse*this.m_u2.y;b1.m_linearVelocity.x+=b1.m_invMass*P1X;b1.m_linearVelocity.y+=b1.m_invMass*P1Y;b1.m_angularVelocity+=b1.m_invI*(r1X*P1Y-r1Y*P1X);b2.m_linearVelocity.x+=b2.m_invMass*P2X;b2.m_linearVelocity.y+=b2.m_invMass*P2Y;b2.m_angularVelocity+=b2.m_invI*(r2X*P2Y-r2Y*P2X);if(this.m_limitState1==b2Joint.e_atUpperLimit)
-{v1X=b1.m_linearVelocity.x+(-b1.m_angularVelocity*r1Y);v1Y=b1.m_linearVelocity.y+(b1.m_angularVelocity*r1X);Cdot=-(this.m_u1.x*v1X+this.m_u1.y*v1Y);impulse=-this.m_limitMass1*Cdot;oldLimitImpulse=this.m_limitImpulse1;this.m_limitImpulse1=b2Math.b2Max(0.0,this.m_limitImpulse1+impulse);impulse=this.m_limitImpulse1-oldLimitImpulse;P1X=-impulse*this.m_u1.x;P1Y=-impulse*this.m_u1.y;b1.m_linearVelocity.x+=b1.m_invMass*P1X;b1.m_linearVelocity.y+=b1.m_invMass*P1Y;b1.m_angularVelocity+=b1.m_invI*(r1X*P1Y-r1Y*P1X);}
-if(this.m_limitState2==b2Joint.e_atUpperLimit)
-{v2X=b2.m_linearVelocity.x+(-b2.m_angularVelocity*r2Y);v2Y=b2.m_linearVelocity.y+(b2.m_angularVelocity*r2X);Cdot=-(this.m_u2.x*v2X+this.m_u2.y*v2Y);impulse=-this.m_limitMass2*Cdot;oldLimitImpulse=this.m_limitImpulse2;this.m_limitImpulse2=b2Math.b2Max(0.0,this.m_limitImpulse2+impulse);impulse=this.m_limitImpulse2-oldLimitImpulse;P2X=-impulse*this.m_u2.x;P2Y=-impulse*this.m_u2.y;b2.m_linearVelocity.x+=b2.m_invMass*P2X;b2.m_linearVelocity.y+=b2.m_invMass*P2Y;b2.m_angularVelocity+=b2.m_invI*(r2X*P2Y-r2Y*P2X);}},SolvePositionConstraints:function(){var b1=this.m_body1;var b2=this.m_body2;var tMat;var s1X=this.m_ground.m_position.x+this.m_groundAnchor1.x;var s1Y=this.m_ground.m_position.y+this.m_groundAnchor1.y;var s2X=this.m_ground.m_position.x+this.m_groundAnchor2.x;var s2Y=this.m_ground.m_position.y+this.m_groundAnchor2.y;var r1X;var r1Y;var r2X;var r2Y;var p1X;var p1Y;var p2X;var p2Y;var length1;var length2;var C;var impulse;var oldLimitPositionImpulse;var linearError=0.0;{tMat=b1.m_R;r1X=tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y;r1Y=tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y;tMat=b2.m_R;r2X=tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y;r2Y=tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y;p1X=b1.m_position.x+r1X;p1Y=b1.m_position.y+r1Y;p2X=b2.m_position.x+r2X;p2Y=b2.m_position.y+r2Y;this.m_u1.Set(p1X-s1X,p1Y-s1Y);this.m_u2.Set(p2X-s2X,p2Y-s2Y);length1=this.m_u1.Length();length2=this.m_u2.Length();if(length1>b2Settings.b2_linearSlop)
-{this.m_u1.Multiply(1.0/length1);}
-else
-{this.m_u1.SetZero();}
-if(length2>b2Settings.b2_linearSlop)
-{this.m_u2.Multiply(1.0/length2);}
-else
-{this.m_u2.SetZero();}
-C=this.m_constant-length1-this.m_ratio*length2;linearError=b2Math.b2Max(linearError,Math.abs(C));C=b2Math.b2Clamp(C,-b2Settings.b2_maxLinearCorrection,b2Settings.b2_maxLinearCorrection);impulse=-this.m_pulleyMass*C;p1X=-impulse*this.m_u1.x;p1Y=-impulse*this.m_u1.y;p2X=-this.m_ratio*impulse*this.m_u2.x;p2Y=-this.m_ratio*impulse*this.m_u2.y;b1.m_position.x+=b1.m_invMass*p1X;b1.m_position.y+=b1.m_invMass*p1Y;b1.m_rotation+=b1.m_invI*(r1X*p1Y-r1Y*p1X);b2.m_position.x+=b2.m_invMass*p2X;b2.m_position.y+=b2.m_invMass*p2Y;b2.m_rotation+=b2.m_invI*(r2X*p2Y-r2Y*p2X);b1.m_R.Set(b1.m_rotation);b2.m_R.Set(b2.m_rotation);}
-if(this.m_limitState1==b2Joint.e_atUpperLimit)
-{tMat=b1.m_R;r1X=tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y;r1Y=tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y;p1X=b1.m_position.x+r1X;p1Y=b1.m_position.y+r1Y;this.m_u1.Set(p1X-s1X,p1Y-s1Y);length1=this.m_u1.Length();if(length1>b2Settings.b2_linearSlop)
-{this.m_u1.x*=1.0/length1;this.m_u1.y*=1.0/length1;}
-else
-{this.m_u1.SetZero();}
-C=this.m_maxLength1-length1;linearError=b2Math.b2Max(linearError,-C);C=b2Math.b2Clamp(C+b2Settings.b2_linearSlop,-b2Settings.b2_maxLinearCorrection,0.0);impulse=-this.m_limitMass1*C;oldLimitPositionImpulse=this.m_limitPositionImpulse1;this.m_limitPositionImpulse1=b2Math.b2Max(0.0,this.m_limitPositionImpulse1+impulse);impulse=this.m_limitPositionImpulse1-oldLimitPositionImpulse;p1X=-impulse*this.m_u1.x;p1Y=-impulse*this.m_u1.y;b1.m_position.x+=b1.m_invMass*p1X;b1.m_position.y+=b1.m_invMass*p1Y;b1.m_rotation+=b1.m_invI*(r1X*p1Y-r1Y*p1X);b1.m_R.Set(b1.m_rotation);}
-if(this.m_limitState2==b2Joint.e_atUpperLimit)
-{tMat=b2.m_R;r2X=tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y;r2Y=tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y;p2X=b2.m_position.x+r2X;p2Y=b2.m_position.y+r2Y;this.m_u2.Set(p2X-s2X,p2Y-s2Y);length2=this.m_u2.Length();if(length2>b2Settings.b2_linearSlop)
-{this.m_u2.x*=1.0/length2;this.m_u2.y*=1.0/length2;}
-else
-{this.m_u2.SetZero();}
-C=this.m_maxLength2-length2;linearError=b2Math.b2Max(linearError,-C);C=b2Math.b2Clamp(C+b2Settings.b2_linearSlop,-b2Settings.b2_maxLinearCorrection,0.0);impulse=-this.m_limitMass2*C;oldLimitPositionImpulse=this.m_limitPositionImpulse2;this.m_limitPositionImpulse2=b2Math.b2Max(0.0,this.m_limitPositionImpulse2+impulse);impulse=this.m_limitPositionImpulse2-oldLimitPositionImpulse;p2X=-impulse*this.m_u2.x;p2Y=-impulse*this.m_u2.y;b2.m_position.x+=b2.m_invMass*p2X;b2.m_position.y+=b2.m_invMass*p2Y;b2.m_rotation+=b2.m_invI*(r2X*p2Y-r2Y*p2X);b2.m_R.Set(b2.m_rotation);}
-return linearError<b2Settings.b2_linearSlop;},m_ground:null,m_groundAnchor1:new b2Vec2(),m_groundAnchor2:new b2Vec2(),m_localAnchor1:new b2Vec2(),m_localAnchor2:new b2Vec2(),m_u1:new b2Vec2(),m_u2:new b2Vec2(),m_constant:null,m_ratio:null,m_maxLength1:null,m_maxLength2:null,m_pulleyMass:null,m_limitMass1:null,m_limitMass2:null,m_pulleyImpulse:null,m_limitImpulse1:null,m_limitImpulse2:null,m_limitPositionImpulse1:null,m_limitPositionImpulse2:null,m_limitState1:0,m_limitState2:0});b2PulleyJoint.b2_minPulleyLength=b2Settings.b2_lengthUnitsPerMeter;
-var b2PulleyJointDef=Class.create();Object.extend(b2PulleyJointDef.prototype,b2JointDef.prototype);Object.extend(b2PulleyJointDef.prototype,{initialize:function()
-{this.type=b2Joint.e_unknownJoint;this.userData=null;this.body1=null;this.body2=null;this.collideConnected=false;this.groundPoint1=new b2Vec2();this.groundPoint2=new b2Vec2();this.anchorPoint1=new b2Vec2();this.anchorPoint2=new b2Vec2();this.type=b2Joint.e_pulleyJoint;this.groundPoint1.Set(-1.0,1.0);this.groundPoint2.Set(1.0,1.0);this.anchorPoint1.Set(-1.0,0.0);this.anchorPoint2.Set(1.0,0.0);this.maxLength1=0.5*b2PulleyJoint.b2_minPulleyLength;this.maxLength2=0.5*b2PulleyJoint.b2_minPulleyLength;this.ratio=1.0;this.collideConnected=true;},groundPoint1:new b2Vec2(),groundPoint2:new b2Vec2(),anchorPoint1:new b2Vec2(),anchorPoint2:new b2Vec2(),maxLength1:null,maxLength2:null,ratio:null});
-var b2RevoluteJoint=Class.create();Object.extend(b2RevoluteJoint.prototype,b2Joint.prototype);Object.extend(b2RevoluteJoint.prototype,{GetAnchor1:function(){var tMat=this.m_body1.m_R;return new b2Vec2(this.m_body1.m_position.x+(tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y),this.m_body1.m_position.y+(tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y));},GetAnchor2:function(){var tMat=this.m_body2.m_R;return new b2Vec2(this.m_body2.m_position.x+(tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y),this.m_body2.m_position.y+(tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y));},GetJointAngle:function(){return this.m_body2.m_rotation-this.m_body1.m_rotation;},GetJointSpeed:function(){return this.m_body2.m_angularVelocity-this.m_body1.m_angularVelocity;},GetMotorTorque:function(invTimeStep){return invTimeStep*this.m_motorImpulse;},SetMotorSpeed:function(speed)
-{this.m_motorSpeed=speed;},SetMotorTorque:function(torque)
-{this.m_maxMotorTorque=torque;},GetReactionForce:function(invTimeStep)
-{var tVec=this.m_ptpImpulse.Copy();tVec.Multiply(invTimeStep);return tVec;},GetReactionTorque:function(invTimeStep)
-{return invTimeStep*this.m_limitImpulse;},initialize:function(def){this.m_node1=new b2JointNode();this.m_node2=new b2JointNode();this.m_type=def.type;this.m_prev=null;this.m_next=null;this.m_body1=def.body1;this.m_body2=def.body2;this.m_collideConnected=def.collideConnected;this.m_islandFlag=false;this.m_userData=def.userData;this.K=new b2Mat22();this.K1=new b2Mat22();this.K2=new b2Mat22();this.K3=new b2Mat22();this.m_localAnchor1=new b2Vec2();this.m_localAnchor2=new b2Vec2();this.m_ptpImpulse=new b2Vec2();this.m_ptpMass=new b2Mat22();var tMat;var tX;var tY;tMat=this.m_body1.m_R;tX=def.anchorPoint.x-this.m_body1.m_position.x;tY=def.anchorPoint.y-this.m_body1.m_position.y;this.m_localAnchor1.x=tX*tMat.col1.x+tY*tMat.col1.y;this.m_localAnchor1.y=tX*tMat.col2.x+tY*tMat.col2.y;tMat=this.m_body2.m_R;tX=def.anchorPoint.x-this.m_body2.m_position.x;tY=def.anchorPoint.y-this.m_body2.m_position.y;this.m_localAnchor2.x=tX*tMat.col1.x+tY*tMat.col1.y;this.m_localAnchor2.y=tX*tMat.col2.x+tY*tMat.col2.y;this.m_intialAngle=this.m_body2.m_rotation-this.m_body1.m_rotation;this.m_ptpImpulse.Set(0.0,0.0);this.m_motorImpulse=0.0;this.m_limitImpulse=0.0;this.m_limitPositionImpulse=0.0;this.m_lowerAngle=def.lowerAngle;this.m_upperAngle=def.upperAngle;this.m_maxMotorTorque=def.motorTorque;this.m_motorSpeed=def.motorSpeed;this.m_enableLimit=def.enableLimit;this.m_enableMotor=def.enableMotor;},K:new b2Mat22(),K1:new b2Mat22(),K2:new b2Mat22(),K3:new b2Mat22(),PrepareVelocitySolver:function(){var b1=this.m_body1;var b2=this.m_body2;var tMat;tMat=b1.m_R;var r1X=tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y;var r1Y=tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y;tMat=b2.m_R;var r2X=tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y;var r2Y=tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y;var invMass1=b1.m_invMass;var invMass2=b2.m_invMass;var invI1=b1.m_invI;var invI2=b2.m_invI;this.K1.col1.x=invMass1+invMass2;this.K1.col2.x=0.0;this.K1.col1.y=0.0;this.K1.col2.y=invMass1+invMass2;this.K2.col1.x=invI1*r1Y*r1Y;this.K2.col2.x=-invI1*r1X*r1Y;this.K2.col1.y=-invI1*r1X*r1Y;this.K2.col2.y=invI1*r1X*r1X;this.K3.col1.x=invI2*r2Y*r2Y;this.K3.col2.x=-invI2*r2X*r2Y;this.K3.col1.y=-invI2*r2X*r2Y;this.K3.col2.y=invI2*r2X*r2X;this.K.SetM(this.K1);this.K.AddM(this.K2);this.K.AddM(this.K3);this.K.Invert(this.m_ptpMass);this.m_motorMass=1.0/(invI1+invI2);if(this.m_enableMotor==false)
-{this.m_motorImpulse=0.0;}
-if(this.m_enableLimit)
-{var jointAngle=b2.m_rotation-b1.m_rotation-this.m_intialAngle;if(b2Math.b2Abs(this.m_upperAngle-this.m_lowerAngle)<2.0*b2Settings.b2_angularSlop)
-{this.m_limitState=b2Joint.e_equalLimits;}
-else if(jointAngle<=this.m_lowerAngle)
-{if(this.m_limitState!=b2Joint.e_atLowerLimit)
-{this.m_limitImpulse=0.0;}
-this.m_limitState=b2Joint.e_atLowerLimit;}
-else if(jointAngle>=this.m_upperAngle)
-{if(this.m_limitState!=b2Joint.e_atUpperLimit)
-{this.m_limitImpulse=0.0;}
-this.m_limitState=b2Joint.e_atUpperLimit;}
-else
-{this.m_limitState=b2Joint.e_inactiveLimit;this.m_limitImpulse=0.0;}}
-else
-{this.m_limitImpulse=0.0;}
-if(b2World.s_enableWarmStarting)
-{b1.m_linearVelocity.x-=invMass1*this.m_ptpImpulse.x;b1.m_linearVelocity.y-=invMass1*this.m_ptpImpulse.y;b1.m_angularVelocity-=invI1*((r1X*this.m_ptpImpulse.y-r1Y*this.m_ptpImpulse.x)+this.m_motorImpulse+this.m_limitImpulse);b2.m_linearVelocity.x+=invMass2*this.m_ptpImpulse.x;b2.m_linearVelocity.y+=invMass2*this.m_ptpImpulse.y;b2.m_angularVelocity+=invI2*((r2X*this.m_ptpImpulse.y-r2Y*this.m_ptpImpulse.x)+this.m_motorImpulse+this.m_limitImpulse);}
-else{this.m_ptpImpulse.SetZero();this.m_motorImpulse=0.0;this.m_limitImpulse=0.0;}
-this.m_limitPositionImpulse=0.0;},SolveVelocityConstraints:function(step){var b1=this.m_body1;var b2=this.m_body2;var tMat;tMat=b1.m_R;var r1X=tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y;var r1Y=tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y;tMat=b2.m_R;var r2X=tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y;var r2Y=tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y;var oldLimitImpulse;var ptpCdotX=b2.m_linearVelocity.x+(-b2.m_angularVelocity*r2Y)-b1.m_linearVelocity.x-(-b1.m_angularVelocity*r1Y);var ptpCdotY=b2.m_linearVelocity.y+(b2.m_angularVelocity*r2X)-b1.m_linearVelocity.y-(b1.m_angularVelocity*r1X);var ptpImpulseX=-(this.m_ptpMass.col1.x*ptpCdotX+this.m_ptpMass.col2.x*ptpCdotY);var ptpImpulseY=-(this.m_ptpMass.col1.y*ptpCdotX+this.m_ptpMass.col2.y*ptpCdotY);this.m_ptpImpulse.x+=ptpImpulseX;this.m_ptpImpulse.y+=ptpImpulseY;b1.m_linearVelocity.x-=b1.m_invMass*ptpImpulseX;b1.m_linearVelocity.y-=b1.m_invMass*ptpImpulseY;b1.m_angularVelocity-=b1.m_invI*(r1X*ptpImpulseY-r1Y*ptpImpulseX);b2.m_linearVelocity.x+=b2.m_invMass*ptpImpulseX;b2.m_linearVelocity.y+=b2.m_invMass*ptpImpulseY;b2.m_angularVelocity+=b2.m_invI*(r2X*ptpImpulseY-r2Y*ptpImpulseX);if(this.m_enableMotor&&this.m_limitState!=b2Joint.e_equalLimits)
-{var motorCdot=b2.m_angularVelocity-b1.m_angularVelocity-this.m_motorSpeed;var motorImpulse=-this.m_motorMass*motorCdot;var oldMotorImpulse=this.m_motorImpulse;this.m_motorImpulse=b2Math.b2Clamp(this.m_motorImpulse+motorImpulse,-step.dt*this.m_maxMotorTorque,step.dt*this.m_maxMotorTorque);motorImpulse=this.m_motorImpulse-oldMotorImpulse;b1.m_angularVelocity-=b1.m_invI*motorImpulse;b2.m_angularVelocity+=b2.m_invI*motorImpulse;}
-if(this.m_enableLimit&&this.m_limitState!=b2Joint.e_inactiveLimit)
-{var limitCdot=b2.m_angularVelocity-b1.m_angularVelocity;var limitImpulse=-this.m_motorMass*limitCdot;if(this.m_limitState==b2Joint.e_equalLimits)
-{this.m_limitImpulse+=limitImpulse;}
-else if(this.m_limitState==b2Joint.e_atLowerLimit)
-{oldLimitImpulse=this.m_limitImpulse;this.m_limitImpulse=b2Math.b2Max(this.m_limitImpulse+limitImpulse,0.0);limitImpulse=this.m_limitImpulse-oldLimitImpulse;}
-else if(this.m_limitState==b2Joint.e_atUpperLimit)
-{oldLimitImpulse=this.m_limitImpulse;this.m_limitImpulse=b2Math.b2Min(this.m_limitImpulse+limitImpulse,0.0);limitImpulse=this.m_limitImpulse-oldLimitImpulse;}
-b1.m_angularVelocity-=b1.m_invI*limitImpulse;b2.m_angularVelocity+=b2.m_invI*limitImpulse;}},SolvePositionConstraints:function(){var oldLimitImpulse;var limitC;var b1=this.m_body1;var b2=this.m_body2;var positionError=0.0;var tMat;tMat=b1.m_R;var r1X=tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y;var r1Y=tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y;tMat=b2.m_R;var r2X=tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y;var r2Y=tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y;var p1X=b1.m_position.x+r1X;var p1Y=b1.m_position.y+r1Y;var p2X=b2.m_position.x+r2X;var p2Y=b2.m_position.y+r2Y;var ptpCX=p2X-p1X;var ptpCY=p2Y-p1Y;positionError=Math.sqrt(ptpCX*ptpCX+ptpCY*ptpCY);var invMass1=b1.m_invMass;var invMass2=b2.m_invMass;var invI1=b1.m_invI;var invI2=b2.m_invI;this.K1.col1.x=invMass1+invMass2;this.K1.col2.x=0.0;this.K1.col1.y=0.0;this.K1.col2.y=invMass1+invMass2;this.K2.col1.x=invI1*r1Y*r1Y;this.K2.col2.x=-invI1*r1X*r1Y;this.K2.col1.y=-invI1*r1X*r1Y;this.K2.col2.y=invI1*r1X*r1X;this.K3.col1.x=invI2*r2Y*r2Y;this.K3.col2.x=-invI2*r2X*r2Y;this.K3.col1.y=-invI2*r2X*r2Y;this.K3.col2.y=invI2*r2X*r2X;this.K.SetM(this.K1);this.K.AddM(this.K2);this.K.AddM(this.K3);this.K.Solve(b2RevoluteJoint.tImpulse,-ptpCX,-ptpCY);var impulseX=b2RevoluteJoint.tImpulse.x;var impulseY=b2RevoluteJoint.tImpulse.y;b1.m_position.x-=b1.m_invMass*impulseX;b1.m_position.y-=b1.m_invMass*impulseY;b1.m_rotation-=b1.m_invI*(r1X*impulseY-r1Y*impulseX);b1.m_R.Set(b1.m_rotation);b2.m_position.x+=b2.m_invMass*impulseX;b2.m_position.y+=b2.m_invMass*impulseY;b2.m_rotation+=b2.m_invI*(r2X*impulseY-r2Y*impulseX);b2.m_R.Set(b2.m_rotation);var angularError=0.0;if(this.m_enableLimit&&this.m_limitState!=b2Joint.e_inactiveLimit)
-{var angle=b2.m_rotation-b1.m_rotation-this.m_intialAngle;var limitImpulse=0.0;if(this.m_limitState==b2Joint.e_equalLimits)
-{limitC=b2Math.b2Clamp(angle,-b2Settings.b2_maxAngularCorrection,b2Settings.b2_maxAngularCorrection);limitImpulse=-this.m_motorMass*limitC;angularError=b2Math.b2Abs(limitC);}
-else if(this.m_limitState==b2Joint.e_atLowerLimit)
-{limitC=angle-this.m_lowerAngle;angularError=b2Math.b2Max(0.0,-limitC);limitC=b2Math.b2Clamp(limitC+b2Settings.b2_angularSlop,-b2Settings.b2_maxAngularCorrection,0.0);limitImpulse=-this.m_motorMass*limitC;oldLimitImpulse=this.m_limitPositionImpulse;this.m_limitPositionImpulse=b2Math.b2Max(this.m_limitPositionImpulse+limitImpulse,0.0);limitImpulse=this.m_limitPositionImpulse-oldLimitImpulse;}
-else if(this.m_limitState==b2Joint.e_atUpperLimit)
-{limitC=angle-this.m_upperAngle;angularError=b2Math.b2Max(0.0,limitC);limitC=b2Math.b2Clamp(limitC-b2Settings.b2_angularSlop,0.0,b2Settings.b2_maxAngularCorrection);limitImpulse=-this.m_motorMass*limitC;oldLimitImpulse=this.m_limitPositionImpulse;this.m_limitPositionImpulse=b2Math.b2Min(this.m_limitPositionImpulse+limitImpulse,0.0);limitImpulse=this.m_limitPositionImpulse-oldLimitImpulse;}
-b1.m_rotation-=b1.m_invI*limitImpulse;b1.m_R.Set(b1.m_rotation);b2.m_rotation+=b2.m_invI*limitImpulse;b2.m_R.Set(b2.m_rotation);}
-return positionError<=b2Settings.b2_linearSlop&&angularError<=b2Settings.b2_angularSlop;},m_localAnchor1:new b2Vec2(),m_localAnchor2:new b2Vec2(),m_ptpImpulse:new b2Vec2(),m_motorImpulse:null,m_limitImpulse:null,m_limitPositionImpulse:null,m_ptpMass:new b2Mat22(),m_motorMass:null,m_intialAngle:null,m_lowerAngle:null,m_upperAngle:null,m_maxMotorTorque:null,m_motorSpeed:null,m_enableLimit:null,m_enableMotor:null,m_limitState:0});b2RevoluteJoint.tImpulse=new b2Vec2();
-var b2RevoluteJointDef=Class.create();Object.extend(b2RevoluteJointDef.prototype,b2JointDef.prototype);Object.extend(b2RevoluteJointDef.prototype,{initialize:function()
-{this.type=b2Joint.e_unknownJoint;this.userData=null;this.body1=null;this.body2=null;this.collideConnected=false;this.type=b2Joint.e_revoluteJoint;this.anchorPoint=new b2Vec2(0.0,0.0);this.lowerAngle=0.0;this.upperAngle=0.0;this.motorTorque=0.0;this.motorSpeed=0.0;this.enableLimit=false;this.enableMotor=false;},anchorPoint:null,lowerAngle:null,upperAngle:null,motorTorque:null,motorSpeed:null,enableLimit:null,enableMotor:null});
+/*
+ * Box2Djs (port of Box2DFlash 1.4.3.1) - http://box2d-js.sourceforge.net/
+ * Single-filed and jsmined ( http://code.google.com/p/jsmin-php/ ) by Mr.doob
+ */
+
+var b2Settings=Class.create();b2Settings.prototype={initialize:function(){}}
+b2Settings.USHRT_MAX=0x0000ffff;b2Settings.b2_pi=Math.PI;b2Settings.b2_massUnitsPerKilogram=1.0;b2Settings.b2_timeUnitsPerSecond=1.0;b2Settings.b2_lengthUnitsPerMeter=30.0;b2Settings.b2_maxManifoldPoints=2;b2Settings.b2_maxShapesPerBody=64;b2Settings.b2_maxPolyVertices=8;b2Settings.b2_maxProxies=1024;b2Settings.b2_maxPairs=8*b2Settings.b2_maxProxies;b2Settings.b2_linearSlop=0.005*b2Settings.b2_lengthUnitsPerMeter;b2Settings.b2_angularSlop=2.0/180.0*b2Settings.b2_pi;b2Settings.b2_velocityThreshold=1.0*b2Settings.b2_lengthUnitsPerMeter/b2Settings.b2_timeUnitsPerSecond;b2Settings.b2_maxLinearCorrection=0.2*b2Settings.b2_lengthUnitsPerMeter;b2Settings.b2_maxAngularCorrection=8.0/180.0*b2Settings.b2_pi;b2Settings.b2_contactBaumgarte=0.2;b2Settings.b2_timeToSleep=0.5*b2Settings.b2_timeUnitsPerSecond;b2Settings.b2_linearSleepTolerance=0.01*b2Settings.b2_lengthUnitsPerMeter/b2Settings.b2_timeUnitsPerSecond;b2Settings.b2_angularSleepTolerance=2.0/180.0/b2Settings.b2_timeUnitsPerSecond;b2Settings.b2Assert=function(a)
+{if(!a){var nullVec;nullVec.x++;}};
+var b2Vec2=Class.create();b2Vec2.prototype={initialize:function(x_,y_){this.x=x_;this.y=y_;},SetZero:function(){this.x=0.0;this.y=0.0;},Set:function(x_,y_){this.x=x_;this.y=y_;},SetV:function(v){this.x=v.x;this.y=v.y;},Negative:function(){return new b2Vec2(-this.x,-this.y);},Copy:function(){return new b2Vec2(this.x,this.y);},Add:function(v)
+{this.x+=v.x;this.y+=v.y;},Subtract:function(v)
+{this.x-=v.x;this.y-=v.y;},Multiply:function(a)
+{this.x*=a;this.y*=a;},MulM:function(A)
+{var tX=this.x;this.x=A.col1.x*tX+A.col2.x*this.y;this.y=A.col1.y*tX+A.col2.y*this.y;},MulTM:function(A)
+{var tX=b2Math.b2Dot(this,A.col1);this.y=b2Math.b2Dot(this,A.col2);this.x=tX;},CrossVF:function(s)
+{var tX=this.x;this.x=s*this.y;this.y=-s*tX;},CrossFV:function(s)
+{var tX=this.x;this.x=-s*this.y;this.y=s*tX;},MinV:function(b)
+{this.x=this.x<b.x?this.x:b.x;this.y=this.y<b.y?this.y:b.y;},MaxV:function(b)
+{this.x=this.x>b.x?this.x:b.x;this.y=this.y>b.y?this.y:b.y;},Abs:function()
+{this.x=Math.abs(this.x);this.y=Math.abs(this.y);},Length:function()
+{return Math.sqrt(this.x*this.x+this.y*this.y);},Normalize:function()
+{var length=this.Length();if(length<Number.MIN_VALUE)
+{return 0.0;}
+var invLength=1.0/length;this.x*=invLength;this.y*=invLength;return length;},IsValid:function()
+{return b2Math.b2IsValid(this.x)&&b2Math.b2IsValid(this.y);},x:null,y:null};b2Vec2.Make=function(x_,y_)
+{return new b2Vec2(x_,y_);};
+var b2Mat22=Class.create();b2Mat22.prototype={initialize:function(angle,c1,c2)
+{if(angle==null)angle=0;this.col1=new b2Vec2();this.col2=new b2Vec2();if(c1!=null&&c2!=null){this.col1.SetV(c1);this.col2.SetV(c2);}
+else{var c=Math.cos(angle);var s=Math.sin(angle);this.col1.x=c;this.col2.x=-s;this.col1.y=s;this.col2.y=c;}},Set:function(angle)
+{var c=Math.cos(angle);var s=Math.sin(angle);this.col1.x=c;this.col2.x=-s;this.col1.y=s;this.col2.y=c;},SetVV:function(c1,c2)
+{this.col1.SetV(c1);this.col2.SetV(c2);},Copy:function(){return new b2Mat22(0,this.col1,this.col2);},SetM:function(m)
+{this.col1.SetV(m.col1);this.col2.SetV(m.col2);},AddM:function(m)
+{this.col1.x+=m.col1.x;this.col1.y+=m.col1.y;this.col2.x+=m.col2.x;this.col2.y+=m.col2.y;},SetIdentity:function()
+{this.col1.x=1.0;this.col2.x=0.0;this.col1.y=0.0;this.col2.y=1.0;},SetZero:function()
+{this.col1.x=0.0;this.col2.x=0.0;this.col1.y=0.0;this.col2.y=0.0;},Invert:function(out)
+{var a=this.col1.x;var b=this.col2.x;var c=this.col1.y;var d=this.col2.y;var det=a*d-b*c;det=1.0/det;out.col1.x=det*d;out.col2.x=-det*b;out.col1.y=-det*c;out.col2.y=det*a;return out;},Solve:function(out,bX,bY)
+{var a11=this.col1.x;var a12=this.col2.x;var a21=this.col1.y;var a22=this.col2.y;var det=a11*a22-a12*a21;det=1.0/det;out.x=det*(a22*bX-a12*bY);out.y=det*(a11*bY-a21*bX);return out;},Abs:function()
+{this.col1.Abs();this.col2.Abs();},col1:new b2Vec2(),col2:new b2Vec2()};
+var b2Math=Class.create();b2Math.prototype={initialize:function(){}}
+b2Math.b2IsValid=function(x)
+{return isFinite(x);};b2Math.b2Dot=function(a,b)
+{return a.x*b.x+a.y*b.y;};b2Math.b2CrossVV=function(a,b)
+{return a.x*b.y-a.y*b.x;};b2Math.b2CrossVF=function(a,s)
+{var v=new b2Vec2(s*a.y,-s*a.x);return v;};b2Math.b2CrossFV=function(s,a)
+{var v=new b2Vec2(-s*a.y,s*a.x);return v;};b2Math.b2MulMV=function(A,v)
+{var u=new b2Vec2(A.col1.x*v.x+A.col2.x*v.y,A.col1.y*v.x+A.col2.y*v.y);return u;};b2Math.b2MulTMV=function(A,v)
+{var u=new b2Vec2(b2Math.b2Dot(v,A.col1),b2Math.b2Dot(v,A.col2));return u;};b2Math.AddVV=function(a,b)
+{var v=new b2Vec2(a.x+b.x,a.y+b.y);return v;};b2Math.SubtractVV=function(a,b)
+{var v=new b2Vec2(a.x-b.x,a.y-b.y);return v;};b2Math.MulFV=function(s,a)
+{var v=new b2Vec2(s*a.x,s*a.y);return v;};b2Math.AddMM=function(A,B)
+{var C=new b2Mat22(0,b2Math.AddVV(A.col1,B.col1),b2Math.AddVV(A.col2,B.col2));return C;};b2Math.b2MulMM=function(A,B)
+{var C=new b2Mat22(0,b2Math.b2MulMV(A,B.col1),b2Math.b2MulMV(A,B.col2));return C;};b2Math.b2MulTMM=function(A,B)
+{var c1=new b2Vec2(b2Math.b2Dot(A.col1,B.col1),b2Math.b2Dot(A.col2,B.col1));var c2=new b2Vec2(b2Math.b2Dot(A.col1,B.col2),b2Math.b2Dot(A.col2,B.col2));var C=new b2Mat22(0,c1,c2);return C;};b2Math.b2Abs=function(a)
+{return a>0.0?a:-a;};b2Math.b2AbsV=function(a)
+{var b=new b2Vec2(b2Math.b2Abs(a.x),b2Math.b2Abs(a.y));return b;};b2Math.b2AbsM=function(A)
+{var B=new b2Mat22(0,b2Math.b2AbsV(A.col1),b2Math.b2AbsV(A.col2));return B;};b2Math.b2Min=function(a,b)
+{return a<b?a:b;};b2Math.b2MinV=function(a,b)
+{var c=new b2Vec2(b2Math.b2Min(a.x,b.x),b2Math.b2Min(a.y,b.y));return c;};b2Math.b2Max=function(a,b)
+{return a>b?a:b;};b2Math.b2MaxV=function(a,b)
+{var c=new b2Vec2(b2Math.b2Max(a.x,b.x),b2Math.b2Max(a.y,b.y));return c;};b2Math.b2Clamp=function(a,low,high)
+{return b2Math.b2Max(low,b2Math.b2Min(a,high));};b2Math.b2ClampV=function(a,low,high)
+{return b2Math.b2MaxV(low,b2Math.b2MinV(a,high));};b2Math.b2Swap=function(a,b)
+{var tmp=a[0];a[0]=b[0];b[0]=tmp;};b2Math.b2Random=function()
+{return Math.random()*2-1;};b2Math.b2NextPowerOfTwo=function(x)
+{x|=(x>>1)&0x7FFFFFFF;x|=(x>>2)&0x3FFFFFFF;x|=(x>>4)&0x0FFFFFFF;x|=(x>>8)&0x00FFFFFF;x|=(x>>16)&0x0000FFFF;return x+1;};b2Math.b2IsPowerOfTwo=function(x)
+{var result=x>0&&(x&(x-1))==0;return result;};b2Math.tempVec2=new b2Vec2();b2Math.tempVec3=new b2Vec2();b2Math.tempVec4=new b2Vec2();b2Math.tempVec5=new b2Vec2();b2Math.tempMat=new b2Mat22();
+var b2AABB=Class.create();b2AABB.prototype={IsValid:function(){var dX=this.maxVertex.x;var dY=this.maxVertex.y;dX=this.maxVertex.x;dY=this.maxVertex.y;dX-=this.minVertex.x;dY-=this.minVertex.y;var valid=dX>=0.0&&dY>=0.0;valid=valid&&this.minVertex.IsValid()&&this.maxVertex.IsValid();return valid;},minVertex:new b2Vec2(),maxVertex:new b2Vec2(),initialize:function(){this.minVertex=new b2Vec2();this.maxVertex=new b2Vec2();}};
+var b2Bound=Class.create();b2Bound.prototype={IsLower:function(){return(this.value&1)==0;},IsUpper:function(){return(this.value&1)==1;},Swap:function(b){var tempValue=this.value;var tempProxyId=this.proxyId;var tempStabbingCount=this.stabbingCount;this.value=b.value;this.proxyId=b.proxyId;this.stabbingCount=b.stabbingCount;b.value=tempValue;b.proxyId=tempProxyId;b.stabbingCount=tempStabbingCount;},value:0,proxyId:0,stabbingCount:0,initialize:function(){}}
+
+var b2BoundValues=Class.create();b2BoundValues.prototype={lowerValues:[0,0],upperValues:[0,0],initialize:function(){this.lowerValues=[0,0];this.upperValues=[0,0];}}
+
+var b2Pair=Class.create();b2Pair.prototype={SetBuffered:function(){this.status|=b2Pair.e_pairBuffered;},ClearBuffered:function(){this.status&=~b2Pair.e_pairBuffered;},IsBuffered:function(){return(this.status&b2Pair.e_pairBuffered)==b2Pair.e_pairBuffered;},SetRemoved:function(){this.status|=b2Pair.e_pairRemoved;},ClearRemoved:function(){this.status&=~b2Pair.e_pairRemoved;},IsRemoved:function(){return(this.status&b2Pair.e_pairRemoved)==b2Pair.e_pairRemoved;},SetFinal:function(){this.status|=b2Pair.e_pairFinal;},IsFinal:function(){return(this.status&b2Pair.e_pairFinal)==b2Pair.e_pairFinal;},userData:null,proxyId1:0,proxyId2:0,next:0,status:0,initialize:function(){}};b2Pair.b2_nullPair=b2Settings.USHRT_MAX;b2Pair.b2_nullProxy=b2Settings.USHRT_MAX;b2Pair.b2_tableCapacity=b2Settings.b2_maxPairs;b2Pair.b2_tableMask=b2Pair.b2_tableCapacity-1;b2Pair.e_pairBuffered=0x0001;b2Pair.e_pairRemoved=0x0002;b2Pair.e_pairFinal=0x0004;
+var b2PairCallback=Class.create();b2PairCallback.prototype={PairAdded:function(proxyUserData1,proxyUserData2){return null},PairRemoved:function(proxyUserData1,proxyUserData2,pairUserData){},initialize:function(){}};
+var b2BufferedPair=Class.create();b2BufferedPair.prototype={proxyId1:0,proxyId2:0,initialize:function(){}}
+
+var b2PairManager=Class.create();b2PairManager.prototype={initialize:function(){var i=0;this.m_hashTable=new Array(b2Pair.b2_tableCapacity);for(i=0;i<b2Pair.b2_tableCapacity;++i)
+{this.m_hashTable[i]=b2Pair.b2_nullPair;}
+this.m_pairs=new Array(b2Settings.b2_maxPairs);for(i=0;i<b2Settings.b2_maxPairs;++i)
+{this.m_pairs[i]=new b2Pair();}
+this.m_pairBuffer=new Array(b2Settings.b2_maxPairs);for(i=0;i<b2Settings.b2_maxPairs;++i)
+{this.m_pairBuffer[i]=new b2BufferedPair();}
+for(i=0;i<b2Settings.b2_maxPairs;++i)
+{this.m_pairs[i].proxyId1=b2Pair.b2_nullProxy;this.m_pairs[i].proxyId2=b2Pair.b2_nullProxy;this.m_pairs[i].userData=null;this.m_pairs[i].status=0;this.m_pairs[i].next=(i+1);}
+this.m_pairs[b2Settings.b2_maxPairs-1].next=b2Pair.b2_nullPair;this.m_pairCount=0;},Initialize:function(broadPhase,callback){this.m_broadPhase=broadPhase;this.m_callback=callback;},AddBufferedPair:function(proxyId1,proxyId2){var pair=this.AddPair(proxyId1,proxyId2);if(pair.IsBuffered()==false)
+{pair.SetBuffered();this.m_pairBuffer[this.m_pairBufferCount].proxyId1=pair.proxyId1;this.m_pairBuffer[this.m_pairBufferCount].proxyId2=pair.proxyId2;++this.m_pairBufferCount;}
+pair.ClearRemoved();if(b2BroadPhase.s_validate)
+{this.ValidateBuffer();}},RemoveBufferedPair:function(proxyId1,proxyId2){var pair=this.Find(proxyId1,proxyId2);if(pair==null)
+{return;}
+if(pair.IsBuffered()==false)
+{pair.SetBuffered();this.m_pairBuffer[this.m_pairBufferCount].proxyId1=pair.proxyId1;this.m_pairBuffer[this.m_pairBufferCount].proxyId2=pair.proxyId2;++this.m_pairBufferCount;}
+pair.SetRemoved();if(b2BroadPhase.s_validate)
+{this.ValidateBuffer();}},Commit:function(){var i=0;var removeCount=0;var proxies=this.m_broadPhase.m_proxyPool;for(i=0;i<this.m_pairBufferCount;++i)
+{var pair=this.Find(this.m_pairBuffer[i].proxyId1,this.m_pairBuffer[i].proxyId2);pair.ClearBuffered();var proxy1=proxies[pair.proxyId1];var proxy2=proxies[pair.proxyId2];if(pair.IsRemoved())
+{if(pair.IsFinal()==true)
+{this.m_callback.PairRemoved(proxy1.userData,proxy2.userData,pair.userData);}
+this.m_pairBuffer[removeCount].proxyId1=pair.proxyId1;this.m_pairBuffer[removeCount].proxyId2=pair.proxyId2;++removeCount;}
+else
+{if(pair.IsFinal()==false)
+{pair.userData=this.m_callback.PairAdded(proxy1.userData,proxy2.userData);pair.SetFinal();}}}
+for(i=0;i<removeCount;++i)
+{this.RemovePair(this.m_pairBuffer[i].proxyId1,this.m_pairBuffer[i].proxyId2);}
+this.m_pairBufferCount=0;if(b2BroadPhase.s_validate)
+{this.ValidateTable();}},AddPair:function(proxyId1,proxyId2){if(proxyId1>proxyId2){var temp=proxyId1;proxyId1=proxyId2;proxyId2=temp;}
+var hash=b2PairManager.Hash(proxyId1,proxyId2)&b2Pair.b2_tableMask;var pair=pair=this.FindHash(proxyId1,proxyId2,hash);if(pair!=null)
+{return pair;}
+var pIndex=this.m_freePair;pair=this.m_pairs[pIndex];this.m_freePair=pair.next;pair.proxyId1=proxyId1;pair.proxyId2=proxyId2;pair.status=0;pair.userData=null;pair.next=this.m_hashTable[hash];this.m_hashTable[hash]=pIndex;++this.m_pairCount;return pair;},RemovePair:function(proxyId1,proxyId2){if(proxyId1>proxyId2){var temp=proxyId1;proxyId1=proxyId2;proxyId2=temp;}
+var hash=b2PairManager.Hash(proxyId1,proxyId2)&b2Pair.b2_tableMask;var node=this.m_hashTable[hash];var pNode=null;while(node!=b2Pair.b2_nullPair)
+{if(b2PairManager.Equals(this.m_pairs[node],proxyId1,proxyId2))
+{var index=node;if(pNode){pNode.next=this.m_pairs[node].next;}
+else{this.m_hashTable[hash]=this.m_pairs[node].next;}
+var pair=this.m_pairs[index];var userData=pair.userData;pair.next=this.m_freePair;pair.proxyId1=b2Pair.b2_nullProxy;pair.proxyId2=b2Pair.b2_nullProxy;pair.userData=null;pair.status=0;this.m_freePair=index;--this.m_pairCount;return userData;}
+else
+{pNode=this.m_pairs[node];node=pNode.next;}}
+return null;},Find:function(proxyId1,proxyId2){if(proxyId1>proxyId2){var temp=proxyId1;proxyId1=proxyId2;proxyId2=temp;}
+var hash=b2PairManager.Hash(proxyId1,proxyId2)&b2Pair.b2_tableMask;return this.FindHash(proxyId1,proxyId2,hash);},FindHash:function(proxyId1,proxyId2,hash){var index=this.m_hashTable[hash];while(index!=b2Pair.b2_nullPair&&b2PairManager.Equals(this.m_pairs[index],proxyId1,proxyId2)==false)
+{index=this.m_pairs[index].next;}
+if(index==b2Pair.b2_nullPair)
+{return null;}
+return this.m_pairs[index];},ValidateBuffer:function(){},ValidateTable:function(){},m_broadPhase:null,m_callback:null,m_pairs:null,m_freePair:0,m_pairCount:0,m_pairBuffer:null,m_pairBufferCount:0,m_hashTable:null};b2PairManager.Hash=function(proxyId1,proxyId2)
+{var key=((proxyId2<<16)&0xffff0000)|proxyId1;key=~key+((key<<15)&0xFFFF8000);key=key^((key>>12)&0x000fffff);key=key+((key<<2)&0xFFFFFFFC);key=key^((key>>4)&0x0fffffff);key=key*2057;key=key^((key>>16)&0x0000ffff);return key;};b2PairManager.Equals=function(pair,proxyId1,proxyId2)
+{return(pair.proxyId1==proxyId1&&pair.proxyId2==proxyId2);};b2PairManager.EqualsPair=function(pair1,pair2)
+{return pair1.proxyId1==pair2.proxyId1&&pair1.proxyId2==pair2.proxyId2;};
+var b2BroadPhase=Class.create();b2BroadPhase.prototype={initialize:function(worldAABB,callback){this.m_pairManager=new b2PairManager();this.m_proxyPool=new Array(b2Settings.b2_maxPairs);this.m_bounds=new Array(2*b2Settings.b2_maxProxies);this.m_queryResults=new Array(b2Settings.b2_maxProxies);this.m_quantizationFactor=new b2Vec2();var i=0;this.m_pairManager.Initialize(this,callback);this.m_worldAABB=worldAABB;this.m_proxyCount=0;for(i=0;i<b2Settings.b2_maxProxies;i++){this.m_queryResults[i]=0;}
+this.m_bounds=new Array(2);for(i=0;i<2;i++){this.m_bounds[i]=new Array(2*b2Settings.b2_maxProxies);for(var j=0;j<2*b2Settings.b2_maxProxies;j++){this.m_bounds[i][j]=new b2Bound();}}
+var dX=worldAABB.maxVertex.x;var dY=worldAABB.maxVertex.y;dX-=worldAABB.minVertex.x;dY-=worldAABB.minVertex.y;this.m_quantizationFactor.x=b2Settings.USHRT_MAX/dX;this.m_quantizationFactor.y=b2Settings.USHRT_MAX/dY;var tProxy;for(i=0;i<b2Settings.b2_maxProxies-1;++i)
+{tProxy=new b2Proxy();this.m_proxyPool[i]=tProxy;tProxy.SetNext(i+1);tProxy.timeStamp=0;tProxy.overlapCount=b2BroadPhase.b2_invalid;tProxy.userData=null;}
+tProxy=new b2Proxy();this.m_proxyPool[b2Settings.b2_maxProxies-1]=tProxy;tProxy.SetNext(b2Pair.b2_nullProxy);tProxy.timeStamp=0;tProxy.overlapCount=b2BroadPhase.b2_invalid;tProxy.userData=null;this.m_freeProxy=0;this.m_timeStamp=1;this.m_queryResultCount=0;},InRange:function(aabb){var dX;var dY;var d2X;var d2Y;dX=aabb.minVertex.x;dY=aabb.minVertex.y;dX-=this.m_worldAABB.maxVertex.x;dY-=this.m_worldAABB.maxVertex.y;d2X=this.m_worldAABB.minVertex.x;d2Y=this.m_worldAABB.minVertex.y;d2X-=aabb.maxVertex.x;d2Y-=aabb.maxVertex.y;dX=b2Math.b2Max(dX,d2X);dY=b2Math.b2Max(dY,d2Y);return b2Math.b2Max(dX,dY)<0.0;},GetProxy:function(proxyId){if(proxyId==b2Pair.b2_nullProxy||this.m_proxyPool[proxyId].IsValid()==false)
+{return null;}
+return this.m_proxyPool[proxyId];},CreateProxy:function(aabb,userData){var index=0;var proxy;var proxyId=this.m_freeProxy;proxy=this.m_proxyPool[proxyId];this.m_freeProxy=proxy.GetNext();proxy.overlapCount=0;proxy.userData=userData;var boundCount=2*this.m_proxyCount;var lowerValues=new Array();var upperValues=new Array();this.ComputeBounds(lowerValues,upperValues,aabb);for(var axis=0;axis<2;++axis)
+{var bounds=this.m_bounds[axis];var lowerIndex=0;var upperIndex=0;var lowerIndexOut=[lowerIndex];var upperIndexOut=[upperIndex];this.Query(lowerIndexOut,upperIndexOut,lowerValues[axis],upperValues[axis],bounds,boundCount,axis);lowerIndex=lowerIndexOut[0];upperIndex=upperIndexOut[0];var tArr=new Array();var j=0;var tEnd=boundCount-upperIndex
+var tBound1;var tBound2;for(j=0;j<tEnd;j++){tArr[j]=new b2Bound();tBound1=tArr[j];tBound2=bounds[upperIndex+j];tBound1.value=tBound2.value;tBound1.proxyId=tBound2.proxyId;tBound1.stabbingCount=tBound2.stabbingCount;}
+tEnd=tArr.length;var tIndex=upperIndex+2;for(j=0;j<tEnd;j++){tBound2=tArr[j];tBound1=bounds[tIndex+j]
+tBound1.value=tBound2.value;tBound1.proxyId=tBound2.proxyId;tBound1.stabbingCount=tBound2.stabbingCount;}
+tArr=new Array();tEnd=upperIndex-lowerIndex;for(j=0;j<tEnd;j++){tArr[j]=new b2Bound();tBound1=tArr[j];tBound2=bounds[lowerIndex+j];tBound1.value=tBound2.value;tBound1.proxyId=tBound2.proxyId;tBound1.stabbingCount=tBound2.stabbingCount;}
+tEnd=tArr.length;tIndex=lowerIndex+1;for(j=0;j<tEnd;j++){tBound2=tArr[j];tBound1=bounds[tIndex+j]
+tBound1.value=tBound2.value;tBound1.proxyId=tBound2.proxyId;tBound1.stabbingCount=tBound2.stabbingCount;}
+++upperIndex;bounds[lowerIndex].value=lowerValues[axis];bounds[lowerIndex].proxyId=proxyId;bounds[upperIndex].value=upperValues[axis];bounds[upperIndex].proxyId=proxyId;bounds[lowerIndex].stabbingCount=lowerIndex==0?0:bounds[lowerIndex-1].stabbingCount;bounds[upperIndex].stabbingCount=bounds[upperIndex-1].stabbingCount;for(index=lowerIndex;index<upperIndex;++index)
+{bounds[index].stabbingCount++;}
+for(index=lowerIndex;index<boundCount+2;++index)
+{var proxy2=this.m_proxyPool[bounds[index].proxyId];if(bounds[index].IsLower())
+{proxy2.lowerBounds[axis]=index;}
+else
+{proxy2.upperBounds[axis]=index;}}}
+++this.m_proxyCount;for(var i=0;i<this.m_queryResultCount;++i)
+{this.m_pairManager.AddBufferedPair(proxyId,this.m_queryResults[i]);}
+this.m_pairManager.Commit();this.m_queryResultCount=0;this.IncrementTimeStamp();return proxyId;},DestroyProxy:function(proxyId){var proxy=this.m_proxyPool[proxyId];var boundCount=2*this.m_proxyCount;for(var axis=0;axis<2;++axis)
+{var bounds=this.m_bounds[axis];var lowerIndex=proxy.lowerBounds[axis];var upperIndex=proxy.upperBounds[axis];var lowerValue=bounds[lowerIndex].value;var upperValue=bounds[upperIndex].value;var tArr=new Array();var j=0;var tEnd=upperIndex-lowerIndex-1;var tBound1;var tBound2;for(j=0;j<tEnd;j++){tArr[j]=new b2Bound();tBound1=tArr[j];tBound2=bounds[lowerIndex+1+j];tBound1.value=tBound2.value;tBound1.proxyId=tBound2.proxyId;tBound1.stabbingCount=tBound2.stabbingCount;}
+tEnd=tArr.length;var tIndex=lowerIndex;for(j=0;j<tEnd;j++){tBound2=tArr[j];tBound1=bounds[tIndex+j]
+tBound1.value=tBound2.value;tBound1.proxyId=tBound2.proxyId;tBound1.stabbingCount=tBound2.stabbingCount;}
+tArr=new Array();tEnd=boundCount-upperIndex-1;for(j=0;j<tEnd;j++){tArr[j]=new b2Bound();tBound1=tArr[j];tBound2=bounds[upperIndex+1+j];tBound1.value=tBound2.value;tBound1.proxyId=tBound2.proxyId;tBound1.stabbingCount=tBound2.stabbingCount;}
+tEnd=tArr.length;tIndex=upperIndex-1;for(j=0;j<tEnd;j++){tBound2=tArr[j];tBound1=bounds[tIndex+j]
+tBound1.value=tBound2.value;tBound1.proxyId=tBound2.proxyId;tBound1.stabbingCount=tBound2.stabbingCount;}
+tEnd=boundCount-2;for(var index=lowerIndex;index<tEnd;++index)
+{var proxy2=this.m_proxyPool[bounds[index].proxyId];if(bounds[index].IsLower())
+{proxy2.lowerBounds[axis]=index;}
+else
+{proxy2.upperBounds[axis]=index;}}
+tEnd=upperIndex-1;for(var index2=lowerIndex;index2<tEnd;++index2)
+{bounds[index2].stabbingCount--;}
+this.Query([0],[0],lowerValue,upperValue,bounds,boundCount-2,axis);}
+for(var i=0;i<this.m_queryResultCount;++i)
+{this.m_pairManager.RemoveBufferedPair(proxyId,this.m_queryResults[i]);}
+this.m_pairManager.Commit();this.m_queryResultCount=0;this.IncrementTimeStamp();proxy.userData=null;proxy.overlapCount=b2BroadPhase.b2_invalid;proxy.lowerBounds[0]=b2BroadPhase.b2_invalid;proxy.lowerBounds[1]=b2BroadPhase.b2_invalid;proxy.upperBounds[0]=b2BroadPhase.b2_invalid;proxy.upperBounds[1]=b2BroadPhase.b2_invalid;proxy.SetNext(this.m_freeProxy);this.m_freeProxy=proxyId;--this.m_proxyCount;},MoveProxy:function(proxyId,aabb){var axis=0;var index=0;var bound;var prevBound
+var nextBound
+var nextProxyId=0;var nextProxy;if(proxyId==b2Pair.b2_nullProxy||b2Settings.b2_maxProxies<=proxyId)
+{return;}
+if(aabb.IsValid()==false)
+{return;}
+var boundCount=2*this.m_proxyCount;var proxy=this.m_proxyPool[proxyId];var newValues=new b2BoundValues();this.ComputeBounds(newValues.lowerValues,newValues.upperValues,aabb);var oldValues=new b2BoundValues();for(axis=0;axis<2;++axis)
+{oldValues.lowerValues[axis]=this.m_bounds[axis][proxy.lowerBounds[axis]].value;oldValues.upperValues[axis]=this.m_bounds[axis][proxy.upperBounds[axis]].value;}
+for(axis=0;axis<2;++axis)
+{var bounds=this.m_bounds[axis];var lowerIndex=proxy.lowerBounds[axis];var upperIndex=proxy.upperBounds[axis];var lowerValue=newValues.lowerValues[axis];var upperValue=newValues.upperValues[axis];var deltaLower=lowerValue-bounds[lowerIndex].value;var deltaUpper=upperValue-bounds[upperIndex].value;bounds[lowerIndex].value=lowerValue;bounds[upperIndex].value=upperValue;if(deltaLower<0)
+{index=lowerIndex;while(index>0&&lowerValue<bounds[index-1].value)
+{bound=bounds[index];prevBound=bounds[index-1];var prevProxyId=prevBound.proxyId;var prevProxy=this.m_proxyPool[prevBound.proxyId];prevBound.stabbingCount++;if(prevBound.IsUpper()==true)
+{if(this.TestOverlap(newValues,prevProxy))
+{this.m_pairManager.AddBufferedPair(proxyId,prevProxyId);}
+prevProxy.upperBounds[axis]++;bound.stabbingCount++;}
+else
+{prevProxy.lowerBounds[axis]++;bound.stabbingCount--;}
+proxy.lowerBounds[axis]--;bound.Swap(prevBound);--index;}}
+if(deltaUpper>0)
+{index=upperIndex;while(index<boundCount-1&&bounds[index+1].value<=upperValue)
+{bound=bounds[index];nextBound=bounds[index+1];nextProxyId=nextBound.proxyId;nextProxy=this.m_proxyPool[nextProxyId];nextBound.stabbingCount++;if(nextBound.IsLower()==true)
+{if(this.TestOverlap(newValues,nextProxy))
+{this.m_pairManager.AddBufferedPair(proxyId,nextProxyId);}
+nextProxy.lowerBounds[axis]--;bound.stabbingCount++;}
+else
+{nextProxy.upperBounds[axis]--;bound.stabbingCount--;}
+proxy.upperBounds[axis]++;bound.Swap(nextBound);index++;}}
+if(deltaLower>0)
+{index=lowerIndex;while(index<boundCount-1&&bounds[index+1].value<=lowerValue)
+{bound=bounds[index];nextBound=bounds[index+1];nextProxyId=nextBound.proxyId;nextProxy=this.m_proxyPool[nextProxyId];nextBound.stabbingCount--;if(nextBound.IsUpper())
+{if(this.TestOverlap(oldValues,nextProxy))
+{this.m_pairManager.RemoveBufferedPair(proxyId,nextProxyId);}
+nextProxy.upperBounds[axis]--;bound.stabbingCount--;}
+else
+{nextProxy.lowerBounds[axis]--;bound.stabbingCount++;}
+proxy.lowerBounds[axis]++;bound.Swap(nextBound);index++;}}
+if(deltaUpper<0)
+{index=upperIndex;while(index>0&&upperValue<bounds[index-1].value)
+{bound=bounds[index];prevBound=bounds[index-1];prevProxyId=prevBound.proxyId;prevProxy=this.m_proxyPool[prevProxyId];prevBound.stabbingCount--;if(prevBound.IsLower()==true)
+{if(this.TestOverlap(oldValues,prevProxy))
+{this.m_pairManager.RemoveBufferedPair(proxyId,prevProxyId);}
+prevProxy.lowerBounds[axis]++;bound.stabbingCount--;}
+else
+{prevProxy.upperBounds[axis]++;bound.stabbingCount++;}
+proxy.upperBounds[axis]--;bound.Swap(prevBound);index--;}}}},Commit:function(){this.m_pairManager.Commit();},QueryAABB:function(aabb,userData,maxCount){var lowerValues=new Array();var upperValues=new Array();this.ComputeBounds(lowerValues,upperValues,aabb);var lowerIndex=0;var upperIndex=0;var lowerIndexOut=[lowerIndex];var upperIndexOut=[upperIndex];this.Query(lowerIndexOut,upperIndexOut,lowerValues[0],upperValues[0],this.m_bounds[0],2*this.m_proxyCount,0);this.Query(lowerIndexOut,upperIndexOut,lowerValues[1],upperValues[1],this.m_bounds[1],2*this.m_proxyCount,1);var count=0;for(var i=0;i<this.m_queryResultCount&&count<maxCount;++i,++count)
+{var proxy=this.m_proxyPool[this.m_queryResults[i]];userData[i]=proxy.userData;}
+this.m_queryResultCount=0;this.IncrementTimeStamp();return count;},Validate:function(){var pair;var proxy1;var proxy2;var overlap;for(var axis=0;axis<2;++axis)
+{var bounds=this.m_bounds[axis];var boundCount=2*this.m_proxyCount;var stabbingCount=0;for(var i=0;i<boundCount;++i)
+{var bound=bounds[i];if(bound.IsLower()==true)
+{stabbingCount++;}
+else
+{stabbingCount--;}}}},ComputeBounds:function(lowerValues,upperValues,aabb)
+{var minVertexX=aabb.minVertex.x;var minVertexY=aabb.minVertex.y;minVertexX=b2Math.b2Min(minVertexX,this.m_worldAABB.maxVertex.x);minVertexY=b2Math.b2Min(minVertexY,this.m_worldAABB.maxVertex.y);minVertexX=b2Math.b2Max(minVertexX,this.m_worldAABB.minVertex.x);minVertexY=b2Math.b2Max(minVertexY,this.m_worldAABB.minVertex.y);var maxVertexX=aabb.maxVertex.x;var maxVertexY=aabb.maxVertex.y;maxVertexX=b2Math.b2Min(maxVertexX,this.m_worldAABB.maxVertex.x);maxVertexY=b2Math.b2Min(maxVertexY,this.m_worldAABB.maxVertex.y);maxVertexX=b2Math.b2Max(maxVertexX,this.m_worldAABB.minVertex.x);maxVertexY=b2Math.b2Max(maxVertexY,this.m_worldAABB.minVertex.y);lowerValues[0]=(this.m_quantizationFactor.x*(minVertexX-this.m_worldAABB.minVertex.x))&(b2Settings.USHRT_MAX-1);upperValues[0]=((this.m_quantizationFactor.x*(maxVertexX-this.m_worldAABB.minVertex.x))&0x0000ffff)|1;lowerValues[1]=(this.m_quantizationFactor.y*(minVertexY-this.m_worldAABB.minVertex.y))&(b2Settings.USHRT_MAX-1);upperValues[1]=((this.m_quantizationFactor.y*(maxVertexY-this.m_worldAABB.minVertex.y))&0x0000ffff)|1;},TestOverlapValidate:function(p1,p2){for(var axis=0;axis<2;++axis)
+{var bounds=this.m_bounds[axis];if(bounds[p1.lowerBounds[axis]].value>bounds[p2.upperBounds[axis]].value)
+return false;if(bounds[p1.upperBounds[axis]].value<bounds[p2.lowerBounds[axis]].value)
+return false;}
+return true;},TestOverlap:function(b,p)
+{for(var axis=0;axis<2;++axis)
+{var bounds=this.m_bounds[axis];if(b.lowerValues[axis]>bounds[p.upperBounds[axis]].value)
+return false;if(b.upperValues[axis]<bounds[p.lowerBounds[axis]].value)
+return false;}
+return true;},Query:function(lowerQueryOut,upperQueryOut,lowerValue,upperValue,bounds,boundCount,axis){var lowerQuery=b2BroadPhase.BinarySearch(bounds,boundCount,lowerValue);var upperQuery=b2BroadPhase.BinarySearch(bounds,boundCount,upperValue);for(var j=lowerQuery;j<upperQuery;++j)
+{if(bounds[j].IsLower())
+{this.IncrementOverlapCount(bounds[j].proxyId);}}
+if(lowerQuery>0)
+{var i=lowerQuery-1;var s=bounds[i].stabbingCount;while(s)
+{if(bounds[i].IsLower())
+{var proxy=this.m_proxyPool[bounds[i].proxyId];if(lowerQuery<=proxy.upperBounds[axis])
+{this.IncrementOverlapCount(bounds[i].proxyId);--s;}}
+--i;}}
+lowerQueryOut[0]=lowerQuery;upperQueryOut[0]=upperQuery;},IncrementOverlapCount:function(proxyId){var proxy=this.m_proxyPool[proxyId];if(proxy.timeStamp<this.m_timeStamp)
+{proxy.timeStamp=this.m_timeStamp;proxy.overlapCount=1;}
+else
+{proxy.overlapCount=2;this.m_queryResults[this.m_queryResultCount]=proxyId;++this.m_queryResultCount;}},IncrementTimeStamp:function(){if(this.m_timeStamp==b2Settings.USHRT_MAX)
+{for(var i=0;i<b2Settings.b2_maxProxies;++i)
+{this.m_proxyPool[i].timeStamp=0;}
+this.m_timeStamp=1;}
+else
+{++this.m_timeStamp;}},m_pairManager:new b2PairManager(),m_proxyPool:new Array(b2Settings.b2_maxPairs),m_freeProxy:0,m_bounds:new Array(2*b2Settings.b2_maxProxies),m_queryResults:new Array(b2Settings.b2_maxProxies),m_queryResultCount:0,m_worldAABB:null,m_quantizationFactor:new b2Vec2(),m_proxyCount:0,m_timeStamp:0};b2BroadPhase.s_validate=false;b2BroadPhase.b2_invalid=b2Settings.USHRT_MAX;b2BroadPhase.b2_nullEdge=b2Settings.USHRT_MAX;b2BroadPhase.BinarySearch=function(bounds,count,value)
+{var low=0;var high=count-1;while(low<=high)
+{var mid=Math.floor((low+high)/2);if(bounds[mid].value>value)
+{high=mid-1;}
+else if(bounds[mid].value<value)
+{low=mid+1;}
+else
+{return(mid);}}
+return(low);};
+var b2Collision=Class.create();b2Collision.prototype={initialize:function(){}}
+b2Collision.b2_nullFeature=0x000000ff;b2Collision.ClipSegmentToLine=function(vOut,vIn,normal,offset)
+{var numOut=0;var vIn0=vIn[0].v;var vIn1=vIn[1].v;var distance0=b2Math.b2Dot(normal,vIn[0].v)-offset;var distance1=b2Math.b2Dot(normal,vIn[1].v)-offset;if(distance0<=0.0)vOut[numOut++]=vIn[0];if(distance1<=0.0)vOut[numOut++]=vIn[1];if(distance0*distance1<0.0)
+{var interp=distance0/(distance0-distance1);var tVec=vOut[numOut].v;tVec.x=vIn0.x+interp*(vIn1.x-vIn0.x);tVec.y=vIn0.y+interp*(vIn1.y-vIn0.y);if(distance0>0.0)
+{vOut[numOut].id=vIn[0].id;}
+else
+{vOut[numOut].id=vIn[1].id;}
+++numOut;}
+return numOut;};b2Collision.EdgeSeparation=function(poly1,edge1,poly2)
+{var vert1s=poly1.m_vertices;var count2=poly2.m_vertexCount;var vert2s=poly2.m_vertices;var normalX=poly1.m_normals[edge1].x;var normalY=poly1.m_normals[edge1].y;var tX=normalX;var tMat=poly1.m_R;normalX=tMat.col1.x*tX+tMat.col2.x*normalY;normalY=tMat.col1.y*tX+tMat.col2.y*normalY;var normalLocal2X=normalX;var normalLocal2Y=normalY;tMat=poly2.m_R;tX=normalLocal2X*tMat.col1.x+normalLocal2Y*tMat.col1.y;normalLocal2Y=normalLocal2X*tMat.col2.x+normalLocal2Y*tMat.col2.y;normalLocal2X=tX;var vertexIndex2=0;var minDot=Number.MAX_VALUE;for(var i=0;i<count2;++i)
+{var tVec=vert2s[i];var dot=tVec.x*normalLocal2X+tVec.y*normalLocal2Y;if(dot<minDot)
+{minDot=dot;vertexIndex2=i;}}
+tMat=poly1.m_R;var v1X=poly1.m_position.x+(tMat.col1.x*vert1s[edge1].x+tMat.col2.x*vert1s[edge1].y)
+var v1Y=poly1.m_position.y+(tMat.col1.y*vert1s[edge1].x+tMat.col2.y*vert1s[edge1].y)
+tMat=poly2.m_R;var v2X=poly2.m_position.x+(tMat.col1.x*vert2s[vertexIndex2].x+tMat.col2.x*vert2s[vertexIndex2].y)
+var v2Y=poly2.m_position.y+(tMat.col1.y*vert2s[vertexIndex2].x+tMat.col2.y*vert2s[vertexIndex2].y)
+v2X-=v1X;v2Y-=v1Y;var separation=v2X*normalX+v2Y*normalY;return separation;};b2Collision.FindMaxSeparation=function(edgeIndex,poly1,poly2,conservative)
+{var count1=poly1.m_vertexCount;var dX=poly2.m_position.x-poly1.m_position.x;var dY=poly2.m_position.y-poly1.m_position.y;var dLocal1X=(dX*poly1.m_R.col1.x+dY*poly1.m_R.col1.y);var dLocal1Y=(dX*poly1.m_R.col2.x+dY*poly1.m_R.col2.y);var edge=0;var maxDot=-Number.MAX_VALUE;for(var i=0;i<count1;++i)
+{var dot=(poly1.m_normals[i].x*dLocal1X+poly1.m_normals[i].y*dLocal1Y);if(dot>maxDot)
+{maxDot=dot;edge=i;}}
+var s=b2Collision.EdgeSeparation(poly1,edge,poly2);if(s>0.0&&conservative==false)
+{return s;}
+var prevEdge=edge-1>=0?edge-1:count1-1;var sPrev=b2Collision.EdgeSeparation(poly1,prevEdge,poly2);if(sPrev>0.0&&conservative==false)
+{return sPrev;}
+var nextEdge=edge+1<count1?edge+1:0;var sNext=b2Collision.EdgeSeparation(poly1,nextEdge,poly2);if(sNext>0.0&&conservative==false)
+{return sNext;}
+var bestEdge=0;var bestSeparation;var increment=0;if(sPrev>s&&sPrev>sNext)
+{increment=-1;bestEdge=prevEdge;bestSeparation=sPrev;}
+else if(sNext>s)
+{increment=1;bestEdge=nextEdge;bestSeparation=sNext;}
+else
+{edgeIndex[0]=edge;return s;}
+while(true)
+{if(increment==-1)
+edge=bestEdge-1>=0?bestEdge-1:count1-1;else
+edge=bestEdge+1<count1?bestEdge+1:0;s=b2Collision.EdgeSeparation(poly1,edge,poly2);if(s>0.0&&conservative==false)
+{return s;}
+if(s>bestSeparation)
+{bestEdge=edge;bestSeparation=s;}
+else
+{break;}}
+edgeIndex[0]=bestEdge;return bestSeparation;};b2Collision.FindIncidentEdge=function(c,poly1,edge1,poly2)
+{var count1=poly1.m_vertexCount;var vert1s=poly1.m_vertices;var count2=poly2.m_vertexCount;var vert2s=poly2.m_vertices;var vertex11=edge1;var vertex12=edge1+1==count1?0:edge1+1;var tVec=vert1s[vertex12];var normal1Local1X=tVec.x;var normal1Local1Y=tVec.y;tVec=vert1s[vertex11];normal1Local1X-=tVec.x;normal1Local1Y-=tVec.y;var tX=normal1Local1X;normal1Local1X=normal1Local1Y;normal1Local1Y=-tX;var invLength=1.0/Math.sqrt(normal1Local1X*normal1Local1X+normal1Local1Y*normal1Local1Y);normal1Local1X*=invLength;normal1Local1Y*=invLength;var normal1X=normal1Local1X;var normal1Y=normal1Local1Y;tX=normal1X;var tMat=poly1.m_R;normal1X=tMat.col1.x*tX+tMat.col2.x*normal1Y;normal1Y=tMat.col1.y*tX+tMat.col2.y*normal1Y;var normal1Local2X=normal1X;var normal1Local2Y=normal1Y;tMat=poly2.m_R;tX=normal1Local2X*tMat.col1.x+normal1Local2Y*tMat.col1.y;normal1Local2Y=normal1Local2X*tMat.col2.x+normal1Local2Y*tMat.col2.y;normal1Local2X=tX;var vertex21=0;var vertex22=0;var minDot=Number.MAX_VALUE;for(var i=0;i<count2;++i)
+{var i1=i;var i2=i+1<count2?i+1:0;tVec=vert2s[i2];var normal2Local2X=tVec.x;var normal2Local2Y=tVec.y;tVec=vert2s[i1];normal2Local2X-=tVec.x;normal2Local2Y-=tVec.y;tX=normal2Local2X;normal2Local2X=normal2Local2Y;normal2Local2Y=-tX;invLength=1.0/Math.sqrt(normal2Local2X*normal2Local2X+normal2Local2Y*normal2Local2Y);normal2Local2X*=invLength;normal2Local2Y*=invLength;var dot=normal2Local2X*normal1Local2X+normal2Local2Y*normal1Local2Y;if(dot<minDot)
+{minDot=dot;vertex21=i1;vertex22=i2;}}
+var tClip;tClip=c[0];tVec=tClip.v;tVec.SetV(vert2s[vertex21]);tVec.MulM(poly2.m_R);tVec.Add(poly2.m_position);tClip.id.features.referenceFace=edge1;tClip.id.features.incidentEdge=vertex21;tClip.id.features.incidentVertex=vertex21;tClip=c[1];tVec=tClip.v;tVec.SetV(vert2s[vertex22]);tVec.MulM(poly2.m_R);tVec.Add(poly2.m_position);tClip.id.features.referenceFace=edge1;tClip.id.features.incidentEdge=vertex21;tClip.id.features.incidentVertex=vertex22;};b2Collision.b2CollidePolyTempVec=new b2Vec2();b2Collision.b2CollidePoly=function(manifold,polyA,polyB,conservative)
+{manifold.pointCount=0;var edgeA=0;var edgeAOut=[edgeA];var separationA=b2Collision.FindMaxSeparation(edgeAOut,polyA,polyB,conservative);edgeA=edgeAOut[0];if(separationA>0.0&&conservative==false)
+return;var edgeB=0;var edgeBOut=[edgeB];var separationB=b2Collision.FindMaxSeparation(edgeBOut,polyB,polyA,conservative);edgeB=edgeBOut[0];if(separationB>0.0&&conservative==false)
+return;var poly1;var poly2;var edge1=0;var flip=0;var k_relativeTol=0.98;var k_absoluteTol=0.001;if(separationB>k_relativeTol*separationA+k_absoluteTol)
+{poly1=polyB;poly2=polyA;edge1=edgeB;flip=1;}
+else
+{poly1=polyA;poly2=polyB;edge1=edgeA;flip=0;}
+var incidentEdge=[new ClipVertex(),new ClipVertex()];b2Collision.FindIncidentEdge(incidentEdge,poly1,edge1,poly2);var count1=poly1.m_vertexCount;var vert1s=poly1.m_vertices;var v11=vert1s[edge1];var v12=edge1+1<count1?vert1s[edge1+1]:vert1s[0];var dvX=v12.x-v11.x;var dvY=v12.y-v11.y;var sideNormalX=v12.x-v11.x;var sideNormalY=v12.y-v11.y;var tX=sideNormalX;var tMat=poly1.m_R;sideNormalX=tMat.col1.x*tX+tMat.col2.x*sideNormalY;sideNormalY=tMat.col1.y*tX+tMat.col2.y*sideNormalY;var invLength=1.0/Math.sqrt(sideNormalX*sideNormalX+sideNormalY*sideNormalY);sideNormalX*=invLength;sideNormalY*=invLength;var frontNormalX=sideNormalX;var frontNormalY=sideNormalY;tX=frontNormalX;frontNormalX=frontNormalY;frontNormalY=-tX;var v11X=v11.x;var v11Y=v11.y;tX=v11X;tMat=poly1.m_R;v11X=tMat.col1.x*tX+tMat.col2.x*v11Y;v11Y=tMat.col1.y*tX+tMat.col2.y*v11Y;v11X+=poly1.m_position.x;v11Y+=poly1.m_position.y;var v12X=v12.x;var v12Y=v12.y;tX=v12X;tMat=poly1.m_R;v12X=tMat.col1.x*tX+tMat.col2.x*v12Y;v12Y=tMat.col1.y*tX+tMat.col2.y*v12Y;v12X+=poly1.m_position.x;v12Y+=poly1.m_position.y;var frontOffset=frontNormalX*v11X+frontNormalY*v11Y;var sideOffset1=-(sideNormalX*v11X+sideNormalY*v11Y);var sideOffset2=sideNormalX*v12X+sideNormalY*v12Y;var clipPoints1=[new ClipVertex(),new ClipVertex()];var clipPoints2=[new ClipVertex(),new ClipVertex()];var np=0;b2Collision.b2CollidePolyTempVec.Set(-sideNormalX,-sideNormalY);np=b2Collision.ClipSegmentToLine(clipPoints1,incidentEdge,b2Collision.b2CollidePolyTempVec,sideOffset1);if(np<2)
+return;b2Collision.b2CollidePolyTempVec.Set(sideNormalX,sideNormalY);np=b2Collision.ClipSegmentToLine(clipPoints2,clipPoints1,b2Collision.b2CollidePolyTempVec,sideOffset2);if(np<2)
+return;if(flip){manifold.normal.Set(-frontNormalX,-frontNormalY);}
+else{manifold.normal.Set(frontNormalX,frontNormalY);}
+var pointCount=0;for(var i=0;i<b2Settings.b2_maxManifoldPoints;++i)
+{var tVec=clipPoints2[i].v;var separation=(frontNormalX*tVec.x+frontNormalY*tVec.y)-frontOffset;if(separation<=0.0||conservative==true)
+{var cp=manifold.points[pointCount];cp.separation=separation;cp.position.SetV(clipPoints2[i].v);cp.id.Set(clipPoints2[i].id);cp.id.features.flip=flip;++pointCount;}}
+manifold.pointCount=pointCount;};b2Collision.b2CollideCircle=function(manifold,circle1,circle2,conservative)
+{manifold.pointCount=0;var dX=circle2.m_position.x-circle1.m_position.x;var dY=circle2.m_position.y-circle1.m_position.y;var distSqr=dX*dX+dY*dY;var radiusSum=circle1.m_radius+circle2.m_radius;if(distSqr>radiusSum*radiusSum&&conservative==false)
+{return;}
+var separation;if(distSqr<Number.MIN_VALUE)
+{separation=-radiusSum;manifold.normal.Set(0.0,1.0);}
+else
+{var dist=Math.sqrt(distSqr);separation=dist-radiusSum;var a=1.0/dist;manifold.normal.x=a*dX;manifold.normal.y=a*dY;}
+manifold.pointCount=1;var tPoint=manifold.points[0];tPoint.id.set_key(0);tPoint.separation=separation;tPoint.position.x=circle2.m_position.x-(circle2.m_radius*manifold.normal.x);tPoint.position.y=circle2.m_position.y-(circle2.m_radius*manifold.normal.y);};b2Collision.b2CollidePolyAndCircle=function(manifold,poly,circle,conservative)
+{manifold.pointCount=0;var tPoint;var dX;var dY;var xLocalX=circle.m_position.x-poly.m_position.x;var xLocalY=circle.m_position.y-poly.m_position.y;var tMat=poly.m_R;var tX=xLocalX*tMat.col1.x+xLocalY*tMat.col1.y;xLocalY=xLocalX*tMat.col2.x+xLocalY*tMat.col2.y;xLocalX=tX;var dist;var normalIndex=0;var separation=-Number.MAX_VALUE;var radius=circle.m_radius;for(var i=0;i<poly.m_vertexCount;++i)
+{var s=poly.m_normals[i].x*(xLocalX-poly.m_vertices[i].x)+poly.m_normals[i].y*(xLocalY-poly.m_vertices[i].y);if(s>radius)
+{return;}
+if(s>separation)
+{separation=s;normalIndex=i;}}
+if(separation<Number.MIN_VALUE)
+{manifold.pointCount=1;var tVec=poly.m_normals[normalIndex];manifold.normal.x=tMat.col1.x*tVec.x+tMat.col2.x*tVec.y;manifold.normal.y=tMat.col1.y*tVec.x+tMat.col2.y*tVec.y;tPoint=manifold.points[0];tPoint.id.features.incidentEdge=normalIndex;tPoint.id.features.incidentVertex=b2Collision.b2_nullFeature;tPoint.id.features.referenceFace=b2Collision.b2_nullFeature;tPoint.id.features.flip=0;tPoint.position.x=circle.m_position.x-radius*manifold.normal.x;tPoint.position.y=circle.m_position.y-radius*manifold.normal.y;tPoint.separation=separation-radius;return;}
+var vertIndex1=normalIndex;var vertIndex2=vertIndex1+1<poly.m_vertexCount?vertIndex1+1:0;var eX=poly.m_vertices[vertIndex2].x-poly.m_vertices[vertIndex1].x;var eY=poly.m_vertices[vertIndex2].y-poly.m_vertices[vertIndex1].y;var length=Math.sqrt(eX*eX+eY*eY);eX/=length;eY/=length;if(length<Number.MIN_VALUE)
+{dX=xLocalX-poly.m_vertices[vertIndex1].x;dY=xLocalY-poly.m_vertices[vertIndex1].y;dist=Math.sqrt(dX*dX+dY*dY);dX/=dist;dY/=dist;if(dist>radius)
+{return;}
+manifold.pointCount=1;manifold.normal.Set(tMat.col1.x*dX+tMat.col2.x*dY,tMat.col1.y*dX+tMat.col2.y*dY);tPoint=manifold.points[0];tPoint.id.features.incidentEdge=b2Collision.b2_nullFeature;tPoint.id.features.incidentVertex=vertIndex1;tPoint.id.features.referenceFace=b2Collision.b2_nullFeature;tPoint.id.features.flip=0;tPoint.position.x=circle.m_position.x-radius*manifold.normal.x;tPoint.position.y=circle.m_position.y-radius*manifold.normal.y;tPoint.separation=dist-radius;return;}
+var u=(xLocalX-poly.m_vertices[vertIndex1].x)*eX+(xLocalY-poly.m_vertices[vertIndex1].y)*eY;tPoint=manifold.points[0];tPoint.id.features.incidentEdge=b2Collision.b2_nullFeature;tPoint.id.features.incidentVertex=b2Collision.b2_nullFeature;tPoint.id.features.referenceFace=b2Collision.b2_nullFeature;tPoint.id.features.flip=0;var pX,pY;if(u<=0.0)
+{pX=poly.m_vertices[vertIndex1].x;pY=poly.m_vertices[vertIndex1].y;tPoint.id.features.incidentVertex=vertIndex1;}
+else if(u>=length)
+{pX=poly.m_vertices[vertIndex2].x;pY=poly.m_vertices[vertIndex2].y;tPoint.id.features.incidentVertex=vertIndex2;}
+else
+{pX=eX*u+poly.m_vertices[vertIndex1].x;pY=eY*u+poly.m_vertices[vertIndex1].y;tPoint.id.features.incidentEdge=vertIndex1;}
+dX=xLocalX-pX;dY=xLocalY-pY;dist=Math.sqrt(dX*dX+dY*dY);dX/=dist;dY/=dist;if(dist>radius)
+{return;}
+manifold.pointCount=1;manifold.normal.Set(tMat.col1.x*dX+tMat.col2.x*dY,tMat.col1.y*dX+tMat.col2.y*dY);tPoint.position.x=circle.m_position.x-radius*manifold.normal.x;tPoint.position.y=circle.m_position.y-radius*manifold.normal.y;tPoint.separation=dist-radius;};b2Collision.b2TestOverlap=function(a,b)
+{var t1=b.minVertex;var t2=a.maxVertex;var d1X=t1.x-t2.x;var d1Y=t1.y-t2.y;t1=a.minVertex;t2=b.maxVertex;var d2X=t1.x-t2.x;var d2Y=t1.y-t2.y;if(d1X>0.0||d1Y>0.0)
+return false;if(d2X>0.0||d2Y>0.0)
+return false;return true;};
+var Features=Class.create();Features.prototype={set_referenceFace:function(value){this._referenceFace=value;this._m_id._key=(this._m_id._key&0xffffff00)|(this._referenceFace&0x000000ff)},get_referenceFace:function(){return this._referenceFace;},_referenceFace:0,set_incidentEdge:function(value){this._incidentEdge=value;this._m_id._key=(this._m_id._key&0xffff00ff)|((this._incidentEdge<<8)&0x0000ff00)},get_incidentEdge:function(){return this._incidentEdge;},_incidentEdge:0,set_incidentVertex:function(value){this._incidentVertex=value;this._m_id._key=(this._m_id._key&0xff00ffff)|((this._incidentVertex<<16)&0x00ff0000)},get_incidentVertex:function(){return this._incidentVertex;},_incidentVertex:0,set_flip:function(value){this._flip=value;this._m_id._key=(this._m_id._key&0x00ffffff)|((this._flip<<24)&0xff000000)},get_flip:function(){return this._flip;},_flip:0,_m_id:null,initialize:function(){}};
+var b2ContactID=Class.create();b2ContactID.prototype={initialize:function(){this.features=new Features();this.features._m_id=this;},Set:function(id){this.set_key(id._key);},Copy:function(){var id=new b2ContactID();id.set_key(this._key);return id;},get_key:function(){return this._key;},set_key:function(value){this._key=value;this.features._referenceFace=this._key&0x000000ff;this.features._incidentEdge=((this._key&0x0000ff00)>>8)&0x000000ff;this.features._incidentVertex=((this._key&0x00ff0000)>>16)&0x000000ff;this.features._flip=((this._key&0xff000000)>>24)&0x000000ff;},features:new Features(),_key:0};
+var b2ContactPoint=Class.create();b2ContactPoint.prototype={position:new b2Vec2(),separation:null,normalImpulse:null,tangentImpulse:null,id:new b2ContactID(),initialize:function(){this.position=new b2Vec2();this.id=new b2ContactID();}};var b2Distance=Class.create();b2Distance.prototype={initialize:function(){}};b2Distance.ProcessTwo=function(p1Out,p2Out,p1s,p2s,points)
+{var rX=-points[1].x;var rY=-points[1].y;var dX=points[0].x-points[1].x;var dY=points[0].y-points[1].y;var length=Math.sqrt(dX*dX+dY*dY);dX/=length;dY/=length;var lambda=rX*dX+rY*dY;if(lambda<=0.0||length<Number.MIN_VALUE)
+{p1Out.SetV(p1s[1]);p2Out.SetV(p2s[1]);p1s[0].SetV(p1s[1]);p2s[0].SetV(p2s[1]);points[0].SetV(points[1]);return 1;}
+lambda/=length;p1Out.x=p1s[1].x+lambda*(p1s[0].x-p1s[1].x);p1Out.y=p1s[1].y+lambda*(p1s[0].y-p1s[1].y);p2Out.x=p2s[1].x+lambda*(p2s[0].x-p2s[1].x);p2Out.y=p2s[1].y+lambda*(p2s[0].y-p2s[1].y);return 2;};b2Distance.ProcessThree=function(p1Out,p2Out,p1s,p2s,points)
+{var aX=points[0].x;var aY=points[0].y;var bX=points[1].x;var bY=points[1].y;var cX=points[2].x;var cY=points[2].y;var abX=bX-aX;var abY=bY-aY;var acX=cX-aX;var acY=cY-aY;var bcX=cX-bX;var bcY=cY-bY;var sn=-(aX*abX+aY*abY);var sd=(bX*abX+bY*abY);var tn=-(aX*acX+aY*acY);var td=(cX*acX+cY*acY);var un=-(bX*bcX+bY*bcY);var ud=(cX*bcX+cY*bcY);if(td<=0.0&&ud<=0.0)
+{p1Out.SetV(p1s[2]);p2Out.SetV(p2s[2]);p1s[0].SetV(p1s[2]);p2s[0].SetV(p2s[2]);points[0].SetV(points[2]);return 1;}
+var n=abX*acY-abY*acX;var vc=n*(aX*bY-aY*bX);var va=n*(bX*cY-bY*cX);if(va<=0.0&&un>=0.0&&ud>=0.0)
+{var lambda=un/(un+ud);p1Out.x=p1s[1].x+lambda*(p1s[2].x-p1s[1].x);p1Out.y=p1s[1].y+lambda*(p1s[2].y-p1s[1].y);p2Out.x=p2s[1].x+lambda*(p2s[2].x-p2s[1].x);p2Out.y=p2s[1].y+lambda*(p2s[2].y-p2s[1].y);p1s[0].SetV(p1s[2]);p2s[0].SetV(p2s[2]);points[0].SetV(points[2]);return 2;}
+var vb=n*(cX*aY-cY*aX);if(vb<=0.0&&tn>=0.0&&td>=0.0)
+{var lambda=tn/(tn+td);p1Out.x=p1s[0].x+lambda*(p1s[2].x-p1s[0].x);p1Out.y=p1s[0].y+lambda*(p1s[2].y-p1s[0].y);p2Out.x=p2s[0].x+lambda*(p2s[2].x-p2s[0].x);p2Out.y=p2s[0].y+lambda*(p2s[2].y-p2s[0].y);p1s[1].SetV(p1s[2]);p2s[1].SetV(p2s[2]);points[1].SetV(points[2]);return 2;}
+var denom=va+vb+vc;denom=1.0/denom;var u=va*denom;var v=vb*denom;var w=1.0-u-v;p1Out.x=u*p1s[0].x+v*p1s[1].x+w*p1s[2].x;p1Out.y=u*p1s[0].y+v*p1s[1].y+w*p1s[2].y;p2Out.x=u*p2s[0].x+v*p2s[1].x+w*p2s[2].x;p2Out.y=u*p2s[0].y+v*p2s[1].y+w*p2s[2].y;return 3;};b2Distance.InPoinsts=function(w,points,pointCount)
+{for(var i=0;i<pointCount;++i)
+{if(w.x==points[i].x&&w.y==points[i].y)
+{return true;}}
+return false;};b2Distance.Distance=function(p1Out,p2Out,shape1,shape2)
+{var p1s=new Array(3);var p2s=new Array(3);var points=new Array(3);var pointCount=0;p1Out.SetV(shape1.m_position);p2Out.SetV(shape2.m_position);var vSqr=0.0;var maxIterations=20;for(var iter=0;iter<maxIterations;++iter)
+{var vX=p2Out.x-p1Out.x;var vY=p2Out.y-p1Out.y;var w1=shape1.Support(vX,vY);var w2=shape2.Support(-vX,-vY);vSqr=(vX*vX+vY*vY);var wX=w2.x-w1.x;var wY=w2.y-w1.y;var vw=(vX*wX+vY*wY);if(vSqr-b2Dot(vX*wX+vY*wY)<=0.01*vSqr)
+{if(pointCount==0)
+{p1Out.SetV(w1);p2Out.SetV(w2);}
+b2Distance.g_GJK_Iterations=iter;return Math.sqrt(vSqr);}
+switch(pointCount)
+{case 0:p1s[0].SetV(w1);p2s[0].SetV(w2);points[0]=w;p1Out.SetV(p1s[0]);p2Out.SetV(p2s[0]);++pointCount;break;case 1:p1s[1].SetV(w1);p2s[1].SetV(w2);points[1].x=wX;points[1].y=wY;pointCount=b2Distance.ProcessTwo(p1Out,p2Out,p1s,p2s,points);break;case 2:p1s[2].SetV(w1);p2s[2].SetV(w2);points[2].x=wX;points[2].y=wY;pointCount=b2Distance.ProcessThree(p1Out,p2Out,p1s,p2s,points);break;}
+if(pointCount==3)
+{b2Distance.g_GJK_Iterations=iter;return 0.0;}
+var maxSqr=-Number.MAX_VALUE;for(var i=0;i<pointCount;++i)
+{maxSqr=b2Math.b2Max(maxSqr,(points[i].x*points[i].x+points[i].y*points[i].y));}
+if(pointCount==3||vSqr<=100.0*Number.MIN_VALUE*maxSqr)
+{b2Distance.g_GJK_Iterations=iter;return Math.sqrt(vSqr);}}
+b2Distance.g_GJK_Iterations=maxIterations;return Math.sqrt(vSqr);};b2Distance.g_GJK_Iterations=0;
+var b2Manifold=Class.create();b2Manifold.prototype={initialize:function(){this.points=new Array(b2Settings.b2_maxManifoldPoints);for(var i=0;i<b2Settings.b2_maxManifoldPoints;i++){this.points[i]=new b2ContactPoint();}
+this.normal=new b2Vec2();},points:null,normal:null,pointCount:0};
+var b2OBB=Class.create();b2OBB.prototype={R:new b2Mat22(),center:new b2Vec2(),extents:new b2Vec2(),initialize:function(){this.R=new b2Mat22();this.center=new b2Vec2();this.extents=new b2Vec2();}};
+var b2Proxy=Class.create();b2Proxy.prototype={GetNext:function(){return this.lowerBounds[0];},SetNext:function(next){this.lowerBounds[0]=next;},IsValid:function(){return this.overlapCount!=b2BroadPhase.b2_invalid;},lowerBounds:[(0),(0)],upperBounds:[(0),(0)],overlapCount:0,timeStamp:0,userData:null,initialize:function(){this.lowerBounds=[(0),(0)];this.upperBounds=[(0),(0)];}}
+
+var ClipVertex=Class.create();ClipVertex.prototype={v:new b2Vec2(),id:new b2ContactID(),initialize:function(){this.v=new b2Vec2();this.id=new b2ContactID();}};var b2Shape=Class.create();b2Shape.prototype={TestPoint:function(p){return false},GetUserData:function(){return this.m_userData;},GetType:function(){return this.m_type;},GetBody:function(){return this.m_body;},GetPosition:function(){return this.m_position;},GetRotationMatrix:function(){return this.m_R;},ResetProxy:function(broadPhase){},GetNext:function(){return this.m_next;},initialize:function(def,body){this.m_R=new b2Mat22();this.m_position=new b2Vec2();this.m_userData=def.userData;this.m_friction=def.friction;this.m_restitution=def.restitution;this.m_body=body;this.m_proxyId=b2Pair.b2_nullProxy;this.m_maxRadius=0.0;this.m_categoryBits=def.categoryBits;this.m_maskBits=def.maskBits;this.m_groupIndex=def.groupIndex;},DestroyProxy:function()
+{if(this.m_proxyId!=b2Pair.b2_nullProxy)
+{this.m_body.m_world.m_broadPhase.DestroyProxy(this.m_proxyId);this.m_proxyId=b2Pair.b2_nullProxy;}},Synchronize:function(position1,R1,position2,R2){},QuickSync:function(position,R){},Support:function(dX,dY,out){},GetMaxRadius:function(){return this.m_maxRadius;},m_next:null,m_R:new b2Mat22(),m_position:new b2Vec2(),m_type:0,m_userData:null,m_body:null,m_friction:null,m_restitution:null,m_maxRadius:null,m_proxyId:0,m_categoryBits:0,m_maskBits:0,m_groupIndex:0};b2Shape.Create=function(def,body,center){switch(def.type)
+{case b2Shape.e_circleShape:{return new b2CircleShape(def,body,center);}
+case b2Shape.e_boxShape:case b2Shape.e_polyShape:{return new b2PolyShape(def,body,center);}}
+return null;};b2Shape.Destroy=function(shape)
+{if(shape.m_proxyId!=b2Pair.b2_nullProxy)
+shape.m_body.m_world.m_broadPhase.DestroyProxy(shape.m_proxyId);};b2Shape.e_unknownShape=-1;b2Shape.e_circleShape=0;b2Shape.e_boxShape=1;b2Shape.e_polyShape=2;b2Shape.e_meshShape=3;b2Shape.e_shapeTypeCount=4;b2Shape.PolyMass=function(massData,vs,count,rho)
+{var center=new b2Vec2();center.SetZero();var area=0.0;var I=0.0;var pRef=new b2Vec2(0.0,0.0);var inv3=1.0/3.0;for(var i=0;i<count;++i)
+{var p1=pRef;var p2=vs[i];var p3=i+1<count?vs[i+1]:vs[0];var e1=b2Math.SubtractVV(p2,p1);var e2=b2Math.SubtractVV(p3,p1);var D=b2Math.b2CrossVV(e1,e2);var triangleArea=0.5*D;area+=triangleArea;var tVec=new b2Vec2();tVec.SetV(p1);tVec.Add(p2);tVec.Add(p3);tVec.Multiply(inv3*triangleArea);center.Add(tVec);var px=p1.x;var py=p1.y;var ex1=e1.x;var ey1=e1.y;var ex2=e2.x;var ey2=e2.y;var intx2=inv3*(0.25*(ex1*ex1+ex2*ex1+ex2*ex2)+(px*ex1+px*ex2))+0.5*px*px;var inty2=inv3*(0.25*(ey1*ey1+ey2*ey1+ey2*ey2)+(py*ey1+py*ey2))+0.5*py*py;I+=D*(intx2+inty2);}
+massData.mass=rho*area;center.Multiply(1.0/area);massData.center=center;I=rho*(I-area*b2Math.b2Dot(center,center));massData.I=I;};b2Shape.PolyCentroid=function(vs,count,out)
+{var cX=0.0;var cY=0.0;var area=0.0;var pRefX=0.0;var pRefY=0.0;var inv3=1.0/3.0;for(var i=0;i<count;++i)
+{var p1X=pRefX;var p1Y=pRefY;var p2X=vs[i].x;var p2Y=vs[i].y;var p3X=i+1<count?vs[i+1].x:vs[0].x;var p3Y=i+1<count?vs[i+1].y:vs[0].y;var e1X=p2X-p1X;var e1Y=p2Y-p1Y;var e2X=p3X-p1X;var e2Y=p3Y-p1Y;var D=(e1X*e2Y-e1Y*e2X);var triangleArea=0.5*D;area+=triangleArea;cX+=triangleArea*inv3*(p1X+p2X+p3X);cY+=triangleArea*inv3*(p1Y+p2Y+p3Y);}
+cX*=1.0/area;cY*=1.0/area;out.Set(cX,cY);};
+var b2ShapeDef=Class.create();b2ShapeDef.prototype={initialize:function()
+{this.type=b2Shape.e_unknownShape;this.userData=null;this.localPosition=new b2Vec2(0.0,0.0);this.localRotation=0.0;this.friction=0.2;this.restitution=0.0;this.density=0.0;this.categoryBits=0x0001;this.maskBits=0xFFFF;this.groupIndex=0;},ComputeMass:function(massData)
+{massData.center=new b2Vec2(0.0,0.0)
+if(this.density==0.0)
+{massData.mass=0.0;massData.center.Set(0.0,0.0);massData.I=0.0;};switch(this.type)
+{case b2Shape.e_circleShape:{var circle=this;massData.mass=this.density*b2Settings.b2_pi*circle.radius*circle.radius;massData.center.Set(0.0,0.0);massData.I=0.5*(massData.mass)*circle.radius*circle.radius;}
+break;case b2Shape.e_boxShape:{var box=this;massData.mass=4.0*this.density*box.extents.x*box.extents.y;massData.center.Set(0.0,0.0);massData.I=massData.mass/3.0*b2Math.b2Dot(box.extents,box.extents);}
+break;case b2Shape.e_polyShape:{var poly=this;b2Shape.PolyMass(massData,poly.vertices,poly.vertexCount,this.density);}
+break;default:massData.mass=0.0;massData.center.Set(0.0,0.0);massData.I=0.0;break;}},type:0,userData:null,localPosition:null,localRotation:null,friction:null,restitution:null,density:null,categoryBits:0,maskBits:0,groupIndex:0};
+var b2BoxDef=Class.create();Object.extend(b2BoxDef.prototype,b2ShapeDef.prototype);Object.extend(b2BoxDef.prototype,{initialize:function()
+{this.type=b2Shape.e_unknownShape;this.userData=null;this.localPosition=new b2Vec2(0.0,0.0);this.localRotation=0.0;this.friction=0.2;this.restitution=0.0;this.density=0.0;this.categoryBits=0x0001;this.maskBits=0xFFFF;this.groupIndex=0;this.type=b2Shape.e_boxShape;this.extents=new b2Vec2(1.0,1.0);},extents:null});
+var b2CircleDef=Class.create();Object.extend(b2CircleDef.prototype,b2ShapeDef.prototype);Object.extend(b2CircleDef.prototype,{initialize:function()
+{this.type=b2Shape.e_unknownShape;this.userData=null;this.localPosition=new b2Vec2(0.0,0.0);this.localRotation=0.0;this.friction=0.2;this.restitution=0.0;this.density=0.0;this.categoryBits=0x0001;this.maskBits=0xFFFF;this.groupIndex=0;this.type=b2Shape.e_circleShape;this.radius=1.0;},radius:null});var b2CircleShape=Class.create();Object.extend(b2CircleShape.prototype,b2Shape.prototype);Object.extend(b2CircleShape.prototype,{TestPoint:function(p){var d=new b2Vec2();d.SetV(p);d.Subtract(this.m_position);return b2Math.b2Dot(d,d)<=this.m_radius*this.m_radius;},initialize:function(def,body,localCenter){this.m_R=new b2Mat22();this.m_position=new b2Vec2();this.m_userData=def.userData;this.m_friction=def.friction;this.m_restitution=def.restitution;this.m_body=body;this.m_proxyId=b2Pair.b2_nullProxy;this.m_maxRadius=0.0;this.m_categoryBits=def.categoryBits;this.m_maskBits=def.maskBits;this.m_groupIndex=def.groupIndex;this.m_localPosition=new b2Vec2();var circle=def;this.m_localPosition.Set(def.localPosition.x-localCenter.x,def.localPosition.y-localCenter.y);this.m_type=b2Shape.e_circleShape;this.m_radius=circle.radius;this.m_R.SetM(this.m_body.m_R);var rX=this.m_R.col1.x*this.m_localPosition.x+this.m_R.col2.x*this.m_localPosition.y;var rY=this.m_R.col1.y*this.m_localPosition.x+this.m_R.col2.y*this.m_localPosition.y;this.m_position.x=this.m_body.m_position.x+rX;this.m_position.y=this.m_body.m_position.y+rY;this.m_maxRadius=Math.sqrt(rX*rX+rY*rY)+this.m_radius;var aabb=new b2AABB();aabb.minVertex.Set(this.m_position.x-this.m_radius,this.m_position.y-this.m_radius);aabb.maxVertex.Set(this.m_position.x+this.m_radius,this.m_position.y+this.m_radius);var broadPhase=this.m_body.m_world.m_broadPhase;if(broadPhase.InRange(aabb))
+{this.m_proxyId=broadPhase.CreateProxy(aabb,this);}
+else
+{this.m_proxyId=b2Pair.b2_nullProxy;}
+if(this.m_proxyId==b2Pair.b2_nullProxy)
+{this.m_body.Freeze();}},Synchronize:function(position1,R1,position2,R2){this.m_R.SetM(R2);this.m_position.x=(R2.col1.x*this.m_localPosition.x+R2.col2.x*this.m_localPosition.y)+position2.x;this.m_position.y=(R2.col1.y*this.m_localPosition.x+R2.col2.y*this.m_localPosition.y)+position2.y;if(this.m_proxyId==b2Pair.b2_nullProxy)
+{return;}
+var p1X=position1.x+(R1.col1.x*this.m_localPosition.x+R1.col2.x*this.m_localPosition.y);var p1Y=position1.y+(R1.col1.y*this.m_localPosition.x+R1.col2.y*this.m_localPosition.y);var lowerX=Math.min(p1X,this.m_position.x);var lowerY=Math.min(p1Y,this.m_position.y);var upperX=Math.max(p1X,this.m_position.x);var upperY=Math.max(p1Y,this.m_position.y);var aabb=new b2AABB();aabb.minVertex.Set(lowerX-this.m_radius,lowerY-this.m_radius);aabb.maxVertex.Set(upperX+this.m_radius,upperY+this.m_radius);var broadPhase=this.m_body.m_world.m_broadPhase;if(broadPhase.InRange(aabb))
+{broadPhase.MoveProxy(this.m_proxyId,aabb);}
+else
+{this.m_body.Freeze();}},QuickSync:function(position,R){this.m_R.SetM(R);this.m_position.x=(R.col1.x*this.m_localPosition.x+R.col2.x*this.m_localPosition.y)+position.x;this.m_position.y=(R.col1.y*this.m_localPosition.x+R.col2.y*this.m_localPosition.y)+position.y;},ResetProxy:function(broadPhase)
+{if(this.m_proxyId==b2Pair.b2_nullProxy)
+{return;}
+var proxy=broadPhase.GetProxy(this.m_proxyId);broadPhase.DestroyProxy(this.m_proxyId);proxy=null;var aabb=new b2AABB();aabb.minVertex.Set(this.m_position.x-this.m_radius,this.m_position.y-this.m_radius);aabb.maxVertex.Set(this.m_position.x+this.m_radius,this.m_position.y+this.m_radius);if(broadPhase.InRange(aabb))
+{this.m_proxyId=broadPhase.CreateProxy(aabb,this);}
+else
+{this.m_proxyId=b2Pair.b2_nullProxy;}
+if(this.m_proxyId==b2Pair.b2_nullProxy)
+{this.m_body.Freeze();}},Support:function(dX,dY,out)
+{var len=Math.sqrt(dX*dX+dY*dY);dX/=len;dY/=len;out.Set(this.m_position.x+this.m_radius*dX,this.m_position.y+this.m_radius*dY);},m_localPosition:new b2Vec2(),m_radius:null});
+var b2MassData=Class.create();b2MassData.prototype={mass:0.0,center:new b2Vec2(0,0),I:0.0,initialize:function(){this.center=new b2Vec2(0,0);}}
+
+var b2PolyDef=Class.create();Object.extend(b2PolyDef.prototype,b2ShapeDef.prototype);Object.extend(b2PolyDef.prototype,{initialize:function()
+{this.type=b2Shape.e_unknownShape;this.userData=null;this.localPosition=new b2Vec2(0.0,0.0);this.localRotation=0.0;this.friction=0.2;this.restitution=0.0;this.density=0.0;this.categoryBits=0x0001;this.maskBits=0xFFFF;this.groupIndex=0;this.vertices=new Array(b2Settings.b2_maxPolyVertices);this.type=b2Shape.e_polyShape;this.vertexCount=0;for(var i=0;i<b2Settings.b2_maxPolyVertices;i++){this.vertices[i]=new b2Vec2();}},vertices:new Array(b2Settings.b2_maxPolyVertices),vertexCount:0});var b2PolyShape=Class.create();Object.extend(b2PolyShape.prototype,b2Shape.prototype);Object.extend(b2PolyShape.prototype,{TestPoint:function(p){var pLocal=new b2Vec2();pLocal.SetV(p);pLocal.Subtract(this.m_position);pLocal.MulTM(this.m_R);for(var i=0;i<this.m_vertexCount;++i)
+{var tVec=new b2Vec2();tVec.SetV(pLocal);tVec.Subtract(this.m_vertices[i]);var dot=b2Math.b2Dot(this.m_normals[i],tVec);if(dot>0.0)
+{return false;}}
+return true;},initialize:function(def,body,newOrigin){this.m_R=new b2Mat22();this.m_position=new b2Vec2();this.m_userData=def.userData;this.m_friction=def.friction;this.m_restitution=def.restitution;this.m_body=body;this.m_proxyId=b2Pair.b2_nullProxy;this.m_maxRadius=0.0;this.m_categoryBits=def.categoryBits;this.m_maskBits=def.maskBits;this.m_groupIndex=def.groupIndex;this.syncAABB=new b2AABB();this.syncMat=new b2Mat22();this.m_localCentroid=new b2Vec2();this.m_localOBB=new b2OBB();var i=0;var hX;var hY;var tVec;var aabb=new b2AABB();this.m_vertices=new Array(b2Settings.b2_maxPolyVertices);this.m_coreVertices=new Array(b2Settings.b2_maxPolyVertices);this.m_normals=new Array(b2Settings.b2_maxPolyVertices);this.m_type=b2Shape.e_polyShape;var localR=new b2Mat22(def.localRotation);if(def.type==b2Shape.e_boxShape)
+{this.m_localCentroid.x=def.localPosition.x-newOrigin.x;this.m_localCentroid.y=def.localPosition.y-newOrigin.y;var box=def;this.m_vertexCount=4;hX=box.extents.x;hY=box.extents.y;var hcX=Math.max(0.0,hX-2.0*b2Settings.b2_linearSlop);var hcY=Math.max(0.0,hY-2.0*b2Settings.b2_linearSlop);tVec=this.m_vertices[0]=new b2Vec2();tVec.x=localR.col1.x*hX+localR.col2.x*hY;tVec.y=localR.col1.y*hX+localR.col2.y*hY;tVec=this.m_vertices[1]=new b2Vec2();tVec.x=localR.col1.x*-hX+localR.col2.x*hY;tVec.y=localR.col1.y*-hX+localR.col2.y*hY;tVec=this.m_vertices[2]=new b2Vec2();tVec.x=localR.col1.x*-hX+localR.col2.x*-hY;tVec.y=localR.col1.y*-hX+localR.col2.y*-hY;tVec=this.m_vertices[3]=new b2Vec2();tVec.x=localR.col1.x*hX+localR.col2.x*-hY;tVec.y=localR.col1.y*hX+localR.col2.y*-hY;tVec=this.m_coreVertices[0]=new b2Vec2();tVec.x=localR.col1.x*hcX+localR.col2.x*hcY;tVec.y=localR.col1.y*hcX+localR.col2.y*hcY;tVec=this.m_coreVertices[1]=new b2Vec2();tVec.x=localR.col1.x*-hcX+localR.col2.x*hcY;tVec.y=localR.col1.y*-hcX+localR.col2.y*hcY;tVec=this.m_coreVertices[2]=new b2Vec2();tVec.x=localR.col1.x*-hcX+localR.col2.x*-hcY;tVec.y=localR.col1.y*-hcX+localR.col2.y*-hcY;tVec=this.m_coreVertices[3]=new b2Vec2();tVec.x=localR.col1.x*hcX+localR.col2.x*-hcY;tVec.y=localR.col1.y*hcX+localR.col2.y*-hcY;}
+else
+{var poly=def;this.m_vertexCount=poly.vertexCount;b2Shape.PolyCentroid(poly.vertices,poly.vertexCount,b2PolyShape.tempVec);var centroidX=b2PolyShape.tempVec.x;var centroidY=b2PolyShape.tempVec.y;this.m_localCentroid.x=def.localPosition.x+(localR.col1.x*centroidX+localR.col2.x*centroidY)-newOrigin.x;this.m_localCentroid.y=def.localPosition.y+(localR.col1.y*centroidX+localR.col2.y*centroidY)-newOrigin.y;for(i=0;i<this.m_vertexCount;++i)
+{this.m_vertices[i]=new b2Vec2();this.m_coreVertices[i]=new b2Vec2();hX=poly.vertices[i].x-centroidX;hY=poly.vertices[i].y-centroidY;this.m_vertices[i].x=localR.col1.x*hX+localR.col2.x*hY;this.m_vertices[i].y=localR.col1.y*hX+localR.col2.y*hY;var uX=this.m_vertices[i].x;var uY=this.m_vertices[i].y;var length=Math.sqrt(uX*uX+uY*uY);if(length>Number.MIN_VALUE)
+{uX*=1.0/length;uY*=1.0/length;}
+this.m_coreVertices[i].x=this.m_vertices[i].x-2.0*b2Settings.b2_linearSlop*uX;this.m_coreVertices[i].y=this.m_vertices[i].y-2.0*b2Settings.b2_linearSlop*uY;}}
+var minVertexX=Number.MAX_VALUE;var minVertexY=Number.MAX_VALUE;var maxVertexX=-Number.MAX_VALUE;var maxVertexY=-Number.MAX_VALUE;this.m_maxRadius=0.0;for(i=0;i<this.m_vertexCount;++i)
+{var v=this.m_vertices[i];minVertexX=Math.min(minVertexX,v.x);minVertexY=Math.min(minVertexY,v.y);maxVertexX=Math.max(maxVertexX,v.x);maxVertexY=Math.max(maxVertexY,v.y);this.m_maxRadius=Math.max(this.m_maxRadius,v.Length());}
+this.m_localOBB.R.SetIdentity();this.m_localOBB.center.Set((minVertexX+maxVertexX)*0.5,(minVertexY+maxVertexY)*0.5);this.m_localOBB.extents.Set((maxVertexX-minVertexX)*0.5,(maxVertexY-minVertexY)*0.5);var i1=0;var i2=0;for(i=0;i<this.m_vertexCount;++i)
+{this.m_normals[i]=new b2Vec2();i1=i;i2=i+1<this.m_vertexCount?i+1:0;this.m_normals[i].x=this.m_vertices[i2].y-this.m_vertices[i1].y;this.m_normals[i].y=-(this.m_vertices[i2].x-this.m_vertices[i1].x);this.m_normals[i].Normalize();}
+for(i=0;i<this.m_vertexCount;++i)
+{i1=i;i2=i+1<this.m_vertexCount?i+1:0;}
+this.m_R.SetM(this.m_body.m_R);this.m_position.x=this.m_body.m_position.x+(this.m_R.col1.x*this.m_localCentroid.x+this.m_R.col2.x*this.m_localCentroid.y);this.m_position.y=this.m_body.m_position.y+(this.m_R.col1.y*this.m_localCentroid.x+this.m_R.col2.y*this.m_localCentroid.y);b2PolyShape.tAbsR.col1.x=this.m_R.col1.x*this.m_localOBB.R.col1.x+this.m_R.col2.x*this.m_localOBB.R.col1.y;b2PolyShape.tAbsR.col1.y=this.m_R.col1.y*this.m_localOBB.R.col1.x+this.m_R.col2.y*this.m_localOBB.R.col1.y;b2PolyShape.tAbsR.col2.x=this.m_R.col1.x*this.m_localOBB.R.col2.x+this.m_R.col2.x*this.m_localOBB.R.col2.y;b2PolyShape.tAbsR.col2.y=this.m_R.col1.y*this.m_localOBB.R.col2.x+this.m_R.col2.y*this.m_localOBB.R.col2.y;b2PolyShape.tAbsR.Abs()
+hX=b2PolyShape.tAbsR.col1.x*this.m_localOBB.extents.x+b2PolyShape.tAbsR.col2.x*this.m_localOBB.extents.y;hY=b2PolyShape.tAbsR.col1.y*this.m_localOBB.extents.x+b2PolyShape.tAbsR.col2.y*this.m_localOBB.extents.y;var positionX=this.m_position.x+(this.m_R.col1.x*this.m_localOBB.center.x+this.m_R.col2.x*this.m_localOBB.center.y);var positionY=this.m_position.y+(this.m_R.col1.y*this.m_localOBB.center.x+this.m_R.col2.y*this.m_localOBB.center.y);aabb.minVertex.x=positionX-hX;aabb.minVertex.y=positionY-hY;aabb.maxVertex.x=positionX+hX;aabb.maxVertex.y=positionY+hY;var broadPhase=this.m_body.m_world.m_broadPhase;if(broadPhase.InRange(aabb))
+{this.m_proxyId=broadPhase.CreateProxy(aabb,this);}
+else
+{this.m_proxyId=b2Pair.b2_nullProxy;}
+if(this.m_proxyId==b2Pair.b2_nullProxy)
+{this.m_body.Freeze();}},syncAABB:new b2AABB(),syncMat:new b2Mat22(),Synchronize:function(position1,R1,position2,R2){this.m_R.SetM(R2);this.m_position.x=this.m_body.m_position.x+(R2.col1.x*this.m_localCentroid.x+R2.col2.x*this.m_localCentroid.y);this.m_position.y=this.m_body.m_position.y+(R2.col1.y*this.m_localCentroid.x+R2.col2.y*this.m_localCentroid.y);if(this.m_proxyId==b2Pair.b2_nullProxy)
+{return;}
+var hX;var hY;var v1=R1.col1;var v2=R1.col2;var v3=this.m_localOBB.R.col1;var v4=this.m_localOBB.R.col2;this.syncMat.col1.x=v1.x*v3.x+v2.x*v3.y;this.syncMat.col1.y=v1.y*v3.x+v2.y*v3.y;this.syncMat.col2.x=v1.x*v4.x+v2.x*v4.y;this.syncMat.col2.y=v1.y*v4.x+v2.y*v4.y;this.syncMat.Abs();hX=this.m_localCentroid.x+this.m_localOBB.center.x;hY=this.m_localCentroid.y+this.m_localOBB.center.y;var centerX=position1.x+(R1.col1.x*hX+R1.col2.x*hY);var centerY=position1.y+(R1.col1.y*hX+R1.col2.y*hY);hX=this.syncMat.col1.x*this.m_localOBB.extents.x+this.syncMat.col2.x*this.m_localOBB.extents.y;hY=this.syncMat.col1.y*this.m_localOBB.extents.x+this.syncMat.col2.y*this.m_localOBB.extents.y;this.syncAABB.minVertex.x=centerX-hX;this.syncAABB.minVertex.y=centerY-hY;this.syncAABB.maxVertex.x=centerX+hX;this.syncAABB.maxVertex.y=centerY+hY;v1=R2.col1;v2=R2.col2;v3=this.m_localOBB.R.col1;v4=this.m_localOBB.R.col2;this.syncMat.col1.x=v1.x*v3.x+v2.x*v3.y;this.syncMat.col1.y=v1.y*v3.x+v2.y*v3.y;this.syncMat.col2.x=v1.x*v4.x+v2.x*v4.y;this.syncMat.col2.y=v1.y*v4.x+v2.y*v4.y;this.syncMat.Abs();hX=this.m_localCentroid.x+this.m_localOBB.center.x;hY=this.m_localCentroid.y+this.m_localOBB.center.y;centerX=position2.x+(R2.col1.x*hX+R2.col2.x*hY);centerY=position2.y+(R2.col1.y*hX+R2.col2.y*hY);hX=this.syncMat.col1.x*this.m_localOBB.extents.x+this.syncMat.col2.x*this.m_localOBB.extents.y;hY=this.syncMat.col1.y*this.m_localOBB.extents.x+this.syncMat.col2.y*this.m_localOBB.extents.y;this.syncAABB.minVertex.x=Math.min(this.syncAABB.minVertex.x,centerX-hX);this.syncAABB.minVertex.y=Math.min(this.syncAABB.minVertex.y,centerY-hY);this.syncAABB.maxVertex.x=Math.max(this.syncAABB.maxVertex.x,centerX+hX);this.syncAABB.maxVertex.y=Math.max(this.syncAABB.maxVertex.y,centerY+hY);var broadPhase=this.m_body.m_world.m_broadPhase;if(broadPhase.InRange(this.syncAABB))
+{broadPhase.MoveProxy(this.m_proxyId,this.syncAABB);}
+else
+{this.m_body.Freeze();}},QuickSync:function(position,R){this.m_R.SetM(R);this.m_position.x=position.x+(R.col1.x*this.m_localCentroid.x+R.col2.x*this.m_localCentroid.y);this.m_position.y=position.y+(R.col1.y*this.m_localCentroid.x+R.col2.y*this.m_localCentroid.y);},ResetProxy:function(broadPhase){if(this.m_proxyId==b2Pair.b2_nullProxy)
+{return;}
+var proxy=broadPhase.GetProxy(this.m_proxyId);broadPhase.DestroyProxy(this.m_proxyId);proxy=null;var R=b2Math.b2MulMM(this.m_R,this.m_localOBB.R);var absR=b2Math.b2AbsM(R);var h=b2Math.b2MulMV(absR,this.m_localOBB.extents);var position=b2Math.b2MulMV(this.m_R,this.m_localOBB.center);position.Add(this.m_position);var aabb=new b2AABB();aabb.minVertex.SetV(position);aabb.minVertex.Subtract(h);aabb.maxVertex.SetV(position);aabb.maxVertex.Add(h);if(broadPhase.InRange(aabb))
+{this.m_proxyId=broadPhase.CreateProxy(aabb,this);}
+else
+{this.m_proxyId=b2Pair.b2_nullProxy;}
+if(this.m_proxyId==b2Pair.b2_nullProxy)
+{this.m_body.Freeze();}},Support:function(dX,dY,out)
+{var dLocalX=(dX*this.m_R.col1.x+dY*this.m_R.col1.y);var dLocalY=(dX*this.m_R.col2.x+dY*this.m_R.col2.y);var bestIndex=0;var bestValue=(this.m_coreVertices[0].x*dLocalX+this.m_coreVertices[0].y*dLocalY);for(var i=1;i<this.m_vertexCount;++i)
+{var value=(this.m_coreVertices[i].x*dLocalX+this.m_coreVertices[i].y*dLocalY);if(value>bestValue)
+{bestIndex=i;bestValue=value;}}
+out.Set(this.m_position.x+(this.m_R.col1.x*this.m_coreVertices[bestIndex].x+this.m_R.col2.x*this.m_coreVertices[bestIndex].y),this.m_position.y+(this.m_R.col1.y*this.m_coreVertices[bestIndex].x+this.m_R.col2.y*this.m_coreVertices[bestIndex].y));},m_localCentroid:new b2Vec2(),m_localOBB:new b2OBB(),m_vertices:null,m_coreVertices:null,m_vertexCount:0,m_normals:null});b2PolyShape.tempVec=new b2Vec2();b2PolyShape.tAbsR=new b2Mat22();
+var b2Body=Class.create();b2Body.prototype={SetOriginPosition:function(position,rotation){if(this.IsFrozen())
+{return;}
+this.m_rotation=rotation;this.m_R.Set(this.m_rotation);this.m_position=b2Math.AddVV(position,b2Math.b2MulMV(this.m_R,this.m_center));this.m_position0.SetV(this.m_position);this.m_rotation0=this.m_rotation;for(var s=this.m_shapeList;s!=null;s=s.m_next)
+{s.Synchronize(this.m_position,this.m_R,this.m_position,this.m_R);}
+this.m_world.m_broadPhase.Commit();},GetOriginPosition:function(){return b2Math.SubtractVV(this.m_position,b2Math.b2MulMV(this.m_R,this.m_center));},SetCenterPosition:function(position,rotation){if(this.IsFrozen())
+{return;}
+this.m_rotation=rotation;this.m_R.Set(this.m_rotation);this.m_position.SetV(position);this.m_position0.SetV(this.m_position);this.m_rotation0=this.m_rotation;for(var s=this.m_shapeList;s!=null;s=s.m_next)
+{s.Synchronize(this.m_position,this.m_R,this.m_position,this.m_R);}
+this.m_world.m_broadPhase.Commit();},GetCenterPosition:function(){return this.m_position;},GetRotation:function(){return this.m_rotation;},GetRotationMatrix:function(){return this.m_R;},SetLinearVelocity:function(v){this.m_linearVelocity.SetV(v);},GetLinearVelocity:function(){return this.m_linearVelocity;},SetAngularVelocity:function(w){this.m_angularVelocity=w;},GetAngularVelocity:function(){return this.m_angularVelocity;},ApplyForce:function(force,point)
+{if(this.IsSleeping()==false)
+{this.m_force.Add(force);this.m_torque+=b2Math.b2CrossVV(b2Math.SubtractVV(point,this.m_position),force);}},ApplyTorque:function(torque)
+{if(this.IsSleeping()==false)
+{this.m_torque+=torque;}},ApplyImpulse:function(impulse,point)
+{if(this.IsSleeping()==false)
+{this.m_linearVelocity.Add(b2Math.MulFV(this.m_invMass,impulse));this.m_angularVelocity+=(this.m_invI*b2Math.b2CrossVV(b2Math.SubtractVV(point,this.m_position),impulse));}},GetMass:function(){return this.m_mass;},GetInertia:function(){return this.m_I;},GetWorldPoint:function(localPoint){return b2Math.AddVV(this.m_position,b2Math.b2MulMV(this.m_R,localPoint));},GetWorldVector:function(localVector){return b2Math.b2MulMV(this.m_R,localVector);},GetLocalPoint:function(worldPoint){return b2Math.b2MulTMV(this.m_R,b2Math.SubtractVV(worldPoint,this.m_position));},GetLocalVector:function(worldVector){return b2Math.b2MulTMV(this.m_R,worldVector);},IsStatic:function(){return(this.m_flags&b2Body.e_staticFlag)==b2Body.e_staticFlag;},IsFrozen:function()
+{return(this.m_flags&b2Body.e_frozenFlag)==b2Body.e_frozenFlag;},IsSleeping:function(){return(this.m_flags&b2Body.e_sleepFlag)==b2Body.e_sleepFlag;},AllowSleeping:function(flag)
+{if(flag)
+{this.m_flags|=b2Body.e_allowSleepFlag;}
+else
+{this.m_flags&=~b2Body.e_allowSleepFlag;this.WakeUp();}},WakeUp:function(){this.m_flags&=~b2Body.e_sleepFlag;this.m_sleepTime=0.0;},GetShapeList:function(){return this.m_shapeList;},GetContactList:function()
+{return this.m_contactList;},GetJointList:function()
+{return this.m_jointList;},GetNext:function(){return this.m_next;},GetUserData:function(){return this.m_userData;},initialize:function(bd,world){this.sMat0=new b2Mat22();this.m_position=new b2Vec2();this.m_R=new b2Mat22(0);this.m_position0=new b2Vec2();var i=0;var sd;var massData;this.m_flags=0;this.m_position.SetV(bd.position);this.m_rotation=bd.rotation;this.m_R.Set(this.m_rotation);this.m_position0.SetV(this.m_position);this.m_rotation0=this.m_rotation;this.m_world=world;this.m_linearDamping=b2Math.b2Clamp(1.0-bd.linearDamping,0.0,1.0);this.m_angularDamping=b2Math.b2Clamp(1.0-bd.angularDamping,0.0,1.0);this.m_force=new b2Vec2(0.0,0.0);this.m_torque=0.0;this.m_mass=0.0;var massDatas=new Array(b2Settings.b2_maxShapesPerBody);for(i=0;i<b2Settings.b2_maxShapesPerBody;i++){massDatas[i]=new b2MassData();}
+this.m_shapeCount=0;this.m_center=new b2Vec2(0.0,0.0);for(i=0;i<b2Settings.b2_maxShapesPerBody;++i)
+{sd=bd.shapes[i];if(sd==null)break;massData=massDatas[i];sd.ComputeMass(massData);this.m_mass+=massData.mass;this.m_center.x+=massData.mass*(sd.localPosition.x+massData.center.x);this.m_center.y+=massData.mass*(sd.localPosition.y+massData.center.y);++this.m_shapeCount;}
+if(this.m_mass>0.0)
+{this.m_center.Multiply(1.0/this.m_mass);this.m_position.Add(b2Math.b2MulMV(this.m_R,this.m_center));}
+else
+{this.m_flags|=b2Body.e_staticFlag;}
+this.m_I=0.0;for(i=0;i<this.m_shapeCount;++i)
+{sd=bd.shapes[i];massData=massDatas[i];this.m_I+=massData.I;var r=b2Math.SubtractVV(b2Math.AddVV(sd.localPosition,massData.center),this.m_center);this.m_I+=massData.mass*b2Math.b2Dot(r,r);}
+if(this.m_mass>0.0)
+{this.m_invMass=1.0/this.m_mass;}
+else
+{this.m_invMass=0.0;}
+if(this.m_I>0.0&&bd.preventRotation==false)
+{this.m_invI=1.0/this.m_I;}
+else
+{this.m_I=0.0;this.m_invI=0.0;}
+this.m_linearVelocity=b2Math.AddVV(bd.linearVelocity,b2Math.b2CrossFV(bd.angularVelocity,this.m_center));this.m_angularVelocity=bd.angularVelocity;this.m_jointList=null;this.m_contactList=null;this.m_prev=null;this.m_next=null;this.m_shapeList=null;for(i=0;i<this.m_shapeCount;++i)
+{sd=bd.shapes[i];var shape=b2Shape.Create(sd,this,this.m_center);shape.m_next=this.m_shapeList;this.m_shapeList=shape;}
+this.m_sleepTime=0.0;if(bd.allowSleep)
+{this.m_flags|=b2Body.e_allowSleepFlag;}
+if(bd.isSleeping)
+{this.m_flags|=b2Body.e_sleepFlag;}
+if((this.m_flags&b2Body.e_sleepFlag)||this.m_invMass==0.0)
+{this.m_linearVelocity.Set(0.0,0.0);this.m_angularVelocity=0.0;}
+this.m_userData=bd.userData;},Destroy:function(){var s=this.m_shapeList;while(s)
+{var s0=s;s=s.m_next;b2Shape.Destroy(s0);}},sMat0:new b2Mat22(),SynchronizeShapes:function(){this.sMat0.Set(this.m_rotation0);for(var s=this.m_shapeList;s!=null;s=s.m_next)
+{s.Synchronize(this.m_position0,this.sMat0,this.m_position,this.m_R);}},QuickSyncShapes:function(){for(var s=this.m_shapeList;s!=null;s=s.m_next)
+{s.QuickSync(this.m_position,this.m_R);}},IsConnected:function(other){for(var jn=this.m_jointList;jn!=null;jn=jn.next)
+{if(jn.other==other)
+return jn.joint.m_collideConnected==false;}
+return false;},Freeze:function(){this.m_flags|=b2Body.e_frozenFlag;this.m_linearVelocity.SetZero();this.m_angularVelocity=0.0;for(var s=this.m_shapeList;s!=null;s=s.m_next)
+{s.DestroyProxy();}},m_flags:0,m_position:new b2Vec2(),m_rotation:null,m_R:new b2Mat22(0),m_position0:new b2Vec2(),m_rotation0:null,m_linearVelocity:null,m_angularVelocity:null,m_force:null,m_torque:null,m_center:null,m_world:null,m_prev:null,m_next:null,m_shapeList:null,m_shapeCount:0,m_jointList:null,m_contactList:null,m_mass:null,m_invMass:null,m_I:null,m_invI:null,m_linearDamping:null,m_angularDamping:null,m_sleepTime:null,m_userData:null};b2Body.e_staticFlag=0x0001;b2Body.e_frozenFlag=0x0002;b2Body.e_islandFlag=0x0004;b2Body.e_sleepFlag=0x0008;b2Body.e_allowSleepFlag=0x0010;b2Body.e_destroyFlag=0x0020;
+var b2BodyDef=Class.create();b2BodyDef.prototype={initialize:function()
+{this.shapes=new Array();this.userData=null;for(var i=0;i<b2Settings.b2_maxShapesPerBody;i++){this.shapes[i]=null;}
+this.position=new b2Vec2(0.0,0.0);this.rotation=0.0;this.linearVelocity=new b2Vec2(0.0,0.0);this.angularVelocity=0.0;this.linearDamping=0.0;this.angularDamping=0.0;this.allowSleep=true;this.isSleeping=false;this.preventRotation=false;},userData:null,shapes:new Array(),position:null,rotation:null,linearVelocity:null,angularVelocity:null,linearDamping:null,angularDamping:null,allowSleep:null,isSleeping:null,preventRotation:null,AddShape:function(shape)
+{for(var i=0;i<b2Settings.b2_maxShapesPerBody;++i)
+{if(this.shapes[i]==null)
+{this.shapes[i]=shape;break;}}}};
+var b2CollisionFilter=Class.create();b2CollisionFilter.prototype={ShouldCollide:function(shape1,shape2){if(shape1.m_groupIndex==shape2.m_groupIndex&&shape1.m_groupIndex!=0)
+{return shape1.m_groupIndex>0;}
+var collide=(shape1.m_maskBits&shape2.m_categoryBits)!=0&&(shape1.m_categoryBits&shape2.m_maskBits)!=0;return collide;},initialize:function(){}};b2CollisionFilter.b2_defaultFilter=new b2CollisionFilter;
+var b2Island=Class.create();b2Island.prototype={initialize:function(bodyCapacity,contactCapacity,jointCapacity,allocator)
+{var i=0;this.m_bodyCapacity=bodyCapacity;this.m_contactCapacity=contactCapacity;this.m_jointCapacity=jointCapacity;this.m_bodyCount=0;this.m_contactCount=0;this.m_jointCount=0;this.m_bodies=new Array(bodyCapacity);for(i=0;i<bodyCapacity;i++)
+this.m_bodies[i]=null;this.m_contacts=new Array(contactCapacity);for(i=0;i<contactCapacity;i++)
+this.m_contacts[i]=null;this.m_joints=new Array(jointCapacity);for(i=0;i<jointCapacity;i++)
+this.m_joints[i]=null;this.m_allocator=allocator;},Clear:function()
+{this.m_bodyCount=0;this.m_contactCount=0;this.m_jointCount=0;},Solve:function(step,gravity)
+{var i=0;var b;for(i=0;i<this.m_bodyCount;++i)
+{b=this.m_bodies[i];if(b.m_invMass==0.0)
+continue;b.m_linearVelocity.Add(b2Math.MulFV(step.dt,b2Math.AddVV(gravity,b2Math.MulFV(b.m_invMass,b.m_force))));b.m_angularVelocity+=step.dt*b.m_invI*b.m_torque;b.m_linearVelocity.Multiply(b.m_linearDamping);b.m_angularVelocity*=b.m_angularDamping;b.m_position0.SetV(b.m_position);b.m_rotation0=b.m_rotation;}
+var contactSolver=new b2ContactSolver(this.m_contacts,this.m_contactCount,this.m_allocator);contactSolver.PreSolve();for(i=0;i<this.m_jointCount;++i)
+{this.m_joints[i].PrepareVelocitySolver();}
+for(i=0;i<step.iterations;++i)
+{contactSolver.SolveVelocityConstraints();for(var j=0;j<this.m_jointCount;++j)
+{this.m_joints[j].SolveVelocityConstraints(step);}}
+for(i=0;i<this.m_bodyCount;++i)
+{b=this.m_bodies[i];if(b.m_invMass==0.0)
+continue;b.m_position.x+=step.dt*b.m_linearVelocity.x;b.m_position.y+=step.dt*b.m_linearVelocity.y;b.m_rotation+=step.dt*b.m_angularVelocity;b.m_R.Set(b.m_rotation);}
+for(i=0;i<this.m_jointCount;++i)
+{this.m_joints[i].PreparePositionSolver();}
+if(b2World.s_enablePositionCorrection)
+{for(b2Island.m_positionIterationCount=0;b2Island.m_positionIterationCount<step.iterations;++b2Island.m_positionIterationCount)
+{var contactsOkay=contactSolver.SolvePositionConstraints(b2Settings.b2_contactBaumgarte);var jointsOkay=true;for(i=0;i<this.m_jointCount;++i)
+{var jointOkay=this.m_joints[i].SolvePositionConstraints();jointsOkay=jointsOkay&&jointOkay;}
+if(contactsOkay&&jointsOkay)
+{break;}}}
+contactSolver.PostSolve();for(i=0;i<this.m_bodyCount;++i)
+{b=this.m_bodies[i];if(b.m_invMass==0.0)
+continue;b.m_R.Set(b.m_rotation);b.SynchronizeShapes();b.m_force.Set(0.0,0.0);b.m_torque=0.0;}},UpdateSleep:function(dt)
+{var i=0;var b;var minSleepTime=Number.MAX_VALUE;var linTolSqr=b2Settings.b2_linearSleepTolerance*b2Settings.b2_linearSleepTolerance;var angTolSqr=b2Settings.b2_angularSleepTolerance*b2Settings.b2_angularSleepTolerance;for(i=0;i<this.m_bodyCount;++i)
+{b=this.m_bodies[i];if(b.m_invMass==0.0)
+{continue;}
+if((b.m_flags&b2Body.e_allowSleepFlag)==0)
+{b.m_sleepTime=0.0;minSleepTime=0.0;}
+if((b.m_flags&b2Body.e_allowSleepFlag)==0||b.m_angularVelocity*b.m_angularVelocity>angTolSqr||b2Math.b2Dot(b.m_linearVelocity,b.m_linearVelocity)>linTolSqr)
+{b.m_sleepTime=0.0;minSleepTime=0.0;}
+else
+{b.m_sleepTime+=dt;minSleepTime=b2Math.b2Min(minSleepTime,b.m_sleepTime);}}
+if(minSleepTime>=b2Settings.b2_timeToSleep)
+{for(i=0;i<this.m_bodyCount;++i)
+{b=this.m_bodies[i];b.m_flags|=b2Body.e_sleepFlag;}}},AddBody:function(body)
+{this.m_bodies[this.m_bodyCount++]=body;},AddContact:function(contact)
+{this.m_contacts[this.m_contactCount++]=contact;},AddJoint:function(joint)
+{this.m_joints[this.m_jointCount++]=joint;},m_allocator:null,m_bodies:null,m_contacts:null,m_joints:null,m_bodyCount:0,m_jointCount:0,m_contactCount:0,m_bodyCapacity:0,m_contactCapacity:0,m_jointCapacity:0,m_positionError:null};b2Island.m_positionIterationCount=0;
+var b2TimeStep=Class.create();b2TimeStep.prototype={dt:null,inv_dt:null,iterations:0,initialize:function(){}};
+var b2ContactNode=Class.create();b2ContactNode.prototype={other:null,contact:null,prev:null,next:null,initialize:function(){}};
+var b2Contact=Class.create();b2Contact.prototype={GetManifolds:function(){return null},GetManifoldCount:function()
+{return this.m_manifoldCount;},GetNext:function(){return this.m_next;},GetShape1:function(){return this.m_shape1;},GetShape2:function(){return this.m_shape2;},initialize:function(s1,s2)
+{this.m_node1=new b2ContactNode();this.m_node2=new b2ContactNode();this.m_flags=0;if(!s1||!s2){this.m_shape1=null;this.m_shape2=null;return;}
+this.m_shape1=s1;this.m_shape2=s2;this.m_manifoldCount=0;this.m_friction=Math.sqrt(this.m_shape1.m_friction*this.m_shape2.m_friction);this.m_restitution=b2Math.b2Max(this.m_shape1.m_restitution,this.m_shape2.m_restitution);this.m_prev=null;this.m_next=null;this.m_node1.contact=null;this.m_node1.prev=null;this.m_node1.next=null;this.m_node1.other=null;this.m_node2.contact=null;this.m_node2.prev=null;this.m_node2.next=null;this.m_node2.other=null;},Evaluate:function(){},m_flags:0,m_prev:null,m_next:null,m_node1:new b2ContactNode(),m_node2:new b2ContactNode(),m_shape1:null,m_shape2:null,m_manifoldCount:0,m_friction:null,m_restitution:null};b2Contact.e_islandFlag=0x0001;b2Contact.e_destroyFlag=0x0002;b2Contact.AddType=function(createFcn,destroyFcn,type1,type2)
+{b2Contact.s_registers[type1][type2].createFcn=createFcn;b2Contact.s_registers[type1][type2].destroyFcn=destroyFcn;b2Contact.s_registers[type1][type2].primary=true;if(type1!=type2)
+{b2Contact.s_registers[type2][type1].createFcn=createFcn;b2Contact.s_registers[type2][type1].destroyFcn=destroyFcn;b2Contact.s_registers[type2][type1].primary=false;}};b2Contact.InitializeRegisters=function(){b2Contact.s_registers=new Array(b2Shape.e_shapeTypeCount);for(var i=0;i<b2Shape.e_shapeTypeCount;i++){b2Contact.s_registers[i]=new Array(b2Shape.e_shapeTypeCount);for(var j=0;j<b2Shape.e_shapeTypeCount;j++){b2Contact.s_registers[i][j]=new b2ContactRegister();}}
+b2Contact.AddType(b2CircleContact.Create,b2CircleContact.Destroy,b2Shape.e_circleShape,b2Shape.e_circleShape);b2Contact.AddType(b2PolyAndCircleContact.Create,b2PolyAndCircleContact.Destroy,b2Shape.e_polyShape,b2Shape.e_circleShape);b2Contact.AddType(b2PolyContact.Create,b2PolyContact.Destroy,b2Shape.e_polyShape,b2Shape.e_polyShape);};b2Contact.Create=function(shape1,shape2,allocator){if(b2Contact.s_initialized==false)
+{b2Contact.InitializeRegisters();b2Contact.s_initialized=true;}
+var type1=shape1.m_type;var type2=shape2.m_type;var createFcn=b2Contact.s_registers[type1][type2].createFcn;if(createFcn)
+{if(b2Contact.s_registers[type1][type2].primary)
+{return createFcn(shape1,shape2,allocator);}
+else
+{var c=createFcn(shape2,shape1,allocator);for(var i=0;i<c.GetManifoldCount();++i)
+{var m=c.GetManifolds()[i];m.normal=m.normal.Negative();}
+return c;}}
+else
+{return null;}};b2Contact.Destroy=function(contact,allocator){if(contact.GetManifoldCount()>0)
+{contact.m_shape1.m_body.WakeUp();contact.m_shape2.m_body.WakeUp();}
+var type1=contact.m_shape1.m_type;var type2=contact.m_shape2.m_type;var destroyFcn=b2Contact.s_registers[type1][type2].destroyFcn;destroyFcn(contact,allocator);};b2Contact.s_registers=null;b2Contact.s_initialized=false;
+var b2ContactConstraint=Class.create();b2ContactConstraint.prototype={initialize:function(){this.normal=new b2Vec2();this.points=new Array(b2Settings.b2_maxManifoldPoints);for(var i=0;i<b2Settings.b2_maxManifoldPoints;i++){this.points[i]=new b2ContactConstraintPoint();}},points:null,normal:new b2Vec2(),manifold:null,body1:null,body2:null,friction:null,restitution:null,pointCount:0};
+var b2ContactConstraintPoint=Class.create();b2ContactConstraintPoint.prototype={localAnchor1:new b2Vec2(),localAnchor2:new b2Vec2(),normalImpulse:null,tangentImpulse:null,positionImpulse:null,normalMass:null,tangentMass:null,separation:null,velocityBias:null,initialize:function(){this.localAnchor1=new b2Vec2();this.localAnchor2=new b2Vec2();}};
+var b2ContactRegister=Class.create();b2ContactRegister.prototype={createFcn:null,destroyFcn:null,primary:null,initialize:function(){}};
+var b2ContactSolver=Class.create();b2ContactSolver.prototype={initialize:function(contacts,contactCount,allocator){this.m_constraints=new Array();this.m_allocator=allocator;var i=0;var tVec;var tMat;this.m_constraintCount=0;for(i=0;i<contactCount;++i)
+{this.m_constraintCount+=contacts[i].GetManifoldCount();}
+for(i=0;i<this.m_constraintCount;i++){this.m_constraints[i]=new b2ContactConstraint();}
+var count=0;for(i=0;i<contactCount;++i)
+{var contact=contacts[i];var b1=contact.m_shape1.m_body;var b2=contact.m_shape2.m_body;var manifoldCount=contact.GetManifoldCount();var manifolds=contact.GetManifolds();var friction=contact.m_friction;var restitution=contact.m_restitution;var v1X=b1.m_linearVelocity.x;var v1Y=b1.m_linearVelocity.y;var v2X=b2.m_linearVelocity.x;var v2Y=b2.m_linearVelocity.y;var w1=b1.m_angularVelocity;var w2=b2.m_angularVelocity;for(var j=0;j<manifoldCount;++j)
+{var manifold=manifolds[j];var normalX=manifold.normal.x;var normalY=manifold.normal.y;var c=this.m_constraints[count];c.body1=b1;c.body2=b2;c.manifold=manifold;c.normal.x=normalX;c.normal.y=normalY;c.pointCount=manifold.pointCount;c.friction=friction;c.restitution=restitution;for(var k=0;k<c.pointCount;++k)
+{var cp=manifold.points[k];var ccp=c.points[k];ccp.normalImpulse=cp.normalImpulse;ccp.tangentImpulse=cp.tangentImpulse;ccp.separation=cp.separation;var r1X=cp.position.x-b1.m_position.x;var r1Y=cp.position.y-b1.m_position.y;var r2X=cp.position.x-b2.m_position.x;var r2Y=cp.position.y-b2.m_position.y;tVec=ccp.localAnchor1;tMat=b1.m_R;tVec.x=r1X*tMat.col1.x+r1Y*tMat.col1.y;tVec.y=r1X*tMat.col2.x+r1Y*tMat.col2.y;tVec=ccp.localAnchor2;tMat=b2.m_R;tVec.x=r2X*tMat.col1.x+r2Y*tMat.col1.y;tVec.y=r2X*tMat.col2.x+r2Y*tMat.col2.y;var r1Sqr=r1X*r1X+r1Y*r1Y;var r2Sqr=r2X*r2X+r2Y*r2Y;var rn1=r1X*normalX+r1Y*normalY;var rn2=r2X*normalX+r2Y*normalY;var kNormal=b1.m_invMass+b2.m_invMass;kNormal+=b1.m_invI*(r1Sqr-rn1*rn1)+b2.m_invI*(r2Sqr-rn2*rn2);ccp.normalMass=1.0/kNormal;var tangentX=normalY
+var tangentY=-normalX;var rt1=r1X*tangentX+r1Y*tangentY;var rt2=r2X*tangentX+r2Y*tangentY;var kTangent=b1.m_invMass+b2.m_invMass;kTangent+=b1.m_invI*(r1Sqr-rt1*rt1)+b2.m_invI*(r2Sqr-rt2*rt2);ccp.tangentMass=1.0/kTangent;ccp.velocityBias=0.0;if(ccp.separation>0.0)
+{ccp.velocityBias=-60.0*ccp.separation;}
+var tX=v2X+(-w2*r2Y)-v1X-(-w1*r1Y);var tY=v2Y+(w2*r2X)-v1Y-(w1*r1X);var vRel=c.normal.x*tX+c.normal.y*tY;if(vRel<-b2Settings.b2_velocityThreshold)
+{ccp.velocityBias+=-c.restitution*vRel;}}
+++count;}}},PreSolve:function(){var tVec;var tVec2;var tMat;for(var i=0;i<this.m_constraintCount;++i)
+{var c=this.m_constraints[i];var b1=c.body1;var b2=c.body2;var invMass1=b1.m_invMass;var invI1=b1.m_invI;var invMass2=b2.m_invMass;var invI2=b2.m_invI;var normalX=c.normal.x;var normalY=c.normal.y;var tangentX=normalY;var tangentY=-normalX;var j=0;var tCount=0;if(b2World.s_enableWarmStarting)
+{tCount=c.pointCount;for(j=0;j<tCount;++j)
+{var ccp=c.points[j];var PX=ccp.normalImpulse*normalX+ccp.tangentImpulse*tangentX;var PY=ccp.normalImpulse*normalY+ccp.tangentImpulse*tangentY;tMat=b1.m_R;tVec=ccp.localAnchor1;var r1X=tMat.col1.x*tVec.x+tMat.col2.x*tVec.y;var r1Y=tMat.col1.y*tVec.x+tMat.col2.y*tVec.y;tMat=b2.m_R;tVec=ccp.localAnchor2;var r2X=tMat.col1.x*tVec.x+tMat.col2.x*tVec.y;var r2Y=tMat.col1.y*tVec.x+tMat.col2.y*tVec.y;b1.m_angularVelocity-=invI1*(r1X*PY-r1Y*PX);b1.m_linearVelocity.x-=invMass1*PX;b1.m_linearVelocity.y-=invMass1*PY;b2.m_angularVelocity+=invI2*(r2X*PY-r2Y*PX);b2.m_linearVelocity.x+=invMass2*PX;b2.m_linearVelocity.y+=invMass2*PY;ccp.positionImpulse=0.0;}}
+else{tCount=c.pointCount;for(j=0;j<tCount;++j)
+{var ccp2=c.points[j];ccp2.normalImpulse=0.0;ccp2.tangentImpulse=0.0;ccp2.positionImpulse=0.0;}}}},SolveVelocityConstraints:function(){var j=0;var ccp;var r1X;var r1Y;var r2X;var r2Y;var dvX;var dvY;var lambda;var newImpulse;var PX;var PY;var tMat;var tVec;for(var i=0;i<this.m_constraintCount;++i)
+{var c=this.m_constraints[i];var b1=c.body1;var b2=c.body2;var b1_angularVelocity=b1.m_angularVelocity;var b1_linearVelocity=b1.m_linearVelocity;var b2_angularVelocity=b2.m_angularVelocity;var b2_linearVelocity=b2.m_linearVelocity;var invMass1=b1.m_invMass;var invI1=b1.m_invI;var invMass2=b2.m_invMass;var invI2=b2.m_invI;var normalX=c.normal.x;var normalY=c.normal.y;var tangentX=normalY;var tangentY=-normalX;var tCount=c.pointCount;for(j=0;j<tCount;++j)
+{ccp=c.points[j];tMat=b1.m_R;tVec=ccp.localAnchor1;r1X=tMat.col1.x*tVec.x+tMat.col2.x*tVec.y
+r1Y=tMat.col1.y*tVec.x+tMat.col2.y*tVec.y
+tMat=b2.m_R;tVec=ccp.localAnchor2;r2X=tMat.col1.x*tVec.x+tMat.col2.x*tVec.y
+r2Y=tMat.col1.y*tVec.x+tMat.col2.y*tVec.y
+dvX=b2_linearVelocity.x+(-b2_angularVelocity*r2Y)-b1_linearVelocity.x-(-b1_angularVelocity*r1Y);dvY=b2_linearVelocity.y+(b2_angularVelocity*r2X)-b1_linearVelocity.y-(b1_angularVelocity*r1X);var vn=dvX*normalX+dvY*normalY;lambda=-ccp.normalMass*(vn-ccp.velocityBias);newImpulse=b2Math.b2Max(ccp.normalImpulse+lambda,0.0);lambda=newImpulse-ccp.normalImpulse;PX=lambda*normalX;PY=lambda*normalY;b1_linearVelocity.x-=invMass1*PX;b1_linearVelocity.y-=invMass1*PY;b1_angularVelocity-=invI1*(r1X*PY-r1Y*PX);b2_linearVelocity.x+=invMass2*PX;b2_linearVelocity.y+=invMass2*PY;b2_angularVelocity+=invI2*(r2X*PY-r2Y*PX);ccp.normalImpulse=newImpulse;dvX=b2_linearVelocity.x+(-b2_angularVelocity*r2Y)-b1_linearVelocity.x-(-b1_angularVelocity*r1Y);dvY=b2_linearVelocity.y+(b2_angularVelocity*r2X)-b1_linearVelocity.y-(b1_angularVelocity*r1X);var vt=dvX*tangentX+dvY*tangentY;lambda=ccp.tangentMass*(-vt);var maxFriction=c.friction*ccp.normalImpulse;newImpulse=b2Math.b2Clamp(ccp.tangentImpulse+lambda,-maxFriction,maxFriction);lambda=newImpulse-ccp.tangentImpulse;PX=lambda*tangentX;PY=lambda*tangentY;b1_linearVelocity.x-=invMass1*PX;b1_linearVelocity.y-=invMass1*PY;b1_angularVelocity-=invI1*(r1X*PY-r1Y*PX);b2_linearVelocity.x+=invMass2*PX;b2_linearVelocity.y+=invMass2*PY;b2_angularVelocity+=invI2*(r2X*PY-r2Y*PX);ccp.tangentImpulse=newImpulse;}
+b1.m_angularVelocity=b1_angularVelocity;b2.m_angularVelocity=b2_angularVelocity;}},SolvePositionConstraints:function(beta){var minSeparation=0.0;var tMat;var tVec;for(var i=0;i<this.m_constraintCount;++i)
+{var c=this.m_constraints[i];var b1=c.body1;var b2=c.body2;var b1_position=b1.m_position;var b1_rotation=b1.m_rotation;var b2_position=b2.m_position;var b2_rotation=b2.m_rotation;var invMass1=b1.m_invMass;var invI1=b1.m_invI;var invMass2=b2.m_invMass;var invI2=b2.m_invI;var normalX=c.normal.x;var normalY=c.normal.y;var tangentX=normalY;var tangentY=-normalX;var tCount=c.pointCount;for(var j=0;j<tCount;++j)
+{var ccp=c.points[j];tMat=b1.m_R;tVec=ccp.localAnchor1;var r1X=tMat.col1.x*tVec.x+tMat.col2.x*tVec.y
+var r1Y=tMat.col1.y*tVec.x+tMat.col2.y*tVec.y
+tMat=b2.m_R;tVec=ccp.localAnchor2;var r2X=tMat.col1.x*tVec.x+tMat.col2.x*tVec.y
+var r2Y=tMat.col1.y*tVec.x+tMat.col2.y*tVec.y
+var p1X=b1_position.x+r1X;var p1Y=b1_position.y+r1Y;var p2X=b2_position.x+r2X;var p2Y=b2_position.y+r2Y;var dpX=p2X-p1X;var dpY=p2Y-p1Y;var separation=(dpX*normalX+dpY*normalY)+ccp.separation;minSeparation=b2Math.b2Min(minSeparation,separation);var C=beta*b2Math.b2Clamp(separation+b2Settings.b2_linearSlop,-b2Settings.b2_maxLinearCorrection,0.0);var dImpulse=-ccp.normalMass*C;var impulse0=ccp.positionImpulse;ccp.positionImpulse=b2Math.b2Max(impulse0+dImpulse,0.0);dImpulse=ccp.positionImpulse-impulse0;var impulseX=dImpulse*normalX;var impulseY=dImpulse*normalY;b1_position.x-=invMass1*impulseX;b1_position.y-=invMass1*impulseY;b1_rotation-=invI1*(r1X*impulseY-r1Y*impulseX);b1.m_R.Set(b1_rotation);b2_position.x+=invMass2*impulseX;b2_position.y+=invMass2*impulseY;b2_rotation+=invI2*(r2X*impulseY-r2Y*impulseX);b2.m_R.Set(b2_rotation);}
+b1.m_rotation=b1_rotation;b2.m_rotation=b2_rotation;}
+return minSeparation>=-b2Settings.b2_linearSlop;},PostSolve:function(){for(var i=0;i<this.m_constraintCount;++i)
+{var c=this.m_constraints[i];var m=c.manifold;for(var j=0;j<c.pointCount;++j)
+{var mPoint=m.points[j];var cPoint=c.points[j];mPoint.normalImpulse=cPoint.normalImpulse;mPoint.tangentImpulse=cPoint.tangentImpulse;}}},m_allocator:null,m_constraints:new Array(),m_constraintCount:0};
+var b2CircleContact=Class.create();Object.extend(b2CircleContact.prototype,b2Contact.prototype);Object.extend(b2CircleContact.prototype,{initialize:function(s1,s2){this.m_node1=new b2ContactNode();this.m_node2=new b2ContactNode();this.m_flags=0;if(!s1||!s2){this.m_shape1=null;this.m_shape2=null;return;}
+this.m_shape1=s1;this.m_shape2=s2;this.m_manifoldCount=0;this.m_friction=Math.sqrt(this.m_shape1.m_friction*this.m_shape2.m_friction);this.m_restitution=b2Math.b2Max(this.m_shape1.m_restitution,this.m_shape2.m_restitution);this.m_prev=null;this.m_next=null;this.m_node1.contact=null;this.m_node1.prev=null;this.m_node1.next=null;this.m_node1.other=null;this.m_node2.contact=null;this.m_node2.prev=null;this.m_node2.next=null;this.m_node2.other=null;this.m_manifold=[new b2Manifold()];this.m_manifold[0].pointCount=0;this.m_manifold[0].points[0].normalImpulse=0.0;this.m_manifold[0].points[0].tangentImpulse=0.0;},Evaluate:function(){b2Collision.b2CollideCircle(this.m_manifold[0],this.m_shape1,this.m_shape2,false);if(this.m_manifold[0].pointCount>0)
+{this.m_manifoldCount=1;}
+else
+{this.m_manifoldCount=0;}},GetManifolds:function()
+{return this.m_manifold;},m_manifold:[new b2Manifold()]});b2CircleContact.Create=function(shape1,shape2,allocator){return new b2CircleContact(shape1,shape2);};b2CircleContact.Destroy=function(contact,allocator){};
+var b2Conservative=Class.create();b2Conservative.prototype={initialize:function(){}}
+b2Conservative.R1=new b2Mat22();b2Conservative.R2=new b2Mat22();b2Conservative.x1=new b2Vec2();b2Conservative.x2=new b2Vec2();b2Conservative.Conservative=function(shape1,shape2){var body1=shape1.GetBody();var body2=shape2.GetBody();var v1X=body1.m_position.x-body1.m_position0.x;var v1Y=body1.m_position.y-body1.m_position0.y;var omega1=body1.m_rotation-body1.m_rotation0;var v2X=body2.m_position.x-body2.m_position0.x;var v2Y=body2.m_position.y-body2.m_position0.y;var omega2=body2.m_rotation-body2.m_rotation0;var r1=shape1.GetMaxRadius();var r2=shape2.GetMaxRadius();var p1StartX=body1.m_position0.x;var p1StartY=body1.m_position0.y;var a1Start=body1.m_rotation0;var p2StartX=body2.m_position0.x;var p2StartY=body2.m_position0.y;var a2Start=body2.m_rotation0;var p1X=p1StartX;var p1Y=p1StartY;var a1=a1Start;var p2X=p2StartX;var p2Y=p2StartY;var a2=a2Start;b2Conservative.R1.Set(a1);b2Conservative.R2.Set(a2);shape1.QuickSync(p1,b2Conservative.R1);shape2.QuickSync(p2,b2Conservative.R2);var s1=0.0;var maxIterations=10;var dX;var dY;var invRelativeVelocity=0.0;var hit=true;for(var iter=0;iter<maxIterations;++iter)
+{var distance=b2Distance.Distance(b2Conservative.x1,b2Conservative.x2,shape1,shape2);if(distance<b2Settings.b2_linearSlop)
+{if(iter==0)
+{hit=false;}
+else
+{hit=true;}
+break;}
+if(iter==0)
+{dX=b2Conservative.x2.x-b2Conservative.x1.x;dY=b2Conservative.x2.y-b2Conservative.x1.y;var dLen=Math.sqrt(dX*dX+dY*dY);var relativeVelocity=(dX*(v1X-v2X)+dY*(v1Y-v2Y))+Math.abs(omega1)*r1+Math.abs(omega2)*r2;if(Math.abs(relativeVelocity)<Number.MIN_VALUE)
+{hit=false;break;}
+invRelativeVelocity=1.0/relativeVelocity;}
+var ds=distance*invRelativeVelocity;var s2=s1+ds;if(s2<0.0||1.0<s2)
+{hit=false;break;}
+if(s2<(1.0+100.0*Number.MIN_VALUE)*s1)
+{hit=true;break;}
+s1=s2;p1X=p1StartX+s1*v1.x;p1Y=p1StartY+s1*v1.y;a1=a1Start+s1*omega1;p2X=p2StartX+s1*v2.x;p2Y=p2StartY+s1*v2.y;a2=a2Start+s1*omega2;b2Conservative.R1.Set(a1);b2Conservative.R2.Set(a2);shape1.QuickSync(p1,b2Conservative.R1);shape2.QuickSync(p2,b2Conservative.R2);}
+if(hit)
+{dX=b2Conservative.x2.x-b2Conservative.x1.x;dY=b2Conservative.x2.y-b2Conservative.x1.y;var length=Math.sqrt(dX*dX+dY*dY);if(length>FLT_EPSILON)
+{d*=b2_linearSlop/length;}
+if(body1.IsStatic())
+{body1.m_position.x=p1X;body1.m_position.y=p1Y;}
+else
+{body1.m_position.x=p1X-dX;body1.m_position.y=p1Y-dY;}
+body1.m_rotation=a1;body1.m_R.Set(a1);body1.QuickSyncShapes();if(body2.IsStatic())
+{body2.m_position.x=p2X;body2.m_position.y=p2Y;}
+else
+{body2.m_position.x=p2X+dX;body2.m_position.y=p2Y+dY;}
+body2.m_position.x=p2X+dX;body2.m_position.y=p2Y+dY;body2.m_rotation=a2;body2.m_R.Set(a2);body2.QuickSyncShapes();return true;}
+shape1.QuickSync(body1.m_position,body1.m_R);shape2.QuickSync(body2.m_position,body2.m_R);return false;};
+var b2NullContact=Class.create();Object.extend(b2NullContact.prototype,b2Contact.prototype);Object.extend(b2NullContact.prototype,{initialize:function(s1,s2){this.m_node1=new b2ContactNode();this.m_node2=new b2ContactNode();this.m_flags=0;if(!s1||!s2){this.m_shape1=null;this.m_shape2=null;return;}
+this.m_shape1=s1;this.m_shape2=s2;this.m_manifoldCount=0;this.m_friction=Math.sqrt(this.m_shape1.m_friction*this.m_shape2.m_friction);this.m_restitution=b2Math.b2Max(this.m_shape1.m_restitution,this.m_shape2.m_restitution);this.m_prev=null;this.m_next=null;this.m_node1.contact=null;this.m_node1.prev=null;this.m_node1.next=null;this.m_node1.other=null;this.m_node2.contact=null;this.m_node2.prev=null;this.m_node2.next=null;this.m_node2.other=null;},Evaluate:function(){},GetManifolds:function(){return null;}});
+var b2PolyAndCircleContact=Class.create();Object.extend(b2PolyAndCircleContact.prototype,b2Contact.prototype);Object.extend(b2PolyAndCircleContact.prototype,{initialize:function(s1,s2){this.m_node1=new b2ContactNode();this.m_node2=new b2ContactNode();this.m_flags=0;if(!s1||!s2){this.m_shape1=null;this.m_shape2=null;return;}
+this.m_shape1=s1;this.m_shape2=s2;this.m_manifoldCount=0;this.m_friction=Math.sqrt(this.m_shape1.m_friction*this.m_shape2.m_friction);this.m_restitution=b2Math.b2Max(this.m_shape1.m_restitution,this.m_shape2.m_restitution);this.m_prev=null;this.m_next=null;this.m_node1.contact=null;this.m_node1.prev=null;this.m_node1.next=null;this.m_node1.other=null;this.m_node2.contact=null;this.m_node2.prev=null;this.m_node2.next=null;this.m_node2.other=null;this.m_manifold=[new b2Manifold()];b2Settings.b2Assert(this.m_shape1.m_type==b2Shape.e_polyShape);b2Settings.b2Assert(this.m_shape2.m_type==b2Shape.e_circleShape);this.m_manifold[0].pointCount=0;this.m_manifold[0].points[0].normalImpulse=0.0;this.m_manifold[0].points[0].tangentImpulse=0.0;},Evaluate:function(){b2Collision.b2CollidePolyAndCircle(this.m_manifold[0],this.m_shape1,this.m_shape2,false);if(this.m_manifold[0].pointCount>0)
+{this.m_manifoldCount=1;}
+else
+{this.m_manifoldCount=0;}},GetManifolds:function()
+{return this.m_manifold;},m_manifold:[new b2Manifold()]})
+b2PolyAndCircleContact.Create=function(shape1,shape2,allocator){return new b2PolyAndCircleContact(shape1,shape2);};b2PolyAndCircleContact.Destroy=function(contact,allocator){};
+var b2PolyContact=Class.create();Object.extend(b2PolyContact.prototype,b2Contact.prototype);Object.extend(b2PolyContact.prototype,{initialize:function(s1,s2){this.m_node1=new b2ContactNode();this.m_node2=new b2ContactNode();this.m_flags=0;if(!s1||!s2){this.m_shape1=null;this.m_shape2=null;return;}
+this.m_shape1=s1;this.m_shape2=s2;this.m_manifoldCount=0;this.m_friction=Math.sqrt(this.m_shape1.m_friction*this.m_shape2.m_friction);this.m_restitution=b2Math.b2Max(this.m_shape1.m_restitution,this.m_shape2.m_restitution);this.m_prev=null;this.m_next=null;this.m_node1.contact=null;this.m_node1.prev=null;this.m_node1.next=null;this.m_node1.other=null;this.m_node2.contact=null;this.m_node2.prev=null;this.m_node2.next=null;this.m_node2.other=null;this.m0=new b2Manifold();this.m_manifold=[new b2Manifold()];this.m_manifold[0].pointCount=0;},m0:new b2Manifold(),Evaluate:function(){var tMani=this.m_manifold[0];var tPoints=this.m0.points;for(var k=0;k<tMani.pointCount;k++){var tPoint=tPoints[k];var tPoint0=tMani.points[k];tPoint.normalImpulse=tPoint0.normalImpulse;tPoint.tangentImpulse=tPoint0.tangentImpulse;tPoint.id=tPoint0.id.Copy();}
+this.m0.pointCount=tMani.pointCount;b2Collision.b2CollidePoly(tMani,this.m_shape1,this.m_shape2,false);if(tMani.pointCount>0)
+{var match=[false,false];for(var i=0;i<tMani.pointCount;++i)
+{var cp=tMani.points[i];cp.normalImpulse=0.0;cp.tangentImpulse=0.0;var idKey=cp.id.key;for(var j=0;j<this.m0.pointCount;++j)
+{if(match[j]==true)
+continue;var cp0=this.m0.points[j];var id0=cp0.id;if(id0.key==idKey)
+{match[j]=true;cp.normalImpulse=cp0.normalImpulse;cp.tangentImpulse=cp0.tangentImpulse;break;}}}
+this.m_manifoldCount=1;}
+else
+{this.m_manifoldCount=0;}},GetManifolds:function()
+{return this.m_manifold;},m_manifold:[new b2Manifold()]});b2PolyContact.Create=function(shape1,shape2,allocator){return new b2PolyContact(shape1,shape2);};b2PolyContact.Destroy=function(contact,allocator){};
+var b2ContactManager=Class.create();Object.extend(b2ContactManager.prototype,b2PairCallback.prototype);Object.extend(b2ContactManager.prototype,{initialize:function(){this.m_nullContact=new b2NullContact();this.m_world=null;this.m_destroyImmediate=false;},PairAdded:function(proxyUserData1,proxyUserData2){var shape1=proxyUserData1;var shape2=proxyUserData2;var body1=shape1.m_body;var body2=shape2.m_body;if(body1.IsStatic()&&body2.IsStatic())
+{return this.m_nullContact;}
+if(shape1.m_body==shape2.m_body)
+{return this.m_nullContact;}
+if(body2.IsConnected(body1))
+{return this.m_nullContact;}
+if(this.m_world.m_filter!=null&&this.m_world.m_filter.ShouldCollide(shape1,shape2)==false)
+{return this.m_nullContact;}
+if(body2.m_invMass==0.0)
+{var tempShape=shape1;shape1=shape2;shape2=tempShape;var tempBody=body1;body1=body2;body2=tempBody;}
+var contact=b2Contact.Create(shape1,shape2,this.m_world.m_blockAllocator);if(contact==null)
+{return this.m_nullContact;}
+else
+{contact.m_prev=null;contact.m_next=this.m_world.m_contactList;if(this.m_world.m_contactList!=null)
+{this.m_world.m_contactList.m_prev=contact;}
+this.m_world.m_contactList=contact;this.m_world.m_contactCount++;}
+return contact;},PairRemoved:function(proxyUserData1,proxyUserData2,pairUserData){if(pairUserData==null)
+{return;}
+var c=pairUserData;if(c!=this.m_nullContact)
+{if(this.m_destroyImmediate==true)
+{this.DestroyContact(c);c=null;}
+else
+{c.m_flags|=b2Contact.e_destroyFlag;}}},DestroyContact:function(c)
+{if(c.m_prev)
+{c.m_prev.m_next=c.m_next;}
+if(c.m_next)
+{c.m_next.m_prev=c.m_prev;}
+if(c==this.m_world.m_contactList)
+{this.m_world.m_contactList=c.m_next;}
+if(c.GetManifoldCount()>0)
+{var body1=c.m_shape1.m_body;var body2=c.m_shape2.m_body;var node1=c.m_node1;var node2=c.m_node2;body1.WakeUp();body2.WakeUp();if(node1.prev)
+{node1.prev.next=node1.next;}
+if(node1.next)
+{node1.next.prev=node1.prev;}
+if(node1==body1.m_contactList)
+{body1.m_contactList=node1.next;}
+node1.prev=null;node1.next=null;if(node2.prev)
+{node2.prev.next=node2.next;}
+if(node2.next)
+{node2.next.prev=node2.prev;}
+if(node2==body2.m_contactList)
+{body2.m_contactList=node2.next;}
+node2.prev=null;node2.next=null;}
+b2Contact.Destroy(c,this.m_world.m_blockAllocator);--this.m_world.m_contactCount;},CleanContactList:function()
+{var c=this.m_world.m_contactList;while(c!=null)
+{var c0=c;c=c.m_next;if(c0.m_flags&b2Contact.e_destroyFlag)
+{this.DestroyContact(c0);c0=null;}}},Collide:function()
+{var body1;var body2;var node1;var node2;for(var c=this.m_world.m_contactList;c!=null;c=c.m_next)
+{if(c.m_shape1.m_body.IsSleeping()&&c.m_shape2.m_body.IsSleeping())
+{continue;}
+var oldCount=c.GetManifoldCount();c.Evaluate();var newCount=c.GetManifoldCount();if(oldCount==0&&newCount>0)
+{body1=c.m_shape1.m_body;body2=c.m_shape2.m_body;node1=c.m_node1;node2=c.m_node2;node1.contact=c;node1.other=body2;node1.prev=null;node1.next=body1.m_contactList;if(node1.next!=null)
+{node1.next.prev=c.m_node1;}
+body1.m_contactList=c.m_node1;node2.contact=c;node2.other=body1;node2.prev=null;node2.next=body2.m_contactList;if(node2.next!=null)
+{node2.next.prev=node2;}
+body2.m_contactList=node2;}
+else if(oldCount>0&&newCount==0)
+{body1=c.m_shape1.m_body;body2=c.m_shape2.m_body;node1=c.m_node1;node2=c.m_node2;if(node1.prev)
+{node1.prev.next=node1.next;}
+if(node1.next)
+{node1.next.prev=node1.prev;}
+if(node1==body1.m_contactList)
+{body1.m_contactList=node1.next;}
+node1.prev=null;node1.next=null;if(node2.prev)
+{node2.prev.next=node2.next;}
+if(node2.next)
+{node2.next.prev=node2.prev;}
+if(node2==body2.m_contactList)
+{body2.m_contactList=node2.next;}
+node2.prev=null;node2.next=null;}}},m_world:null,m_nullContact:new b2NullContact(),m_destroyImmediate:null});
+var b2World=Class.create();b2World.prototype={initialize:function(worldAABB,gravity,doSleep){this.step=new b2TimeStep();this.m_contactManager=new b2ContactManager();this.m_listener=null;this.m_filter=b2CollisionFilter.b2_defaultFilter;this.m_bodyList=null;this.m_contactList=null;this.m_jointList=null;this.m_bodyCount=0;this.m_contactCount=0;this.m_jointCount=0;this.m_bodyDestroyList=null;this.m_allowSleep=doSleep;this.m_gravity=gravity;this.m_contactManager.m_world=this;this.m_broadPhase=new b2BroadPhase(worldAABB,this.m_contactManager);var bd=new b2BodyDef();this.m_groundBody=this.CreateBody(bd);},SetListener:function(listener){this.m_listener=listener;},SetFilter:function(filter){this.m_filter=filter;},CreateBody:function(def){var b=new b2Body(def,this);b.m_prev=null;b.m_next=this.m_bodyList;if(this.m_bodyList)
+{this.m_bodyList.m_prev=b;}
+this.m_bodyList=b;++this.m_bodyCount;return b;},DestroyBody:function(b)
+{if(b.m_flags&b2Body.e_destroyFlag)
+{return;}
+if(b.m_prev)
+{b.m_prev.m_next=b.m_next;}
+if(b.m_next)
+{b.m_next.m_prev=b.m_prev;}
+if(b==this.m_bodyList)
+{this.m_bodyList=b.m_next;}
+b.m_flags|=b2Body.e_destroyFlag;--this.m_bodyCount;b.m_prev=null;b.m_next=this.m_bodyDestroyList;this.m_bodyDestroyList=b;},CleanBodyList:function()
+{this.m_contactManager.m_destroyImmediate=true;var b=this.m_bodyDestroyList;while(b)
+{var b0=b;b=b.m_next;var jn=b0.m_jointList;while(jn)
+{var jn0=jn;jn=jn.next;if(this.m_listener)
+{this.m_listener.NotifyJointDestroyed(jn0.joint);}
+this.DestroyJoint(jn0.joint);}
+b0.Destroy();}
+this.m_bodyDestroyList=null;this.m_contactManager.m_destroyImmediate=false;},CreateJoint:function(def){var j=b2Joint.Create(def,this.m_blockAllocator);j.m_prev=null;j.m_next=this.m_jointList;if(this.m_jointList)
+{this.m_jointList.m_prev=j;}
+this.m_jointList=j;++this.m_jointCount;j.m_node1.joint=j;j.m_node1.other=j.m_body2;j.m_node1.prev=null;j.m_node1.next=j.m_body1.m_jointList;if(j.m_body1.m_jointList)j.m_body1.m_jointList.prev=j.m_node1;j.m_body1.m_jointList=j.m_node1;j.m_node2.joint=j;j.m_node2.other=j.m_body1;j.m_node2.prev=null;j.m_node2.next=j.m_body2.m_jointList;if(j.m_body2.m_jointList)j.m_body2.m_jointList.prev=j.m_node2;j.m_body2.m_jointList=j.m_node2;if(def.collideConnected==false)
+{var b=def.body1.m_shapeCount<def.body2.m_shapeCount?def.body1:def.body2;for(var s=b.m_shapeList;s;s=s.m_next)
+{s.ResetProxy(this.m_broadPhase);}}
+return j;},DestroyJoint:function(j)
+{var collideConnected=j.m_collideConnected;if(j.m_prev)
+{j.m_prev.m_next=j.m_next;}
+if(j.m_next)
+{j.m_next.m_prev=j.m_prev;}
+if(j==this.m_jointList)
+{this.m_jointList=j.m_next;}
+var body1=j.m_body1;var body2=j.m_body2;body1.WakeUp();body2.WakeUp();if(j.m_node1.prev)
+{j.m_node1.prev.next=j.m_node1.next;}
+if(j.m_node1.next)
+{j.m_node1.next.prev=j.m_node1.prev;}
+if(j.m_node1==body1.m_jointList)
+{body1.m_jointList=j.m_node1.next;}
+j.m_node1.prev=null;j.m_node1.next=null;if(j.m_node2.prev)
+{j.m_node2.prev.next=j.m_node2.next;}
+if(j.m_node2.next)
+{j.m_node2.next.prev=j.m_node2.prev;}
+if(j.m_node2==body2.m_jointList)
+{body2.m_jointList=j.m_node2.next;}
+j.m_node2.prev=null;j.m_node2.next=null;b2Joint.Destroy(j,this.m_blockAllocator);--this.m_jointCount;if(collideConnected==false)
+{var b=body1.m_shapeCount<body2.m_shapeCount?body1:body2;for(var s=b.m_shapeList;s;s=s.m_next)
+{s.ResetProxy(this.m_broadPhase);}}},GetGroundBody:function(){return this.m_groundBody;},step:new b2TimeStep(),Step:function(dt,iterations){var b;var other;this.step.dt=dt;this.step.iterations=iterations;if(dt>0.0)
+{this.step.inv_dt=1.0/dt;}
+else
+{this.step.inv_dt=0.0;}
+this.m_positionIterationCount=0;this.m_contactManager.CleanContactList();this.CleanBodyList();this.m_contactManager.Collide();var island=new b2Island(this.m_bodyCount,this.m_contactCount,this.m_jointCount,this.m_stackAllocator);for(b=this.m_bodyList;b!=null;b=b.m_next)
+{b.m_flags&=~b2Body.e_islandFlag;}
+for(var c=this.m_contactList;c!=null;c=c.m_next)
+{c.m_flags&=~b2Contact.e_islandFlag;}
+for(var j=this.m_jointList;j!=null;j=j.m_next)
+{j.m_islandFlag=false;}
+var stackSize=this.m_bodyCount;var stack=new Array(this.m_bodyCount);for(var k=0;k<this.m_bodyCount;k++)
+stack[k]=null;for(var seed=this.m_bodyList;seed!=null;seed=seed.m_next)
+{if(seed.m_flags&(b2Body.e_staticFlag|b2Body.e_islandFlag|b2Body.e_sleepFlag|b2Body.e_frozenFlag))
+{continue;}
+island.Clear();var stackCount=0;stack[stackCount++]=seed;seed.m_flags|=b2Body.e_islandFlag;;while(stackCount>0)
+{b=stack[--stackCount];island.AddBody(b);b.m_flags&=~b2Body.e_sleepFlag;if(b.m_flags&b2Body.e_staticFlag)
+{continue;}
+for(var cn=b.m_contactList;cn!=null;cn=cn.next)
+{if(cn.contact.m_flags&b2Contact.e_islandFlag)
+{continue;}
+island.AddContact(cn.contact);cn.contact.m_flags|=b2Contact.e_islandFlag;other=cn.other;if(other.m_flags&b2Body.e_islandFlag)
+{continue;}
+stack[stackCount++]=other;other.m_flags|=b2Body.e_islandFlag;}
+for(var jn=b.m_jointList;jn!=null;jn=jn.next)
+{if(jn.joint.m_islandFlag==true)
+{continue;}
+island.AddJoint(jn.joint);jn.joint.m_islandFlag=true;other=jn.other;if(other.m_flags&b2Body.e_islandFlag)
+{continue;}
+stack[stackCount++]=other;other.m_flags|=b2Body.e_islandFlag;}}
+island.Solve(this.step,this.m_gravity);this.m_positionIterationCount=b2Math.b2Max(this.m_positionIterationCount,b2Island.m_positionIterationCount);if(this.m_allowSleep)
+{island.UpdateSleep(dt);}
+for(var i=0;i<island.m_bodyCount;++i)
+{b=island.m_bodies[i];if(b.m_flags&b2Body.e_staticFlag)
+{b.m_flags&=~b2Body.e_islandFlag;}
+if(b.IsFrozen()&&this.m_listener)
+{var response=this.m_listener.NotifyBoundaryViolated(b);if(response==b2WorldListener.b2_destroyBody)
+{this.DestroyBody(b);b=null;island.m_bodies[i]=null;}}}}
+this.m_broadPhase.Commit();},Query:function(aabb,shapes,maxCount){var results=new Array();var count=this.m_broadPhase.QueryAABB(aabb,results,maxCount);for(var i=0;i<count;++i)
+{shapes[i]=results[i];}
+return count;},GetBodyList:function(){return this.m_bodyList;},GetJointList:function(){return this.m_jointList;},GetContactList:function(){return this.m_contactList;},m_blockAllocator:null,m_stackAllocator:null,m_broadPhase:null,m_contactManager:new b2ContactManager(),m_bodyList:null,m_contactList:null,m_jointList:null,m_bodyCount:0,m_contactCount:0,m_jointCount:0,m_bodyDestroyList:null,m_gravity:null,m_allowSleep:null,m_groundBody:null,m_listener:null,m_filter:null,m_positionIterationCount:0};b2World.s_enablePositionCorrection=1;b2World.s_enableWarmStarting=1;
+var b2WorldListener=Class.create();b2WorldListener.prototype={NotifyJointDestroyed:function(joint){},NotifyBoundaryViolated:function(body)
+{return b2WorldListener.b2_freezeBody;},initialize:function(){}};b2WorldListener.b2_freezeBody=0;b2WorldListener.b2_destroyBody=1;
+var b2JointNode=Class.create();b2JointNode.prototype={other:null,joint:null,prev:null,next:null,initialize:function(){}}
+
+var b2Joint=Class.create();b2Joint.prototype={GetType:function(){return this.m_type;},GetAnchor1:function(){return null},GetAnchor2:function(){return null},GetReactionForce:function(invTimeStep){return null},GetReactionTorque:function(invTimeStep){return 0.0},GetBody1:function()
+{return this.m_body1;},GetBody2:function()
+{return this.m_body2;},GetNext:function(){return this.m_next;},GetUserData:function(){return this.m_userData;},initialize:function(def){this.m_node1=new b2JointNode();this.m_node2=new b2JointNode();this.m_type=def.type;this.m_prev=null;this.m_next=null;this.m_body1=def.body1;this.m_body2=def.body2;this.m_collideConnected=def.collideConnected;this.m_islandFlag=false;this.m_userData=def.userData;},PrepareVelocitySolver:function(){},SolveVelocityConstraints:function(step){},PreparePositionSolver:function(){},SolvePositionConstraints:function(){return false},m_type:0,m_prev:null,m_next:null,m_node1:new b2JointNode(),m_node2:new b2JointNode(),m_body1:null,m_body2:null,m_islandFlag:null,m_collideConnected:null,m_userData:null};b2Joint.Create=function(def,allocator){var joint=null;switch(def.type)
+{case b2Joint.e_distanceJoint:{joint=new b2DistanceJoint(def);}
+break;case b2Joint.e_mouseJoint:{joint=new b2MouseJoint(def);}
+break;case b2Joint.e_prismaticJoint:{joint=new b2PrismaticJoint(def);}
+break;case b2Joint.e_revoluteJoint:{joint=new b2RevoluteJoint(def);}
+break;case b2Joint.e_pulleyJoint:{joint=new b2PulleyJoint(def);}
+break;case b2Joint.e_gearJoint:{joint=new b2GearJoint(def);}
+break;default:break;}
+return joint;};b2Joint.Destroy=function(joint,allocator){};b2Joint.e_unknownJoint=0;b2Joint.e_revoluteJoint=1;b2Joint.e_prismaticJoint=2;b2Joint.e_distanceJoint=3;b2Joint.e_pulleyJoint=4;b2Joint.e_mouseJoint=5;b2Joint.e_gearJoint=6;b2Joint.e_inactiveLimit=0;b2Joint.e_atLowerLimit=1;b2Joint.e_atUpperLimit=2;b2Joint.e_equalLimits=3;
+var b2JointDef=Class.create();b2JointDef.prototype={initialize:function()
+{this.type=b2Joint.e_unknownJoint;this.userData=null;this.body1=null;this.body2=null;this.collideConnected=false;},type:0,userData:null,body1:null,body2:null,collideConnected:null}
+
+var b2DistanceJoint=Class.create();Object.extend(b2DistanceJoint.prototype,b2Joint.prototype);Object.extend(b2DistanceJoint.prototype,{initialize:function(def){this.m_node1=new b2JointNode();this.m_node2=new b2JointNode();this.m_type=def.type;this.m_prev=null;this.m_next=null;this.m_body1=def.body1;this.m_body2=def.body2;this.m_collideConnected=def.collideConnected;this.m_islandFlag=false;this.m_userData=def.userData;this.m_localAnchor1=new b2Vec2();this.m_localAnchor2=new b2Vec2();this.m_u=new b2Vec2();var tMat;var tX;var tY;tMat=this.m_body1.m_R;tX=def.anchorPoint1.x-this.m_body1.m_position.x;tY=def.anchorPoint1.y-this.m_body1.m_position.y;this.m_localAnchor1.x=tX*tMat.col1.x+tY*tMat.col1.y;this.m_localAnchor1.y=tX*tMat.col2.x+tY*tMat.col2.y;tMat=this.m_body2.m_R;tX=def.anchorPoint2.x-this.m_body2.m_position.x;tY=def.anchorPoint2.y-this.m_body2.m_position.y;this.m_localAnchor2.x=tX*tMat.col1.x+tY*tMat.col1.y;this.m_localAnchor2.y=tX*tMat.col2.x+tY*tMat.col2.y;tX=def.anchorPoint2.x-def.anchorPoint1.x;tY=def.anchorPoint2.y-def.anchorPoint1.y;this.m_length=Math.sqrt(tX*tX+tY*tY);this.m_impulse=0.0;},PrepareVelocitySolver:function(){var tMat;tMat=this.m_body1.m_R;var r1X=tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y;var r1Y=tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y;tMat=this.m_body2.m_R;var r2X=tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y;var r2Y=tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y;this.m_u.x=this.m_body2.m_position.x+r2X-this.m_body1.m_position.x-r1X;this.m_u.y=this.m_body2.m_position.y+r2Y-this.m_body1.m_position.y-r1Y;var length=Math.sqrt(this.m_u.x*this.m_u.x+this.m_u.y*this.m_u.y);if(length>b2Settings.b2_linearSlop)
+{this.m_u.Multiply(1.0/length);}
+else
+{this.m_u.SetZero();}
+var cr1u=(r1X*this.m_u.y-r1Y*this.m_u.x);var cr2u=(r2X*this.m_u.y-r2Y*this.m_u.x);this.m_mass=this.m_body1.m_invMass+this.m_body1.m_invI*cr1u*cr1u+this.m_body2.m_invMass+this.m_body2.m_invI*cr2u*cr2u;this.m_mass=1.0/this.m_mass;if(b2World.s_enableWarmStarting)
+{var PX=this.m_impulse*this.m_u.x;var PY=this.m_impulse*this.m_u.y;this.m_body1.m_linearVelocity.x-=this.m_body1.m_invMass*PX;this.m_body1.m_linearVelocity.y-=this.m_body1.m_invMass*PY;this.m_body1.m_angularVelocity-=this.m_body1.m_invI*(r1X*PY-r1Y*PX);this.m_body2.m_linearVelocity.x+=this.m_body2.m_invMass*PX;this.m_body2.m_linearVelocity.y+=this.m_body2.m_invMass*PY;this.m_body2.m_angularVelocity+=this.m_body2.m_invI*(r2X*PY-r2Y*PX);}
+else
+{this.m_impulse=0.0;}},SolveVelocityConstraints:function(step){var tMat;tMat=this.m_body1.m_R;var r1X=tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y;var r1Y=tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y;tMat=this.m_body2.m_R;var r2X=tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y;var r2Y=tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y;var v1X=this.m_body1.m_linearVelocity.x+(-this.m_body1.m_angularVelocity*r1Y);var v1Y=this.m_body1.m_linearVelocity.y+(this.m_body1.m_angularVelocity*r1X);var v2X=this.m_body2.m_linearVelocity.x+(-this.m_body2.m_angularVelocity*r2Y);var v2Y=this.m_body2.m_linearVelocity.y+(this.m_body2.m_angularVelocity*r2X);var Cdot=(this.m_u.x*(v2X-v1X)+this.m_u.y*(v2Y-v1Y));var impulse=-this.m_mass*Cdot;this.m_impulse+=impulse;var PX=impulse*this.m_u.x;var PY=impulse*this.m_u.y;this.m_body1.m_linearVelocity.x-=this.m_body1.m_invMass*PX;this.m_body1.m_linearVelocity.y-=this.m_body1.m_invMass*PY;this.m_body1.m_angularVelocity-=this.m_body1.m_invI*(r1X*PY-r1Y*PX);this.m_body2.m_linearVelocity.x+=this.m_body2.m_invMass*PX;this.m_body2.m_linearVelocity.y+=this.m_body2.m_invMass*PY;this.m_body2.m_angularVelocity+=this.m_body2.m_invI*(r2X*PY-r2Y*PX);},SolvePositionConstraints:function(){var tMat;tMat=this.m_body1.m_R;var r1X=tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y;var r1Y=tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y;tMat=this.m_body2.m_R;var r2X=tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y;var r2Y=tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y;var dX=this.m_body2.m_position.x+r2X-this.m_body1.m_position.x-r1X;var dY=this.m_body2.m_position.y+r2Y-this.m_body1.m_position.y-r1Y;var length=Math.sqrt(dX*dX+dY*dY);dX/=length;dY/=length;var C=length-this.m_length;C=b2Math.b2Clamp(C,-b2Settings.b2_maxLinearCorrection,b2Settings.b2_maxLinearCorrection);var impulse=-this.m_mass*C;this.m_u.Set(dX,dY);var PX=impulse*this.m_u.x;var PY=impulse*this.m_u.y;this.m_body1.m_position.x-=this.m_body1.m_invMass*PX;this.m_body1.m_position.y-=this.m_body1.m_invMass*PY;this.m_body1.m_rotation-=this.m_body1.m_invI*(r1X*PY-r1Y*PX);this.m_body2.m_position.x+=this.m_body2.m_invMass*PX;this.m_body2.m_position.y+=this.m_body2.m_invMass*PY;this.m_body2.m_rotation+=this.m_body2.m_invI*(r2X*PY-r2Y*PX);this.m_body1.m_R.Set(this.m_body1.m_rotation);this.m_body2.m_R.Set(this.m_body2.m_rotation);return b2Math.b2Abs(C)<b2Settings.b2_linearSlop;},GetAnchor1:function(){return b2Math.AddVV(this.m_body1.m_position,b2Math.b2MulMV(this.m_body1.m_R,this.m_localAnchor1));},GetAnchor2:function(){return b2Math.AddVV(this.m_body2.m_position,b2Math.b2MulMV(this.m_body2.m_R,this.m_localAnchor2));},GetReactionForce:function(invTimeStep)
+{var F=new b2Vec2();F.SetV(this.m_u);F.Multiply(this.m_impulse*invTimeStep);return F;},GetReactionTorque:function(invTimeStep)
+{return 0.0;},m_localAnchor1:new b2Vec2(),m_localAnchor2:new b2Vec2(),m_u:new b2Vec2(),m_impulse:null,m_mass:null,m_length:null});
+var b2DistanceJointDef=Class.create();Object.extend(b2DistanceJointDef.prototype,b2JointDef.prototype);Object.extend(b2DistanceJointDef.prototype,{initialize:function()
+{this.type=b2Joint.e_unknownJoint;this.userData=null;this.body1=null;this.body2=null;this.collideConnected=false;this.anchorPoint1=new b2Vec2();this.anchorPoint2=new b2Vec2();this.type=b2Joint.e_distanceJoint;},anchorPoint1:new b2Vec2(),anchorPoint2:new b2Vec2()});
+var b2Jacobian=Class.create();b2Jacobian.prototype={linear1:new b2Vec2(),angular1:null,linear2:new b2Vec2(),angular2:null,SetZero:function(){this.linear1.SetZero();this.angular1=0.0;this.linear2.SetZero();this.angular2=0.0;},Set:function(x1,a1,x2,a2){this.linear1.SetV(x1);this.angular1=a1;this.linear2.SetV(x2);this.angular2=a2;},Compute:function(x1,a1,x2,a2){return(this.linear1.x*x1.x+this.linear1.y*x1.y)+this.angular1*a1+(this.linear2.x*x2.x+this.linear2.y*x2.y)+this.angular2*a2;},initialize:function(){this.linear1=new b2Vec2();this.linear2=new b2Vec2();}};
+var b2GearJoint=Class.create();Object.extend(b2GearJoint.prototype,b2Joint.prototype);Object.extend(b2GearJoint.prototype,{GetAnchor1:function(){var tMat=this.m_body1.m_R;return new b2Vec2(this.m_body1.m_position.x+(tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y),this.m_body1.m_position.y+(tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y));},GetAnchor2:function(){var tMat=this.m_body2.m_R;return new b2Vec2(this.m_body2.m_position.x+(tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y),this.m_body2.m_position.y+(tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y));},GetReactionForce:function(invTimeStep){return new b2Vec2();},GetReactionTorque:function(invTimeStep){return 0.0;},GetRatio:function(){return this.m_ratio;},initialize:function(def){this.m_node1=new b2JointNode();this.m_node2=new b2JointNode();this.m_type=def.type;this.m_prev=null;this.m_next=null;this.m_body1=def.body1;this.m_body2=def.body2;this.m_collideConnected=def.collideConnected;this.m_islandFlag=false;this.m_userData=def.userData;this.m_groundAnchor1=new b2Vec2();this.m_groundAnchor2=new b2Vec2();this.m_localAnchor1=new b2Vec2();this.m_localAnchor2=new b2Vec2();this.m_J=new b2Jacobian();this.m_revolute1=null;this.m_prismatic1=null;this.m_revolute2=null;this.m_prismatic2=null;var coordinate1;var coordinate2;this.m_ground1=def.joint1.m_body1;this.m_body1=def.joint1.m_body2;if(def.joint1.m_type==b2Joint.e_revoluteJoint)
+{this.m_revolute1=def.joint1;this.m_groundAnchor1.SetV(this.m_revolute1.m_localAnchor1);this.m_localAnchor1.SetV(this.m_revolute1.m_localAnchor2);coordinate1=this.m_revolute1.GetJointAngle();}
+else
+{this.m_prismatic1=def.joint1;this.m_groundAnchor1.SetV(this.m_prismatic1.m_localAnchor1);this.m_localAnchor1.SetV(this.m_prismatic1.m_localAnchor2);coordinate1=this.m_prismatic1.GetJointTranslation();}
+this.m_ground2=def.joint2.m_body1;this.m_body2=def.joint2.m_body2;if(def.joint2.m_type==b2Joint.e_revoluteJoint)
+{this.m_revolute2=def.joint2;this.m_groundAnchor2.SetV(this.m_revolute2.m_localAnchor1);this.m_localAnchor2.SetV(this.m_revolute2.m_localAnchor2);coordinate2=this.m_revolute2.GetJointAngle();}
+else
+{this.m_prismatic2=def.joint2;this.m_groundAnchor2.SetV(this.m_prismatic2.m_localAnchor1);this.m_localAnchor2.SetV(this.m_prismatic2.m_localAnchor2);coordinate2=this.m_prismatic2.GetJointTranslation();}
+this.m_ratio=def.ratio;this.m_constant=coordinate1+this.m_ratio*coordinate2;this.m_impulse=0.0;},PrepareVelocitySolver:function(){var g1=this.m_ground1;var g2=this.m_ground2;var b1=this.m_body1;var b2=this.m_body2;var ugX;var ugY;var rX;var rY;var tMat;var tVec;var crug;var K=0.0;this.m_J.SetZero();if(this.m_revolute1)
+{this.m_J.angular1=-1.0;K+=b1.m_invI;}
+else
+{tMat=g1.m_R;tVec=this.m_prismatic1.m_localXAxis1;ugX=tMat.col1.x*tVec.x+tMat.col2.x*tVec.y;ugY=tMat.col1.y*tVec.x+tMat.col2.y*tVec.y;tMat=b1.m_R;rX=tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y;rY=tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y;crug=rX*ugY-rY*ugX;this.m_J.linear1.Set(-ugX,-ugY);this.m_J.angular1=-crug;K+=b1.m_invMass+b1.m_invI*crug*crug;}
+if(this.m_revolute2)
+{this.m_J.angular2=-this.m_ratio;K+=this.m_ratio*this.m_ratio*b2.m_invI;}
+else
+{tMat=g2.m_R;tVec=this.m_prismatic2.m_localXAxis1;ugX=tMat.col1.x*tVec.x+tMat.col2.x*tVec.y;ugY=tMat.col1.y*tVec.x+tMat.col2.y*tVec.y;tMat=b2.m_R;rX=tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y;rY=tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y;crug=rX*ugY-rY*ugX;this.m_J.linear2.Set(-this.m_ratio*ugX,-this.m_ratio*ugY);this.m_J.angular2=-this.m_ratio*crug;K+=this.m_ratio*this.m_ratio*(b2.m_invMass+b2.m_invI*crug*crug);}
+this.m_mass=1.0/K;b1.m_linearVelocity.x+=b1.m_invMass*this.m_impulse*this.m_J.linear1.x;b1.m_linearVelocity.y+=b1.m_invMass*this.m_impulse*this.m_J.linear1.y;b1.m_angularVelocity+=b1.m_invI*this.m_impulse*this.m_J.angular1;b2.m_linearVelocity.x+=b2.m_invMass*this.m_impulse*this.m_J.linear2.x;b2.m_linearVelocity.y+=b2.m_invMass*this.m_impulse*this.m_J.linear2.y;b2.m_angularVelocity+=b2.m_invI*this.m_impulse*this.m_J.angular2;},SolveVelocityConstraints:function(step){var b1=this.m_body1;var b2=this.m_body2;var Cdot=this.m_J.Compute(b1.m_linearVelocity,b1.m_angularVelocity,b2.m_linearVelocity,b2.m_angularVelocity);var impulse=-this.m_mass*Cdot;this.m_impulse+=impulse;b1.m_linearVelocity.x+=b1.m_invMass*impulse*this.m_J.linear1.x;b1.m_linearVelocity.y+=b1.m_invMass*impulse*this.m_J.linear1.y;b1.m_angularVelocity+=b1.m_invI*impulse*this.m_J.angular1;b2.m_linearVelocity.x+=b2.m_invMass*impulse*this.m_J.linear2.x;b2.m_linearVelocity.y+=b2.m_invMass*impulse*this.m_J.linear2.y;b2.m_angularVelocity+=b2.m_invI*impulse*this.m_J.angular2;},SolvePositionConstraints:function(){var linearError=0.0;var b1=this.m_body1;var b2=this.m_body2;var coordinate1;var coordinate2;if(this.m_revolute1)
+{coordinate1=this.m_revolute1.GetJointAngle();}
+else
+{coordinate1=this.m_prismatic1.GetJointTranslation();}
+if(this.m_revolute2)
+{coordinate2=this.m_revolute2.GetJointAngle();}
+else
+{coordinate2=this.m_prismatic2.GetJointTranslation();}
+var C=this.m_constant-(coordinate1+this.m_ratio*coordinate2);var impulse=-this.m_mass*C;b1.m_position.x+=b1.m_invMass*impulse*this.m_J.linear1.x;b1.m_position.y+=b1.m_invMass*impulse*this.m_J.linear1.y;b1.m_rotation+=b1.m_invI*impulse*this.m_J.angular1;b2.m_position.x+=b2.m_invMass*impulse*this.m_J.linear2.x;b2.m_position.y+=b2.m_invMass*impulse*this.m_J.linear2.y;b2.m_rotation+=b2.m_invI*impulse*this.m_J.angular2;b1.m_R.Set(b1.m_rotation);b2.m_R.Set(b2.m_rotation);return linearError<b2Settings.b2_linearSlop;},m_ground1:null,m_ground2:null,m_revolute1:null,m_prismatic1:null,m_revolute2:null,m_prismatic2:null,m_groundAnchor1:new b2Vec2(),m_groundAnchor2:new b2Vec2(),m_localAnchor1:new b2Vec2(),m_localAnchor2:new b2Vec2(),m_J:new b2Jacobian(),m_constant:null,m_ratio:null,m_mass:null,m_impulse:null});
+var b2GearJointDef=Class.create();Object.extend(b2GearJointDef.prototype,b2JointDef.prototype);Object.extend(b2GearJointDef.prototype,{initialize:function()
+{this.type=b2Joint.e_gearJoint;this.joint1=null;this.joint2=null;this.ratio=1.0;},joint1:null,joint2:null,ratio:null});
+var b2MouseJoint=Class.create();Object.extend(b2MouseJoint.prototype,b2Joint.prototype);Object.extend(b2MouseJoint.prototype,{GetAnchor1:function(){return this.m_target;},GetAnchor2:function(){var tVec=b2Math.b2MulMV(this.m_body2.m_R,this.m_localAnchor);tVec.Add(this.m_body2.m_position);return tVec;},GetReactionForce:function(invTimeStep)
+{var F=new b2Vec2();F.SetV(this.m_impulse);F.Multiply(invTimeStep);return F;},GetReactionTorque:function(invTimeStep)
+{return 0.0;},SetTarget:function(target){this.m_body2.WakeUp();this.m_target=target;},initialize:function(def){this.m_node1=new b2JointNode();this.m_node2=new b2JointNode();this.m_type=def.type;this.m_prev=null;this.m_next=null;this.m_body1=def.body1;this.m_body2=def.body2;this.m_collideConnected=def.collideConnected;this.m_islandFlag=false;this.m_userData=def.userData;this.K=new b2Mat22();this.K1=new b2Mat22();this.K2=new b2Mat22();this.m_localAnchor=new b2Vec2();this.m_target=new b2Vec2();this.m_impulse=new b2Vec2();this.m_ptpMass=new b2Mat22();this.m_C=new b2Vec2();this.m_target.SetV(def.target);var tX=this.m_target.x-this.m_body2.m_position.x;var tY=this.m_target.y-this.m_body2.m_position.y;this.m_localAnchor.x=(tX*this.m_body2.m_R.col1.x+tY*this.m_body2.m_R.col1.y);this.m_localAnchor.y=(tX*this.m_body2.m_R.col2.x+tY*this.m_body2.m_R.col2.y);this.m_maxForce=def.maxForce;this.m_impulse.SetZero();var mass=this.m_body2.m_mass;var omega=2.0*b2Settings.b2_pi*def.frequencyHz;var d=2.0*mass*def.dampingRatio*omega;var k=mass*omega*omega;this.m_gamma=1.0/(d+def.timeStep*k);this.m_beta=def.timeStep*k/(d+def.timeStep*k);},K:new b2Mat22(),K1:new b2Mat22(),K2:new b2Mat22(),PrepareVelocitySolver:function(){var b=this.m_body2;var tMat;tMat=b.m_R;var rX=tMat.col1.x*this.m_localAnchor.x+tMat.col2.x*this.m_localAnchor.y;var rY=tMat.col1.y*this.m_localAnchor.x+tMat.col2.y*this.m_localAnchor.y;var invMass=b.m_invMass;var invI=b.m_invI;this.K1.col1.x=invMass;this.K1.col2.x=0.0;this.K1.col1.y=0.0;this.K1.col2.y=invMass;this.K2.col1.x=invI*rY*rY;this.K2.col2.x=-invI*rX*rY;this.K2.col1.y=-invI*rX*rY;this.K2.col2.y=invI*rX*rX;this.K.SetM(this.K1);this.K.AddM(this.K2);this.K.col1.x+=this.m_gamma;this.K.col2.y+=this.m_gamma;this.K.Invert(this.m_ptpMass);this.m_C.x=b.m_position.x+rX-this.m_target.x;this.m_C.y=b.m_position.y+rY-this.m_target.y;b.m_angularVelocity*=0.98;var PX=this.m_impulse.x;var PY=this.m_impulse.y;b.m_linearVelocity.x+=invMass*PX;b.m_linearVelocity.y+=invMass*PY;b.m_angularVelocity+=invI*(rX*PY-rY*PX);},SolveVelocityConstraints:function(step){var body=this.m_body2;var tMat;tMat=body.m_R;var rX=tMat.col1.x*this.m_localAnchor.x+tMat.col2.x*this.m_localAnchor.y;var rY=tMat.col1.y*this.m_localAnchor.x+tMat.col2.y*this.m_localAnchor.y;var CdotX=body.m_linearVelocity.x+(-body.m_angularVelocity*rY);var CdotY=body.m_linearVelocity.y+(body.m_angularVelocity*rX);tMat=this.m_ptpMass;var tX=CdotX+(this.m_beta*step.inv_dt)*this.m_C.x+this.m_gamma*this.m_impulse.x;var tY=CdotY+(this.m_beta*step.inv_dt)*this.m_C.y+this.m_gamma*this.m_impulse.y;var impulseX=-(tMat.col1.x*tX+tMat.col2.x*tY);var impulseY=-(tMat.col1.y*tX+tMat.col2.y*tY);var oldImpulseX=this.m_impulse.x;var oldImpulseY=this.m_impulse.y;this.m_impulse.x+=impulseX;this.m_impulse.y+=impulseY;var length=this.m_impulse.Length();if(length>step.dt*this.m_maxForce)
+{this.m_impulse.Multiply(step.dt*this.m_maxForce/length);}
+impulseX=this.m_impulse.x-oldImpulseX;impulseY=this.m_impulse.y-oldImpulseY;body.m_linearVelocity.x+=body.m_invMass*impulseX;body.m_linearVelocity.y+=body.m_invMass*impulseY;body.m_angularVelocity+=body.m_invI*(rX*impulseY-rY*impulseX);},SolvePositionConstraints:function(){return true;},m_localAnchor:new b2Vec2(),m_target:new b2Vec2(),m_impulse:new b2Vec2(),m_ptpMass:new b2Mat22(),m_C:new b2Vec2(),m_maxForce:null,m_beta:null,m_gamma:null});
+var b2MouseJointDef=Class.create();Object.extend(b2MouseJointDef.prototype,b2JointDef.prototype);Object.extend(b2MouseJointDef.prototype,{initialize:function()
+{this.type=b2Joint.e_unknownJoint;this.userData=null;this.body1=null;this.body2=null;this.collideConnected=false;this.target=new b2Vec2();this.type=b2Joint.e_mouseJoint;this.maxForce=0.0;this.frequencyHz=5.0;this.dampingRatio=0.7;this.timeStep=1.0/60.0;},target:new b2Vec2(),maxForce:null,frequencyHz:null,dampingRatio:null,timeStep:null});
+var b2PrismaticJoint=Class.create();Object.extend(b2PrismaticJoint.prototype,b2Joint.prototype);Object.extend(b2PrismaticJoint.prototype,{GetAnchor1:function(){var b1=this.m_body1;var tVec=new b2Vec2();tVec.SetV(this.m_localAnchor1);tVec.MulM(b1.m_R);tVec.Add(b1.m_position);return tVec;},GetAnchor2:function(){var b2=this.m_body2;var tVec=new b2Vec2();tVec.SetV(this.m_localAnchor2);tVec.MulM(b2.m_R);tVec.Add(b2.m_position);return tVec;},GetJointTranslation:function(){var b1=this.m_body1;var b2=this.m_body2;var tMat;tMat=b1.m_R;var r1X=tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y;var r1Y=tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y;tMat=b2.m_R;var r2X=tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y;var r2Y=tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y;var p1X=b1.m_position.x+r1X;var p1Y=b1.m_position.y+r1Y;var p2X=b2.m_position.x+r2X;var p2Y=b2.m_position.y+r2Y;var dX=p2X-p1X;var dY=p2Y-p1Y;tMat=b1.m_R;var ax1X=tMat.col1.x*this.m_localXAxis1.x+tMat.col2.x*this.m_localXAxis1.y;var ax1Y=tMat.col1.y*this.m_localXAxis1.x+tMat.col2.y*this.m_localXAxis1.y;var translation=ax1X*dX+ax1Y*dY;return translation;},GetJointSpeed:function(){var b1=this.m_body1;var b2=this.m_body2;var tMat;tMat=b1.m_R;var r1X=tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y;var r1Y=tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y;tMat=b2.m_R;var r2X=tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y;var r2Y=tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y;var p1X=b1.m_position.x+r1X;var p1Y=b1.m_position.y+r1Y;var p2X=b2.m_position.x+r2X;var p2Y=b2.m_position.y+r2Y;var dX=p2X-p1X;var dY=p2Y-p1Y;tMat=b1.m_R;var ax1X=tMat.col1.x*this.m_localXAxis1.x+tMat.col2.x*this.m_localXAxis1.y;var ax1Y=tMat.col1.y*this.m_localXAxis1.x+tMat.col2.y*this.m_localXAxis1.y;var v1=b1.m_linearVelocity;var v2=b2.m_linearVelocity;var w1=b1.m_angularVelocity;var w2=b2.m_angularVelocity;var speed=(dX*(-w1*ax1Y)+dY*(w1*ax1X))+(ax1X*(((v2.x+(-w2*r2Y))-v1.x)-(-w1*r1Y))+ax1Y*(((v2.y+(w2*r2X))-v1.y)-(w1*r1X)));return speed;},GetMotorForce:function(invTimeStep){return invTimeStep*this.m_motorImpulse;},SetMotorSpeed:function(speed)
+{this.m_motorSpeed=speed;},SetMotorForce:function(force)
+{this.m_maxMotorForce=force;},GetReactionForce:function(invTimeStep)
+{var tImp=invTimeStep*this.m_limitImpulse;var tMat;tMat=this.m_body1.m_R;var ax1X=tImp*(tMat.col1.x*this.m_localXAxis1.x+tMat.col2.x*this.m_localXAxis1.y);var ax1Y=tImp*(tMat.col1.y*this.m_localXAxis1.x+tMat.col2.y*this.m_localXAxis1.y);var ay1X=tImp*(tMat.col1.x*this.m_localYAxis1.x+tMat.col2.x*this.m_localYAxis1.y);var ay1Y=tImp*(tMat.col1.y*this.m_localYAxis1.x+tMat.col2.y*this.m_localYAxis1.y);return new b2Vec2(ax1X+ay1X,ax1Y+ay1Y);},GetReactionTorque:function(invTimeStep)
+{return invTimeStep*this.m_angularImpulse;},initialize:function(def){this.m_node1=new b2JointNode();this.m_node2=new b2JointNode();this.m_type=def.type;this.m_prev=null;this.m_next=null;this.m_body1=def.body1;this.m_body2=def.body2;this.m_collideConnected=def.collideConnected;this.m_islandFlag=false;this.m_userData=def.userData;this.m_localAnchor1=new b2Vec2();this.m_localAnchor2=new b2Vec2();this.m_localXAxis1=new b2Vec2();this.m_localYAxis1=new b2Vec2();this.m_linearJacobian=new b2Jacobian();this.m_motorJacobian=new b2Jacobian();var tMat;var tX;var tY;tMat=this.m_body1.m_R;tX=(def.anchorPoint.x-this.m_body1.m_position.x);tY=(def.anchorPoint.y-this.m_body1.m_position.y);this.m_localAnchor1.Set((tX*tMat.col1.x+tY*tMat.col1.y),(tX*tMat.col2.x+tY*tMat.col2.y));tMat=this.m_body2.m_R;tX=(def.anchorPoint.x-this.m_body2.m_position.x);tY=(def.anchorPoint.y-this.m_body2.m_position.y);this.m_localAnchor2.Set((tX*tMat.col1.x+tY*tMat.col1.y),(tX*tMat.col2.x+tY*tMat.col2.y));tMat=this.m_body1.m_R;tX=def.axis.x;tY=def.axis.y;this.m_localXAxis1.Set((tX*tMat.col1.x+tY*tMat.col1.y),(tX*tMat.col2.x+tY*tMat.col2.y));this.m_localYAxis1.x=-this.m_localXAxis1.y;this.m_localYAxis1.y=this.m_localXAxis1.x;this.m_initialAngle=this.m_body2.m_rotation-this.m_body1.m_rotation;this.m_linearJacobian.SetZero();this.m_linearMass=0.0;this.m_linearImpulse=0.0;this.m_angularMass=0.0;this.m_angularImpulse=0.0;this.m_motorJacobian.SetZero();this.m_motorMass=0.0;this.m_motorImpulse=0.0;this.m_limitImpulse=0.0;this.m_limitPositionImpulse=0.0;this.m_lowerTranslation=def.lowerTranslation;this.m_upperTranslation=def.upperTranslation;this.m_maxMotorForce=def.motorForce;this.m_motorSpeed=def.motorSpeed;this.m_enableLimit=def.enableLimit;this.m_enableMotor=def.enableMotor;},PrepareVelocitySolver:function(){var b1=this.m_body1;var b2=this.m_body2;var tMat;tMat=b1.m_R;var r1X=tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y;var r1Y=tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y;tMat=b2.m_R;var r2X=tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y;var r2Y=tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y;var invMass1=b1.m_invMass;var invMass2=b2.m_invMass;var invI1=b1.m_invI;var invI2=b2.m_invI;tMat=b1.m_R;var ay1X=tMat.col1.x*this.m_localYAxis1.x+tMat.col2.x*this.m_localYAxis1.y;var ay1Y=tMat.col1.y*this.m_localYAxis1.x+tMat.col2.y*this.m_localYAxis1.y;var eX=b2.m_position.x+r2X-b1.m_position.x;var eY=b2.m_position.y+r2Y-b1.m_position.y;this.m_linearJacobian.linear1.x=-ay1X;this.m_linearJacobian.linear1.y=-ay1Y;this.m_linearJacobian.linear2.x=ay1X;this.m_linearJacobian.linear2.y=ay1Y;this.m_linearJacobian.angular1=-(eX*ay1Y-eY*ay1X);this.m_linearJacobian.angular2=r2X*ay1Y-r2Y*ay1X;this.m_linearMass=invMass1+invI1*this.m_linearJacobian.angular1*this.m_linearJacobian.angular1+
+invMass2+invI2*this.m_linearJacobian.angular2*this.m_linearJacobian.angular2;this.m_linearMass=1.0/this.m_linearMass;this.m_angularMass=1.0/(invI1+invI2);if(this.m_enableLimit||this.m_enableMotor)
+{tMat=b1.m_R;var ax1X=tMat.col1.x*this.m_localXAxis1.x+tMat.col2.x*this.m_localXAxis1.y;var ax1Y=tMat.col1.y*this.m_localXAxis1.x+tMat.col2.y*this.m_localXAxis1.y;this.m_motorJacobian.linear1.x=-ax1X;this.m_motorJacobian.linear1.y=-ax1Y;this.m_motorJacobian.linear2.x=ax1X;this.m_motorJacobian.linear2.y=ax1Y;this.m_motorJacobian.angular1=-(eX*ax1Y-eY*ax1X);this.m_motorJacobian.angular2=r2X*ax1Y-r2Y*ax1X;this.m_motorMass=invMass1+invI1*this.m_motorJacobian.angular1*this.m_motorJacobian.angular1+
+invMass2+invI2*this.m_motorJacobian.angular2*this.m_motorJacobian.angular2;this.m_motorMass=1.0/this.m_motorMass;if(this.m_enableLimit)
+{var dX=eX-r1X;var dY=eY-r1Y;var jointTranslation=ax1X*dX+ax1Y*dY;if(b2Math.b2Abs(this.m_upperTranslation-this.m_lowerTranslation)<2.0*b2Settings.b2_linearSlop)
+{this.m_limitState=b2Joint.e_equalLimits;}
+else if(jointTranslation<=this.m_lowerTranslation)
+{if(this.m_limitState!=b2Joint.e_atLowerLimit)
+{this.m_limitImpulse=0.0;}
+this.m_limitState=b2Joint.e_atLowerLimit;}
+else if(jointTranslation>=this.m_upperTranslation)
+{if(this.m_limitState!=b2Joint.e_atUpperLimit)
+{this.m_limitImpulse=0.0;}
+this.m_limitState=b2Joint.e_atUpperLimit;}
+else
+{this.m_limitState=b2Joint.e_inactiveLimit;this.m_limitImpulse=0.0;}}}
+if(this.m_enableMotor==false)
+{this.m_motorImpulse=0.0;}
+if(this.m_enableLimit==false)
+{this.m_limitImpulse=0.0;}
+if(b2World.s_enableWarmStarting)
+{var P1X=this.m_linearImpulse*this.m_linearJacobian.linear1.x+(this.m_motorImpulse+this.m_limitImpulse)*this.m_motorJacobian.linear1.x;var P1Y=this.m_linearImpulse*this.m_linearJacobian.linear1.y+(this.m_motorImpulse+this.m_limitImpulse)*this.m_motorJacobian.linear1.y;var P2X=this.m_linearImpulse*this.m_linearJacobian.linear2.x+(this.m_motorImpulse+this.m_limitImpulse)*this.m_motorJacobian.linear2.x;var P2Y=this.m_linearImpulse*this.m_linearJacobian.linear2.y+(this.m_motorImpulse+this.m_limitImpulse)*this.m_motorJacobian.linear2.y;var L1=this.m_linearImpulse*this.m_linearJacobian.angular1-this.m_angularImpulse+(this.m_motorImpulse+this.m_limitImpulse)*this.m_motorJacobian.angular1;var L2=this.m_linearImpulse*this.m_linearJacobian.angular2+this.m_angularImpulse+(this.m_motorImpulse+this.m_limitImpulse)*this.m_motorJacobian.angular2;b1.m_linearVelocity.x+=invMass1*P1X;b1.m_linearVelocity.y+=invMass1*P1Y;b1.m_angularVelocity+=invI1*L1;b2.m_linearVelocity.x+=invMass2*P2X;b2.m_linearVelocity.y+=invMass2*P2Y;b2.m_angularVelocity+=invI2*L2;}
+else
+{this.m_linearImpulse=0.0;this.m_angularImpulse=0.0;this.m_limitImpulse=0.0;this.m_motorImpulse=0.0;}
+this.m_limitPositionImpulse=0.0;},SolveVelocityConstraints:function(step){var b1=this.m_body1;var b2=this.m_body2;var invMass1=b1.m_invMass;var invMass2=b2.m_invMass;var invI1=b1.m_invI;var invI2=b2.m_invI;var oldLimitImpulse;var linearCdot=this.m_linearJacobian.Compute(b1.m_linearVelocity,b1.m_angularVelocity,b2.m_linearVelocity,b2.m_angularVelocity);var linearImpulse=-this.m_linearMass*linearCdot;this.m_linearImpulse+=linearImpulse;b1.m_linearVelocity.x+=(invMass1*linearImpulse)*this.m_linearJacobian.linear1.x;b1.m_linearVelocity.y+=(invMass1*linearImpulse)*this.m_linearJacobian.linear1.y;b1.m_angularVelocity+=invI1*linearImpulse*this.m_linearJacobian.angular1;b2.m_linearVelocity.x+=(invMass2*linearImpulse)*this.m_linearJacobian.linear2.x;b2.m_linearVelocity.y+=(invMass2*linearImpulse)*this.m_linearJacobian.linear2.y;b2.m_angularVelocity+=invI2*linearImpulse*this.m_linearJacobian.angular2;var angularCdot=b2.m_angularVelocity-b1.m_angularVelocity;var angularImpulse=-this.m_angularMass*angularCdot;this.m_angularImpulse+=angularImpulse;b1.m_angularVelocity-=invI1*angularImpulse;b2.m_angularVelocity+=invI2*angularImpulse;if(this.m_enableMotor&&this.m_limitState!=b2Joint.e_equalLimits)
+{var motorCdot=this.m_motorJacobian.Compute(b1.m_linearVelocity,b1.m_angularVelocity,b2.m_linearVelocity,b2.m_angularVelocity)-this.m_motorSpeed;var motorImpulse=-this.m_motorMass*motorCdot;var oldMotorImpulse=this.m_motorImpulse;this.m_motorImpulse=b2Math.b2Clamp(this.m_motorImpulse+motorImpulse,-step.dt*this.m_maxMotorForce,step.dt*this.m_maxMotorForce);motorImpulse=this.m_motorImpulse-oldMotorImpulse;b1.m_linearVelocity.x+=(invMass1*motorImpulse)*this.m_motorJacobian.linear1.x;b1.m_linearVelocity.y+=(invMass1*motorImpulse)*this.m_motorJacobian.linear1.y;b1.m_angularVelocity+=invI1*motorImpulse*this.m_motorJacobian.angular1;b2.m_linearVelocity.x+=(invMass2*motorImpulse)*this.m_motorJacobian.linear2.x;b2.m_linearVelocity.y+=(invMass2*motorImpulse)*this.m_motorJacobian.linear2.y;b2.m_angularVelocity+=invI2*motorImpulse*this.m_motorJacobian.angular2;}
+if(this.m_enableLimit&&this.m_limitState!=b2Joint.e_inactiveLimit)
+{var limitCdot=this.m_motorJacobian.Compute(b1.m_linearVelocity,b1.m_angularVelocity,b2.m_linearVelocity,b2.m_angularVelocity);var limitImpulse=-this.m_motorMass*limitCdot;if(this.m_limitState==b2Joint.e_equalLimits)
+{this.m_limitImpulse+=limitImpulse;}
+else if(this.m_limitState==b2Joint.e_atLowerLimit)
+{oldLimitImpulse=this.m_limitImpulse;this.m_limitImpulse=b2Math.b2Max(this.m_limitImpulse+limitImpulse,0.0);limitImpulse=this.m_limitImpulse-oldLimitImpulse;}
+else if(this.m_limitState==b2Joint.e_atUpperLimit)
+{oldLimitImpulse=this.m_limitImpulse;this.m_limitImpulse=b2Math.b2Min(this.m_limitImpulse+limitImpulse,0.0);limitImpulse=this.m_limitImpulse-oldLimitImpulse;}
+b1.m_linearVelocity.x+=(invMass1*limitImpulse)*this.m_motorJacobian.linear1.x;b1.m_linearVelocity.y+=(invMass1*limitImpulse)*this.m_motorJacobian.linear1.y;b1.m_angularVelocity+=invI1*limitImpulse*this.m_motorJacobian.angular1;b2.m_linearVelocity.x+=(invMass2*limitImpulse)*this.m_motorJacobian.linear2.x;b2.m_linearVelocity.y+=(invMass2*limitImpulse)*this.m_motorJacobian.linear2.y;b2.m_angularVelocity+=invI2*limitImpulse*this.m_motorJacobian.angular2;}},SolvePositionConstraints:function(){var limitC;var oldLimitImpulse;var b1=this.m_body1;var b2=this.m_body2;var invMass1=b1.m_invMass;var invMass2=b2.m_invMass;var invI1=b1.m_invI;var invI2=b2.m_invI;var tMat;tMat=b1.m_R;var r1X=tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y;var r1Y=tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y;tMat=b2.m_R;var r2X=tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y;var r2Y=tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y;var p1X=b1.m_position.x+r1X;var p1Y=b1.m_position.y+r1Y;var p2X=b2.m_position.x+r2X;var p2Y=b2.m_position.y+r2Y;var dX=p2X-p1X;var dY=p2Y-p1Y;tMat=b1.m_R;var ay1X=tMat.col1.x*this.m_localYAxis1.x+tMat.col2.x*this.m_localYAxis1.y;var ay1Y=tMat.col1.y*this.m_localYAxis1.x+tMat.col2.y*this.m_localYAxis1.y;var linearC=ay1X*dX+ay1Y*dY;linearC=b2Math.b2Clamp(linearC,-b2Settings.b2_maxLinearCorrection,b2Settings.b2_maxLinearCorrection);var linearImpulse=-this.m_linearMass*linearC;b1.m_position.x+=(invMass1*linearImpulse)*this.m_linearJacobian.linear1.x;b1.m_position.y+=(invMass1*linearImpulse)*this.m_linearJacobian.linear1.y;b1.m_rotation+=invI1*linearImpulse*this.m_linearJacobian.angular1;b2.m_position.x+=(invMass2*linearImpulse)*this.m_linearJacobian.linear2.x;b2.m_position.y+=(invMass2*linearImpulse)*this.m_linearJacobian.linear2.y;b2.m_rotation+=invI2*linearImpulse*this.m_linearJacobian.angular2;var positionError=b2Math.b2Abs(linearC);var angularC=b2.m_rotation-b1.m_rotation-this.m_initialAngle;angularC=b2Math.b2Clamp(angularC,-b2Settings.b2_maxAngularCorrection,b2Settings.b2_maxAngularCorrection);var angularImpulse=-this.m_angularMass*angularC;b1.m_rotation-=b1.m_invI*angularImpulse;b1.m_R.Set(b1.m_rotation);b2.m_rotation+=b2.m_invI*angularImpulse;b2.m_R.Set(b2.m_rotation);var angularError=b2Math.b2Abs(angularC);if(this.m_enableLimit&&this.m_limitState!=b2Joint.e_inactiveLimit)
+{tMat=b1.m_R;r1X=tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y;r1Y=tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y;tMat=b2.m_R;r2X=tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y;r2Y=tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y;p1X=b1.m_position.x+r1X;p1Y=b1.m_position.y+r1Y;p2X=b2.m_position.x+r2X;p2Y=b2.m_position.y+r2Y;dX=p2X-p1X;dY=p2Y-p1Y;tMat=b1.m_R;var ax1X=tMat.col1.x*this.m_localXAxis1.x+tMat.col2.x*this.m_localXAxis1.y;var ax1Y=tMat.col1.y*this.m_localXAxis1.x+tMat.col2.y*this.m_localXAxis1.y;var translation=(ax1X*dX+ax1Y*dY);var limitImpulse=0.0;if(this.m_limitState==b2Joint.e_equalLimits)
+{limitC=b2Math.b2Clamp(translation,-b2Settings.b2_maxLinearCorrection,b2Settings.b2_maxLinearCorrection);limitImpulse=-this.m_motorMass*limitC;positionError=b2Math.b2Max(positionError,b2Math.b2Abs(angularC));}
+else if(this.m_limitState==b2Joint.e_atLowerLimit)
+{limitC=translation-this.m_lowerTranslation;positionError=b2Math.b2Max(positionError,-limitC);limitC=b2Math.b2Clamp(limitC+b2Settings.b2_linearSlop,-b2Settings.b2_maxLinearCorrection,0.0);limitImpulse=-this.m_motorMass*limitC;oldLimitImpulse=this.m_limitPositionImpulse;this.m_limitPositionImpulse=b2Math.b2Max(this.m_limitPositionImpulse+limitImpulse,0.0);limitImpulse=this.m_limitPositionImpulse-oldLimitImpulse;}
+else if(this.m_limitState==b2Joint.e_atUpperLimit)
+{limitC=translation-this.m_upperTranslation;positionError=b2Math.b2Max(positionError,limitC);limitC=b2Math.b2Clamp(limitC-b2Settings.b2_linearSlop,0.0,b2Settings.b2_maxLinearCorrection);limitImpulse=-this.m_motorMass*limitC;oldLimitImpulse=this.m_limitPositionImpulse;this.m_limitPositionImpulse=b2Math.b2Min(this.m_limitPositionImpulse+limitImpulse,0.0);limitImpulse=this.m_limitPositionImpulse-oldLimitImpulse;}
+b1.m_position.x+=(invMass1*limitImpulse)*this.m_motorJacobian.linear1.x;b1.m_position.y+=(invMass1*limitImpulse)*this.m_motorJacobian.linear1.y;b1.m_rotation+=invI1*limitImpulse*this.m_motorJacobian.angular1;b1.m_R.Set(b1.m_rotation);b2.m_position.x+=(invMass2*limitImpulse)*this.m_motorJacobian.linear2.x;b2.m_position.y+=(invMass2*limitImpulse)*this.m_motorJacobian.linear2.y;b2.m_rotation+=invI2*limitImpulse*this.m_motorJacobian.angular2;b2.m_R.Set(b2.m_rotation);}
+return positionError<=b2Settings.b2_linearSlop&&angularError<=b2Settings.b2_angularSlop;},m_localAnchor1:new b2Vec2(),m_localAnchor2:new b2Vec2(),m_localXAxis1:new b2Vec2(),m_localYAxis1:new b2Vec2(),m_initialAngle:null,m_linearJacobian:new b2Jacobian(),m_linearMass:null,m_linearImpulse:null,m_angularMass:null,m_angularImpulse:null,m_motorJacobian:new b2Jacobian(),m_motorMass:null,m_motorImpulse:null,m_limitImpulse:null,m_limitPositionImpulse:null,m_lowerTranslation:null,m_upperTranslation:null,m_maxMotorForce:null,m_motorSpeed:null,m_enableLimit:null,m_enableMotor:null,m_limitState:0});
+var b2PrismaticJointDef=Class.create();Object.extend(b2PrismaticJointDef.prototype,b2JointDef.prototype);Object.extend(b2PrismaticJointDef.prototype,{initialize:function()
+{this.type=b2Joint.e_unknownJoint;this.userData=null;this.body1=null;this.body2=null;this.collideConnected=false;this.type=b2Joint.e_prismaticJoint;this.anchorPoint=new b2Vec2(0.0,0.0);this.axis=new b2Vec2(0.0,0.0);this.lowerTranslation=0.0;this.upperTranslation=0.0;this.motorForce=0.0;this.motorSpeed=0.0;this.enableLimit=false;this.enableMotor=false;},anchorPoint:null,axis:null,lowerTranslation:null,upperTranslation:null,motorForce:null,motorSpeed:null,enableLimit:null,enableMotor:null});
+var b2PulleyJoint=Class.create();Object.extend(b2PulleyJoint.prototype,b2Joint.prototype);Object.extend(b2PulleyJoint.prototype,{GetAnchor1:function(){var tMat=this.m_body1.m_R;return new b2Vec2(this.m_body1.m_position.x+(tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y),this.m_body1.m_position.y+(tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y));},GetAnchor2:function(){var tMat=this.m_body2.m_R;return new b2Vec2(this.m_body2.m_position.x+(tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y),this.m_body2.m_position.y+(tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y));},GetGroundPoint1:function(){return new b2Vec2(this.m_ground.m_position.x+this.m_groundAnchor1.x,this.m_ground.m_position.y+this.m_groundAnchor1.y);},GetGroundPoint2:function(){return new b2Vec2(this.m_ground.m_position.x+this.m_groundAnchor2.x,this.m_ground.m_position.y+this.m_groundAnchor2.y);},GetReactionForce:function(invTimeStep){return new b2Vec2();},GetReactionTorque:function(invTimeStep){return 0.0;},GetLength1:function(){var tMat;tMat=this.m_body1.m_R;var pX=this.m_body1.m_position.x+(tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y);var pY=this.m_body1.m_position.y+(tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y);var dX=pX-(this.m_ground.m_position.x+this.m_groundAnchor1.x);var dY=pY-(this.m_ground.m_position.y+this.m_groundAnchor1.y);return Math.sqrt(dX*dX+dY*dY);},GetLength2:function(){var tMat;tMat=this.m_body2.m_R;var pX=this.m_body2.m_position.x+(tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y);var pY=this.m_body2.m_position.y+(tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y);var dX=pX-(this.m_ground.m_position.x+this.m_groundAnchor2.x);var dY=pY-(this.m_ground.m_position.y+this.m_groundAnchor2.y);return Math.sqrt(dX*dX+dY*dY);},GetRatio:function(){return this.m_ratio;},initialize:function(def){this.m_node1=new b2JointNode();this.m_node2=new b2JointNode();this.m_type=def.type;this.m_prev=null;this.m_next=null;this.m_body1=def.body1;this.m_body2=def.body2;this.m_collideConnected=def.collideConnected;this.m_islandFlag=false;this.m_userData=def.userData;this.m_groundAnchor1=new b2Vec2();this.m_groundAnchor2=new b2Vec2();this.m_localAnchor1=new b2Vec2();this.m_localAnchor2=new b2Vec2();this.m_u1=new b2Vec2();this.m_u2=new b2Vec2();var tMat;var tX;var tY;this.m_ground=this.m_body1.m_world.m_groundBody;this.m_groundAnchor1.x=def.groundPoint1.x-this.m_ground.m_position.x;this.m_groundAnchor1.y=def.groundPoint1.y-this.m_ground.m_position.y;this.m_groundAnchor2.x=def.groundPoint2.x-this.m_ground.m_position.x;this.m_groundAnchor2.y=def.groundPoint2.y-this.m_ground.m_position.y;tMat=this.m_body1.m_R;tX=def.anchorPoint1.x-this.m_body1.m_position.x;tY=def.anchorPoint1.y-this.m_body1.m_position.y;this.m_localAnchor1.x=tX*tMat.col1.x+tY*tMat.col1.y;this.m_localAnchor1.y=tX*tMat.col2.x+tY*tMat.col2.y;tMat=this.m_body2.m_R;tX=def.anchorPoint2.x-this.m_body2.m_position.x;tY=def.anchorPoint2.y-this.m_body2.m_position.y;this.m_localAnchor2.x=tX*tMat.col1.x+tY*tMat.col1.y;this.m_localAnchor2.y=tX*tMat.col2.x+tY*tMat.col2.y;this.m_ratio=def.ratio;tX=def.groundPoint1.x-def.anchorPoint1.x;tY=def.groundPoint1.y-def.anchorPoint1.y;var d1Len=Math.sqrt(tX*tX+tY*tY);tX=def.groundPoint2.x-def.anchorPoint2.x;tY=def.groundPoint2.y-def.anchorPoint2.y;var d2Len=Math.sqrt(tX*tX+tY*tY);var length1=b2Math.b2Max(0.5*b2PulleyJoint.b2_minPulleyLength,d1Len);var length2=b2Math.b2Max(0.5*b2PulleyJoint.b2_minPulleyLength,d2Len);this.m_constant=length1+this.m_ratio*length2;this.m_maxLength1=b2Math.b2Clamp(def.maxLength1,length1,this.m_constant-this.m_ratio*b2PulleyJoint.b2_minPulleyLength);this.m_maxLength2=b2Math.b2Clamp(def.maxLength2,length2,(this.m_constant-b2PulleyJoint.b2_minPulleyLength)/this.m_ratio);this.m_pulleyImpulse=0.0;this.m_limitImpulse1=0.0;this.m_limitImpulse2=0.0;},PrepareVelocitySolver:function(){var b1=this.m_body1;var b2=this.m_body2;var tMat;tMat=b1.m_R;var r1X=tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y;var r1Y=tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y;tMat=b2.m_R;var r2X=tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y;var r2Y=tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y;var p1X=b1.m_position.x+r1X;var p1Y=b1.m_position.y+r1Y;var p2X=b2.m_position.x+r2X;var p2Y=b2.m_position.y+r2Y;var s1X=this.m_ground.m_position.x+this.m_groundAnchor1.x;var s1Y=this.m_ground.m_position.y+this.m_groundAnchor1.y;var s2X=this.m_ground.m_position.x+this.m_groundAnchor2.x;var s2Y=this.m_ground.m_position.y+this.m_groundAnchor2.y;this.m_u1.Set(p1X-s1X,p1Y-s1Y);this.m_u2.Set(p2X-s2X,p2Y-s2Y);var length1=this.m_u1.Length();var length2=this.m_u2.Length();if(length1>b2Settings.b2_linearSlop)
+{this.m_u1.Multiply(1.0/length1);}
+else
+{this.m_u1.SetZero();}
+if(length2>b2Settings.b2_linearSlop)
+{this.m_u2.Multiply(1.0/length2);}
+else
+{this.m_u2.SetZero();}
+if(length1<this.m_maxLength1)
+{this.m_limitState1=b2Joint.e_inactiveLimit;this.m_limitImpulse1=0.0;}
+else
+{this.m_limitState1=b2Joint.e_atUpperLimit;this.m_limitPositionImpulse1=0.0;}
+if(length2<this.m_maxLength2)
+{this.m_limitState2=b2Joint.e_inactiveLimit;this.m_limitImpulse2=0.0;}
+else
+{this.m_limitState2=b2Joint.e_atUpperLimit;this.m_limitPositionImpulse2=0.0;}
+var cr1u1=r1X*this.m_u1.y-r1Y*this.m_u1.x;var cr2u2=r2X*this.m_u2.y-r2Y*this.m_u2.x;this.m_limitMass1=b1.m_invMass+b1.m_invI*cr1u1*cr1u1;this.m_limitMass2=b2.m_invMass+b2.m_invI*cr2u2*cr2u2;this.m_pulleyMass=this.m_limitMass1+this.m_ratio*this.m_ratio*this.m_limitMass2;this.m_limitMass1=1.0/this.m_limitMass1;this.m_limitMass2=1.0/this.m_limitMass2;this.m_pulleyMass=1.0/this.m_pulleyMass;var P1X=(-this.m_pulleyImpulse-this.m_limitImpulse1)*this.m_u1.x;var P1Y=(-this.m_pulleyImpulse-this.m_limitImpulse1)*this.m_u1.y;var P2X=(-this.m_ratio*this.m_pulleyImpulse-this.m_limitImpulse2)*this.m_u2.x;var P2Y=(-this.m_ratio*this.m_pulleyImpulse-this.m_limitImpulse2)*this.m_u2.y;b1.m_linearVelocity.x+=b1.m_invMass*P1X;b1.m_linearVelocity.y+=b1.m_invMass*P1Y;b1.m_angularVelocity+=b1.m_invI*(r1X*P1Y-r1Y*P1X);b2.m_linearVelocity.x+=b2.m_invMass*P2X;b2.m_linearVelocity.y+=b2.m_invMass*P2Y;b2.m_angularVelocity+=b2.m_invI*(r2X*P2Y-r2Y*P2X);},SolveVelocityConstraints:function(step){var b1=this.m_body1;var b2=this.m_body2;var tMat;tMat=b1.m_R;var r1X=tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y;var r1Y=tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y;tMat=b2.m_R;var r2X=tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y;var r2Y=tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y;var v1X;var v1Y;var v2X;var v2Y;var P1X;var P1Y;var P2X;var P2Y;var Cdot;var impulse;var oldLimitImpulse;v1X=b1.m_linearVelocity.x+(-b1.m_angularVelocity*r1Y);v1Y=b1.m_linearVelocity.y+(b1.m_angularVelocity*r1X);v2X=b2.m_linearVelocity.x+(-b2.m_angularVelocity*r2Y);v2Y=b2.m_linearVelocity.y+(b2.m_angularVelocity*r2X);Cdot=-(this.m_u1.x*v1X+this.m_u1.y*v1Y)-this.m_ratio*(this.m_u2.x*v2X+this.m_u2.y*v2Y);impulse=-this.m_pulleyMass*Cdot;this.m_pulleyImpulse+=impulse;P1X=-impulse*this.m_u1.x;P1Y=-impulse*this.m_u1.y;P2X=-this.m_ratio*impulse*this.m_u2.x;P2Y=-this.m_ratio*impulse*this.m_u2.y;b1.m_linearVelocity.x+=b1.m_invMass*P1X;b1.m_linearVelocity.y+=b1.m_invMass*P1Y;b1.m_angularVelocity+=b1.m_invI*(r1X*P1Y-r1Y*P1X);b2.m_linearVelocity.x+=b2.m_invMass*P2X;b2.m_linearVelocity.y+=b2.m_invMass*P2Y;b2.m_angularVelocity+=b2.m_invI*(r2X*P2Y-r2Y*P2X);if(this.m_limitState1==b2Joint.e_atUpperLimit)
+{v1X=b1.m_linearVelocity.x+(-b1.m_angularVelocity*r1Y);v1Y=b1.m_linearVelocity.y+(b1.m_angularVelocity*r1X);Cdot=-(this.m_u1.x*v1X+this.m_u1.y*v1Y);impulse=-this.m_limitMass1*Cdot;oldLimitImpulse=this.m_limitImpulse1;this.m_limitImpulse1=b2Math.b2Max(0.0,this.m_limitImpulse1+impulse);impulse=this.m_limitImpulse1-oldLimitImpulse;P1X=-impulse*this.m_u1.x;P1Y=-impulse*this.m_u1.y;b1.m_linearVelocity.x+=b1.m_invMass*P1X;b1.m_linearVelocity.y+=b1.m_invMass*P1Y;b1.m_angularVelocity+=b1.m_invI*(r1X*P1Y-r1Y*P1X);}
+if(this.m_limitState2==b2Joint.e_atUpperLimit)
+{v2X=b2.m_linearVelocity.x+(-b2.m_angularVelocity*r2Y);v2Y=b2.m_linearVelocity.y+(b2.m_angularVelocity*r2X);Cdot=-(this.m_u2.x*v2X+this.m_u2.y*v2Y);impulse=-this.m_limitMass2*Cdot;oldLimitImpulse=this.m_limitImpulse2;this.m_limitImpulse2=b2Math.b2Max(0.0,this.m_limitImpulse2+impulse);impulse=this.m_limitImpulse2-oldLimitImpulse;P2X=-impulse*this.m_u2.x;P2Y=-impulse*this.m_u2.y;b2.m_linearVelocity.x+=b2.m_invMass*P2X;b2.m_linearVelocity.y+=b2.m_invMass*P2Y;b2.m_angularVelocity+=b2.m_invI*(r2X*P2Y-r2Y*P2X);}},SolvePositionConstraints:function(){var b1=this.m_body1;var b2=this.m_body2;var tMat;var s1X=this.m_ground.m_position.x+this.m_groundAnchor1.x;var s1Y=this.m_ground.m_position.y+this.m_groundAnchor1.y;var s2X=this.m_ground.m_position.x+this.m_groundAnchor2.x;var s2Y=this.m_ground.m_position.y+this.m_groundAnchor2.y;var r1X;var r1Y;var r2X;var r2Y;var p1X;var p1Y;var p2X;var p2Y;var length1;var length2;var C;var impulse;var oldLimitPositionImpulse;var linearError=0.0;{tMat=b1.m_R;r1X=tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y;r1Y=tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y;tMat=b2.m_R;r2X=tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y;r2Y=tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y;p1X=b1.m_position.x+r1X;p1Y=b1.m_position.y+r1Y;p2X=b2.m_position.x+r2X;p2Y=b2.m_position.y+r2Y;this.m_u1.Set(p1X-s1X,p1Y-s1Y);this.m_u2.Set(p2X-s2X,p2Y-s2Y);length1=this.m_u1.Length();length2=this.m_u2.Length();if(length1>b2Settings.b2_linearSlop)
+{this.m_u1.Multiply(1.0/length1);}
+else
+{this.m_u1.SetZero();}
+if(length2>b2Settings.b2_linearSlop)
+{this.m_u2.Multiply(1.0/length2);}
+else
+{this.m_u2.SetZero();}
+C=this.m_constant-length1-this.m_ratio*length2;linearError=b2Math.b2Max(linearError,Math.abs(C));C=b2Math.b2Clamp(C,-b2Settings.b2_maxLinearCorrection,b2Settings.b2_maxLinearCorrection);impulse=-this.m_pulleyMass*C;p1X=-impulse*this.m_u1.x;p1Y=-impulse*this.m_u1.y;p2X=-this.m_ratio*impulse*this.m_u2.x;p2Y=-this.m_ratio*impulse*this.m_u2.y;b1.m_position.x+=b1.m_invMass*p1X;b1.m_position.y+=b1.m_invMass*p1Y;b1.m_rotation+=b1.m_invI*(r1X*p1Y-r1Y*p1X);b2.m_position.x+=b2.m_invMass*p2X;b2.m_position.y+=b2.m_invMass*p2Y;b2.m_rotation+=b2.m_invI*(r2X*p2Y-r2Y*p2X);b1.m_R.Set(b1.m_rotation);b2.m_R.Set(b2.m_rotation);}
+if(this.m_limitState1==b2Joint.e_atUpperLimit)
+{tMat=b1.m_R;r1X=tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y;r1Y=tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y;p1X=b1.m_position.x+r1X;p1Y=b1.m_position.y+r1Y;this.m_u1.Set(p1X-s1X,p1Y-s1Y);length1=this.m_u1.Length();if(length1>b2Settings.b2_linearSlop)
+{this.m_u1.x*=1.0/length1;this.m_u1.y*=1.0/length1;}
+else
+{this.m_u1.SetZero();}
+C=this.m_maxLength1-length1;linearError=b2Math.b2Max(linearError,-C);C=b2Math.b2Clamp(C+b2Settings.b2_linearSlop,-b2Settings.b2_maxLinearCorrection,0.0);impulse=-this.m_limitMass1*C;oldLimitPositionImpulse=this.m_limitPositionImpulse1;this.m_limitPositionImpulse1=b2Math.b2Max(0.0,this.m_limitPositionImpulse1+impulse);impulse=this.m_limitPositionImpulse1-oldLimitPositionImpulse;p1X=-impulse*this.m_u1.x;p1Y=-impulse*this.m_u1.y;b1.m_position.x+=b1.m_invMass*p1X;b1.m_position.y+=b1.m_invMass*p1Y;b1.m_rotation+=b1.m_invI*(r1X*p1Y-r1Y*p1X);b1.m_R.Set(b1.m_rotation);}
+if(this.m_limitState2==b2Joint.e_atUpperLimit)
+{tMat=b2.m_R;r2X=tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y;r2Y=tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y;p2X=b2.m_position.x+r2X;p2Y=b2.m_position.y+r2Y;this.m_u2.Set(p2X-s2X,p2Y-s2Y);length2=this.m_u2.Length();if(length2>b2Settings.b2_linearSlop)
+{this.m_u2.x*=1.0/length2;this.m_u2.y*=1.0/length2;}
+else
+{this.m_u2.SetZero();}
+C=this.m_maxLength2-length2;linearError=b2Math.b2Max(linearError,-C);C=b2Math.b2Clamp(C+b2Settings.b2_linearSlop,-b2Settings.b2_maxLinearCorrection,0.0);impulse=-this.m_limitMass2*C;oldLimitPositionImpulse=this.m_limitPositionImpulse2;this.m_limitPositionImpulse2=b2Math.b2Max(0.0,this.m_limitPositionImpulse2+impulse);impulse=this.m_limitPositionImpulse2-oldLimitPositionImpulse;p2X=-impulse*this.m_u2.x;p2Y=-impulse*this.m_u2.y;b2.m_position.x+=b2.m_invMass*p2X;b2.m_position.y+=b2.m_invMass*p2Y;b2.m_rotation+=b2.m_invI*(r2X*p2Y-r2Y*p2X);b2.m_R.Set(b2.m_rotation);}
+return linearError<b2Settings.b2_linearSlop;},m_ground:null,m_groundAnchor1:new b2Vec2(),m_groundAnchor2:new b2Vec2(),m_localAnchor1:new b2Vec2(),m_localAnchor2:new b2Vec2(),m_u1:new b2Vec2(),m_u2:new b2Vec2(),m_constant:null,m_ratio:null,m_maxLength1:null,m_maxLength2:null,m_pulleyMass:null,m_limitMass1:null,m_limitMass2:null,m_pulleyImpulse:null,m_limitImpulse1:null,m_limitImpulse2:null,m_limitPositionImpulse1:null,m_limitPositionImpulse2:null,m_limitState1:0,m_limitState2:0});b2PulleyJoint.b2_minPulleyLength=b2Settings.b2_lengthUnitsPerMeter;
+var b2PulleyJointDef=Class.create();Object.extend(b2PulleyJointDef.prototype,b2JointDef.prototype);Object.extend(b2PulleyJointDef.prototype,{initialize:function()
+{this.type=b2Joint.e_unknownJoint;this.userData=null;this.body1=null;this.body2=null;this.collideConnected=false;this.groundPoint1=new b2Vec2();this.groundPoint2=new b2Vec2();this.anchorPoint1=new b2Vec2();this.anchorPoint2=new b2Vec2();this.type=b2Joint.e_pulleyJoint;this.groundPoint1.Set(-1.0,1.0);this.groundPoint2.Set(1.0,1.0);this.anchorPoint1.Set(-1.0,0.0);this.anchorPoint2.Set(1.0,0.0);this.maxLength1=0.5*b2PulleyJoint.b2_minPulleyLength;this.maxLength2=0.5*b2PulleyJoint.b2_minPulleyLength;this.ratio=1.0;this.collideConnected=true;},groundPoint1:new b2Vec2(),groundPoint2:new b2Vec2(),anchorPoint1:new b2Vec2(),anchorPoint2:new b2Vec2(),maxLength1:null,maxLength2:null,ratio:null});
+var b2RevoluteJoint=Class.create();Object.extend(b2RevoluteJoint.prototype,b2Joint.prototype);Object.extend(b2RevoluteJoint.prototype,{GetAnchor1:function(){var tMat=this.m_body1.m_R;return new b2Vec2(this.m_body1.m_position.x+(tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y),this.m_body1.m_position.y+(tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y));},GetAnchor2:function(){var tMat=this.m_body2.m_R;return new b2Vec2(this.m_body2.m_position.x+(tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y),this.m_body2.m_position.y+(tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y));},GetJointAngle:function(){return this.m_body2.m_rotation-this.m_body1.m_rotation;},GetJointSpeed:function(){return this.m_body2.m_angularVelocity-this.m_body1.m_angularVelocity;},GetMotorTorque:function(invTimeStep){return invTimeStep*this.m_motorImpulse;},SetMotorSpeed:function(speed)
+{this.m_motorSpeed=speed;},SetMotorTorque:function(torque)
+{this.m_maxMotorTorque=torque;},GetReactionForce:function(invTimeStep)
+{var tVec=this.m_ptpImpulse.Copy();tVec.Multiply(invTimeStep);return tVec;},GetReactionTorque:function(invTimeStep)
+{return invTimeStep*this.m_limitImpulse;},initialize:function(def){this.m_node1=new b2JointNode();this.m_node2=new b2JointNode();this.m_type=def.type;this.m_prev=null;this.m_next=null;this.m_body1=def.body1;this.m_body2=def.body2;this.m_collideConnected=def.collideConnected;this.m_islandFlag=false;this.m_userData=def.userData;this.K=new b2Mat22();this.K1=new b2Mat22();this.K2=new b2Mat22();this.K3=new b2Mat22();this.m_localAnchor1=new b2Vec2();this.m_localAnchor2=new b2Vec2();this.m_ptpImpulse=new b2Vec2();this.m_ptpMass=new b2Mat22();var tMat;var tX;var tY;tMat=this.m_body1.m_R;tX=def.anchorPoint.x-this.m_body1.m_position.x;tY=def.anchorPoint.y-this.m_body1.m_position.y;this.m_localAnchor1.x=tX*tMat.col1.x+tY*tMat.col1.y;this.m_localAnchor1.y=tX*tMat.col2.x+tY*tMat.col2.y;tMat=this.m_body2.m_R;tX=def.anchorPoint.x-this.m_body2.m_position.x;tY=def.anchorPoint.y-this.m_body2.m_position.y;this.m_localAnchor2.x=tX*tMat.col1.x+tY*tMat.col1.y;this.m_localAnchor2.y=tX*tMat.col2.x+tY*tMat.col2.y;this.m_intialAngle=this.m_body2.m_rotation-this.m_body1.m_rotation;this.m_ptpImpulse.Set(0.0,0.0);this.m_motorImpulse=0.0;this.m_limitImpulse=0.0;this.m_limitPositionImpulse=0.0;this.m_lowerAngle=def.lowerAngle;this.m_upperAngle=def.upperAngle;this.m_maxMotorTorque=def.motorTorque;this.m_motorSpeed=def.motorSpeed;this.m_enableLimit=def.enableLimit;this.m_enableMotor=def.enableMotor;},K:new b2Mat22(),K1:new b2Mat22(),K2:new b2Mat22(),K3:new b2Mat22(),PrepareVelocitySolver:function(){var b1=this.m_body1;var b2=this.m_body2;var tMat;tMat=b1.m_R;var r1X=tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y;var r1Y=tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y;tMat=b2.m_R;var r2X=tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y;var r2Y=tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y;var invMass1=b1.m_invMass;var invMass2=b2.m_invMass;var invI1=b1.m_invI;var invI2=b2.m_invI;this.K1.col1.x=invMass1+invMass2;this.K1.col2.x=0.0;this.K1.col1.y=0.0;this.K1.col2.y=invMass1+invMass2;this.K2.col1.x=invI1*r1Y*r1Y;this.K2.col2.x=-invI1*r1X*r1Y;this.K2.col1.y=-invI1*r1X*r1Y;this.K2.col2.y=invI1*r1X*r1X;this.K3.col1.x=invI2*r2Y*r2Y;this.K3.col2.x=-invI2*r2X*r2Y;this.K3.col1.y=-invI2*r2X*r2Y;this.K3.col2.y=invI2*r2X*r2X;this.K.SetM(this.K1);this.K.AddM(this.K2);this.K.AddM(this.K3);this.K.Invert(this.m_ptpMass);this.m_motorMass=1.0/(invI1+invI2);if(this.m_enableMotor==false)
+{this.m_motorImpulse=0.0;}
+if(this.m_enableLimit)
+{var jointAngle=b2.m_rotation-b1.m_rotation-this.m_intialAngle;if(b2Math.b2Abs(this.m_upperAngle-this.m_lowerAngle)<2.0*b2Settings.b2_angularSlop)
+{this.m_limitState=b2Joint.e_equalLimits;}
+else if(jointAngle<=this.m_lowerAngle)
+{if(this.m_limitState!=b2Joint.e_atLowerLimit)
+{this.m_limitImpulse=0.0;}
+this.m_limitState=b2Joint.e_atLowerLimit;}
+else if(jointAngle>=this.m_upperAngle)
+{if(this.m_limitState!=b2Joint.e_atUpperLimit)
+{this.m_limitImpulse=0.0;}
+this.m_limitState=b2Joint.e_atUpperLimit;}
+else
+{this.m_limitState=b2Joint.e_inactiveLimit;this.m_limitImpulse=0.0;}}
+else
+{this.m_limitImpulse=0.0;}
+if(b2World.s_enableWarmStarting)
+{b1.m_linearVelocity.x-=invMass1*this.m_ptpImpulse.x;b1.m_linearVelocity.y-=invMass1*this.m_ptpImpulse.y;b1.m_angularVelocity-=invI1*((r1X*this.m_ptpImpulse.y-r1Y*this.m_ptpImpulse.x)+this.m_motorImpulse+this.m_limitImpulse);b2.m_linearVelocity.x+=invMass2*this.m_ptpImpulse.x;b2.m_linearVelocity.y+=invMass2*this.m_ptpImpulse.y;b2.m_angularVelocity+=invI2*((r2X*this.m_ptpImpulse.y-r2Y*this.m_ptpImpulse.x)+this.m_motorImpulse+this.m_limitImpulse);}
+else{this.m_ptpImpulse.SetZero();this.m_motorImpulse=0.0;this.m_limitImpulse=0.0;}
+this.m_limitPositionImpulse=0.0;},SolveVelocityConstraints:function(step){var b1=this.m_body1;var b2=this.m_body2;var tMat;tMat=b1.m_R;var r1X=tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y;var r1Y=tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y;tMat=b2.m_R;var r2X=tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y;var r2Y=tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y;var oldLimitImpulse;var ptpCdotX=b2.m_linearVelocity.x+(-b2.m_angularVelocity*r2Y)-b1.m_linearVelocity.x-(-b1.m_angularVelocity*r1Y);var ptpCdotY=b2.m_linearVelocity.y+(b2.m_angularVelocity*r2X)-b1.m_linearVelocity.y-(b1.m_angularVelocity*r1X);var ptpImpulseX=-(this.m_ptpMass.col1.x*ptpCdotX+this.m_ptpMass.col2.x*ptpCdotY);var ptpImpulseY=-(this.m_ptpMass.col1.y*ptpCdotX+this.m_ptpMass.col2.y*ptpCdotY);this.m_ptpImpulse.x+=ptpImpulseX;this.m_ptpImpulse.y+=ptpImpulseY;b1.m_linearVelocity.x-=b1.m_invMass*ptpImpulseX;b1.m_linearVelocity.y-=b1.m_invMass*ptpImpulseY;b1.m_angularVelocity-=b1.m_invI*(r1X*ptpImpulseY-r1Y*ptpImpulseX);b2.m_linearVelocity.x+=b2.m_invMass*ptpImpulseX;b2.m_linearVelocity.y+=b2.m_invMass*ptpImpulseY;b2.m_angularVelocity+=b2.m_invI*(r2X*ptpImpulseY-r2Y*ptpImpulseX);if(this.m_enableMotor&&this.m_limitState!=b2Joint.e_equalLimits)
+{var motorCdot=b2.m_angularVelocity-b1.m_angularVelocity-this.m_motorSpeed;var motorImpulse=-this.m_motorMass*motorCdot;var oldMotorImpulse=this.m_motorImpulse;this.m_motorImpulse=b2Math.b2Clamp(this.m_motorImpulse+motorImpulse,-step.dt*this.m_maxMotorTorque,step.dt*this.m_maxMotorTorque);motorImpulse=this.m_motorImpulse-oldMotorImpulse;b1.m_angularVelocity-=b1.m_invI*motorImpulse;b2.m_angularVelocity+=b2.m_invI*motorImpulse;}
+if(this.m_enableLimit&&this.m_limitState!=b2Joint.e_inactiveLimit)
+{var limitCdot=b2.m_angularVelocity-b1.m_angularVelocity;var limitImpulse=-this.m_motorMass*limitCdot;if(this.m_limitState==b2Joint.e_equalLimits)
+{this.m_limitImpulse+=limitImpulse;}
+else if(this.m_limitState==b2Joint.e_atLowerLimit)
+{oldLimitImpulse=this.m_limitImpulse;this.m_limitImpulse=b2Math.b2Max(this.m_limitImpulse+limitImpulse,0.0);limitImpulse=this.m_limitImpulse-oldLimitImpulse;}
+else if(this.m_limitState==b2Joint.e_atUpperLimit)
+{oldLimitImpulse=this.m_limitImpulse;this.m_limitImpulse=b2Math.b2Min(this.m_limitImpulse+limitImpulse,0.0);limitImpulse=this.m_limitImpulse-oldLimitImpulse;}
+b1.m_angularVelocity-=b1.m_invI*limitImpulse;b2.m_angularVelocity+=b2.m_invI*limitImpulse;}},SolvePositionConstraints:function(){var oldLimitImpulse;var limitC;var b1=this.m_body1;var b2=this.m_body2;var positionError=0.0;var tMat;tMat=b1.m_R;var r1X=tMat.col1.x*this.m_localAnchor1.x+tMat.col2.x*this.m_localAnchor1.y;var r1Y=tMat.col1.y*this.m_localAnchor1.x+tMat.col2.y*this.m_localAnchor1.y;tMat=b2.m_R;var r2X=tMat.col1.x*this.m_localAnchor2.x+tMat.col2.x*this.m_localAnchor2.y;var r2Y=tMat.col1.y*this.m_localAnchor2.x+tMat.col2.y*this.m_localAnchor2.y;var p1X=b1.m_position.x+r1X;var p1Y=b1.m_position.y+r1Y;var p2X=b2.m_position.x+r2X;var p2Y=b2.m_position.y+r2Y;var ptpCX=p2X-p1X;var ptpCY=p2Y-p1Y;positionError=Math.sqrt(ptpCX*ptpCX+ptpCY*ptpCY);var invMass1=b1.m_invMass;var invMass2=b2.m_invMass;var invI1=b1.m_invI;var invI2=b2.m_invI;this.K1.col1.x=invMass1+invMass2;this.K1.col2.x=0.0;this.K1.col1.y=0.0;this.K1.col2.y=invMass1+invMass2;this.K2.col1.x=invI1*r1Y*r1Y;this.K2.col2.x=-invI1*r1X*r1Y;this.K2.col1.y=-invI1*r1X*r1Y;this.K2.col2.y=invI1*r1X*r1X;this.K3.col1.x=invI2*r2Y*r2Y;this.K3.col2.x=-invI2*r2X*r2Y;this.K3.col1.y=-invI2*r2X*r2Y;this.K3.col2.y=invI2*r2X*r2X;this.K.SetM(this.K1);this.K.AddM(this.K2);this.K.AddM(this.K3);this.K.Solve(b2RevoluteJoint.tImpulse,-ptpCX,-ptpCY);var impulseX=b2RevoluteJoint.tImpulse.x;var impulseY=b2RevoluteJoint.tImpulse.y;b1.m_position.x-=b1.m_invMass*impulseX;b1.m_position.y-=b1.m_invMass*impulseY;b1.m_rotation-=b1.m_invI*(r1X*impulseY-r1Y*impulseX);b1.m_R.Set(b1.m_rotation);b2.m_position.x+=b2.m_invMass*impulseX;b2.m_position.y+=b2.m_invMass*impulseY;b2.m_rotation+=b2.m_invI*(r2X*impulseY-r2Y*impulseX);b2.m_R.Set(b2.m_rotation);var angularError=0.0;if(this.m_enableLimit&&this.m_limitState!=b2Joint.e_inactiveLimit)
+{var angle=b2.m_rotation-b1.m_rotation-this.m_intialAngle;var limitImpulse=0.0;if(this.m_limitState==b2Joint.e_equalLimits)
+{limitC=b2Math.b2Clamp(angle,-b2Settings.b2_maxAngularCorrection,b2Settings.b2_maxAngularCorrection);limitImpulse=-this.m_motorMass*limitC;angularError=b2Math.b2Abs(limitC);}
+else if(this.m_limitState==b2Joint.e_atLowerLimit)
+{limitC=angle-this.m_lowerAngle;angularError=b2Math.b2Max(0.0,-limitC);limitC=b2Math.b2Clamp(limitC+b2Settings.b2_angularSlop,-b2Settings.b2_maxAngularCorrection,0.0);limitImpulse=-this.m_motorMass*limitC;oldLimitImpulse=this.m_limitPositionImpulse;this.m_limitPositionImpulse=b2Math.b2Max(this.m_limitPositionImpulse+limitImpulse,0.0);limitImpulse=this.m_limitPositionImpulse-oldLimitImpulse;}
+else if(this.m_limitState==b2Joint.e_atUpperLimit)
+{limitC=angle-this.m_upperAngle;angularError=b2Math.b2Max(0.0,limitC);limitC=b2Math.b2Clamp(limitC-b2Settings.b2_angularSlop,0.0,b2Settings.b2_maxAngularCorrection);limitImpulse=-this.m_motorMass*limitC;oldLimitImpulse=this.m_limitPositionImpulse;this.m_limitPositionImpulse=b2Math.b2Min(this.m_limitPositionImpulse+limitImpulse,0.0);limitImpulse=this.m_limitPositionImpulse-oldLimitImpulse;}
+b1.m_rotation-=b1.m_invI*limitImpulse;b1.m_R.Set(b1.m_rotation);b2.m_rotation+=b2.m_invI*limitImpulse;b2.m_R.Set(b2.m_rotation);}
+return positionError<=b2Settings.b2_linearSlop&&angularError<=b2Settings.b2_angularSlop;},m_localAnchor1:new b2Vec2(),m_localAnchor2:new b2Vec2(),m_ptpImpulse:new b2Vec2(),m_motorImpulse:null,m_limitImpulse:null,m_limitPositionImpulse:null,m_ptpMass:new b2Mat22(),m_motorMass:null,m_intialAngle:null,m_lowerAngle:null,m_upperAngle:null,m_maxMotorTorque:null,m_motorSpeed:null,m_enableLimit:null,m_enableMotor:null,m_limitState:0});b2RevoluteJoint.tImpulse=new b2Vec2();
+var b2RevoluteJointDef=Class.create();Object.extend(b2RevoluteJointDef.prototype,b2JointDef.prototype);Object.extend(b2RevoluteJointDef.prototype,{initialize:function()
+{this.type=b2Joint.e_unknownJoint;this.userData=null;this.body1=null;this.body2=null;this.collideConnected=false;this.type=b2Joint.e_revoluteJoint;this.anchorPoint=new b2Vec2(0.0,0.0);this.lowerAngle=0.0;this.upperAngle=0.0;this.motorTorque=0.0;this.motorSpeed=0.0;this.enableLimit=false;this.enableMotor=false;},anchorPoint:null,lowerAngle:null,upperAngle:null,motorTorque:null,motorSpeed:null,enableLimit:null,enableMotor:null});
diff --git a/o3d/samples/manipulators/translate1.html b/o3d/samples/manipulators/translate1.html
index dd3eadb..7debeae 100644
--- a/o3d/samples/manipulators/translate1.html
+++ b/o3d/samples/manipulators/translate1.html
@@ -1,273 +1,273 @@
-<!--
-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.
--->
-
-<!--
-Translate1 manipulator
-
-This sample shows how to use the o3djs.manipulators.Translate1 class
-to interactively drag objects around the scene.
--->
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
- "http://www.w3.org/TR/html4/loose.dtd">
-<html>
-<head>
-<meta http-equiv="content-type" content="text/html; charset=UTF-8">
-<title>
-Translate1 Manipulator
-</title>
-<script type="text/javascript" src="../o3djs/base.js"></script>
-<script type="text/javascript" id="o3dscript">
-o3djs.require('o3djs.util');
-o3djs.require('o3djs.math');
-o3djs.require('o3djs.quaternions');
-o3djs.require('o3djs.rendergraph');
-o3djs.require('o3djs.primitives');
-o3djs.require('o3djs.manipulators');
-o3djs.require('o3djs.effect');
-
-// global variables
-var g_o3dElement;
-var g_client;
-var g_o3d;
-var g_math;
-var g_pack;
-var g_viewInfo;
-
-var g_lightPosition = [5, 5, 7];
-var g_eyePosition = [1, 5, 23];
-
-var g_primitives = [];
-var g_manager;
-
-/**
- * Creates the client area.
- */
-function initClient() {
- window.g_finished = false; // for selenium testing.
-
- // Runs the sample in V8. Comment out this line to run it in the browser
- // JavaScript engine, for example if you want to debug it.
- // TODO(kbr): we need to investigate why turning this on is
- // significantly slower than leaving it disabled.
- // o3djs.util.setMainEngine(o3djs.util.Engine.V8);
-
- o3djs.util.makeClients(main);
-}
-
-/**
- * Initializes global variables, positions camera, draws shapes.
- * @param {Array} clientElements Array of o3d object elements.
- */
-function main(clientElements) {
- var o3dElement = clientElements[0];
-
- // Init global variables.
- initGlobals(clientElements);
-
- // Set up the view and projection transformations.
- initContext();
-
- // Add the shapes to the transform heirarchy.
- createShapes();
-
- // Add the manipulators to the transform hierarchy.
- createManipulators();
-
- // Start picking; it won't do anything until the scene finishes loading.
- o3djs.event.addEventListener(o3dElement, 'mousedown', onMouseDown);
- o3djs.event.addEventListener(o3dElement, 'mousemove', onMouseMove);
- o3djs.event.addEventListener(o3dElement, 'mouseup', onMouseUp);
-
- window.g_finished = true; // for selenium testing.
-}
-
-function onMouseDown(e) {
- g_manager.mousedown(e.x, e.y,
- g_viewInfo.drawContext.view,
- g_viewInfo.drawContext.projection,
- g_client.width,
- g_client.height);
-}
-
-function onMouseMove(e) {
- g_manager.mousemove(e.x, e.y,
- g_viewInfo.drawContext.view,
- g_viewInfo.drawContext.projection,
- g_client.width,
- g_client.height);
- g_manager.updateInactiveManipulators();
-}
-
-function onMouseUp(e) {
- g_manager.mouseup();
- g_manager.updateInactiveManipulators();
-}
-
-/**
- * Initializes global variables and libraries.
- */
-function initGlobals(clientElements) {
- g_o3dElement = clientElements[0];
- window.g_client = g_client = g_o3dElement.client;
- g_o3d = g_o3dElement.o3d;
- g_math = o3djs.math;
-
- // Create a pack to manage the objects created.
- g_pack = g_client.createPack();
-
- // Create the render graph for a view.
- g_viewInfo = o3djs.rendergraph.createBasicView(
- g_pack,
- g_client.root,
- g_client.renderGraphRoot);
-}
-
-/**
- * Sets up reasonable view and projection matrices.
- */
-function initContext() {
- // Set up a perspective transformation for the projection.
- g_viewInfo.drawContext.projection = g_math.matrix4.perspective(
- g_math.degToRad(30), // 30 degree frustum.
- g_o3dElement.clientWidth / g_o3dElement.clientHeight, // Aspect ratio.
- 1, // Near plane.
- 5000); // Far plane.
-
- // Set up our view transformation to look towards the world origin where the
- // primitives are located.
- g_viewInfo.drawContext.view = g_math.matrix4.lookAt(
- g_eyePosition, // eye
- [0, 2, 0], // target
- [0, 1, 0]); // up
-}
-
-/**
- * Creates shapes using the primitives utility library, and adds them to the
- * transform graph at the root node.
- */
-function createShapes() {
- // Create a little tree-like hierarchy of cubes
- createCubeTree(2, 1.5, [0, 0, 0], g_client.root);
-}
-
-/**
- * Creates a small tree of cubes to demonstrate interaction with a
- * hierarchy of shapes.
- */
-function createCubeTree(depth, edgeLength, translation, parent) {
- var cur = createCube(edgeLength, translation, parent);
- if (depth > 0) {
- createCubeTree(depth - 1,
- edgeLength / 1.5,
- o3djs.math.addVector(translation,
- [-1.2 * edgeLength,
- 1.0 * edgeLength,
- 0]),
- cur);
- createCubeTree(depth - 1,
- edgeLength / 1.5,
- o3djs.math.addVector(translation,
- [1.2 * edgeLength,
- 1.0 * edgeLength,
- 0]),
- cur);
- }
- return cur;
-}
-
-/**
- * Creates a cube shape using the primitives utility library, with an
- * optional translation and parent. Returns the newly-created
- * transform for the cube.
- */
-function createCube(edgeLength, opt_translation, opt_parent) {
- var cube = o3djs.primitives.createCube(
- g_pack,
- // A green phong-shaded material.
- o3djs.material.createBasicMaterial(g_pack,
- g_viewInfo,
- [0, 1, 0, 1]),
- edgeLength);
- var transform = g_pack.createObject('Transform');
- transform.addShape(cube);
- if (opt_translation) {
- transform.translate(opt_translation);
- }
- if (opt_parent) {
- transform.parent = opt_parent;
- } else {
- transform.parent = g_client.root;
- }
- g_primitives.push(transform);
- return transform;
-}
-
-/**
- * Creates manipulators attached to the objects we've just created.
- */
-function createManipulators() {
- g_manager = o3djs.manipulators.createManager(g_pack,
- g_viewInfo.performanceDrawList,
- g_client.root,
- null,
- 0);
- var jj = 2;
- for (var ii = 0; ii < g_primitives.length; ii++) {
- var manip = g_manager.createTranslate1();
- manip.attachTo(g_primitives[ii]);
- manip.setOffsetTranslation([0, -1.5, 0]);
- // Demonstrate that we can drag along arbitrary directions.
- if ((++jj % 4) == 0) {
- manip.setOffsetRotation(o3djs.quaternions.rotationY(Math.PI / 4));
- }
- }
-}
-
-/**
- * Removes any callbacks so they don't get called after the page has unloaded.
- */
-function unload() {
- if (g_client) {
- g_client.cleanup();
- }
-}
-</script>
-</head>
-<body onload="initClient()" onunload="unload()">
-<h1>Translate1 Manipulator Sample</h1>
-This example shows how to move objects around the scene using the
-Translate1 manipulator.
-<br/>
-<!-- Start of O3D plugin -->
-<div id="o3d" style="width: 600px; height: 600px;"></div>
-<!-- End of O3D plugin -->
-</body>
-</html>
+<!--
+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.
+-->
+
+<!--
+Translate1 manipulator
+
+This sample shows how to use the o3djs.manipulators.Translate1 class
+to interactively drag objects around the scene.
+-->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<title>
+Translate1 Manipulator
+</title>
+<script type="text/javascript" src="../o3djs/base.js"></script>
+<script type="text/javascript" id="o3dscript">
+o3djs.require('o3djs.util');
+o3djs.require('o3djs.math');
+o3djs.require('o3djs.quaternions');
+o3djs.require('o3djs.rendergraph');
+o3djs.require('o3djs.primitives');
+o3djs.require('o3djs.manipulators');
+o3djs.require('o3djs.effect');
+
+// global variables
+var g_o3dElement;
+var g_client;
+var g_o3d;
+var g_math;
+var g_pack;
+var g_viewInfo;
+
+var g_lightPosition = [5, 5, 7];
+var g_eyePosition = [1, 5, 23];
+
+var g_primitives = [];
+var g_manager;
+
+/**
+ * Creates the client area.
+ */
+function initClient() {
+ window.g_finished = false; // for selenium testing.
+
+ // Runs the sample in V8. Comment out this line to run it in the browser
+ // JavaScript engine, for example if you want to debug it.
+ // TODO(kbr): we need to investigate why turning this on is
+ // significantly slower than leaving it disabled.
+ // o3djs.util.setMainEngine(o3djs.util.Engine.V8);
+
+ o3djs.util.makeClients(main);
+}
+
+/**
+ * Initializes global variables, positions camera, draws shapes.
+ * @param {Array} clientElements Array of o3d object elements.
+ */
+function main(clientElements) {
+ var o3dElement = clientElements[0];
+
+ // Init global variables.
+ initGlobals(clientElements);
+
+ // Set up the view and projection transformations.
+ initContext();
+
+ // Add the shapes to the transform heirarchy.
+ createShapes();
+
+ // Add the manipulators to the transform hierarchy.
+ createManipulators();
+
+ // Start picking; it won't do anything until the scene finishes loading.
+ o3djs.event.addEventListener(o3dElement, 'mousedown', onMouseDown);
+ o3djs.event.addEventListener(o3dElement, 'mousemove', onMouseMove);
+ o3djs.event.addEventListener(o3dElement, 'mouseup', onMouseUp);
+
+ window.g_finished = true; // for selenium testing.
+}
+
+function onMouseDown(e) {
+ g_manager.mousedown(e.x, e.y,
+ g_viewInfo.drawContext.view,
+ g_viewInfo.drawContext.projection,
+ g_client.width,
+ g_client.height);
+}
+
+function onMouseMove(e) {
+ g_manager.mousemove(e.x, e.y,
+ g_viewInfo.drawContext.view,
+ g_viewInfo.drawContext.projection,
+ g_client.width,
+ g_client.height);
+ g_manager.updateInactiveManipulators();
+}
+
+function onMouseUp(e) {
+ g_manager.mouseup();
+ g_manager.updateInactiveManipulators();
+}
+
+/**
+ * Initializes global variables and libraries.
+ */
+function initGlobals(clientElements) {
+ g_o3dElement = clientElements[0];
+ window.g_client = g_client = g_o3dElement.client;
+ g_o3d = g_o3dElement.o3d;
+ g_math = o3djs.math;
+
+ // Create a pack to manage the objects created.
+ g_pack = g_client.createPack();
+
+ // Create the render graph for a view.
+ g_viewInfo = o3djs.rendergraph.createBasicView(
+ g_pack,
+ g_client.root,
+ g_client.renderGraphRoot);
+}
+
+/**
+ * Sets up reasonable view and projection matrices.
+ */
+function initContext() {
+ // Set up a perspective transformation for the projection.
+ g_viewInfo.drawContext.projection = g_math.matrix4.perspective(
+ g_math.degToRad(30), // 30 degree frustum.
+ g_o3dElement.clientWidth / g_o3dElement.clientHeight, // Aspect ratio.
+ 1, // Near plane.
+ 5000); // Far plane.
+
+ // Set up our view transformation to look towards the world origin where the
+ // primitives are located.
+ g_viewInfo.drawContext.view = g_math.matrix4.lookAt(
+ g_eyePosition, // eye
+ [0, 2, 0], // target
+ [0, 1, 0]); // up
+}
+
+/**
+ * Creates shapes using the primitives utility library, and adds them to the
+ * transform graph at the root node.
+ */
+function createShapes() {
+ // Create a little tree-like hierarchy of cubes
+ createCubeTree(2, 1.5, [0, 0, 0], g_client.root);
+}
+
+/**
+ * Creates a small tree of cubes to demonstrate interaction with a
+ * hierarchy of shapes.
+ */
+function createCubeTree(depth, edgeLength, translation, parent) {
+ var cur = createCube(edgeLength, translation, parent);
+ if (depth > 0) {
+ createCubeTree(depth - 1,
+ edgeLength / 1.5,
+ o3djs.math.addVector(translation,
+ [-1.2 * edgeLength,
+ 1.0 * edgeLength,
+ 0]),
+ cur);
+ createCubeTree(depth - 1,
+ edgeLength / 1.5,
+ o3djs.math.addVector(translation,
+ [1.2 * edgeLength,
+ 1.0 * edgeLength,
+ 0]),
+ cur);
+ }
+ return cur;
+}
+
+/**
+ * Creates a cube shape using the primitives utility library, with an
+ * optional translation and parent. Returns the newly-created
+ * transform for the cube.
+ */
+function createCube(edgeLength, opt_translation, opt_parent) {
+ var cube = o3djs.primitives.createCube(
+ g_pack,
+ // A green phong-shaded material.
+ o3djs.material.createBasicMaterial(g_pack,
+ g_viewInfo,
+ [0, 1, 0, 1]),
+ edgeLength);
+ var transform = g_pack.createObject('Transform');
+ transform.addShape(cube);
+ if (opt_translation) {
+ transform.translate(opt_translation);
+ }
+ if (opt_parent) {
+ transform.parent = opt_parent;
+ } else {
+ transform.parent = g_client.root;
+ }
+ g_primitives.push(transform);
+ return transform;
+}
+
+/**
+ * Creates manipulators attached to the objects we've just created.
+ */
+function createManipulators() {
+ g_manager = o3djs.manipulators.createManager(g_pack,
+ g_viewInfo.performanceDrawList,
+ g_client.root,
+ null,
+ 0);
+ var jj = 2;
+ for (var ii = 0; ii < g_primitives.length; ii++) {
+ var manip = g_manager.createTranslate1();
+ manip.attachTo(g_primitives[ii]);
+ manip.setOffsetTranslation([0, -1.5, 0]);
+ // Demonstrate that we can drag along arbitrary directions.
+ if ((++jj % 4) == 0) {
+ manip.setOffsetRotation(o3djs.quaternions.rotationY(Math.PI / 4));
+ }
+ }
+}
+
+/**
+ * Removes any callbacks so they don't get called after the page has unloaded.
+ */
+function unload() {
+ if (g_client) {
+ g_client.cleanup();
+ }
+}
+</script>
+</head>
+<body onload="initClient()" onunload="unload()">
+<h1>Translate1 Manipulator Sample</h1>
+This example shows how to move objects around the scene using the
+Translate1 manipulator.
+<br/>
+<!-- Start of O3D plugin -->
+<div id="o3d" style="width: 600px; height: 600px;"></div>
+<!-- End of O3D plugin -->
+</body>
+</html>
diff --git a/o3d/samples/o3djs/manipulators.js b/o3d/samples/o3djs/manipulators.js
index e1ddce6..cade671 100644
--- a/o3d/samples/o3djs/manipulators.js
+++ b/o3d/samples/o3djs/manipulators.js
@@ -1,962 +1,962 @@
-/*
- * 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 contains classes that implement several
- * forms of 2D and 3D manipulation.
- */
-
-o3djs.provide('o3djs.manipulators');
-
-o3djs.require('o3djs.material');
-
-o3djs.require('o3djs.math');
-
-o3djs.require('o3djs.picking');
-
-o3djs.require('o3djs.primitives');
-
-o3djs.require('o3djs.quaternions');
-
-/**
- * A module implementing several forms of 2D and 3D manipulation.
- * @namespace
- */
-o3djs.manipulators = o3djs.manipulators || {};
-
-/**
- * Creates a new manipulator manager, which maintains multiple
- * manipulators in the same scene. The manager is implicitly
- * associated with a particular O3D client via the Pack which is
- * passed in, although multiple managers can be created for a given
- * client. The manipulators are positioned in world coordinates and
- * are placed in the scene graph underneath the parent transform which
- * is passed in.
- * @param {!o3d.Pack} pack Pack in which manipulators' geometry and
- * materials will be created.
- * @param {!o3d.DrawList} drawList The draw list against which
- * internal materials are created.
- * @param {!o3d.Transform} parentTransform The parent transform under
- * which the manipulators' geometry should be parented.
- * @param {!o3d.RenderNode} parentRenderNode The parent render node
- * under which the manipulators' draw elements should be placed.
- * @param {number} renderNodePriority The priority that the
- * manipulators' geometry should use for rendering.
- * @return {!o3djs.manipulators.Manager} The created manipulator
- * manager.
- */
-o3djs.manipulators.createManager = function(pack,
- drawList,
- parentTransform,
- parentRenderNode,
- renderNodePriority) {
- return new o3djs.manipulators.Manager(pack,
- drawList,
- parentTransform,
- parentRenderNode,
- renderNodePriority);
-}
-
-//
-// Some linear algebra classes.
-// TODO(kbr): find a better home for these.
-//
-
-/**
- * Creates a new Line object, which implements projection and
- * closest-point operations.
- * @constructor
- * @private
- * @param {o3djs.math.Vector3} opt_direction The direction of the
- * line. Does not need to be normalized but must not be the zero
- * vector. Defaults to [1, 0, 0] if not specified.
- * @param {o3djs.math.Vector3} opt_point A point through which the
- * line goes. Defaults to [0, 0, 0] if not specified.
- */
-o3djs.manipulators.Line_ = function(opt_direction,
- opt_point) {
- if (opt_direction) {
- this.direction_ = o3djs.math.copyVector(opt_direction);
- } else {
- this.direction_ = [1, 0, 0];
- }
-
- if (opt_point) {
- this.point_ = o3djs.math.copyVector(opt_point);
- } else {
- this.point_ = [0, 0, 0];
- }
-
- // Helper for computing projections along the line
- this.alongVec_ = [0, 0, 0];
- this.recalc_();
-}
-
-/**
- * Sets the direction of this line.
- * @private
- * @param {!o3djs.math.Vector3} direction The new direction of the
- * line. Does not need to be normalized but must not be the zero
- * vector.
- */
-o3djs.manipulators.Line_.prototype.setDirection = function(direction) {
- this.direction_ = o3djs.math.copyVector(direction);
- this.recalc_();
-}
-
-/**
- * Gets the direction of this line.
- * @private
- * @return {!o3djs.math.Vector3} The direction of the line.
- */
-o3djs.manipulators.Line_.prototype.getDirection = function() {
- return this.direction_;
-}
-
-/**
- * Sets one point through which this line travels.
- * @private
- * @param {!o3djs.math.Vector3} point A point which through the line
- * will travel.
- */
-o3djs.manipulators.Line_.prototype.setPoint = function(point) {
- this.point_ = o3djs.math.copyVector(point);
- this.recalc_();
-}
-
-/**
- * Gets one point through which this line travels.
- * @private
- * @return {!o3djs.math.Vector3} A point which through the line
- * travels.
- */
-o3djs.manipulators.Line_.prototype.getPoint = function() {
- return this.point_;
-}
-
-/**
- * Projects a point onto the line.
- * @private
- * @param {!o3djs.math.Vector3} point Point to be projected.
- * @return {!o3djs.math.Vector3} Point on the line closest to the
- * passed point.
- */
-o3djs.manipulators.Line_.prototype.projectPoint = function(point) {
- var dotp = o3djs.math.dot(this.direction_, point);
- return o3djs.math.addVector(this.alongVec_,
- o3djs.math.mulScalarVector(dotp,
- this.direction_));
-}
-
-o3djs.manipulators.EPSILON = 0.00001;
-o3djs.manipulators.X_AXIS = [1, 0, 0];
-
-
-/**
- * Returns the closest point on this line to the given ray, which is
- * specified by start and end points. If the ray is parallel to the
- * line, returns null.
- * @private
- * @param {!o3djs.math.Vector3} startPoint Start point of ray.
- * @param {!o3djs.math.Vector3} endPoint End point of ray.
- * @return {o3djs.math.Vector3} The closest point on the line to the
- * ray, or null if the ray is parallel to the line.
- */
-o3djs.manipulators.Line_.prototype.closestPointToRay = function(startPoint,
- endPoint) {
- // Consider a two-sided line and a one-sided ray, both in in 3D
- // space, and assume they are not parallel. Their parametric
- // formulation is:
- //
- // p1 = point + t * dir
- // p2 = raystart + u * raydir
- //
- // Here t and u are scalar parameter values, and the other values
- // are three-dimensional vectors. p1 and p2 are arbitrary points on
- // the line and ray, respectively.
- //
- // At the points cp1 and cp2 on these two lines where the line and
- // the ray are closest together, the line segment between cp1 and
- // cp2 is perpendicular to both of the lines.
- //
- // We can therefore write the following equations:
- //
- // dot( dir, (cp2 - cp1)) = 0
- // dot(raydir, (cp2 - cp1)) = 0
- //
- // Define t' and u' as the parameter values for cp1 and cp2,
- // respectively. Expanding, these equations become
- //
- // dot( dir, ((raystart + u' * raydir) - (point + t' * dir))) = 0
- // dot(raydir, ((raystart + u' * raydir) - (point + t' * dir))) = 0
- //
- // With some reshuffling, these can be expressed in vector/matrix
- // form:
- //
- // [ dot( dir, raystart) - dot( dir, point) ]
- // [ dot(raydir, raystart) - dot(raydir, point) ] + (continued)
- //
- // [ -dot( dir, dir) dot( dir, raydir) ] [ t' ] [0]
- // [ -dot(raydir, dir) dot(raydir, raydir) ] * [ u' ] = [0]
- //
- // u' is the parameter for the world space ray being cast into the
- // screen. We can deduce whether the starting point of the ray is
- // actually the closest point to the infinite 3D line by whether the
- // value of u' is less than zero.
- var rayDirection = o3djs.math.subVector(endPoint, startPoint);
- var ddrd = o3djs.math.dot(this.direction_, rayDirection);
- var A = [[-o3djs.math.lengthSquared(this.direction_), ddrd],
- [ddrd, -o3djs.math.lengthSquared(rayDirection)]];
- var det = o3djs.math.det2(A);
- if (Math.abs(det) < o3djs.manipulators.EPSILON) {
- return null;
- }
- var Ainv = o3djs.math.inverse2(A);
- var b = [o3djs.math.dot(this.point_, this.direction_) -
- o3djs.math.dot(startPoint, this.direction_),
- o3djs.math.dot(startPoint, rayDirection) -
- o3djs.math.dot(this.point_, rayDirection)];
- var x = o3djs.math.mulMatrixVector(Ainv, b);
- if (x[1] < 0) {
- // Means that start point is closest point to this line
- return startPoint;
- } else {
- return o3djs.math.addVector(this.point_,
- o3djs.math.mulScalarVector(
- x[0],
- this.direction_));
- }
-}
-
-/**
- * Performs internal recalculations when the parameters of the line change.
- * @private
- */
-o3djs.manipulators.Line_.prototype.recalc_ = function() {
- var denom = o3djs.math.lengthSquared(this.direction_);
- if (denom == 0.0) {
- throw 'Line_.recalc: ERROR: direction was the zero vector (not allowed)';
- }
- this.alongVec_ =
- o3djs.math.subVector(this.point_,
- o3djs.math.mulScalarVector(
- o3djs.math.dot(this.point_,
- this.direction_),
- this.direction_));
-}
-
-o3djs.manipulators.DEFAULT_COLOR = [0.8, 0.8, 0.8, 1.0];
-o3djs.manipulators.HIGHLIGHTED_COLOR = [0.9, 0.9, 0.0, 1.0];
-
-/**
- * Constructs a new manipulator manager. Do not call this directly;
- * use o3djs.manipulators.createManager instead.
- * @constructor
- * @param {!o3d.Pack} pack Pack in which manipulators' geometry and
- * materials will be created.
- * @param {!o3d.DrawList} drawList The draw list against which
- * internal materials are created.
- * @param {!o3d.Transform} parentTransform The parent transform under
- * which the manipulators' geometry should be parented.
- * @param {!o3d.RenderNode} parentRenderNode The parent render node
- * under which the manipulators' draw elements should be placed.
- * @param {number} renderNodePriority The priority that the
- * manipulators' geometry should use for rendering.
- */
-o3djs.manipulators.Manager = function(pack,
- drawList,
- parentTransform,
- parentRenderNode,
- renderNodePriority) {
- this.pack = pack;
- this.drawList = drawList;
- this.parentTransform = parentTransform;
- this.parentRenderNode = parentRenderNode;
- this.renderNodePriority = renderNodePriority;
-
- this.lightPosition = [10, 10, 10];
-
- // Create the default and highlighted materials.
- this.defaultMaterial =
- this.createPhongMaterial_(o3djs.manipulators.DEFAULT_COLOR);
- this.highlightedMaterial =
- this.createPhongMaterial_(o3djs.manipulators.HIGHLIGHTED_COLOR);
-
- // This is a map from the manip's parent Transform clientId to the manip.
- this.manipsByClientId = [];
-
- // Presumably we need a TransformInfo for the parentTransform.
- this.transformInfo =
- o3djs.picking.createTransformInfo(this.parentTransform, null);
-
- /**
- * The currently-highlighted manipulator.
- * @type {o3djs.manipulators.Manip}
- */
- this.highlightedManip = null;
-
- /**
- * The manipulator currently being dragged.
- * @private
- * @type {o3djs.manipulators.Manip}
- */
- this.draggedManip_ = null;
-}
-
-/**
- * Creates a phong material based on the given single color.
- * @private
- * @param {!o3djs.math.Vector4} baseColor A vector with 4 entries, the
- * R,G,B, and A components of a color.
- * @return {!o3d.Material} A phong material whose overall pigment is baseColor.
- */
-o3djs.manipulators.Manager.prototype.createPhongMaterial_ =
- function(baseColor) {
- // Create a new, empty Material object.
- var material = this.pack.createObject('Material');
-
- o3djs.effect.attachStandardShader(
- this.pack, material, this.lightPosition, 'phong');
-
- material.drawList = this.drawList;
-
- // Assign parameters to the phong material.
- material.getParam('emissive').value = [0, 0, 0, 1];
- material.getParam('ambient').value =
- o3djs.math.mulScalarVector(0.1, baseColor);
- material.getParam('diffuse').value = baseColor;
- material.getParam('specular').value = [.2, .2, .2, 1];
- material.getParam('shininess').value = 20;
-
- return material;
-}
-
-/**
- * Creates a new Translate1 manipulator. A Translate1 moves along the
- * X axis in its local coordinate system.
- * @return {!o3djs.manipulators.Translate1} A new Translate1 manipulator.
- */
-o3djs.manipulators.Manager.prototype.createTranslate1 = function() {
- var manip = new o3djs.manipulators.Translate1(this);
- this.add_(manip);
- return manip;
-}
-
-/**
- * Adds a manipulator to this manager's set.
- * @private
- * @param {!o3djs.manipulators.Manip} manip The manipulator to add.
- */
-o3djs.manipulators.Manager.prototype.add_ = function(manip) {
- // Generate draw elements for the manipulator's transform
- manip.getTransform().createDrawElements(this.pack, null);
- // Add the manipulator's transform to the parent transform
- manip.getBaseTransform_().parent = this.parentTransform;
- // Add the manipulator into our managed list
- this.manipsByClientId[manip.getTransform().clientId] = manip;
-}
-
-/**
- * Event handler for multiple kinds of mouse events.
- * @private
- * @param {number} x The x coordinate of the mouse event.
- * @param {number} y The y coordinate of the mouse event.
- * @param {!o3djs.math.Matrix4} view The current view matrix.
- * @param {!o3djs.math.Matrix4} projection The current projection matrix.
- * @param {number} width The width of the viewport.
- * @param {number} height The height of the viewport.
- * @param {!function(!o3djs.manipulators.Manager,
- * o3djs.picking.PickInfo, o3djs.manipulators.Manip): void} func
- * Callback function. Always receives the manager as argument; if
- * a manipulator was picked, receives non-null PickInfo and Manip
- * arguments, otherwise receives null for both of these arguments.
- */
-o3djs.manipulators.Manager.prototype.handleMouse_ = function(x,
- y,
- view,
- projection,
- width,
- height,
- func) {
- this.transformInfo.update();
-
- // Create the world ray
- var worldRay =
- o3djs.picking.clientPositionToWorldRayEx(x, y,
- view, projection,
- width, height);
-
- // Pick against all of the manipulators' geometry
- var pickResult = this.transformInfo.pick(worldRay);
- if (pickResult != null) {
- // Find which manipulator we picked.
- // NOTE this assumes some things about the transform graph
- // structure of the manipulators.
- var manip =
- this.manipsByClientId[pickResult.shapeInfo.parent.transform.clientId];
- func(this, pickResult, manip);
- } else {
- func(this, null, null);
- }
-}
-
-/**
- * Callback handling the mouse-down event on a manipulator.
- * @private
- * @param {!o3djs.manipulators.Manager} manager The manipulator
- * manager owning the given manipulator.
- * @param {o3djs.picking.PickInfo} pickResult The picking information
- * associated with the mouse-down event.
- * @param {o3djs.manipulators.Manip} manip The manipulator to be
- * selected.
- */
-o3djs.manipulators.mouseDownCallback_ = function(manager,
- pickResult,
- manip) {
- if (manip != null) {
- manager.draggedManip_ = manip;
- manip.makeActive(pickResult);
- }
-}
-
-/**
- * Callback handling the mouse-over event on a manipulator.
- * @private
- * @param {!o3djs.manipulators.Manager} manager The manipulator
- * manager owning the given manipulator.
- * @param {o3djs.picking.PickInfo} pickResult The picking information
- * associated with the mouse-over event.
- * @param {o3djs.manipulators.Manip} manip The manipulator to be
- * highlighted.
- */
-o3djs.manipulators.hoverCallback_ = function(manager,
- pickResult,
- manip) {
- if (manager.highlightedManip != null &&
- manager.highlightedManip != manip) {
- // Un-highlight the previously highlighted manipulator
- manager.highlightedManip.clearHighlight();
- manager.highlightedManip = null;
- }
-
- if (manip != null) {
- manip.highlight(pickResult);
- manager.highlightedManip = manip;
- }
-}
-
-/**
- * Method which should be called by end user code upon receiving a
- * mouse-down event.
- * @param {number} x The x coordinate of the mouse event.
- * @param {number} y The y coordinate of the mouse event.
- * @param {!o3djs.math.Matrix4} view The current view matrix.
- * @param {!o3djs.math.Matrix4} projection The current projection matrix.
- * @param {number} width The width of the viewport.
- * @param {number} height The height of the viewport.
- */
-o3djs.manipulators.Manager.prototype.mousedown = function(x,
- y,
- view,
- projection,
- width,
- height) {
- this.handleMouse_(x, y, view, projection, width, height,
- o3djs.manipulators.mouseDownCallback_);
-}
-
-/**
- * Method which should be called by end user code upon receiving a
- * mouse motion event.
- * @param {number} x The x coordinate of the mouse event.
- * @param {number} y The y coordinate of the mouse event.
- * @param {!o3djs.math.Matrix4} view The current view matrix.
- * @param {!o3djs.math.Matrix4} projection The current projection matrix.
- * @param {number} width The width of the viewport.
- * @param {number} height The height of the viewport.
- */
-o3djs.manipulators.Manager.prototype.mousemove = function(x,
- y,
- view,
- projection,
- width,
- height) {
- if (this.draggedManip_ != null) {
- var worldRay =
- o3djs.picking.clientPositionToWorldRayEx(x, y,
- view, projection,
- width, height);
- this.draggedManip_.drag(worldRay.near, worldRay.far);
- } else {
- this.handleMouse_(x, y, view, projection, width, height,
- o3djs.manipulators.hoverCallback_);
- }
-}
-
-/**
- * Method which should be called by end user code upon receiving a
- * mouse-up event.
- */
-o3djs.manipulators.Manager.prototype.mouseup = function() {
- if (this.draggedManip_ != null) {
- this.draggedManip_.makeInactive();
- this.draggedManip_ = null;
- }
-}
-
-/**
- * Method which should be called by end user code, typically in
- * response to mouse move events, to update the transforms of
- * manipulators which might have been moved either because of
- * manipulators further up the hierarchy, or programmatic changes to
- * transforms.
- */
-o3djs.manipulators.Manager.prototype.updateInactiveManipulators = function() {
- for (var ii in this.manipsByClientId) {
- var manip = this.manipsByClientId[ii];
- if (!manip.isActive()) {
- manip.updateBaseTransformFromAttachedTransform_();
- }
- }
-}
-
-/**
- * Base class for all manipulators.
- * @constructor
- * @param {!o3djs.manipulators.Manager} manager The manager of this
- * manipulator.
- */
-o3djs.manipulators.Manip = function(manager) {
- this.manager_ = manager;
- var pack = manager.pack;
- // This transform holds the local transformation of the manipulator,
- // which is either applied to the transform to which it is attached,
- // or (see below) consumed by the user in the manipulator's
- // callbacks. After each interaction, if there is an attached
- // transform, this local transform is added in to it and reset to
- // the identity.
- // TODO(kbr): add support for user callbacks on manipulators.
- this.localTransform_ = pack.createObject('Transform');
-
- // This transform provides an offset, if desired, between the
- // manipulator's geometry and the transform (and, implicitly, the
- // shape) to which it is attached. This allows the manipulator to be
- // easily placed below an object, for example.
- this.offsetTransform_ = pack.createObject('Transform');
-
- // This transform is the one which is actually parented to the
- // manager's parentTransform. It is used to place the manipulator in
- // world space, regardless of the world space location of the
- // parentTransform supplied to the manager. If this manipulator is
- // attached to a given transform, then upon completion of a
- // particular drag interaction, this transform is adjusted to take
- // into account the attached transform's new value.
- this.baseTransform_ = pack.createObject('Transform');
-
- // Hook up these transforms
- this.localTransform_.parent = this.offsetTransform_;
- this.offsetTransform_.parent = this.baseTransform_;
-
- // This is the transform in the scene graph to which this
- // manipulator is conceptually "attached", and whose local transform
- // we are modifying.
- this.attachedTransform_ = null;
-
- this.active_ = false;
-}
-
-/**
- * Adds shapes to the internal transform of this manipulator.
- * @private
- * @param {!Array.<!o3d.Shape>} shapes Array of shapes to add.
- */
-o3djs.manipulators.Manip.prototype.addShapes_ = function(shapes) {
- for (var ii = 0; ii < shapes.length; ii++) {
- this.localTransform_.addShape(shapes[ii]);
- }
-}
-
-/**
- * Returns the "base" transform of this manipulator, which places the
- * origin of the manipulator at the local origin of the attached
- * transform.
- * @private
- * @return {!o3d.Transform} The base transform of this manipulator.
- */
-o3djs.manipulators.Manip.prototype.getBaseTransform_ = function() {
- return this.baseTransform_;
-}
-
-/**
- * Returns the "offset" transform of this manipulator, which allows
- * the manipulator's geometry to be moved or rotated with respect to
- * the local origin of the attached transform.
- * @return {!o3d.Transform} The offset transform of this manipulator.
- */
-o3djs.manipulators.Manip.prototype.getOffsetTransform = function() {
- return this.offsetTransform_;
-}
-
-/**
- * Returns the local transform of this manipulator, which contains the
- * changes that have been made in response to the current drag
- * operation. Upon completion of the drag, this transform's effects
- * are composed in to the attached transform, and this transform is
- * reset to the identity.
- * @return {!o3d.Transform} The local transform of this manipulator.
- */
-o3djs.manipulators.Manip.prototype.getTransform = function() {
- return this.localTransform_;
-}
-
-/**
- * Sets the translation component of the offset transform. This is
- * useful for moving the manipulator's geometry with respect to the
- * local origin of the attached transform.
- * @param {!o3djs.math.Vector3} translation The offset translation for
- * this manipulator.
- */
-o3djs.manipulators.Manip.prototype.setOffsetTranslation =
- function(translation) {
- this.getOffsetTransform().localMatrix =
- o3djs.math.matrix4.setTranslation(this.getOffsetTransform().localMatrix,
- translation);
-
-}
-
-/**
- * Sets the rotation component of the offset transform. This is useful
- * for orienting the manipulator's geometry with respect to the local
- * origin of the attached transform.
- * @param {!o3djs.quaternions.Quaternion} quaternion The offset
- * rotation for this manipulator.
- */
-o3djs.manipulators.Manip.prototype.setOffsetRotation = function(quaternion) {
- var rot = o3djs.quaternions.quaternionToRotation(quaternion);
- this.getOffsetTransform().localMatrix =
- o3djs.math.matrix4.setUpper3x3(this.getOffsetTransform().localMatrix,
- rot);
-
-}
-
-/**
- * Explicitly sets the local translation of this manipulator.
- * (TODO(kbr): it is not clear that this capability should be in the
- * API.)
- * @param {!o3djs.math.Vector3} translation The local translation for
- * this manipulator.
- */
-o3djs.manipulators.Manip.prototype.setTranslation = function(translation) {
- this.getTransform().localMatrix =
- o3djs.math.matrix4.setTranslation(this.getTransform().localMatrix,
- translation);
-
-}
-
-/**
- * Explicitly sets the local rotation of this manipulator. (TODO(kbr):
- * it is not clear that this capability should be in the API.)
- * @param {!o3djs.quaternions.Quaternion} quaternion The local
- * rotation for this manipulator.
- */
-o3djs.manipulators.Manip.prototype.setRotation = function(quaternion) {
- var rot = o3djs.quaternions.quaternionToRotation(quaternion);
- this.getTransform().localMatrix =
- o3djs.math.matrix4.setUpper3x3(this.getTransform().localMatrix,
- rot);
-
-}
-
-/**
- * Attaches this manipulator to the given transform. Interactions with
- * the manipulator will cause this transform's local matrix to be
- * modified appropriately.
- * @param {!o3d.Transform} transform The transform to which this
- * manipulator should be attached.
- */
-o3djs.manipulators.Manip.prototype.attachTo = function(transform) {
- this.attachedTransform_ = transform;
- // Update our base transform to place the manipulator at exactly the
- // location of the attached transform.
- this.updateBaseTransformFromAttachedTransform_();
-}
-
-/**
- * Highlights this manipulator according to the given pick result.
- * @param {o3djs.picking.PickInfo} pickResult The pick result which
- * caused this manipulator to become highlighted.
- */
-o3djs.manipulators.Manip.prototype.highlight = function(pickResult) {
-}
-
-/**
- * Clears any highlight for this manipulator.
- */
-o3djs.manipulators.Manip.prototype.clearHighlight = function() {
-}
-
-/**
- * Activates this manipulator according to the given pick result. In
- * complex manipulators, picking different portions of the manipulator
- * may result in different forms of interaction.
- * @param {o3djs.picking.PickInfo} pickResult The pick result which
- * caused this manipulator to become active.
- */
-o3djs.manipulators.Manip.prototype.makeActive = function(pickResult) {
- this.active_ = true;
-}
-
-/**
- * Deactivates this manipulator.
- */
-o3djs.manipulators.Manip.prototype.makeInactive = function() {
- this.active_ = false;
-}
-
-/**
- * Drags this manipulator according to the world-space ray specified
- * by startPoint and endPoint. makeActive must already have been
- * called with the initial pick result causing this manipulator to
- * become active. This method exists only to be overridden.
- * @param {!o3djs.math.Vector3} startPoint Start point of the
- * world-space ray through the current mouse position.
- * @param {!o3djs.math.Vector3} endPoint End point of the world-space
- * ray through the current mouse position.
- */
-o3djs.manipulators.Manip.prototype.drag = function(startPoint,
- endPoint) {
-}
-
-/**
- * Indicates whether this manipulator is active.
- * @return {boolean} Whether this manipulator is active.
- */
-o3djs.manipulators.Manip.prototype.isActive = function() {
- return this.active_;
-}
-
-/**
- * Updates the base transform of this manipulator from the state of
- * its attached transform, resetting the local transform of this
- * manipulator to the identity.
- * @private
- */
-o3djs.manipulators.Manip.prototype.updateBaseTransformFromAttachedTransform_ =
- function() {
- if (this.attachedTransform_ != null) {
- var attWorld = this.attachedTransform_.worldMatrix;
- var parWorld = this.manager_.parentTransform.worldMatrix;
- var parWorldInv = o3djs.math.matrix4.inverse(parWorld);
- this.baseTransform_.localMatrix =
- o3djs.math.matrix4.mul(attWorld, parWorldInv);
- // Reset the manipulator's local matrix to the identity.
- this.localTransform_.localMatrix = o3djs.math.matrix4.identity();
- }
-}
-
-/**
- * Updates this manipulator's attached transform based on the values
- * in the local transform.
- * @private
- */
-o3djs.manipulators.Manip.prototype.updateAttachedTransformFromLocalTransform_ =
- function() {
- if (this.attachedTransform_ != null) {
- // Compute the composition of the base and local transforms.
- // The offset transform is skipped except for transforming the
- // local matrix's translation by the rotation component of the
- // offset transform.
- var base = this.baseTransform_.worldMatrix;
- var local = this.localTransform_.localMatrix;
- var xlate = o3djs.math.matrix4.getTranslation(local);
- var transformedXlate =
- o3djs.math.matrix4.transformDirection(
- this.offsetTransform_.localMatrix,
- o3djs.math.matrix4.getTranslation(local));
- o3djs.math.matrix4.setTranslation(local, transformedXlate);
- var totalMat = o3djs.math.matrix4.mul(base, local);
-
- // Set this into the attached transform, taking into account its
- // parent's transform, if any.
- // Note that we can not query the parent's transform directly, so
- // we compute it using a little trick.
- var attWorld = this.attachedTransform_.worldMatrix;
- var attLocal = this.attachedTransform_.localMatrix;
- var attParentMat =
- o3djs.math.matrix4.mul(attWorld,
- o3djs.math.matrix4.inverse(attLocal));
- // Now we can take the inverse of this matrix
- var attParentMatInv = o3djs.math.matrix4.inverse(attParentMat);
- totalMat = o3djs.math.matrix4.mul(attParentMatInv, totalMat);
- this.attachedTransform_.localMatrix = totalMat;
- }
-}
-
-/**
- * Sets the material of the given shape's draw elements.
- * @private
- */
-o3djs.manipulators.Manip.prototype.setMaterial_ = function(shape, material) {
- var elements = shape.elements;
- for (var ii = 0; ii < elements.length; ii++) {
- var drawElements = elements[ii].drawElements;
- for (var jj = 0; jj < drawElements.length; jj++) {
- drawElements[jj].material = material;
- }
- }
-}
-
-/**
- * Sets the materials of the given shapes' draw elements.
- * @private
- */
-o3djs.manipulators.Manip.prototype.setMaterials_ = function(shapes, material) {
- for (var ii = 0; ii < shapes.length; ii++) {
- this.setMaterial_(shapes[ii], material);
- }
-}
-
-/**
- * A manipulator allowing an object to be dragged along a line.
- * @constructor
- * @extends {o3djs.manipulators.Manip}
- * @param {!o3djs.manipulators.Manager} manager The manager for the
- * new Translate1 manipulator.
- */
-o3djs.manipulators.Translate1 = function(manager) {
- o3djs.manipulators.Manip.call(this, manager);
-
- var pack = manager.pack;
- var material = manager.defaultMaterial;
-
- var shape = manager.translate1Shape_;
- if (!shape) {
- // Create the geometry for the manipulator, which looks like a
- // two-way arrow going from (-1, 0, 0) to (1, 0, 0).
- var matrix4 = o3djs.math.matrix4;
- var zRot = matrix4.rotationZ(Math.PI / 2);
-
- var verts = o3djs.primitives.createTruncatedConeVertices(
- 0.15, // Bottom radius.
- 0.0, // Top radius.
- 0.3, // Height.
- 4, // Number of radial subdivisions.
- 1, // Number of vertical subdivisions.
- matrix4.mul(matrix4.translation([0, 0.85, 0]), zRot));
-
- verts.append(o3djs.primitives.createCylinderVertices(
- 0.06, // Radius.
- 1.4, // Height.
- 4, // Number of radial subdivisions.
- 1, // Number of vertical subdivisions.
- zRot));
-
- verts.append(o3djs.primitives.createTruncatedConeVertices(
- 0.0, // Bottom radius.
- 0.15, // Top radius.
- 0.3, // Height.
- 4, // Number of radial subdivisions.
- 1, // Number of vertical subdivisions.
- matrix4.mul(matrix4.translation([0, -0.85, 0]), zRot)));
-
- shape = verts.createShape(pack, material);
- manager.translate1Shape_ = shape;
- }
-
- this.addShapes_([ shape ]);
-
- this.transformInfo = o3djs.picking.createTransformInfo(this.getTransform(),
- manager.transformInfo);
-
- // Add a parameter to our transform to be able to change the
- // material's color for highlighting.
- this.colorParam = this.getTransform().createParam('diffuse', 'ParamFloat4');
- this.clearHighlight();
-
- /** Dragging state */
- this.dragLine = new o3djs.manipulators.Line_();
-}
-
-o3djs.base.inherit(o3djs.manipulators.Translate1, o3djs.manipulators.Manip);
-
-o3djs.manipulators.Translate1.prototype.highlight = function(pickResult) {
- // We can use instanced geometry for the entire Translate1 since its
- // entire color changes during highlighting.
- // TODO(kbr): support custom user geometry and associated callbacks.
- this.colorParam.value = o3djs.manipulators.HIGHLIGHTED_COLOR;
-}
-
-o3djs.manipulators.Translate1.prototype.clearHighlight = function() {
- this.colorParam.value = o3djs.manipulators.DEFAULT_COLOR;
-}
-
-o3djs.manipulators.Translate1.prototype.makeActive = function(pickResult) {
- o3djs.manipulators.Manip.prototype.makeActive.call(this, pickResult);
- this.highlight(pickResult);
- var worldMatrix = this.getTransform().worldMatrix;
- this.dragLine.setDirection(
- o3djs.math.matrix4.transformDirection(worldMatrix,
- o3djs.manipulators.X_AXIS));
- this.dragLine.setPoint(pickResult.worldIntersectionPosition);
-}
-
-o3djs.manipulators.Translate1.prototype.makeInactive = function() {
- o3djs.manipulators.Manip.prototype.makeInactive.call(this);
- this.clearHighlight();
- this.updateAttachedTransformFromLocalTransform_();
- this.updateBaseTransformFromAttachedTransform_();
-}
-
-o3djs.manipulators.Translate1.prototype.drag = function(startPoint,
- endPoint) {
- // Algorithm: Find closest point of ray to dragLine. Subtract this
- // point from the line's point to find difference vector; transform
- // from world to local coordinates to find new local offset of
- // manipulator.
- var closestPoint = this.dragLine.closestPointToRay(startPoint, endPoint);
- if (closestPoint == null) {
- // Drag axis is parallel to ray. Punt.
- return;
- }
- // Need to do a world-to-local transformation on the difference vector.
- // Note that we also incorporate the translation portion of the matrix.
- var diffVector =
- o3djs.math.subVector(closestPoint, this.dragLine.getPoint());
- var worldToLocal =
- o3djs.math.matrix4.inverse(this.getTransform().worldMatrix);
- this.getTransform().localMatrix =
- o3djs.math.matrix4.setTranslation(
- this.getTransform().localMatrix,
- o3djs.math.matrix4.transformDirection(worldToLocal,
- diffVector));
- this.updateAttachedTransformFromLocalTransform_();
-}
+/*
+ * 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 contains classes that implement several
+ * forms of 2D and 3D manipulation.
+ */
+
+o3djs.provide('o3djs.manipulators');
+
+o3djs.require('o3djs.material');
+
+o3djs.require('o3djs.math');
+
+o3djs.require('o3djs.picking');
+
+o3djs.require('o3djs.primitives');
+
+o3djs.require('o3djs.quaternions');
+
+/**
+ * A module implementing several forms of 2D and 3D manipulation.
+ * @namespace
+ */
+o3djs.manipulators = o3djs.manipulators || {};
+
+/**
+ * Creates a new manipulator manager, which maintains multiple
+ * manipulators in the same scene. The manager is implicitly
+ * associated with a particular O3D client via the Pack which is
+ * passed in, although multiple managers can be created for a given
+ * client. The manipulators are positioned in world coordinates and
+ * are placed in the scene graph underneath the parent transform which
+ * is passed in.
+ * @param {!o3d.Pack} pack Pack in which manipulators' geometry and
+ * materials will be created.
+ * @param {!o3d.DrawList} drawList The draw list against which
+ * internal materials are created.
+ * @param {!o3d.Transform} parentTransform The parent transform under
+ * which the manipulators' geometry should be parented.
+ * @param {!o3d.RenderNode} parentRenderNode The parent render node
+ * under which the manipulators' draw elements should be placed.
+ * @param {number} renderNodePriority The priority that the
+ * manipulators' geometry should use for rendering.
+ * @return {!o3djs.manipulators.Manager} The created manipulator
+ * manager.
+ */
+o3djs.manipulators.createManager = function(pack,
+ drawList,
+ parentTransform,
+ parentRenderNode,
+ renderNodePriority) {
+ return new o3djs.manipulators.Manager(pack,
+ drawList,
+ parentTransform,
+ parentRenderNode,
+ renderNodePriority);
+}
+
+//
+// Some linear algebra classes.
+// TODO(kbr): find a better home for these.
+//
+
+/**
+ * Creates a new Line object, which implements projection and
+ * closest-point operations.
+ * @constructor
+ * @private
+ * @param {o3djs.math.Vector3} opt_direction The direction of the
+ * line. Does not need to be normalized but must not be the zero
+ * vector. Defaults to [1, 0, 0] if not specified.
+ * @param {o3djs.math.Vector3} opt_point A point through which the
+ * line goes. Defaults to [0, 0, 0] if not specified.
+ */
+o3djs.manipulators.Line_ = function(opt_direction,
+ opt_point) {
+ if (opt_direction) {
+ this.direction_ = o3djs.math.copyVector(opt_direction);
+ } else {
+ this.direction_ = [1, 0, 0];
+ }
+
+ if (opt_point) {
+ this.point_ = o3djs.math.copyVector(opt_point);
+ } else {
+ this.point_ = [0, 0, 0];
+ }
+
+ // Helper for computing projections along the line
+ this.alongVec_ = [0, 0, 0];
+ this.recalc_();
+}
+
+/**
+ * Sets the direction of this line.
+ * @private
+ * @param {!o3djs.math.Vector3} direction The new direction of the
+ * line. Does not need to be normalized but must not be the zero
+ * vector.
+ */
+o3djs.manipulators.Line_.prototype.setDirection = function(direction) {
+ this.direction_ = o3djs.math.copyVector(direction);
+ this.recalc_();
+}
+
+/**
+ * Gets the direction of this line.
+ * @private
+ * @return {!o3djs.math.Vector3} The direction of the line.
+ */
+o3djs.manipulators.Line_.prototype.getDirection = function() {
+ return this.direction_;
+}
+
+/**
+ * Sets one point through which this line travels.
+ * @private
+ * @param {!o3djs.math.Vector3} point A point which through the line
+ * will travel.
+ */
+o3djs.manipulators.Line_.prototype.setPoint = function(point) {
+ this.point_ = o3djs.math.copyVector(point);
+ this.recalc_();
+}
+
+/**
+ * Gets one point through which this line travels.
+ * @private
+ * @return {!o3djs.math.Vector3} A point which through the line
+ * travels.
+ */
+o3djs.manipulators.Line_.prototype.getPoint = function() {
+ return this.point_;
+}
+
+/**
+ * Projects a point onto the line.
+ * @private
+ * @param {!o3djs.math.Vector3} point Point to be projected.
+ * @return {!o3djs.math.Vector3} Point on the line closest to the
+ * passed point.
+ */
+o3djs.manipulators.Line_.prototype.projectPoint = function(point) {
+ var dotp = o3djs.math.dot(this.direction_, point);
+ return o3djs.math.addVector(this.alongVec_,
+ o3djs.math.mulScalarVector(dotp,
+ this.direction_));
+}
+
+o3djs.manipulators.EPSILON = 0.00001;
+o3djs.manipulators.X_AXIS = [1, 0, 0];
+
+
+/**
+ * Returns the closest point on this line to the given ray, which is
+ * specified by start and end points. If the ray is parallel to the
+ * line, returns null.
+ * @private
+ * @param {!o3djs.math.Vector3} startPoint Start point of ray.
+ * @param {!o3djs.math.Vector3} endPoint End point of ray.
+ * @return {o3djs.math.Vector3} The closest point on the line to the
+ * ray, or null if the ray is parallel to the line.
+ */
+o3djs.manipulators.Line_.prototype.closestPointToRay = function(startPoint,
+ endPoint) {
+ // Consider a two-sided line and a one-sided ray, both in in 3D
+ // space, and assume they are not parallel. Their parametric
+ // formulation is:
+ //
+ // p1 = point + t * dir
+ // p2 = raystart + u * raydir
+ //
+ // Here t and u are scalar parameter values, and the other values
+ // are three-dimensional vectors. p1 and p2 are arbitrary points on
+ // the line and ray, respectively.
+ //
+ // At the points cp1 and cp2 on these two lines where the line and
+ // the ray are closest together, the line segment between cp1 and
+ // cp2 is perpendicular to both of the lines.
+ //
+ // We can therefore write the following equations:
+ //
+ // dot( dir, (cp2 - cp1)) = 0
+ // dot(raydir, (cp2 - cp1)) = 0
+ //
+ // Define t' and u' as the parameter values for cp1 and cp2,
+ // respectively. Expanding, these equations become
+ //
+ // dot( dir, ((raystart + u' * raydir) - (point + t' * dir))) = 0
+ // dot(raydir, ((raystart + u' * raydir) - (point + t' * dir))) = 0
+ //
+ // With some reshuffling, these can be expressed in vector/matrix
+ // form:
+ //
+ // [ dot( dir, raystart) - dot( dir, point) ]
+ // [ dot(raydir, raystart) - dot(raydir, point) ] + (continued)
+ //
+ // [ -dot( dir, dir) dot( dir, raydir) ] [ t' ] [0]
+ // [ -dot(raydir, dir) dot(raydir, raydir) ] * [ u' ] = [0]
+ //
+ // u' is the parameter for the world space ray being cast into the
+ // screen. We can deduce whether the starting point of the ray is
+ // actually the closest point to the infinite 3D line by whether the
+ // value of u' is less than zero.
+ var rayDirection = o3djs.math.subVector(endPoint, startPoint);
+ var ddrd = o3djs.math.dot(this.direction_, rayDirection);
+ var A = [[-o3djs.math.lengthSquared(this.direction_), ddrd],
+ [ddrd, -o3djs.math.lengthSquared(rayDirection)]];
+ var det = o3djs.math.det2(A);
+ if (Math.abs(det) < o3djs.manipulators.EPSILON) {
+ return null;
+ }
+ var Ainv = o3djs.math.inverse2(A);
+ var b = [o3djs.math.dot(this.point_, this.direction_) -
+ o3djs.math.dot(startPoint, this.direction_),
+ o3djs.math.dot(startPoint, rayDirection) -
+ o3djs.math.dot(this.point_, rayDirection)];
+ var x = o3djs.math.mulMatrixVector(Ainv, b);
+ if (x[1] < 0) {
+ // Means that start point is closest point to this line
+ return startPoint;
+ } else {
+ return o3djs.math.addVector(this.point_,
+ o3djs.math.mulScalarVector(
+ x[0],
+ this.direction_));
+ }
+}
+
+/**
+ * Performs internal recalculations when the parameters of the line change.
+ * @private
+ */
+o3djs.manipulators.Line_.prototype.recalc_ = function() {
+ var denom = o3djs.math.lengthSquared(this.direction_);
+ if (denom == 0.0) {
+ throw 'Line_.recalc: ERROR: direction was the zero vector (not allowed)';
+ }
+ this.alongVec_ =
+ o3djs.math.subVector(this.point_,
+ o3djs.math.mulScalarVector(
+ o3djs.math.dot(this.point_,
+ this.direction_),
+ this.direction_));
+}
+
+o3djs.manipulators.DEFAULT_COLOR = [0.8, 0.8, 0.8, 1.0];
+o3djs.manipulators.HIGHLIGHTED_COLOR = [0.9, 0.9, 0.0, 1.0];
+
+/**
+ * Constructs a new manipulator manager. Do not call this directly;
+ * use o3djs.manipulators.createManager instead.
+ * @constructor
+ * @param {!o3d.Pack} pack Pack in which manipulators' geometry and
+ * materials will be created.
+ * @param {!o3d.DrawList} drawList The draw list against which
+ * internal materials are created.
+ * @param {!o3d.Transform} parentTransform The parent transform under
+ * which the manipulators' geometry should be parented.
+ * @param {!o3d.RenderNode} parentRenderNode The parent render node
+ * under which the manipulators' draw elements should be placed.
+ * @param {number} renderNodePriority The priority that the
+ * manipulators' geometry should use for rendering.
+ */
+o3djs.manipulators.Manager = function(pack,
+ drawList,
+ parentTransform,
+ parentRenderNode,
+ renderNodePriority) {
+ this.pack = pack;
+ this.drawList = drawList;
+ this.parentTransform = parentTransform;
+ this.parentRenderNode = parentRenderNode;
+ this.renderNodePriority = renderNodePriority;
+
+ this.lightPosition = [10, 10, 10];
+
+ // Create the default and highlighted materials.
+ this.defaultMaterial =
+ this.createPhongMaterial_(o3djs.manipulators.DEFAULT_COLOR);
+ this.highlightedMaterial =
+ this.createPhongMaterial_(o3djs.manipulators.HIGHLIGHTED_COLOR);
+
+ // This is a map from the manip's parent Transform clientId to the manip.
+ this.manipsByClientId = [];
+
+ // Presumably we need a TransformInfo for the parentTransform.
+ this.transformInfo =
+ o3djs.picking.createTransformInfo(this.parentTransform, null);
+
+ /**
+ * The currently-highlighted manipulator.
+ * @type {o3djs.manipulators.Manip}
+ */
+ this.highlightedManip = null;
+
+ /**
+ * The manipulator currently being dragged.
+ * @private
+ * @type {o3djs.manipulators.Manip}
+ */
+ this.draggedManip_ = null;
+}
+
+/**
+ * Creates a phong material based on the given single color.
+ * @private
+ * @param {!o3djs.math.Vector4} baseColor A vector with 4 entries, the
+ * R,G,B, and A components of a color.
+ * @return {!o3d.Material} A phong material whose overall pigment is baseColor.
+ */
+o3djs.manipulators.Manager.prototype.createPhongMaterial_ =
+ function(baseColor) {
+ // Create a new, empty Material object.
+ var material = this.pack.createObject('Material');
+
+ o3djs.effect.attachStandardShader(
+ this.pack, material, this.lightPosition, 'phong');
+
+ material.drawList = this.drawList;
+
+ // Assign parameters to the phong material.
+ material.getParam('emissive').value = [0, 0, 0, 1];
+ material.getParam('ambient').value =
+ o3djs.math.mulScalarVector(0.1, baseColor);
+ material.getParam('diffuse').value = baseColor;
+ material.getParam('specular').value = [.2, .2, .2, 1];
+ material.getParam('shininess').value = 20;
+
+ return material;
+}
+
+/**
+ * Creates a new Translate1 manipulator. A Translate1 moves along the
+ * X axis in its local coordinate system.
+ * @return {!o3djs.manipulators.Translate1} A new Translate1 manipulator.
+ */
+o3djs.manipulators.Manager.prototype.createTranslate1 = function() {
+ var manip = new o3djs.manipulators.Translate1(this);
+ this.add_(manip);
+ return manip;
+}
+
+/**
+ * Adds a manipulator to this manager's set.
+ * @private
+ * @param {!o3djs.manipulators.Manip} manip The manipulator to add.
+ */
+o3djs.manipulators.Manager.prototype.add_ = function(manip) {
+ // Generate draw elements for the manipulator's transform
+ manip.getTransform().createDrawElements(this.pack, null);
+ // Add the manipulator's transform to the parent transform
+ manip.getBaseTransform_().parent = this.parentTransform;
+ // Add the manipulator into our managed list
+ this.manipsByClientId[manip.getTransform().clientId] = manip;
+}
+
+/**
+ * Event handler for multiple kinds of mouse events.
+ * @private
+ * @param {number} x The x coordinate of the mouse event.
+ * @param {number} y The y coordinate of the mouse event.
+ * @param {!o3djs.math.Matrix4} view The current view matrix.
+ * @param {!o3djs.math.Matrix4} projection The current projection matrix.
+ * @param {number} width The width of the viewport.
+ * @param {number} height The height of the viewport.
+ * @param {!function(!o3djs.manipulators.Manager,
+ * o3djs.picking.PickInfo, o3djs.manipulators.Manip): void} func
+ * Callback function. Always receives the manager as argument; if
+ * a manipulator was picked, receives non-null PickInfo and Manip
+ * arguments, otherwise receives null for both of these arguments.
+ */
+o3djs.manipulators.Manager.prototype.handleMouse_ = function(x,
+ y,
+ view,
+ projection,
+ width,
+ height,
+ func) {
+ this.transformInfo.update();
+
+ // Create the world ray
+ var worldRay =
+ o3djs.picking.clientPositionToWorldRayEx(x, y,
+ view, projection,
+ width, height);
+
+ // Pick against all of the manipulators' geometry
+ var pickResult = this.transformInfo.pick(worldRay);
+ if (pickResult != null) {
+ // Find which manipulator we picked.
+ // NOTE this assumes some things about the transform graph
+ // structure of the manipulators.
+ var manip =
+ this.manipsByClientId[pickResult.shapeInfo.parent.transform.clientId];
+ func(this, pickResult, manip);
+ } else {
+ func(this, null, null);
+ }
+}
+
+/**
+ * Callback handling the mouse-down event on a manipulator.
+ * @private
+ * @param {!o3djs.manipulators.Manager} manager The manipulator
+ * manager owning the given manipulator.
+ * @param {o3djs.picking.PickInfo} pickResult The picking information
+ * associated with the mouse-down event.
+ * @param {o3djs.manipulators.Manip} manip The manipulator to be
+ * selected.
+ */
+o3djs.manipulators.mouseDownCallback_ = function(manager,
+ pickResult,
+ manip) {
+ if (manip != null) {
+ manager.draggedManip_ = manip;
+ manip.makeActive(pickResult);
+ }
+}
+
+/**
+ * Callback handling the mouse-over event on a manipulator.
+ * @private
+ * @param {!o3djs.manipulators.Manager} manager The manipulator
+ * manager owning the given manipulator.
+ * @param {o3djs.picking.PickInfo} pickResult The picking information
+ * associated with the mouse-over event.
+ * @param {o3djs.manipulators.Manip} manip The manipulator to be
+ * highlighted.
+ */
+o3djs.manipulators.hoverCallback_ = function(manager,
+ pickResult,
+ manip) {
+ if (manager.highlightedManip != null &&
+ manager.highlightedManip != manip) {
+ // Un-highlight the previously highlighted manipulator
+ manager.highlightedManip.clearHighlight();
+ manager.highlightedManip = null;
+ }
+
+ if (manip != null) {
+ manip.highlight(pickResult);
+ manager.highlightedManip = manip;
+ }
+}
+
+/**
+ * Method which should be called by end user code upon receiving a
+ * mouse-down event.
+ * @param {number} x The x coordinate of the mouse event.
+ * @param {number} y The y coordinate of the mouse event.
+ * @param {!o3djs.math.Matrix4} view The current view matrix.
+ * @param {!o3djs.math.Matrix4} projection The current projection matrix.
+ * @param {number} width The width of the viewport.
+ * @param {number} height The height of the viewport.
+ */
+o3djs.manipulators.Manager.prototype.mousedown = function(x,
+ y,
+ view,
+ projection,
+ width,
+ height) {
+ this.handleMouse_(x, y, view, projection, width, height,
+ o3djs.manipulators.mouseDownCallback_);
+}
+
+/**
+ * Method which should be called by end user code upon receiving a
+ * mouse motion event.
+ * @param {number} x The x coordinate of the mouse event.
+ * @param {number} y The y coordinate of the mouse event.
+ * @param {!o3djs.math.Matrix4} view The current view matrix.
+ * @param {!o3djs.math.Matrix4} projection The current projection matrix.
+ * @param {number} width The width of the viewport.
+ * @param {number} height The height of the viewport.
+ */
+o3djs.manipulators.Manager.prototype.mousemove = function(x,
+ y,
+ view,
+ projection,
+ width,
+ height) {
+ if (this.draggedManip_ != null) {
+ var worldRay =
+ o3djs.picking.clientPositionToWorldRayEx(x, y,
+ view, projection,
+ width, height);
+ this.draggedManip_.drag(worldRay.near, worldRay.far);
+ } else {
+ this.handleMouse_(x, y, view, projection, width, height,
+ o3djs.manipulators.hoverCallback_);
+ }
+}
+
+/**
+ * Method which should be called by end user code upon receiving a
+ * mouse-up event.
+ */
+o3djs.manipulators.Manager.prototype.mouseup = function() {
+ if (this.draggedManip_ != null) {
+ this.draggedManip_.makeInactive();
+ this.draggedManip_ = null;
+ }
+}
+
+/**
+ * Method which should be called by end user code, typically in
+ * response to mouse move events, to update the transforms of
+ * manipulators which might have been moved either because of
+ * manipulators further up the hierarchy, or programmatic changes to
+ * transforms.
+ */
+o3djs.manipulators.Manager.prototype.updateInactiveManipulators = function() {
+ for (var ii in this.manipsByClientId) {
+ var manip = this.manipsByClientId[ii];
+ if (!manip.isActive()) {
+ manip.updateBaseTransformFromAttachedTransform_();
+ }
+ }
+}
+
+/**
+ * Base class for all manipulators.
+ * @constructor
+ * @param {!o3djs.manipulators.Manager} manager The manager of this
+ * manipulator.
+ */
+o3djs.manipulators.Manip = function(manager) {
+ this.manager_ = manager;
+ var pack = manager.pack;
+ // This transform holds the local transformation of the manipulator,
+ // which is either applied to the transform to which it is attached,
+ // or (see below) consumed by the user in the manipulator's
+ // callbacks. After each interaction, if there is an attached
+ // transform, this local transform is added in to it and reset to
+ // the identity.
+ // TODO(kbr): add support for user callbacks on manipulators.
+ this.localTransform_ = pack.createObject('Transform');
+
+ // This transform provides an offset, if desired, between the
+ // manipulator's geometry and the transform (and, implicitly, the
+ // shape) to which it is attached. This allows the manipulator to be
+ // easily placed below an object, for example.
+ this.offsetTransform_ = pack.createObject('Transform');
+
+ // This transform is the one which is actually parented to the
+ // manager's parentTransform. It is used to place the manipulator in
+ // world space, regardless of the world space location of the
+ // parentTransform supplied to the manager. If this manipulator is
+ // attached to a given transform, then upon completion of a
+ // particular drag interaction, this transform is adjusted to take
+ // into account the attached transform's new value.
+ this.baseTransform_ = pack.createObject('Transform');
+
+ // Hook up these transforms
+ this.localTransform_.parent = this.offsetTransform_;
+ this.offsetTransform_.parent = this.baseTransform_;
+
+ // This is the transform in the scene graph to which this
+ // manipulator is conceptually "attached", and whose local transform
+ // we are modifying.
+ this.attachedTransform_ = null;
+
+ this.active_ = false;
+}
+
+/**
+ * Adds shapes to the internal transform of this manipulator.
+ * @private
+ * @param {!Array.<!o3d.Shape>} shapes Array of shapes to add.
+ */
+o3djs.manipulators.Manip.prototype.addShapes_ = function(shapes) {
+ for (var ii = 0; ii < shapes.length; ii++) {
+ this.localTransform_.addShape(shapes[ii]);
+ }
+}
+
+/**
+ * Returns the "base" transform of this manipulator, which places the
+ * origin of the manipulator at the local origin of the attached
+ * transform.
+ * @private
+ * @return {!o3d.Transform} The base transform of this manipulator.
+ */
+o3djs.manipulators.Manip.prototype.getBaseTransform_ = function() {
+ return this.baseTransform_;
+}
+
+/**
+ * Returns the "offset" transform of this manipulator, which allows
+ * the manipulator's geometry to be moved or rotated with respect to
+ * the local origin of the attached transform.
+ * @return {!o3d.Transform} The offset transform of this manipulator.
+ */
+o3djs.manipulators.Manip.prototype.getOffsetTransform = function() {
+ return this.offsetTransform_;
+}
+
+/**
+ * Returns the local transform of this manipulator, which contains the
+ * changes that have been made in response to the current drag
+ * operation. Upon completion of the drag, this transform's effects
+ * are composed in to the attached transform, and this transform is
+ * reset to the identity.
+ * @return {!o3d.Transform} The local transform of this manipulator.
+ */
+o3djs.manipulators.Manip.prototype.getTransform = function() {
+ return this.localTransform_;
+}
+
+/**
+ * Sets the translation component of the offset transform. This is
+ * useful for moving the manipulator's geometry with respect to the
+ * local origin of the attached transform.
+ * @param {!o3djs.math.Vector3} translation The offset translation for
+ * this manipulator.
+ */
+o3djs.manipulators.Manip.prototype.setOffsetTranslation =
+ function(translation) {
+ this.getOffsetTransform().localMatrix =
+ o3djs.math.matrix4.setTranslation(this.getOffsetTransform().localMatrix,
+ translation);
+
+}
+
+/**
+ * Sets the rotation component of the offset transform. This is useful
+ * for orienting the manipulator's geometry with respect to the local
+ * origin of the attached transform.
+ * @param {!o3djs.quaternions.Quaternion} quaternion The offset
+ * rotation for this manipulator.
+ */
+o3djs.manipulators.Manip.prototype.setOffsetRotation = function(quaternion) {
+ var rot = o3djs.quaternions.quaternionToRotation(quaternion);
+ this.getOffsetTransform().localMatrix =
+ o3djs.math.matrix4.setUpper3x3(this.getOffsetTransform().localMatrix,
+ rot);
+
+}
+
+/**
+ * Explicitly sets the local translation of this manipulator.
+ * (TODO(kbr): it is not clear that this capability should be in the
+ * API.)
+ * @param {!o3djs.math.Vector3} translation The local translation for
+ * this manipulator.
+ */
+o3djs.manipulators.Manip.prototype.setTranslation = function(translation) {
+ this.getTransform().localMatrix =
+ o3djs.math.matrix4.setTranslation(this.getTransform().localMatrix,
+ translation);
+
+}
+
+/**
+ * Explicitly sets the local rotation of this manipulator. (TODO(kbr):
+ * it is not clear that this capability should be in the API.)
+ * @param {!o3djs.quaternions.Quaternion} quaternion The local
+ * rotation for this manipulator.
+ */
+o3djs.manipulators.Manip.prototype.setRotation = function(quaternion) {
+ var rot = o3djs.quaternions.quaternionToRotation(quaternion);
+ this.getTransform().localMatrix =
+ o3djs.math.matrix4.setUpper3x3(this.getTransform().localMatrix,
+ rot);
+
+}
+
+/**
+ * Attaches this manipulator to the given transform. Interactions with
+ * the manipulator will cause this transform's local matrix to be
+ * modified appropriately.
+ * @param {!o3d.Transform} transform The transform to which this
+ * manipulator should be attached.
+ */
+o3djs.manipulators.Manip.prototype.attachTo = function(transform) {
+ this.attachedTransform_ = transform;
+ // Update our base transform to place the manipulator at exactly the
+ // location of the attached transform.
+ this.updateBaseTransformFromAttachedTransform_();
+}
+
+/**
+ * Highlights this manipulator according to the given pick result.
+ * @param {o3djs.picking.PickInfo} pickResult The pick result which
+ * caused this manipulator to become highlighted.
+ */
+o3djs.manipulators.Manip.prototype.highlight = function(pickResult) {
+}
+
+/**
+ * Clears any highlight for this manipulator.
+ */
+o3djs.manipulators.Manip.prototype.clearHighlight = function() {
+}
+
+/**
+ * Activates this manipulator according to the given pick result. In
+ * complex manipulators, picking different portions of the manipulator
+ * may result in different forms of interaction.
+ * @param {o3djs.picking.PickInfo} pickResult The pick result which
+ * caused this manipulator to become active.
+ */
+o3djs.manipulators.Manip.prototype.makeActive = function(pickResult) {
+ this.active_ = true;
+}
+
+/**
+ * Deactivates this manipulator.
+ */
+o3djs.manipulators.Manip.prototype.makeInactive = function() {
+ this.active_ = false;
+}
+
+/**
+ * Drags this manipulator according to the world-space ray specified
+ * by startPoint and endPoint. makeActive must already have been
+ * called with the initial pick result causing this manipulator to
+ * become active. This method exists only to be overridden.
+ * @param {!o3djs.math.Vector3} startPoint Start point of the
+ * world-space ray through the current mouse position.
+ * @param {!o3djs.math.Vector3} endPoint End point of the world-space
+ * ray through the current mouse position.
+ */
+o3djs.manipulators.Manip.prototype.drag = function(startPoint,
+ endPoint) {
+}
+
+/**
+ * Indicates whether this manipulator is active.
+ * @return {boolean} Whether this manipulator is active.
+ */
+o3djs.manipulators.Manip.prototype.isActive = function() {
+ return this.active_;
+}
+
+/**
+ * Updates the base transform of this manipulator from the state of
+ * its attached transform, resetting the local transform of this
+ * manipulator to the identity.
+ * @private
+ */
+o3djs.manipulators.Manip.prototype.updateBaseTransformFromAttachedTransform_ =
+ function() {
+ if (this.attachedTransform_ != null) {
+ var attWorld = this.attachedTransform_.worldMatrix;
+ var parWorld = this.manager_.parentTransform.worldMatrix;
+ var parWorldInv = o3djs.math.matrix4.inverse(parWorld);
+ this.baseTransform_.localMatrix =
+ o3djs.math.matrix4.mul(attWorld, parWorldInv);
+ // Reset the manipulator's local matrix to the identity.
+ this.localTransform_.localMatrix = o3djs.math.matrix4.identity();
+ }
+}
+
+/**
+ * Updates this manipulator's attached transform based on the values
+ * in the local transform.
+ * @private
+ */
+o3djs.manipulators.Manip.prototype.updateAttachedTransformFromLocalTransform_ =
+ function() {
+ if (this.attachedTransform_ != null) {
+ // Compute the composition of the base and local transforms.
+ // The offset transform is skipped except for transforming the
+ // local matrix's translation by the rotation component of the
+ // offset transform.
+ var base = this.baseTransform_.worldMatrix;
+ var local = this.localTransform_.localMatrix;
+ var xlate = o3djs.math.matrix4.getTranslation(local);
+ var transformedXlate =
+ o3djs.math.matrix4.transformDirection(
+ this.offsetTransform_.localMatrix,
+ o3djs.math.matrix4.getTranslation(local));
+ o3djs.math.matrix4.setTranslation(local, transformedXlate);
+ var totalMat = o3djs.math.matrix4.mul(base, local);
+
+ // Set this into the attached transform, taking into account its
+ // parent's transform, if any.
+ // Note that we can not query the parent's transform directly, so
+ // we compute it using a little trick.
+ var attWorld = this.attachedTransform_.worldMatrix;
+ var attLocal = this.attachedTransform_.localMatrix;
+ var attParentMat =
+ o3djs.math.matrix4.mul(attWorld,
+ o3djs.math.matrix4.inverse(attLocal));
+ // Now we can take the inverse of this matrix
+ var attParentMatInv = o3djs.math.matrix4.inverse(attParentMat);
+ totalMat = o3djs.math.matrix4.mul(attParentMatInv, totalMat);
+ this.attachedTransform_.localMatrix = totalMat;
+ }
+}
+
+/**
+ * Sets the material of the given shape's draw elements.
+ * @private
+ */
+o3djs.manipulators.Manip.prototype.setMaterial_ = function(shape, material) {
+ var elements = shape.elements;
+ for (var ii = 0; ii < elements.length; ii++) {
+ var drawElements = elements[ii].drawElements;
+ for (var jj = 0; jj < drawElements.length; jj++) {
+ drawElements[jj].material = material;
+ }
+ }
+}
+
+/**
+ * Sets the materials of the given shapes' draw elements.
+ * @private
+ */
+o3djs.manipulators.Manip.prototype.setMaterials_ = function(shapes, material) {
+ for (var ii = 0; ii < shapes.length; ii++) {
+ this.setMaterial_(shapes[ii], material);
+ }
+}
+
+/**
+ * A manipulator allowing an object to be dragged along a line.
+ * @constructor
+ * @extends {o3djs.manipulators.Manip}
+ * @param {!o3djs.manipulators.Manager} manager The manager for the
+ * new Translate1 manipulator.
+ */
+o3djs.manipulators.Translate1 = function(manager) {
+ o3djs.manipulators.Manip.call(this, manager);
+
+ var pack = manager.pack;
+ var material = manager.defaultMaterial;
+
+ var shape = manager.translate1Shape_;
+ if (!shape) {
+ // Create the geometry for the manipulator, which looks like a
+ // two-way arrow going from (-1, 0, 0) to (1, 0, 0).
+ var matrix4 = o3djs.math.matrix4;
+ var zRot = matrix4.rotationZ(Math.PI / 2);
+
+ var verts = o3djs.primitives.createTruncatedConeVertices(
+ 0.15, // Bottom radius.
+ 0.0, // Top radius.
+ 0.3, // Height.
+ 4, // Number of radial subdivisions.
+ 1, // Number of vertical subdivisions.
+ matrix4.mul(matrix4.translation([0, 0.85, 0]), zRot));
+
+ verts.append(o3djs.primitives.createCylinderVertices(
+ 0.06, // Radius.
+ 1.4, // Height.
+ 4, // Number of radial subdivisions.
+ 1, // Number of vertical subdivisions.
+ zRot));
+
+ verts.append(o3djs.primitives.createTruncatedConeVertices(
+ 0.0, // Bottom radius.
+ 0.15, // Top radius.
+ 0.3, // Height.
+ 4, // Number of radial subdivisions.
+ 1, // Number of vertical subdivisions.
+ matrix4.mul(matrix4.translation([0, -0.85, 0]), zRot)));
+
+ shape = verts.createShape(pack, material);
+ manager.translate1Shape_ = shape;
+ }
+
+ this.addShapes_([ shape ]);
+
+ this.transformInfo = o3djs.picking.createTransformInfo(this.getTransform(),
+ manager.transformInfo);
+
+ // Add a parameter to our transform to be able to change the
+ // material's color for highlighting.
+ this.colorParam = this.getTransform().createParam('diffuse', 'ParamFloat4');
+ this.clearHighlight();
+
+ /** Dragging state */
+ this.dragLine = new o3djs.manipulators.Line_();
+}
+
+o3djs.base.inherit(o3djs.manipulators.Translate1, o3djs.manipulators.Manip);
+
+o3djs.manipulators.Translate1.prototype.highlight = function(pickResult) {
+ // We can use instanced geometry for the entire Translate1 since its
+ // entire color changes during highlighting.
+ // TODO(kbr): support custom user geometry and associated callbacks.
+ this.colorParam.value = o3djs.manipulators.HIGHLIGHTED_COLOR;
+}
+
+o3djs.manipulators.Translate1.prototype.clearHighlight = function() {
+ this.colorParam.value = o3djs.manipulators.DEFAULT_COLOR;
+}
+
+o3djs.manipulators.Translate1.prototype.makeActive = function(pickResult) {
+ o3djs.manipulators.Manip.prototype.makeActive.call(this, pickResult);
+ this.highlight(pickResult);
+ var worldMatrix = this.getTransform().worldMatrix;
+ this.dragLine.setDirection(
+ o3djs.math.matrix4.transformDirection(worldMatrix,
+ o3djs.manipulators.X_AXIS));
+ this.dragLine.setPoint(pickResult.worldIntersectionPosition);
+}
+
+o3djs.manipulators.Translate1.prototype.makeInactive = function() {
+ o3djs.manipulators.Manip.prototype.makeInactive.call(this);
+ this.clearHighlight();
+ this.updateAttachedTransformFromLocalTransform_();
+ this.updateBaseTransformFromAttachedTransform_();
+}
+
+o3djs.manipulators.Translate1.prototype.drag = function(startPoint,
+ endPoint) {
+ // Algorithm: Find closest point of ray to dragLine. Subtract this
+ // point from the line's point to find difference vector; transform
+ // from world to local coordinates to find new local offset of
+ // manipulator.
+ var closestPoint = this.dragLine.closestPointToRay(startPoint, endPoint);
+ if (closestPoint == null) {
+ // Drag axis is parallel to ray. Punt.
+ return;
+ }
+ // Need to do a world-to-local transformation on the difference vector.
+ // Note that we also incorporate the translation portion of the matrix.
+ var diffVector =
+ o3djs.math.subVector(closestPoint, this.dragLine.getPoint());
+ var worldToLocal =
+ o3djs.math.matrix4.inverse(this.getTransform().worldMatrix);
+ this.getTransform().localMatrix =
+ o3djs.math.matrix4.setTranslation(
+ this.getTransform().localMatrix,
+ o3djs.math.matrix4.transformDirection(worldToLocal,
+ diffVector));
+ this.updateAttachedTransformFromLocalTransform_();
+}
diff --git a/o3d/samples/o3djs/performance.js b/o3d/samples/o3djs/performance.js
index 92865e5..c5faeaa 100644
--- a/o3d/samples/o3djs/performance.js
+++ b/o3d/samples/o3djs/performance.js
@@ -1,202 +1,202 @@
-/*
- * 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 contains a utility that helps adjust rendering
- * quality [or any other setting, really] based on rendering performance.
- *
- */
-
-o3djs.provide('o3djs.performance');
-
-/**
- * A Module to help with adjusting performance.
- * @namespace
- */
-o3djs.performance = o3djs.performance || {};
-
-/**
- * Creates a utility that monitors performance [in terms of FPS] and helps to
- * adjust the rendered scene accordingly.
- * @param {number} targetFPSMin the minimum acceptable frame rate; if we're
- * under this, try to decrease quality to improve performance.
- * @param {number} targetFPSMax if we're over this, try to increase quality.
- * @param {!function(): void} increaseQuality a function to increase
- * quality because we're rendering at high-enough FPS to afford it.
- * @param {!function(): void} decreaseQuality a function to decrease
- * quality to try to raise our rendering speed.
- * @param {!o3djs.performance.PerformanceMonitor.Options} opt_options Options.
- * @return {!o3djs.performance.PerformanceMonitor} The created
- * PerformanceMonitor.
- */
-o3djs.performance.createPerformanceMonitor = function(
- targetFPSMin, targetFPSMax, increaseQuality, decreaseQuality, opt_options) {
- return new o3djs.performance.PerformanceMonitor(targetFPSMin, targetFPSMax,
- increaseQuality, decreaseQuality, opt_options);
-};
-
-/**
- * A class that monitors performance [in terms of FPS] and helps to adjust the
- * rendered scene accordingly.
- * @constructor
- * @param {number} targetFPSMin the minimum acceptable frame rate; if we're
- * under this, try to decrease quality to improve performance.
- * @param {number} targetFPSMax if we're over this, try to increase quality.
- * @param {function(): void} increaseQuality a function to increase
- * quality/lower FPS.
- * @param {function(): void} decreaseQuality a function to decrease
- * quality/raise FPS.
- * @param {!o3djs.performance.PerformanceMonitor.Options} opt_options Options.
- */
-o3djs.performance.PerformanceMonitor = function(
- targetFPSMin, targetFPSMax, increaseQuality, decreaseQuality, opt_options) {
- opt_options = opt_options || {};
-
- /**
- * A function to increase quality/lower FPS.
- * @type {function(): void}
- */
- this.increaseQuality = increaseQuality;
-
- /**
- * A function to decrease quality/raise FPS.
- * @type {function(): void}
- */
- this.decreaseQuality = decreaseQuality;
-
- /**
- * The mean time taken per frame so far, in seconds. This is only valid once
- * we've collected at least minSamples samples.
- * @type {number}
- */
- this.meanFrameTime = 0;
-
- /**
- * The number of samples we've collected so far, when that number is less than
- * or equal to this.damping. After that point, we no longer update
- * this.sampleCount, so it will clip at this.damping.
- *
- * @type {number}
- */
- this.sampleCount = 0;
-
- /**
- * The minimum number of samples to collect before trying to adjust quality.
- *
- * @type {number}
- */
- this.minSamples = opt_options.opt_minSamples || 60;
-
- /**
- * A number that controls the rate at which the effects of any given sample
- * fade away. Higher is slower, but also means that each individual sample
- * counts for less at its most-influential. Damping defaults to 120; anywhere
- * between 60 and 600 are probably reasonable values, depending on your needs,
- * but the number must be no less than minSamples.
- *
- * @type {number}
- */
- this.damping = opt_options.opt_damping || 120;
-
- /**
- * The minimum number of samples to take in between adjustments, to cut down
- * on overshoot. It defaults to 2 * minSamples.
- *
- * @type {number}
- */
- this.delayCycles = opt_options.opt_delayCycles || 2 * this.minSamples;
-
- this.targetFrameTimeMax_ = 1 / targetFPSMin;
- this.targetFrameTimeMin_ = 1 / targetFPSMax;
- this.scaleInput_ = 1 / this.minSamples;
- this.scaleMean_ = 1;
- this.delayCyclesLeft_ = 0;
- if (this.damping < this.minSamples) {
- throw Error('Damping must be at least minSamples.');
- }
-};
-
-/**
- * Options for the PerformanceMonitor.
- *
- * opt_minSamples is the minimum number of samples to take before making any
- * performance adjustments.
- * opt_damping is a number that controls the rate at which the effects of any
- * given sample fade away. Higher is slower, but also means that each
- * individual sample counts for less at its most-influential. Damping
- * defaults to 120; anywhere between 60 and 600 are probably reasonable values,
- * depending on your needs, but the number must be no less than minSamples.
- * opt_delayCycles is the minimum number of samples to take in between
- * adjustments, to cut down on overshoot. It defaults to 2 * opt_minSamples.
- *
- * @type {{
- * opt_minSamples: number,
- * opt_damping: number,
- * opt_delayCycles: number
- * }}
- */
-o3djs.performance.PerformanceMonitor.Options = goog.typedef;
-
-/**
- * Call this once per frame with the elapsed time since the last call, and it
- * will attempt to adjust your rendering quality as needed.
- *
- * @param {number} seconds the elapsed time since the last frame was rendered,
- * in seconds.
- */
-o3djs.performance.PerformanceMonitor.prototype.onRender = function(seconds) {
- var test = true;
- if (this.sampleCount < this.damping) {
- if (this.sampleCount >= this.minSamples) {
- this.scaleInput_ = 1 / (this.sampleCount + 1);
- this.scaleMean_ = this.sampleCount * this.scaleInput_;
- } else {
- test = false;
- }
- this.sampleCount += 1;
- }
- this.meanFrameTime = this.meanFrameTime * this.scaleMean_ +
- seconds * this.scaleInput_;
- if (this.delayCyclesLeft_ > 0) {
- this.delayCyclesLeft_ -= 1;
- } else if (test) {
- if (this.meanFrameTime < this.targetFrameTimeMin_) {
- this.increaseQuality();
- this.delayCyclesLeft_ = this.delayCycles;
- } else if (this.meanFrameTime > this.targetFrameTimeMax_) {
- this.decreaseQuality();
- this.delayCyclesLeft_ = this.delayCycles;
- }
- }
-};
-
-
+/*
+ * 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 contains a utility that helps adjust rendering
+ * quality [or any other setting, really] based on rendering performance.
+ *
+ */
+
+o3djs.provide('o3djs.performance');
+
+/**
+ * A Module to help with adjusting performance.
+ * @namespace
+ */
+o3djs.performance = o3djs.performance || {};
+
+/**
+ * Creates a utility that monitors performance [in terms of FPS] and helps to
+ * adjust the rendered scene accordingly.
+ * @param {number} targetFPSMin the minimum acceptable frame rate; if we're
+ * under this, try to decrease quality to improve performance.
+ * @param {number} targetFPSMax if we're over this, try to increase quality.
+ * @param {!function(): void} increaseQuality a function to increase
+ * quality because we're rendering at high-enough FPS to afford it.
+ * @param {!function(): void} decreaseQuality a function to decrease
+ * quality to try to raise our rendering speed.
+ * @param {!o3djs.performance.PerformanceMonitor.Options} opt_options Options.
+ * @return {!o3djs.performance.PerformanceMonitor} The created
+ * PerformanceMonitor.
+ */
+o3djs.performance.createPerformanceMonitor = function(
+ targetFPSMin, targetFPSMax, increaseQuality, decreaseQuality, opt_options) {
+ return new o3djs.performance.PerformanceMonitor(targetFPSMin, targetFPSMax,
+ increaseQuality, decreaseQuality, opt_options);
+};
+
+/**
+ * A class that monitors performance [in terms of FPS] and helps to adjust the
+ * rendered scene accordingly.
+ * @constructor
+ * @param {number} targetFPSMin the minimum acceptable frame rate; if we're
+ * under this, try to decrease quality to improve performance.
+ * @param {number} targetFPSMax if we're over this, try to increase quality.
+ * @param {function(): void} increaseQuality a function to increase
+ * quality/lower FPS.
+ * @param {function(): void} decreaseQuality a function to decrease
+ * quality/raise FPS.
+ * @param {!o3djs.performance.PerformanceMonitor.Options} opt_options Options.
+ */
+o3djs.performance.PerformanceMonitor = function(
+ targetFPSMin, targetFPSMax, increaseQuality, decreaseQuality, opt_options) {
+ opt_options = opt_options || {};
+
+ /**
+ * A function to increase quality/lower FPS.
+ * @type {function(): void}
+ */
+ this.increaseQuality = increaseQuality;
+
+ /**
+ * A function to decrease quality/raise FPS.
+ * @type {function(): void}
+ */
+ this.decreaseQuality = decreaseQuality;
+
+ /**
+ * The mean time taken per frame so far, in seconds. This is only valid once
+ * we've collected at least minSamples samples.
+ * @type {number}
+ */
+ this.meanFrameTime = 0;
+
+ /**
+ * The number of samples we've collected so far, when that number is less than
+ * or equal to this.damping. After that point, we no longer update
+ * this.sampleCount, so it will clip at this.damping.
+ *
+ * @type {number}
+ */
+ this.sampleCount = 0;
+
+ /**
+ * The minimum number of samples to collect before trying to adjust quality.
+ *
+ * @type {number}
+ */
+ this.minSamples = opt_options.opt_minSamples || 60;
+
+ /**
+ * A number that controls the rate at which the effects of any given sample
+ * fade away. Higher is slower, but also means that each individual sample
+ * counts for less at its most-influential. Damping defaults to 120; anywhere
+ * between 60 and 600 are probably reasonable values, depending on your needs,
+ * but the number must be no less than minSamples.
+ *
+ * @type {number}
+ */
+ this.damping = opt_options.opt_damping || 120;
+
+ /**
+ * The minimum number of samples to take in between adjustments, to cut down
+ * on overshoot. It defaults to 2 * minSamples.
+ *
+ * @type {number}
+ */
+ this.delayCycles = opt_options.opt_delayCycles || 2 * this.minSamples;
+
+ this.targetFrameTimeMax_ = 1 / targetFPSMin;
+ this.targetFrameTimeMin_ = 1 / targetFPSMax;
+ this.scaleInput_ = 1 / this.minSamples;
+ this.scaleMean_ = 1;
+ this.delayCyclesLeft_ = 0;
+ if (this.damping < this.minSamples) {
+ throw Error('Damping must be at least minSamples.');
+ }
+};
+
+/**
+ * Options for the PerformanceMonitor.
+ *
+ * opt_minSamples is the minimum number of samples to take before making any
+ * performance adjustments.
+ * opt_damping is a number that controls the rate at which the effects of any
+ * given sample fade away. Higher is slower, but also means that each
+ * individual sample counts for less at its most-influential. Damping
+ * defaults to 120; anywhere between 60 and 600 are probably reasonable values,
+ * depending on your needs, but the number must be no less than minSamples.
+ * opt_delayCycles is the minimum number of samples to take in between
+ * adjustments, to cut down on overshoot. It defaults to 2 * opt_minSamples.
+ *
+ * @type {{
+ * opt_minSamples: number,
+ * opt_damping: number,
+ * opt_delayCycles: number
+ * }}
+ */
+o3djs.performance.PerformanceMonitor.Options = goog.typedef;
+
+/**
+ * Call this once per frame with the elapsed time since the last call, and it
+ * will attempt to adjust your rendering quality as needed.
+ *
+ * @param {number} seconds the elapsed time since the last frame was rendered,
+ * in seconds.
+ */
+o3djs.performance.PerformanceMonitor.prototype.onRender = function(seconds) {
+ var test = true;
+ if (this.sampleCount < this.damping) {
+ if (this.sampleCount >= this.minSamples) {
+ this.scaleInput_ = 1 / (this.sampleCount + 1);
+ this.scaleMean_ = this.sampleCount * this.scaleInput_;
+ } else {
+ test = false;
+ }
+ this.sampleCount += 1;
+ }
+ this.meanFrameTime = this.meanFrameTime * this.scaleMean_ +
+ seconds * this.scaleInput_;
+ if (this.delayCyclesLeft_ > 0) {
+ this.delayCyclesLeft_ -= 1;
+ } else if (test) {
+ if (this.meanFrameTime < this.targetFrameTimeMin_) {
+ this.increaseQuality();
+ this.delayCyclesLeft_ = this.delayCycles;
+ } else if (this.meanFrameTime > this.targetFrameTimeMax_) {
+ this.decreaseQuality();
+ this.delayCyclesLeft_ = this.delayCycles;
+ }
+ }
+};
+
+
diff --git a/o3d/samples/o3djs/texture.js b/o3d/samples/o3djs/texture.js
index 33678b2..5041dde 100644
--- a/o3d/samples/o3djs/texture.js
+++ b/o3d/samples/o3djs/texture.js
@@ -1,239 +1,239 @@
-/*
- * 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 contains functions helping to manipulate and manage
- * textures.
- */
-
-o3djs.provide('o3djs.texture');
-
-/**
- * A Module for bitmaps.
- * @namespace
- */
-o3djs.texture = o3djs.texture || {};
-
-/**
- * The maximum dimension of a texture.
- * @type {number}
- */
-o3djs.texture.MAX_TEXTURE_DIMENSION = 2048;
-
-/**
- * Computes the maximum number of levels of mips a given width and height could
- * use.
- * @param {number} width Width of texture.
- * @param {number} height Height of texture.
- * @return {number} The maximum number of levels for the given width and height.
- */
-o3djs.texture.computeNumLevels = function(width, height) {
- if (width == 0 || height == 0) {
- return 0;
- }
- var max = Math.max(width, height);
- var levels = 0;
- while (max > 0) {
- ++levels;
- max = max >> 1;
- }
- return levels;
-};
-
-/**
- * Creates a texture from a RawData object.
- * @param {!o3d.Pack} pack The pack to create the texture in.
- * @param {!o3d.RawData} rawData The raw data to create the texture from.
- * @param {boolean} opt_generateMips Whether or not to generate mips. Note, mips
- * can not be generated for DXT textures although they will be loaded if they
- * exist in the RawData.
- * @param {boolean} opt_flip Whether or not to flip the texture. Most DCC tools
- * Like Maya, Max, etc expect the textures to be flipped. Note that only
- * 2D (image) textures will be flipped. Cube textures will not be flipped.
- * Default = true.
- * @param {number} opt_maxWidth The maximum width of the texture. If the RawData
- * is larger than this size it will be scaled down to this size. Note that
- * DXT format textures can not be scaled. Default = 2048.
- * @param {number} opt_maxHeight The maximum width of the texture. If the
- * RawData is larger than this size it will be scaled down to this size. Note
- * that DXT format textures can not be scaled. Default = 2048.
- * @return {!o3d.Texture} The created texture.
- */
-o3djs.texture.createTextureFromRawData = function(
- pack,
- rawData,
- opt_generateMips,
- opt_flip,
- opt_maxWidth,
- opt_maxHeight) {
- // Make a bitmaps from the raw data.
- var bitmaps = pack.createBitmapsFromRawData(rawData);
- if (opt_flip || typeof opt_flip === 'undefined') {
- for (var ii = 0; ii < bitmaps.length; ++ii) {
- var bitmap = bitmaps[ii];
- if (bitmap.semantic == o3djs.base.o3d.Bitmap.IMAGE) {
- bitmaps[ii].flipVertically();
- }
- }
- }
-
- // Create a texture from the bitmaps.
- var texture = o3djs.texture.createTextureFromBitmaps(
- pack, bitmaps, opt_generateMips);
-
- // Delete the bitmaps.
- for (var ii = 0; ii < bitmaps.length; ++ii) {
- pack.removeObject(bitmaps[ii]);
- }
-
- return texture;
-};
-
-/**
- * Returns whether or not a given texture format can be scaled.
- * @param {!o3d.Texture.Format} format The format to check.
- * @return {boolean} True if you can scale and make mips for the given format.
- */
-o3djs.texture.canMakeMipsAndScale = function(format) {
- switch (format) {
- case o3djs.base.o3d.Texture.XRGB8:
- case o3djs.base.o3d.Texture.ARGB8:
- case o3djs.base.o3d.Texture.ABGR16F:
- case o3djs.base.o3d.Texture.R32F:
- case o3djs.base.o3d.Texture.ABGR32F:
- return true;
- case o3djs.base.o3d.Texture.DXT1:
- case o3djs.base.o3d.Texture.DXT3:
- case o3djs.base.o3d.Texture.DXT5:
- return false;
- }
- return false;
-};
-
-/**
- * Creates a Texture from an array of bitmaps.
- * @param {!o3d.Pack} pack The pack to create the texture in.
- * @param {!Array.<!o3d.Bitmap>} bitmaps An array of bitmaps to create the
- * texture from. For a 2D texture this would be 1 bitmap. For a cubemap this
- * would be 6 bitmaps.
- * @param {boolean} opt_generateMips Whether or not to generate mips. Note, mips
- * can not be generated for DXT textures although they will be loaded if they
- * exist in the RawData. Default = true.
- * @return {!o3d.Texture} The created texture.
- */
-o3djs.texture.createTextureFromBitmaps = function(
- pack,
- bitmaps,
- opt_generateMips) {
-
- if (bitmaps.length == 0) {
- throw 'no bitmaps';
- }
-
- var srcWidth = bitmaps[0].width;
- var srcHeight = bitmaps[0].height;
- var format = bitmaps[0].format;
- var mipMaps = bitmaps[0].numMipmaps;
- var maxMips = o3djs.texture.computeNumLevels(srcWidth, srcHeight);
- var targetMips = mipMaps;
- var dstWidth = srcWidth;
- var dstHeight = srcHeight;
- if ((typeof opt_generateMips === 'undefined' || opt_generateMips) &&
- o3djs.texture.canMakeMipsAndScale(format) &&
- mipMaps == 1 && maxMips > 1) {
- targetMips = maxMips;
- }
-
- // Check that all the bitmaps are the same size and make mips
- for (var ii = 0; ii < bitmaps.length; ++ii) {
- var bitmap = bitmaps[ii];
- if (bitmap.width != srcWidth ||
- bitmap.height != srcHeight ||
- bitmap.format != format ||
- bitmap.numMipmaps != mipMaps) {
- throw 'bitmaps must all be the same width, height, mips and format';
- }
- if (targetMips != mipMaps) {
- bitmap.generateMips(0, targetMips - 1);
- }
- }
-
- var levels = bitmap.numMipmaps > 1 ? bitmap.numMipmaps :
- o3djs.texture.computeNumLevels(dstWidth, dstHeight);
- var texture;
- if (bitmaps.length == 6 &&
- bitmaps[0].semantic != o3djs.base.o3d.Bitmap.SLICE) {
- if (srcWidth != srcHeight ||
- srcWidth != dstWidth ||
- srcHeight != dstHeight) {
- throw 'Cubemaps must be square';
- }
- texture = pack.createTextureCUBE(dstWidth, format, targetMips, false);
- for (var ii = 0; ii < 6; ++ii) {
- texture.setFromBitmap(
- /** @type {o3d.TextureCUBE.CubeFace} */ (ii),
- bitmaps[ii]);
- }
- } else if (bitmaps.length == 1) {
- texture = pack.createTexture2D(
- dstWidth, dstHeight, format, targetMips, false);
- texture.setFromBitmap(bitmaps[0]);
- }
-
- return /** @type{!o3d.Texture} */ (texture);
-};
-
-/**
- * Creates a TextureCUBE from 6 bitmaps. The bitmaps do not have to be the same
- * size thought they do have to be the same format.
- *
- * @param {!o3d.Pack} pack The pack to create the texture in.
- * @param {number} edgeLength The size of the cubemap.
- * @param {!Array.<!o3d.Bitmap>} bitmaps An array of 6 bitmaps in the order
- * FACE_POSITIVE_X, FACE_NEGATIVE_X, FACE_POSITIVE_Y, FACE_NEGATIVE_Y,
- * FACE_POSITIVE_Z, FACE_NEGATIVE_Z.
- * @return {!o3d.Texture} The created texture.
- */
-o3djs.texture.createCubeTextureFrom6Bitmaps = function(
- pack, edgeLength, bitmaps) {
- var numMips = o3djs.texture.computeNumLevels(edgeLength, edgeLength);
- var texture = pack.createTextureCUBE(
- edgeLength, bitmaps[0].format, numMips, false);
- for (var ii = 0; ii < 6; ++ii) {
- var bitmap = bitmaps[ii];
- texture.drawImage(bitmap, 0, 0, 0, bitmap.width, bitmap.height,
- ii, 0, 0, edgeLength, edgeLength);
- }
- texture.generateMips(0, numMips - 1);
- return texture;
-};
-
+/*
+ * 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 contains functions helping to manipulate and manage
+ * textures.
+ */
+
+o3djs.provide('o3djs.texture');
+
+/**
+ * A Module for bitmaps.
+ * @namespace
+ */
+o3djs.texture = o3djs.texture || {};
+
+/**
+ * The maximum dimension of a texture.
+ * @type {number}
+ */
+o3djs.texture.MAX_TEXTURE_DIMENSION = 2048;
+
+/**
+ * Computes the maximum number of levels of mips a given width and height could
+ * use.
+ * @param {number} width Width of texture.
+ * @param {number} height Height of texture.
+ * @return {number} The maximum number of levels for the given width and height.
+ */
+o3djs.texture.computeNumLevels = function(width, height) {
+ if (width == 0 || height == 0) {
+ return 0;
+ }
+ var max = Math.max(width, height);
+ var levels = 0;
+ while (max > 0) {
+ ++levels;
+ max = max >> 1;
+ }
+ return levels;
+};
+
+/**
+ * Creates a texture from a RawData object.
+ * @param {!o3d.Pack} pack The pack to create the texture in.
+ * @param {!o3d.RawData} rawData The raw data to create the texture from.
+ * @param {boolean} opt_generateMips Whether or not to generate mips. Note, mips
+ * can not be generated for DXT textures although they will be loaded if they
+ * exist in the RawData.
+ * @param {boolean} opt_flip Whether or not to flip the texture. Most DCC tools
+ * Like Maya, Max, etc expect the textures to be flipped. Note that only
+ * 2D (image) textures will be flipped. Cube textures will not be flipped.
+ * Default = true.
+ * @param {number} opt_maxWidth The maximum width of the texture. If the RawData
+ * is larger than this size it will be scaled down to this size. Note that
+ * DXT format textures can not be scaled. Default = 2048.
+ * @param {number} opt_maxHeight The maximum width of the texture. If the
+ * RawData is larger than this size it will be scaled down to this size. Note
+ * that DXT format textures can not be scaled. Default = 2048.
+ * @return {!o3d.Texture} The created texture.
+ */
+o3djs.texture.createTextureFromRawData = function(
+ pack,
+ rawData,
+ opt_generateMips,
+ opt_flip,
+ opt_maxWidth,
+ opt_maxHeight) {
+ // Make a bitmaps from the raw data.
+ var bitmaps = pack.createBitmapsFromRawData(rawData);
+ if (opt_flip || typeof opt_flip === 'undefined') {
+ for (var ii = 0; ii < bitmaps.length; ++ii) {
+ var bitmap = bitmaps[ii];
+ if (bitmap.semantic == o3djs.base.o3d.Bitmap.IMAGE) {
+ bitmaps[ii].flipVertically();
+ }
+ }
+ }
+
+ // Create a texture from the bitmaps.
+ var texture = o3djs.texture.createTextureFromBitmaps(
+ pack, bitmaps, opt_generateMips);
+
+ // Delete the bitmaps.
+ for (var ii = 0; ii < bitmaps.length; ++ii) {
+ pack.removeObject(bitmaps[ii]);
+ }
+
+ return texture;
+};
+
+/**
+ * Returns whether or not a given texture format can be scaled.
+ * @param {!o3d.Texture.Format} format The format to check.
+ * @return {boolean} True if you can scale and make mips for the given format.
+ */
+o3djs.texture.canMakeMipsAndScale = function(format) {
+ switch (format) {
+ case o3djs.base.o3d.Texture.XRGB8:
+ case o3djs.base.o3d.Texture.ARGB8:
+ case o3djs.base.o3d.Texture.ABGR16F:
+ case o3djs.base.o3d.Texture.R32F:
+ case o3djs.base.o3d.Texture.ABGR32F:
+ return true;
+ case o3djs.base.o3d.Texture.DXT1:
+ case o3djs.base.o3d.Texture.DXT3:
+ case o3djs.base.o3d.Texture.DXT5:
+ return false;
+ }
+ return false;
+};
+
+/**
+ * Creates a Texture from an array of bitmaps.
+ * @param {!o3d.Pack} pack The pack to create the texture in.
+ * @param {!Array.<!o3d.Bitmap>} bitmaps An array of bitmaps to create the
+ * texture from. For a 2D texture this would be 1 bitmap. For a cubemap this
+ * would be 6 bitmaps.
+ * @param {boolean} opt_generateMips Whether or not to generate mips. Note, mips
+ * can not be generated for DXT textures although they will be loaded if they
+ * exist in the RawData. Default = true.
+ * @return {!o3d.Texture} The created texture.
+ */
+o3djs.texture.createTextureFromBitmaps = function(
+ pack,
+ bitmaps,
+ opt_generateMips) {
+
+ if (bitmaps.length == 0) {
+ throw 'no bitmaps';
+ }
+
+ var srcWidth = bitmaps[0].width;
+ var srcHeight = bitmaps[0].height;
+ var format = bitmaps[0].format;
+ var mipMaps = bitmaps[0].numMipmaps;
+ var maxMips = o3djs.texture.computeNumLevels(srcWidth, srcHeight);
+ var targetMips = mipMaps;
+ var dstWidth = srcWidth;
+ var dstHeight = srcHeight;
+ if ((typeof opt_generateMips === 'undefined' || opt_generateMips) &&
+ o3djs.texture.canMakeMipsAndScale(format) &&
+ mipMaps == 1 && maxMips > 1) {
+ targetMips = maxMips;
+ }
+
+ // Check that all the bitmaps are the same size and make mips
+ for (var ii = 0; ii < bitmaps.length; ++ii) {
+ var bitmap = bitmaps[ii];
+ if (bitmap.width != srcWidth ||
+ bitmap.height != srcHeight ||
+ bitmap.format != format ||
+ bitmap.numMipmaps != mipMaps) {
+ throw 'bitmaps must all be the same width, height, mips and format';
+ }
+ if (targetMips != mipMaps) {
+ bitmap.generateMips(0, targetMips - 1);
+ }
+ }
+
+ var levels = bitmap.numMipmaps > 1 ? bitmap.numMipmaps :
+ o3djs.texture.computeNumLevels(dstWidth, dstHeight);
+ var texture;
+ if (bitmaps.length == 6 &&
+ bitmaps[0].semantic != o3djs.base.o3d.Bitmap.SLICE) {
+ if (srcWidth != srcHeight ||
+ srcWidth != dstWidth ||
+ srcHeight != dstHeight) {
+ throw 'Cubemaps must be square';
+ }
+ texture = pack.createTextureCUBE(dstWidth, format, targetMips, false);
+ for (var ii = 0; ii < 6; ++ii) {
+ texture.setFromBitmap(
+ /** @type {o3d.TextureCUBE.CubeFace} */ (ii),
+ bitmaps[ii]);
+ }
+ } else if (bitmaps.length == 1) {
+ texture = pack.createTexture2D(
+ dstWidth, dstHeight, format, targetMips, false);
+ texture.setFromBitmap(bitmaps[0]);
+ }
+
+ return /** @type{!o3d.Texture} */ (texture);
+};
+
+/**
+ * Creates a TextureCUBE from 6 bitmaps. The bitmaps do not have to be the same
+ * size thought they do have to be the same format.
+ *
+ * @param {!o3d.Pack} pack The pack to create the texture in.
+ * @param {number} edgeLength The size of the cubemap.
+ * @param {!Array.<!o3d.Bitmap>} bitmaps An array of 6 bitmaps in the order
+ * FACE_POSITIVE_X, FACE_NEGATIVE_X, FACE_POSITIVE_Y, FACE_NEGATIVE_Y,
+ * FACE_POSITIVE_Z, FACE_NEGATIVE_Z.
+ * @return {!o3d.Texture} The created texture.
+ */
+o3djs.texture.createCubeTextureFrom6Bitmaps = function(
+ pack, edgeLength, bitmaps) {
+ var numMips = o3djs.texture.computeNumLevels(edgeLength, edgeLength);
+ var texture = pack.createTextureCUBE(
+ edgeLength, bitmaps[0].format, numMips, false);
+ for (var ii = 0; ii < 6; ++ii) {
+ var bitmap = bitmaps[ii];
+ texture.drawImage(bitmap, 0, 0, 0, bitmap.width, bitmap.height,
+ ii, 0, 0, edgeLength, edgeLength);
+ }
+ texture.generateMips(0, numMips - 1);
+ return texture;
+};
+
diff --git a/o3d/samples/siteswap/animation.js b/o3d/samples/siteswap/animation.js
index eb20cc8..c9aa80a 100644
--- a/o3d/samples/siteswap/animation.js
+++ b/o3d/samples/siteswap/animation.js
@@ -1,198 +1,198 @@
-// @@REWRITE(insert js-copyright)
-// @@REWRITE(delete-start)
-// Copyright 2009 Google Inc. All Rights Reserved
-// @@REWRITE(delete-end)
-
-/**
- * This file contains the animation-management code for the siteswap animator.
- * This is encapsulated in the EventQueue and QueueEvent classes, the event
- * handler, and startAnimation, the main external interface to the animation.
- */
-
-/**
- * A record, held in the EventQueue, that describes the curve that should be
- * given to a shape at a time.
- * @constructor
- * @param {!number} time base time at which the event occurs/the curve starts.
- * @param {!o3d.Shape} shape the shape to be updated.
- * @param {Curve} curve the path for the shape to follow.
- */
-function QueueEvent(time, shape, curve) {
- this.time = time;
- this.shape = shape;
- this.curve = curve;
- return this;
-}
-
-/**
- * A circular queue of events that will happen during the course of an animation
- * that's duration beats long. The queue is ordered by the time each curve
- * starts. Note that a curve may start after it ends, since time loops
- * endlessly. The nextEvent field is the index of the next event to occur; it
- * keeps track of how far we've gotten in the queue.
- * @constructor
- * @param {!number} duration the length of the animation in beats.
- */
-function EventQueue(duration) {
- this.events = [];
- this.nextEvent = 0;
- this.duration = duration;
- this.timeCorrection = 0; // Corrects from queue entry time to real time.
- return this;
-}
-
-/**
- * Add an event to the queue, inserting into order by its time field.
- * A heap-based priority queue would be faster, but likely overkill, as this
- * won't ever contain that many items, and isn't likely to be speed-critical.
- * @param {!QueueEvent} event the event to add.
- */
-EventQueue.prototype.addEvent = function(event) {
- var i = 0;
- while (i < this.events.length && event.time > this.events[i].time) {
- ++i;
- }
- this.events.splice(i, 0, event);
-};
-
-/**
- * Pull the next event off the queue.
- * @return {!QueueEvent} the event.
- */
-EventQueue.prototype.shift = function() {
- var e = this.events[this.nextEvent];
- if (++this.nextEvent >= this.events.length) {
- assert(this.nextEvent > 0);
- this.nextEvent = 0;
- this.timeCorrection += this.duration;
- }
- return e;
-};
-
-/**
- * Process all current events, updating all animated objects with their new
- * curves, until we find that the next event in the queue is in the future.
- * @param {!number} time the current time in beats. This number is an absolute,
- * not locked to the range of the duration of the pattern, so getNextTime()
- * returns a doctored number to add in the offset from in-pattern time to real
- * time.
- * @return {!number} the time of the next future event.
- */
-EventQueue.prototype.processEvents = function(time) {
- while (this.getNextTime() <= time) {
- var e = this.shift();
- setParamCurveInfo(e.curve, e.shape, time);
- }
- return this.getNextTime(); // In case you want to set a callback.
-};
-
-/**
- * Look up the initial curve for a shape [the curve that it'll be starting or in
- * the middle of at time 0].
- * @param {!CurveSet} curveSet the complete set of curves for a Shape.
- * @return {!Object} the curve and the time at which it would have started.
- */
-function getInitialCurveInfo(curveSet) {
- var curve = curveSet.getCurveForUnsafeTime(0);
- var curveBaseTime;
- if (!curve.startTime) {
- curveBaseTime = 0;
- } else {
- // If the curve isn't starting now, it must have wrapped around.
- assert(curve.startTime + curve.duration > curveSet.duration);
- // So subtract off one wrap so that its startTime is in the right space of
- // numbers. We assume here that no curve duration is longer than the
- // pattern, which must be guaranteed by the code that generates patterns.
- assert(curve.duration <= curveSet.duration);
- curveBaseTime = curve.startTime - curveSet.duration;
- }
- return { curve: curve, curveBaseTime: curveBaseTime };
-}
-
-/**
- * Set up the event queue with a complete pattern starting at time 0.
- * @param {!Array.CurveSet} curveSets the curve sets for all shapes.
- * @param {!Array.o3d.Shape} shapes all the shapes to animate.
- */
-EventQueue.prototype.setUp = function(curveSets, shapes) {
- assert(curveSets.length == shapes.length);
- for (var i = 0; i < shapes.length; ++i) {
- var curveSet = curveSets[i];
- assert(this.duration % curveSet.duration == 0);
- var shape = shapes[i];
- var record = getInitialCurveInfo(curveSet);
- var curveBaseTime = record.curveBaseTime;
- var curve = record.curve;
- setParamCurveInfo(curve, shape, curveBaseTime);
- do {
- curveBaseTime += curve.duration;
- curve = curveSet.getCurveForTime(curveBaseTime);
- var e = new QueueEvent(curveBaseTime % this.duration, shape, curve);
- this.addEvent(e);
- } while (curveBaseTime + curve.duration <= this.duration);
- }
-};
-
-/**
- * Return the time of the next future event.
- * @return {!number} the time.
- */
-EventQueue.prototype.getNextTime = function() {
- return this.events[this.nextEvent].time + this.timeCorrection;
-};
-
-/**
- * This is the event handler that runs the whole animation. When triggered by
- * the counter, it updates the curves on all objects whose curves have expired.
- *
- * The current time will be some time around when we wanted to be called. It
- * might be exact, but it might be a bit off due to floating point error, or a
- * lot off due to the system getting bogged down somewhere for a second or
- * two. e.g. if we wanted to get a call at time 7, it's likely to be
- * something like 7.04, but might even be 11. We then use 7, not 7.04, as the
- * start time for each of the curves set, so as to remove clock drift. Since
- * the time we wanted to be called is stored in the next item in the queue, we
- * can just pull that out and use it. However, if we then find that we're
- * setting our callback in the past, we repeat the process until our callback
- * is set safely in the future. We may get some visual artifacts, but at
- * least we won't drop any events [leading to stuff drifting endlessly off
- * into the distance].
- */
-function handler() {
- var eventTime = g.eventQueue.getNextTime();
- var trueCurrentTime;
- do {
- g.counter.removeCallback(eventTime);
- eventTime = g.eventQueue.processEvents(eventTime);
- g.counter.addCallback(eventTime, handler);
- trueCurrentTime = g.counter.count;
- } while (eventTime < trueCurrentTime);
-}
-
-/**
- * Given a precomputed juggling pattern, this sets up the O3D objects,
- * EventQueue, and callback necessary to start an animation, then calls
- * updateAnimating to kick it off if enabled.
- *
- * @param {!number} numBalls the number of balls in the animation.
- * @param {!number} numHands the number of hands in the animation.
- * @param {!number} duration the length of the full animation cycle in beats.
- * @param {!Array.CurveSet} ballCurveSets one CurveSet per ball.
- * @param {!Array.CurveSet} handCurveSets one CurveSet per hand.
- */
-function startAnimation(numBalls, numHands, duration, ballCurveSets,
- handCurveSets) {
- g.counter.running = false;
- g.counter.reset();
-
- setNumBalls(numBalls);
- setNumHands(numHands);
-
- g.eventQueue = new EventQueue(duration);
- g.eventQueue.setUp(handCurveSets, g.handShapes);
- g.eventQueue.setUp(ballCurveSets, g.ballShapes);
- g.counter.addCallback(g.eventQueue.getNextTime(), handler);
-
- updateAnimating();
-}
-
+// @@REWRITE(insert js-copyright)
+// @@REWRITE(delete-start)
+// Copyright 2009 Google Inc. All Rights Reserved
+// @@REWRITE(delete-end)
+
+/**
+ * This file contains the animation-management code for the siteswap animator.
+ * This is encapsulated in the EventQueue and QueueEvent classes, the event
+ * handler, and startAnimation, the main external interface to the animation.
+ */
+
+/**
+ * A record, held in the EventQueue, that describes the curve that should be
+ * given to a shape at a time.
+ * @constructor
+ * @param {!number} time base time at which the event occurs/the curve starts.
+ * @param {!o3d.Shape} shape the shape to be updated.
+ * @param {Curve} curve the path for the shape to follow.
+ */
+function QueueEvent(time, shape, curve) {
+ this.time = time;
+ this.shape = shape;
+ this.curve = curve;
+ return this;
+}
+
+/**
+ * A circular queue of events that will happen during the course of an animation
+ * that's duration beats long. The queue is ordered by the time each curve
+ * starts. Note that a curve may start after it ends, since time loops
+ * endlessly. The nextEvent field is the index of the next event to occur; it
+ * keeps track of how far we've gotten in the queue.
+ * @constructor
+ * @param {!number} duration the length of the animation in beats.
+ */
+function EventQueue(duration) {
+ this.events = [];
+ this.nextEvent = 0;
+ this.duration = duration;
+ this.timeCorrection = 0; // Corrects from queue entry time to real time.
+ return this;
+}
+
+/**
+ * Add an event to the queue, inserting into order by its time field.
+ * A heap-based priority queue would be faster, but likely overkill, as this
+ * won't ever contain that many items, and isn't likely to be speed-critical.
+ * @param {!QueueEvent} event the event to add.
+ */
+EventQueue.prototype.addEvent = function(event) {
+ var i = 0;
+ while (i < this.events.length && event.time > this.events[i].time) {
+ ++i;
+ }
+ this.events.splice(i, 0, event);
+};
+
+/**
+ * Pull the next event off the queue.
+ * @return {!QueueEvent} the event.
+ */
+EventQueue.prototype.shift = function() {
+ var e = this.events[this.nextEvent];
+ if (++this.nextEvent >= this.events.length) {
+ assert(this.nextEvent > 0);
+ this.nextEvent = 0;
+ this.timeCorrection += this.duration;
+ }
+ return e;
+};
+
+/**
+ * Process all current events, updating all animated objects with their new
+ * curves, until we find that the next event in the queue is in the future.
+ * @param {!number} time the current time in beats. This number is an absolute,
+ * not locked to the range of the duration of the pattern, so getNextTime()
+ * returns a doctored number to add in the offset from in-pattern time to real
+ * time.
+ * @return {!number} the time of the next future event.
+ */
+EventQueue.prototype.processEvents = function(time) {
+ while (this.getNextTime() <= time) {
+ var e = this.shift();
+ setParamCurveInfo(e.curve, e.shape, time);
+ }
+ return this.getNextTime(); // In case you want to set a callback.
+};
+
+/**
+ * Look up the initial curve for a shape [the curve that it'll be starting or in
+ * the middle of at time 0].
+ * @param {!CurveSet} curveSet the complete set of curves for a Shape.
+ * @return {!Object} the curve and the time at which it would have started.
+ */
+function getInitialCurveInfo(curveSet) {
+ var curve = curveSet.getCurveForUnsafeTime(0);
+ var curveBaseTime;
+ if (!curve.startTime) {
+ curveBaseTime = 0;
+ } else {
+ // If the curve isn't starting now, it must have wrapped around.
+ assert(curve.startTime + curve.duration > curveSet.duration);
+ // So subtract off one wrap so that its startTime is in the right space of
+ // numbers. We assume here that no curve duration is longer than the
+ // pattern, which must be guaranteed by the code that generates patterns.
+ assert(curve.duration <= curveSet.duration);
+ curveBaseTime = curve.startTime - curveSet.duration;
+ }
+ return { curve: curve, curveBaseTime: curveBaseTime };
+}
+
+/**
+ * Set up the event queue with a complete pattern starting at time 0.
+ * @param {!Array.CurveSet} curveSets the curve sets for all shapes.
+ * @param {!Array.o3d.Shape} shapes all the shapes to animate.
+ */
+EventQueue.prototype.setUp = function(curveSets, shapes) {
+ assert(curveSets.length == shapes.length);
+ for (var i = 0; i < shapes.length; ++i) {
+ var curveSet = curveSets[i];
+ assert(this.duration % curveSet.duration == 0);
+ var shape = shapes[i];
+ var record = getInitialCurveInfo(curveSet);
+ var curveBaseTime = record.curveBaseTime;
+ var curve = record.curve;
+ setParamCurveInfo(curve, shape, curveBaseTime);
+ do {
+ curveBaseTime += curve.duration;
+ curve = curveSet.getCurveForTime(curveBaseTime);
+ var e = new QueueEvent(curveBaseTime % this.duration, shape, curve);
+ this.addEvent(e);
+ } while (curveBaseTime + curve.duration <= this.duration);
+ }
+};
+
+/**
+ * Return the time of the next future event.
+ * @return {!number} the time.
+ */
+EventQueue.prototype.getNextTime = function() {
+ return this.events[this.nextEvent].time + this.timeCorrection;
+};
+
+/**
+ * This is the event handler that runs the whole animation. When triggered by
+ * the counter, it updates the curves on all objects whose curves have expired.
+ *
+ * The current time will be some time around when we wanted to be called. It
+ * might be exact, but it might be a bit off due to floating point error, or a
+ * lot off due to the system getting bogged down somewhere for a second or
+ * two. e.g. if we wanted to get a call at time 7, it's likely to be
+ * something like 7.04, but might even be 11. We then use 7, not 7.04, as the
+ * start time for each of the curves set, so as to remove clock drift. Since
+ * the time we wanted to be called is stored in the next item in the queue, we
+ * can just pull that out and use it. However, if we then find that we're
+ * setting our callback in the past, we repeat the process until our callback
+ * is set safely in the future. We may get some visual artifacts, but at
+ * least we won't drop any events [leading to stuff drifting endlessly off
+ * into the distance].
+ */
+function handler() {
+ var eventTime = g.eventQueue.getNextTime();
+ var trueCurrentTime;
+ do {
+ g.counter.removeCallback(eventTime);
+ eventTime = g.eventQueue.processEvents(eventTime);
+ g.counter.addCallback(eventTime, handler);
+ trueCurrentTime = g.counter.count;
+ } while (eventTime < trueCurrentTime);
+}
+
+/**
+ * Given a precomputed juggling pattern, this sets up the O3D objects,
+ * EventQueue, and callback necessary to start an animation, then calls
+ * updateAnimating to kick it off if enabled.
+ *
+ * @param {!number} numBalls the number of balls in the animation.
+ * @param {!number} numHands the number of hands in the animation.
+ * @param {!number} duration the length of the full animation cycle in beats.
+ * @param {!Array.CurveSet} ballCurveSets one CurveSet per ball.
+ * @param {!Array.CurveSet} handCurveSets one CurveSet per hand.
+ */
+function startAnimation(numBalls, numHands, duration, ballCurveSets,
+ handCurveSets) {
+ g.counter.running = false;
+ g.counter.reset();
+
+ setNumBalls(numBalls);
+ setNumHands(numHands);
+
+ g.eventQueue = new EventQueue(duration);
+ g.eventQueue.setUp(handCurveSets, g.handShapes);
+ g.eventQueue.setUp(ballCurveSets, g.ballShapes);
+ g.counter.addCallback(g.eventQueue.getNextTime(), handler);
+
+ updateAnimating();
+}
+
diff --git a/o3d/samples/siteswap/math.js b/o3d/samples/siteswap/math.js
index c5e2f43..e584744 100644
--- a/o3d/samples/siteswap/math.js
+++ b/o3d/samples/siteswap/math.js
@@ -1,1492 +1,1492 @@
-// @@REWRITE(insert js-copyright)
-// @@REWRITE(delete-start)
-// Copyright 2009 Google Inc. All Rights Reserved
-// @@REWRITE(delete-end)
-
-/**
- * @fileoverview This file contains all the math for the siteswap animator. It
- * handles all of the site-swap-related stuff [converting a sequence of integers
- * into a more-useful representation of a pattern, pattern validation, etc.] as
- * well as all the physics used for the simulation.
- */
-
-/**
- * This is a container class that holds the coefficients of an equation
- * describing the motion of an object.
- * The basic equation is:
- * f(x) := a t^2 + b t + c + d sin (f t) + e cos (f t).
- * However, sometimes we LERP between that function and this one:
- * g(x) := lA t^2 + lB t + lC
- * lerpRate [so far] is always either 1 [LERP from f to g over 1 beat] or -1,
- * [LERP from g to f over one beat].
- *
- * Just plug in t to evaluate the equation. There's no JavaScript function to
- * do this because it's always done on the GPU.
- *
- * @constructor
- */
-EquationCoefficients = function(a, b, c, d, e, f, lA, lB, lC, lerpRate) {
- assert(!isNaN(a) && !isNaN(b) && !isNaN(c));
- d = d || 0;
- e = e || 0;
- f = f || 0;
- assert(!isNaN(d) && !isNaN(e) && !isNaN(f));
- lA = lA || 0;
- lB = lB || 0;
- lC = lC || 0;
- assert(!isNaN(lA) && !isNaN(lB) && !isNaN(lC));
- lerpRate = lerpRate || 0;
- this.a = a;
- this.b = b;
- this.c = c;
- this.d = d;
- this.e = e;
- this.f = f;
- this.lA = lA;
- this.lB = lB;
- this.lC = lC;
- this.lerpRate = lerpRate;
-}
-
-/**
- * Create a new equation that's equivalent to this equation's coefficients a-f
- * with a LERP to the polynomial portion of the supplied equation.
- * @param {!EquationCoefficients} eqn the source of coefficients.
- * @param {!number} lerpRate the rate and direction of the LERP; positive for
- * "from this equation to the new one" and vice-versa.
- * @return {!EquationCoefficients} a new set of coefficients.
- */
-EquationCoefficients.prototype.lerpIn = function(eqn, lerpRate) {
- assert(!this.lerpRate);
- return new EquationCoefficients(this.a, this.b, this.c, this.d, this.e,
- this.f, eqn.a, eqn.b, eqn.c, lerpRate);
-};
-
-/**
- * Convert the EquationCoefficients to a string for debugging.
- * @return {String} debugging output.
- */
-EquationCoefficients.prototype.toString = function() {
- return 'F(t) := ' + this.a.toFixed(2) + ' t^2 + ' + this.b.toFixed(2) +
- ' t + ' + this.c.toFixed(2) + ' + ' +
- this.d.toFixed(2) + ' sin(' + this.f.toFixed(2) + ' t) + ' +
- this.e.toFixed(2) + ' cos(' + this.f.toFixed(2) + ' t) + LERP(' +
- this.lerpRate.toFixed(2) + ') of ' +
- this.lA.toFixed(2) + ' t^2 + ' + this.lB.toFixed(2) +
- ' t + ' + this.lC.toFixed(2);
-};
-
-/**
- * A set of equations which describe the motion of an object over time.
- * The three equations each supply one dimension of the motion, and the curve is
- * valid from startTime to startTime + duration.
- * @param {!number} startTime the initial time at which the curve is valid.
- * @param {!number} duration how long [in beats] the curve is valid.
- * @param {!EquationCoefficients} xEqn the equation for motion in x.
- * @param {!EquationCoefficients} yEqn the equation for motion in y.
- * @param {!EquationCoefficients} zEqn the equation for motion in z.
- * @constructor
- */
-Curve = function(startTime, duration, xEqn, yEqn, zEqn) {
- this.startTime = startTime;
- this.duration = duration;
- this.xEqn = xEqn;
- this.yEqn = yEqn;
- this.zEqn = zEqn;
-}
-
-/**
- * Convert the Curve to a string for debugging.
- * @return {String} debugging output.
- */
-Curve.prototype.toString = function() {
- var s = 'startTime: ' + this.startTime + '\n';
- s += 'duration: ' + this.duration + '\n';
- s += this.xEqn + '\n';
- s += this.yEqn + '\n';
- s += this.zEqn + '\n';
- return s;
-};
-
-/**
- * Modify this curve's coefficients to include a LERP to the polynomial
- * portion of the supplied curve.
- * @param {!Curve} curve the source of coefficients.
- * @param {!number} lerpRate the rate and direction of the LERP; positive for
- * "from this equation to the new one" and vice-versa.
- * @return {!Curve} a new curve.
- */
-Curve.prototype.lerpIn = function(curve, lerpRate) {
- assert(this.startTime == curve.startTime);
- assert(this.duration == curve.duration);
- var xEqn = this.xEqn.lerpIn(curve.xEqn, lerpRate);
- var yEqn = this.yEqn.lerpIn(curve.yEqn, lerpRate);
- var zEqn = this.zEqn.lerpIn(curve.zEqn, lerpRate);
- return new Curve(this.startTime, this.duration, xEqn, yEqn, zEqn);
-};
-
-/**
- * Produce a set of polynomial coefficients that describe linear motion between
- * two points in 1 dimension.
- * @param {!number} startPos the starting position.
- * @param {!number} endPos the ending position.
- * @param {!number} duration how long the motion takes.
- * @return {!EquationCoefficients} the equation for the motion.
- */
-Curve.computeLinearCoefficients = function(startPos, endPos, duration) {
- return new EquationCoefficients(
- 0, (endPos - startPos) / duration, startPos);
-}
-
-var GRAVITY = 1; // Higher means higher throws for the same duration.
-/**
- * Produce a set of polynomial coefficients that describe parabolic motion
- * between two points in 1 dimension.
- * @param {!number} startPos the starting position.
- * @param {!number} endPos the ending position.
- * @param {!number} duration how long the motion takes.
- * @return {!EquationCoefficients} the equation for the motion.
- */
-Curve.computeParabolicCoefficients = function(startPos, endPos, duration) {
- var dY = endPos - startPos;
- return new EquationCoefficients(-GRAVITY / 2,
- dY / duration + GRAVITY * duration / 2,
- startPos);
-}
-
-/**
- * Compute the curve taken by a ball given its throw and catch positions, the
- * time it was thrown, and how long it stayed in the air.
- *
- * We use duration rather than throwTime and catchTime because, what
- * with the modular arithmetic used in our records, catchTime might be before
- * throwTime, and in some representations the pattern could wrap around a few
- * times while the ball's in the air. When the parabola computed here is used,
- * time must be supplied as an offset from the time of the throw, and must of
- * course not wrap at all. That is, these coefficients work for f(0) ==
- * throwPos, f(duration) == catchPos.
- *
- * We treat the y axis as vertical and thus affected by gravity.
- *
- * @param {!EquationCoefficients} throwPos
- * @param {!EquationCoefficients} catchPos
- * @param {!number} startTime
- * @param {!number} duration
- * @return {!Curve}
- */
-Curve.computeThrowCurve = function(throwPos, catchPos, startTime, duration) {
- var xEqn = Curve.computeLinearCoefficients(throwPos.x, catchPos.x, duration);
- var yEqn = Curve.computeParabolicCoefficients(throwPos.y, catchPos.y,
- duration);
- var zEqn = Curve.computeLinearCoefficients(throwPos.z, catchPos.z, duration);
- return new Curve(startTime, duration, xEqn, yEqn, zEqn);
-}
-
-/**
- * Compute a straight line Curve given start and end positions, the start time,
- * and the duration of the motion.
- *
- * @param {!EquationCoefficients} startPos
- * @param {!EquationCoefficients} endPos
- * @param {!number} startTime
- * @param {!number} duration
- * @return {!Curve}
- */
-Curve.computeStraightLineCurve =
- function(startPos, endPos, startTime, duration) {
- var xEqn = Curve.computeLinearCoefficients(startPos.x, endPos.x, duration);
- var yEqn = Curve.computeLinearCoefficients(startPos.y, endPos.y, duration);
- var zEqn = Curve.computeLinearCoefficients(startPos.z, endPos.z, duration);
- return new Curve(startTime, duration, xEqn, yEqn, zEqn);
-}
-
-/**
- * Threshold horizontal distance below which computeCircularCurve won't bother
- * trying to approximate a circular curve. See the comment above
- * computeCircularCurve for more info.
- * @type {number}
- */
-Curve.EPSILON = .0001;
-
-/**
- * Compute a circular curve, used as an approximation for the motion of a hand
- * between a catch and its following throw.
- *
- * Assumes a lot of stuff about this looking like a "normal" throw: the catch is
- * moving roughly the opposite direction as the throw, the throw and catch
- * aren't at the same place, and such. Otherwise this looks very odd at best.
- * This is used for the height of the curve.
- * This produces coefficients for d sin(f t) + e cos(f t) for each of x, y, z.
- * It produces a vertical-ish circular curve from the start to the end, going
- * down, then up. So if dV [the distance from the start to finish in the x-z
- * plane, ignoring y] is less than Curve.EPSILON, it doesn't know which way down
- * is, and it bails by returning a straight line instead.
- */
-Curve.computeCircularCurve = function(startPos, endPos, startTime, duration) {
- var dX = endPos.x - startPos.x;
- var dY = endPos.y - startPos.y;
- var dZ = endPos.z - startPos.z;
- var dV = Math.sqrt(dX * dX + dZ * dZ);
- if (dV < Curve.EPSILON) {
- return Curve.computeStraightLineCurve(startPos, endPos, startTime,
- duration);
- }
- var negHalfdV = -0.5 * dV;
- var negHalfdY = -0.5 * dY;
- var f = Math.PI / duration;
- var yEqn = new EquationCoefficients(
- 0, 0, startPos.y + dY / 2,
- negHalfdV, negHalfdY, f);
- var ratio = dX / dV;
- var xEqn = new EquationCoefficients(
- 0, 0, startPos.x + dX / 2,
- negHalfdY * ratio, negHalfdV * ratio, f);
- ratio = dZ / dV;
- var zEqn = new EquationCoefficients(
- 0, 0, startPos.z + dZ / 2,
- negHalfdY * ratio, negHalfdV * ratio, f);
- return new Curve(startTime, duration, xEqn, yEqn, zEqn);
-}
-
-/**
- * This is the abstract base class for an object that describes a throw, catch,
- * or empty hand [placeholder] in a site-swap pattern.
- * @constructor
- */
-Descriptor = function() {
-}
-
-/**
- * Create an otherwise-identical copy of this descriptor at a given time offset.
- * Note that offset may put time past patternLength; the caller will have to fix
- * this up manually.
- * @param {number} offset how many beats to offset the new descriptor.
- * Derived classes must override this function.
- */
-Descriptor.prototype.clone = function(offset) {
- throw new Error('Unimplemented.');
-};
-
-/**
- * Generate the Curve implied by this descriptor and the supplied hand
- * positions.
- * @param {!Array.HandPositionRecord} handPositions where the hands will be.
- * Derived classes must override this function.
- */
-Descriptor.prototype.generateCurve = function(handPositions) {
- throw new Error('Unimplemented.');
-};
-
-/**
- * Adjust the start time of this Descriptor to be in [0, pathLength).
- * @param {!number} pathLength the duration of a path, in beats.
- * @return {!Descriptor} this.
- */
-Descriptor.prototype.fixUpModPathLength = function(pathLength) {
- this.time = this.time % pathLength;
- return this;
-};
-
-/**
- * This describes a throw in a site-swap pattern.
- * @param {!number} throwNum the site-swap number of the throw.
- * @param {!number} throwTime the time this throw occurs.
- * @param {!number} sourceHand the index of the throwing hand.
- * @param {!number} destHand the index of the catching hand.
- * @constructor
- */
-ThrowDescriptor = function(throwNum, throwTime, sourceHand, destHand) {
- this.throwNum = throwNum;
- this.sourceHand = sourceHand;
- this.destHand = destHand;
- this.time = throwTime;
-}
-
-/**
- * This is a subclass of Descriptor.
- */
-ThrowDescriptor.prototype = new Descriptor();
-
-/**
- * Set up the constructor, just to be neat.
- */
-ThrowDescriptor.prototype.constructor = ThrowDescriptor;
-
-/**
- * We label each Descriptor subclass with a type for debugging.
- */
-ThrowDescriptor.prototype.type = 'THROW';
-
-/**
- * Create an otherwise-identical copy of this descriptor at a given time offset.
- * Note that offset may put time past patternLength; the caller will have to fix
- * this up manually.
- * @param {number} offset how many beats to offset the new descriptor.
- * @return {!Descriptor} the new copy.
- */
-ThrowDescriptor.prototype.clone = function(offset) {
- offset = offset || 0; // Turn null into 0.
- return new ThrowDescriptor(this.throwNum, this.time + offset,
- this.sourceHand, this.destHand);
-};
-
-/**
- * Convert the ThrowDescriptor to a string for debugging.
- * @return {String} debugging output.
- */
-ThrowDescriptor.prototype.toString = function() {
- return '(' + this.throwNum + ' from hand ' + this.sourceHand + ' to hand ' +
- this.destHand + ')';
-};
-
-/**
- * Generate the Curve implied by this descriptor and the supplied hand
- * positions.
- * @param {!Array.HandPositionRecord} handPositions where the hands will be.
- * @return {!Curve} the curve.
- */
-ThrowDescriptor.prototype.generateCurve = function(handPositions) {
- var startPos = handPositions[this.sourceHand].throwPositions[this.destHand];
- var endPos = handPositions[this.destHand].catchPosition;
- return Curve.computeThrowCurve(startPos, endPos, this.time,
- this.throwNum - 1); };
-
-/**
- * This describes a catch in a site-swap pattern.
- * @param {!number} hand the index of the catching hand.
- * @param {!number} sourceThrowNum the site-swap number of the preceeding throw.
- * @param {!number} destThrowNum the site-swap number of the following throw.
- * @param {!number} sourceHand the index of the hand throwing the source throw.
- * @param {!number} destHand the index of the hand catching the following throw.
- * @param {!number} catchTime the time at which the catch occurs.
- * @constructor
- */
-CarryDescriptor = function(hand, sourceThrowNum, destThrowNum, sourceHand,
- destHand, catchTime) {
- this.hand = hand;
- this.sourceThrowNum = sourceThrowNum;
- this.destThrowNum = destThrowNum;
- this.sourceHand = sourceHand;
- this.destHand = destHand;
- this.time = catchTime;
-}
-
-/**
- * This is a subclass of Descriptor.
- */
-CarryDescriptor.prototype = new Descriptor();
-
-/**
- * Set up the constructor, just to be neat.
- */
-CarryDescriptor.prototype.constructor = CarryDescriptor;
-
-/**
- * We label each Descriptor subclass with a type for debugging.
- */
-CarryDescriptor.prototype.type = 'CARRY';
-
-/**
- * Since this gets pathLength, not patternLength, we'll have to collapse sets
- * of CarryDescriptors later, as they may be spread sparsely through the full
- * animation and we'll only want them to be distributed over the full pattern
- * length. We may have dupes to throw away as well.
- * @param {!ThrowDescriptor} inThrowDescriptor
- * @param {!ThrowDescriptor} outThrowDescriptor
- * @param {!number} pathLength
- * @return {!CarryDescriptor}
- */
-CarryDescriptor.fromThrowDescriptors = function(inThrowDescriptor,
- outThrowDescriptor, pathLength) {
- assert(inThrowDescriptor.destHand == outThrowDescriptor.sourceHand);
- assert((inThrowDescriptor.time + inThrowDescriptor.throwNum) %
- pathLength == outThrowDescriptor.time);
- return new CarryDescriptor(inThrowDescriptor.destHand,
- inThrowDescriptor.throwNum, outThrowDescriptor.throwNum,
- inThrowDescriptor.sourceHand, outThrowDescriptor.destHand,
- (outThrowDescriptor.time + pathLength - 1) % pathLength);
-};
-
-/**
- * Create an otherwise-identical copy of this descriptor at a given time offset.
- * Note that offset may put time past patternLength; the caller will have to fix
- * this up manually.
- * @param {number} offset how many beats to offset the new descriptor.
- * @return {!Descriptor} the new copy.
- */
-CarryDescriptor.prototype.clone = function(offset) {
- offset = offset || 0; // Turn null into 0.
- return new CarryDescriptor(this.hand, this.sourceThrowNum,
- this.destThrowNum, this.sourceHand, this.destHand, this.time + offset);
-};
-
-/**
- * Convert the CarryDescriptor to a string for debugging.
- * @return {String} debugging output.
- */
-CarryDescriptor.prototype.toString = function() {
- return 'time: ' + this.time + ' (hand ' + this.hand + ' catches ' +
- this.sourceThrowNum + ' from hand ' + this.sourceHand + ' then throws ' +
- this.destThrowNum + ' to hand ' + this.destHand + ')';
-};
-
-/**
- * Test if this CarryDescriptor is equivalent to another, mod patternLength.
- * @param {!CarryDescriptor} cd the other CarryDescriptor.
- * @param {!number} patternLength the length of the pattern.
- * @return {!bool}
- */
-CarryDescriptor.prototype.equalsWithMod = function(cd, patternLength) {
- if (!(cd instanceof CarryDescriptor)) {
- return false;
- }
- if (this.hand != cd.hand) {
- return false;
- }
- if (this.sourceThrowNum != cd.sourceThrowNum) {
- return false;
- }
- if (this.destThrowNum != cd.destThrowNum) {
- return false;
- }
- if (this.sourceHand != cd.sourceHand) {
- return false;
- }
- if (this.destHand != cd.destHand) {
- return false;
- }
- if (this.time % patternLength != cd.time % patternLength) {
- return false;
- }
- return true;
-};
-
-/**
- * Generate the Curve implied by this descriptor and the supplied hand
- * positions.
- * @param {!Array.HandPositionRecord} handPositions where the hands will be.
- * @return {!Curve} the curve.
- */
-CarryDescriptor.prototype.generateCurve = function(handPositions) {
- var startPos = handPositions[this.hand].catchPosition;
- var endPos = handPositions[this.hand].throwPositions[this.destHand];
- return Curve.computeCircularCurve(startPos, endPos, this.time, 1);
-};
-
-/**
- * This describes a carry of a "1" in a site-swap pattern.
- * The flags isThrow and isCatch tell whether this is the actual 1 [isThrow] or
- * the carry that receives the handoff [isCatch]. It's legal for both to be
- * true, which happens when there are two 1s in a row.
- * @param {!number} sourceThrowNum the site-swap number of the prev throw
- * [including this one if isCatch].
- * @param {!number} sourceHand the index of the hand throwing sourceThrowNum.
- * @param {!number} destThrowNum the site-swap number of the next throw
- * [including this one if isThrow].
- * @param {!number} destHand the index of the hand catching destThrowNum.
- * @param {!number} hand the index of the hand doing this carry.
- * @param {!number} time the time at which the carry starts.
- * @param {!bool} isThrow whether this is a 1.
- * @param {!bool} isCatch whether this is the carry after a 1.
- * @constructor
- */
-CarryOneDescriptor = function(sourceThrowNum, sourceHand, destThrowNum,
- destHand, hand, time, isThrow, isCatch) {
- // It's possible to have !isCatch with sourceThrowNum == 1 temporarily, if we
- // just haven't handled that 1 yet [we're doing the throw of this one, and
- // will later get to the previous one, due to wraparound], and vice-versa.
- assert(isThrow || (sourceThrowNum == 1));
- assert(isCatch || (destThrowNum == 1));
- this.sourceThrowNum = sourceThrowNum;
- this.sourceHand = sourceHand;
- this.destHand = destHand;
- this.destThrowNum = destThrowNum;
- this.hand = hand;
- this.time = time;
- this.isThrow = isThrow;
- this.isCatch = isCatch;
- return this;
-}
-
-/**
- * This is a subclass of Descriptor.
- */
-CarryOneDescriptor.prototype = new Descriptor();
-
-/**
- * Set up the constructor, just to be neat.
- */
-CarryOneDescriptor.prototype.constructor = CarryOneDescriptor;
-
-/**
- * We label each Descriptor subclass with a type for debugging.
- */
-CarryOneDescriptor.prototype.type = 'CARRY_ONE';
-
-/**
- * Create a pair of CarryOneDescriptors to describe the carry that is a throw of
- * 1. A 1 spends all its time being carried, so these two carries surrounding
- * it represent [and therefore don't have] a throw between them.
- * Prev and post are generally the ordinary CarryDescriptors surrounding the
- * throw of 1 that we're trying to implement. However, they could each [or
- * both] independently be CarryOneDescriptors implementing other 1 throws.
- * @param {!Descriptor} prev the carry descriptor previous to the 1.
- * @param {!Descriptor} post the carry descriptor subsequent to the 1.
- * @return {!Array.CarryOneDescriptor} a pair of CarryOneDescriptors.
- */
-CarryOneDescriptor.getDescriptorPair = function(prev, post) {
- assert(prev instanceof CarryDescriptor || prev instanceof CarryOneDescriptor);
- assert(post instanceof CarryDescriptor || post instanceof CarryOneDescriptor);
- assert(prev.destHand == post.hand);
- assert(prev.hand == post.sourceHand);
- var newPrev;
- var newPost;
- if (prev instanceof CarryOneDescriptor) {
- assert(prev.isCatch && !prev.isThrow);
- newPrev = prev;
- newPrev.isThrow = true;
- assert(newPrev.destHand == post.hand);
- } else {
- newPrev = new CarryOneDescriptor(prev.sourceThrowNum, prev.sourceHand, 1,
- post.hand, prev.hand, prev.time, true, false);
- }
- if (post instanceof CarryOneDescriptor) {
- assert(post.isThrow && !post.isCatch);
- newPost = post;
- newPost.isCatch = true;
- assert(newPost.sourceHand == prev.hand);
- assert(newPost.sourceThrowNum == 1);
- } else {
- newPost = new CarryOneDescriptor(1, prev.hand, post.destThrowNum,
- post.destHand, post.hand, post.time, false, true);
- }
- return [newPrev, newPost];
-};
-
-/**
- * Convert the CarryOneDescriptor to a string for debugging.
- * @return {String} debugging output.
- */
-CarryOneDescriptor.prototype.toString = function() {
- var s;
- if (this.isThrow) {
- s = 'Hand ' + this.hand + ' catches a ' + this.sourceThrowNum + ' from ' +
- this.sourceHand + ' at time ' + this.time + ' and then passes a 1 to ' +
- this.destHand + '.';
- } else {
- assert(this.isCatch && this.sourceThrowNum == 1);
- s = 'Hand ' + this.hand + ' catches a 1 from ' + this.sourceHand +
- ' at time ' + this.time + ' and then passes a ' + this.destThrowNum +
- ' to ' + this.destHand + '.';
- }
- return s;
-};
-
-/**
- * Compute the curve taken by a ball during the carry representing a 1, as long
- * as it's not both a catch and a throw of a 1, which is handled elsewhere.
- * It's either a LERP from a circular curve [a catch of a throw > 1] to a
- * straight line to the handoff point [for isThrow] or a LERP from a straight
- * line from the handoff to a circular curve for the next throw > 1 [for
- * isCatch].
- *
- * @param {!EquationCoefficients} catchPos
- * @param {!EquationCoefficients} throwPos
- * @param {!EquationCoefficients} handoffPos
- * @param {!number} startTime
- * @param {!bool} isCatch whether this is the carry after a 1.
- * @param {!bool} isThrow whether this is a 1.
- * @return {!Curve}
- */
-Curve.computeCarryOneCurve = function(catchPos, throwPos, handoffPos, startTime,
- isCatch, isThrow) {
- assert(!isCatch != !isThrow);
- var curve = Curve.computeCircularCurve(catchPos, throwPos, startTime, 1);
- var curve2 = Curve.computeStraightLineCurve(handoffPos, handoffPos,
- startTime, 1);
- return curve.lerpIn(curve2, isThrow ? 1 : -1);
-}
-
-/**
- * Compute the curve taken by a ball during the carry representing a 1 that is
- * both the catch of one 1 and the immediately-following throw of another 1.
- *
- * @param {!EquationCoefficients} leadingHandoffPos
- * @param {!EquationCoefficients} trailingHandoffPos
- * @param {!Array.HandPositionRecord} handPositions where the hands will be.
- * @param {!number} hand
- * @param {!number} time the time at which the first 1's catch takes place.
- * @return {!Curve}
- */
-Curve.computeConsecutiveCarryOneCurve = function(leadingHandoffPos,
- trailingHandoffPos, handPositions, hand, time) {
- var curve = Curve.computeStraightLineCurve(leadingHandoffPos,
- handPositions[hand].basePosition, time, 1);
- var curve2 =
- Curve.computeStraightLineCurve(handPositions[hand].basePosition,
- trailingHandoffPos, time, 1);
- return curve.lerpIn(curve2, 1);
-}
-
-/**
- * Generate the Curve implied by this descriptor and the supplied hand
- * positions.
- * @param {!Array.HandPositionRecord} handPositions where the hands will be.
- * @return {!Curve} the curve.
- */
-CarryOneDescriptor.prototype.generateCurve = function(handPositions) {
- var leadingHandoffPos, trailingHandoffPos;
- if (this.isCatch) {
- var p0 = handPositions[this.hand].basePosition;
- var p1 = handPositions[this.sourceHand].basePosition;
- handoffPos = leadingHandoffPos = p0.add(p1).scale(0.5);
- }
- if (this.isThrow) {
- var p0 = handPositions[this.hand].basePosition;
- var p1 = handPositions[this.destHand].basePosition;
- handoffPos = trailingHandoffPos = p0.add(p1).scale(0.5);
- }
- if (!this.isCatch || !this.isThrow) {
- return Curve.computeCarryOneCurve(handPositions[this.hand].catchPosition,
- handPositions[this.hand].throwPositions[this.destHand], handoffPos,
- this.time, this.isCatch, this.isThrow);
- } else {
- return Curve.computeConsecutiveCarryOneCurve(leadingHandoffPos,
- trailingHandoffPos, handPositions, this.hand, this.time);
- }
-};
-
-/**
- * Create an otherwise-identical copy of this descriptor at a given time offset.
- * Note that offset may put time past patternLength; the caller will have to fix
- * this up manually.
- * @param {number} offset how many beats to offset the new descriptor.
- * @return {!Descriptor} the new copy.
- */
-CarryOneDescriptor.prototype.clone = function(offset) {
- offset = offset || 0; // Turn null into 0.
- return new CarryOneDescriptor(this.sourceThrowNum, this.sourceHand,
- this.destThrowNum, this.destHand, this.hand, this.time + offset,
- this.isThrow, this.isCatch);
-};
-
-/**
- * Test if this CarryOneDescriptor is equivalent to another, mod patternLength.
- * @param {!CarryOneDescriptor} cd the other CarryOneDescriptor.
- * @param {!number} patternLength the length of the pattern.
- * @return {!bool}
- */
-CarryOneDescriptor.prototype.equalsWithMod = function(cd, patternLength) {
- if (!(cd instanceof CarryOneDescriptor)) {
- return false;
- }
- if (this.hand != cd.hand) {
- return false;
- }
- if (this.sourceThrowNum != cd.sourceThrowNum) {
- return false;
- }
- if (this.destThrowNum != cd.destThrowNum) {
- return false;
- }
- if (this.sourceHand != cd.sourceHand) {
- return false;
- }
- if (this.destHand != cd.destHand) {
- return false;
- }
- if (this.isCatch != cd.isCatch) {
- return false;
- }
- if (this.isThrow != cd.isThrow) {
- return false;
- }
- if (this.time % patternLength != cd.time % patternLength) {
- return false;
- }
- return true;
-};
-
-/**
- * This describes an empty hand in a site-swap pattern.
- * @param {!Descriptor} cd0 the CarryDescriptor or CarryOneDescriptor describing
- * this hand immediately before it was emptied.
- * @param {!Descriptor} cd1 the CarryDescriptor or CarryOneDescriptor describing
- * this hand immediately after it's done being empty.
- * @param {!number} patternLength the length of the pattern.
- * @constructor
- */
-EmptyHandDescriptor = function(cd0, cd1, patternLength) {
- assert(cd0.hand == cd1.hand);
- this.hand = cd0.hand;
- this.prevThrowDest = cd0.destHand;
- this.sourceThrowNum = cd0.destThrowNum;
- this.nextCatchSource = cd1.sourceHand;
- this.destThrowNum = cd1.sourceThrowNum;
- // This code assumes that each CarryDescriptor and CarryOneDescriptor always
- // has a duration of 1 beat. If we want to be able to allow long-held balls
- // [instead of thrown twos, for example], we'll have to fix that here and a
- // number of other places.
- this.time = (cd0.time + 1) % patternLength;
- this.duration = cd1.time - this.time;
- if (this.duration < 0) {
- this.duration += patternLength;
- assert(this.duration > 0);
- }
-}
-
-/**
- * This is a subclass of Descriptor.
- */
-EmptyHandDescriptor.prototype = new Descriptor();
-
-/**
- * Set up the constructor, just to be neat.
- */
-EmptyHandDescriptor.prototype.constructor = EmptyHandDescriptor;
-
-/**
- * We label each Descriptor subclass with a type for debugging.
- */
-EmptyHandDescriptor.prototype.type = 'EMPTY';
-
-/**
- * Convert the EmptyHandDescriptor to a string for debugging.
- * @return {String} debugging output.
- */
-EmptyHandDescriptor.prototype.toString = function() {
- return 'time: ' + this.time + ' for ' + this.duration + ' (hand ' +
- this.hand + ', after throwing a ' + this.sourceThrowNum + ' to hand ' +
- this.prevThrowDest + ' then catches a ' + this.destThrowNum +
- ' from hand ' + this.nextCatchSource + ')';
-};
-
-/**
- * Generate the Curve implied by this descriptor and the supplied hand
- * positions.
- * @param {!Array.HandPositionRecord} handPositions where the hands will be.
- * @return {!Curve} the curve.
- */
-EmptyHandDescriptor.prototype.generateCurve = function(handPositions) {
- var startPos, endPos;
- if (this.sourceThrowNum == 1) {
- var p0 = handPositions[this.hand].basePosition;
- var p1 = handPositions[this.prevThrowDest].basePosition;
- startPos = p0.add(p1).scale(0.5);
- } else {
- startPos = handPositions[this.hand].throwPositions[this.prevThrowDest];
- }
- if (this.destThrowNum == 1) {
- var p0 = handPositions[this.hand].basePosition;
- var p1 = handPositions[this.nextCatchSource].basePosition;
- endPos = p0.add(p1).scale(0.5);
- } else {
- endPos = handPositions[this.hand].catchPosition;
- }
- // TODO: Replace with a good empty-hand curve.
- return Curve.computeStraightLineCurve(startPos, endPos, this.time,
- this.duration);
-};
-
-/**
- * A series of descriptors that describes the full path of an object during a
- * pattern.
- * @param {!Array.Descriptor} descriptors all descriptors for the object.
- * @param {!number} pathLength the length of the path in beats.
- * @constructor
- */
-Path = function(descriptors, pathLength) {
- this.descriptors = descriptors;
- this.pathLength = pathLength;
-}
-
-/**
- * Create a Path representing a ball, filling in the gaps between the throws
- * with carry descriptors. Since it's a ball's path, there are no
- * EmptyHandDescriptors in the output.
- * @param {!Array.ThrowDescriptor} throwDescriptors the ball's part of the
- * pattern.
- * @param {!number} pathLength the length of the pattern in beats.
- * @return {!Path} the ball's full path.
- */
-Path.ballPathFromThrowDescriptors = function(throwDescriptors, pathLength) {
- return new Path(
- Path.createDescriptorList(throwDescriptors, pathLength), pathLength);
-};
-
-/**
- * Create the sequence of ThrowDescriptors, CarryDescriptors, and
- * CarryOneDescriptor describing the path of a ball through a pattern.
- * A sequence such as (h j k) generally maps to an alternating series of throw
- * and carry descriptors [Th Chj Tj Cjk Tk Ck? ...]. However, when j is a 1,
- * you remove the throw descriptor and modify the previous and subsequent carry
- * descriptors, since the throw descriptor has zero duration and the carry
- * descriptors need to take into account the handoff.
- * @param {!Array.ThrowDescriptor} throwDescriptors the ball's part of the
- * pattern.
- * @param {!number} pathLength the length of the pattern in beats.
- * @return {!Array.Descriptor} the full set of descriptors for the ball.
- */
-Path.createDescriptorList = function(throwDescriptors, pathLength) {
- var descriptors = [];
- var prevThrow;
- for (var index in throwDescriptors) {
- var td = throwDescriptors[index];
- if (prevThrow) {
- descriptors.push(
- CarryDescriptor.fromThrowDescriptors(prevThrow, td, pathLength));
- } // Else it's handled after the loop.
- descriptors.push(td);
- prevThrow = td;
- }
- descriptors.push(
- CarryDescriptor.fromThrowDescriptors(prevThrow, throwDescriptors[0],
- pathLength));
- // Now post-process to take care of throws of 1. It's easier to do it here
- // than during construction since we can now assume that the previous and
- // subsequent carry descriptors are already in place [modulo pathLength].
- for (var i = 0; i < descriptors.length; ++i) {
- var descriptor = descriptors[i];
- if (descriptor instanceof ThrowDescriptor) {
- if (descriptor.throwNum == 1) {
- var prevIndex = (i + descriptors.length - 1) % descriptors.length;
- var postIndex = (i + 1) % descriptors.length;
- var replacements = CarryOneDescriptor.getDescriptorPair(
- descriptors[prevIndex], descriptors[postIndex]);
- descriptors[prevIndex] = replacements[0];
- descriptors[postIndex] = replacements[1];
- descriptors.splice(i, 1);
- // We've removed a descriptor from the array, but since we can never
- // have 2 ThrowDescriptors in a row, we don't need to decrement i.
- }
- }
- }
- return descriptors;
-};
-
-/**
- * Convert the Path to a string for debugging.
- * @return {String} debugging output.
- */
-Path.prototype.toString = function() {
- var ret = 'pathLength is ' + this.pathLength + '; [';
- for (var index in this.descriptors) {
- ret += this.descriptors[index].toString();
- }
- ret += ']';
- return ret;
-};
-
-/**
- * Create an otherwise-identical copy of this path at a given time offset.
- * Note that offset may put time references in the Path past the length of the
- * pattern. The caller must fix this up manually.
- * @param {number} offset how many beats to offset the new Path.
- * @return {!Path} the new copy.
- */
-Path.prototype.clone = function(offset) {
- offset = offset || 0; // Turn null into 0.
- var descriptors = [];
- for (var index in this.descriptors) {
- descriptors.push(this.descriptors[index].clone(offset));
- }
- return new Path(descriptors, this.pathLength);
-};
-
-/**
- * Adjust the start time of all descriptors to be in [0, pathLength) via modular
- * arithmetic. Reorder the array such that they're sorted in increasing order
- * of time.
- * @return {!Path} this.
- */
-Path.prototype.fixUpModPathLength = function() {
- var splitIndex;
- var prevTime = 0;
- for (var index in this.descriptors) {
- var d = this.descriptors[index];
- d.fixUpModPathLength(this.pathLength);
- if (d.time < prevTime) {
- assert(null == splitIndex);
- splitIndex = index; // From here to the end should move to the start.
- }
- prevTime = d.time;
- }
- if (null != splitIndex) {
- var temp = this.descriptors.slice(splitIndex);
- this.descriptors.length = splitIndex;
- this.descriptors = temp.concat(this.descriptors);
- }
- return this;
-};
-
-/**
- * Take a standard asynch siteswap pattern [expressed as an array of ints] and
- * a number of hands, and expand it into a 2D grid of ThrowDescriptors with one
- * row per hand.
- * Non-asynch patterns are more complicated, since their linear forms aren't
- * fully-specified, so we don't handle them here.
- * You'll want to expand your pattern to the LCM of numHands and minimal pattern
- * length before calling this.
- * The basic approach doesn't really work for one-handed patterns. It ends up
- * with catches and throws happening at the same time [having removed all
- * empty-hand time in between them]. To fix this, we double all throw heights
- * and space them out, as if doing a two-handed pattern with all zeroes from the
- * other hand. Yes, this points out that the overall approach we're taking is a
- * bit odd [since you end up with hands empty for time proportional to the
- * number of hands], but you have to make some sort of assumptions to generalize
- * siteswaps to N hands, and that's what I chose.
- * @param {!Array.number} pattern an asynch siteswap pattern.
- * @param {!number} numHands the number of hands.
- * @return {!Array.Array.ThrowDescriptor} the expanded pattern.
- */
-function expandPattern(pattern, numHands) {
- var fullPattern = [];
- assert(numHands > 0);
- if (numHands == 1) {
- numHands = 2;
- var temp = [];
- for (var i = 0; i < pattern.length; ++i) {
- temp[2 * i] = 2 * pattern[i];
- temp[2 * i + 1] = 0;
- }
- pattern = temp;
- }
- for (var hand = 0; hand < numHands; ++hand) {
- fullPattern[hand] = [];
- }
- for (var time = 0; time < pattern.length; ++time) {
- for (var hand = 0; hand < numHands; ++hand) {
- var t;
- if (hand == time % numHands) {
- t = new ThrowDescriptor(pattern[time], time, hand,
- (hand + pattern[time]) % numHands);
- } else {
- // These are ignored during analysis, so they don't appear in BallPaths.
- t = new ThrowDescriptor(0, time, hand, hand);
- }
- fullPattern[hand].push(t);
- }
- }
- return fullPattern;
-}
-
-// TODO: Wrap the final pattern in a class, then make the remaining few global
-// functions be members of that class to clean up the global namespace.
-
-/**
- * Given a valid site-swap for a nonzero number of balls, stored as an expanded
- * pattern array-of-arrays, with pattern length the LCM of hands and minimal
- * pattern length, produce Paths for all the balls.
- * @param {!Array.Array.ThrowDescriptor} pattern a valid pattern.
- * @return {!Array.Path} the paths of all the balls.
- */
-function generateBallPaths(pattern) {
- var numHands = pattern.length;
- assert(numHands > 0);
- var patternLength = pattern[0].length;
- assert(patternLength > 0);
- var sum = 0;
- for (var hand in pattern) {
- for (var time in pattern[hand]) {
- sum += pattern[hand][time].throwNum;
- }
- }
- var numBalls = sum / patternLength;
- assert(numBalls == Math.round(numBalls));
- assert(numBalls > 0);
-
- var ballsToAllocate = numBalls;
- var ballPaths = [];
- // NOTE: The indices of locationsChecked are reversed from those of pattern
- // for simplicity of allocation. This might be worth flipping to match.
- var locationsChecked = [];
- for (var time = 0; time < patternLength && ballsToAllocate; ++time) {
- locationsChecked[time] = locationsChecked[time] || [];
- for (var hand = 0; hand < numHands && ballsToAllocate; ++hand) {
- if (locationsChecked[time][hand]) {
- continue;
- }
- var curThrowDesc = pattern[hand][time];
- var curThrow = curThrowDesc.throwNum;
- if (!curThrow) {
- assert(curThrow === 0);
- continue;
- }
- var throwDescriptors = [];
- var curTime = time;
- var curHand = hand;
- var wraps = 0;
- do {
- if (!locationsChecked[curTime]) {
- locationsChecked[curTime] = [];
- }
- assert(!locationsChecked[curTime][curHand]);
- locationsChecked[curTime][curHand] = true;
- // We copy curThrowDesc here, adding wraps * patternLength, to get
- // the true throw time relative to offset. Later we'll add in offset
- // when we clone again, then mod by pathLength.
- throwDescriptors.push(curThrowDesc.clone(wraps * patternLength));
- var nextThrowTime = curThrow + curTime;
- wraps += Math.floor(nextThrowTime / patternLength);
- curTime = nextThrowTime % patternLength;
- assert(curTime >= time); // Else we'd have covered it earlier.
- curHand = curThrowDesc.destHand;
- var tempThrowDesc = curThrowDesc;
- curThrowDesc = pattern[curHand][curTime];
- curThrow = curThrowDesc.throwNum;
- assert(tempThrowDesc.destHand == curThrowDesc.sourceHand);
- assert(curThrowDesc.time ==
- (tempThrowDesc.throwNum + tempThrowDesc.time) % patternLength);
- } while (curTime != time || curHand != hand);
- var pathLength = wraps * patternLength;
- var ballPath =
- Path.ballPathFromThrowDescriptors(throwDescriptors, pathLength);
- for (var i = 0; i < wraps; ++i) {
- var offset = i * patternLength % pathLength;
- ballPaths.push(ballPath.clone(offset, pathLength).fixUpModPathLength());
- }
- ballsToAllocate -= wraps;
- assert(ballsToAllocate >= 0);
- }
- }
- return ballPaths;
-}
-
-/**
- * Given an array of ball paths, produce the corresponding set of hand paths.
- * @param {!Array.Path} ballPaths the Paths of all the balls in the pattern.
- * @param {!number} numHands how many hands to use in the pattern.
- * @param {!number} patternLength the length, in beats, of the pattern.
- * @return {!Array.Path} the paths of all the hands.
- */
-function generateHandPaths(ballPaths, numHands, patternLength) {
- assert(numHands > 0);
- assert(patternLength > 0);
- var handRecords = []; // One record per hand.
- for (var idxBR in ballPaths) {
- var descriptors = ballPaths[idxBR].descriptors;
- for (var idxD in descriptors) {
- var descriptor = descriptors[idxD];
- // TODO: Fix likely needed for throws of 1.
- if (!(descriptor instanceof ThrowDescriptor)) {
- // It's a CarryDescriptor or a CarryOneDescriptor.
- var hand = descriptor.hand;
- if (!handRecords[hand]) {
- handRecords[hand] = [];
- }
- // TODO: Should we not shorten stuff here if we're going to lengthen
- // everything later anyway? Is there a risk of inconsistency due to
- // ball paths of different lengths?
- var catchTime = descriptor.time % patternLength;
- if (!handRecords[hand][catchTime]) {
- // We pass in this offset to set the new descriptor's time to
- // catchTime, so as to keep it within [0, patternLength).
- handRecords[hand][catchTime] =
- descriptor.clone(catchTime - descriptor.time);
- } else {
- assert(
- handRecords[hand][catchTime].equalsWithMod(
- descriptor, patternLength));
- }
- }
- }
- }
- var handPaths = [];
- for (var hand in handRecords) {
- var outDescriptors = [];
- var inDescriptors = handRecords[hand];
- var prevDescriptor = null;
- var descriptor;
- for (var idxD in inDescriptors) {
- descriptor = inDescriptors[idxD];
- assert(descriptor); // Enumeration should skip array holes.
- assert(descriptor.hand == hand);
- if (prevDescriptor) {
- outDescriptors.push(new EmptyHandDescriptor(prevDescriptor, descriptor,
- patternLength));
- }
- outDescriptors.push(descriptor.clone());
- prevDescriptor = descriptor;
- }
- // Note that this EmptyHandDescriptor that wraps around the end lives at the
- // end of the array, not the beginning, despite the fact that it may be the
- // active one at time zero. This is the same behavior as with Paths for
- // balls.
- descriptor = new EmptyHandDescriptor(prevDescriptor, outDescriptors[0],
- patternLength);
- if (descriptor.time < outDescriptors[0].time) {
- assert(descriptor.time + descriptor.duration == outDescriptors[0].time);
- outDescriptors.unshift(descriptor);
- } else {
- assert(descriptor.time ==
- outDescriptors[outDescriptors.length - 1].time + 1);
- outDescriptors.push(descriptor);
- }
- handPaths[hand] =
- new Path(outDescriptors, patternLength).fixUpModPathLength();
- }
- return handPaths;
-}
-
-// NOTE: All this Vector stuff does lots of object allocations. If that's a
-// problem for your browser [e.g. IE6], you'd better stick with the embedded V8.
-// This code predates the creation of o3djs/math.js; I should probably switch it
-// over at some point, but for now it's not worth the trouble.
-
-/**
- * A simple 3-dimensional vector.
- * @constructor
- */
-Vector = function(x, y, z) {
- this.x = x;
- this.y = y;
- this.z = z;
-}
-
-Vector.prototype.sub = function(v) {
- return new Vector(this.x - v.x, this.y - v.y, this.z - v.z);
-};
-
-Vector.prototype.add = function(v) {
- return new Vector(this.x + v.x, this.y + v.y, this.z + v.z);
-};
-
-Vector.prototype.dot = function(v) {
- return this.x * v.x + this.y * v.y + this.z * v.z;
-};
-
-Vector.prototype.length = function() {
- return Math.sqrt(this.dot(this));
-};
-
-Vector.prototype.scale = function(s) {
- return new Vector(this.x * s, this.y * s, this.z * s);
-};
-
-Vector.prototype.set = function(v) {
- this.x = v.x;
- this.y = v.y;
- this.z = v.z;
-};
-
-Vector.prototype.normalize = function() {
- var length = this.length();
- assert(length);
- this.set(this.scale(1 / length));
- return this;
-};
-
-/**
- * Convert the Vector to a string for debugging.
- * @return {String} debugging output.
- */
-Vector.prototype.toString = function() {
- return '{' + this.x.toFixed(3) + ', ' + this.y.toFixed(3) + ', ' +
- this.z.toFixed(3) + '}';
-};
-
-/**
- * A container class that holds the positions relevant to a hand: where it is
- * when it's not doing anything, where it likes to catch balls, and where it
- * likes to throw balls to each of the other hands.
- * @param {!Vector} basePosition the centroid of throw and catch positions when
- * the hand throws to itself.
- * @param {!Vector} catchPosition where the hand likes to catch balls.
- * @constructor
- */
-HandPositionRecord = function(basePosition, catchPosition) {
- this.basePosition = basePosition;
- this.catchPosition = catchPosition;
- this.throwPositions = [];
-}
-
-/**
- * Convert the HandPositionRecord to a string for debugging.
- * @return {String} debugging output.
- */
-HandPositionRecord.prototype.toString = function() {
- var s = 'base: ' + this.basePosition.toString() + ';\n';
- s += 'catch: ' + this.catchPosition.toString() + ';\n';
- s += 'throws:\n';
- for (var i = 0; i < this.throwPositions.length; ++i) {
- s += '[' + i + '] ' + this.throwPositions[i].toString() + '\n';
- }
- return s;
-};
-
-/**
- * Compute all the hand positions used in a pattern given a number of hands and
- * a grouping style ["even" for evenly-spaced hands, "pairs" to group them in
- * pairs, as with 2-handed jugglers].
- * @param {!number} numHands the number of hands to use.
- * @param {!String} style the grouping style.
- * @return {!Array.HandPositionRecord} a full set of hand positions.
- */
-function computeHandPositions(numHands, style) {
- assert(numHands > 0);
- var majorRadiusScale = 0.75;
- var majorRadius = majorRadiusScale * (numHands - 1);
- var throwCatchOffset = 0.45;
- var catchRadius = majorRadius + throwCatchOffset;
- var handPositionRecords = [];
- for (var hand = 0; hand < numHands; ++hand) {
- var circleFraction;
- if (style == 'even') {
- circleFraction = hand / numHands;
- } else {
- assert(style == 'pairs');
- circleFraction = (hand + Math.floor(hand / 2)) / (1.5 * numHands);
- }
- var cos = Math.cos(Math.PI * 2 * circleFraction);
- var sin = Math.sin(Math.PI * 2 * circleFraction);
- var cX = catchRadius * cos;
- var cY = 0;
- var cZ = catchRadius * sin;
- var bX = majorRadius * cos;
- var bY = 0;
- var bZ = majorRadius * sin;
- handPositionRecords[hand] = new HandPositionRecord(
- new Vector(bX, bY, bZ), new Vector(cX, cY, cZ));
- }
- // Now that we've got all the hands' base and catch positions, we need to
- // compute the appropriate throw positions for each hand pair.
- for (var source = 0; source < numHands; ++source) {
- var throwHand = handPositionRecords[source];
- for (var target = 0; target < numHands; ++target) {
- var catchHand = handPositionRecords[target];
- if (throwHand == catchHand) {
- var baseV = throwHand.basePosition;
- throwHand.throwPositions[target] =
- baseV.add(baseV.sub(throwHand.catchPosition));
- } else {
- var directionV =
- catchHand.catchPosition.sub(throwHand.basePosition).normalize();
- var offsetV = directionV.scale(throwCatchOffset);
- throwHand.throwPositions[target] =
- throwHand.basePosition.add(offsetV);
- }
- }
- }
- return handPositionRecords;
-}
-
-/**
- * Convert an array of HandPositionRecord to a string for debugging.
- * @param {!Array.HandPositionRecord} positions the positions to display.
- * @return {String} debugging output.
- */
-function getStringFromHandPositions(positions) {
- var s = '';
- for (index in positions) {
- s += positions[index].toString();
- }
- return s;
-}
-
-/**
- * The set of curves an object passes through throughout a full animation cycle.
- * @param {!number} duration the length of the animation in beats.
- * @param {!Array.Curve} curves the full set of Curves.
- * @constructor
- */
-CurveSet = function(duration, curves) {
- this.duration = duration;
- this.curves = curves;
-}
-
-/**
- * Looks up what curve is active at a particular time. This is slower than
- * getCurveForTime, but can be used even if no Curve starts precisely at
- * unsafeTime % this.duration.
- * @param {!number} unsafeTime the time at which to check.
- * @return {!Curve} the curve active at unsafeTime.
- */
-CurveSet.prototype.getCurveForUnsafeTime = function(unsafeTime) {
- unsafeTime %= this.duration;
- time = Math.floor(unsafeTime);
- if (this.curves[time]) {
- return this.curves[time];
- }
- var curve;
- for (var i = time; i >= 0; --i) {
- curve = this.curves[i];
- if (curve) {
- assert(i + curve.duration >= unsafeTime);
- return curve;
- }
- }
- // We must want the last one. There's always a last one, given how we
- // construct the CurveSets; they're sparse, but the length gets set by adding
- // elements at the end.
- curve = this.curves[this.curves.length - 1];
- unsafeTime += this.duration;
- assert(curve.startTime <= unsafeTime);
- assert(curve.startTime + curve.duration > unsafeTime);
- return curve;
-};
-
-/**
- * Looks up what curve is active at a particular time. This is faster than
- * getCurveForUnsafeTime, but can only be used if if a Curve starts precisely at
- * unsafeTime % this.duration.
- * @param {!number} time the time at which to check.
- * @return {!Curve} the curve starting at time.
- */
-CurveSet.prototype.getCurveForTime = function(time) {
- return this.curves[time % this.duration];
-};
-
-/**
- * Convert the CurveSet to a string for debugging.
- * @return {String} debugging output.
- */
-CurveSet.prototype.toString = function() {
- var s = 'Duration: ' + this.duration + '\n';
- for (var c in this.curves) {
- s += this.curves[c].toString();
- }
- return s;
-};
-
-/**
- * Namespace object to hold the pure math functions.
- * TODO: Consider just rolling these into the Pattern object, when it gets
- * created.
- */
-var JugglingMath = {};
-
-/**
- * Computes the greatest common devisor of integers a and b.
- * @param {!number} a an integer.
- * @param {!number} b an integer.
- * @return {!number} the GCD of a and b.
- */
-JugglingMath.computeGCD = function(a, b) {
- assert(Math.round(a) == a);
- assert(Math.round(b) == b);
- assert(a >= 0);
- assert(b >= 0);
- if (!b) {
- return a;
- } else {
- return JugglingMath.computeGCD(b, a % b);
- }
-}
-
-/**
- * Computes the least common multiple of integers a and b, by making use of the
- * fact that LCM(a, b) * GCD(a, b) == a * b.
- * @param {!number} a an integer.
- * @param {!number} b an integer.
- * @return {!number} the LCM of a and b.
- */
-JugglingMath.computeLCM = function(a, b) {
- assert(Math.round(a) == a);
- assert(Math.round(b) == b);
- assert(a >= 0);
- assert(b >= 0);
- var ret = a * b / JugglingMath.computeGCD(a, b);
- assert(Math.round(ret) == ret);
- return ret;
-}
-
-/**
- * Given a Path and a set of hand positions, compute the corresponding set of
- * Curves.
- * @param {!Path} path the path of an object.
- * @param {!Array.HandPositionRecord} handPositions the positions of the hands
- * juggling the pattern containing the path.
- * @return {!CurveSet} the full set of curves.
- */
-CurveSet.getCurveSetFromPath = function(path, handPositions) {
- var curves = [];
- var pathLength = path.pathLength;
- for (var index in path.descriptors) {
- var descriptor = path.descriptors[index];
- var curve = descriptor.generateCurve(handPositions);
- assert(!curves[curve.startTime]);
- assert(curve.startTime < pathLength);
- curves[curve.startTime] = curve;
- }
- return new CurveSet(pathLength, curves);
-}
-
-/**
- * Given a set of Paths and a set of hand positions, compute the corresponding
- * CurveSets.
- * @param {!Array.Path} paths the paths of a number of objects.
- * @param {!Array.HandPositionRecord} handPositions the positions of the hands
- * juggling the pattern containing the paths.
- * @return {!Array.CurveSet} the CurveSets.
- */
-CurveSet.getCurveSetsFromPaths = function(paths, handPositions) {
- var curveSets = [];
- for (var index in paths) {
- var path = paths[index];
- curveSets[index] = CurveSet.getCurveSetFromPath(path, handPositions);
- }
- return curveSets;
-}
-
-/**
- * This is a temporary top-level calculation function that converts a standard
- * asynchronous siteswap, expressed as a string of digits, into a full
- * ready-to-animate set of CurveSets. Later on we'll be using an interface that
- * can create a richer set of patterns than those expressable in the traditional
- * string-of-ints format.
- * @param {!String} patternString the siteswap.
- * @param {!number} numHands the number of hands to use for the pattern.
- * @param {!String} style how to space the hands ["pairs" or "even"].
- * @return {!Object} a fully-analyzed pattern as CurveSets and associated data.
- */
-function computeFullPatternFromString(patternString, numHands, style) {
- var patternAsStrings = patternString.split(/[ ,]+ */);
- var patternSegment = [];
- for (var index in patternAsStrings) {
- if (patternAsStrings[index]) { // Beware extra whitespace at the ends.
- patternSegment.push(parseInt(patternAsStrings[index]));
- }
- }
- var pattern = [];
- // Now expand the pattern out to the length of the LCM of pattern length and
- // number of hands, so that each throw gets done in each of its incarnations.
- var multiple = JugglingMath.computeLCM(patternSegment.length, numHands) /
- patternSegment.length;
- for (var i = 0; i < multiple; ++i) {
- pattern = pattern.concat(patternSegment);
- }
-
- var fullPattern = expandPattern(pattern, numHands);
- var patternLength = fullPattern[0].length;
-
- var ballPaths = generateBallPaths(fullPattern);
- var handPaths = generateHandPaths(ballPaths, numHands, patternLength);
-
- var handPositions = computeHandPositions(numHands, style);
- var ballCurveSets = CurveSet.getCurveSetsFromPaths(ballPaths, handPositions);
- var handCurveSets = CurveSet.getCurveSetsFromPaths(handPaths, handPositions);
-
- // Find the LCM of all the curveSet durations. This will be the length of the
- // fully-expanded queue. We could expand to this before computing the
- // CurveSets, but this way's probably just a little cheaper.
- var lcmDuration = 1;
- for (var i in ballCurveSets) {
- var duration = ballCurveSets[i].duration;
- if (duration > lcmDuration || lcmDuration % duration) {
- lcmDuration = JugglingMath.computeLCM(lcmDuration, duration);
- }
- }
- for (var i in handCurveSets) {
- var duration = handCurveSets[i].duration;
- if (duration > lcmDuration || lcmDuration % duration) {
- lcmDuration = JugglingMath.computeLCM(lcmDuration, duration);
- }
- }
- return {
- numBalls: ballPaths.length,
- numHands: handPaths.length,
- duration: lcmDuration,
- handCurveSets: handCurveSets,
- ballCurveSets: ballCurveSets
- }
-}
+// @@REWRITE(insert js-copyright)
+// @@REWRITE(delete-start)
+// Copyright 2009 Google Inc. All Rights Reserved
+// @@REWRITE(delete-end)
+
+/**
+ * @fileoverview This file contains all the math for the siteswap animator. It
+ * handles all of the site-swap-related stuff [converting a sequence of integers
+ * into a more-useful representation of a pattern, pattern validation, etc.] as
+ * well as all the physics used for the simulation.
+ */
+
+/**
+ * This is a container class that holds the coefficients of an equation
+ * describing the motion of an object.
+ * The basic equation is:
+ * f(x) := a t^2 + b t + c + d sin (f t) + e cos (f t).
+ * However, sometimes we LERP between that function and this one:
+ * g(x) := lA t^2 + lB t + lC
+ * lerpRate [so far] is always either 1 [LERP from f to g over 1 beat] or -1,
+ * [LERP from g to f over one beat].
+ *
+ * Just plug in t to evaluate the equation. There's no JavaScript function to
+ * do this because it's always done on the GPU.
+ *
+ * @constructor
+ */
+EquationCoefficients = function(a, b, c, d, e, f, lA, lB, lC, lerpRate) {
+ assert(!isNaN(a) && !isNaN(b) && !isNaN(c));
+ d = d || 0;
+ e = e || 0;
+ f = f || 0;
+ assert(!isNaN(d) && !isNaN(e) && !isNaN(f));
+ lA = lA || 0;
+ lB = lB || 0;
+ lC = lC || 0;
+ assert(!isNaN(lA) && !isNaN(lB) && !isNaN(lC));
+ lerpRate = lerpRate || 0;
+ this.a = a;
+ this.b = b;
+ this.c = c;
+ this.d = d;
+ this.e = e;
+ this.f = f;
+ this.lA = lA;
+ this.lB = lB;
+ this.lC = lC;
+ this.lerpRate = lerpRate;
+}
+
+/**
+ * Create a new equation that's equivalent to this equation's coefficients a-f
+ * with a LERP to the polynomial portion of the supplied equation.
+ * @param {!EquationCoefficients} eqn the source of coefficients.
+ * @param {!number} lerpRate the rate and direction of the LERP; positive for
+ * "from this equation to the new one" and vice-versa.
+ * @return {!EquationCoefficients} a new set of coefficients.
+ */
+EquationCoefficients.prototype.lerpIn = function(eqn, lerpRate) {
+ assert(!this.lerpRate);
+ return new EquationCoefficients(this.a, this.b, this.c, this.d, this.e,
+ this.f, eqn.a, eqn.b, eqn.c, lerpRate);
+};
+
+/**
+ * Convert the EquationCoefficients to a string for debugging.
+ * @return {String} debugging output.
+ */
+EquationCoefficients.prototype.toString = function() {
+ return 'F(t) := ' + this.a.toFixed(2) + ' t^2 + ' + this.b.toFixed(2) +
+ ' t + ' + this.c.toFixed(2) + ' + ' +
+ this.d.toFixed(2) + ' sin(' + this.f.toFixed(2) + ' t) + ' +
+ this.e.toFixed(2) + ' cos(' + this.f.toFixed(2) + ' t) + LERP(' +
+ this.lerpRate.toFixed(2) + ') of ' +
+ this.lA.toFixed(2) + ' t^2 + ' + this.lB.toFixed(2) +
+ ' t + ' + this.lC.toFixed(2);
+};
+
+/**
+ * A set of equations which describe the motion of an object over time.
+ * The three equations each supply one dimension of the motion, and the curve is
+ * valid from startTime to startTime + duration.
+ * @param {!number} startTime the initial time at which the curve is valid.
+ * @param {!number} duration how long [in beats] the curve is valid.
+ * @param {!EquationCoefficients} xEqn the equation for motion in x.
+ * @param {!EquationCoefficients} yEqn the equation for motion in y.
+ * @param {!EquationCoefficients} zEqn the equation for motion in z.
+ * @constructor
+ */
+Curve = function(startTime, duration, xEqn, yEqn, zEqn) {
+ this.startTime = startTime;
+ this.duration = duration;
+ this.xEqn = xEqn;
+ this.yEqn = yEqn;
+ this.zEqn = zEqn;
+}
+
+/**
+ * Convert the Curve to a string for debugging.
+ * @return {String} debugging output.
+ */
+Curve.prototype.toString = function() {
+ var s = 'startTime: ' + this.startTime + '\n';
+ s += 'duration: ' + this.duration + '\n';
+ s += this.xEqn + '\n';
+ s += this.yEqn + '\n';
+ s += this.zEqn + '\n';
+ return s;
+};
+
+/**
+ * Modify this curve's coefficients to include a LERP to the polynomial
+ * portion of the supplied curve.
+ * @param {!Curve} curve the source of coefficients.
+ * @param {!number} lerpRate the rate and direction of the LERP; positive for
+ * "from this equation to the new one" and vice-versa.
+ * @return {!Curve} a new curve.
+ */
+Curve.prototype.lerpIn = function(curve, lerpRate) {
+ assert(this.startTime == curve.startTime);
+ assert(this.duration == curve.duration);
+ var xEqn = this.xEqn.lerpIn(curve.xEqn, lerpRate);
+ var yEqn = this.yEqn.lerpIn(curve.yEqn, lerpRate);
+ var zEqn = this.zEqn.lerpIn(curve.zEqn, lerpRate);
+ return new Curve(this.startTime, this.duration, xEqn, yEqn, zEqn);
+};
+
+/**
+ * Produce a set of polynomial coefficients that describe linear motion between
+ * two points in 1 dimension.
+ * @param {!number} startPos the starting position.
+ * @param {!number} endPos the ending position.
+ * @param {!number} duration how long the motion takes.
+ * @return {!EquationCoefficients} the equation for the motion.
+ */
+Curve.computeLinearCoefficients = function(startPos, endPos, duration) {
+ return new EquationCoefficients(
+ 0, (endPos - startPos) / duration, startPos);
+}
+
+var GRAVITY = 1; // Higher means higher throws for the same duration.
+/**
+ * Produce a set of polynomial coefficients that describe parabolic motion
+ * between two points in 1 dimension.
+ * @param {!number} startPos the starting position.
+ * @param {!number} endPos the ending position.
+ * @param {!number} duration how long the motion takes.
+ * @return {!EquationCoefficients} the equation for the motion.
+ */
+Curve.computeParabolicCoefficients = function(startPos, endPos, duration) {
+ var dY = endPos - startPos;
+ return new EquationCoefficients(-GRAVITY / 2,
+ dY / duration + GRAVITY * duration / 2,
+ startPos);
+}
+
+/**
+ * Compute the curve taken by a ball given its throw and catch positions, the
+ * time it was thrown, and how long it stayed in the air.
+ *
+ * We use duration rather than throwTime and catchTime because, what
+ * with the modular arithmetic used in our records, catchTime might be before
+ * throwTime, and in some representations the pattern could wrap around a few
+ * times while the ball's in the air. When the parabola computed here is used,
+ * time must be supplied as an offset from the time of the throw, and must of
+ * course not wrap at all. That is, these coefficients work for f(0) ==
+ * throwPos, f(duration) == catchPos.
+ *
+ * We treat the y axis as vertical and thus affected by gravity.
+ *
+ * @param {!EquationCoefficients} throwPos
+ * @param {!EquationCoefficients} catchPos
+ * @param {!number} startTime
+ * @param {!number} duration
+ * @return {!Curve}
+ */
+Curve.computeThrowCurve = function(throwPos, catchPos, startTime, duration) {
+ var xEqn = Curve.computeLinearCoefficients(throwPos.x, catchPos.x, duration);
+ var yEqn = Curve.computeParabolicCoefficients(throwPos.y, catchPos.y,
+ duration);
+ var zEqn = Curve.computeLinearCoefficients(throwPos.z, catchPos.z, duration);
+ return new Curve(startTime, duration, xEqn, yEqn, zEqn);
+}
+
+/**
+ * Compute a straight line Curve given start and end positions, the start time,
+ * and the duration of the motion.
+ *
+ * @param {!EquationCoefficients} startPos
+ * @param {!EquationCoefficients} endPos
+ * @param {!number} startTime
+ * @param {!number} duration
+ * @return {!Curve}
+ */
+Curve.computeStraightLineCurve =
+ function(startPos, endPos, startTime, duration) {
+ var xEqn = Curve.computeLinearCoefficients(startPos.x, endPos.x, duration);
+ var yEqn = Curve.computeLinearCoefficients(startPos.y, endPos.y, duration);
+ var zEqn = Curve.computeLinearCoefficients(startPos.z, endPos.z, duration);
+ return new Curve(startTime, duration, xEqn, yEqn, zEqn);
+}
+
+/**
+ * Threshold horizontal distance below which computeCircularCurve won't bother
+ * trying to approximate a circular curve. See the comment above
+ * computeCircularCurve for more info.
+ * @type {number}
+ */
+Curve.EPSILON = .0001;
+
+/**
+ * Compute a circular curve, used as an approximation for the motion of a hand
+ * between a catch and its following throw.
+ *
+ * Assumes a lot of stuff about this looking like a "normal" throw: the catch is
+ * moving roughly the opposite direction as the throw, the throw and catch
+ * aren't at the same place, and such. Otherwise this looks very odd at best.
+ * This is used for the height of the curve.
+ * This produces coefficients for d sin(f t) + e cos(f t) for each of x, y, z.
+ * It produces a vertical-ish circular curve from the start to the end, going
+ * down, then up. So if dV [the distance from the start to finish in the x-z
+ * plane, ignoring y] is less than Curve.EPSILON, it doesn't know which way down
+ * is, and it bails by returning a straight line instead.
+ */
+Curve.computeCircularCurve = function(startPos, endPos, startTime, duration) {
+ var dX = endPos.x - startPos.x;
+ var dY = endPos.y - startPos.y;
+ var dZ = endPos.z - startPos.z;
+ var dV = Math.sqrt(dX * dX + dZ * dZ);
+ if (dV < Curve.EPSILON) {
+ return Curve.computeStraightLineCurve(startPos, endPos, startTime,
+ duration);
+ }
+ var negHalfdV = -0.5 * dV;
+ var negHalfdY = -0.5 * dY;
+ var f = Math.PI / duration;
+ var yEqn = new EquationCoefficients(
+ 0, 0, startPos.y + dY / 2,
+ negHalfdV, negHalfdY, f);
+ var ratio = dX / dV;
+ var xEqn = new EquationCoefficients(
+ 0, 0, startPos.x + dX / 2,
+ negHalfdY * ratio, negHalfdV * ratio, f);
+ ratio = dZ / dV;
+ var zEqn = new EquationCoefficients(
+ 0, 0, startPos.z + dZ / 2,
+ negHalfdY * ratio, negHalfdV * ratio, f);
+ return new Curve(startTime, duration, xEqn, yEqn, zEqn);
+}
+
+/**
+ * This is the abstract base class for an object that describes a throw, catch,
+ * or empty hand [placeholder] in a site-swap pattern.
+ * @constructor
+ */
+Descriptor = function() {
+}
+
+/**
+ * Create an otherwise-identical copy of this descriptor at a given time offset.
+ * Note that offset may put time past patternLength; the caller will have to fix
+ * this up manually.
+ * @param {number} offset how many beats to offset the new descriptor.
+ * Derived classes must override this function.
+ */
+Descriptor.prototype.clone = function(offset) {
+ throw new Error('Unimplemented.');
+};
+
+/**
+ * Generate the Curve implied by this descriptor and the supplied hand
+ * positions.
+ * @param {!Array.HandPositionRecord} handPositions where the hands will be.
+ * Derived classes must override this function.
+ */
+Descriptor.prototype.generateCurve = function(handPositions) {
+ throw new Error('Unimplemented.');
+};
+
+/**
+ * Adjust the start time of this Descriptor to be in [0, pathLength).
+ * @param {!number} pathLength the duration of a path, in beats.
+ * @return {!Descriptor} this.
+ */
+Descriptor.prototype.fixUpModPathLength = function(pathLength) {
+ this.time = this.time % pathLength;
+ return this;
+};
+
+/**
+ * This describes a throw in a site-swap pattern.
+ * @param {!number} throwNum the site-swap number of the throw.
+ * @param {!number} throwTime the time this throw occurs.
+ * @param {!number} sourceHand the index of the throwing hand.
+ * @param {!number} destHand the index of the catching hand.
+ * @constructor
+ */
+ThrowDescriptor = function(throwNum, throwTime, sourceHand, destHand) {
+ this.throwNum = throwNum;
+ this.sourceHand = sourceHand;
+ this.destHand = destHand;
+ this.time = throwTime;
+}
+
+/**
+ * This is a subclass of Descriptor.
+ */
+ThrowDescriptor.prototype = new Descriptor();
+
+/**
+ * Set up the constructor, just to be neat.
+ */
+ThrowDescriptor.prototype.constructor = ThrowDescriptor;
+
+/**
+ * We label each Descriptor subclass with a type for debugging.
+ */
+ThrowDescriptor.prototype.type = 'THROW';
+
+/**
+ * Create an otherwise-identical copy of this descriptor at a given time offset.
+ * Note that offset may put time past patternLength; the caller will have to fix
+ * this up manually.
+ * @param {number} offset how many beats to offset the new descriptor.
+ * @return {!Descriptor} the new copy.
+ */
+ThrowDescriptor.prototype.clone = function(offset) {
+ offset = offset || 0; // Turn null into 0.
+ return new ThrowDescriptor(this.throwNum, this.time + offset,
+ this.sourceHand, this.destHand);
+};
+
+/**
+ * Convert the ThrowDescriptor to a string for debugging.
+ * @return {String} debugging output.
+ */
+ThrowDescriptor.prototype.toString = function() {
+ return '(' + this.throwNum + ' from hand ' + this.sourceHand + ' to hand ' +
+ this.destHand + ')';
+};
+
+/**
+ * Generate the Curve implied by this descriptor and the supplied hand
+ * positions.
+ * @param {!Array.HandPositionRecord} handPositions where the hands will be.
+ * @return {!Curve} the curve.
+ */
+ThrowDescriptor.prototype.generateCurve = function(handPositions) {
+ var startPos = handPositions[this.sourceHand].throwPositions[this.destHand];
+ var endPos = handPositions[this.destHand].catchPosition;
+ return Curve.computeThrowCurve(startPos, endPos, this.time,
+ this.throwNum - 1); };
+
+/**
+ * This describes a catch in a site-swap pattern.
+ * @param {!number} hand the index of the catching hand.
+ * @param {!number} sourceThrowNum the site-swap number of the preceeding throw.
+ * @param {!number} destThrowNum the site-swap number of the following throw.
+ * @param {!number} sourceHand the index of the hand throwing the source throw.
+ * @param {!number} destHand the index of the hand catching the following throw.
+ * @param {!number} catchTime the time at which the catch occurs.
+ * @constructor
+ */
+CarryDescriptor = function(hand, sourceThrowNum, destThrowNum, sourceHand,
+ destHand, catchTime) {
+ this.hand = hand;
+ this.sourceThrowNum = sourceThrowNum;
+ this.destThrowNum = destThrowNum;
+ this.sourceHand = sourceHand;
+ this.destHand = destHand;
+ this.time = catchTime;
+}
+
+/**
+ * This is a subclass of Descriptor.
+ */
+CarryDescriptor.prototype = new Descriptor();
+
+/**
+ * Set up the constructor, just to be neat.
+ */
+CarryDescriptor.prototype.constructor = CarryDescriptor;
+
+/**
+ * We label each Descriptor subclass with a type for debugging.
+ */
+CarryDescriptor.prototype.type = 'CARRY';
+
+/**
+ * Since this gets pathLength, not patternLength, we'll have to collapse sets
+ * of CarryDescriptors later, as they may be spread sparsely through the full
+ * animation and we'll only want them to be distributed over the full pattern
+ * length. We may have dupes to throw away as well.
+ * @param {!ThrowDescriptor} inThrowDescriptor
+ * @param {!ThrowDescriptor} outThrowDescriptor
+ * @param {!number} pathLength
+ * @return {!CarryDescriptor}
+ */
+CarryDescriptor.fromThrowDescriptors = function(inThrowDescriptor,
+ outThrowDescriptor, pathLength) {
+ assert(inThrowDescriptor.destHand == outThrowDescriptor.sourceHand);
+ assert((inThrowDescriptor.time + inThrowDescriptor.throwNum) %
+ pathLength == outThrowDescriptor.time);
+ return new CarryDescriptor(inThrowDescriptor.destHand,
+ inThrowDescriptor.throwNum, outThrowDescriptor.throwNum,
+ inThrowDescriptor.sourceHand, outThrowDescriptor.destHand,
+ (outThrowDescriptor.time + pathLength - 1) % pathLength);
+};
+
+/**
+ * Create an otherwise-identical copy of this descriptor at a given time offset.
+ * Note that offset may put time past patternLength; the caller will have to fix
+ * this up manually.
+ * @param {number} offset how many beats to offset the new descriptor.
+ * @return {!Descriptor} the new copy.
+ */
+CarryDescriptor.prototype.clone = function(offset) {
+ offset = offset || 0; // Turn null into 0.
+ return new CarryDescriptor(this.hand, this.sourceThrowNum,
+ this.destThrowNum, this.sourceHand, this.destHand, this.time + offset);
+};
+
+/**
+ * Convert the CarryDescriptor to a string for debugging.
+ * @return {String} debugging output.
+ */
+CarryDescriptor.prototype.toString = function() {
+ return 'time: ' + this.time + ' (hand ' + this.hand + ' catches ' +
+ this.sourceThrowNum + ' from hand ' + this.sourceHand + ' then throws ' +
+ this.destThrowNum + ' to hand ' + this.destHand + ')';
+};
+
+/**
+ * Test if this CarryDescriptor is equivalent to another, mod patternLength.
+ * @param {!CarryDescriptor} cd the other CarryDescriptor.
+ * @param {!number} patternLength the length of the pattern.
+ * @return {!bool}
+ */
+CarryDescriptor.prototype.equalsWithMod = function(cd, patternLength) {
+ if (!(cd instanceof CarryDescriptor)) {
+ return false;
+ }
+ if (this.hand != cd.hand) {
+ return false;
+ }
+ if (this.sourceThrowNum != cd.sourceThrowNum) {
+ return false;
+ }
+ if (this.destThrowNum != cd.destThrowNum) {
+ return false;
+ }
+ if (this.sourceHand != cd.sourceHand) {
+ return false;
+ }
+ if (this.destHand != cd.destHand) {
+ return false;
+ }
+ if (this.time % patternLength != cd.time % patternLength) {
+ return false;
+ }
+ return true;
+};
+
+/**
+ * Generate the Curve implied by this descriptor and the supplied hand
+ * positions.
+ * @param {!Array.HandPositionRecord} handPositions where the hands will be.
+ * @return {!Curve} the curve.
+ */
+CarryDescriptor.prototype.generateCurve = function(handPositions) {
+ var startPos = handPositions[this.hand].catchPosition;
+ var endPos = handPositions[this.hand].throwPositions[this.destHand];
+ return Curve.computeCircularCurve(startPos, endPos, this.time, 1);
+};
+
+/**
+ * This describes a carry of a "1" in a site-swap pattern.
+ * The flags isThrow and isCatch tell whether this is the actual 1 [isThrow] or
+ * the carry that receives the handoff [isCatch]. It's legal for both to be
+ * true, which happens when there are two 1s in a row.
+ * @param {!number} sourceThrowNum the site-swap number of the prev throw
+ * [including this one if isCatch].
+ * @param {!number} sourceHand the index of the hand throwing sourceThrowNum.
+ * @param {!number} destThrowNum the site-swap number of the next throw
+ * [including this one if isThrow].
+ * @param {!number} destHand the index of the hand catching destThrowNum.
+ * @param {!number} hand the index of the hand doing this carry.
+ * @param {!number} time the time at which the carry starts.
+ * @param {!bool} isThrow whether this is a 1.
+ * @param {!bool} isCatch whether this is the carry after a 1.
+ * @constructor
+ */
+CarryOneDescriptor = function(sourceThrowNum, sourceHand, destThrowNum,
+ destHand, hand, time, isThrow, isCatch) {
+ // It's possible to have !isCatch with sourceThrowNum == 1 temporarily, if we
+ // just haven't handled that 1 yet [we're doing the throw of this one, and
+ // will later get to the previous one, due to wraparound], and vice-versa.
+ assert(isThrow || (sourceThrowNum == 1));
+ assert(isCatch || (destThrowNum == 1));
+ this.sourceThrowNum = sourceThrowNum;
+ this.sourceHand = sourceHand;
+ this.destHand = destHand;
+ this.destThrowNum = destThrowNum;
+ this.hand = hand;
+ this.time = time;
+ this.isThrow = isThrow;
+ this.isCatch = isCatch;
+ return this;
+}
+
+/**
+ * This is a subclass of Descriptor.
+ */
+CarryOneDescriptor.prototype = new Descriptor();
+
+/**
+ * Set up the constructor, just to be neat.
+ */
+CarryOneDescriptor.prototype.constructor = CarryOneDescriptor;
+
+/**
+ * We label each Descriptor subclass with a type for debugging.
+ */
+CarryOneDescriptor.prototype.type = 'CARRY_ONE';
+
+/**
+ * Create a pair of CarryOneDescriptors to describe the carry that is a throw of
+ * 1. A 1 spends all its time being carried, so these two carries surrounding
+ * it represent [and therefore don't have] a throw between them.
+ * Prev and post are generally the ordinary CarryDescriptors surrounding the
+ * throw of 1 that we're trying to implement. However, they could each [or
+ * both] independently be CarryOneDescriptors implementing other 1 throws.
+ * @param {!Descriptor} prev the carry descriptor previous to the 1.
+ * @param {!Descriptor} post the carry descriptor subsequent to the 1.
+ * @return {!Array.CarryOneDescriptor} a pair of CarryOneDescriptors.
+ */
+CarryOneDescriptor.getDescriptorPair = function(prev, post) {
+ assert(prev instanceof CarryDescriptor || prev instanceof CarryOneDescriptor);
+ assert(post instanceof CarryDescriptor || post instanceof CarryOneDescriptor);
+ assert(prev.destHand == post.hand);
+ assert(prev.hand == post.sourceHand);
+ var newPrev;
+ var newPost;
+ if (prev instanceof CarryOneDescriptor) {
+ assert(prev.isCatch && !prev.isThrow);
+ newPrev = prev;
+ newPrev.isThrow = true;
+ assert(newPrev.destHand == post.hand);
+ } else {
+ newPrev = new CarryOneDescriptor(prev.sourceThrowNum, prev.sourceHand, 1,
+ post.hand, prev.hand, prev.time, true, false);
+ }
+ if (post instanceof CarryOneDescriptor) {
+ assert(post.isThrow && !post.isCatch);
+ newPost = post;
+ newPost.isCatch = true;
+ assert(newPost.sourceHand == prev.hand);
+ assert(newPost.sourceThrowNum == 1);
+ } else {
+ newPost = new CarryOneDescriptor(1, prev.hand, post.destThrowNum,
+ post.destHand, post.hand, post.time, false, true);
+ }
+ return [newPrev, newPost];
+};
+
+/**
+ * Convert the CarryOneDescriptor to a string for debugging.
+ * @return {String} debugging output.
+ */
+CarryOneDescriptor.prototype.toString = function() {
+ var s;
+ if (this.isThrow) {
+ s = 'Hand ' + this.hand + ' catches a ' + this.sourceThrowNum + ' from ' +
+ this.sourceHand + ' at time ' + this.time + ' and then passes a 1 to ' +
+ this.destHand + '.';
+ } else {
+ assert(this.isCatch && this.sourceThrowNum == 1);
+ s = 'Hand ' + this.hand + ' catches a 1 from ' + this.sourceHand +
+ ' at time ' + this.time + ' and then passes a ' + this.destThrowNum +
+ ' to ' + this.destHand + '.';
+ }
+ return s;
+};
+
+/**
+ * Compute the curve taken by a ball during the carry representing a 1, as long
+ * as it's not both a catch and a throw of a 1, which is handled elsewhere.
+ * It's either a LERP from a circular curve [a catch of a throw > 1] to a
+ * straight line to the handoff point [for isThrow] or a LERP from a straight
+ * line from the handoff to a circular curve for the next throw > 1 [for
+ * isCatch].
+ *
+ * @param {!EquationCoefficients} catchPos
+ * @param {!EquationCoefficients} throwPos
+ * @param {!EquationCoefficients} handoffPos
+ * @param {!number} startTime
+ * @param {!bool} isCatch whether this is the carry after a 1.
+ * @param {!bool} isThrow whether this is a 1.
+ * @return {!Curve}
+ */
+Curve.computeCarryOneCurve = function(catchPos, throwPos, handoffPos, startTime,
+ isCatch, isThrow) {
+ assert(!isCatch != !isThrow);
+ var curve = Curve.computeCircularCurve(catchPos, throwPos, startTime, 1);
+ var curve2 = Curve.computeStraightLineCurve(handoffPos, handoffPos,
+ startTime, 1);
+ return curve.lerpIn(curve2, isThrow ? 1 : -1);
+}
+
+/**
+ * Compute the curve taken by a ball during the carry representing a 1 that is
+ * both the catch of one 1 and the immediately-following throw of another 1.
+ *
+ * @param {!EquationCoefficients} leadingHandoffPos
+ * @param {!EquationCoefficients} trailingHandoffPos
+ * @param {!Array.HandPositionRecord} handPositions where the hands will be.
+ * @param {!number} hand
+ * @param {!number} time the time at which the first 1's catch takes place.
+ * @return {!Curve}
+ */
+Curve.computeConsecutiveCarryOneCurve = function(leadingHandoffPos,
+ trailingHandoffPos, handPositions, hand, time) {
+ var curve = Curve.computeStraightLineCurve(leadingHandoffPos,
+ handPositions[hand].basePosition, time, 1);
+ var curve2 =
+ Curve.computeStraightLineCurve(handPositions[hand].basePosition,
+ trailingHandoffPos, time, 1);
+ return curve.lerpIn(curve2, 1);
+}
+
+/**
+ * Generate the Curve implied by this descriptor and the supplied hand
+ * positions.
+ * @param {!Array.HandPositionRecord} handPositions where the hands will be.
+ * @return {!Curve} the curve.
+ */
+CarryOneDescriptor.prototype.generateCurve = function(handPositions) {
+ var leadingHandoffPos, trailingHandoffPos;
+ if (this.isCatch) {
+ var p0 = handPositions[this.hand].basePosition;
+ var p1 = handPositions[this.sourceHand].basePosition;
+ handoffPos = leadingHandoffPos = p0.add(p1).scale(0.5);
+ }
+ if (this.isThrow) {
+ var p0 = handPositions[this.hand].basePosition;
+ var p1 = handPositions[this.destHand].basePosition;
+ handoffPos = trailingHandoffPos = p0.add(p1).scale(0.5);
+ }
+ if (!this.isCatch || !this.isThrow) {
+ return Curve.computeCarryOneCurve(handPositions[this.hand].catchPosition,
+ handPositions[this.hand].throwPositions[this.destHand], handoffPos,
+ this.time, this.isCatch, this.isThrow);
+ } else {
+ return Curve.computeConsecutiveCarryOneCurve(leadingHandoffPos,
+ trailingHandoffPos, handPositions, this.hand, this.time);
+ }
+};
+
+/**
+ * Create an otherwise-identical copy of this descriptor at a given time offset.
+ * Note that offset may put time past patternLength; the caller will have to fix
+ * this up manually.
+ * @param {number} offset how many beats to offset the new descriptor.
+ * @return {!Descriptor} the new copy.
+ */
+CarryOneDescriptor.prototype.clone = function(offset) {
+ offset = offset || 0; // Turn null into 0.
+ return new CarryOneDescriptor(this.sourceThrowNum, this.sourceHand,
+ this.destThrowNum, this.destHand, this.hand, this.time + offset,
+ this.isThrow, this.isCatch);
+};
+
+/**
+ * Test if this CarryOneDescriptor is equivalent to another, mod patternLength.
+ * @param {!CarryOneDescriptor} cd the other CarryOneDescriptor.
+ * @param {!number} patternLength the length of the pattern.
+ * @return {!bool}
+ */
+CarryOneDescriptor.prototype.equalsWithMod = function(cd, patternLength) {
+ if (!(cd instanceof CarryOneDescriptor)) {
+ return false;
+ }
+ if (this.hand != cd.hand) {
+ return false;
+ }
+ if (this.sourceThrowNum != cd.sourceThrowNum) {
+ return false;
+ }
+ if (this.destThrowNum != cd.destThrowNum) {
+ return false;
+ }
+ if (this.sourceHand != cd.sourceHand) {
+ return false;
+ }
+ if (this.destHand != cd.destHand) {
+ return false;
+ }
+ if (this.isCatch != cd.isCatch) {
+ return false;
+ }
+ if (this.isThrow != cd.isThrow) {
+ return false;
+ }
+ if (this.time % patternLength != cd.time % patternLength) {
+ return false;
+ }
+ return true;
+};
+
+/**
+ * This describes an empty hand in a site-swap pattern.
+ * @param {!Descriptor} cd0 the CarryDescriptor or CarryOneDescriptor describing
+ * this hand immediately before it was emptied.
+ * @param {!Descriptor} cd1 the CarryDescriptor or CarryOneDescriptor describing
+ * this hand immediately after it's done being empty.
+ * @param {!number} patternLength the length of the pattern.
+ * @constructor
+ */
+EmptyHandDescriptor = function(cd0, cd1, patternLength) {
+ assert(cd0.hand == cd1.hand);
+ this.hand = cd0.hand;
+ this.prevThrowDest = cd0.destHand;
+ this.sourceThrowNum = cd0.destThrowNum;
+ this.nextCatchSource = cd1.sourceHand;
+ this.destThrowNum = cd1.sourceThrowNum;
+ // This code assumes that each CarryDescriptor and CarryOneDescriptor always
+ // has a duration of 1 beat. If we want to be able to allow long-held balls
+ // [instead of thrown twos, for example], we'll have to fix that here and a
+ // number of other places.
+ this.time = (cd0.time + 1) % patternLength;
+ this.duration = cd1.time - this.time;
+ if (this.duration < 0) {
+ this.duration += patternLength;
+ assert(this.duration > 0);
+ }
+}
+
+/**
+ * This is a subclass of Descriptor.
+ */
+EmptyHandDescriptor.prototype = new Descriptor();
+
+/**
+ * Set up the constructor, just to be neat.
+ */
+EmptyHandDescriptor.prototype.constructor = EmptyHandDescriptor;
+
+/**
+ * We label each Descriptor subclass with a type for debugging.
+ */
+EmptyHandDescriptor.prototype.type = 'EMPTY';
+
+/**
+ * Convert the EmptyHandDescriptor to a string for debugging.
+ * @return {String} debugging output.
+ */
+EmptyHandDescriptor.prototype.toString = function() {
+ return 'time: ' + this.time + ' for ' + this.duration + ' (hand ' +
+ this.hand + ', after throwing a ' + this.sourceThrowNum + ' to hand ' +
+ this.prevThrowDest + ' then catches a ' + this.destThrowNum +
+ ' from hand ' + this.nextCatchSource + ')';
+};
+
+/**
+ * Generate the Curve implied by this descriptor and the supplied hand
+ * positions.
+ * @param {!Array.HandPositionRecord} handPositions where the hands will be.
+ * @return {!Curve} the curve.
+ */
+EmptyHandDescriptor.prototype.generateCurve = function(handPositions) {
+ var startPos, endPos;
+ if (this.sourceThrowNum == 1) {
+ var p0 = handPositions[this.hand].basePosition;
+ var p1 = handPositions[this.prevThrowDest].basePosition;
+ startPos = p0.add(p1).scale(0.5);
+ } else {
+ startPos = handPositions[this.hand].throwPositions[this.prevThrowDest];
+ }
+ if (this.destThrowNum == 1) {
+ var p0 = handPositions[this.hand].basePosition;
+ var p1 = handPositions[this.nextCatchSource].basePosition;
+ endPos = p0.add(p1).scale(0.5);
+ } else {
+ endPos = handPositions[this.hand].catchPosition;
+ }
+ // TODO: Replace with a good empty-hand curve.
+ return Curve.computeStraightLineCurve(startPos, endPos, this.time,
+ this.duration);
+};
+
+/**
+ * A series of descriptors that describes the full path of an object during a
+ * pattern.
+ * @param {!Array.Descriptor} descriptors all descriptors for the object.
+ * @param {!number} pathLength the length of the path in beats.
+ * @constructor
+ */
+Path = function(descriptors, pathLength) {
+ this.descriptors = descriptors;
+ this.pathLength = pathLength;
+}
+
+/**
+ * Create a Path representing a ball, filling in the gaps between the throws
+ * with carry descriptors. Since it's a ball's path, there are no
+ * EmptyHandDescriptors in the output.
+ * @param {!Array.ThrowDescriptor} throwDescriptors the ball's part of the
+ * pattern.
+ * @param {!number} pathLength the length of the pattern in beats.
+ * @return {!Path} the ball's full path.
+ */
+Path.ballPathFromThrowDescriptors = function(throwDescriptors, pathLength) {
+ return new Path(
+ Path.createDescriptorList(throwDescriptors, pathLength), pathLength);
+};
+
+/**
+ * Create the sequence of ThrowDescriptors, CarryDescriptors, and
+ * CarryOneDescriptor describing the path of a ball through a pattern.
+ * A sequence such as (h j k) generally maps to an alternating series of throw
+ * and carry descriptors [Th Chj Tj Cjk Tk Ck? ...]. However, when j is a 1,
+ * you remove the throw descriptor and modify the previous and subsequent carry
+ * descriptors, since the throw descriptor has zero duration and the carry
+ * descriptors need to take into account the handoff.
+ * @param {!Array.ThrowDescriptor} throwDescriptors the ball's part of the
+ * pattern.
+ * @param {!number} pathLength the length of the pattern in beats.
+ * @return {!Array.Descriptor} the full set of descriptors for the ball.
+ */
+Path.createDescriptorList = function(throwDescriptors, pathLength) {
+ var descriptors = [];
+ var prevThrow;
+ for (var index in throwDescriptors) {
+ var td = throwDescriptors[index];
+ if (prevThrow) {
+ descriptors.push(
+ CarryDescriptor.fromThrowDescriptors(prevThrow, td, pathLength));
+ } // Else it's handled after the loop.
+ descriptors.push(td);
+ prevThrow = td;
+ }
+ descriptors.push(
+ CarryDescriptor.fromThrowDescriptors(prevThrow, throwDescriptors[0],
+ pathLength));
+ // Now post-process to take care of throws of 1. It's easier to do it here
+ // than during construction since we can now assume that the previous and
+ // subsequent carry descriptors are already in place [modulo pathLength].
+ for (var i = 0; i < descriptors.length; ++i) {
+ var descriptor = descriptors[i];
+ if (descriptor instanceof ThrowDescriptor) {
+ if (descriptor.throwNum == 1) {
+ var prevIndex = (i + descriptors.length - 1) % descriptors.length;
+ var postIndex = (i + 1) % descriptors.length;
+ var replacements = CarryOneDescriptor.getDescriptorPair(
+ descriptors[prevIndex], descriptors[postIndex]);
+ descriptors[prevIndex] = replacements[0];
+ descriptors[postIndex] = replacements[1];
+ descriptors.splice(i, 1);
+ // We've removed a descriptor from the array, but since we can never
+ // have 2 ThrowDescriptors in a row, we don't need to decrement i.
+ }
+ }
+ }
+ return descriptors;
+};
+
+/**
+ * Convert the Path to a string for debugging.
+ * @return {String} debugging output.
+ */
+Path.prototype.toString = function() {
+ var ret = 'pathLength is ' + this.pathLength + '; [';
+ for (var index in this.descriptors) {
+ ret += this.descriptors[index].toString();
+ }
+ ret += ']';
+ return ret;
+};
+
+/**
+ * Create an otherwise-identical copy of this path at a given time offset.
+ * Note that offset may put time references in the Path past the length of the
+ * pattern. The caller must fix this up manually.
+ * @param {number} offset how many beats to offset the new Path.
+ * @return {!Path} the new copy.
+ */
+Path.prototype.clone = function(offset) {
+ offset = offset || 0; // Turn null into 0.
+ var descriptors = [];
+ for (var index in this.descriptors) {
+ descriptors.push(this.descriptors[index].clone(offset));
+ }
+ return new Path(descriptors, this.pathLength);
+};
+
+/**
+ * Adjust the start time of all descriptors to be in [0, pathLength) via modular
+ * arithmetic. Reorder the array such that they're sorted in increasing order
+ * of time.
+ * @return {!Path} this.
+ */
+Path.prototype.fixUpModPathLength = function() {
+ var splitIndex;
+ var prevTime = 0;
+ for (var index in this.descriptors) {
+ var d = this.descriptors[index];
+ d.fixUpModPathLength(this.pathLength);
+ if (d.time < prevTime) {
+ assert(null == splitIndex);
+ splitIndex = index; // From here to the end should move to the start.
+ }
+ prevTime = d.time;
+ }
+ if (null != splitIndex) {
+ var temp = this.descriptors.slice(splitIndex);
+ this.descriptors.length = splitIndex;
+ this.descriptors = temp.concat(this.descriptors);
+ }
+ return this;
+};
+
+/**
+ * Take a standard asynch siteswap pattern [expressed as an array of ints] and
+ * a number of hands, and expand it into a 2D grid of ThrowDescriptors with one
+ * row per hand.
+ * Non-asynch patterns are more complicated, since their linear forms aren't
+ * fully-specified, so we don't handle them here.
+ * You'll want to expand your pattern to the LCM of numHands and minimal pattern
+ * length before calling this.
+ * The basic approach doesn't really work for one-handed patterns. It ends up
+ * with catches and throws happening at the same time [having removed all
+ * empty-hand time in between them]. To fix this, we double all throw heights
+ * and space them out, as if doing a two-handed pattern with all zeroes from the
+ * other hand. Yes, this points out that the overall approach we're taking is a
+ * bit odd [since you end up with hands empty for time proportional to the
+ * number of hands], but you have to make some sort of assumptions to generalize
+ * siteswaps to N hands, and that's what I chose.
+ * @param {!Array.number} pattern an asynch siteswap pattern.
+ * @param {!number} numHands the number of hands.
+ * @return {!Array.Array.ThrowDescriptor} the expanded pattern.
+ */
+function expandPattern(pattern, numHands) {
+ var fullPattern = [];
+ assert(numHands > 0);
+ if (numHands == 1) {
+ numHands = 2;
+ var temp = [];
+ for (var i = 0; i < pattern.length; ++i) {
+ temp[2 * i] = 2 * pattern[i];
+ temp[2 * i + 1] = 0;
+ }
+ pattern = temp;
+ }
+ for (var hand = 0; hand < numHands; ++hand) {
+ fullPattern[hand] = [];
+ }
+ for (var time = 0; time < pattern.length; ++time) {
+ for (var hand = 0; hand < numHands; ++hand) {
+ var t;
+ if (hand == time % numHands) {
+ t = new ThrowDescriptor(pattern[time], time, hand,
+ (hand + pattern[time]) % numHands);
+ } else {
+ // These are ignored during analysis, so they don't appear in BallPaths.
+ t = new ThrowDescriptor(0, time, hand, hand);
+ }
+ fullPattern[hand].push(t);
+ }
+ }
+ return fullPattern;
+}
+
+// TODO: Wrap the final pattern in a class, then make the remaining few global
+// functions be members of that class to clean up the global namespace.
+
+/**
+ * Given a valid site-swap for a nonzero number of balls, stored as an expanded
+ * pattern array-of-arrays, with pattern length the LCM of hands and minimal
+ * pattern length, produce Paths for all the balls.
+ * @param {!Array.Array.ThrowDescriptor} pattern a valid pattern.
+ * @return {!Array.Path} the paths of all the balls.
+ */
+function generateBallPaths(pattern) {
+ var numHands = pattern.length;
+ assert(numHands > 0);
+ var patternLength = pattern[0].length;
+ assert(patternLength > 0);
+ var sum = 0;
+ for (var hand in pattern) {
+ for (var time in pattern[hand]) {
+ sum += pattern[hand][time].throwNum;
+ }
+ }
+ var numBalls = sum / patternLength;
+ assert(numBalls == Math.round(numBalls));
+ assert(numBalls > 0);
+
+ var ballsToAllocate = numBalls;
+ var ballPaths = [];
+ // NOTE: The indices of locationsChecked are reversed from those of pattern
+ // for simplicity of allocation. This might be worth flipping to match.
+ var locationsChecked = [];
+ for (var time = 0; time < patternLength && ballsToAllocate; ++time) {
+ locationsChecked[time] = locationsChecked[time] || [];
+ for (var hand = 0; hand < numHands && ballsToAllocate; ++hand) {
+ if (locationsChecked[time][hand]) {
+ continue;
+ }
+ var curThrowDesc = pattern[hand][time];
+ var curThrow = curThrowDesc.throwNum;
+ if (!curThrow) {
+ assert(curThrow === 0);
+ continue;
+ }
+ var throwDescriptors = [];
+ var curTime = time;
+ var curHand = hand;
+ var wraps = 0;
+ do {
+ if (!locationsChecked[curTime]) {
+ locationsChecked[curTime] = [];
+ }
+ assert(!locationsChecked[curTime][curHand]);
+ locationsChecked[curTime][curHand] = true;
+ // We copy curThrowDesc here, adding wraps * patternLength, to get
+ // the true throw time relative to offset. Later we'll add in offset
+ // when we clone again, then mod by pathLength.
+ throwDescriptors.push(curThrowDesc.clone(wraps * patternLength));
+ var nextThrowTime = curThrow + curTime;
+ wraps += Math.floor(nextThrowTime / patternLength);
+ curTime = nextThrowTime % patternLength;
+ assert(curTime >= time); // Else we'd have covered it earlier.
+ curHand = curThrowDesc.destHand;
+ var tempThrowDesc = curThrowDesc;
+ curThrowDesc = pattern[curHand][curTime];
+ curThrow = curThrowDesc.throwNum;
+ assert(tempThrowDesc.destHand == curThrowDesc.sourceHand);
+ assert(curThrowDesc.time ==
+ (tempThrowDesc.throwNum + tempThrowDesc.time) % patternLength);
+ } while (curTime != time || curHand != hand);
+ var pathLength = wraps * patternLength;
+ var ballPath =
+ Path.ballPathFromThrowDescriptors(throwDescriptors, pathLength);
+ for (var i = 0; i < wraps; ++i) {
+ var offset = i * patternLength % pathLength;
+ ballPaths.push(ballPath.clone(offset, pathLength).fixUpModPathLength());
+ }
+ ballsToAllocate -= wraps;
+ assert(ballsToAllocate >= 0);
+ }
+ }
+ return ballPaths;
+}
+
+/**
+ * Given an array of ball paths, produce the corresponding set of hand paths.
+ * @param {!Array.Path} ballPaths the Paths of all the balls in the pattern.
+ * @param {!number} numHands how many hands to use in the pattern.
+ * @param {!number} patternLength the length, in beats, of the pattern.
+ * @return {!Array.Path} the paths of all the hands.
+ */
+function generateHandPaths(ballPaths, numHands, patternLength) {
+ assert(numHands > 0);
+ assert(patternLength > 0);
+ var handRecords = []; // One record per hand.
+ for (var idxBR in ballPaths) {
+ var descriptors = ballPaths[idxBR].descriptors;
+ for (var idxD in descriptors) {
+ var descriptor = descriptors[idxD];
+ // TODO: Fix likely needed for throws of 1.
+ if (!(descriptor instanceof ThrowDescriptor)) {
+ // It's a CarryDescriptor or a CarryOneDescriptor.
+ var hand = descriptor.hand;
+ if (!handRecords[hand]) {
+ handRecords[hand] = [];
+ }
+ // TODO: Should we not shorten stuff here if we're going to lengthen
+ // everything later anyway? Is there a risk of inconsistency due to
+ // ball paths of different lengths?
+ var catchTime = descriptor.time % patternLength;
+ if (!handRecords[hand][catchTime]) {
+ // We pass in this offset to set the new descriptor's time to
+ // catchTime, so as to keep it within [0, patternLength).
+ handRecords[hand][catchTime] =
+ descriptor.clone(catchTime - descriptor.time);
+ } else {
+ assert(
+ handRecords[hand][catchTime].equalsWithMod(
+ descriptor, patternLength));
+ }
+ }
+ }
+ }
+ var handPaths = [];
+ for (var hand in handRecords) {
+ var outDescriptors = [];
+ var inDescriptors = handRecords[hand];
+ var prevDescriptor = null;
+ var descriptor;
+ for (var idxD in inDescriptors) {
+ descriptor = inDescriptors[idxD];
+ assert(descriptor); // Enumeration should skip array holes.
+ assert(descriptor.hand == hand);
+ if (prevDescriptor) {
+ outDescriptors.push(new EmptyHandDescriptor(prevDescriptor, descriptor,
+ patternLength));
+ }
+ outDescriptors.push(descriptor.clone());
+ prevDescriptor = descriptor;
+ }
+ // Note that this EmptyHandDescriptor that wraps around the end lives at the
+ // end of the array, not the beginning, despite the fact that it may be the
+ // active one at time zero. This is the same behavior as with Paths for
+ // balls.
+ descriptor = new EmptyHandDescriptor(prevDescriptor, outDescriptors[0],
+ patternLength);
+ if (descriptor.time < outDescriptors[0].time) {
+ assert(descriptor.time + descriptor.duration == outDescriptors[0].time);
+ outDescriptors.unshift(descriptor);
+ } else {
+ assert(descriptor.time ==
+ outDescriptors[outDescriptors.length - 1].time + 1);
+ outDescriptors.push(descriptor);
+ }
+ handPaths[hand] =
+ new Path(outDescriptors, patternLength).fixUpModPathLength();
+ }
+ return handPaths;
+}
+
+// NOTE: All this Vector stuff does lots of object allocations. If that's a
+// problem for your browser [e.g. IE6], you'd better stick with the embedded V8.
+// This code predates the creation of o3djs/math.js; I should probably switch it
+// over at some point, but for now it's not worth the trouble.
+
+/**
+ * A simple 3-dimensional vector.
+ * @constructor
+ */
+Vector = function(x, y, z) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+}
+
+Vector.prototype.sub = function(v) {
+ return new Vector(this.x - v.x, this.y - v.y, this.z - v.z);
+};
+
+Vector.prototype.add = function(v) {
+ return new Vector(this.x + v.x, this.y + v.y, this.z + v.z);
+};
+
+Vector.prototype.dot = function(v) {
+ return this.x * v.x + this.y * v.y + this.z * v.z;
+};
+
+Vector.prototype.length = function() {
+ return Math.sqrt(this.dot(this));
+};
+
+Vector.prototype.scale = function(s) {
+ return new Vector(this.x * s, this.y * s, this.z * s);
+};
+
+Vector.prototype.set = function(v) {
+ this.x = v.x;
+ this.y = v.y;
+ this.z = v.z;
+};
+
+Vector.prototype.normalize = function() {
+ var length = this.length();
+ assert(length);
+ this.set(this.scale(1 / length));
+ return this;
+};
+
+/**
+ * Convert the Vector to a string for debugging.
+ * @return {String} debugging output.
+ */
+Vector.prototype.toString = function() {
+ return '{' + this.x.toFixed(3) + ', ' + this.y.toFixed(3) + ', ' +
+ this.z.toFixed(3) + '}';
+};
+
+/**
+ * A container class that holds the positions relevant to a hand: where it is
+ * when it's not doing anything, where it likes to catch balls, and where it
+ * likes to throw balls to each of the other hands.
+ * @param {!Vector} basePosition the centroid of throw and catch positions when
+ * the hand throws to itself.
+ * @param {!Vector} catchPosition where the hand likes to catch balls.
+ * @constructor
+ */
+HandPositionRecord = function(basePosition, catchPosition) {
+ this.basePosition = basePosition;
+ this.catchPosition = catchPosition;
+ this.throwPositions = [];
+}
+
+/**
+ * Convert the HandPositionRecord to a string for debugging.
+ * @return {String} debugging output.
+ */
+HandPositionRecord.prototype.toString = function() {
+ var s = 'base: ' + this.basePosition.toString() + ';\n';
+ s += 'catch: ' + this.catchPosition.toString() + ';\n';
+ s += 'throws:\n';
+ for (var i = 0; i < this.throwPositions.length; ++i) {
+ s += '[' + i + '] ' + this.throwPositions[i].toString() + '\n';
+ }
+ return s;
+};
+
+/**
+ * Compute all the hand positions used in a pattern given a number of hands and
+ * a grouping style ["even" for evenly-spaced hands, "pairs" to group them in
+ * pairs, as with 2-handed jugglers].
+ * @param {!number} numHands the number of hands to use.
+ * @param {!String} style the grouping style.
+ * @return {!Array.HandPositionRecord} a full set of hand positions.
+ */
+function computeHandPositions(numHands, style) {
+ assert(numHands > 0);
+ var majorRadiusScale = 0.75;
+ var majorRadius = majorRadiusScale * (numHands - 1);
+ var throwCatchOffset = 0.45;
+ var catchRadius = majorRadius + throwCatchOffset;
+ var handPositionRecords = [];
+ for (var hand = 0; hand < numHands; ++hand) {
+ var circleFraction;
+ if (style == 'even') {
+ circleFraction = hand / numHands;
+ } else {
+ assert(style == 'pairs');
+ circleFraction = (hand + Math.floor(hand / 2)) / (1.5 * numHands);
+ }
+ var cos = Math.cos(Math.PI * 2 * circleFraction);
+ var sin = Math.sin(Math.PI * 2 * circleFraction);
+ var cX = catchRadius * cos;
+ var cY = 0;
+ var cZ = catchRadius * sin;
+ var bX = majorRadius * cos;
+ var bY = 0;
+ var bZ = majorRadius * sin;
+ handPositionRecords[hand] = new HandPositionRecord(
+ new Vector(bX, bY, bZ), new Vector(cX, cY, cZ));
+ }
+ // Now that we've got all the hands' base and catch positions, we need to
+ // compute the appropriate throw positions for each hand pair.
+ for (var source = 0; source < numHands; ++source) {
+ var throwHand = handPositionRecords[source];
+ for (var target = 0; target < numHands; ++target) {
+ var catchHand = handPositionRecords[target];
+ if (throwHand == catchHand) {
+ var baseV = throwHand.basePosition;
+ throwHand.throwPositions[target] =
+ baseV.add(baseV.sub(throwHand.catchPosition));
+ } else {
+ var directionV =
+ catchHand.catchPosition.sub(throwHand.basePosition).normalize();
+ var offsetV = directionV.scale(throwCatchOffset);
+ throwHand.throwPositions[target] =
+ throwHand.basePosition.add(offsetV);
+ }
+ }
+ }
+ return handPositionRecords;
+}
+
+/**
+ * Convert an array of HandPositionRecord to a string for debugging.
+ * @param {!Array.HandPositionRecord} positions the positions to display.
+ * @return {String} debugging output.
+ */
+function getStringFromHandPositions(positions) {
+ var s = '';
+ for (index in positions) {
+ s += positions[index].toString();
+ }
+ return s;
+}
+
+/**
+ * The set of curves an object passes through throughout a full animation cycle.
+ * @param {!number} duration the length of the animation in beats.
+ * @param {!Array.Curve} curves the full set of Curves.
+ * @constructor
+ */
+CurveSet = function(duration, curves) {
+ this.duration = duration;
+ this.curves = curves;
+}
+
+/**
+ * Looks up what curve is active at a particular time. This is slower than
+ * getCurveForTime, but can be used even if no Curve starts precisely at
+ * unsafeTime % this.duration.
+ * @param {!number} unsafeTime the time at which to check.
+ * @return {!Curve} the curve active at unsafeTime.
+ */
+CurveSet.prototype.getCurveForUnsafeTime = function(unsafeTime) {
+ unsafeTime %= this.duration;
+ time = Math.floor(unsafeTime);
+ if (this.curves[time]) {
+ return this.curves[time];
+ }
+ var curve;
+ for (var i = time; i >= 0; --i) {
+ curve = this.curves[i];
+ if (curve) {
+ assert(i + curve.duration >= unsafeTime);
+ return curve;
+ }
+ }
+ // We must want the last one. There's always a last one, given how we
+ // construct the CurveSets; they're sparse, but the length gets set by adding
+ // elements at the end.
+ curve = this.curves[this.curves.length - 1];
+ unsafeTime += this.duration;
+ assert(curve.startTime <= unsafeTime);
+ assert(curve.startTime + curve.duration > unsafeTime);
+ return curve;
+};
+
+/**
+ * Looks up what curve is active at a particular time. This is faster than
+ * getCurveForUnsafeTime, but can only be used if if a Curve starts precisely at
+ * unsafeTime % this.duration.
+ * @param {!number} time the time at which to check.
+ * @return {!Curve} the curve starting at time.
+ */
+CurveSet.prototype.getCurveForTime = function(time) {
+ return this.curves[time % this.duration];
+};
+
+/**
+ * Convert the CurveSet to a string for debugging.
+ * @return {String} debugging output.
+ */
+CurveSet.prototype.toString = function() {
+ var s = 'Duration: ' + this.duration + '\n';
+ for (var c in this.curves) {
+ s += this.curves[c].toString();
+ }
+ return s;
+};
+
+/**
+ * Namespace object to hold the pure math functions.
+ * TODO: Consider just rolling these into the Pattern object, when it gets
+ * created.
+ */
+var JugglingMath = {};
+
+/**
+ * Computes the greatest common devisor of integers a and b.
+ * @param {!number} a an integer.
+ * @param {!number} b an integer.
+ * @return {!number} the GCD of a and b.
+ */
+JugglingMath.computeGCD = function(a, b) {
+ assert(Math.round(a) == a);
+ assert(Math.round(b) == b);
+ assert(a >= 0);
+ assert(b >= 0);
+ if (!b) {
+ return a;
+ } else {
+ return JugglingMath.computeGCD(b, a % b);
+ }
+}
+
+/**
+ * Computes the least common multiple of integers a and b, by making use of the
+ * fact that LCM(a, b) * GCD(a, b) == a * b.
+ * @param {!number} a an integer.
+ * @param {!number} b an integer.
+ * @return {!number} the LCM of a and b.
+ */
+JugglingMath.computeLCM = function(a, b) {
+ assert(Math.round(a) == a);
+ assert(Math.round(b) == b);
+ assert(a >= 0);
+ assert(b >= 0);
+ var ret = a * b / JugglingMath.computeGCD(a, b);
+ assert(Math.round(ret) == ret);
+ return ret;
+}
+
+/**
+ * Given a Path and a set of hand positions, compute the corresponding set of
+ * Curves.
+ * @param {!Path} path the path of an object.
+ * @param {!Array.HandPositionRecord} handPositions the positions of the hands
+ * juggling the pattern containing the path.
+ * @return {!CurveSet} the full set of curves.
+ */
+CurveSet.getCurveSetFromPath = function(path, handPositions) {
+ var curves = [];
+ var pathLength = path.pathLength;
+ for (var index in path.descriptors) {
+ var descriptor = path.descriptors[index];
+ var curve = descriptor.generateCurve(handPositions);
+ assert(!curves[curve.startTime]);
+ assert(curve.startTime < pathLength);
+ curves[curve.startTime] = curve;
+ }
+ return new CurveSet(pathLength, curves);
+}
+
+/**
+ * Given a set of Paths and a set of hand positions, compute the corresponding
+ * CurveSets.
+ * @param {!Array.Path} paths the paths of a number of objects.
+ * @param {!Array.HandPositionRecord} handPositions the positions of the hands
+ * juggling the pattern containing the paths.
+ * @return {!Array.CurveSet} the CurveSets.
+ */
+CurveSet.getCurveSetsFromPaths = function(paths, handPositions) {
+ var curveSets = [];
+ for (var index in paths) {
+ var path = paths[index];
+ curveSets[index] = CurveSet.getCurveSetFromPath(path, handPositions);
+ }
+ return curveSets;
+}
+
+/**
+ * This is a temporary top-level calculation function that converts a standard
+ * asynchronous siteswap, expressed as a string of digits, into a full
+ * ready-to-animate set of CurveSets. Later on we'll be using an interface that
+ * can create a richer set of patterns than those expressable in the traditional
+ * string-of-ints format.
+ * @param {!String} patternString the siteswap.
+ * @param {!number} numHands the number of hands to use for the pattern.
+ * @param {!String} style how to space the hands ["pairs" or "even"].
+ * @return {!Object} a fully-analyzed pattern as CurveSets and associated data.
+ */
+function computeFullPatternFromString(patternString, numHands, style) {
+ var patternAsStrings = patternString.split(/[ ,]+ */);
+ var patternSegment = [];
+ for (var index in patternAsStrings) {
+ if (patternAsStrings[index]) { // Beware extra whitespace at the ends.
+ patternSegment.push(parseInt(patternAsStrings[index]));
+ }
+ }
+ var pattern = [];
+ // Now expand the pattern out to the length of the LCM of pattern length and
+ // number of hands, so that each throw gets done in each of its incarnations.
+ var multiple = JugglingMath.computeLCM(patternSegment.length, numHands) /
+ patternSegment.length;
+ for (var i = 0; i < multiple; ++i) {
+ pattern = pattern.concat(patternSegment);
+ }
+
+ var fullPattern = expandPattern(pattern, numHands);
+ var patternLength = fullPattern[0].length;
+
+ var ballPaths = generateBallPaths(fullPattern);
+ var handPaths = generateHandPaths(ballPaths, numHands, patternLength);
+
+ var handPositions = computeHandPositions(numHands, style);
+ var ballCurveSets = CurveSet.getCurveSetsFromPaths(ballPaths, handPositions);
+ var handCurveSets = CurveSet.getCurveSetsFromPaths(handPaths, handPositions);
+
+ // Find the LCM of all the curveSet durations. This will be the length of the
+ // fully-expanded queue. We could expand to this before computing the
+ // CurveSets, but this way's probably just a little cheaper.
+ var lcmDuration = 1;
+ for (var i in ballCurveSets) {
+ var duration = ballCurveSets[i].duration;
+ if (duration > lcmDuration || lcmDuration % duration) {
+ lcmDuration = JugglingMath.computeLCM(lcmDuration, duration);
+ }
+ }
+ for (var i in handCurveSets) {
+ var duration = handCurveSets[i].duration;
+ if (duration > lcmDuration || lcmDuration % duration) {
+ lcmDuration = JugglingMath.computeLCM(lcmDuration, duration);
+ }
+ }
+ return {
+ numBalls: ballPaths.length,
+ numHands: handPaths.length,
+ duration: lcmDuration,
+ handCurveSets: handCurveSets,
+ ballCurveSets: ballCurveSets
+ }
+}
diff --git a/o3d/samples/siteswap/siteswap.html b/o3d/samples/siteswap/siteswap.html
index 15d7497..06656eb 100644
--- a/o3d/samples/siteswap/siteswap.html
+++ b/o3d/samples/siteswap/siteswap.html
@@ -1,323 +1,323 @@
-<!-- @@REWRITE(insert html-copyright) -->
-<!--
-O3D Siteswap animator
-@@REWRITE(delete-start)
-Author: Eric Uhrhane (ericu@google.com)
-@@REWRITE(delete-end)
--->
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
- "http://www.w3.org/TR/html4/loose.dtd">
-<html>
-<head>
-<meta http-equiv="content-type" content="text/html; charset=UTF-8">
-<title>
- Site Swap Simulator
-</title>
-<style type="text/css">
- html, body {
- height: 100%;
- margin: 0;
- padding: 0;
- border: none;
- }
-</style>
-<!-- Our javascript code -->
-<script type="text/javascript" src="../o3djs/base.js"></script>
-<script type="text/javascript" src="siteswap.js"></script>
-<script type="text/javascript" src="math.js"></script>
-<script type="text/javascript" src="animation.js"></script>
-<script type="text/javascript" id="o3dscript">
-
-o3djs.require('o3djs.util');
-
-// Set up the client area.
-function init() {
- o3djs.util.setMainEngine(o3djs.util.Engine.V8);
- o3djs.util.addScriptUri(''); // Allow V8 to load scripts in the cwd.
- o3djs.util.makeClients(initStep2);
- setUpSelection();
-}
-
-// Select the entire input pattern, so that the user can just type.
-function setUpSelection() {
- var input_pattern = document.getElementById('input_pattern');
- input_pattern.focus();
- input_pattern.selectionStart = 0;
- input_pattern.selectionEnd = input_pattern.value.length;
-}
-
-/*
- * Wrappers to enable button presses to call through to the embedded V8 engine.
- */
-
-// Update whether we're animating or frozen based on the value of the checkbox.
-function updateAnimatingWrapper() {
- g.o3dElement.eval('updateAnimating()');
-}
-
-// Compute a new pattern.
-function onComputePatternWrapper() {
- g.o3dElement.eval('onComputePattern()');
-}
-
-// Adjust the view matrix to the new proportions of the plugin window.
-// TODO: Switch to using the resize event once that's checked in.
-function onResizeWrapper() {
- g.o3dElement.eval('onResize()');
-}
-window.onresize = onResizeWrapper;
-
-// Clean up all our callbacks, etc.
-function cleanupWrapper() {
- if (g && g.o3dElement) {
- g.o3dElement.eval('cleanup()');
- }
-}
-
-// The point of this function is to suppress form submit; we want to use the
-// pattern entered when the user hits return, not submit the page to the
-// webserver.
-function suppressSubmit(event) {
- onComputePatternWrapper(); // TODO: This suppresses form autocomplete storage.
- return false;
-}
-
-</script>
-</head>
-<body onload="init()" onunload="cleanupWrapper()">
-<table width="100%" style="height:100%;">
- <tr>
- <td>
- <h1>Juggler</h1>
- This sample displays a site-swap juggling pattern with animation done by
- a vertex shader.
- <form name="the_form" onsubmit="return suppressSubmit(event)">
- <table>
- <tr>
- <td>
- <table>
- <tr>
- <td>
- <input
- type="radio"
- name="radio_group_hands"
- value="1"
- onclick=onComputePatternWrapper()>
- 1 Hand<br>
- <input
- type="radio"
- name="radio_group_hands"
- value="2"
- onclick=onComputePatternWrapper()
- checked>
- 2 Hands<br>
- <input
- type="radio"
- name="radio_group_hands"
- value="3"
- onclick=onComputePatternWrapper()>
- 3 Hands<br>
- <input
- type="radio"
- name="radio_group_hands"
- value="4"
- onclick=onComputePatternWrapper()>
- 4 Hands<br>
- </td>
- <td>
- <input type="text" name="input_pattern" id="input_pattern"
- value="3 4 5">
- </td>
- <td>
- <input type="checkbox" name="check_box" checked
- onclick=updateAnimatingWrapper()>Animate
- <input
- type="checkbox"
- name="pair_hands"
- onclick=onComputePatternWrapper();
- >Pair Hands
- </td>
- <td>
- <input type="button" name="computePattern"
- value="Compute Pattern"
- onclick=onComputePatternWrapper()>
- </td>
- </tr>
- </table>
- </td>
- <td>
- </td>
- </tr>
- </table>
- </form>
- <table id="container" width="90%" style="height:70%;">
- <tr>
- <td height="100%">
- <!-- Start of g.o3d plugin -->
- <div id="o3d" style="width: 100%; height: 100%;"></div>
- <!-- End of g.o3d plugin -->
- </td>
- </tr>
- </table>
- <!-- a simple way to get a multiline string -->
- <textarea id="shader" name="shader" cols="80" rows="20"
- style="display: none;">
-// the 4x4 world view projection matrix
-float4x4 worldViewProjection : WorldViewProjection;
-
-// positions of the light and camera
-float3 light_pos;
-float3 camera_pos;
-
-// phong lighting properties of the material
-float4 light_ambient;
-float4 light_diffuse;
-float4 light_specular;
-
-// shininess of the material (for specular lighting)
-float shininess;
-
-// time for animation
-float time;
-
-// coefficients for a t^2 + b t + c for each of x, y, z
-float3 coeff_a;
-float3 coeff_b;
-float3 coeff_c;
-
-// flag and coefficient for optional LERP with rate t * coeff_lerp;
-float coeff_lerp;
-
-// coefficients for a t^2 + b t + c for each of x, y, z, for optional LERP
-float3 coeff_l_a;
-float3 coeff_l_b;
-float3 coeff_l_c;
-
-// coefficients for d sin(f t) + e cos(e t) for each of x, y, z
-float3 coeff_d;
-float3 coeff_e;
-float3 coeff_f;
-
-// to be subtracted from time to get the t for the above equation
-float time_base;
-
-// input parameters for our vertex shader
-struct VertexShaderInput {
- float4 position : POSITION;
- float3 normal : NORMAL;
- float4 color : COLOR;
-};
-
-// input parameters for our pixel shader
-// also the output parameters for our vertex shader
-struct PixelShaderInput {
- float4 position : POSITION;
- float3 lightVector : TEXCOORD0;
- float3 normal : TEXCOORD1;
- float3 viewPosition : TEXCOORD2;
- float4 color : COLOR;
-};
-
-/**
- * Vertex Shader - vertex shader for phong illumination
- */
-PixelShaderInput vertexShaderFunction(VertexShaderInput input) {
- /**
- * We use the standard phong illumination equation here.
- * We restrict (clamp) the dot products so that we
- * don't get any negative values.
- * All vectors are normalized for proper calculations.
- *
- * The output color is the summation of the
- * ambient, diffuse, and specular contributions.
- *
- * Note that we have to transform each vertex and normal
- * by the world view projection matrix first.
- */
- PixelShaderInput output;
-
- float t = time - time_base;
- float3 offset = float3(0, 0, 0);
- offset += t * t * coeff_a + t * coeff_b + coeff_c;
- offset += coeff_d * sin(t * coeff_f);
- offset += coeff_e * cos(t * coeff_f);
-
- float3 lerpOffset = t * t * coeff_l_a + t * coeff_l_b + coeff_l_c;
- if (coeff_lerp > 0) {
- float rate = min(coeff_lerp * t, 1);
- float3 lerpVector = float3(rate, rate, rate);
- offset = lerp(offset, lerpOffset, lerpVector);
- } else if (coeff_lerp < 0) {
- float rate = min(-coeff_lerp * t, 1);
- float3 lerpVector = float3(rate, rate, rate);
- offset = lerp(lerpOffset, offset, lerpVector);
- }
-
- input.position = input.position + float4(offset.xyz, 0);
-
- output.position = mul(input.position, worldViewProjection);
-
- /**
- * lightVector - light vector
- * normal - normal vector
- * viewPosition - view vector (from camera)
- */
-
- // NOTE: In this case we do not need to multiply by any matrices since the
- // WORLD transformation matrix is the identity. If you were moving the
- // object such that the WORLD transform matrix was not the identity, you
- // would need to multiply the normal by the WORLDINVERSETTRANSFORM matrix
- // since the normal is in object space. Other values (light_pos, camera_pos)
- // are already in world space.
- float3 lightVector = light_pos - input.position.xyz;
- float3 normal = input.normal;
- float3 viewPosition = camera_pos - input.position.xyz;
-
- output.lightVector = lightVector;
- output.normal = normal;
- output.viewPosition = viewPosition;
- output.color = input.color;
- return output;
-}
-
-/**
- * Pixel Shader
- */
-float4 pixelShaderFunction(PixelShaderInput input): COLOR {
- float3 lightVector = normalize(input.lightVector);
- float3 normal = normalize(input.normal);
- float3 viewPosition = normalize(input.viewPosition);
- float3 halfVector = normalize(lightVector + viewPosition);
-
- // use lit function to calculate phong shading
- // x component contains the ambient coefficient
- // y component contains the diffuse coefficient:
- // max(dot(normal, lightVector),0)
- // z component contains the specular coefficient:
- // dot(normal, lightVector) < 0 || dot(normal, halfVector) < 0 ?
- // 0 : pow(dot(normal, halfVector), shininess)
- // NOTE: This is actually Blinn-Phong shading, not Phong shading
- // which would use the reflection vector instead of the half vector
-
- float4 phong_coeff = lit(dot(normal, lightVector),
- dot(normal, halfVector), shininess);
-
- float4 ambient = light_ambient * phong_coeff.x * input.color;
- float4 diffuse = light_diffuse * phong_coeff.y * input.color;
- float4 specular = light_specular * phong_coeff.z * input.color;
-
- return ambient + diffuse + specular;
-}
-
-// Here we tell our effect file *which* functions are
-// our vertex and pixel shaders.
-
-// #o3d VertexShaderEntryPoint vertexShaderFunction
-// #o3d PixelShaderEntryPoint pixelShaderFunction
-// #o3d MatrixLoadOrder RowMajor
- </textarea>
- </td>
- </tr>
-</table>
-</body>
-</html>
+<!-- @@REWRITE(insert html-copyright) -->
+<!--
+O3D Siteswap animator
+@@REWRITE(delete-start)
+Author: Eric Uhrhane (ericu@google.com)
+@@REWRITE(delete-end)
+-->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<title>
+ Site Swap Simulator
+</title>
+<style type="text/css">
+ html, body {
+ height: 100%;
+ margin: 0;
+ padding: 0;
+ border: none;
+ }
+</style>
+<!-- Our javascript code -->
+<script type="text/javascript" src="../o3djs/base.js"></script>
+<script type="text/javascript" src="siteswap.js"></script>
+<script type="text/javascript" src="math.js"></script>
+<script type="text/javascript" src="animation.js"></script>
+<script type="text/javascript" id="o3dscript">
+
+o3djs.require('o3djs.util');
+
+// Set up the client area.
+function init() {
+ o3djs.util.setMainEngine(o3djs.util.Engine.V8);
+ o3djs.util.addScriptUri(''); // Allow V8 to load scripts in the cwd.
+ o3djs.util.makeClients(initStep2);
+ setUpSelection();
+}
+
+// Select the entire input pattern, so that the user can just type.
+function setUpSelection() {
+ var input_pattern = document.getElementById('input_pattern');
+ input_pattern.focus();
+ input_pattern.selectionStart = 0;
+ input_pattern.selectionEnd = input_pattern.value.length;
+}
+
+/*
+ * Wrappers to enable button presses to call through to the embedded V8 engine.
+ */
+
+// Update whether we're animating or frozen based on the value of the checkbox.
+function updateAnimatingWrapper() {
+ g.o3dElement.eval('updateAnimating()');
+}
+
+// Compute a new pattern.
+function onComputePatternWrapper() {
+ g.o3dElement.eval('onComputePattern()');
+}
+
+// Adjust the view matrix to the new proportions of the plugin window.
+// TODO: Switch to using the resize event once that's checked in.
+function onResizeWrapper() {
+ g.o3dElement.eval('onResize()');
+}
+window.onresize = onResizeWrapper;
+
+// Clean up all our callbacks, etc.
+function cleanupWrapper() {
+ if (g && g.o3dElement) {
+ g.o3dElement.eval('cleanup()');
+ }
+}
+
+// The point of this function is to suppress form submit; we want to use the
+// pattern entered when the user hits return, not submit the page to the
+// webserver.
+function suppressSubmit(event) {
+ onComputePatternWrapper(); // TODO: This suppresses form autocomplete storage.
+ return false;
+}
+
+</script>
+</head>
+<body onload="init()" onunload="cleanupWrapper()">
+<table width="100%" style="height:100%;">
+ <tr>
+ <td>
+ <h1>Juggler</h1>
+ This sample displays a site-swap juggling pattern with animation done by
+ a vertex shader.
+ <form name="the_form" onsubmit="return suppressSubmit(event)">
+ <table>
+ <tr>
+ <td>
+ <table>
+ <tr>
+ <td>
+ <input
+ type="radio"
+ name="radio_group_hands"
+ value="1"
+ onclick=onComputePatternWrapper()>
+ 1 Hand<br>
+ <input
+ type="radio"
+ name="radio_group_hands"
+ value="2"
+ onclick=onComputePatternWrapper()
+ checked>
+ 2 Hands<br>
+ <input
+ type="radio"
+ name="radio_group_hands"
+ value="3"
+ onclick=onComputePatternWrapper()>
+ 3 Hands<br>
+ <input
+ type="radio"
+ name="radio_group_hands"
+ value="4"
+ onclick=onComputePatternWrapper()>
+ 4 Hands<br>
+ </td>
+ <td>
+ <input type="text" name="input_pattern" id="input_pattern"
+ value="3 4 5">
+ </td>
+ <td>
+ <input type="checkbox" name="check_box" checked
+ onclick=updateAnimatingWrapper()>Animate
+ <input
+ type="checkbox"
+ name="pair_hands"
+ onclick=onComputePatternWrapper();
+ >Pair Hands
+ </td>
+ <td>
+ <input type="button" name="computePattern"
+ value="Compute Pattern"
+ onclick=onComputePatternWrapper()>
+ </td>
+ </tr>
+ </table>
+ </td>
+ <td>
+ </td>
+ </tr>
+ </table>
+ </form>
+ <table id="container" width="90%" style="height:70%;">
+ <tr>
+ <td height="100%">
+ <!-- Start of g.o3d plugin -->
+ <div id="o3d" style="width: 100%; height: 100%;"></div>
+ <!-- End of g.o3d plugin -->
+ </td>
+ </tr>
+ </table>
+ <!-- a simple way to get a multiline string -->
+ <textarea id="shader" name="shader" cols="80" rows="20"
+ style="display: none;">
+// the 4x4 world view projection matrix
+float4x4 worldViewProjection : WorldViewProjection;
+
+// positions of the light and camera
+float3 light_pos;
+float3 camera_pos;
+
+// phong lighting properties of the material
+float4 light_ambient;
+float4 light_diffuse;
+float4 light_specular;
+
+// shininess of the material (for specular lighting)
+float shininess;
+
+// time for animation
+float time;
+
+// coefficients for a t^2 + b t + c for each of x, y, z
+float3 coeff_a;
+float3 coeff_b;
+float3 coeff_c;
+
+// flag and coefficient for optional LERP with rate t * coeff_lerp;
+float coeff_lerp;
+
+// coefficients for a t^2 + b t + c for each of x, y, z, for optional LERP
+float3 coeff_l_a;
+float3 coeff_l_b;
+float3 coeff_l_c;
+
+// coefficients for d sin(f t) + e cos(e t) for each of x, y, z
+float3 coeff_d;
+float3 coeff_e;
+float3 coeff_f;
+
+// to be subtracted from time to get the t for the above equation
+float time_base;
+
+// input parameters for our vertex shader
+struct VertexShaderInput {
+ float4 position : POSITION;
+ float3 normal : NORMAL;
+ float4 color : COLOR;
+};
+
+// input parameters for our pixel shader
+// also the output parameters for our vertex shader
+struct PixelShaderInput {
+ float4 position : POSITION;
+ float3 lightVector : TEXCOORD0;
+ float3 normal : TEXCOORD1;
+ float3 viewPosition : TEXCOORD2;
+ float4 color : COLOR;
+};
+
+/**
+ * Vertex Shader - vertex shader for phong illumination
+ */
+PixelShaderInput vertexShaderFunction(VertexShaderInput input) {
+ /**
+ * We use the standard phong illumination equation here.
+ * We restrict (clamp) the dot products so that we
+ * don't get any negative values.
+ * All vectors are normalized for proper calculations.
+ *
+ * The output color is the summation of the
+ * ambient, diffuse, and specular contributions.
+ *
+ * Note that we have to transform each vertex and normal
+ * by the world view projection matrix first.
+ */
+ PixelShaderInput output;
+
+ float t = time - time_base;
+ float3 offset = float3(0, 0, 0);
+ offset += t * t * coeff_a + t * coeff_b + coeff_c;
+ offset += coeff_d * sin(t * coeff_f);
+ offset += coeff_e * cos(t * coeff_f);
+
+ float3 lerpOffset = t * t * coeff_l_a + t * coeff_l_b + coeff_l_c;
+ if (coeff_lerp > 0) {
+ float rate = min(coeff_lerp * t, 1);
+ float3 lerpVector = float3(rate, rate, rate);
+ offset = lerp(offset, lerpOffset, lerpVector);
+ } else if (coeff_lerp < 0) {
+ float rate = min(-coeff_lerp * t, 1);
+ float3 lerpVector = float3(rate, rate, rate);
+ offset = lerp(lerpOffset, offset, lerpVector);
+ }
+
+ input.position = input.position + float4(offset.xyz, 0);
+
+ output.position = mul(input.position, worldViewProjection);
+
+ /**
+ * lightVector - light vector
+ * normal - normal vector
+ * viewPosition - view vector (from camera)
+ */
+
+ // NOTE: In this case we do not need to multiply by any matrices since the
+ // WORLD transformation matrix is the identity. If you were moving the
+ // object such that the WORLD transform matrix was not the identity, you
+ // would need to multiply the normal by the WORLDINVERSETTRANSFORM matrix
+ // since the normal is in object space. Other values (light_pos, camera_pos)
+ // are already in world space.
+ float3 lightVector = light_pos - input.position.xyz;
+ float3 normal = input.normal;
+ float3 viewPosition = camera_pos - input.position.xyz;
+
+ output.lightVector = lightVector;
+ output.normal = normal;
+ output.viewPosition = viewPosition;
+ output.color = input.color;
+ return output;
+}
+
+/**
+ * Pixel Shader
+ */
+float4 pixelShaderFunction(PixelShaderInput input): COLOR {
+ float3 lightVector = normalize(input.lightVector);
+ float3 normal = normalize(input.normal);
+ float3 viewPosition = normalize(input.viewPosition);
+ float3 halfVector = normalize(lightVector + viewPosition);
+
+ // use lit function to calculate phong shading
+ // x component contains the ambient coefficient
+ // y component contains the diffuse coefficient:
+ // max(dot(normal, lightVector),0)
+ // z component contains the specular coefficient:
+ // dot(normal, lightVector) < 0 || dot(normal, halfVector) < 0 ?
+ // 0 : pow(dot(normal, halfVector), shininess)
+ // NOTE: This is actually Blinn-Phong shading, not Phong shading
+ // which would use the reflection vector instead of the half vector
+
+ float4 phong_coeff = lit(dot(normal, lightVector),
+ dot(normal, halfVector), shininess);
+
+ float4 ambient = light_ambient * phong_coeff.x * input.color;
+ float4 diffuse = light_diffuse * phong_coeff.y * input.color;
+ float4 specular = light_specular * phong_coeff.z * input.color;
+
+ return ambient + diffuse + specular;
+}
+
+// Here we tell our effect file *which* functions are
+// our vertex and pixel shaders.
+
+// #o3d VertexShaderEntryPoint vertexShaderFunction
+// #o3d PixelShaderEntryPoint pixelShaderFunction
+// #o3d MatrixLoadOrder RowMajor
+ </textarea>
+ </td>
+ </tr>
+</table>
+</body>
+</html>
diff --git a/o3d/samples/siteswap/siteswap.js b/o3d/samples/siteswap/siteswap.js
index 24a59a7cd..6b77aff 100644
--- a/o3d/samples/siteswap/siteswap.js
+++ b/o3d/samples/siteswap/siteswap.js
@@ -1,415 +1,415 @@
-// @@REWRITE(insert js-copyright)
-// @@REWRITE(delete-start)
-// Copyright 2009 Google Inc. All Rights Reserved
-// @@REWRITE(delete-end)
-
-/**
- * This file contains the top-level logic and o3d-related code for the siteswap
- * animator.
- */
-
-o3djs.require('o3djs.rendergraph');
-o3djs.require('o3djs.math');
-o3djs.require('o3djs.primitives');
-o3djs.require('o3djs.dump');
-
-// Global variables are all referenced via g, so that either interpreter can
-// find them easily.
-var g = {};
-
-/**
- * Creates a color based on an input index as a seed.
- * @param {!number} index the seed value to select the color.
- * @return {!Array.number} an [r g b a] color.
- */
-function createColor(index) {
- var N = 12; // Number of distinct colors.
- var root3 = Math.sqrt(3);
- var theta = 2 * Math.PI * index / N;
- var sin = Math.sin(theta);
- var cos = Math.cos(theta);
- return [(1 / 3 + 2 / 3 * cos) + (1 / 3 - cos / 3 - sin / root3),
- (1 / 3 - cos / 3 + sin / root3) + (1 / 3 + 2 / 3 * cos),
- (1 / 3 - cos / 3 - sin / root3) + (1 / 3 - cos / 3 + sin / root3),
- 1];
-}
-
-/**
- * Creates a material, given the index as a seed to make it distinguishable.
- * @param {number} index an integer used to create a distinctive color.
- * @return {!o3d.Material} the material.
- */
-function createMaterial(index) {
- var material = g.pack.createObject('Material');
-
- // Apply our effect to this material. The effect tells the 3D hardware
- // which shader to use.
- material.effect = g.effect;
-
- // Set the material's drawList
- material.drawList = g.viewInfo.performanceDrawList;
-
- // This will create our quadColor parameter on the material.
- g.effect.createUniformParameters(material);
-
- // Set up the individual parameters in our effect file.
-
- // Light position
- var light_pos_param = material.getParam('light_pos');
- light_pos_param.value = [10, 10, 20];
-
- // Phong components of the light source
- var light_ambient_param = material.getParam('light_ambient');
- var light_diffuse_param = material.getParam('light_diffuse');
- var light_specular_param = material.getParam('light_specular');
-
- // White ambient light
- light_ambient_param.value = [0.04, 0.04, 0.04, 1];
-
- light_diffuse_param.value = createColor(index);
- // White specular light
- light_specular_param.value = [0.5, 0.5, 0.5, 1];
-
- // Shininess of the material (for specular lighting)
- var shininess_param = material.getParam('shininess');
- shininess_param.value = 30.0;
-
- // Bind the counter's count to the input of the FunctionEval.
- var paramTime = material.getParam('time');
- paramTime.bind(g.counter.getParam('count'));
-
- material.getParam('camera_pos').value = g.eye;
-
- return material;
-}
-
-/**
- * Gets a material from our cache, creating it if it's not yet been made.
- * Uses index as a seed to make the material distinguishable.
- * @param {number} index an integer used to create/fetch a distinctive color.
- * @return {!o3d.Material} the material.
- */
-function getMaterial(index) {
- g.materials = g.materials || []; // See initStep2 for a comment.
- if (!g.materials[index]) {
- g.materials[index] = createMaterial(index);
- }
- return g.materials[index];
-}
-
-/**
- * Initializes g.o3d.
- * @param {Array} clientElements Array of o3d object elements.
- */
-function initStep2(clientElements) {
- // Initializes global variables and libraries.
- window.g = g;
-
- // Used to tell whether we need to recompute our view on resize.
- g.o3dWidth = -1;
- g.o3dHeight = -1;
-
- // We create a different material for each color of object.
- //g.materials = []; // TODO(ericu): If this is executed, we fail. Why?
-
- // We hold on to all the shapes here so that we can clean them up when we want
- // to change patterns.
- g.ballShapes = [];
- g.handShapes = [];
-
- g.o3dElement = clientElements[0];
- g.o3d = g.o3dElement.o3d;
- g.math = o3djs.math;
- g.client = g.o3dElement.client;
-
- // Initialize client sample libraries.
- o3djs.base.init(g.o3dElement);
-
- // Create a g.pack to manage our resources/assets
- g.pack = g.client.createPack();
-
- // Create the render graph for a view.
- g.viewInfo = o3djs.rendergraph.createBasicView(
- g.pack,
- g.client.root,
- g.client.renderGraphRoot);
-
- // Get the default context to hold view/projection matrices.
- g.context = g.viewInfo.drawContext;
-
- // Load a simple effect from a textarea.
- g.effect = g.pack.createObject('Effect');
- g.effect.loadFromFXString(document.getElementById('shader').value);
-
- // Eye-position: this is where our camera is located.
- // Global because each material we create must also know where it is, so that
- // the shader works properly.
- g.eye = [1, 6, 10];
-
- // Target, this is the point at which our camera is pointed.
- var target = [0, 2, 0];
-
- // Up-vector, this tells the camera which direction is 'up'.
- // We define the positive y-direction to be up in this example.
- var up = [0, 1, 0];
-
- g.context.view = g.math.matrix4.lookAt(g.eye, target, up);
-
- // Make a SecondCounter to provide the time for our animation.
- g.counter = g.pack.createObject('SecondCounter');
- g.counter.multiplier = 3; // Speed up time; this is in throws per second.
-
- // Generate the projection and viewProjection matrices based
- // on the g.o3d plugin size by calling onResize().
- onResize();
-
- // If we don't check the size of the client area every frame we don't get a
- // chance to adjust the perspective matrix fast enough to keep up with the
- // browser resizing us.
- // TODO(ericu): Switch to using the resize event once it's checked in.
- g.client.setRenderCallback(onResize);
-}
-
-/**
- * Stops or starts the animation based on the state of an html checkbox.
- */
-function updateAnimating() {
- var box = document.the_form.check_box;
- g.counter.running = box.checked;
-}
-
-/**
- * Generates the projection matrix based on the size of the g.o3d plugin
- * and calculates the view-projection matrix.
- */
-function onResize() {
- var newWidth = g.client.width;
- var newHeight = g.client.height;
-
- if (newWidth != g.o3dWidth || newHeight != g.o3dHeight) {
- debug('resizing');
- g.o3dWidth = newWidth;
- g.o3dHeight = newHeight;
-
- // Create our projection matrix, with a vertical field of view of 45 degrees
- // a near clipping plane of 0.1 and far clipping plane of 100.
- g.context.projection = g.math.matrix4.perspective(
- 45 * Math.PI / 180,
- g.o3dWidth / g.o3dHeight,
- 0.1,
- 100);
- }
-}
-
-/**
- * Computes and prepares animation of the pattern input via the html form. If
- * the box is checked, this will immediately begin animation as well.
- */
-function onComputePattern() {
- try {
- g.counter.removeAllCallbacks();
- var group = document.the_form.radio_group_hands;
- var numHands = -1;
- for (var i = 0; i < group.length; ++i) {
- if (group[i].checked) {
- numHands = parseInt(group[i].value);
- }
- }
- var style = 'even';
- if (document.the_form.pair_hands.checked) {
- style = 'pairs';
- }
- var patternString = document.getElementById('input_pattern').value;
- var patternData =
- computeFullPatternFromString(patternString, numHands, style);
- startAnimation(
- patternData.numBalls,
- patternData.numHands,
- patternData.duration,
- patternData.ballCurveSets,
- patternData.handCurveSets);
- } catch (ex) {
- popup(stringifyObj(ex));
- throw ex;
- }
- setUpSelection();
-}
-
-/**
- * Removes any callbacks so they don't get called after the page has unloaded.
- */
-function cleanup() {
- g.client.cleanup();
-}
-
-
-/**
- * Dump out a newline-terminated string to the debug console, if available.
- * @param {!string} s the string to output.
- */
-function debug(s) {
- o3djs.dump.dump(s + '\n');
-}
-
-/**
- * Dump out a newline-terminated string to the debug console, if available,
- * then display it via an alert.
- * @param {!string} s the string to output.
- */
-function popup(s) {
- debug(s);
- window.alert(s);
-}
-
-/**
- * If t, throw an exception.
- * @param {!bool} t the value to test.
- */
-function assert(t) {
- if (!t) {
- throw new Error('Assertion failed!');
- }
-}
-
-/**
- * Convert an object to a string containing a full one-level-deep property
- * listing, with values.
- * @param {!Object} o the object to convert.
- * @return {!string} the converted object.
- */
-function stringifyObj(o) {
- var s = '';
- for (var i in o) {
- s += i + ':' + o[i] + '\n';
- }
- return s;
-}
-
-/**
- * Add the information in a curve to the params on a shape, such that the vertex
- * shader will move the shape along the curve at times after timeBase.
- * @param {!Curve} curve the curve the shape should follow.
- * @param {!o3d.Shape} shape the shape being moved.
- * @param {!number} timeBase the base to subtract from the current time when
- * giving the curve calculation its time input.
- */
-function setParamCurveInfo(curve, shape, timeBase) {
- assert(curve);
- assert(shape);
- try {
- shape.elements[0].getParam('time_base').value = timeBase;
- shape.elements[0].getParam('coeff_a').value =
- [curve.xEqn.a, curve.yEqn.a, curve.zEqn.a];
- shape.elements[0].getParam('coeff_b').value =
- [curve.xEqn.b, curve.yEqn.b, curve.zEqn.b];
- shape.elements[0].getParam('coeff_c').value =
- [curve.xEqn.c, curve.yEqn.c, curve.zEqn.c];
- shape.elements[0].getParam('coeff_d').value =
- [curve.xEqn.d, curve.yEqn.d, curve.zEqn.d];
- shape.elements[0].getParam('coeff_e').value =
- [curve.xEqn.e, curve.yEqn.e, curve.zEqn.e];
- shape.elements[0].getParam('coeff_f').value =
- [curve.xEqn.f, curve.yEqn.f, curve.zEqn.f];
-
- assert(curve.xEqn.lerpRate == curve.yEqn.lerpRate);
- assert(curve.xEqn.lerpRate == curve.zEqn.lerpRate);
- shape.elements[0].getParam('coeff_lerp').value = curve.xEqn.lerpRate;
- if (curve.xEqn.lerpRate) {
- shape.elements[0].getParam('coeff_l_a').value =
- [curve.xEqn.lA, curve.yEqn.lA, curve.zEqn.lA];
- shape.elements[0].getParam('coeff_l_b').value =
- [curve.xEqn.lB, curve.yEqn.lB, curve.zEqn.lB];
- shape.elements[0].getParam('coeff_l_c').value =
- [curve.xEqn.lC, curve.yEqn.lC, curve.zEqn.lC];
- }
- } catch (ex) {
- debug(ex);
- throw ex;
- }
-}
-
-/**
- * Create the params that the shader expects on the supplied shape's first
- * element.
- * @param {!o3d.Shape} shape the shape on whose first element to create params.
- */
-function createParams(shape) {
- shape.elements[0].createParam('coeff_a', 'ParamFloat3').value = [0, 0, 0];
- shape.elements[0].createParam('coeff_b', 'ParamFloat3').value = [0, 0, 0];
- shape.elements[0].createParam('coeff_c', 'ParamFloat3').value = [0, 0, 0];
- shape.elements[0].createParam('coeff_d', 'ParamFloat3').value = [0, 0, 0];
- shape.elements[0].createParam('coeff_e', 'ParamFloat3').value = [0, 0, 0];
- shape.elements[0].createParam('coeff_f', 'ParamFloat3').value = [0, 0, 0];
- shape.elements[0].createParam('coeff_l_a', 'ParamFloat3').value = [0, 0, 0];
- shape.elements[0].createParam('coeff_l_b', 'ParamFloat3').value = [0, 0, 0];
- shape.elements[0].createParam('coeff_l_c', 'ParamFloat3').value = [0, 0, 0];
- shape.elements[0].createParam('coeff_lerp', 'ParamFloat').value = 0;
- shape.elements[0].createParam('time_base', 'ParamFloat').value = 0;
-}
-
-/**
- * Adjust the number of ball shapes in g.pack.
- * @param {!number} numBalls the number of balls desired.
- */
-function setNumBalls(numBalls) {
- for (var i = 0; i < g.ballShapes.length; ++i) {
- g.pack.removeObject(g.ballShapes[i]);
- g.client.root.removeShape(g.ballShapes[i]);
- }
- g.ballShapes = [];
-
- for (var i = 0; i < numBalls; ++i) {
- var shape = o3djs.primitives.createSphere(g.pack,
- getMaterial(5 * i),
- 0.10,
- 70,
- 70);
- shape.name = 'Ball ' + i;
-
- // generate the draw elements.
- shape.createDrawElements(g.pack, null);
-
- // Now attach the sphere to the root of the scene graph.
- g.client.root.addShape(shape);
-
- // Create the material params for the shader.
- createParams(shape);
-
- g.ballShapes[i] = shape;
- }
-}
-
-/**
- * Adjust the number of hand shapes in g.pack.
- * @param {!number} numHands the number of hands desired.
- */
-function setNumHands(numHands) {
- g.counter.removeAllCallbacks();
-
- for (var i = 0; i < g.handShapes.length; ++i) {
- g.pack.removeObject(g.handShapes[i]);
- g.client.root.removeShape(g.handShapes[i]);
- }
- g.handShapes = [];
-
- for (var i = 0; i < numHands; ++i) {
- var shape = o3djs.primitives.createBox(g.pack,
- getMaterial(3 * (i + 1)),
- 0.25,
- 0.05,
- 0.25);
- shape.name = 'Hand ' + i;
-
- // generate the draw elements.
- shape.createDrawElements(g.pack, null);
-
- // Now attach the sphere to the root of the scene graph.
- g.client.root.addShape(shape);
-
- // Create the material params for the shader.
- createParams(shape);
-
- g.handShapes[i] = shape;
- }
-}
-
+// @@REWRITE(insert js-copyright)
+// @@REWRITE(delete-start)
+// Copyright 2009 Google Inc. All Rights Reserved
+// @@REWRITE(delete-end)
+
+/**
+ * This file contains the top-level logic and o3d-related code for the siteswap
+ * animator.
+ */
+
+o3djs.require('o3djs.rendergraph');
+o3djs.require('o3djs.math');
+o3djs.require('o3djs.primitives');
+o3djs.require('o3djs.dump');
+
+// Global variables are all referenced via g, so that either interpreter can
+// find them easily.
+var g = {};
+
+/**
+ * Creates a color based on an input index as a seed.
+ * @param {!number} index the seed value to select the color.
+ * @return {!Array.number} an [r g b a] color.
+ */
+function createColor(index) {
+ var N = 12; // Number of distinct colors.
+ var root3 = Math.sqrt(3);
+ var theta = 2 * Math.PI * index / N;
+ var sin = Math.sin(theta);
+ var cos = Math.cos(theta);
+ return [(1 / 3 + 2 / 3 * cos) + (1 / 3 - cos / 3 - sin / root3),
+ (1 / 3 - cos / 3 + sin / root3) + (1 / 3 + 2 / 3 * cos),
+ (1 / 3 - cos / 3 - sin / root3) + (1 / 3 - cos / 3 + sin / root3),
+ 1];
+}
+
+/**
+ * Creates a material, given the index as a seed to make it distinguishable.
+ * @param {number} index an integer used to create a distinctive color.
+ * @return {!o3d.Material} the material.
+ */
+function createMaterial(index) {
+ var material = g.pack.createObject('Material');
+
+ // Apply our effect to this material. The effect tells the 3D hardware
+ // which shader to use.
+ material.effect = g.effect;
+
+ // Set the material's drawList
+ material.drawList = g.viewInfo.performanceDrawList;
+
+ // This will create our quadColor parameter on the material.
+ g.effect.createUniformParameters(material);
+
+ // Set up the individual parameters in our effect file.
+
+ // Light position
+ var light_pos_param = material.getParam('light_pos');
+ light_pos_param.value = [10, 10, 20];
+
+ // Phong components of the light source
+ var light_ambient_param = material.getParam('light_ambient');
+ var light_diffuse_param = material.getParam('light_diffuse');
+ var light_specular_param = material.getParam('light_specular');
+
+ // White ambient light
+ light_ambient_param.value = [0.04, 0.04, 0.04, 1];
+
+ light_diffuse_param.value = createColor(index);
+ // White specular light
+ light_specular_param.value = [0.5, 0.5, 0.5, 1];
+
+ // Shininess of the material (for specular lighting)
+ var shininess_param = material.getParam('shininess');
+ shininess_param.value = 30.0;
+
+ // Bind the counter's count to the input of the FunctionEval.
+ var paramTime = material.getParam('time');
+ paramTime.bind(g.counter.getParam('count'));
+
+ material.getParam('camera_pos').value = g.eye;
+
+ return material;
+}
+
+/**
+ * Gets a material from our cache, creating it if it's not yet been made.
+ * Uses index as a seed to make the material distinguishable.
+ * @param {number} index an integer used to create/fetch a distinctive color.
+ * @return {!o3d.Material} the material.
+ */
+function getMaterial(index) {
+ g.materials = g.materials || []; // See initStep2 for a comment.
+ if (!g.materials[index]) {
+ g.materials[index] = createMaterial(index);
+ }
+ return g.materials[index];
+}
+
+/**
+ * Initializes g.o3d.
+ * @param {Array} clientElements Array of o3d object elements.
+ */
+function initStep2(clientElements) {
+ // Initializes global variables and libraries.
+ window.g = g;
+
+ // Used to tell whether we need to recompute our view on resize.
+ g.o3dWidth = -1;
+ g.o3dHeight = -1;
+
+ // We create a different material for each color of object.
+ //g.materials = []; // TODO(ericu): If this is executed, we fail. Why?
+
+ // We hold on to all the shapes here so that we can clean them up when we want
+ // to change patterns.
+ g.ballShapes = [];
+ g.handShapes = [];
+
+ g.o3dElement = clientElements[0];
+ g.o3d = g.o3dElement.o3d;
+ g.math = o3djs.math;
+ g.client = g.o3dElement.client;
+
+ // Initialize client sample libraries.
+ o3djs.base.init(g.o3dElement);
+
+ // Create a g.pack to manage our resources/assets
+ g.pack = g.client.createPack();
+
+ // Create the render graph for a view.
+ g.viewInfo = o3djs.rendergraph.createBasicView(
+ g.pack,
+ g.client.root,
+ g.client.renderGraphRoot);
+
+ // Get the default context to hold view/projection matrices.
+ g.context = g.viewInfo.drawContext;
+
+ // Load a simple effect from a textarea.
+ g.effect = g.pack.createObject('Effect');
+ g.effect.loadFromFXString(document.getElementById('shader').value);
+
+ // Eye-position: this is where our camera is located.
+ // Global because each material we create must also know where it is, so that
+ // the shader works properly.
+ g.eye = [1, 6, 10];
+
+ // Target, this is the point at which our camera is pointed.
+ var target = [0, 2, 0];
+
+ // Up-vector, this tells the camera which direction is 'up'.
+ // We define the positive y-direction to be up in this example.
+ var up = [0, 1, 0];
+
+ g.context.view = g.math.matrix4.lookAt(g.eye, target, up);
+
+ // Make a SecondCounter to provide the time for our animation.
+ g.counter = g.pack.createObject('SecondCounter');
+ g.counter.multiplier = 3; // Speed up time; this is in throws per second.
+
+ // Generate the projection and viewProjection matrices based
+ // on the g.o3d plugin size by calling onResize().
+ onResize();
+
+ // If we don't check the size of the client area every frame we don't get a
+ // chance to adjust the perspective matrix fast enough to keep up with the
+ // browser resizing us.
+ // TODO(ericu): Switch to using the resize event once it's checked in.
+ g.client.setRenderCallback(onResize);
+}
+
+/**
+ * Stops or starts the animation based on the state of an html checkbox.
+ */
+function updateAnimating() {
+ var box = document.the_form.check_box;
+ g.counter.running = box.checked;
+}
+
+/**
+ * Generates the projection matrix based on the size of the g.o3d plugin
+ * and calculates the view-projection matrix.
+ */
+function onResize() {
+ var newWidth = g.client.width;
+ var newHeight = g.client.height;
+
+ if (newWidth != g.o3dWidth || newHeight != g.o3dHeight) {
+ debug('resizing');
+ g.o3dWidth = newWidth;
+ g.o3dHeight = newHeight;
+
+ // Create our projection matrix, with a vertical field of view of 45 degrees
+ // a near clipping plane of 0.1 and far clipping plane of 100.
+ g.context.projection = g.math.matrix4.perspective(
+ 45 * Math.PI / 180,
+ g.o3dWidth / g.o3dHeight,
+ 0.1,
+ 100);
+ }
+}
+
+/**
+ * Computes and prepares animation of the pattern input via the html form. If
+ * the box is checked, this will immediately begin animation as well.
+ */
+function onComputePattern() {
+ try {
+ g.counter.removeAllCallbacks();
+ var group = document.the_form.radio_group_hands;
+ var numHands = -1;
+ for (var i = 0; i < group.length; ++i) {
+ if (group[i].checked) {
+ numHands = parseInt(group[i].value);
+ }
+ }
+ var style = 'even';
+ if (document.the_form.pair_hands.checked) {
+ style = 'pairs';
+ }
+ var patternString = document.getElementById('input_pattern').value;
+ var patternData =
+ computeFullPatternFromString(patternString, numHands, style);
+ startAnimation(
+ patternData.numBalls,
+ patternData.numHands,
+ patternData.duration,
+ patternData.ballCurveSets,
+ patternData.handCurveSets);
+ } catch (ex) {
+ popup(stringifyObj(ex));
+ throw ex;
+ }
+ setUpSelection();
+}
+
+/**
+ * Removes any callbacks so they don't get called after the page has unloaded.
+ */
+function cleanup() {
+ g.client.cleanup();
+}
+
+
+/**
+ * Dump out a newline-terminated string to the debug console, if available.
+ * @param {!string} s the string to output.
+ */
+function debug(s) {
+ o3djs.dump.dump(s + '\n');
+}
+
+/**
+ * Dump out a newline-terminated string to the debug console, if available,
+ * then display it via an alert.
+ * @param {!string} s the string to output.
+ */
+function popup(s) {
+ debug(s);
+ window.alert(s);
+}
+
+/**
+ * If t, throw an exception.
+ * @param {!bool} t the value to test.
+ */
+function assert(t) {
+ if (!t) {
+ throw new Error('Assertion failed!');
+ }
+}
+
+/**
+ * Convert an object to a string containing a full one-level-deep property
+ * listing, with values.
+ * @param {!Object} o the object to convert.
+ * @return {!string} the converted object.
+ */
+function stringifyObj(o) {
+ var s = '';
+ for (var i in o) {
+ s += i + ':' + o[i] + '\n';
+ }
+ return s;
+}
+
+/**
+ * Add the information in a curve to the params on a shape, such that the vertex
+ * shader will move the shape along the curve at times after timeBase.
+ * @param {!Curve} curve the curve the shape should follow.
+ * @param {!o3d.Shape} shape the shape being moved.
+ * @param {!number} timeBase the base to subtract from the current time when
+ * giving the curve calculation its time input.
+ */
+function setParamCurveInfo(curve, shape, timeBase) {
+ assert(curve);
+ assert(shape);
+ try {
+ shape.elements[0].getParam('time_base').value = timeBase;
+ shape.elements[0].getParam('coeff_a').value =
+ [curve.xEqn.a, curve.yEqn.a, curve.zEqn.a];
+ shape.elements[0].getParam('coeff_b').value =
+ [curve.xEqn.b, curve.yEqn.b, curve.zEqn.b];
+ shape.elements[0].getParam('coeff_c').value =
+ [curve.xEqn.c, curve.yEqn.c, curve.zEqn.c];
+ shape.elements[0].getParam('coeff_d').value =
+ [curve.xEqn.d, curve.yEqn.d, curve.zEqn.d];
+ shape.elements[0].getParam('coeff_e').value =
+ [curve.xEqn.e, curve.yEqn.e, curve.zEqn.e];
+ shape.elements[0].getParam('coeff_f').value =
+ [curve.xEqn.f, curve.yEqn.f, curve.zEqn.f];
+
+ assert(curve.xEqn.lerpRate == curve.yEqn.lerpRate);
+ assert(curve.xEqn.lerpRate == curve.zEqn.lerpRate);
+ shape.elements[0].getParam('coeff_lerp').value = curve.xEqn.lerpRate;
+ if (curve.xEqn.lerpRate) {
+ shape.elements[0].getParam('coeff_l_a').value =
+ [curve.xEqn.lA, curve.yEqn.lA, curve.zEqn.lA];
+ shape.elements[0].getParam('coeff_l_b').value =
+ [curve.xEqn.lB, curve.yEqn.lB, curve.zEqn.lB];
+ shape.elements[0].getParam('coeff_l_c').value =
+ [curve.xEqn.lC, curve.yEqn.lC, curve.zEqn.lC];
+ }
+ } catch (ex) {
+ debug(ex);
+ throw ex;
+ }
+}
+
+/**
+ * Create the params that the shader expects on the supplied shape's first
+ * element.
+ * @param {!o3d.Shape} shape the shape on whose first element to create params.
+ */
+function createParams(shape) {
+ shape.elements[0].createParam('coeff_a', 'ParamFloat3').value = [0, 0, 0];
+ shape.elements[0].createParam('coeff_b', 'ParamFloat3').value = [0, 0, 0];
+ shape.elements[0].createParam('coeff_c', 'ParamFloat3').value = [0, 0, 0];
+ shape.elements[0].createParam('coeff_d', 'ParamFloat3').value = [0, 0, 0];
+ shape.elements[0].createParam('coeff_e', 'ParamFloat3').value = [0, 0, 0];
+ shape.elements[0].createParam('coeff_f', 'ParamFloat3').value = [0, 0, 0];
+ shape.elements[0].createParam('coeff_l_a', 'ParamFloat3').value = [0, 0, 0];
+ shape.elements[0].createParam('coeff_l_b', 'ParamFloat3').value = [0, 0, 0];
+ shape.elements[0].createParam('coeff_l_c', 'ParamFloat3').value = [0, 0, 0];
+ shape.elements[0].createParam('coeff_lerp', 'ParamFloat').value = 0;
+ shape.elements[0].createParam('time_base', 'ParamFloat').value = 0;
+}
+
+/**
+ * Adjust the number of ball shapes in g.pack.
+ * @param {!number} numBalls the number of balls desired.
+ */
+function setNumBalls(numBalls) {
+ for (var i = 0; i < g.ballShapes.length; ++i) {
+ g.pack.removeObject(g.ballShapes[i]);
+ g.client.root.removeShape(g.ballShapes[i]);
+ }
+ g.ballShapes = [];
+
+ for (var i = 0; i < numBalls; ++i) {
+ var shape = o3djs.primitives.createSphere(g.pack,
+ getMaterial(5 * i),
+ 0.10,
+ 70,
+ 70);
+ shape.name = 'Ball ' + i;
+
+ // generate the draw elements.
+ shape.createDrawElements(g.pack, null);
+
+ // Now attach the sphere to the root of the scene graph.
+ g.client.root.addShape(shape);
+
+ // Create the material params for the shader.
+ createParams(shape);
+
+ g.ballShapes[i] = shape;
+ }
+}
+
+/**
+ * Adjust the number of hand shapes in g.pack.
+ * @param {!number} numHands the number of hands desired.
+ */
+function setNumHands(numHands) {
+ g.counter.removeAllCallbacks();
+
+ for (var i = 0; i < g.handShapes.length; ++i) {
+ g.pack.removeObject(g.handShapes[i]);
+ g.client.root.removeShape(g.handShapes[i]);
+ }
+ g.handShapes = [];
+
+ for (var i = 0; i < numHands; ++i) {
+ var shape = o3djs.primitives.createBox(g.pack,
+ getMaterial(3 * (i + 1)),
+ 0.25,
+ 0.05,
+ 0.25);
+ shape.name = 'Hand ' + i;
+
+ // generate the draw elements.
+ shape.createDrawElements(g.pack, null);
+
+ // Now attach the sphere to the root of the scene graph.
+ g.client.root.addShape(shape);
+
+ // Create the material params for the shader.
+ createParams(shape);
+
+ g.handShapes[i] = shape;
+ }
+}
+
diff --git a/o3d/serializer/cross/README.txt b/o3d/serializer/cross/README.txt
index 9292bfb..17c04ef 100644
--- a/o3d/serializer/cross/README.txt
+++ b/o3d/serializer/cross/README.txt
@@ -1,67 +1,67 @@
-These are the formats for the various O3D objects that can be stored in binary.
-
-NOTE:
-All int16, uint16, int32, uint32 and floats are stored in LITTLE ENDIAN format.
-
------------------------- Buffer ------------------------------------------------
-A Buffer (VertexBuffer, SourceBuffer, IndexBuffer) are all stored as follows.
-
-// Header
-uint8[4] id : A 4 byte ID with the ascii characters "BUFF"
-int32 version : A version number. Must be 1
-int32 numFields : The number of fields in the buffer.
-
-// For each field
- uint8 fieldType : Type of field. 1 = FloatField, 2 = UInt32Field, 3 = UByteNField.
- uint8 numComponents : The number of components for that field.
-// End for
-
-// stored once.
-uint32 numElements : The number of elements in the buffer.
-
-// For each field. Depending on the type of field
- // If FloatField
- float[numElements * numComponents]
-
- // If UInt32Field
- uint32[numElements * numComponents]
-
- // If UByteNField
- uint8[numElements * numComponents]
-// End for
-
-
------------------------- Curve -------------------------------------------------
-A Curve is stored as follows.
-
-// Header
-uint8[4] id : A 4 byte ID with the ascii characters "CURV"
-int32 version : A version number. Must be 1
-
-// For each key in the Curve
- uint8 keyType : The type of key. 1 = StepCurveKey, 2 = LinearCurveKey, 3 = BezierCurveKey
- float input : The input of the key
- float output : The output of the key
- // If it is a BezierCurveKey
- float inTangentX : the x component of the in tangent.
- float inTangentY : the y component of the in tangent.
- float outTangentX : the x component of the out tangent.
- float outTangentY : the y component of the out tangent.
-// End for
-
-
------------------------- Skin --------------------------------------------------
-A Skin is stored as follows.
-
-// Header
-uint8[4] id : A 4 byte ID with the ascii characters "SKIN"
-int32 version : A version number. Must be 1
-
-// For each vertex in the skin
- int32 numInfluences : The number of influences on this vertex.
- // For each influence
- int32 matrixIndex : the Index of a matrix that affects this vertex.
- float weight : The weight for this matrix.
- // End for each influence
-// End for each vertex
-
+These are the formats for the various O3D objects that can be stored in binary.
+
+NOTE:
+All int16, uint16, int32, uint32 and floats are stored in LITTLE ENDIAN format.
+
+------------------------ Buffer ------------------------------------------------
+A Buffer (VertexBuffer, SourceBuffer, IndexBuffer) are all stored as follows.
+
+// Header
+uint8[4] id : A 4 byte ID with the ascii characters "BUFF"
+int32 version : A version number. Must be 1
+int32 numFields : The number of fields in the buffer.
+
+// For each field
+ uint8 fieldType : Type of field. 1 = FloatField, 2 = UInt32Field, 3 = UByteNField.
+ uint8 numComponents : The number of components for that field.
+// End for
+
+// stored once.
+uint32 numElements : The number of elements in the buffer.
+
+// For each field. Depending on the type of field
+ // If FloatField
+ float[numElements * numComponents]
+
+ // If UInt32Field
+ uint32[numElements * numComponents]
+
+ // If UByteNField
+ uint8[numElements * numComponents]
+// End for
+
+
+------------------------ Curve -------------------------------------------------
+A Curve is stored as follows.
+
+// Header
+uint8[4] id : A 4 byte ID with the ascii characters "CURV"
+int32 version : A version number. Must be 1
+
+// For each key in the Curve
+ uint8 keyType : The type of key. 1 = StepCurveKey, 2 = LinearCurveKey, 3 = BezierCurveKey
+ float input : The input of the key
+ float output : The output of the key
+ // If it is a BezierCurveKey
+ float inTangentX : the x component of the in tangent.
+ float inTangentY : the y component of the in tangent.
+ float outTangentX : the x component of the out tangent.
+ float outTangentY : the y component of the out tangent.
+// End for
+
+
+------------------------ Skin --------------------------------------------------
+A Skin is stored as follows.
+
+// Header
+uint8[4] id : A 4 byte ID with the ascii characters "SKIN"
+int32 version : A version number. Must be 1
+
+// For each vertex in the skin
+ int32 numInfluences : The number of influences on this vertex.
+ // For each influence
+ int32 matrixIndex : the Index of a matrix that affects this vertex.
+ float weight : The weight for this matrix.
+ // End for each influence
+// End for each vertex
+
diff --git a/o3d/tests/lab/runner_constants.py b/o3d/tests/lab/runner_constants.py
index a7ec00b..33afbe5 100644
--- a/o3d/tests/lab/runner_constants.py
+++ b/o3d/tests/lab/runner_constants.py
@@ -74,7 +74,7 @@ elif util.IsMac():
BUILD_PATH = join(BASE_PATH, 'xcodebuild')
else:
BUILD_PATH = join(BASE_PATH, 'sconsbuild')
-
+
# Product directory.
if os.path.exists(join(BUILD_PATH, 'Debug')):
PRODUCT_DIR_PATH = join(BUILD_PATH, 'Debug')
diff --git a/o3d/tests/selenium/pdiff_test.py b/o3d/tests/selenium/pdiff_test.py
index d1d4940..0a91f55 100644
--- a/o3d/tests/selenium/pdiff_test.py
+++ b/o3d/tests/selenium/pdiff_test.py
@@ -1,132 +1,132 @@
-import os
-import re
-import subprocess
-import unittest
-import sys
-
-import selenium_utilities
-import selenium_constants
-
-class PDiffTest(unittest.TestCase):
- """A perceptual diff test class, for running perceptual diffs on any
- number of screenshots."""
-
- def __init__(self, name, num_screenshots, screenshot_name, pdiff_path,
- gen_dir, ref_dir, options):
- unittest.TestCase.__init__(self, name)
- self.name = name
- self.num_screenshots = num_screenshots
- self.screenshot_name = screenshot_name
- self.pdiff_path = pdiff_path
- self.gen_dir = gen_dir
- self.ref_dir = ref_dir
- self.options = options
-
- def shortDescription(self):
- """override unittest.TestCase shortDescription for our own descriptions."""
- return "Screenshot comparison for: " + self.name
-
- def PDiffTest(self):
- """Runs a generic Perceptual Diff test."""
- # Get arguments for perceptual diff.
- pixel_threshold = "10"
- alpha_threshold = "1.0"
- use_colorfactor = False
- use_downsample = False
- use_edge = True
- edge_threshold = "5"
-
- for opt in self.options:
- if opt.startswith("pdiff_threshold"):
- pixel_threshold = selenium_utilities.GetArgument(opt)
- elif (opt.startswith("pdiff_threshold_mac") and
- sys.platform == "darwin"):
- pixel_threshold = selenium_utilities.GetArgument(opt)
- elif (opt.startswith("pdiff_threshold_win") and
- sys.platform == 'win32' or sys.platform == "cygwin"):
- pixel_threshold = selenium_utilities.GetArgument(opt)
- elif (opt.startswith("pdiff_threshold_linux") and
- sys.platform[:5] == "linux"):
- pixel_threshold = selenium_utilities.GetArgument(opt)
- elif (opt.startswith("colorfactor")):
- colorfactor = selenium_utilities.GetArgument(opt)
- use_colorfactor = True
- elif (opt.startswith("downsample")):
- downsample_factor = selenium_utilities.GetArgument(opt)
- use_downsample = True
- elif (opt.startswith("pdiff_edge_ignore_off")):
- use_edge = False
- elif (opt.startswith("pdiff_edge_threshold")):
- edge_threshold = selenium_utilities.GetArgument(opt)
-
- results = []
- # Loop over number of screenshots.
- for screenshot_no in range(self.num_screenshots):
- # Find reference image.
- shotname = self.screenshot_name + str(screenshot_no + 1)
- J = os.path.join
- platform_img_path = J(self.ref_dir,
- selenium_constants.PLATFORM_SCREENSHOT_DIR,
- shotname + '_reference.png')
- reg_img_path = J(self.ref_dir,
- selenium_constants.DEFAULT_SCREENSHOT_DIR,
- shotname + '_reference.png')
-
- if os.path.exists(platform_img_path):
- ref_img_path = platform_img_path
- elif os.path.exists(reg_img_path):
- ref_img_path = reg_img_path
- else:
- self.fail('Reference image for ' + shotname + ' not found.')
-
- # Find generated image.
- gen_img_path = J(self.gen_dir, shotname + '.png')
- diff_img_path = J(self.gen_dir, 'cmp_' + shotname + '.png')
-
- self.assertTrue(os.path.exists(gen_img_path),
- 'Generated screenshot for ' + shotname + ' not found.\n')
-
- # Run perceptual diff
- arguments = [self.pdiff_path,
- ref_img_path,
- gen_img_path,
- "-output", diff_img_path,
- "-fov", "45",
- "-alphaThreshold", alpha_threshold,
- # Turn on verbose output for the percetual diff so we
- # can see how far off we are on the threshold.
- "-verbose",
- # Set the threshold to zero so we can get a count
- # of the different pixels. This causes the program
- # to return failure for most images, but we can compare
- # the values ourselves below.
- "-threshold", "0"]
- if use_colorfactor:
- arguments += ["-colorfactor", colorfactor]
- if use_downsample:
- arguments += ["-downsample", downsample_factor]
- if use_edge:
- arguments += ["-ignoreEdges", edge_threshold]
-
- pdiff_pipe = subprocess.Popen(arguments,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- (pdiff_stdout, pdiff_stderr) = pdiff_pipe.communicate()
- result = pdiff_pipe.returncode
- # Find out how many pixels were different by looking at the output.
- pixel_re = re.compile("(\d+) pixels are different", re.DOTALL)
- pixel_match = pixel_re.search(pdiff_stdout)
- different_pixels = "0"
- if pixel_match:
- different_pixels = pixel_match.group(1)
-
- results += [(shotname, int(different_pixels))]
-
- all_tests_passed = True
- msg = "Pixel threshold is %s. Failing screenshots:\n" % pixel_threshold
- for name, pixels in results:
- if pixels >= int(pixel_threshold):
- all_tests_passed = False
- msg += " %s, differing by %s\n" % (name, str(pixels))
-
- self.assertTrue(all_tests_passed, msg)
+import os
+import re
+import subprocess
+import unittest
+import sys
+
+import selenium_utilities
+import selenium_constants
+
+class PDiffTest(unittest.TestCase):
+ """A perceptual diff test class, for running perceptual diffs on any
+ number of screenshots."""
+
+ def __init__(self, name, num_screenshots, screenshot_name, pdiff_path,
+ gen_dir, ref_dir, options):
+ unittest.TestCase.__init__(self, name)
+ self.name = name
+ self.num_screenshots = num_screenshots
+ self.screenshot_name = screenshot_name
+ self.pdiff_path = pdiff_path
+ self.gen_dir = gen_dir
+ self.ref_dir = ref_dir
+ self.options = options
+
+ def shortDescription(self):
+ """override unittest.TestCase shortDescription for our own descriptions."""
+ return "Screenshot comparison for: " + self.name
+
+ def PDiffTest(self):
+ """Runs a generic Perceptual Diff test."""
+ # Get arguments for perceptual diff.
+ pixel_threshold = "10"
+ alpha_threshold = "1.0"
+ use_colorfactor = False
+ use_downsample = False
+ use_edge = True
+ edge_threshold = "5"
+
+ for opt in self.options:
+ if opt.startswith("pdiff_threshold"):
+ pixel_threshold = selenium_utilities.GetArgument(opt)
+ elif (opt.startswith("pdiff_threshold_mac") and
+ sys.platform == "darwin"):
+ pixel_threshold = selenium_utilities.GetArgument(opt)
+ elif (opt.startswith("pdiff_threshold_win") and
+ sys.platform == 'win32' or sys.platform == "cygwin"):
+ pixel_threshold = selenium_utilities.GetArgument(opt)
+ elif (opt.startswith("pdiff_threshold_linux") and
+ sys.platform[:5] == "linux"):
+ pixel_threshold = selenium_utilities.GetArgument(opt)
+ elif (opt.startswith("colorfactor")):
+ colorfactor = selenium_utilities.GetArgument(opt)
+ use_colorfactor = True
+ elif (opt.startswith("downsample")):
+ downsample_factor = selenium_utilities.GetArgument(opt)
+ use_downsample = True
+ elif (opt.startswith("pdiff_edge_ignore_off")):
+ use_edge = False
+ elif (opt.startswith("pdiff_edge_threshold")):
+ edge_threshold = selenium_utilities.GetArgument(opt)
+
+ results = []
+ # Loop over number of screenshots.
+ for screenshot_no in range(self.num_screenshots):
+ # Find reference image.
+ shotname = self.screenshot_name + str(screenshot_no + 1)
+ J = os.path.join
+ platform_img_path = J(self.ref_dir,
+ selenium_constants.PLATFORM_SCREENSHOT_DIR,
+ shotname + '_reference.png')
+ reg_img_path = J(self.ref_dir,
+ selenium_constants.DEFAULT_SCREENSHOT_DIR,
+ shotname + '_reference.png')
+
+ if os.path.exists(platform_img_path):
+ ref_img_path = platform_img_path
+ elif os.path.exists(reg_img_path):
+ ref_img_path = reg_img_path
+ else:
+ self.fail('Reference image for ' + shotname + ' not found.')
+
+ # Find generated image.
+ gen_img_path = J(self.gen_dir, shotname + '.png')
+ diff_img_path = J(self.gen_dir, 'cmp_' + shotname + '.png')
+
+ self.assertTrue(os.path.exists(gen_img_path),
+ 'Generated screenshot for ' + shotname + ' not found.\n')
+
+ # Run perceptual diff
+ arguments = [self.pdiff_path,
+ ref_img_path,
+ gen_img_path,
+ "-output", diff_img_path,
+ "-fov", "45",
+ "-alphaThreshold", alpha_threshold,
+ # Turn on verbose output for the percetual diff so we
+ # can see how far off we are on the threshold.
+ "-verbose",
+ # Set the threshold to zero so we can get a count
+ # of the different pixels. This causes the program
+ # to return failure for most images, but we can compare
+ # the values ourselves below.
+ "-threshold", "0"]
+ if use_colorfactor:
+ arguments += ["-colorfactor", colorfactor]
+ if use_downsample:
+ arguments += ["-downsample", downsample_factor]
+ if use_edge:
+ arguments += ["-ignoreEdges", edge_threshold]
+
+ pdiff_pipe = subprocess.Popen(arguments,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ (pdiff_stdout, pdiff_stderr) = pdiff_pipe.communicate()
+ result = pdiff_pipe.returncode
+ # Find out how many pixels were different by looking at the output.
+ pixel_re = re.compile("(\d+) pixels are different", re.DOTALL)
+ pixel_match = pixel_re.search(pdiff_stdout)
+ different_pixels = "0"
+ if pixel_match:
+ different_pixels = pixel_match.group(1)
+
+ results += [(shotname, int(different_pixels))]
+
+ all_tests_passed = True
+ msg = "Pixel threshold is %s. Failing screenshots:\n" % pixel_threshold
+ for name, pixels in results:
+ if pixels >= int(pixel_threshold):
+ all_tests_passed = False
+ msg += " %s, differing by %s\n" % (name, str(pixels))
+
+ self.assertTrue(all_tests_passed, msg)
diff --git a/o3d/tests/selenium/tests/render-target-clear-test.html b/o3d/tests/selenium/tests/render-target-clear-test.html
index 91c50b7..65ccbb1 100644
--- a/o3d/tests/selenium/tests/render-target-clear-test.html
+++ b/o3d/tests/selenium/tests/render-target-clear-test.html
@@ -1,156 +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.
--->
-<!--
-Tests that Render Targets clear correctly.
--->
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
- "http://www.w3.org/TR/html4/loose.dtd">
-<html>
-<head>
-<meta http-equiv="content-type" content="text/html; charset=UTF-8">
-<title>
-Render Target Clear Test.
-</title>
-<link rel="stylesheet" type="text/css" href="assets/style.css" />
-<!-- Include sample javascript library functions-->
-<script type="text/javascript" src="../../../samples/o3djs/base.js"></script>
-
-<!-- Our javascript code -->
-<script type="text/javascript" id="o3dscript">
-o3djs.require('o3djs.util');
-o3djs.require('o3djs.math');
-o3djs.require('o3djs.rendergraph');
-o3djs.require('o3djs.primitives');
-o3djs.require('o3djs.material');
-
-// Events
-// init() once the page has finished loading.
-// unload() when the page is unloaded.
-window.onload = init;
-window.onunload = unload;
-
-// global variables
-var g_o3dElement;
-var g_o3d;
-var g_math;
-var g_client;
-var g_viewInfo;
-var g_pack;
-var g_root;
-var g_o3dElement;
-
-/**
- * Creates the client area.
- */
-function init() {
- o3djs.util.makeClients(initStep2);
-}
-
-/**
- * Initializes O3D and creates one shape.
- * @param {Array} clientElements Array of o3d object elements.
- */
-function initStep2(clientElements) {
- // Initializes global variables and libraries.
- g_o3dElement = clientElements[0];
- g_o3d = g_o3dElement.o3d;
- g_math = o3djs.math;
- g_client = g_o3dElement.client;
-
- // Creates a pack to manage our resources/assets
- g_pack = g_client.createPack();
-
- g_root = g_pack.createObject('Transform');
-
- g_viewInfo = o3djs.rendergraph.createBasicView(
- g_pack,
- g_root,
- g_client.renderGraphRoot,
- [0.2, 0.3, 0.4, 1]);
-
- var clientWidth = g_client.width;
- var clientHeight = g_client.height;
- g_viewInfo.drawContext.projection = g_math.matrix4.orthographic(
- -clientWidth * 0.5 + 0.5,
- clientWidth * 0.5 + 0.5,
- -clientHeight * 0.5 + 0.5,
- clientHeight * 0.5 + 0.5,
- 0.001,
- 1000);
- g_viewInfo.drawContext.view = g_math.matrix4.lookAt(
- [0, 500, 0], // eye
- [0, 0, 0], // target
- [0, 0, -1]); // up
-
- for (var ii = 0; ii < 3; ++ii) {
- var texture = g_pack.createTexture2D(
- 256, 256, g_o3d.Texture.ARGB8, 1, true);
- var surface = texture.getRenderSurface(0);
- var renderSet = g_pack.createObject('RenderSurfaceSet');
- renderSet.renderSurface = surface;
- // Make render before the main display.
- renderSet.priority = -10 + ii;
-
- var material = o3djs.material.createConstantMaterial(
- g_pack, g_viewInfo, texture);
- var shape = o3djs.primitives.createPlane(g_pack, material, 128, 128, 1, 1);
- var transform = g_pack.createObject("Transform");
- transform.translate(-200 + 150 * ii, 0, 0);
- transform.parent = g_root;
- transform.addShape(shape);
- var clearColor = [0, 0, 0, 1];
- clearColor[ii] = 1;
- var viewInfo = o3djs.rendergraph.createBasicView(
- g_pack, null, renderSet, clearColor);
- // Splice it into the render graph AFTER everything is setup.
- renderSet.parent = g_client.renderGraphRoot;
- }
-
- window.g_testResult = true;
-}
-
-/**
- * Remove any callbacks so they don't get called after the page has unloaded.
- */
-function unload() {
- if (g_client) {
- g_client.cleanup();
- }
-}
-</script>
-</head>
-<body>
-<h1>Tests that render targets clear correctly.</h1>
-Should be red, green, blue on dark blue background.
-<div id="o3d" style="width: 600px; height: 600px"></div>
-</body>
-</html>
-
+<!--
+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.
+-->
+<!--
+Tests that Render Targets clear correctly.
+-->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<title>
+Render Target Clear Test.
+</title>
+<link rel="stylesheet" type="text/css" href="assets/style.css" />
+<!-- Include sample javascript library functions-->
+<script type="text/javascript" src="../../../samples/o3djs/base.js"></script>
+
+<!-- Our javascript code -->
+<script type="text/javascript" id="o3dscript">
+o3djs.require('o3djs.util');
+o3djs.require('o3djs.math');
+o3djs.require('o3djs.rendergraph');
+o3djs.require('o3djs.primitives');
+o3djs.require('o3djs.material');
+
+// Events
+// init() once the page has finished loading.
+// unload() when the page is unloaded.
+window.onload = init;
+window.onunload = unload;
+
+// global variables
+var g_o3dElement;
+var g_o3d;
+var g_math;
+var g_client;
+var g_viewInfo;
+var g_pack;
+var g_root;
+var g_o3dElement;
+
+/**
+ * Creates the client area.
+ */
+function init() {
+ o3djs.util.makeClients(initStep2);
+}
+
+/**
+ * Initializes O3D and creates one shape.
+ * @param {Array} clientElements Array of o3d object elements.
+ */
+function initStep2(clientElements) {
+ // Initializes global variables and libraries.
+ g_o3dElement = clientElements[0];
+ g_o3d = g_o3dElement.o3d;
+ g_math = o3djs.math;
+ g_client = g_o3dElement.client;
+
+ // Creates a pack to manage our resources/assets
+ g_pack = g_client.createPack();
+
+ g_root = g_pack.createObject('Transform');
+
+ g_viewInfo = o3djs.rendergraph.createBasicView(
+ g_pack,
+ g_root,
+ g_client.renderGraphRoot,
+ [0.2, 0.3, 0.4, 1]);
+
+ var clientWidth = g_client.width;
+ var clientHeight = g_client.height;
+ g_viewInfo.drawContext.projection = g_math.matrix4.orthographic(
+ -clientWidth * 0.5 + 0.5,
+ clientWidth * 0.5 + 0.5,
+ -clientHeight * 0.5 + 0.5,
+ clientHeight * 0.5 + 0.5,
+ 0.001,
+ 1000);
+ g_viewInfo.drawContext.view = g_math.matrix4.lookAt(
+ [0, 500, 0], // eye
+ [0, 0, 0], // target
+ [0, 0, -1]); // up
+
+ for (var ii = 0; ii < 3; ++ii) {
+ var texture = g_pack.createTexture2D(
+ 256, 256, g_o3d.Texture.ARGB8, 1, true);
+ var surface = texture.getRenderSurface(0);
+ var renderSet = g_pack.createObject('RenderSurfaceSet');
+ renderSet.renderSurface = surface;
+ // Make render before the main display.
+ renderSet.priority = -10 + ii;
+
+ var material = o3djs.material.createConstantMaterial(
+ g_pack, g_viewInfo, texture);
+ var shape = o3djs.primitives.createPlane(g_pack, material, 128, 128, 1, 1);
+ var transform = g_pack.createObject("Transform");
+ transform.translate(-200 + 150 * ii, 0, 0);
+ transform.parent = g_root;
+ transform.addShape(shape);
+ var clearColor = [0, 0, 0, 1];
+ clearColor[ii] = 1;
+ var viewInfo = o3djs.rendergraph.createBasicView(
+ g_pack, null, renderSet, clearColor);
+ // Splice it into the render graph AFTER everything is setup.
+ renderSet.parent = g_client.renderGraphRoot;
+ }
+
+ window.g_testResult = true;
+}
+
+/**
+ * Remove any callbacks so they don't get called after the page has unloaded.
+ */
+function unload() {
+ if (g_client) {
+ g_client.cleanup();
+ }
+}
+</script>
+</head>
+<body>
+<h1>Tests that render targets clear correctly.</h1>
+Should be red, green, blue on dark blue background.
+<div id="o3d" style="width: 600px; height: 600px"></div>
+</body>
+</html>
+
diff --git a/o3d/utils/cross/base64.h b/o3d/utils/cross/base64.h
index 6cc7762..eae0817 100644
--- a/o3d/utils/cross/base64.h
+++ b/o3d/utils/cross/base64.h
@@ -1,92 +1,92 @@
-/*
- * 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 contains the declaration of functions for dealing with base64
-// encoding and decoding
-
-#ifndef O3D_UTILS_CROSS_BASE64_H_
-#define O3D_UTILS_CROSS_BASE64_H_
-
-#include <stddef.h>
-
-namespace o3d {
-namespace base64 {
-
-// The possible error codes that can occur during a decoding.
-enum DecodeStatus {
- kSuccess,
- kPadError,
- kBadCharError,
- kOutputOverflowError
-};
-
-// Returns the number of bytes needed to encode length bytes in base64.
-size_t GetEncodeLength(size_t length);
-
-// Encodes the src into base64 into the dst. The dst must have enough
-// space to hold the result.
-// Parameters:
-// src: pointer to source data.
-// length: the length of the source data
-// dst: pointer to place to store result.
-void Encode(const void* src, size_t length, void* dst);
-
-// Used to obtain the number of bytes needed to decode the src data
-// from base64.
-// Parameters:
-// src: pointer to the source data.
-// input_length: the length of the source data
-// decode_length: the length in bytes of the decoded data will be
-// placed here.
-DecodeStatus GetDecodeLength(const void* src,
- size_t input_length,
- size_t* decode_length);
-
-// Decodes the src, which should be encoded in base64, into the dst.
-// dst must have enough space to hold the result. The number of bytes
-// necessary can be obtained by calling GetDecodeLength()
-// Parameters:
-// src: pointer to the source data
-// input_length: the length of the source data
-// dst: pointer to where the result should be stored.
-// dst_buffer_length: the size in bytes of the dst buffer. This is
-// used to check for buffer overflow.
-// Returns an error code (of type DecodeStatus)
-DecodeStatus Decode(const void* src,
- size_t input_length,
- void* dst,
- size_t dst_buffer_length);
-
-} // namespace base64
-} // namespace o3d
-
-#endif // O3D_UTILS_CROSS_BASE64_H_
-
+/*
+ * 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 contains the declaration of functions for dealing with base64
+// encoding and decoding
+
+#ifndef O3D_UTILS_CROSS_BASE64_H_
+#define O3D_UTILS_CROSS_BASE64_H_
+
+#include <stddef.h>
+
+namespace o3d {
+namespace base64 {
+
+// The possible error codes that can occur during a decoding.
+enum DecodeStatus {
+ kSuccess,
+ kPadError,
+ kBadCharError,
+ kOutputOverflowError
+};
+
+// Returns the number of bytes needed to encode length bytes in base64.
+size_t GetEncodeLength(size_t length);
+
+// Encodes the src into base64 into the dst. The dst must have enough
+// space to hold the result.
+// Parameters:
+// src: pointer to source data.
+// length: the length of the source data
+// dst: pointer to place to store result.
+void Encode(const void* src, size_t length, void* dst);
+
+// Used to obtain the number of bytes needed to decode the src data
+// from base64.
+// Parameters:
+// src: pointer to the source data.
+// input_length: the length of the source data
+// decode_length: the length in bytes of the decoded data will be
+// placed here.
+DecodeStatus GetDecodeLength(const void* src,
+ size_t input_length,
+ size_t* decode_length);
+
+// Decodes the src, which should be encoded in base64, into the dst.
+// dst must have enough space to hold the result. The number of bytes
+// necessary can be obtained by calling GetDecodeLength()
+// Parameters:
+// src: pointer to the source data
+// input_length: the length of the source data
+// dst: pointer to where the result should be stored.
+// dst_buffer_length: the size in bytes of the dst buffer. This is
+// used to check for buffer overflow.
+// Returns an error code (of type DecodeStatus)
+DecodeStatus Decode(const void* src,
+ size_t input_length,
+ void* dst,
+ size_t dst_buffer_length);
+
+} // namespace base64
+} // namespace o3d
+
+#endif // O3D_UTILS_CROSS_BASE64_H_
+
diff --git a/o3d/utils/cross/dataurl.h b/o3d/utils/cross/dataurl.h
index 7cb979a..c403388 100644
--- a/o3d/utils/cross/dataurl.h
+++ b/o3d/utils/cross/dataurl.h
@@ -1,70 +1,70 @@
-/*
- * 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 contains the declaration of functions for dealing with data urls.
-
-#ifndef O3D_UTILS_CROSS_DATAURL_H_
-#define O3D_UTILS_CROSS_DATAURL_H_
-
-#include "core/cross/types.h"
-#include "base/scoped_ptr.h"
-
-namespace o3d {
-namespace dataurl {
-
-// An empty data URL. ("data:,")
-extern const char* const kEmptyDataURL;
-
-// Creates a data URL for the given data.
-String ToDataURL(const String& mime_type, const void* data, size_t length);
-
-// Decodes the data from a data URL and stores a pointer to the data in
-// dst_buffer. If an error occurs in decoding, it returns false and
-// error_string will contain an error message. Otherwise, returns true.
-// Parameters:
-// data_url: The data URL from which to extract the data.
-// dst_buffer: A pointer to the output data will be stored in this
-// scoped_array.
-// output_length: The length of the output data will be stored at this
-// address.
-// error_string: This will contain the error message, if an error occurs.
-// Returns:
-// False if an error occurs in decoding, true otherwise.
-bool FromDataURL(const String& data_url,
- scoped_array<uint8>* dst_buffer,
- size_t* output_length,
- String* error_string);
-
-} // namespace dataurl
-} // namespace o3d
-
-#endif // O3D_UTILS_CROSS_DATAURL_H_
-
+/*
+ * 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 contains the declaration of functions for dealing with data urls.
+
+#ifndef O3D_UTILS_CROSS_DATAURL_H_
+#define O3D_UTILS_CROSS_DATAURL_H_
+
+#include "core/cross/types.h"
+#include "base/scoped_ptr.h"
+
+namespace o3d {
+namespace dataurl {
+
+// An empty data URL. ("data:,")
+extern const char* const kEmptyDataURL;
+
+// Creates a data URL for the given data.
+String ToDataURL(const String& mime_type, const void* data, size_t length);
+
+// Decodes the data from a data URL and stores a pointer to the data in
+// dst_buffer. If an error occurs in decoding, it returns false and
+// error_string will contain an error message. Otherwise, returns true.
+// Parameters:
+// data_url: The data URL from which to extract the data.
+// dst_buffer: A pointer to the output data will be stored in this
+// scoped_array.
+// output_length: The length of the output data will be stored at this
+// address.
+// error_string: This will contain the error message, if an error occurs.
+// Returns:
+// False if an error occurs in decoding, true otherwise.
+bool FromDataURL(const String& data_url,
+ scoped_array<uint8>* dst_buffer,
+ size_t* output_length,
+ String* error_string);
+
+} // namespace dataurl
+} // namespace o3d
+
+#endif // O3D_UTILS_CROSS_DATAURL_H_
+
diff --git a/o3d/utils/cross/math_gtest.h b/o3d/utils/cross/math_gtest.h
index 08ce096..e411eac 100644
--- a/o3d/utils/cross/math_gtest.h
+++ b/o3d/utils/cross/math_gtest.h
@@ -1,71 +1,71 @@
-/*
- * 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 declares the some helper for gtest for the math library used by
-// O3D.
-
-#ifndef O3D_UTILS_CROSS_MATH_GTEST_H_
-#define O3D_UTILS_CROSS_MATH_GTEST_H_
-
-#include <ostream> // NOLINT
-
-namespace Vectormath {
-namespace Aos {
-class Vector4;
-class Matrix4;
-
-bool operator==(const Vector4& left, const Vector4& right);
-bool operator!=(const Vector4& left, const Vector4& right);
-bool operator==(const Matrix4& left, const Matrix4& right);
-bool operator!=(const Matrix4& left, const Matrix4& right);
-std::ostream& operator<<(std::ostream& stream, const Vector4& value);
-std::ostream& operator<<(std::ostream& stream, const Matrix4& value);
-}
-}
-
-namespace o3d {
-class Float2;
-class Float3;
-class Float4;
-
-bool operator==(const Float2& left, const Float2& right);
-bool operator!=(const Float2& left, const Float2& right);
-bool operator==(const Float3& left, const Float3& right);
-bool operator!=(const Float3& left, const Float3& right);
-bool operator==(const Float4& left, const Float4& right);
-bool operator!=(const Float4& left, const Float4& right);
-std::ostream& operator<<(std::ostream& stream, const Float2& value);
-std::ostream& operator<<(std::ostream& stream, const Float3& value);
-std::ostream& operator<<(std::ostream& stream, const Float4& value);
-}
-
-#endif // O3D_UTILS_CROSS_MATH_GTEST_H_
-
+/*
+ * 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 declares the some helper for gtest for the math library used by
+// O3D.
+
+#ifndef O3D_UTILS_CROSS_MATH_GTEST_H_
+#define O3D_UTILS_CROSS_MATH_GTEST_H_
+
+#include <ostream> // NOLINT
+
+namespace Vectormath {
+namespace Aos {
+class Vector4;
+class Matrix4;
+
+bool operator==(const Vector4& left, const Vector4& right);
+bool operator!=(const Vector4& left, const Vector4& right);
+bool operator==(const Matrix4& left, const Matrix4& right);
+bool operator!=(const Matrix4& left, const Matrix4& right);
+std::ostream& operator<<(std::ostream& stream, const Vector4& value);
+std::ostream& operator<<(std::ostream& stream, const Matrix4& value);
+}
+}
+
+namespace o3d {
+class Float2;
+class Float3;
+class Float4;
+
+bool operator==(const Float2& left, const Float2& right);
+bool operator!=(const Float2& left, const Float2& right);
+bool operator==(const Float3& left, const Float3& right);
+bool operator!=(const Float3& left, const Float3& right);
+bool operator==(const Float4& left, const Float4& right);
+bool operator!=(const Float4& left, const Float4& right);
+std::ostream& operator<<(std::ostream& stream, const Float2& value);
+std::ostream& operator<<(std::ostream& stream, const Float3& value);
+std::ostream& operator<<(std::ostream& stream, const Float4& value);
+}
+
+#endif // O3D_UTILS_CROSS_MATH_GTEST_H_
+