diff options
author | apatrick@google.com <apatrick@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-12 19:56:24 +0000 |
---|---|---|
committer | apatrick@google.com <apatrick@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-12 19:56:24 +0000 |
commit | ccf02ac9bd67d4d49ad8264ae7fc6098e361ff4b (patch) | |
tree | fc6e4a0552431c7297798fad46f57fb76c35a3b3 /o3d | |
parent | dfe9d1d2de7fd8d244599b79a22898cce8df7c81 (diff) | |
download | chromium_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')
41 files changed, 8816 insertions, 8816 deletions
@@ -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_ + |