diff options
author | Alon Zakai <alonzakai@gmail.com> | 2013-04-10 15:53:50 -0700 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2013-04-10 15:53:50 -0700 |
commit | f84537c333524d0841923eaec66604584bf77326 (patch) | |
tree | 6a43fab885a397a80de2cd8117b6ebafdb00cdf5 /tests/box2d | |
parent | a4a20535e79f10c553b685b188fcfd6af12fac07 (diff) |
more work towards box2d benchmark
Diffstat (limited to 'tests/box2d')
239 files changed, 78429 insertions, 0 deletions
diff --git a/tests/box2d/Benchmark.cpp b/tests/box2d/Benchmark.cpp new file mode 100644 index 00000000..914c13a0 --- /dev/null +++ b/tests/box2d/Benchmark.cpp @@ -0,0 +1,122 @@ + + +// +// Based on joelgwebber's Box2D benchmarks, +// https://github.com/joelgwebber/bench2d/blob/master/c/Bench2d.cpp +// + + +// Settings ===================== +// Turn this on to include the y-position of the top box in the output. +#define DEBUG 0 + +#define WARMUP 64 +#define FRAMES 256 + +typedef struct { + float mean; + float stddev; +} result_t; +// ============================== + + + +#include <cstdio> +#include <time.h> +#include <math.h> + +#include "Box2D/Box2D.h" +#include "Bench2d.h" + +using namespace std; + +const int e_count = 40; + +result_t measure(clock_t times[FRAMES]) { + float values[FRAMES]; + result_t r; + + float total = 0; + for (int i = 0; i < FRAMES; ++i) { + values[i] = (float)times[i] / CLOCKS_PER_SEC * 1000; + total += values[i]; + } + r.mean = total / FRAMES; + + float variance = 0; + for (int i = 0; i < FRAMES; ++i) { + float diff = values[i] - r.mean; + variance += diff * diff; + } + r.stddev = sqrt(variance / FRAMES); + + return r; +} + +result_t bench() { + // Define the gravity vector. + b2Vec2 gravity(0.0f, -10.0f); + + // Construct a world object, which will hold and simulate the rigid bodies. + b2World world(gravity); + world.SetAllowSleeping(false); + + { + b2BodyDef bd; + b2Body* ground = world.CreateBody(&bd); + + b2EdgeShape shape; + shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f)); + ground->CreateFixture(&shape, 0.0f); + } + + b2Body* topBody; + + { + float32 a = 0.5f; + b2PolygonShape shape; + shape.SetAsBox(a, a); + + b2Vec2 x(-7.0f, 0.75f); + b2Vec2 y; + b2Vec2 deltaX(0.5625f, 1); + b2Vec2 deltaY(1.125f, 0.0f); + + for (int32 i = 0; i < e_count; ++i) { + y = x; + + for (int32 j = i; j < e_count; ++j) { + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position = y; + b2Body* body = world.CreateBody(&bd); + body->CreateFixture(&shape, 5.0f); + + topBody = body; + + y += deltaY; + } + + x += deltaX; + } + } + + for (int32 i = 0; i < WARMUP; ++i) { + world.Step(1.0f/60.0f, 3, 3); + } + + clock_t times[FRAMES]; + for (int32 i = 0; i < FRAMES; ++i) { + clock_t start = clock(); + world.Step(1.0f/60.0f, 3, 3); + clock_t end = clock(); + times[i] = end - start; +#if DEBUG + printf("%f :: ", topBody->GetPosition().y); + printf("%f\n", (float32)(end - start) / CLOCKS_PER_SEC * 1000); +#endif + } + + return measure(times); +} + diff --git a/tests/box2d/Box2D/Box2D.h b/tests/box2d/Box2D/Box2D.h new file mode 100755 index 00000000..66d22174 --- /dev/null +++ b/tests/box2d/Box2D/Box2D.h @@ -0,0 +1,67 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef BOX2D_H
+#define BOX2D_H
+
+/**
+\mainpage Box2D API Documentation
+
+\section intro_sec Getting Started
+
+For documentation please see http://box2d.org/documentation.html
+
+For discussion please visit http://box2d.org/forum
+*/
+
+// These include files constitute the main Box2D API
+
+#include <Box2D/Common/b2Settings.h>
+#include <Box2D/Common/b2Draw.h>
+#include <Box2D/Common/b2Timer.h>
+
+#include <Box2D/Collision/Shapes/b2CircleShape.h>
+#include <Box2D/Collision/Shapes/b2EdgeShape.h>
+#include <Box2D/Collision/Shapes/b2ChainShape.h>
+#include <Box2D/Collision/Shapes/b2PolygonShape.h>
+
+#include <Box2D/Collision/b2BroadPhase.h>
+#include <Box2D/Collision/b2Distance.h>
+#include <Box2D/Collision/b2DynamicTree.h>
+#include <Box2D/Collision/b2TimeOfImpact.h>
+
+#include <Box2D/Dynamics/b2Body.h>
+#include <Box2D/Dynamics/b2Fixture.h>
+#include <Box2D/Dynamics/b2WorldCallbacks.h>
+#include <Box2D/Dynamics/b2TimeStep.h>
+#include <Box2D/Dynamics/b2World.h>
+
+#include <Box2D/Dynamics/Contacts/b2Contact.h>
+
+#include <Box2D/Dynamics/Joints/b2DistanceJoint.h>
+#include <Box2D/Dynamics/Joints/b2FrictionJoint.h>
+#include <Box2D/Dynamics/Joints/b2GearJoint.h>
+#include <Box2D/Dynamics/Joints/b2WheelJoint.h>
+#include <Box2D/Dynamics/Joints/b2MouseJoint.h>
+#include <Box2D/Dynamics/Joints/b2PrismaticJoint.h>
+#include <Box2D/Dynamics/Joints/b2PulleyJoint.h>
+#include <Box2D/Dynamics/Joints/b2RevoluteJoint.h>
+#include <Box2D/Dynamics/Joints/b2RopeJoint.h>
+#include <Box2D/Dynamics/Joints/b2WeldJoint.h>
+
+#endif
diff --git a/tests/box2d/Box2D/Box2DConfig.cmake b/tests/box2d/Box2D/Box2DConfig.cmake new file mode 100755 index 00000000..b567c17d --- /dev/null +++ b/tests/box2d/Box2D/Box2DConfig.cmake @@ -0,0 +1,3 @@ +get_filename_component(SELF_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
+include(${SELF_DIR}/Box2D-targets.cmake)
+get_filename_component(Box2D_INCLUDE_DIRS "${SELF_DIR}/../../include" ABSOLUTE)
diff --git a/tests/box2d/Box2D/CMakeLists.txt b/tests/box2d/Box2D/CMakeLists.txt new file mode 100755 index 00000000..445c248a --- /dev/null +++ b/tests/box2d/Box2D/CMakeLists.txt @@ -0,0 +1,205 @@ +set(BOX2D_Collision_SRCS + Collision/b2BroadPhase.cpp + Collision/b2CollideCircle.cpp + Collision/b2CollideEdge.cpp + Collision/b2CollidePolygon.cpp + Collision/b2Collision.cpp + Collision/b2Distance.cpp + Collision/b2DynamicTree.cpp + Collision/b2TimeOfImpact.cpp +) +set(BOX2D_Collision_HDRS + Collision/b2BroadPhase.h + Collision/b2Collision.h + Collision/b2Distance.h + Collision/b2DynamicTree.h + Collision/b2TimeOfImpact.h +) +set(BOX2D_Shapes_SRCS + Collision/Shapes/b2CircleShape.cpp + Collision/Shapes/b2EdgeShape.cpp + Collision/Shapes/b2ChainShape.cpp + Collision/Shapes/b2PolygonShape.cpp +) +set(BOX2D_Shapes_HDRS + Collision/Shapes/b2CircleShape.h + Collision/Shapes/b2EdgeShape.h + Collision/Shapes/b2ChainShape.h + Collision/Shapes/b2PolygonShape.h + Collision/Shapes/b2Shape.h +) +set(BOX2D_Common_SRCS + Common/b2BlockAllocator.cpp + Common/b2Draw.cpp + Common/b2Math.cpp + Common/b2Settings.cpp + Common/b2StackAllocator.cpp + Common/b2Timer.cpp +) +set(BOX2D_Common_HDRS + Common/b2BlockAllocator.h + Common/b2Draw.h + Common/b2GrowableStack.h + Common/b2Math.h + Common/b2Settings.h + Common/b2StackAllocator.h + Common/b2Timer.h +) +set(BOX2D_Dynamics_SRCS + Dynamics/b2Body.cpp + Dynamics/b2ContactManager.cpp + Dynamics/b2Fixture.cpp + Dynamics/b2Island.cpp + Dynamics/b2World.cpp + Dynamics/b2WorldCallbacks.cpp +) +set(BOX2D_Dynamics_HDRS + Dynamics/b2Body.h + Dynamics/b2ContactManager.h + Dynamics/b2Fixture.h + Dynamics/b2Island.h + Dynamics/b2TimeStep.h + Dynamics/b2World.h + Dynamics/b2WorldCallbacks.h +) +set(BOX2D_Contacts_SRCS + Dynamics/Contacts/b2CircleContact.cpp + Dynamics/Contacts/b2Contact.cpp + Dynamics/Contacts/b2ContactSolver.cpp + Dynamics/Contacts/b2PolygonAndCircleContact.cpp + Dynamics/Contacts/b2EdgeAndCircleContact.cpp + Dynamics/Contacts/b2EdgeAndPolygonContact.cpp + Dynamics/Contacts/b2ChainAndCircleContact.cpp + Dynamics/Contacts/b2ChainAndPolygonContact.cpp + Dynamics/Contacts/b2PolygonContact.cpp +) +set(BOX2D_Contacts_HDRS + Dynamics/Contacts/b2CircleContact.h + Dynamics/Contacts/b2Contact.h + Dynamics/Contacts/b2ContactSolver.h + Dynamics/Contacts/b2PolygonAndCircleContact.h + Dynamics/Contacts/b2EdgeAndCircleContact.h + Dynamics/Contacts/b2EdgeAndPolygonContact.h + Dynamics/Contacts/b2ChainAndCircleContact.h + Dynamics/Contacts/b2ChainAndPolygonContact.h + Dynamics/Contacts/b2PolygonContact.h +) +set(BOX2D_Joints_SRCS + Dynamics/Joints/b2DistanceJoint.cpp + Dynamics/Joints/b2FrictionJoint.cpp + Dynamics/Joints/b2GearJoint.cpp + Dynamics/Joints/b2Joint.cpp + Dynamics/Joints/b2MouseJoint.cpp + Dynamics/Joints/b2PrismaticJoint.cpp + Dynamics/Joints/b2PulleyJoint.cpp + Dynamics/Joints/b2RevoluteJoint.cpp + Dynamics/Joints/b2RopeJoint.cpp + Dynamics/Joints/b2WeldJoint.cpp + Dynamics/Joints/b2WheelJoint.cpp +) +set(BOX2D_Joints_HDRS + Dynamics/Joints/b2DistanceJoint.h + Dynamics/Joints/b2FrictionJoint.h + Dynamics/Joints/b2GearJoint.h + Dynamics/Joints/b2Joint.h + Dynamics/Joints/b2MouseJoint.h + Dynamics/Joints/b2PrismaticJoint.h + Dynamics/Joints/b2PulleyJoint.h + Dynamics/Joints/b2RevoluteJoint.h + Dynamics/Joints/b2RopeJoint.h + Dynamics/Joints/b2WeldJoint.h + Dynamics/Joints/b2WheelJoint.h +) +set(BOX2D_Rope_SRCS + Rope/b2Rope.cpp +) +set(BOX2D_Rope_HDRS + Rope/b2Rope.h +) +set(BOX2D_General_HDRS + Box2D.h +) +include_directories( ../ ) + +if(BOX2D_BUILD_SHARED) + add_library(Box2D_shared SHARED + ${BOX2D_General_HDRS} + ${BOX2D_Joints_SRCS} + ${BOX2D_Joints_HDRS} + ${BOX2D_Contacts_SRCS} + ${BOX2D_Contacts_HDRS} + ${BOX2D_Dynamics_SRCS} + ${BOX2D_Dynamics_HDRS} + ${BOX2D_Common_SRCS} + ${BOX2D_Common_HDRS} + ${BOX2D_Shapes_SRCS} + ${BOX2D_Shapes_HDRS} + ${BOX2D_Collision_SRCS} + ${BOX2D_Collision_HDRS} + ${BOX2D_Rope_SRCS} + ${BOX2D_Rope_HDRS} + ) + set_target_properties(Box2D_shared PROPERTIES + OUTPUT_NAME "Box2D" + CLEAN_DIRECT_OUTPUT 1 + VERSION ${BOX2D_VERSION} + ) +endif() + +if(BOX2D_BUILD_STATIC) + add_library(Box2D STATIC + ${BOX2D_General_HDRS} + ${BOX2D_Joints_SRCS} + ${BOX2D_Joints_HDRS} + ${BOX2D_Contacts_SRCS} + ${BOX2D_Contacts_HDRS} + ${BOX2D_Dynamics_SRCS} + ${BOX2D_Dynamics_HDRS} + ${BOX2D_Common_SRCS} + ${BOX2D_Common_HDRS} + ${BOX2D_Shapes_SRCS} + ${BOX2D_Shapes_HDRS} + ${BOX2D_Collision_SRCS} + ${BOX2D_Collision_HDRS} + ${BOX2D_Rope_SRCS} + ${BOX2D_Rope_HDRS} + ) + set_target_properties(Box2D PROPERTIES + CLEAN_DIRECT_OUTPUT 1 + VERSION ${BOX2D_VERSION} + ) +endif() + +# These are used to create visual studio folders. +source_group(Collision FILES ${BOX2D_Collision_SRCS} ${BOX2D_Collision_HDRS}) +source_group(Collision\\Shapes FILES ${BOX2D_Shapes_SRCS} ${BOX2D_Shapes_HDRS}) +source_group(Common FILES ${BOX2D_Common_SRCS} ${BOX2D_Common_HDRS}) +source_group(Dynamics FILES ${BOX2D_Dynamics_SRCS} ${BOX2D_Dynamics_HDRS}) +source_group(Dynamics\\Contacts FILES ${BOX2D_Contacts_SRCS} ${BOX2D_Contacts_HDRS}) +source_group(Dynamics\\Joints FILES ${BOX2D_Joints_SRCS} ${BOX2D_Joints_HDRS}) +source_group(Include FILES ${BOX2D_General_HDRS}) +source_group(Rope FILES ${BOX2D_Rope_SRCS} ${BOX2D_Rope_HDRS}) + +if(BOX2D_INSTALL) + # install headers + install(FILES ${BOX2D_General_HDRS} DESTINATION include/Box2D) + install(FILES ${BOX2D_Collision_HDRS} DESTINATION include/Box2D/Collision) + install(FILES ${BOX2D_Shapes_HDRS} DESTINATION include/Box2D/Collision/Shapes) + install(FILES ${BOX2D_Common_HDRS} DESTINATION include/Box2D/Common) + install(FILES ${BOX2D_Dynamics_HDRS} DESTINATION include/Box2D/Dynamics) + install(FILES ${BOX2D_Contacts_HDRS} DESTINATION include/Box2D/Dynamics/Contacts) + install(FILES ${BOX2D_Joints_HDRS} DESTINATION include/Box2D/Dynamics/Joints) + install(FILES ${BOX2D_Rope_HDRS} DESTINATION include/Box2D/Rope) + + # install libraries + if(BOX2D_BUILD_SHARED) + install(TARGETS Box2D_shared EXPORT Box2D-targets DESTINATION lib) + endif() + if(BOX2D_BUILD_STATIC) + install(TARGETS Box2D EXPORT Box2D-targets DESTINATION lib) + endif() + + # install build system hooks for third-party apps + install(EXPORT Box2D-targets DESTINATION lib/Box2D) + install(FILES Box2DConfig.cmake DESTINATION lib/Box2D) +endif(BOX2D_INSTALL)
\ No newline at end of file diff --git a/tests/box2d/Box2D/Collision/Shapes/b2ChainShape.cpp b/tests/box2d/Box2D/Collision/Shapes/b2ChainShape.cpp new file mode 100755 index 00000000..f7bbe06b --- /dev/null +++ b/tests/box2d/Box2D/Collision/Shapes/b2ChainShape.cpp @@ -0,0 +1,171 @@ +/*
+* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Collision/Shapes/b2ChainShape.h>
+#include <Box2D/Collision/Shapes/b2EdgeShape.h>
+#include <new>
+#include <cstring>
+using namespace std;
+
+b2ChainShape::~b2ChainShape()
+{
+ b2Free(m_vertices);
+ m_vertices = NULL;
+ m_count = 0;
+}
+
+void b2ChainShape::CreateLoop(const b2Vec2* vertices, int32 count)
+{
+ b2Assert(m_vertices == NULL && m_count == 0);
+ b2Assert(count >= 3);
+ m_count = count + 1;
+ m_vertices = (b2Vec2*)b2Alloc(m_count * sizeof(b2Vec2));
+ memcpy(m_vertices, vertices, count * sizeof(b2Vec2));
+ m_vertices[count] = m_vertices[0];
+ m_prevVertex = m_vertices[m_count - 2];
+ m_nextVertex = m_vertices[1];
+ m_hasPrevVertex = true;
+ m_hasNextVertex = true;
+}
+
+void b2ChainShape::CreateChain(const b2Vec2* vertices, int32 count)
+{
+ b2Assert(m_vertices == NULL && m_count == 0);
+ b2Assert(count >= 2);
+ m_count = count;
+ m_vertices = (b2Vec2*)b2Alloc(count * sizeof(b2Vec2));
+ memcpy(m_vertices, vertices, m_count * sizeof(b2Vec2));
+ m_hasPrevVertex = false;
+ m_hasNextVertex = false;
+}
+
+void b2ChainShape::SetPrevVertex(const b2Vec2& prevVertex)
+{
+ m_prevVertex = prevVertex;
+ m_hasPrevVertex = true;
+}
+
+void b2ChainShape::SetNextVertex(const b2Vec2& nextVertex)
+{
+ m_nextVertex = nextVertex;
+ m_hasNextVertex = true;
+}
+
+b2Shape* b2ChainShape::Clone(b2BlockAllocator* allocator) const
+{
+ void* mem = allocator->Allocate(sizeof(b2ChainShape));
+ b2ChainShape* clone = new (mem) b2ChainShape;
+ clone->CreateChain(m_vertices, m_count);
+ clone->m_prevVertex = m_prevVertex;
+ clone->m_nextVertex = m_nextVertex;
+ clone->m_hasPrevVertex = m_hasPrevVertex;
+ clone->m_hasNextVertex = m_hasNextVertex;
+ return clone;
+}
+
+int32 b2ChainShape::GetChildCount() const
+{
+ // edge count = vertex count - 1
+ return m_count - 1;
+}
+
+void b2ChainShape::GetChildEdge(b2EdgeShape* edge, int32 index) const
+{
+ b2Assert(0 <= index && index < m_count - 1);
+ edge->m_type = b2Shape::e_edge;
+ edge->m_radius = m_radius;
+
+ edge->m_vertex1 = m_vertices[index + 0];
+ edge->m_vertex2 = m_vertices[index + 1];
+
+ if (index > 0)
+ {
+ edge->m_vertex0 = m_vertices[index - 1];
+ edge->m_hasVertex0 = true;
+ }
+ else
+ {
+ edge->m_vertex0 = m_prevVertex;
+ edge->m_hasVertex0 = m_hasPrevVertex;
+ }
+
+ if (index < m_count - 2)
+ {
+ edge->m_vertex3 = m_vertices[index + 2];
+ edge->m_hasVertex3 = true;
+ }
+ else
+ {
+ edge->m_vertex3 = m_nextVertex;
+ edge->m_hasVertex3 = m_hasNextVertex;
+ }
+}
+
+bool b2ChainShape::TestPoint(const b2Transform& xf, const b2Vec2& p) const
+{
+ B2_NOT_USED(xf);
+ B2_NOT_USED(p);
+ return false;
+}
+
+bool b2ChainShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
+ const b2Transform& xf, int32 childIndex) const
+{
+ b2Assert(childIndex < m_count);
+
+ b2EdgeShape edgeShape;
+
+ int32 i1 = childIndex;
+ int32 i2 = childIndex + 1;
+ if (i2 == m_count)
+ {
+ i2 = 0;
+ }
+
+ edgeShape.m_vertex1 = m_vertices[i1];
+ edgeShape.m_vertex2 = m_vertices[i2];
+
+ return edgeShape.RayCast(output, input, xf, 0);
+}
+
+void b2ChainShape::ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const
+{
+ b2Assert(childIndex < m_count);
+
+ int32 i1 = childIndex;
+ int32 i2 = childIndex + 1;
+ if (i2 == m_count)
+ {
+ i2 = 0;
+ }
+
+ b2Vec2 v1 = b2Mul(xf, m_vertices[i1]);
+ b2Vec2 v2 = b2Mul(xf, m_vertices[i2]);
+
+ aabb->lowerBound = b2Min(v1, v2);
+ aabb->upperBound = b2Max(v1, v2);
+}
+
+void b2ChainShape::ComputeMass(b2MassData* massData, float32 density) const
+{
+ B2_NOT_USED(density);
+
+ massData->mass = 0.0f;
+ massData->center.SetZero();
+ massData->I = 0.0f;
+}
diff --git a/tests/box2d/Box2D/Collision/Shapes/b2ChainShape.h b/tests/box2d/Box2D/Collision/Shapes/b2ChainShape.h new file mode 100755 index 00000000..6aa41ea4 --- /dev/null +++ b/tests/box2d/Box2D/Collision/Shapes/b2ChainShape.h @@ -0,0 +1,102 @@ +/*
+* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_CHAIN_SHAPE_H
+#define B2_CHAIN_SHAPE_H
+
+#include <Box2D/Collision/Shapes/b2Shape.h>
+
+class b2EdgeShape;
+
+/// A chain shape is a free form sequence of line segments.
+/// The chain has two-sided collision, so you can use inside and outside collision.
+/// Therefore, you may use any winding order.
+/// Since there may be many vertices, they are allocated using b2Alloc.
+/// Connectivity information is used to create smooth collisions.
+/// WARNING: The chain will not collide properly if there are self-intersections.
+class b2ChainShape : public b2Shape
+{
+public:
+ b2ChainShape();
+
+ /// The destructor frees the vertices using b2Free.
+ ~b2ChainShape();
+
+ /// Create a loop. This automatically adjusts connectivity.
+ /// @param vertices an array of vertices, these are copied
+ /// @param count the vertex count
+ void CreateLoop(const b2Vec2* vertices, int32 count);
+
+ /// Create a chain with isolated end vertices.
+ /// @param vertices an array of vertices, these are copied
+ /// @param count the vertex count
+ void CreateChain(const b2Vec2* vertices, int32 count);
+
+ /// Establish connectivity to a vertex that precedes the first vertex.
+ /// Don't call this for loops.
+ void SetPrevVertex(const b2Vec2& prevVertex);
+
+ /// Establish connectivity to a vertex that follows the last vertex.
+ /// Don't call this for loops.
+ void SetNextVertex(const b2Vec2& nextVertex);
+
+ /// Implement b2Shape. Vertices are cloned using b2Alloc.
+ b2Shape* Clone(b2BlockAllocator* allocator) const;
+
+ /// @see b2Shape::GetChildCount
+ int32 GetChildCount() const;
+
+ /// Get a child edge.
+ void GetChildEdge(b2EdgeShape* edge, int32 index) const;
+
+ /// This always return false.
+ /// @see b2Shape::TestPoint
+ bool TestPoint(const b2Transform& transform, const b2Vec2& p) const;
+
+ /// Implement b2Shape.
+ bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
+ const b2Transform& transform, int32 childIndex) const;
+
+ /// @see b2Shape::ComputeAABB
+ void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const;
+
+ /// Chains have zero mass.
+ /// @see b2Shape::ComputeMass
+ void ComputeMass(b2MassData* massData, float32 density) const;
+
+ /// The vertices. Owned by this class.
+ b2Vec2* m_vertices;
+
+ /// The vertex count.
+ int32 m_count;
+
+ b2Vec2 m_prevVertex, m_nextVertex;
+ bool m_hasPrevVertex, m_hasNextVertex;
+};
+
+inline b2ChainShape::b2ChainShape()
+{
+ m_type = e_chain;
+ m_radius = b2_polygonRadius;
+ m_vertices = NULL;
+ m_count = 0;
+ m_hasPrevVertex = NULL;
+ m_hasNextVertex = NULL;
+}
+
+#endif
diff --git a/tests/box2d/Box2D/Collision/Shapes/b2CircleShape.cpp b/tests/box2d/Box2D/Collision/Shapes/b2CircleShape.cpp new file mode 100755 index 00000000..c03d662d --- /dev/null +++ b/tests/box2d/Box2D/Collision/Shapes/b2CircleShape.cpp @@ -0,0 +1,100 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Collision/Shapes/b2CircleShape.h>
+#include <new>
+using namespace std;
+
+b2Shape* b2CircleShape::Clone(b2BlockAllocator* allocator) const
+{
+ void* mem = allocator->Allocate(sizeof(b2CircleShape));
+ b2CircleShape* clone = new (mem) b2CircleShape;
+ *clone = *this;
+ return clone;
+}
+
+int32 b2CircleShape::GetChildCount() const
+{
+ return 1;
+}
+
+bool b2CircleShape::TestPoint(const b2Transform& transform, const b2Vec2& p) const
+{
+ b2Vec2 center = transform.p + b2Mul(transform.q, m_p);
+ b2Vec2 d = p - center;
+ return b2Dot(d, d) <= m_radius * m_radius;
+}
+
+// Collision Detection in Interactive 3D Environments by Gino van den Bergen
+// From Section 3.1.2
+// x = s + a * r
+// norm(x) = radius
+bool b2CircleShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
+ const b2Transform& transform, int32 childIndex) const
+{
+ B2_NOT_USED(childIndex);
+
+ b2Vec2 position = transform.p + b2Mul(transform.q, m_p);
+ b2Vec2 s = input.p1 - position;
+ float32 b = b2Dot(s, s) - m_radius * m_radius;
+
+ // Solve quadratic equation.
+ b2Vec2 r = input.p2 - input.p1;
+ float32 c = b2Dot(s, r);
+ float32 rr = b2Dot(r, r);
+ float32 sigma = c * c - rr * b;
+
+ // Check for negative discriminant and short segment.
+ if (sigma < 0.0f || rr < b2_epsilon)
+ {
+ return false;
+ }
+
+ // Find the point of intersection of the line with the circle.
+ float32 a = -(c + b2Sqrt(sigma));
+
+ // Is the intersection point on the segment?
+ if (0.0f <= a && a <= input.maxFraction * rr)
+ {
+ a /= rr;
+ output->fraction = a;
+ output->normal = s + a * r;
+ output->normal.Normalize();
+ return true;
+ }
+
+ return false;
+}
+
+void b2CircleShape::ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const
+{
+ B2_NOT_USED(childIndex);
+
+ b2Vec2 p = transform.p + b2Mul(transform.q, m_p);
+ aabb->lowerBound.Set(p.x - m_radius, p.y - m_radius);
+ aabb->upperBound.Set(p.x + m_radius, p.y + m_radius);
+}
+
+void b2CircleShape::ComputeMass(b2MassData* massData, float32 density) const
+{
+ massData->mass = density * b2_pi * m_radius * m_radius;
+ massData->center = m_p;
+
+ // inertia about the local origin
+ massData->I = massData->mass * (0.5f * m_radius * m_radius + b2Dot(m_p, m_p));
+}
diff --git a/tests/box2d/Box2D/Collision/Shapes/b2CircleShape.h b/tests/box2d/Box2D/Collision/Shapes/b2CircleShape.h new file mode 100755 index 00000000..6c1fd543 --- /dev/null +++ b/tests/box2d/Box2D/Collision/Shapes/b2CircleShape.h @@ -0,0 +1,91 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_CIRCLE_SHAPE_H
+#define B2_CIRCLE_SHAPE_H
+
+#include <Box2D/Collision/Shapes/b2Shape.h>
+
+/// A circle shape.
+class b2CircleShape : public b2Shape
+{
+public:
+ b2CircleShape();
+
+ /// Implement b2Shape.
+ b2Shape* Clone(b2BlockAllocator* allocator) const;
+
+ /// @see b2Shape::GetChildCount
+ int32 GetChildCount() const;
+
+ /// Implement b2Shape.
+ bool TestPoint(const b2Transform& transform, const b2Vec2& p) const;
+
+ /// Implement b2Shape.
+ bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
+ const b2Transform& transform, int32 childIndex) const;
+
+ /// @see b2Shape::ComputeAABB
+ void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const;
+
+ /// @see b2Shape::ComputeMass
+ void ComputeMass(b2MassData* massData, float32 density) const;
+
+ /// Get the supporting vertex index in the given direction.
+ int32 GetSupport(const b2Vec2& d) const;
+
+ /// Get the supporting vertex in the given direction.
+ const b2Vec2& GetSupportVertex(const b2Vec2& d) const;
+
+ /// Get the vertex count.
+ int32 GetVertexCount() const { return 1; }
+
+ /// Get a vertex by index. Used by b2Distance.
+ const b2Vec2& GetVertex(int32 index) const;
+
+ /// Position
+ b2Vec2 m_p;
+};
+
+inline b2CircleShape::b2CircleShape()
+{
+ m_type = e_circle;
+ m_radius = 0.0f;
+ m_p.SetZero();
+}
+
+inline int32 b2CircleShape::GetSupport(const b2Vec2 &d) const
+{
+ B2_NOT_USED(d);
+ return 0;
+}
+
+inline const b2Vec2& b2CircleShape::GetSupportVertex(const b2Vec2 &d) const
+{
+ B2_NOT_USED(d);
+ return m_p;
+}
+
+inline const b2Vec2& b2CircleShape::GetVertex(int32 index) const
+{
+ B2_NOT_USED(index);
+ b2Assert(index == 0);
+ return m_p;
+}
+
+#endif
diff --git a/tests/box2d/Box2D/Collision/Shapes/b2EdgeShape.cpp b/tests/box2d/Box2D/Collision/Shapes/b2EdgeShape.cpp new file mode 100755 index 00000000..e204160b --- /dev/null +++ b/tests/box2d/Box2D/Collision/Shapes/b2EdgeShape.cpp @@ -0,0 +1,139 @@ +/*
+* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Collision/Shapes/b2EdgeShape.h>
+#include <new>
+using namespace std;
+
+void b2EdgeShape::Set(const b2Vec2& v1, const b2Vec2& v2)
+{
+ m_vertex1 = v1;
+ m_vertex2 = v2;
+ m_hasVertex0 = false;
+ m_hasVertex3 = false;
+}
+
+b2Shape* b2EdgeShape::Clone(b2BlockAllocator* allocator) const
+{
+ void* mem = allocator->Allocate(sizeof(b2EdgeShape));
+ b2EdgeShape* clone = new (mem) b2EdgeShape;
+ *clone = *this;
+ return clone;
+}
+
+int32 b2EdgeShape::GetChildCount() const
+{
+ return 1;
+}
+
+bool b2EdgeShape::TestPoint(const b2Transform& xf, const b2Vec2& p) const
+{
+ B2_NOT_USED(xf);
+ B2_NOT_USED(p);
+ return false;
+}
+
+// p = p1 + t * d
+// v = v1 + s * e
+// p1 + t * d = v1 + s * e
+// s * e - t * d = p1 - v1
+bool b2EdgeShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
+ const b2Transform& xf, int32 childIndex) const
+{
+ B2_NOT_USED(childIndex);
+
+ // Put the ray into the edge's frame of reference.
+ b2Vec2 p1 = b2MulT(xf.q, input.p1 - xf.p);
+ b2Vec2 p2 = b2MulT(xf.q, input.p2 - xf.p);
+ b2Vec2 d = p2 - p1;
+
+ b2Vec2 v1 = m_vertex1;
+ b2Vec2 v2 = m_vertex2;
+ b2Vec2 e = v2 - v1;
+ b2Vec2 normal(e.y, -e.x);
+ normal.Normalize();
+
+ // q = p1 + t * d
+ // dot(normal, q - v1) = 0
+ // dot(normal, p1 - v1) + t * dot(normal, d) = 0
+ float32 numerator = b2Dot(normal, v1 - p1);
+ float32 denominator = b2Dot(normal, d);
+
+ if (denominator == 0.0f)
+ {
+ return false;
+ }
+
+ float32 t = numerator / denominator;
+ if (t < 0.0f || input.maxFraction < t)
+ {
+ return false;
+ }
+
+ b2Vec2 q = p1 + t * d;
+
+ // q = v1 + s * r
+ // s = dot(q - v1, r) / dot(r, r)
+ b2Vec2 r = v2 - v1;
+ float32 rr = b2Dot(r, r);
+ if (rr == 0.0f)
+ {
+ return false;
+ }
+
+ float32 s = b2Dot(q - v1, r) / rr;
+ if (s < 0.0f || 1.0f < s)
+ {
+ return false;
+ }
+
+ output->fraction = t;
+ if (numerator > 0.0f)
+ {
+ output->normal = -normal;
+ }
+ else
+ {
+ output->normal = normal;
+ }
+ return true;
+}
+
+void b2EdgeShape::ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const
+{
+ B2_NOT_USED(childIndex);
+
+ b2Vec2 v1 = b2Mul(xf, m_vertex1);
+ b2Vec2 v2 = b2Mul(xf, m_vertex2);
+
+ b2Vec2 lower = b2Min(v1, v2);
+ b2Vec2 upper = b2Max(v1, v2);
+
+ b2Vec2 r(m_radius, m_radius);
+ aabb->lowerBound = lower - r;
+ aabb->upperBound = upper + r;
+}
+
+void b2EdgeShape::ComputeMass(b2MassData* massData, float32 density) const
+{
+ B2_NOT_USED(density);
+
+ massData->mass = 0.0f;
+ massData->center = 0.5f * (m_vertex1 + m_vertex2);
+ massData->I = 0.0f;
+}
diff --git a/tests/box2d/Box2D/Collision/Shapes/b2EdgeShape.h b/tests/box2d/Box2D/Collision/Shapes/b2EdgeShape.h new file mode 100755 index 00000000..99f822be --- /dev/null +++ b/tests/box2d/Box2D/Collision/Shapes/b2EdgeShape.h @@ -0,0 +1,74 @@ +/*
+* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_EDGE_SHAPE_H
+#define B2_EDGE_SHAPE_H
+
+#include <Box2D/Collision/Shapes/b2Shape.h>
+
+/// A line segment (edge) shape. These can be connected in chains or loops
+/// to other edge shapes. The connectivity information is used to ensure
+/// correct contact normals.
+class b2EdgeShape : public b2Shape
+{
+public:
+ b2EdgeShape();
+
+ /// Set this as an isolated edge.
+ void Set(const b2Vec2& v1, const b2Vec2& v2);
+
+ /// Implement b2Shape.
+ b2Shape* Clone(b2BlockAllocator* allocator) const;
+
+ /// @see b2Shape::GetChildCount
+ int32 GetChildCount() const;
+
+ /// @see b2Shape::TestPoint
+ bool TestPoint(const b2Transform& transform, const b2Vec2& p) const;
+
+ /// Implement b2Shape.
+ bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
+ const b2Transform& transform, int32 childIndex) const;
+
+ /// @see b2Shape::ComputeAABB
+ void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const;
+
+ /// @see b2Shape::ComputeMass
+ void ComputeMass(b2MassData* massData, float32 density) const;
+
+ /// These are the edge vertices
+ b2Vec2 m_vertex1, m_vertex2;
+
+ /// Optional adjacent vertices. These are used for smooth collision.
+ b2Vec2 m_vertex0, m_vertex3;
+ bool m_hasVertex0, m_hasVertex3;
+};
+
+inline b2EdgeShape::b2EdgeShape()
+{
+ m_type = e_edge;
+ m_radius = b2_polygonRadius;
+ m_vertex0.x = 0.0f;
+ m_vertex0.y = 0.0f;
+ m_vertex3.x = 0.0f;
+ m_vertex3.y = 0.0f;
+ m_hasVertex0 = false;
+ m_hasVertex3 = false;
+}
+
+#endif
diff --git a/tests/box2d/Box2D/Collision/Shapes/b2PolygonShape.cpp b/tests/box2d/Box2D/Collision/Shapes/b2PolygonShape.cpp new file mode 100755 index 00000000..8be81333 --- /dev/null +++ b/tests/box2d/Box2D/Collision/Shapes/b2PolygonShape.cpp @@ -0,0 +1,361 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Collision/Shapes/b2PolygonShape.h>
+#include <new>
+
+b2Shape* b2PolygonShape::Clone(b2BlockAllocator* allocator) const
+{
+ void* mem = allocator->Allocate(sizeof(b2PolygonShape));
+ b2PolygonShape* clone = new (mem) b2PolygonShape;
+ *clone = *this;
+ return clone;
+}
+
+void b2PolygonShape::SetAsBox(float32 hx, float32 hy)
+{
+ m_vertexCount = 4;
+ m_vertices[0].Set(-hx, -hy);
+ m_vertices[1].Set( hx, -hy);
+ m_vertices[2].Set( hx, hy);
+ m_vertices[3].Set(-hx, hy);
+ m_normals[0].Set(0.0f, -1.0f);
+ m_normals[1].Set(1.0f, 0.0f);
+ m_normals[2].Set(0.0f, 1.0f);
+ m_normals[3].Set(-1.0f, 0.0f);
+ m_centroid.SetZero();
+}
+
+void b2PolygonShape::SetAsBox(float32 hx, float32 hy, const b2Vec2& center, float32 angle)
+{
+ m_vertexCount = 4;
+ m_vertices[0].Set(-hx, -hy);
+ m_vertices[1].Set( hx, -hy);
+ m_vertices[2].Set( hx, hy);
+ m_vertices[3].Set(-hx, hy);
+ m_normals[0].Set(0.0f, -1.0f);
+ m_normals[1].Set(1.0f, 0.0f);
+ m_normals[2].Set(0.0f, 1.0f);
+ m_normals[3].Set(-1.0f, 0.0f);
+ m_centroid = center;
+
+ b2Transform xf;
+ xf.p = center;
+ xf.q.Set(angle);
+
+ // Transform vertices and normals.
+ for (int32 i = 0; i < m_vertexCount; ++i)
+ {
+ m_vertices[i] = b2Mul(xf, m_vertices[i]);
+ m_normals[i] = b2Mul(xf.q, m_normals[i]);
+ }
+}
+
+int32 b2PolygonShape::GetChildCount() const
+{
+ return 1;
+}
+
+static b2Vec2 ComputeCentroid(const b2Vec2* vs, int32 count)
+{
+ b2Assert(count >= 3);
+
+ b2Vec2 c; c.Set(0.0f, 0.0f);
+ float32 area = 0.0f;
+
+ // pRef is the reference point for forming triangles.
+ // It's location doesn't change the result (except for rounding error).
+ b2Vec2 pRef(0.0f, 0.0f);
+#if 0
+ // This code would put the reference point inside the polygon.
+ for (int32 i = 0; i < count; ++i)
+ {
+ pRef += vs[i];
+ }
+ pRef *= 1.0f / count;
+#endif
+
+ const float32 inv3 = 1.0f / 3.0f;
+
+ for (int32 i = 0; i < count; ++i)
+ {
+ // Triangle vertices.
+ b2Vec2 p1 = pRef;
+ b2Vec2 p2 = vs[i];
+ b2Vec2 p3 = i + 1 < count ? vs[i+1] : vs[0];
+
+ b2Vec2 e1 = p2 - p1;
+ b2Vec2 e2 = p3 - p1;
+
+ float32 D = b2Cross(e1, e2);
+
+ float32 triangleArea = 0.5f * D;
+ area += triangleArea;
+
+ // Area weighted centroid
+ c += triangleArea * inv3 * (p1 + p2 + p3);
+ }
+
+ // Centroid
+ b2Assert(area > b2_epsilon);
+ c *= 1.0f / area;
+ return c;
+}
+
+void b2PolygonShape::Set(const b2Vec2* vertices, int32 count)
+{
+ b2Assert(3 <= count && count <= b2_maxPolygonVertices);
+ m_vertexCount = count;
+
+ // Copy vertices.
+ for (int32 i = 0; i < m_vertexCount; ++i)
+ {
+ m_vertices[i] = vertices[i];
+ }
+
+ // Compute normals. Ensure the edges have non-zero length.
+ for (int32 i = 0; i < m_vertexCount; ++i)
+ {
+ int32 i1 = i;
+ int32 i2 = i + 1 < m_vertexCount ? i + 1 : 0;
+ b2Vec2 edge = m_vertices[i2] - m_vertices[i1];
+ b2Assert(edge.LengthSquared() > b2_epsilon * b2_epsilon);
+ m_normals[i] = b2Cross(edge, 1.0f);
+ m_normals[i].Normalize();
+ }
+
+#ifdef _DEBUG
+ // Ensure the polygon is convex and the interior
+ // is to the left of each edge.
+ for (int32 i = 0; i < m_vertexCount; ++i)
+ {
+ int32 i1 = i;
+ int32 i2 = i + 1 < m_vertexCount ? i + 1 : 0;
+ b2Vec2 edge = m_vertices[i2] - m_vertices[i1];
+
+ for (int32 j = 0; j < m_vertexCount; ++j)
+ {
+ // Don't check vertices on the current edge.
+ if (j == i1 || j == i2)
+ {
+ continue;
+ }
+
+ b2Vec2 r = m_vertices[j] - m_vertices[i1];
+
+ // If this crashes, your polygon is non-convex, has colinear edges,
+ // or the winding order is wrong.
+ float32 s = b2Cross(edge, r);
+ b2Assert(s > 0.0f && "ERROR: Please ensure your polygon is convex and has a CCW winding order");
+ }
+ }
+#endif
+
+ // Compute the polygon centroid.
+ m_centroid = ComputeCentroid(m_vertices, m_vertexCount);
+}
+
+bool b2PolygonShape::TestPoint(const b2Transform& xf, const b2Vec2& p) const
+{
+ b2Vec2 pLocal = b2MulT(xf.q, p - xf.p);
+
+ for (int32 i = 0; i < m_vertexCount; ++i)
+ {
+ float32 dot = b2Dot(m_normals[i], pLocal - m_vertices[i]);
+ if (dot > 0.0f)
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool b2PolygonShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
+ const b2Transform& xf, int32 childIndex) const
+{
+ B2_NOT_USED(childIndex);
+
+ // Put the ray into the polygon's frame of reference.
+ b2Vec2 p1 = b2MulT(xf.q, input.p1 - xf.p);
+ b2Vec2 p2 = b2MulT(xf.q, input.p2 - xf.p);
+ b2Vec2 d = p2 - p1;
+
+ float32 lower = 0.0f, upper = input.maxFraction;
+
+ int32 index = -1;
+
+ for (int32 i = 0; i < m_vertexCount; ++i)
+ {
+ // p = p1 + a * d
+ // dot(normal, p - v) = 0
+ // dot(normal, p1 - v) + a * dot(normal, d) = 0
+ float32 numerator = b2Dot(m_normals[i], m_vertices[i] - p1);
+ float32 denominator = b2Dot(m_normals[i], d);
+
+ if (denominator == 0.0f)
+ {
+ if (numerator < 0.0f)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ // Note: we want this predicate without division:
+ // lower < numerator / denominator, where denominator < 0
+ // Since denominator < 0, we have to flip the inequality:
+ // lower < numerator / denominator <==> denominator * lower > numerator.
+ if (denominator < 0.0f && numerator < lower * denominator)
+ {
+ // Increase lower.
+ // The segment enters this half-space.
+ lower = numerator / denominator;
+ index = i;
+ }
+ else if (denominator > 0.0f && numerator < upper * denominator)
+ {
+ // Decrease upper.
+ // The segment exits this half-space.
+ upper = numerator / denominator;
+ }
+ }
+
+ // The use of epsilon here causes the assert on lower to trip
+ // in some cases. Apparently the use of epsilon was to make edge
+ // shapes work, but now those are handled separately.
+ //if (upper < lower - b2_epsilon)
+ if (upper < lower)
+ {
+ return false;
+ }
+ }
+
+ b2Assert(0.0f <= lower && lower <= input.maxFraction);
+
+ if (index >= 0)
+ {
+ output->fraction = lower;
+ output->normal = b2Mul(xf.q, m_normals[index]);
+ return true;
+ }
+
+ return false;
+}
+
+void b2PolygonShape::ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const
+{
+ B2_NOT_USED(childIndex);
+
+ b2Vec2 lower = b2Mul(xf, m_vertices[0]);
+ b2Vec2 upper = lower;
+
+ for (int32 i = 1; i < m_vertexCount; ++i)
+ {
+ b2Vec2 v = b2Mul(xf, m_vertices[i]);
+ lower = b2Min(lower, v);
+ upper = b2Max(upper, v);
+ }
+
+ b2Vec2 r(m_radius, m_radius);
+ aabb->lowerBound = lower - r;
+ aabb->upperBound = upper + r;
+}
+
+void b2PolygonShape::ComputeMass(b2MassData* massData, float32 density) const
+{
+ // Polygon mass, centroid, and inertia.
+ // Let rho be the polygon density in mass per unit area.
+ // Then:
+ // mass = rho * int(dA)
+ // centroid.x = (1/mass) * rho * int(x * dA)
+ // centroid.y = (1/mass) * rho * int(y * dA)
+ // I = rho * int((x*x + y*y) * dA)
+ //
+ // We can compute these integrals by summing all the integrals
+ // for each triangle of the polygon. To evaluate the integral
+ // for a single triangle, we make a change of variables to
+ // the (u,v) coordinates of the triangle:
+ // x = x0 + e1x * u + e2x * v
+ // y = y0 + e1y * u + e2y * v
+ // where 0 <= u && 0 <= v && u + v <= 1.
+ //
+ // We integrate u from [0,1-v] and then v from [0,1].
+ // We also need to use the Jacobian of the transformation:
+ // D = cross(e1, e2)
+ //
+ // Simplification: triangle centroid = (1/3) * (p1 + p2 + p3)
+ //
+ // The rest of the derivation is handled by computer algebra.
+
+ b2Assert(m_vertexCount >= 3);
+
+ b2Vec2 center; center.Set(0.0f, 0.0f);
+ float32 area = 0.0f;
+ float32 I = 0.0f;
+
+ // s is the reference point for forming triangles.
+ // It's location doesn't change the result (except for rounding error).
+ b2Vec2 s(0.0f, 0.0f);
+
+ // This code would put the reference point inside the polygon.
+ for (int32 i = 0; i < m_vertexCount; ++i)
+ {
+ s += m_vertices[i];
+ }
+ s *= 1.0f / m_vertexCount;
+
+ const float32 k_inv3 = 1.0f / 3.0f;
+
+ for (int32 i = 0; i < m_vertexCount; ++i)
+ {
+ // Triangle vertices.
+ b2Vec2 e1 = m_vertices[i] - s;
+ b2Vec2 e2 = i + 1 < m_vertexCount ? m_vertices[i+1] - s : m_vertices[0] - s;
+
+ float32 D = b2Cross(e1, e2);
+
+ float32 triangleArea = 0.5f * D;
+ area += triangleArea;
+
+ // Area weighted centroid
+ center += triangleArea * k_inv3 * (e1 + e2);
+
+ float32 ex1 = e1.x, ey1 = e1.y;
+ float32 ex2 = e2.x, ey2 = e2.y;
+
+ float32 intx2 = ex1*ex1 + ex2*ex1 + ex2*ex2;
+ float32 inty2 = ey1*ey1 + ey2*ey1 + ey2*ey2;
+
+ I += (0.25f * k_inv3 * D) * (intx2 + inty2);
+ }
+
+ // Total mass
+ massData->mass = density * area;
+
+ // Center of mass
+ b2Assert(area > b2_epsilon);
+ center *= 1.0f / area;
+ massData->center = center + s;
+
+ // Inertia tensor relative to the local origin (point s).
+ massData->I = density * I;
+
+ // Shift to center of mass then to original body origin.
+ massData->I += massData->mass * (b2Dot(massData->center, massData->center) - b2Dot(center, center));
+}
diff --git a/tests/box2d/Box2D/Collision/Shapes/b2PolygonShape.h b/tests/box2d/Box2D/Collision/Shapes/b2PolygonShape.h new file mode 100755 index 00000000..fd11bd16 --- /dev/null +++ b/tests/box2d/Box2D/Collision/Shapes/b2PolygonShape.h @@ -0,0 +1,95 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_POLYGON_SHAPE_H
+#define B2_POLYGON_SHAPE_H
+
+#include <Box2D/Collision/Shapes/b2Shape.h>
+
+/// A convex polygon. It is assumed that the interior of the polygon is to
+/// the left of each edge.
+/// Polygons have a maximum number of vertices equal to b2_maxPolygonVertices.
+/// In most cases you should not need many vertices for a convex polygon.
+class b2PolygonShape : public b2Shape
+{
+public:
+ b2PolygonShape();
+
+ /// Implement b2Shape.
+ b2Shape* Clone(b2BlockAllocator* allocator) const;
+
+ /// @see b2Shape::GetChildCount
+ int32 GetChildCount() const;
+
+ /// Copy vertices. This assumes the vertices define a convex polygon.
+ /// It is assumed that the exterior is the the right of each edge.
+ /// The count must be in the range [3, b2_maxPolygonVertices].
+ void Set(const b2Vec2* vertices, int32 vertexCount);
+
+ /// Build vertices to represent an axis-aligned box.
+ /// @param hx the half-width.
+ /// @param hy the half-height.
+ void SetAsBox(float32 hx, float32 hy);
+
+ /// Build vertices to represent an oriented box.
+ /// @param hx the half-width.
+ /// @param hy the half-height.
+ /// @param center the center of the box in local coordinates.
+ /// @param angle the rotation of the box in local coordinates.
+ void SetAsBox(float32 hx, float32 hy, const b2Vec2& center, float32 angle);
+
+ /// @see b2Shape::TestPoint
+ bool TestPoint(const b2Transform& transform, const b2Vec2& p) const;
+
+ /// Implement b2Shape.
+ bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
+ const b2Transform& transform, int32 childIndex) const;
+
+ /// @see b2Shape::ComputeAABB
+ void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const;
+
+ /// @see b2Shape::ComputeMass
+ void ComputeMass(b2MassData* massData, float32 density) const;
+
+ /// Get the vertex count.
+ int32 GetVertexCount() const { return m_vertexCount; }
+
+ /// Get a vertex by index.
+ const b2Vec2& GetVertex(int32 index) const;
+
+ b2Vec2 m_centroid;
+ b2Vec2 m_vertices[b2_maxPolygonVertices];
+ b2Vec2 m_normals[b2_maxPolygonVertices];
+ int32 m_vertexCount;
+};
+
+inline b2PolygonShape::b2PolygonShape()
+{
+ m_type = e_polygon;
+ m_radius = b2_polygonRadius;
+ m_vertexCount = 0;
+ m_centroid.SetZero();
+}
+
+inline const b2Vec2& b2PolygonShape::GetVertex(int32 index) const
+{
+ b2Assert(0 <= index && index < m_vertexCount);
+ return m_vertices[index];
+}
+
+#endif
diff --git a/tests/box2d/Box2D/Collision/Shapes/b2Shape.h b/tests/box2d/Box2D/Collision/Shapes/b2Shape.h new file mode 100755 index 00000000..fd7de262 --- /dev/null +++ b/tests/box2d/Box2D/Collision/Shapes/b2Shape.h @@ -0,0 +1,101 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_SHAPE_H
+#define B2_SHAPE_H
+
+#include <Box2D/Common/b2BlockAllocator.h>
+#include <Box2D/Common/b2Math.h>
+#include <Box2D/Collision/b2Collision.h>
+
+/// This holds the mass data computed for a shape.
+struct b2MassData
+{
+ /// The mass of the shape, usually in kilograms.
+ float32 mass;
+
+ /// The position of the shape's centroid relative to the shape's origin.
+ b2Vec2 center;
+
+ /// The rotational inertia of the shape about the local origin.
+ float32 I;
+};
+
+/// A shape is used for collision detection. You can create a shape however you like.
+/// Shapes used for simulation in b2World are created automatically when a b2Fixture
+/// is created. Shapes may encapsulate a one or more child shapes.
+class b2Shape
+{
+public:
+
+ enum Type
+ {
+ e_circle = 0,
+ e_edge = 1,
+ e_polygon = 2,
+ e_chain = 3,
+ e_typeCount = 4
+ };
+
+ virtual ~b2Shape() {}
+
+ /// Clone the concrete shape using the provided allocator.
+ virtual b2Shape* Clone(b2BlockAllocator* allocator) const = 0;
+
+ /// Get the type of this shape. You can use this to down cast to the concrete shape.
+ /// @return the shape type.
+ Type GetType() const;
+
+ /// Get the number of child primitives.
+ virtual int32 GetChildCount() const = 0;
+
+ /// Test a point for containment in this shape. This only works for convex shapes.
+ /// @param xf the shape world transform.
+ /// @param p a point in world coordinates.
+ virtual bool TestPoint(const b2Transform& xf, const b2Vec2& p) const = 0;
+
+ /// Cast a ray against a child shape.
+ /// @param output the ray-cast results.
+ /// @param input the ray-cast input parameters.
+ /// @param transform the transform to be applied to the shape.
+ /// @param childIndex the child shape index
+ virtual bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
+ const b2Transform& transform, int32 childIndex) const = 0;
+
+ /// Given a transform, compute the associated axis aligned bounding box for a child shape.
+ /// @param aabb returns the axis aligned box.
+ /// @param xf the world transform of the shape.
+ /// @param childIndex the child shape
+ virtual void ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const = 0;
+
+ /// Compute the mass properties of this shape using its dimensions and density.
+ /// The inertia tensor is computed about the local origin.
+ /// @param massData returns the mass data for this shape.
+ /// @param density the density in kilograms per meter squared.
+ virtual void ComputeMass(b2MassData* massData, float32 density) const = 0;
+
+ Type m_type;
+ float32 m_radius;
+};
+
+inline b2Shape::Type b2Shape::GetType() const
+{
+ return m_type;
+}
+
+#endif
diff --git a/tests/box2d/Box2D/Collision/b2BroadPhase.cpp b/tests/box2d/Box2D/Collision/b2BroadPhase.cpp new file mode 100755 index 00000000..2aa62f94 --- /dev/null +++ b/tests/box2d/Box2D/Collision/b2BroadPhase.cpp @@ -0,0 +1,122 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Collision/b2BroadPhase.h>
+#include <cstring>
+using namespace std;
+
+b2BroadPhase::b2BroadPhase()
+{
+ m_proxyCount = 0;
+
+ m_pairCapacity = 16;
+ m_pairCount = 0;
+ m_pairBuffer = (b2Pair*)b2Alloc(m_pairCapacity * sizeof(b2Pair));
+
+ m_moveCapacity = 16;
+ m_moveCount = 0;
+ m_moveBuffer = (int32*)b2Alloc(m_moveCapacity * sizeof(int32));
+}
+
+b2BroadPhase::~b2BroadPhase()
+{
+ b2Free(m_moveBuffer);
+ b2Free(m_pairBuffer);
+}
+
+int32 b2BroadPhase::CreateProxy(const b2AABB& aabb, void* userData)
+{
+ int32 proxyId = m_tree.CreateProxy(aabb, userData);
+ ++m_proxyCount;
+ BufferMove(proxyId);
+ return proxyId;
+}
+
+void b2BroadPhase::DestroyProxy(int32 proxyId)
+{
+ UnBufferMove(proxyId);
+ --m_proxyCount;
+ m_tree.DestroyProxy(proxyId);
+}
+
+void b2BroadPhase::MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement)
+{
+ bool buffer = m_tree.MoveProxy(proxyId, aabb, displacement);
+ if (buffer)
+ {
+ BufferMove(proxyId);
+ }
+}
+
+void b2BroadPhase::TouchProxy(int32 proxyId)
+{
+ BufferMove(proxyId);
+}
+
+void b2BroadPhase::BufferMove(int32 proxyId)
+{
+ if (m_moveCount == m_moveCapacity)
+ {
+ int32* oldBuffer = m_moveBuffer;
+ m_moveCapacity *= 2;
+ m_moveBuffer = (int32*)b2Alloc(m_moveCapacity * sizeof(int32));
+ memcpy(m_moveBuffer, oldBuffer, m_moveCount * sizeof(int32));
+ b2Free(oldBuffer);
+ }
+
+ m_moveBuffer[m_moveCount] = proxyId;
+ ++m_moveCount;
+}
+
+void b2BroadPhase::UnBufferMove(int32 proxyId)
+{
+ for (int32 i = 0; i < m_moveCount; ++i)
+ {
+ if (m_moveBuffer[i] == proxyId)
+ {
+ m_moveBuffer[i] = e_nullProxy;
+ return;
+ }
+ }
+}
+
+// This is called from b2DynamicTree::Query when we are gathering pairs.
+bool b2BroadPhase::QueryCallback(int32 proxyId)
+{
+ // A proxy cannot form a pair with itself.
+ if (proxyId == m_queryProxyId)
+ {
+ return true;
+ }
+
+ // Grow the pair buffer as needed.
+ if (m_pairCount == m_pairCapacity)
+ {
+ b2Pair* oldBuffer = m_pairBuffer;
+ m_pairCapacity *= 2;
+ m_pairBuffer = (b2Pair*)b2Alloc(m_pairCapacity * sizeof(b2Pair));
+ memcpy(m_pairBuffer, oldBuffer, m_pairCount * sizeof(b2Pair));
+ b2Free(oldBuffer);
+ }
+
+ m_pairBuffer[m_pairCount].proxyIdA = b2Min(proxyId, m_queryProxyId);
+ m_pairBuffer[m_pairCount].proxyIdB = b2Max(proxyId, m_queryProxyId);
+ ++m_pairCount;
+
+ return true;
+}
diff --git a/tests/box2d/Box2D/Collision/b2BroadPhase.h b/tests/box2d/Box2D/Collision/b2BroadPhase.h new file mode 100755 index 00000000..e31ff3d2 --- /dev/null +++ b/tests/box2d/Box2D/Collision/b2BroadPhase.h @@ -0,0 +1,250 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_BROAD_PHASE_H
+#define B2_BROAD_PHASE_H
+
+#include <Box2D/Common/b2Settings.h>
+#include <Box2D/Collision/b2Collision.h>
+#include <Box2D/Collision/b2DynamicTree.h>
+#ifndef EM_NO_LIBCPP
+#include <algorithm>
+#endif
+
+struct b2Pair
+{
+ int32 proxyIdA;
+ int32 proxyIdB;
+ int32 next;
+};
+
+/// The broad-phase is used for computing pairs and performing volume queries and ray casts.
+/// This broad-phase does not persist pairs. Instead, this reports potentially new pairs.
+/// It is up to the client to consume the new pairs and to track subsequent overlap.
+class b2BroadPhase
+{
+public:
+
+ enum
+ {
+ e_nullProxy = -1
+ };
+
+ b2BroadPhase();
+ ~b2BroadPhase();
+
+ /// Create a proxy with an initial AABB. Pairs are not reported until
+ /// UpdatePairs is called.
+ int32 CreateProxy(const b2AABB& aabb, void* userData);
+
+ /// Destroy a proxy. It is up to the client to remove any pairs.
+ void DestroyProxy(int32 proxyId);
+
+ /// Call MoveProxy as many times as you like, then when you are done
+ /// call UpdatePairs to finalized the proxy pairs (for your time step).
+ void MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement);
+
+ /// Call to trigger a re-processing of it's pairs on the next call to UpdatePairs.
+ void TouchProxy(int32 proxyId);
+
+ /// Get the fat AABB for a proxy.
+ const b2AABB& GetFatAABB(int32 proxyId) const;
+
+ /// Get user data from a proxy. Returns NULL if the id is invalid.
+ void* GetUserData(int32 proxyId) const;
+
+ /// Test overlap of fat AABBs.
+ bool TestOverlap(int32 proxyIdA, int32 proxyIdB) const;
+
+ /// Get the number of proxies.
+ int32 GetProxyCount() const;
+
+ /// Update the pairs. This results in pair callbacks. This can only add pairs.
+ template <typename T>
+ void UpdatePairs(T* callback);
+
+ /// Query an AABB for overlapping proxies. The callback class
+ /// is called for each proxy that overlaps the supplied AABB.
+ template <typename T>
+ void Query(T* callback, const b2AABB& aabb) const;
+
+ /// Ray-cast against the proxies in the tree. This relies on the callback
+ /// to perform a exact ray-cast in the case were the proxy contains a shape.
+ /// The callback also performs the any collision filtering. This has performance
+ /// roughly equal to k * log(n), where k is the number of collisions and n is the
+ /// number of proxies in the tree.
+ /// @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).
+ /// @param callback a callback class that is called for each proxy that is hit by the ray.
+ template <typename T>
+ void RayCast(T* callback, const b2RayCastInput& input) const;
+
+ /// Get the height of the embedded tree.
+ int32 GetTreeHeight() const;
+
+ /// Get the balance of the embedded tree.
+ int32 GetTreeBalance() const;
+
+ /// Get the quality metric of the embedded tree.
+ float32 GetTreeQuality() const;
+
+private:
+
+ friend class b2DynamicTree;
+
+ void BufferMove(int32 proxyId);
+ void UnBufferMove(int32 proxyId);
+
+ bool QueryCallback(int32 proxyId);
+
+ b2DynamicTree m_tree;
+
+ int32 m_proxyCount;
+
+ int32* m_moveBuffer;
+ int32 m_moveCapacity;
+ int32 m_moveCount;
+
+ b2Pair* m_pairBuffer;
+ int32 m_pairCapacity;
+ int32 m_pairCount;
+
+ int32 m_queryProxyId;
+};
+
+/// This is used to sort pairs.
+inline bool b2PairLessThan(const b2Pair& pair1, const b2Pair& pair2)
+{
+ if (pair1.proxyIdA < pair2.proxyIdA)
+ {
+ return true;
+ }
+
+ if (pair1.proxyIdA == pair2.proxyIdA)
+ {
+ return pair1.proxyIdB < pair2.proxyIdB;
+ }
+
+ return false;
+}
+
+inline void* b2BroadPhase::GetUserData(int32 proxyId) const
+{
+ return m_tree.GetUserData(proxyId);
+}
+
+inline bool b2BroadPhase::TestOverlap(int32 proxyIdA, int32 proxyIdB) const
+{
+ const b2AABB& aabbA = m_tree.GetFatAABB(proxyIdA);
+ const b2AABB& aabbB = m_tree.GetFatAABB(proxyIdB);
+ return b2TestOverlap(aabbA, aabbB);
+}
+
+inline const b2AABB& b2BroadPhase::GetFatAABB(int32 proxyId) const
+{
+ return m_tree.GetFatAABB(proxyId);
+}
+
+inline int32 b2BroadPhase::GetProxyCount() const
+{
+ return m_proxyCount;
+}
+
+inline int32 b2BroadPhase::GetTreeHeight() const
+{
+ return m_tree.GetHeight();
+}
+
+inline int32 b2BroadPhase::GetTreeBalance() const
+{
+ return m_tree.GetMaxBalance();
+}
+
+inline float32 b2BroadPhase::GetTreeQuality() const
+{
+ return m_tree.GetAreaRatio();
+}
+
+template <typename T>
+void b2BroadPhase::UpdatePairs(T* callback)
+{
+ // Reset pair buffer
+ m_pairCount = 0;
+
+ // Perform tree queries for all moving proxies.
+ for (int32 i = 0; i < m_moveCount; ++i)
+ {
+ m_queryProxyId = m_moveBuffer[i];
+ if (m_queryProxyId == e_nullProxy)
+ {
+ continue;
+ }
+
+ // We have to query the tree with the fat AABB so that
+ // we don't fail to create a pair that may touch later.
+ const b2AABB& fatAABB = m_tree.GetFatAABB(m_queryProxyId);
+
+ // Query tree, create pairs and add them pair buffer.
+ m_tree.Query(this, fatAABB);
+ }
+
+ // Reset move buffer
+ m_moveCount = 0;
+
+ // Sort the pair buffer to expose duplicates.
+ std::sort(m_pairBuffer, m_pairBuffer + m_pairCount, b2PairLessThan);
+
+ // Send the pairs back to the client.
+ int32 i = 0;
+ while (i < m_pairCount)
+ {
+ b2Pair* primaryPair = m_pairBuffer + i;
+ void* userDataA = m_tree.GetUserData(primaryPair->proxyIdA);
+ void* userDataB = m_tree.GetUserData(primaryPair->proxyIdB);
+
+ callback->AddPair(userDataA, userDataB);
+ ++i;
+
+ // Skip any duplicate pairs.
+ while (i < m_pairCount)
+ {
+ b2Pair* pair = m_pairBuffer + i;
+ if (pair->proxyIdA != primaryPair->proxyIdA || pair->proxyIdB != primaryPair->proxyIdB)
+ {
+ break;
+ }
+ ++i;
+ }
+ }
+
+ // Try to keep the tree balanced.
+ //m_tree.Rebalance(4);
+}
+
+template <typename T>
+inline void b2BroadPhase::Query(T* callback, const b2AABB& aabb) const
+{
+ m_tree.Query(callback, aabb);
+}
+
+template <typename T>
+inline void b2BroadPhase::RayCast(T* callback, const b2RayCastInput& input) const
+{
+ m_tree.RayCast(callback, input);
+}
+
+#endif
diff --git a/tests/box2d/Box2D/Collision/b2CollideCircle.cpp b/tests/box2d/Box2D/Collision/b2CollideCircle.cpp new file mode 100755 index 00000000..0ad58f00 --- /dev/null +++ b/tests/box2d/Box2D/Collision/b2CollideCircle.cpp @@ -0,0 +1,154 @@ +/*
+* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Collision/b2Collision.h>
+#include <Box2D/Collision/Shapes/b2CircleShape.h>
+#include <Box2D/Collision/Shapes/b2PolygonShape.h>
+
+void b2CollideCircles(
+ b2Manifold* manifold,
+ const b2CircleShape* circleA, const b2Transform& xfA,
+ const b2CircleShape* circleB, const b2Transform& xfB)
+{
+ manifold->pointCount = 0;
+
+ b2Vec2 pA = b2Mul(xfA, circleA->m_p);
+ b2Vec2 pB = b2Mul(xfB, circleB->m_p);
+
+ b2Vec2 d = pB - pA;
+ float32 distSqr = b2Dot(d, d);
+ float32 rA = circleA->m_radius, rB = circleB->m_radius;
+ float32 radius = rA + rB;
+ if (distSqr > radius * radius)
+ {
+ return;
+ }
+
+ manifold->type = b2Manifold::e_circles;
+ manifold->localPoint = circleA->m_p;
+ manifold->localNormal.SetZero();
+ manifold->pointCount = 1;
+
+ manifold->points[0].localPoint = circleB->m_p;
+ manifold->points[0].id.key = 0;
+}
+
+void b2CollidePolygonAndCircle(
+ b2Manifold* manifold,
+ const b2PolygonShape* polygonA, const b2Transform& xfA,
+ const b2CircleShape* circleB, const b2Transform& xfB)
+{
+ manifold->pointCount = 0;
+
+ // Compute circle position in the frame of the polygon.
+ b2Vec2 c = b2Mul(xfB, circleB->m_p);
+ b2Vec2 cLocal = b2MulT(xfA, c);
+
+ // Find the min separating edge.
+ int32 normalIndex = 0;
+ float32 separation = -b2_maxFloat;
+ float32 radius = polygonA->m_radius + circleB->m_radius;
+ int32 vertexCount = polygonA->m_vertexCount;
+ const b2Vec2* vertices = polygonA->m_vertices;
+ const b2Vec2* normals = polygonA->m_normals;
+
+ for (int32 i = 0; i < vertexCount; ++i)
+ {
+ float32 s = b2Dot(normals[i], cLocal - vertices[i]);
+
+ if (s > radius)
+ {
+ // Early out.
+ return;
+ }
+
+ if (s > separation)
+ {
+ separation = s;
+ normalIndex = i;
+ }
+ }
+
+ // Vertices that subtend the incident face.
+ int32 vertIndex1 = normalIndex;
+ int32 vertIndex2 = vertIndex1 + 1 < vertexCount ? vertIndex1 + 1 : 0;
+ b2Vec2 v1 = vertices[vertIndex1];
+ b2Vec2 v2 = vertices[vertIndex2];
+
+ // If the center is inside the polygon ...
+ if (separation < b2_epsilon)
+ {
+ manifold->pointCount = 1;
+ manifold->type = b2Manifold::e_faceA;
+ manifold->localNormal = normals[normalIndex];
+ manifold->localPoint = 0.5f * (v1 + v2);
+ manifold->points[0].localPoint = circleB->m_p;
+ manifold->points[0].id.key = 0;
+ return;
+ }
+
+ // Compute barycentric coordinates
+ float32 u1 = b2Dot(cLocal - v1, v2 - v1);
+ float32 u2 = b2Dot(cLocal - v2, v1 - v2);
+ if (u1 <= 0.0f)
+ {
+ if (b2DistanceSquared(cLocal, v1) > radius * radius)
+ {
+ return;
+ }
+
+ manifold->pointCount = 1;
+ manifold->type = b2Manifold::e_faceA;
+ manifold->localNormal = cLocal - v1;
+ manifold->localNormal.Normalize();
+ manifold->localPoint = v1;
+ manifold->points[0].localPoint = circleB->m_p;
+ manifold->points[0].id.key = 0;
+ }
+ else if (u2 <= 0.0f)
+ {
+ if (b2DistanceSquared(cLocal, v2) > radius * radius)
+ {
+ return;
+ }
+
+ manifold->pointCount = 1;
+ manifold->type = b2Manifold::e_faceA;
+ manifold->localNormal = cLocal - v2;
+ manifold->localNormal.Normalize();
+ manifold->localPoint = v2;
+ manifold->points[0].localPoint = circleB->m_p;
+ manifold->points[0].id.key = 0;
+ }
+ else
+ {
+ b2Vec2 faceCenter = 0.5f * (v1 + v2);
+ float32 separation = b2Dot(cLocal - faceCenter, normals[vertIndex1]);
+ if (separation > radius)
+ {
+ return;
+ }
+
+ manifold->pointCount = 1;
+ manifold->type = b2Manifold::e_faceA;
+ manifold->localNormal = normals[vertIndex1];
+ manifold->localPoint = faceCenter;
+ manifold->points[0].localPoint = circleB->m_p;
+ manifold->points[0].id.key = 0;
+ }
+}
diff --git a/tests/box2d/Box2D/Collision/b2CollideEdge.cpp b/tests/box2d/Box2D/Collision/b2CollideEdge.cpp new file mode 100755 index 00000000..28196718 --- /dev/null +++ b/tests/box2d/Box2D/Collision/b2CollideEdge.cpp @@ -0,0 +1,698 @@ +/*
+ * Copyright (c) 2007-2009 Erin Catto http://www.box2d.org
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+#include <Box2D/Collision/b2Collision.h>
+#include <Box2D/Collision/Shapes/b2CircleShape.h>
+#include <Box2D/Collision/Shapes/b2EdgeShape.h>
+#include <Box2D/Collision/Shapes/b2PolygonShape.h>
+
+
+// Compute contact points for edge versus circle.
+// This accounts for edge connectivity.
+void b2CollideEdgeAndCircle(b2Manifold* manifold,
+ const b2EdgeShape* edgeA, const b2Transform& xfA,
+ const b2CircleShape* circleB, const b2Transform& xfB)
+{
+ manifold->pointCount = 0;
+
+ // Compute circle in frame of edge
+ b2Vec2 Q = b2MulT(xfA, b2Mul(xfB, circleB->m_p));
+
+ b2Vec2 A = edgeA->m_vertex1, B = edgeA->m_vertex2;
+ b2Vec2 e = B - A;
+
+ // Barycentric coordinates
+ float32 u = b2Dot(e, B - Q);
+ float32 v = b2Dot(e, Q - A);
+
+ float32 radius = edgeA->m_radius + circleB->m_radius;
+
+ b2ContactFeature cf;
+ cf.indexB = 0;
+ cf.typeB = b2ContactFeature::e_vertex;
+
+ // Region A
+ if (v <= 0.0f)
+ {
+ b2Vec2 P = A;
+ b2Vec2 d = Q - P;
+ float32 dd = b2Dot(d, d);
+ if (dd > radius * radius)
+ {
+ return;
+ }
+
+ // Is there an edge connected to A?
+ if (edgeA->m_hasVertex0)
+ {
+ b2Vec2 A1 = edgeA->m_vertex0;
+ b2Vec2 B1 = A;
+ b2Vec2 e1 = B1 - A1;
+ float32 u1 = b2Dot(e1, B1 - Q);
+
+ // Is the circle in Region AB of the previous edge?
+ if (u1 > 0.0f)
+ {
+ return;
+ }
+ }
+
+ cf.indexA = 0;
+ cf.typeA = b2ContactFeature::e_vertex;
+ manifold->pointCount = 1;
+ manifold->type = b2Manifold::e_circles;
+ manifold->localNormal.SetZero();
+ manifold->localPoint = P;
+ manifold->points[0].id.key = 0;
+ manifold->points[0].id.cf = cf;
+ manifold->points[0].localPoint = circleB->m_p;
+ return;
+ }
+
+ // Region B
+ if (u <= 0.0f)
+ {
+ b2Vec2 P = B;
+ b2Vec2 d = Q - P;
+ float32 dd = b2Dot(d, d);
+ if (dd > radius * radius)
+ {
+ return;
+ }
+
+ // Is there an edge connected to B?
+ if (edgeA->m_hasVertex3)
+ {
+ b2Vec2 B2 = edgeA->m_vertex3;
+ b2Vec2 A2 = B;
+ b2Vec2 e2 = B2 - A2;
+ float32 v2 = b2Dot(e2, Q - A2);
+
+ // Is the circle in Region AB of the next edge?
+ if (v2 > 0.0f)
+ {
+ return;
+ }
+ }
+
+ cf.indexA = 1;
+ cf.typeA = b2ContactFeature::e_vertex;
+ manifold->pointCount = 1;
+ manifold->type = b2Manifold::e_circles;
+ manifold->localNormal.SetZero();
+ manifold->localPoint = P;
+ manifold->points[0].id.key = 0;
+ manifold->points[0].id.cf = cf;
+ manifold->points[0].localPoint = circleB->m_p;
+ return;
+ }
+
+ // Region AB
+ float32 den = b2Dot(e, e);
+ b2Assert(den > 0.0f);
+ b2Vec2 P = (1.0f / den) * (u * A + v * B);
+ b2Vec2 d = Q - P;
+ float32 dd = b2Dot(d, d);
+ if (dd > radius * radius)
+ {
+ return;
+ }
+
+ b2Vec2 n(-e.y, e.x);
+ if (b2Dot(n, Q - A) < 0.0f)
+ {
+ n.Set(-n.x, -n.y);
+ }
+ n.Normalize();
+
+ cf.indexA = 0;
+ cf.typeA = b2ContactFeature::e_face;
+ manifold->pointCount = 1;
+ manifold->type = b2Manifold::e_faceA;
+ manifold->localNormal = n;
+ manifold->localPoint = A;
+ manifold->points[0].id.key = 0;
+ manifold->points[0].id.cf = cf;
+ manifold->points[0].localPoint = circleB->m_p;
+}
+
+// This structure is used to keep track of the best separating axis.
+struct b2EPAxis
+{
+ enum Type
+ {
+ e_unknown,
+ e_edgeA,
+ e_edgeB
+ };
+
+ Type type;
+ int32 index;
+ float32 separation;
+};
+
+// This holds polygon B expressed in frame A.
+struct b2TempPolygon
+{
+ b2Vec2 vertices[b2_maxPolygonVertices];
+ b2Vec2 normals[b2_maxPolygonVertices];
+ int32 count;
+};
+
+// Reference face used for clipping
+struct b2ReferenceFace
+{
+ int32 i1, i2;
+
+ b2Vec2 v1, v2;
+
+ b2Vec2 normal;
+
+ b2Vec2 sideNormal1;
+ float32 sideOffset1;
+
+ b2Vec2 sideNormal2;
+ float32 sideOffset2;
+};
+
+// This class collides and edge and a polygon, taking into account edge adjacency.
+struct b2EPCollider
+{
+ void Collide(b2Manifold* manifold, const b2EdgeShape* edgeA, const b2Transform& xfA,
+ const b2PolygonShape* polygonB, const b2Transform& xfB);
+ b2EPAxis ComputeEdgeSeparation();
+ b2EPAxis ComputePolygonSeparation();
+
+ enum VertexType
+ {
+ e_isolated,
+ e_concave,
+ e_convex
+ };
+
+ b2TempPolygon m_polygonB;
+
+ b2Transform m_xf;
+ b2Vec2 m_centroidB;
+ b2Vec2 m_v0, m_v1, m_v2, m_v3;
+ b2Vec2 m_normal0, m_normal1, m_normal2;
+ b2Vec2 m_normal;
+ VertexType m_type1, m_type2;
+ b2Vec2 m_lowerLimit, m_upperLimit;
+ float32 m_radius;
+ bool m_front;
+};
+
+// Algorithm:
+// 1. Classify v1 and v2
+// 2. Classify polygon centroid as front or back
+// 3. Flip normal if necessary
+// 4. Initialize normal range to [-pi, pi] about face normal
+// 5. Adjust normal range according to adjacent edges
+// 6. Visit each separating axes, only accept axes within the range
+// 7. Return if _any_ axis indicates separation
+// 8. Clip
+void b2EPCollider::Collide(b2Manifold* manifold, const b2EdgeShape* edgeA, const b2Transform& xfA,
+ const b2PolygonShape* polygonB, const b2Transform& xfB)
+{
+ m_xf = b2MulT(xfA, xfB);
+
+ m_centroidB = b2Mul(m_xf, polygonB->m_centroid);
+
+ m_v0 = edgeA->m_vertex0;
+ m_v1 = edgeA->m_vertex1;
+ m_v2 = edgeA->m_vertex2;
+ m_v3 = edgeA->m_vertex3;
+
+ bool hasVertex0 = edgeA->m_hasVertex0;
+ bool hasVertex3 = edgeA->m_hasVertex3;
+
+ b2Vec2 edge1 = m_v2 - m_v1;
+ edge1.Normalize();
+ m_normal1.Set(edge1.y, -edge1.x);
+ float32 offset1 = b2Dot(m_normal1, m_centroidB - m_v1);
+ float32 offset0 = 0.0f, offset2 = 0.0f;
+ bool convex1 = false, convex2 = false;
+
+ // Is there a preceding edge?
+ if (hasVertex0)
+ {
+ b2Vec2 edge0 = m_v1 - m_v0;
+ edge0.Normalize();
+ m_normal0.Set(edge0.y, -edge0.x);
+ convex1 = b2Cross(edge0, edge1) >= 0.0f;
+ offset0 = b2Dot(m_normal0, m_centroidB - m_v0);
+ }
+
+ // Is there a following edge?
+ if (hasVertex3)
+ {
+ b2Vec2 edge2 = m_v3 - m_v2;
+ edge2.Normalize();
+ m_normal2.Set(edge2.y, -edge2.x);
+ convex2 = b2Cross(edge1, edge2) > 0.0f;
+ offset2 = b2Dot(m_normal2, m_centroidB - m_v2);
+ }
+
+ // Determine front or back collision. Determine collision normal limits.
+ if (hasVertex0 && hasVertex3)
+ {
+ if (convex1 && convex2)
+ {
+ m_front = offset0 >= 0.0f || offset1 >= 0.0f || offset2 >= 0.0f;
+ if (m_front)
+ {
+ m_normal = m_normal1;
+ m_lowerLimit = m_normal0;
+ m_upperLimit = m_normal2;
+ }
+ else
+ {
+ m_normal = -m_normal1;
+ m_lowerLimit = -m_normal1;
+ m_upperLimit = -m_normal1;
+ }
+ }
+ else if (convex1)
+ {
+ m_front = offset0 >= 0.0f || (offset1 >= 0.0f && offset2 >= 0.0f);
+ if (m_front)
+ {
+ m_normal = m_normal1;
+ m_lowerLimit = m_normal0;
+ m_upperLimit = m_normal1;
+ }
+ else
+ {
+ m_normal = -m_normal1;
+ m_lowerLimit = -m_normal2;
+ m_upperLimit = -m_normal1;
+ }
+ }
+ else if (convex2)
+ {
+ m_front = offset2 >= 0.0f || (offset0 >= 0.0f && offset1 >= 0.0f);
+ if (m_front)
+ {
+ m_normal = m_normal1;
+ m_lowerLimit = m_normal1;
+ m_upperLimit = m_normal2;
+ }
+ else
+ {
+ m_normal = -m_normal1;
+ m_lowerLimit = -m_normal1;
+ m_upperLimit = -m_normal0;
+ }
+ }
+ else
+ {
+ m_front = offset0 >= 0.0f && offset1 >= 0.0f && offset2 >= 0.0f;
+ if (m_front)
+ {
+ m_normal = m_normal1;
+ m_lowerLimit = m_normal1;
+ m_upperLimit = m_normal1;
+ }
+ else
+ {
+ m_normal = -m_normal1;
+ m_lowerLimit = -m_normal2;
+ m_upperLimit = -m_normal0;
+ }
+ }
+ }
+ else if (hasVertex0)
+ {
+ if (convex1)
+ {
+ m_front = offset0 >= 0.0f || offset1 >= 0.0f;
+ if (m_front)
+ {
+ m_normal = m_normal1;
+ m_lowerLimit = m_normal0;
+ m_upperLimit = -m_normal1;
+ }
+ else
+ {
+ m_normal = -m_normal1;
+ m_lowerLimit = m_normal1;
+ m_upperLimit = -m_normal1;
+ }
+ }
+ else
+ {
+ m_front = offset0 >= 0.0f && offset1 >= 0.0f;
+ if (m_front)
+ {
+ m_normal = m_normal1;
+ m_lowerLimit = m_normal1;
+ m_upperLimit = -m_normal1;
+ }
+ else
+ {
+ m_normal = -m_normal1;
+ m_lowerLimit = m_normal1;
+ m_upperLimit = -m_normal0;
+ }
+ }
+ }
+ else if (hasVertex3)
+ {
+ if (convex2)
+ {
+ m_front = offset1 >= 0.0f || offset2 >= 0.0f;
+ if (m_front)
+ {
+ m_normal = m_normal1;
+ m_lowerLimit = -m_normal1;
+ m_upperLimit = m_normal2;
+ }
+ else
+ {
+ m_normal = -m_normal1;
+ m_lowerLimit = -m_normal1;
+ m_upperLimit = m_normal1;
+ }
+ }
+ else
+ {
+ m_front = offset1 >= 0.0f && offset2 >= 0.0f;
+ if (m_front)
+ {
+ m_normal = m_normal1;
+ m_lowerLimit = -m_normal1;
+ m_upperLimit = m_normal1;
+ }
+ else
+ {
+ m_normal = -m_normal1;
+ m_lowerLimit = -m_normal2;
+ m_upperLimit = m_normal1;
+ }
+ }
+ }
+ else
+ {
+ m_front = offset1 >= 0.0f;
+ if (m_front)
+ {
+ m_normal = m_normal1;
+ m_lowerLimit = -m_normal1;
+ m_upperLimit = -m_normal1;
+ }
+ else
+ {
+ m_normal = -m_normal1;
+ m_lowerLimit = m_normal1;
+ m_upperLimit = m_normal1;
+ }
+ }
+
+ // Get polygonB in frameA
+ m_polygonB.count = polygonB->m_vertexCount;
+ for (int32 i = 0; i < polygonB->m_vertexCount; ++i)
+ {
+ m_polygonB.vertices[i] = b2Mul(m_xf, polygonB->m_vertices[i]);
+ m_polygonB.normals[i] = b2Mul(m_xf.q, polygonB->m_normals[i]);
+ }
+
+ m_radius = 2.0f * b2_polygonRadius;
+
+ manifold->pointCount = 0;
+
+ b2EPAxis edgeAxis = ComputeEdgeSeparation();
+
+ // If no valid normal can be found than this edge should not collide.
+ if (edgeAxis.type == b2EPAxis::e_unknown)
+ {
+ return;
+ }
+
+ if (edgeAxis.separation > m_radius)
+ {
+ return;
+ }
+
+ b2EPAxis polygonAxis = ComputePolygonSeparation();
+ if (polygonAxis.type != b2EPAxis::e_unknown && polygonAxis.separation > m_radius)
+ {
+ return;
+ }
+
+ // Use hysteresis for jitter reduction.
+ const float32 k_relativeTol = 0.98f;
+ const float32 k_absoluteTol = 0.001f;
+
+ b2EPAxis primaryAxis;
+ if (polygonAxis.type == b2EPAxis::e_unknown)
+ {
+ primaryAxis = edgeAxis;
+ }
+ else if (polygonAxis.separation > k_relativeTol * edgeAxis.separation + k_absoluteTol)
+ {
+ primaryAxis = polygonAxis;
+ }
+ else
+ {
+ primaryAxis = edgeAxis;
+ }
+
+ b2ClipVertex ie[2];
+ b2ReferenceFace rf;
+ if (primaryAxis.type == b2EPAxis::e_edgeA)
+ {
+ manifold->type = b2Manifold::e_faceA;
+
+ // Search for the polygon normal that is most anti-parallel to the edge normal.
+ int32 bestIndex = 0;
+ float32 bestValue = b2Dot(m_normal, m_polygonB.normals[0]);
+ for (int32 i = 1; i < m_polygonB.count; ++i)
+ {
+ float32 value = b2Dot(m_normal, m_polygonB.normals[i]);
+ if (value < bestValue)
+ {
+ bestValue = value;
+ bestIndex = i;
+ }
+ }
+
+ int32 i1 = bestIndex;
+ int32 i2 = i1 + 1 < m_polygonB.count ? i1 + 1 : 0;
+
+ ie[0].v = m_polygonB.vertices[i1];
+ ie[0].id.cf.indexA = 0;
+ ie[0].id.cf.indexB = i1;
+ ie[0].id.cf.typeA = b2ContactFeature::e_face;
+ ie[0].id.cf.typeB = b2ContactFeature::e_vertex;
+
+ ie[1].v = m_polygonB.vertices[i2];
+ ie[1].id.cf.indexA = 0;
+ ie[1].id.cf.indexB = i2;
+ ie[1].id.cf.typeA = b2ContactFeature::e_face;
+ ie[1].id.cf.typeB = b2ContactFeature::e_vertex;
+
+ if (m_front)
+ {
+ rf.i1 = 0;
+ rf.i2 = 1;
+ rf.v1 = m_v1;
+ rf.v2 = m_v2;
+ rf.normal = m_normal1;
+ }
+ else
+ {
+ rf.i1 = 1;
+ rf.i2 = 0;
+ rf.v1 = m_v2;
+ rf.v2 = m_v1;
+ rf.normal = -m_normal1;
+ }
+ }
+ else
+ {
+ manifold->type = b2Manifold::e_faceB;
+
+ ie[0].v = m_v1;
+ ie[0].id.cf.indexA = 0;
+ ie[0].id.cf.indexB = primaryAxis.index;
+ ie[0].id.cf.typeA = b2ContactFeature::e_vertex;
+ ie[0].id.cf.typeB = b2ContactFeature::e_face;
+
+ ie[1].v = m_v2;
+ ie[1].id.cf.indexA = 0;
+ ie[1].id.cf.indexB = primaryAxis.index;
+ ie[1].id.cf.typeA = b2ContactFeature::e_vertex;
+ ie[1].id.cf.typeB = b2ContactFeature::e_face;
+
+ rf.i1 = primaryAxis.index;
+ rf.i2 = rf.i1 + 1 < m_polygonB.count ? rf.i1 + 1 : 0;
+ rf.v1 = m_polygonB.vertices[rf.i1];
+ rf.v2 = m_polygonB.vertices[rf.i2];
+ rf.normal = m_polygonB.normals[rf.i1];
+ }
+
+ rf.sideNormal1.Set(rf.normal.y, -rf.normal.x);
+ rf.sideNormal2 = -rf.sideNormal1;
+ rf.sideOffset1 = b2Dot(rf.sideNormal1, rf.v1);
+ rf.sideOffset2 = b2Dot(rf.sideNormal2, rf.v2);
+
+ // Clip incident edge against extruded edge1 side edges.
+ b2ClipVertex clipPoints1[2];
+ b2ClipVertex clipPoints2[2];
+ int32 np;
+
+ // Clip to box side 1
+ np = b2ClipSegmentToLine(clipPoints1, ie, rf.sideNormal1, rf.sideOffset1, rf.i1);
+
+ if (np < b2_maxManifoldPoints)
+ {
+ return;
+ }
+
+ // Clip to negative box side 1
+ np = b2ClipSegmentToLine(clipPoints2, clipPoints1, rf.sideNormal2, rf.sideOffset2, rf.i2);
+
+ if (np < b2_maxManifoldPoints)
+ {
+ return;
+ }
+
+ // Now clipPoints2 contains the clipped points.
+ if (primaryAxis.type == b2EPAxis::e_edgeA)
+ {
+ manifold->localNormal = rf.normal;
+ manifold->localPoint = rf.v1;
+ }
+ else
+ {
+ manifold->localNormal = polygonB->m_normals[rf.i1];
+ manifold->localPoint = polygonB->m_vertices[rf.i1];
+ }
+
+ int32 pointCount = 0;
+ for (int32 i = 0; i < b2_maxManifoldPoints; ++i)
+ {
+ float32 separation;
+
+ separation = b2Dot(rf.normal, clipPoints2[i].v - rf.v1);
+
+ if (separation <= m_radius)
+ {
+ b2ManifoldPoint* cp = manifold->points + pointCount;
+
+ if (primaryAxis.type == b2EPAxis::e_edgeA)
+ {
+ cp->localPoint = b2MulT(m_xf, clipPoints2[i].v);
+ cp->id = clipPoints2[i].id;
+ }
+ else
+ {
+ cp->localPoint = clipPoints2[i].v;
+ cp->id.cf.typeA = clipPoints2[i].id.cf.typeB;
+ cp->id.cf.typeB = clipPoints2[i].id.cf.typeA;
+ cp->id.cf.indexA = clipPoints2[i].id.cf.indexB;
+ cp->id.cf.indexB = clipPoints2[i].id.cf.indexA;
+ }
+
+ ++pointCount;
+ }
+ }
+
+ manifold->pointCount = pointCount;
+}
+
+b2EPAxis b2EPCollider::ComputeEdgeSeparation()
+{
+ b2EPAxis axis;
+ axis.type = b2EPAxis::e_edgeA;
+ axis.index = m_front ? 0 : 1;
+ axis.separation = FLT_MAX;
+
+ for (int32 i = 0; i < m_polygonB.count; ++i)
+ {
+ float32 s = b2Dot(m_normal, m_polygonB.vertices[i] - m_v1);
+ if (s < axis.separation)
+ {
+ axis.separation = s;
+ }
+ }
+
+ return axis;
+}
+
+b2EPAxis b2EPCollider::ComputePolygonSeparation()
+{
+ b2EPAxis axis;
+ axis.type = b2EPAxis::e_unknown;
+ axis.index = -1;
+ axis.separation = -FLT_MAX;
+
+ b2Vec2 perp(-m_normal.y, m_normal.x);
+
+ for (int32 i = 0; i < m_polygonB.count; ++i)
+ {
+ b2Vec2 n = -m_polygonB.normals[i];
+
+ float32 s1 = b2Dot(n, m_polygonB.vertices[i] - m_v1);
+ float32 s2 = b2Dot(n, m_polygonB.vertices[i] - m_v2);
+ float32 s = b2Min(s1, s2);
+
+ if (s > m_radius)
+ {
+ // No collision
+ axis.type = b2EPAxis::e_edgeB;
+ axis.index = i;
+ axis.separation = s;
+ return axis;
+ }
+
+ // Adjacency
+ if (b2Dot(n, perp) >= 0.0f)
+ {
+ if (b2Dot(n - m_upperLimit, m_normal) < -b2_angularSlop)
+ {
+ continue;
+ }
+ }
+ else
+ {
+ if (b2Dot(n - m_lowerLimit, m_normal) < -b2_angularSlop)
+ {
+ continue;
+ }
+ }
+
+ if (s > axis.separation)
+ {
+ axis.type = b2EPAxis::e_edgeB;
+ axis.index = i;
+ axis.separation = s;
+ }
+ }
+
+ return axis;
+}
+
+void b2CollideEdgeAndPolygon( b2Manifold* manifold,
+ const b2EdgeShape* edgeA, const b2Transform& xfA,
+ const b2PolygonShape* polygonB, const b2Transform& xfB)
+{
+ b2EPCollider collider;
+ collider.Collide(manifold, edgeA, xfA, polygonB, xfB);
+}
diff --git a/tests/box2d/Box2D/Collision/b2CollidePolygon.cpp b/tests/box2d/Box2D/Collision/b2CollidePolygon.cpp new file mode 100755 index 00000000..2f0946b9 --- /dev/null +++ b/tests/box2d/Box2D/Collision/b2CollidePolygon.cpp @@ -0,0 +1,317 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Collision/b2Collision.h>
+#include <Box2D/Collision/Shapes/b2PolygonShape.h>
+
+// Find the separation between poly1 and poly2 for a give edge normal on poly1.
+static float32 b2EdgeSeparation(const b2PolygonShape* poly1, const b2Transform& xf1, int32 edge1,
+ const b2PolygonShape* poly2, const b2Transform& xf2)
+{
+ const b2Vec2* vertices1 = poly1->m_vertices;
+ const b2Vec2* normals1 = poly1->m_normals;
+
+ int32 count2 = poly2->m_vertexCount;
+ const b2Vec2* vertices2 = poly2->m_vertices;
+
+ b2Assert(0 <= edge1 && edge1 < poly1->m_vertexCount);
+
+ // Convert normal from poly1's frame into poly2's frame.
+ b2Vec2 normal1World = b2Mul(xf1.q, normals1[edge1]);
+ b2Vec2 normal1 = b2MulT(xf2.q, normal1World);
+
+ // Find support vertex on poly2 for -normal.
+ int32 index = 0;
+ float32 minDot = b2_maxFloat;
+
+ for (int32 i = 0; i < count2; ++i)
+ {
+ float32 dot = b2Dot(vertices2[i], normal1);
+ if (dot < minDot)
+ {
+ minDot = dot;
+ index = i;
+ }
+ }
+
+ b2Vec2 v1 = b2Mul(xf1, vertices1[edge1]);
+ b2Vec2 v2 = b2Mul(xf2, vertices2[index]);
+ float32 separation = b2Dot(v2 - v1, normal1World);
+ return separation;
+}
+
+// Find the max separation between poly1 and poly2 using edge normals from poly1.
+static float32 b2FindMaxSeparation(int32* edgeIndex,
+ const b2PolygonShape* poly1, const b2Transform& xf1,
+ const b2PolygonShape* poly2, const b2Transform& xf2)
+{
+ int32 count1 = poly1->m_vertexCount;
+ const b2Vec2* normals1 = poly1->m_normals;
+
+ // Vector pointing from the centroid of poly1 to the centroid of poly2.
+ b2Vec2 d = b2Mul(xf2, poly2->m_centroid) - b2Mul(xf1, poly1->m_centroid);
+ b2Vec2 dLocal1 = b2MulT(xf1.q, d);
+
+ // Find edge normal on poly1 that has the largest projection onto d.
+ int32 edge = 0;
+ float32 maxDot = -b2_maxFloat;
+ for (int32 i = 0; i < count1; ++i)
+ {
+ float32 dot = b2Dot(normals1[i], dLocal1);
+ if (dot > maxDot)
+ {
+ maxDot = dot;
+ edge = i;
+ }
+ }
+
+ // Get the separation for the edge normal.
+ float32 s = b2EdgeSeparation(poly1, xf1, edge, poly2, xf2);
+
+ // Check the separation for the previous edge normal.
+ int32 prevEdge = edge - 1 >= 0 ? edge - 1 : count1 - 1;
+ float32 sPrev = b2EdgeSeparation(poly1, xf1, prevEdge, poly2, xf2);
+
+ // Check the separation for the next edge normal.
+ int32 nextEdge = edge + 1 < count1 ? edge + 1 : 0;
+ float32 sNext = b2EdgeSeparation(poly1, xf1, nextEdge, poly2, xf2);
+
+ // Find the best edge and the search direction.
+ int32 bestEdge;
+ float32 bestSeparation;
+ int32 increment;
+ if (sPrev > s && sPrev > sNext)
+ {
+ increment = -1;
+ bestEdge = prevEdge;
+ bestSeparation = sPrev;
+ }
+ else if (sNext > s)
+ {
+ increment = 1;
+ bestEdge = nextEdge;
+ bestSeparation = sNext;
+ }
+ else
+ {
+ *edgeIndex = edge;
+ return s;
+ }
+
+ // Perform a local search for the best edge normal.
+ for ( ; ; )
+ {
+ if (increment == -1)
+ edge = bestEdge - 1 >= 0 ? bestEdge - 1 : count1 - 1;
+ else
+ edge = bestEdge + 1 < count1 ? bestEdge + 1 : 0;
+
+ s = b2EdgeSeparation(poly1, xf1, edge, poly2, xf2);
+
+ if (s > bestSeparation)
+ {
+ bestEdge = edge;
+ bestSeparation = s;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ *edgeIndex = bestEdge;
+ return bestSeparation;
+}
+
+static void b2FindIncidentEdge(b2ClipVertex c[2],
+ const b2PolygonShape* poly1, const b2Transform& xf1, int32 edge1,
+ const b2PolygonShape* poly2, const b2Transform& xf2)
+{
+ const b2Vec2* normals1 = poly1->m_normals;
+
+ int32 count2 = poly2->m_vertexCount;
+ const b2Vec2* vertices2 = poly2->m_vertices;
+ const b2Vec2* normals2 = poly2->m_normals;
+
+ b2Assert(0 <= edge1 && edge1 < poly1->m_vertexCount);
+
+ // Get the normal of the reference edge in poly2's frame.
+ b2Vec2 normal1 = b2MulT(xf2.q, b2Mul(xf1.q, normals1[edge1]));
+
+ // Find the incident edge on poly2.
+ int32 index = 0;
+ float32 minDot = b2_maxFloat;
+ for (int32 i = 0; i < count2; ++i)
+ {
+ float32 dot = b2Dot(normal1, normals2[i]);
+ if (dot < minDot)
+ {
+ minDot = dot;
+ index = i;
+ }
+ }
+
+ // Build the clip vertices for the incident edge.
+ int32 i1 = index;
+ int32 i2 = i1 + 1 < count2 ? i1 + 1 : 0;
+
+ c[0].v = b2Mul(xf2, vertices2[i1]);
+ c[0].id.cf.indexA = (uint8)edge1;
+ c[0].id.cf.indexB = (uint8)i1;
+ c[0].id.cf.typeA = b2ContactFeature::e_face;
+ c[0].id.cf.typeB = b2ContactFeature::e_vertex;
+
+ c[1].v = b2Mul(xf2, vertices2[i2]);
+ c[1].id.cf.indexA = (uint8)edge1;
+ c[1].id.cf.indexB = (uint8)i2;
+ c[1].id.cf.typeA = b2ContactFeature::e_face;
+ c[1].id.cf.typeB = b2ContactFeature::e_vertex;
+}
+
+// Find edge normal of max separation on A - return if separating axis is found
+// Find edge normal of max separation on B - return if separation axis is found
+// Choose reference edge as min(minA, minB)
+// Find incident edge
+// Clip
+
+// The normal points from 1 to 2
+void b2CollidePolygons(b2Manifold* manifold,
+ const b2PolygonShape* polyA, const b2Transform& xfA,
+ const b2PolygonShape* polyB, const b2Transform& xfB)
+{
+ manifold->pointCount = 0;
+ float32 totalRadius = polyA->m_radius + polyB->m_radius;
+
+ int32 edgeA = 0;
+ float32 separationA = b2FindMaxSeparation(&edgeA, polyA, xfA, polyB, xfB);
+ if (separationA > totalRadius)
+ return;
+
+ int32 edgeB = 0;
+ float32 separationB = b2FindMaxSeparation(&edgeB, polyB, xfB, polyA, xfA);
+ if (separationB > totalRadius)
+ return;
+
+ const b2PolygonShape* poly1; // reference polygon
+ const b2PolygonShape* poly2; // incident polygon
+ b2Transform xf1, xf2;
+ int32 edge1; // reference edge
+ uint8 flip;
+ const float32 k_relativeTol = 0.98f;
+ const float32 k_absoluteTol = 0.001f;
+
+ if (separationB > k_relativeTol * separationA + k_absoluteTol)
+ {
+ poly1 = polyB;
+ poly2 = polyA;
+ xf1 = xfB;
+ xf2 = xfA;
+ edge1 = edgeB;
+ manifold->type = b2Manifold::e_faceB;
+ flip = 1;
+ }
+ else
+ {
+ poly1 = polyA;
+ poly2 = polyB;
+ xf1 = xfA;
+ xf2 = xfB;
+ edge1 = edgeA;
+ manifold->type = b2Manifold::e_faceA;
+ flip = 0;
+ }
+
+ b2ClipVertex incidentEdge[2];
+ b2FindIncidentEdge(incidentEdge, poly1, xf1, edge1, poly2, xf2);
+
+ int32 count1 = poly1->m_vertexCount;
+ const b2Vec2* vertices1 = poly1->m_vertices;
+
+ int32 iv1 = edge1;
+ int32 iv2 = edge1 + 1 < count1 ? edge1 + 1 : 0;
+
+ b2Vec2 v11 = vertices1[iv1];
+ b2Vec2 v12 = vertices1[iv2];
+
+ b2Vec2 localTangent = v12 - v11;
+ localTangent.Normalize();
+
+ b2Vec2 localNormal = b2Cross(localTangent, 1.0f);
+ b2Vec2 planePoint = 0.5f * (v11 + v12);
+
+ b2Vec2 tangent = b2Mul(xf1.q, localTangent);
+ b2Vec2 normal = b2Cross(tangent, 1.0f);
+
+ v11 = b2Mul(xf1, v11);
+ v12 = b2Mul(xf1, v12);
+
+ // Face offset.
+ float32 frontOffset = b2Dot(normal, v11);
+
+ // Side offsets, extended by polytope skin thickness.
+ float32 sideOffset1 = -b2Dot(tangent, v11) + totalRadius;
+ float32 sideOffset2 = b2Dot(tangent, v12) + totalRadius;
+
+ // Clip incident edge against extruded edge1 side edges.
+ b2ClipVertex clipPoints1[2];
+ b2ClipVertex clipPoints2[2];
+ int np;
+
+ // Clip to box side 1
+ np = b2ClipSegmentToLine(clipPoints1, incidentEdge, -tangent, sideOffset1, iv1);
+
+ if (np < 2)
+ return;
+
+ // Clip to negative box side 1
+ np = b2ClipSegmentToLine(clipPoints2, clipPoints1, tangent, sideOffset2, iv2);
+
+ if (np < 2)
+ {
+ return;
+ }
+
+ // Now clipPoints2 contains the clipped points.
+ manifold->localNormal = localNormal;
+ manifold->localPoint = planePoint;
+
+ int32 pointCount = 0;
+ for (int32 i = 0; i < b2_maxManifoldPoints; ++i)
+ {
+ float32 separation = b2Dot(normal, clipPoints2[i].v) - frontOffset;
+
+ if (separation <= totalRadius)
+ {
+ b2ManifoldPoint* cp = manifold->points + pointCount;
+ cp->localPoint = b2MulT(xf2, clipPoints2[i].v);
+ cp->id = clipPoints2[i].id;
+ if (flip)
+ {
+ // Swap features
+ b2ContactFeature cf = cp->id.cf;
+ cp->id.cf.indexA = cf.indexB;
+ cp->id.cf.indexB = cf.indexA;
+ cp->id.cf.typeA = cf.typeB;
+ cp->id.cf.typeB = cf.typeA;
+ }
+ ++pointCount;
+ }
+ }
+
+ manifold->pointCount = pointCount;
+}
diff --git a/tests/box2d/Box2D/Collision/b2Collision.cpp b/tests/box2d/Box2D/Collision/b2Collision.cpp new file mode 100755 index 00000000..4b092f0c --- /dev/null +++ b/tests/box2d/Box2D/Collision/b2Collision.cpp @@ -0,0 +1,249 @@ +/*
+* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Collision/b2Collision.h>
+#include <Box2D/Collision/b2Distance.h>
+
+void b2WorldManifold::Initialize(const b2Manifold* manifold,
+ const b2Transform& xfA, float32 radiusA,
+ const b2Transform& xfB, float32 radiusB)
+{
+ if (manifold->pointCount == 0)
+ {
+ return;
+ }
+
+ switch (manifold->type)
+ {
+ case b2Manifold::e_circles:
+ {
+ normal.Set(1.0f, 0.0f);
+ b2Vec2 pointA = b2Mul(xfA, manifold->localPoint);
+ b2Vec2 pointB = b2Mul(xfB, manifold->points[0].localPoint);
+ if (b2DistanceSquared(pointA, pointB) > b2_epsilon * b2_epsilon)
+ {
+ normal = pointB - pointA;
+ normal.Normalize();
+ }
+
+ b2Vec2 cA = pointA + radiusA * normal;
+ b2Vec2 cB = pointB - radiusB * normal;
+ points[0] = 0.5f * (cA + cB);
+ }
+ break;
+
+ case b2Manifold::e_faceA:
+ {
+ normal = b2Mul(xfA.q, manifold->localNormal);
+ b2Vec2 planePoint = b2Mul(xfA, manifold->localPoint);
+
+ for (int32 i = 0; i < manifold->pointCount; ++i)
+ {
+ b2Vec2 clipPoint = b2Mul(xfB, manifold->points[i].localPoint);
+ b2Vec2 cA = clipPoint + (radiusA - b2Dot(clipPoint - planePoint, normal)) * normal;
+ b2Vec2 cB = clipPoint - radiusB * normal;
+ points[i] = 0.5f * (cA + cB);
+ }
+ }
+ break;
+
+ case b2Manifold::e_faceB:
+ {
+ normal = b2Mul(xfB.q, manifold->localNormal);
+ b2Vec2 planePoint = b2Mul(xfB, manifold->localPoint);
+
+ for (int32 i = 0; i < manifold->pointCount; ++i)
+ {
+ b2Vec2 clipPoint = b2Mul(xfA, manifold->points[i].localPoint);
+ b2Vec2 cB = clipPoint + (radiusB - b2Dot(clipPoint - planePoint, normal)) * normal;
+ b2Vec2 cA = clipPoint - radiusA * normal;
+ points[i] = 0.5f * (cA + cB);
+ }
+
+ // Ensure normal points from A to B.
+ normal = -normal;
+ }
+ break;
+ }
+}
+
+void b2GetPointStates(b2PointState state1[b2_maxManifoldPoints], b2PointState state2[b2_maxManifoldPoints],
+ const b2Manifold* manifold1, const b2Manifold* manifold2)
+{
+ for (int32 i = 0; i < b2_maxManifoldPoints; ++i)
+ {
+ state1[i] = b2_nullState;
+ state2[i] = b2_nullState;
+ }
+
+ // Detect persists and removes.
+ for (int32 i = 0; i < manifold1->pointCount; ++i)
+ {
+ b2ContactID id = manifold1->points[i].id;
+
+ state1[i] = b2_removeState;
+
+ for (int32 j = 0; j < manifold2->pointCount; ++j)
+ {
+ if (manifold2->points[j].id.key == id.key)
+ {
+ state1[i] = b2_persistState;
+ break;
+ }
+ }
+ }
+
+ // Detect persists and adds.
+ for (int32 i = 0; i < manifold2->pointCount; ++i)
+ {
+ b2ContactID id = manifold2->points[i].id;
+
+ state2[i] = b2_addState;
+
+ for (int32 j = 0; j < manifold1->pointCount; ++j)
+ {
+ if (manifold1->points[j].id.key == id.key)
+ {
+ state2[i] = b2_persistState;
+ break;
+ }
+ }
+ }
+}
+
+// From Real-time Collision Detection, p179.
+bool b2AABB::RayCast(b2RayCastOutput* output, const b2RayCastInput& input) const
+{
+ float32 tmin = -b2_maxFloat;
+ float32 tmax = b2_maxFloat;
+
+ b2Vec2 p = input.p1;
+ b2Vec2 d = input.p2 - input.p1;
+ b2Vec2 absD = b2Abs(d);
+
+ b2Vec2 normal;
+
+ for (int32 i = 0; i < 2; ++i)
+ {
+ if (absD(i) < b2_epsilon)
+ {
+ // Parallel.
+ if (p(i) < lowerBound(i) || upperBound(i) < p(i))
+ {
+ return false;
+ }
+ }
+ else
+ {
+ float32 inv_d = 1.0f / d(i);
+ float32 t1 = (lowerBound(i) - p(i)) * inv_d;
+ float32 t2 = (upperBound(i) - p(i)) * inv_d;
+
+ // Sign of the normal vector.
+ float32 s = -1.0f;
+
+ if (t1 > t2)
+ {
+ b2Swap(t1, t2);
+ s = 1.0f;
+ }
+
+ // Push the min up
+ if (t1 > tmin)
+ {
+ normal.SetZero();
+ normal(i) = s;
+ tmin = t1;
+ }
+
+ // Pull the max down
+ tmax = b2Min(tmax, t2);
+
+ if (tmin > tmax)
+ {
+ return false;
+ }
+ }
+ }
+
+ // Does the ray start inside the box?
+ // Does the ray intersect beyond the max fraction?
+ if (tmin < 0.0f || input.maxFraction < tmin)
+ {
+ return false;
+ }
+
+ // Intersection.
+ output->fraction = tmin;
+ output->normal = normal;
+ return true;
+}
+
+// Sutherland-Hodgman clipping.
+int32 b2ClipSegmentToLine(b2ClipVertex vOut[2], const b2ClipVertex vIn[2],
+ const b2Vec2& normal, float32 offset, int32 vertexIndexA)
+{
+ // Start with no output points
+ int32 numOut = 0;
+
+ // Calculate the distance of end points to the line
+ float32 distance0 = b2Dot(normal, vIn[0].v) - offset;
+ float32 distance1 = b2Dot(normal, vIn[1].v) - offset;
+
+ // If the points are behind the plane
+ if (distance0 <= 0.0f) vOut[numOut++] = vIn[0];
+ if (distance1 <= 0.0f) vOut[numOut++] = vIn[1];
+
+ // If the points are on different sides of the plane
+ if (distance0 * distance1 < 0.0f)
+ {
+ // Find intersection point of edge and plane
+ float32 interp = distance0 / (distance0 - distance1);
+ vOut[numOut].v = vIn[0].v + interp * (vIn[1].v - vIn[0].v);
+
+ // VertexA is hitting edgeB.
+ vOut[numOut].id.cf.indexA = vertexIndexA;
+ vOut[numOut].id.cf.indexB = vIn[0].id.cf.indexB;
+ vOut[numOut].id.cf.typeA = b2ContactFeature::e_vertex;
+ vOut[numOut].id.cf.typeB = b2ContactFeature::e_face;
+ ++numOut;
+ }
+
+ return numOut;
+}
+
+bool b2TestOverlap( const b2Shape* shapeA, int32 indexA,
+ const b2Shape* shapeB, int32 indexB,
+ const b2Transform& xfA, const b2Transform& xfB)
+{
+ b2DistanceInput input;
+ input.proxyA.Set(shapeA, indexA);
+ input.proxyB.Set(shapeB, indexB);
+ input.transformA = xfA;
+ input.transformB = xfB;
+ input.useRadii = true;
+
+ b2SimplexCache cache;
+ cache.count = 0;
+
+ b2DistanceOutput output;
+
+ b2Distance(&output, &cache, &input);
+
+ return output.distance < 10.0f * b2_epsilon;
+}
diff --git a/tests/box2d/Box2D/Collision/b2Collision.h b/tests/box2d/Box2D/Collision/b2Collision.h new file mode 100755 index 00000000..71bf15b6 --- /dev/null +++ b/tests/box2d/Box2D/Collision/b2Collision.h @@ -0,0 +1,281 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_COLLISION_H
+#define B2_COLLISION_H
+
+#include <Box2D/Common/b2Math.h>
+#ifndef EM_NO_LIBCPP
+#include <climits>
+#endif
+
+/// @file
+/// Structures and functions used for computing contact points, distance
+/// queries, and TOI queries.
+
+class b2Shape;
+class b2CircleShape;
+class b2EdgeShape;
+class b2PolygonShape;
+
+const uint8 b2_nullFeature = UCHAR_MAX;
+
+/// The features that intersect to form the contact point
+/// This must be 4 bytes or less.
+struct b2ContactFeature
+{
+ enum Type
+ {
+ e_vertex = 0,
+ e_face = 1
+ };
+
+ uint8 indexA; ///< Feature index on shapeA
+ uint8 indexB; ///< Feature index on shapeB
+ uint8 typeA; ///< The feature type on shapeA
+ uint8 typeB; ///< The feature type on shapeB
+};
+
+/// Contact ids to facilitate warm starting.
+union b2ContactID
+{
+ b2ContactFeature cf;
+ uint32 key; ///< Used to quickly compare contact ids.
+};
+
+/// A manifold point is a contact point belonging to a contact
+/// manifold. It holds details related to the geometry and dynamics
+/// of the contact points.
+/// The local point usage depends on the manifold type:
+/// -e_circles: the local center of circleB
+/// -e_faceA: the local center of cirlceB or the clip point of polygonB
+/// -e_faceB: the clip point of polygonA
+/// This structure is stored across time steps, so we keep it small.
+/// Note: the impulses are used for internal caching and may not
+/// provide reliable contact forces, especially for high speed collisions.
+struct b2ManifoldPoint
+{
+ b2Vec2 localPoint; ///< usage depends on manifold type
+ float32 normalImpulse; ///< the non-penetration impulse
+ float32 tangentImpulse; ///< the friction impulse
+ b2ContactID id; ///< uniquely identifies a contact point between two shapes
+};
+
+/// A manifold for two touching convex shapes.
+/// Box2D supports multiple types of contact:
+/// - clip point versus plane with radius
+/// - point versus point with radius (circles)
+/// The local point usage depends on the manifold type:
+/// -e_circles: the local center of circleA
+/// -e_faceA: the center of faceA
+/// -e_faceB: the center of faceB
+/// Similarly the local normal usage:
+/// -e_circles: not used
+/// -e_faceA: the normal on polygonA
+/// -e_faceB: the normal on polygonB
+/// We store contacts in this way so that position correction can
+/// account for movement, which is critical for continuous physics.
+/// All contact scenarios must be expressed in one of these types.
+/// This structure is stored across time steps, so we keep it small.
+struct b2Manifold
+{
+ enum Type
+ {
+ e_circles,
+ e_faceA,
+ e_faceB
+ };
+
+ b2ManifoldPoint points[b2_maxManifoldPoints]; ///< the points of contact
+ b2Vec2 localNormal; ///< not use for Type::e_points
+ b2Vec2 localPoint; ///< usage depends on manifold type
+ Type type;
+ int32 pointCount; ///< the number of manifold points
+};
+
+/// This is used to compute the current state of a contact manifold.
+struct b2WorldManifold
+{
+ /// Evaluate the manifold with supplied transforms. This assumes
+ /// modest motion from the original state. This does not change the
+ /// point count, impulses, etc. The radii must come from the shapes
+ /// that generated the manifold.
+ void Initialize(const b2Manifold* manifold,
+ const b2Transform& xfA, float32 radiusA,
+ const b2Transform& xfB, float32 radiusB);
+
+ b2Vec2 normal; ///< world vector pointing from A to B
+ b2Vec2 points[b2_maxManifoldPoints]; ///< world contact point (point of intersection)
+};
+
+/// This is used for determining the state of contact points.
+enum b2PointState
+{
+ b2_nullState, ///< point does not exist
+ b2_addState, ///< point was added in the update
+ b2_persistState, ///< point persisted across the update
+ b2_removeState ///< point was removed in the update
+};
+
+/// Compute the point states given two manifolds. The states pertain to the transition from manifold1
+/// to manifold2. So state1 is either persist or remove while state2 is either add or persist.
+void b2GetPointStates(b2PointState state1[b2_maxManifoldPoints], b2PointState state2[b2_maxManifoldPoints],
+ const b2Manifold* manifold1, const b2Manifold* manifold2);
+
+/// Used for computing contact manifolds.
+struct b2ClipVertex
+{
+ b2Vec2 v;
+ b2ContactID id;
+};
+
+/// Ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).
+struct b2RayCastInput
+{
+ b2Vec2 p1, p2;
+ float32 maxFraction;
+};
+
+/// Ray-cast output data. The ray hits at p1 + fraction * (p2 - p1), where p1 and p2
+/// come from b2RayCastInput.
+struct b2RayCastOutput
+{
+ b2Vec2 normal;
+ float32 fraction;
+};
+
+/// An axis aligned bounding box.
+// emscripten - b2AABB: add constructor
+struct b2AABB
+{
+ b2AABB() {}
+
+ /// Verify that the bounds are sorted.
+ bool IsValid() const;
+
+ /// Get the center of the AABB.
+ b2Vec2 GetCenter() const
+ {
+ return 0.5f * (lowerBound + upperBound);
+ }
+
+ /// Get the extents of the AABB (half-widths).
+ b2Vec2 GetExtents() const
+ {
+ return 0.5f * (upperBound - lowerBound);
+ }
+
+ /// Get the perimeter length
+ float32 GetPerimeter() const
+ {
+ float32 wx = upperBound.x - lowerBound.x;
+ float32 wy = upperBound.y - lowerBound.y;
+ return 2.0f * (wx + wy);
+ }
+
+ /// Combine an AABB into this one.
+ void Combine(const b2AABB& aabb)
+ {
+ lowerBound = b2Min(lowerBound, aabb.lowerBound);
+ upperBound = b2Max(upperBound, aabb.upperBound);
+ }
+
+ /// Combine two AABBs into this one.
+ void Combine(const b2AABB& aabb1, const b2AABB& aabb2)
+ {
+ lowerBound = b2Min(aabb1.lowerBound, aabb2.lowerBound);
+ upperBound = b2Max(aabb1.upperBound, aabb2.upperBound);
+ }
+
+ /// Does this aabb contain the provided AABB.
+ bool Contains(const b2AABB& aabb) const
+ {
+ bool result = true;
+ result = result && lowerBound.x <= aabb.lowerBound.x;
+ result = result && lowerBound.y <= aabb.lowerBound.y;
+ result = result && aabb.upperBound.x <= upperBound.x;
+ result = result && aabb.upperBound.y <= upperBound.y;
+ return result;
+ }
+
+ bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input) const;
+
+ b2Vec2 lowerBound; ///< the lower vertex
+ b2Vec2 upperBound; ///< the upper vertex
+};
+
+/// Compute the collision manifold between two circles.
+void b2CollideCircles(b2Manifold* manifold,
+ const b2CircleShape* circleA, const b2Transform& xfA,
+ const b2CircleShape* circleB, const b2Transform& xfB);
+
+/// Compute the collision manifold between a polygon and a circle.
+void b2CollidePolygonAndCircle(b2Manifold* manifold,
+ const b2PolygonShape* polygonA, const b2Transform& xfA,
+ const b2CircleShape* circleB, const b2Transform& xfB);
+
+/// Compute the collision manifold between two polygons.
+void b2CollidePolygons(b2Manifold* manifold,
+ const b2PolygonShape* polygonA, const b2Transform& xfA,
+ const b2PolygonShape* polygonB, const b2Transform& xfB);
+
+/// Compute the collision manifold between an edge and a circle.
+void b2CollideEdgeAndCircle(b2Manifold* manifold,
+ const b2EdgeShape* polygonA, const b2Transform& xfA,
+ const b2CircleShape* circleB, const b2Transform& xfB);
+
+/// Compute the collision manifold between an edge and a circle.
+void b2CollideEdgeAndPolygon(b2Manifold* manifold,
+ const b2EdgeShape* edgeA, const b2Transform& xfA,
+ const b2PolygonShape* circleB, const b2Transform& xfB);
+
+/// Clipping for contact manifolds.
+int32 b2ClipSegmentToLine(b2ClipVertex vOut[2], const b2ClipVertex vIn[2],
+ const b2Vec2& normal, float32 offset, int32 vertexIndexA);
+
+/// Determine if two generic shapes overlap.
+bool b2TestOverlap( const b2Shape* shapeA, int32 indexA,
+ const b2Shape* shapeB, int32 indexB,
+ const b2Transform& xfA, const b2Transform& xfB);
+
+// ---------------- Inline Functions ------------------------------------------
+
+inline bool b2AABB::IsValid() const
+{
+ b2Vec2 d = upperBound - lowerBound;
+ bool valid = d.x >= 0.0f && d.y >= 0.0f;
+ valid = valid && lowerBound.IsValid() && upperBound.IsValid();
+ return valid;
+}
+
+inline bool b2TestOverlap(const b2AABB& a, const b2AABB& b)
+{
+ b2Vec2 d1, d2;
+ d1 = b.lowerBound - a.upperBound;
+ d2 = a.lowerBound - b.upperBound;
+
+ if (d1.x > 0.0f || d1.y > 0.0f)
+ return false;
+
+ if (d2.x > 0.0f || d2.y > 0.0f)
+ return false;
+
+ return true;
+}
+
+#endif
diff --git a/tests/box2d/Box2D/Collision/b2Distance.cpp b/tests/box2d/Box2D/Collision/b2Distance.cpp new file mode 100755 index 00000000..1010c8c0 --- /dev/null +++ b/tests/box2d/Box2D/Collision/b2Distance.cpp @@ -0,0 +1,603 @@ +/*
+* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Collision/b2Distance.h>
+#include <Box2D/Collision/Shapes/b2CircleShape.h>
+#include <Box2D/Collision/Shapes/b2EdgeShape.h>
+#include <Box2D/Collision/Shapes/b2ChainShape.h>
+#include <Box2D/Collision/Shapes/b2PolygonShape.h>
+
+// GJK using Voronoi regions (Christer Ericson) and Barycentric coordinates.
+int32 b2_gjkCalls, b2_gjkIters, b2_gjkMaxIters;
+
+void b2DistanceProxy::Set(const b2Shape* shape, int32 index)
+{
+ switch (shape->GetType())
+ {
+ case b2Shape::e_circle:
+ {
+ const b2CircleShape* circle = (b2CircleShape*)shape;
+ m_vertices = &circle->m_p;
+ m_count = 1;
+ m_radius = circle->m_radius;
+ }
+ break;
+
+ case b2Shape::e_polygon:
+ {
+ const b2PolygonShape* polygon = (b2PolygonShape*)shape;
+ m_vertices = polygon->m_vertices;
+ m_count = polygon->m_vertexCount;
+ m_radius = polygon->m_radius;
+ }
+ break;
+
+ case b2Shape::e_chain:
+ {
+ const b2ChainShape* chain = (b2ChainShape*)shape;
+ b2Assert(0 <= index && index < chain->m_count);
+
+ m_buffer[0] = chain->m_vertices[index];
+ if (index + 1 < chain->m_count)
+ {
+ m_buffer[1] = chain->m_vertices[index + 1];
+ }
+ else
+ {
+ m_buffer[1] = chain->m_vertices[0];
+ }
+
+ m_vertices = m_buffer;
+ m_count = 2;
+ m_radius = chain->m_radius;
+ }
+ break;
+
+ case b2Shape::e_edge:
+ {
+ const b2EdgeShape* edge = (b2EdgeShape*)shape;
+ m_vertices = &edge->m_vertex1;
+ m_count = 2;
+ m_radius = edge->m_radius;
+ }
+ break;
+
+ default:
+ b2Assert(false);
+ }
+}
+
+
+struct b2SimplexVertex
+{
+ b2Vec2 wA; // support point in proxyA
+ b2Vec2 wB; // support point in proxyB
+ b2Vec2 w; // wB - wA
+ float32 a; // barycentric coordinate for closest point
+ int32 indexA; // wA index
+ int32 indexB; // wB index
+};
+
+struct b2Simplex
+{
+ void ReadCache( const b2SimplexCache* cache,
+ const b2DistanceProxy* proxyA, const b2Transform& transformA,
+ const b2DistanceProxy* proxyB, const b2Transform& transformB)
+ {
+ b2Assert(cache->count <= 3);
+
+ // Copy data from cache.
+ m_count = cache->count;
+ b2SimplexVertex* vertices = &m_v1;
+ for (int32 i = 0; i < m_count; ++i)
+ {
+ b2SimplexVertex* v = vertices + i;
+ v->indexA = cache->indexA[i];
+ v->indexB = cache->indexB[i];
+ b2Vec2 wALocal = proxyA->GetVertex(v->indexA);
+ b2Vec2 wBLocal = proxyB->GetVertex(v->indexB);
+ v->wA = b2Mul(transformA, wALocal);
+ v->wB = b2Mul(transformB, wBLocal);
+ v->w = v->wB - v->wA;
+ v->a = 0.0f;
+ }
+
+ // Compute the new simplex metric, if it is substantially different than
+ // old metric then flush the simplex.
+ if (m_count > 1)
+ {
+ float32 metric1 = cache->metric;
+ float32 metric2 = GetMetric();
+ if (metric2 < 0.5f * metric1 || 2.0f * metric1 < metric2 || metric2 < b2_epsilon)
+ {
+ // Reset the simplex.
+ m_count = 0;
+ }
+ }
+
+ // If the cache is empty or invalid ...
+ if (m_count == 0)
+ {
+ b2SimplexVertex* v = vertices + 0;
+ v->indexA = 0;
+ v->indexB = 0;
+ b2Vec2 wALocal = proxyA->GetVertex(0);
+ b2Vec2 wBLocal = proxyB->GetVertex(0);
+ v->wA = b2Mul(transformA, wALocal);
+ v->wB = b2Mul(transformB, wBLocal);
+ v->w = v->wB - v->wA;
+ m_count = 1;
+ }
+ }
+
+ void WriteCache(b2SimplexCache* cache) const
+ {
+ cache->metric = GetMetric();
+ cache->count = uint16(m_count);
+ const b2SimplexVertex* vertices = &m_v1;
+ for (int32 i = 0; i < m_count; ++i)
+ {
+ cache->indexA[i] = uint8(vertices[i].indexA);
+ cache->indexB[i] = uint8(vertices[i].indexB);
+ }
+ }
+
+ b2Vec2 GetSearchDirection() const
+ {
+ switch (m_count)
+ {
+ case 1:
+ return -m_v1.w;
+
+ case 2:
+ {
+ b2Vec2 e12 = m_v2.w - m_v1.w;
+ float32 sgn = b2Cross(e12, -m_v1.w);
+ if (sgn > 0.0f)
+ {
+ // Origin is left of e12.
+ return b2Cross(1.0f, e12);
+ }
+ else
+ {
+ // Origin is right of e12.
+ return b2Cross(e12, 1.0f);
+ }
+ }
+
+ default:
+ b2Assert(false);
+ return b2Vec2_zero;
+ }
+ }
+
+ b2Vec2 GetClosestPoint() const
+ {
+ switch (m_count)
+ {
+ case 0:
+ b2Assert(false);
+ return b2Vec2_zero;
+
+ case 1:
+ return m_v1.w;
+
+ case 2:
+ return m_v1.a * m_v1.w + m_v2.a * m_v2.w;
+
+ case 3:
+ return b2Vec2_zero;
+
+ default:
+ b2Assert(false);
+ return b2Vec2_zero;
+ }
+ }
+
+ void GetWitnessPoints(b2Vec2* pA, b2Vec2* pB) const
+ {
+ switch (m_count)
+ {
+ case 0:
+ b2Assert(false);
+ break;
+
+ case 1:
+ *pA = m_v1.wA;
+ *pB = m_v1.wB;
+ break;
+
+ case 2:
+ *pA = m_v1.a * m_v1.wA + m_v2.a * m_v2.wA;
+ *pB = m_v1.a * m_v1.wB + m_v2.a * m_v2.wB;
+ break;
+
+ case 3:
+ *pA = m_v1.a * m_v1.wA + m_v2.a * m_v2.wA + m_v3.a * m_v3.wA;
+ *pB = *pA;
+ break;
+
+ default:
+ b2Assert(false);
+ break;
+ }
+ }
+
+ float32 GetMetric() const
+ {
+ switch (m_count)
+ {
+ case 0:
+ b2Assert(false);
+ return 0.0;
+
+ case 1:
+ return 0.0f;
+
+ case 2:
+ return b2Distance(m_v1.w, m_v2.w);
+
+ case 3:
+ return b2Cross(m_v2.w - m_v1.w, m_v3.w - m_v1.w);
+
+ default:
+ b2Assert(false);
+ return 0.0f;
+ }
+ }
+
+ void Solve2();
+ void Solve3();
+
+ b2SimplexVertex m_v1, m_v2, m_v3;
+ int32 m_count;
+};
+
+
+// Solve a line segment using barycentric coordinates.
+//
+// p = a1 * w1 + a2 * w2
+// a1 + a2 = 1
+//
+// The vector from the origin to the closest point on the line is
+// perpendicular to the line.
+// e12 = w2 - w1
+// dot(p, e) = 0
+// a1 * dot(w1, e) + a2 * dot(w2, e) = 0
+//
+// 2-by-2 linear system
+// [1 1 ][a1] = [1]
+// [w1.e12 w2.e12][a2] = [0]
+//
+// Define
+// d12_1 = dot(w2, e12)
+// d12_2 = -dot(w1, e12)
+// d12 = d12_1 + d12_2
+//
+// Solution
+// a1 = d12_1 / d12
+// a2 = d12_2 / d12
+void b2Simplex::Solve2()
+{
+ b2Vec2 w1 = m_v1.w;
+ b2Vec2 w2 = m_v2.w;
+ b2Vec2 e12 = w2 - w1;
+
+ // w1 region
+ float32 d12_2 = -b2Dot(w1, e12);
+ if (d12_2 <= 0.0f)
+ {
+ // a2 <= 0, so we clamp it to 0
+ m_v1.a = 1.0f;
+ m_count = 1;
+ return;
+ }
+
+ // w2 region
+ float32 d12_1 = b2Dot(w2, e12);
+ if (d12_1 <= 0.0f)
+ {
+ // a1 <= 0, so we clamp it to 0
+ m_v2.a = 1.0f;
+ m_count = 1;
+ m_v1 = m_v2;
+ return;
+ }
+
+ // Must be in e12 region.
+ float32 inv_d12 = 1.0f / (d12_1 + d12_2);
+ m_v1.a = d12_1 * inv_d12;
+ m_v2.a = d12_2 * inv_d12;
+ m_count = 2;
+}
+
+// Possible regions:
+// - points[2]
+// - edge points[0]-points[2]
+// - edge points[1]-points[2]
+// - inside the triangle
+void b2Simplex::Solve3()
+{
+ b2Vec2 w1 = m_v1.w;
+ b2Vec2 w2 = m_v2.w;
+ b2Vec2 w3 = m_v3.w;
+
+ // Edge12
+ // [1 1 ][a1] = [1]
+ // [w1.e12 w2.e12][a2] = [0]
+ // a3 = 0
+ b2Vec2 e12 = w2 - w1;
+ float32 w1e12 = b2Dot(w1, e12);
+ float32 w2e12 = b2Dot(w2, e12);
+ float32 d12_1 = w2e12;
+ float32 d12_2 = -w1e12;
+
+ // Edge13
+ // [1 1 ][a1] = [1]
+ // [w1.e13 w3.e13][a3] = [0]
+ // a2 = 0
+ b2Vec2 e13 = w3 - w1;
+ float32 w1e13 = b2Dot(w1, e13);
+ float32 w3e13 = b2Dot(w3, e13);
+ float32 d13_1 = w3e13;
+ float32 d13_2 = -w1e13;
+
+ // Edge23
+ // [1 1 ][a2] = [1]
+ // [w2.e23 w3.e23][a3] = [0]
+ // a1 = 0
+ b2Vec2 e23 = w3 - w2;
+ float32 w2e23 = b2Dot(w2, e23);
+ float32 w3e23 = b2Dot(w3, e23);
+ float32 d23_1 = w3e23;
+ float32 d23_2 = -w2e23;
+
+ // Triangle123
+ float32 n123 = b2Cross(e12, e13);
+
+ float32 d123_1 = n123 * b2Cross(w2, w3);
+ float32 d123_2 = n123 * b2Cross(w3, w1);
+ float32 d123_3 = n123 * b2Cross(w1, w2);
+
+ // w1 region
+ if (d12_2 <= 0.0f && d13_2 <= 0.0f)
+ {
+ m_v1.a = 1.0f;
+ m_count = 1;
+ return;
+ }
+
+ // e12
+ if (d12_1 > 0.0f && d12_2 > 0.0f && d123_3 <= 0.0f)
+ {
+ float32 inv_d12 = 1.0f / (d12_1 + d12_2);
+ m_v1.a = d12_1 * inv_d12;
+ m_v2.a = d12_2 * inv_d12;
+ m_count = 2;
+ return;
+ }
+
+ // e13
+ if (d13_1 > 0.0f && d13_2 > 0.0f && d123_2 <= 0.0f)
+ {
+ float32 inv_d13 = 1.0f / (d13_1 + d13_2);
+ m_v1.a = d13_1 * inv_d13;
+ m_v3.a = d13_2 * inv_d13;
+ m_count = 2;
+ m_v2 = m_v3;
+ return;
+ }
+
+ // w2 region
+ if (d12_1 <= 0.0f && d23_2 <= 0.0f)
+ {
+ m_v2.a = 1.0f;
+ m_count = 1;
+ m_v1 = m_v2;
+ return;
+ }
+
+ // w3 region
+ if (d13_1 <= 0.0f && d23_1 <= 0.0f)
+ {
+ m_v3.a = 1.0f;
+ m_count = 1;
+ m_v1 = m_v3;
+ return;
+ }
+
+ // e23
+ if (d23_1 > 0.0f && d23_2 > 0.0f && d123_1 <= 0.0f)
+ {
+ float32 inv_d23 = 1.0f / (d23_1 + d23_2);
+ m_v2.a = d23_1 * inv_d23;
+ m_v3.a = d23_2 * inv_d23;
+ m_count = 2;
+ m_v1 = m_v3;
+ return;
+ }
+
+ // Must be in triangle123
+ float32 inv_d123 = 1.0f / (d123_1 + d123_2 + d123_3);
+ m_v1.a = d123_1 * inv_d123;
+ m_v2.a = d123_2 * inv_d123;
+ m_v3.a = d123_3 * inv_d123;
+ m_count = 3;
+}
+
+void b2Distance(b2DistanceOutput* output,
+ b2SimplexCache* cache,
+ const b2DistanceInput* input)
+{
+ ++b2_gjkCalls;
+
+ const b2DistanceProxy* proxyA = &input->proxyA;
+ const b2DistanceProxy* proxyB = &input->proxyB;
+
+ b2Transform transformA = input->transformA;
+ b2Transform transformB = input->transformB;
+
+ // Initialize the simplex.
+ b2Simplex simplex;
+ simplex.ReadCache(cache, proxyA, transformA, proxyB, transformB);
+
+ // Get simplex vertices as an array.
+ b2SimplexVertex* vertices = &simplex.m_v1;
+ const int32 k_maxIters = 20;
+
+ // These store the vertices of the last simplex so that we
+ // can check for duplicates and prevent cycling.
+ int32 saveA[3], saveB[3];
+ int32 saveCount = 0;
+
+ b2Vec2 closestPoint = simplex.GetClosestPoint();
+ float32 distanceSqr1 = closestPoint.LengthSquared();
+ float32 distanceSqr2 = distanceSqr1;
+
+ // Main iteration loop.
+ int32 iter = 0;
+ while (iter < k_maxIters)
+ {
+ // Copy simplex so we can identify duplicates.
+ saveCount = simplex.m_count;
+ for (int32 i = 0; i < saveCount; ++i)
+ {
+ saveA[i] = vertices[i].indexA;
+ saveB[i] = vertices[i].indexB;
+ }
+
+ switch (simplex.m_count)
+ {
+ case 1:
+ break;
+
+ case 2:
+ simplex.Solve2();
+ break;
+
+ case 3:
+ simplex.Solve3();
+ break;
+
+ default:
+ b2Assert(false);
+ }
+
+ // If we have 3 points, then the origin is in the corresponding triangle.
+ if (simplex.m_count == 3)
+ {
+ break;
+ }
+
+ // Compute closest point.
+ b2Vec2 p = simplex.GetClosestPoint();
+ distanceSqr2 = p.LengthSquared();
+
+ // Ensure progress
+ if (distanceSqr2 >= distanceSqr1)
+ {
+ //break;
+ }
+ distanceSqr1 = distanceSqr2;
+
+ // Get search direction.
+ b2Vec2 d = simplex.GetSearchDirection();
+
+ // Ensure the search direction is numerically fit.
+ if (d.LengthSquared() < b2_epsilon * b2_epsilon)
+ {
+ // The origin is probably contained by a line segment
+ // or triangle. Thus the shapes are overlapped.
+
+ // We can't return zero here even though there may be overlap.
+ // In case the simplex is a point, segment, or triangle it is difficult
+ // to determine if the origin is contained in the CSO or very close to it.
+ break;
+ }
+
+ // Compute a tentative new simplex vertex using support points.
+ b2SimplexVertex* vertex = vertices + simplex.m_count;
+ vertex->indexA = proxyA->GetSupport(b2MulT(transformA.q, -d));
+ vertex->wA = b2Mul(transformA, proxyA->GetVertex(vertex->indexA));
+ b2Vec2 wBLocal;
+ vertex->indexB = proxyB->GetSupport(b2MulT(transformB.q, d));
+ vertex->wB = b2Mul(transformB, proxyB->GetVertex(vertex->indexB));
+ vertex->w = vertex->wB - vertex->wA;
+
+ // Iteration count is equated to the number of support point calls.
+ ++iter;
+ ++b2_gjkIters;
+
+ // Check for duplicate support points. This is the main termination criteria.
+ bool duplicate = false;
+ for (int32 i = 0; i < saveCount; ++i)
+ {
+ if (vertex->indexA == saveA[i] && vertex->indexB == saveB[i])
+ {
+ duplicate = true;
+ break;
+ }
+ }
+
+ // If we found a duplicate support point we must exit to avoid cycling.
+ if (duplicate)
+ {
+ break;
+ }
+
+ // New vertex is ok and needed.
+ ++simplex.m_count;
+ }
+
+ b2_gjkMaxIters = b2Max(b2_gjkMaxIters, iter);
+
+ // Prepare output.
+ simplex.GetWitnessPoints(&output->pointA, &output->pointB);
+ output->distance = b2Distance(output->pointA, output->pointB);
+ output->iterations = iter;
+
+ // Cache the simplex.
+ simplex.WriteCache(cache);
+
+ // Apply radii if requested.
+ if (input->useRadii)
+ {
+ float32 rA = proxyA->m_radius;
+ float32 rB = proxyB->m_radius;
+
+ if (output->distance > rA + rB && output->distance > b2_epsilon)
+ {
+ // Shapes are still no overlapped.
+ // Move the witness points to the outer surface.
+ output->distance -= rA + rB;
+ b2Vec2 normal = output->pointB - output->pointA;
+ normal.Normalize();
+ output->pointA += rA * normal;
+ output->pointB -= rB * normal;
+ }
+ else
+ {
+ // Shapes are overlapped when radii are considered.
+ // Move the witness points to the middle.
+ b2Vec2 p = 0.5f * (output->pointA + output->pointB);
+ output->pointA = p;
+ output->pointB = p;
+ output->distance = 0.0f;
+ }
+ }
+}
diff --git a/tests/box2d/Box2D/Collision/b2Distance.h b/tests/box2d/Box2D/Collision/b2Distance.h new file mode 100755 index 00000000..54ed1e13 --- /dev/null +++ b/tests/box2d/Box2D/Collision/b2Distance.h @@ -0,0 +1,141 @@ +
+/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_DISTANCE_H
+#define B2_DISTANCE_H
+
+#include <Box2D/Common/b2Math.h>
+
+class b2Shape;
+
+/// A distance proxy is used by the GJK algorithm.
+/// It encapsulates any shape.
+struct b2DistanceProxy
+{
+ b2DistanceProxy() : m_vertices(NULL), m_count(0), m_radius(0.0f) {}
+
+ /// Initialize the proxy using the given shape. The shape
+ /// must remain in scope while the proxy is in use.
+ void Set(const b2Shape* shape, int32 index);
+
+ /// Get the supporting vertex index in the given direction.
+ int32 GetSupport(const b2Vec2& d) const;
+
+ /// Get the supporting vertex in the given direction.
+ const b2Vec2& GetSupportVertex(const b2Vec2& d) const;
+
+ /// Get the vertex count.
+ int32 GetVertexCount() const;
+
+ /// Get a vertex by index. Used by b2Distance.
+ const b2Vec2& GetVertex(int32 index) const;
+
+ b2Vec2 m_buffer[2];
+ const b2Vec2* m_vertices;
+ int32 m_count;
+ float32 m_radius;
+};
+
+/// Used to warm start b2Distance.
+/// Set count to zero on first call.
+struct b2SimplexCache
+{
+ float32 metric; ///< length or area
+ uint16 count;
+ uint8 indexA[3]; ///< vertices on shape A
+ uint8 indexB[3]; ///< vertices on shape B
+};
+
+/// Input for b2Distance.
+/// You have to option to use the shape radii
+/// in the computation. Even
+struct b2DistanceInput
+{
+ b2DistanceProxy proxyA;
+ b2DistanceProxy proxyB;
+ b2Transform transformA;
+ b2Transform transformB;
+ bool useRadii;
+};
+
+/// Output for b2Distance.
+struct b2DistanceOutput
+{
+ b2Vec2 pointA; ///< closest point on shapeA
+ b2Vec2 pointB; ///< closest point on shapeB
+ float32 distance;
+ int32 iterations; ///< number of GJK iterations used
+};
+
+/// Compute the closest points between two shapes. Supports any combination of:
+/// b2CircleShape, b2PolygonShape, b2EdgeShape. The simplex cache is input/output.
+/// On the first call set b2SimplexCache.count to zero.
+void b2Distance(b2DistanceOutput* output,
+ b2SimplexCache* cache,
+ const b2DistanceInput* input);
+
+
+//////////////////////////////////////////////////////////////////////////
+
+inline int32 b2DistanceProxy::GetVertexCount() const
+{
+ return m_count;
+}
+
+inline const b2Vec2& b2DistanceProxy::GetVertex(int32 index) const
+{
+ b2Assert(0 <= index && index < m_count);
+ return m_vertices[index];
+}
+
+inline int32 b2DistanceProxy::GetSupport(const b2Vec2& d) const
+{
+ int32 bestIndex = 0;
+ float32 bestValue = b2Dot(m_vertices[0], d);
+ for (int32 i = 1; i < m_count; ++i)
+ {
+ float32 value = b2Dot(m_vertices[i], d);
+ if (value > bestValue)
+ {
+ bestIndex = i;
+ bestValue = value;
+ }
+ }
+
+ return bestIndex;
+}
+
+inline const b2Vec2& b2DistanceProxy::GetSupportVertex(const b2Vec2& d) const
+{
+ int32 bestIndex = 0;
+ float32 bestValue = b2Dot(m_vertices[0], d);
+ for (int32 i = 1; i < m_count; ++i)
+ {
+ float32 value = b2Dot(m_vertices[i], d);
+ if (value > bestValue)
+ {
+ bestIndex = i;
+ bestValue = value;
+ }
+ }
+
+ return m_vertices[bestIndex];
+}
+
+#endif
diff --git a/tests/box2d/Box2D/Collision/b2DynamicTree.cpp b/tests/box2d/Box2D/Collision/b2DynamicTree.cpp new file mode 100755 index 00000000..1a42c3a5 --- /dev/null +++ b/tests/box2d/Box2D/Collision/b2DynamicTree.cpp @@ -0,0 +1,771 @@ +/*
+* Copyright (c) 2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Collision/b2DynamicTree.h>
+#include <cstring>
+#include <cfloat>
+using namespace std;
+
+
+b2DynamicTree::b2DynamicTree()
+{
+ m_root = b2_nullNode;
+
+ m_nodeCapacity = 16;
+ m_nodeCount = 0;
+ m_nodes = (b2TreeNode*)b2Alloc(m_nodeCapacity * sizeof(b2TreeNode));
+ memset(m_nodes, 0, m_nodeCapacity * sizeof(b2TreeNode));
+
+ // Build a linked list for the free list.
+ for (int32 i = 0; i < m_nodeCapacity - 1; ++i)
+ {
+ m_nodes[i].next = i + 1;
+ m_nodes[i].height = -1;
+ }
+ m_nodes[m_nodeCapacity-1].next = b2_nullNode;
+ m_nodes[m_nodeCapacity-1].height = -1;
+ m_freeList = 0;
+
+ m_path = 0;
+
+ m_insertionCount = 0;
+}
+
+b2DynamicTree::~b2DynamicTree()
+{
+ // This frees the entire tree in one shot.
+ b2Free(m_nodes);
+}
+
+// Allocate a node from the pool. Grow the pool if necessary.
+int32 b2DynamicTree::AllocateNode()
+{
+ // Expand the node pool as needed.
+ if (m_freeList == b2_nullNode)
+ {
+ b2Assert(m_nodeCount == m_nodeCapacity);
+
+ // The free list is empty. Rebuild a bigger pool.
+ b2TreeNode* oldNodes = m_nodes;
+ m_nodeCapacity *= 2;
+ m_nodes = (b2TreeNode*)b2Alloc(m_nodeCapacity * sizeof(b2TreeNode));
+ memcpy(m_nodes, oldNodes, m_nodeCount * sizeof(b2TreeNode));
+ b2Free(oldNodes);
+
+ // Build a linked list for the free list. The parent
+ // pointer becomes the "next" pointer.
+ for (int32 i = m_nodeCount; i < m_nodeCapacity - 1; ++i)
+ {
+ m_nodes[i].next = i + 1;
+ m_nodes[i].height = -1;
+ }
+ m_nodes[m_nodeCapacity-1].next = b2_nullNode;
+ m_nodes[m_nodeCapacity-1].height = -1;
+ m_freeList = m_nodeCount;
+ }
+
+ // Peel a node off the free list.
+ int32 nodeId = m_freeList;
+ m_freeList = m_nodes[nodeId].next;
+ m_nodes[nodeId].parent = b2_nullNode;
+ m_nodes[nodeId].child1 = b2_nullNode;
+ m_nodes[nodeId].child2 = b2_nullNode;
+ m_nodes[nodeId].height = 0;
+ m_nodes[nodeId].userData = NULL;
+ ++m_nodeCount;
+ return nodeId;
+}
+
+// Return a node to the pool.
+void b2DynamicTree::FreeNode(int32 nodeId)
+{
+ b2Assert(0 <= nodeId && nodeId < m_nodeCapacity);
+ b2Assert(0 < m_nodeCount);
+ m_nodes[nodeId].next = m_freeList;
+ m_nodes[nodeId].height = -1;
+ m_freeList = nodeId;
+ --m_nodeCount;
+}
+
+// Create a proxy in the tree as a leaf node. We return the index
+// of the node instead of a pointer so that we can grow
+// the node pool.
+int32 b2DynamicTree::CreateProxy(const b2AABB& aabb, void* userData)
+{
+ int32 proxyId = AllocateNode();
+
+ // Fatten the aabb.
+ b2Vec2 r(b2_aabbExtension, b2_aabbExtension);
+ m_nodes[proxyId].aabb.lowerBound = aabb.lowerBound - r;
+ m_nodes[proxyId].aabb.upperBound = aabb.upperBound + r;
+ m_nodes[proxyId].userData = userData;
+ m_nodes[proxyId].height = 0;
+
+ InsertLeaf(proxyId);
+
+ return proxyId;
+}
+
+void b2DynamicTree::DestroyProxy(int32 proxyId)
+{
+ b2Assert(0 <= proxyId && proxyId < m_nodeCapacity);
+ b2Assert(m_nodes[proxyId].IsLeaf());
+
+ RemoveLeaf(proxyId);
+ FreeNode(proxyId);
+}
+
+bool b2DynamicTree::MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement)
+{
+ b2Assert(0 <= proxyId && proxyId < m_nodeCapacity);
+
+ b2Assert(m_nodes[proxyId].IsLeaf());
+
+ if (m_nodes[proxyId].aabb.Contains(aabb))
+ {
+ return false;
+ }
+
+ RemoveLeaf(proxyId);
+
+ // Extend AABB.
+ b2AABB b = aabb;
+ b2Vec2 r(b2_aabbExtension, b2_aabbExtension);
+ b.lowerBound = b.lowerBound - r;
+ b.upperBound = b.upperBound + r;
+
+ // Predict AABB displacement.
+ b2Vec2 d = b2_aabbMultiplier * displacement;
+
+ if (d.x < 0.0f)
+ {
+ b.lowerBound.x += d.x;
+ }
+ else
+ {
+ b.upperBound.x += d.x;
+ }
+
+ if (d.y < 0.0f)
+ {
+ b.lowerBound.y += d.y;
+ }
+ else
+ {
+ b.upperBound.y += d.y;
+ }
+
+ m_nodes[proxyId].aabb = b;
+
+ InsertLeaf(proxyId);
+ return true;
+}
+
+void b2DynamicTree::InsertLeaf(int32 leaf)
+{
+ ++m_insertionCount;
+
+ if (m_root == b2_nullNode)
+ {
+ m_root = leaf;
+ m_nodes[m_root].parent = b2_nullNode;
+ return;
+ }
+
+ // Find the best sibling for this node
+ b2AABB leafAABB = m_nodes[leaf].aabb;
+ int32 index = m_root;
+ while (m_nodes[index].IsLeaf() == false)
+ {
+ int32 child1 = m_nodes[index].child1;
+ int32 child2 = m_nodes[index].child2;
+
+ float32 area = m_nodes[index].aabb.GetPerimeter();
+
+ b2AABB combinedAABB;
+ combinedAABB.Combine(m_nodes[index].aabb, leafAABB);
+ float32 combinedArea = combinedAABB.GetPerimeter();
+
+ // Cost of creating a new parent for this node and the new leaf
+ float32 cost = 2.0f * combinedArea;
+
+ // Minimum cost of pushing the leaf further down the tree
+ float32 inheritanceCost = 2.0f * (combinedArea - area);
+
+ // Cost of descending into child1
+ float32 cost1;
+ if (m_nodes[child1].IsLeaf())
+ {
+ b2AABB aabb;
+ aabb.Combine(leafAABB, m_nodes[child1].aabb);
+ cost1 = aabb.GetPerimeter() + inheritanceCost;
+ }
+ else
+ {
+ b2AABB aabb;
+ aabb.Combine(leafAABB, m_nodes[child1].aabb);
+ float32 oldArea = m_nodes[child1].aabb.GetPerimeter();
+ float32 newArea = aabb.GetPerimeter();
+ cost1 = (newArea - oldArea) + inheritanceCost;
+ }
+
+ // Cost of descending into child2
+ float32 cost2;
+ if (m_nodes[child2].IsLeaf())
+ {
+ b2AABB aabb;
+ aabb.Combine(leafAABB, m_nodes[child2].aabb);
+ cost2 = aabb.GetPerimeter() + inheritanceCost;
+ }
+ else
+ {
+ b2AABB aabb;
+ aabb.Combine(leafAABB, m_nodes[child2].aabb);
+ float32 oldArea = m_nodes[child2].aabb.GetPerimeter();
+ float32 newArea = aabb.GetPerimeter();
+ cost2 = newArea - oldArea + inheritanceCost;
+ }
+
+ // Descend according to the minimum cost.
+ if (cost < cost1 && cost < cost2)
+ {
+ break;
+ }
+
+ // Descend
+ if (cost1 < cost2)
+ {
+ index = child1;
+ }
+ else
+ {
+ index = child2;
+ }
+ }
+
+ int32 sibling = index;
+
+ // Create a new parent.
+ int32 oldParent = m_nodes[sibling].parent;
+ int32 newParent = AllocateNode();
+ m_nodes[newParent].parent = oldParent;
+ m_nodes[newParent].userData = NULL;
+ m_nodes[newParent].aabb.Combine(leafAABB, m_nodes[sibling].aabb);
+ m_nodes[newParent].height = m_nodes[sibling].height + 1;
+
+ if (oldParent != b2_nullNode)
+ {
+ // The sibling was not the root.
+ if (m_nodes[oldParent].child1 == sibling)
+ {
+ m_nodes[oldParent].child1 = newParent;
+ }
+ else
+ {
+ m_nodes[oldParent].child2 = newParent;
+ }
+
+ m_nodes[newParent].child1 = sibling;
+ m_nodes[newParent].child2 = leaf;
+ m_nodes[sibling].parent = newParent;
+ m_nodes[leaf].parent = newParent;
+ }
+ else
+ {
+ // The sibling was the root.
+ m_nodes[newParent].child1 = sibling;
+ m_nodes[newParent].child2 = leaf;
+ m_nodes[sibling].parent = newParent;
+ m_nodes[leaf].parent = newParent;
+ m_root = newParent;
+ }
+
+ // Walk back up the tree fixing heights and AABBs
+ index = m_nodes[leaf].parent;
+ while (index != b2_nullNode)
+ {
+ index = Balance(index);
+
+ int32 child1 = m_nodes[index].child1;
+ int32 child2 = m_nodes[index].child2;
+
+ b2Assert(child1 != b2_nullNode);
+ b2Assert(child2 != b2_nullNode);
+
+ m_nodes[index].height = 1 + b2Max(m_nodes[child1].height, m_nodes[child2].height);
+ m_nodes[index].aabb.Combine(m_nodes[child1].aabb, m_nodes[child2].aabb);
+
+ index = m_nodes[index].parent;
+ }
+
+ //Validate();
+}
+
+void b2DynamicTree::RemoveLeaf(int32 leaf)
+{
+ if (leaf == m_root)
+ {
+ m_root = b2_nullNode;
+ return;
+ }
+
+ int32 parent = m_nodes[leaf].parent;
+ int32 grandParent = m_nodes[parent].parent;
+ int32 sibling;
+ if (m_nodes[parent].child1 == leaf)
+ {
+ sibling = m_nodes[parent].child2;
+ }
+ else
+ {
+ sibling = m_nodes[parent].child1;
+ }
+
+ if (grandParent != b2_nullNode)
+ {
+ // Destroy parent and connect sibling to grandParent.
+ if (m_nodes[grandParent].child1 == parent)
+ {
+ m_nodes[grandParent].child1 = sibling;
+ }
+ else
+ {
+ m_nodes[grandParent].child2 = sibling;
+ }
+ m_nodes[sibling].parent = grandParent;
+ FreeNode(parent);
+
+ // Adjust ancestor bounds.
+ int32 index = grandParent;
+ while (index != b2_nullNode)
+ {
+ index = Balance(index);
+
+ int32 child1 = m_nodes[index].child1;
+ int32 child2 = m_nodes[index].child2;
+
+ m_nodes[index].aabb.Combine(m_nodes[child1].aabb, m_nodes[child2].aabb);
+ m_nodes[index].height = 1 + b2Max(m_nodes[child1].height, m_nodes[child2].height);
+
+ index = m_nodes[index].parent;
+ }
+ }
+ else
+ {
+ m_root = sibling;
+ m_nodes[sibling].parent = b2_nullNode;
+ FreeNode(parent);
+ }
+
+ //Validate();
+}
+
+// Perform a left or right rotation if node A is imbalanced.
+// Returns the new root index.
+int32 b2DynamicTree::Balance(int32 iA)
+{
+ b2Assert(iA != b2_nullNode);
+
+ b2TreeNode* A = m_nodes + iA;
+ if (A->IsLeaf() || A->height < 2)
+ {
+ return iA;
+ }
+
+ int32 iB = A->child1;
+ int32 iC = A->child2;
+ b2Assert(0 <= iB && iB < m_nodeCapacity);
+ b2Assert(0 <= iC && iC < m_nodeCapacity);
+
+ b2TreeNode* B = m_nodes + iB;
+ b2TreeNode* C = m_nodes + iC;
+
+ int32 balance = C->height - B->height;
+
+ // Rotate C up
+ if (balance > 1)
+ {
+ int32 iF = C->child1;
+ int32 iG = C->child2;
+ b2TreeNode* F = m_nodes + iF;
+ b2TreeNode* G = m_nodes + iG;
+ b2Assert(0 <= iF && iF < m_nodeCapacity);
+ b2Assert(0 <= iG && iG < m_nodeCapacity);
+
+ // Swap A and C
+ C->child1 = iA;
+ C->parent = A->parent;
+ A->parent = iC;
+
+ // A's old parent should point to C
+ if (C->parent != b2_nullNode)
+ {
+ if (m_nodes[C->parent].child1 == iA)
+ {
+ m_nodes[C->parent].child1 = iC;
+ }
+ else
+ {
+ b2Assert(m_nodes[C->parent].child2 == iA);
+ m_nodes[C->parent].child2 = iC;
+ }
+ }
+ else
+ {
+ m_root = iC;
+ }
+
+ // Rotate
+ if (F->height > G->height)
+ {
+ C->child2 = iF;
+ A->child2 = iG;
+ G->parent = iA;
+ A->aabb.Combine(B->aabb, G->aabb);
+ C->aabb.Combine(A->aabb, F->aabb);
+
+ A->height = 1 + b2Max(B->height, G->height);
+ C->height = 1 + b2Max(A->height, F->height);
+ }
+ else
+ {
+ C->child2 = iG;
+ A->child2 = iF;
+ F->parent = iA;
+ A->aabb.Combine(B->aabb, F->aabb);
+ C->aabb.Combine(A->aabb, G->aabb);
+
+ A->height = 1 + b2Max(B->height, F->height);
+ C->height = 1 + b2Max(A->height, G->height);
+ }
+
+ return iC;
+ }
+
+ // Rotate B up
+ if (balance < -1)
+ {
+ int32 iD = B->child1;
+ int32 iE = B->child2;
+ b2TreeNode* D = m_nodes + iD;
+ b2TreeNode* E = m_nodes + iE;
+ b2Assert(0 <= iD && iD < m_nodeCapacity);
+ b2Assert(0 <= iE && iE < m_nodeCapacity);
+
+ // Swap A and B
+ B->child1 = iA;
+ B->parent = A->parent;
+ A->parent = iB;
+
+ // A's old parent should point to B
+ if (B->parent != b2_nullNode)
+ {
+ if (m_nodes[B->parent].child1 == iA)
+ {
+ m_nodes[B->parent].child1 = iB;
+ }
+ else
+ {
+ b2Assert(m_nodes[B->parent].child2 == iA);
+ m_nodes[B->parent].child2 = iB;
+ }
+ }
+ else
+ {
+ m_root = iB;
+ }
+
+ // Rotate
+ if (D->height > E->height)
+ {
+ B->child2 = iD;
+ A->child1 = iE;
+ E->parent = iA;
+ A->aabb.Combine(C->aabb, E->aabb);
+ B->aabb.Combine(A->aabb, D->aabb);
+
+ A->height = 1 + b2Max(C->height, E->height);
+ B->height = 1 + b2Max(A->height, D->height);
+ }
+ else
+ {
+ B->child2 = iE;
+ A->child1 = iD;
+ D->parent = iA;
+ A->aabb.Combine(C->aabb, D->aabb);
+ B->aabb.Combine(A->aabb, E->aabb);
+
+ A->height = 1 + b2Max(C->height, D->height);
+ B->height = 1 + b2Max(A->height, E->height);
+ }
+
+ return iB;
+ }
+
+ return iA;
+}
+
+int32 b2DynamicTree::GetHeight() const
+{
+ if (m_root == b2_nullNode)
+ {
+ return 0;
+ }
+
+ return m_nodes[m_root].height;
+}
+
+//
+float32 b2DynamicTree::GetAreaRatio() const
+{
+ if (m_root == b2_nullNode)
+ {
+ return 0.0f;
+ }
+
+ const b2TreeNode* root = m_nodes + m_root;
+ float32 rootArea = root->aabb.GetPerimeter();
+
+ float32 totalArea = 0.0f;
+ for (int32 i = 0; i < m_nodeCapacity; ++i)
+ {
+ const b2TreeNode* node = m_nodes + i;
+ if (node->height < 0)
+ {
+ // Free node in pool
+ continue;
+ }
+
+ totalArea += node->aabb.GetPerimeter();
+ }
+
+ return totalArea / rootArea;
+}
+
+// Compute the height of a sub-tree.
+int32 b2DynamicTree::ComputeHeight(int32 nodeId) const
+{
+ b2Assert(0 <= nodeId && nodeId < m_nodeCapacity);
+ b2TreeNode* node = m_nodes + nodeId;
+
+ if (node->IsLeaf())
+ {
+ return 0;
+ }
+
+ int32 height1 = ComputeHeight(node->child1);
+ int32 height2 = ComputeHeight(node->child2);
+ return 1 + b2Max(height1, height2);
+}
+
+int32 b2DynamicTree::ComputeHeight() const
+{
+ int32 height = ComputeHeight(m_root);
+ return height;
+}
+
+void b2DynamicTree::ValidateStructure(int32 index) const
+{
+ if (index == b2_nullNode)
+ {
+ return;
+ }
+
+ if (index == m_root)
+ {
+ b2Assert(m_nodes[index].parent == b2_nullNode);
+ }
+
+ const b2TreeNode* node = m_nodes + index;
+
+ int32 child1 = node->child1;
+ int32 child2 = node->child2;
+
+ if (node->IsLeaf())
+ {
+ b2Assert(child1 == b2_nullNode);
+ b2Assert(child2 == b2_nullNode);
+ b2Assert(node->height == 0);
+ return;
+ }
+
+ b2Assert(0 <= child1 && child1 < m_nodeCapacity);
+ b2Assert(0 <= child2 && child2 < m_nodeCapacity);
+
+ b2Assert(m_nodes[child1].parent == index);
+ b2Assert(m_nodes[child2].parent == index);
+
+ ValidateStructure(child1);
+ ValidateStructure(child2);
+}
+
+void b2DynamicTree::ValidateMetrics(int32 index) const
+{
+ if (index == b2_nullNode)
+ {
+ return;
+ }
+
+ const b2TreeNode* node = m_nodes + index;
+
+ int32 child1 = node->child1;
+ int32 child2 = node->child2;
+
+ if (node->IsLeaf())
+ {
+ b2Assert(child1 == b2_nullNode);
+ b2Assert(child2 == b2_nullNode);
+ b2Assert(node->height == 0);
+ return;
+ }
+
+ b2Assert(0 <= child1 && child1 < m_nodeCapacity);
+ b2Assert(0 <= child2 && child2 < m_nodeCapacity);
+
+ int32 height1 = m_nodes[child1].height;
+ int32 height2 = m_nodes[child2].height;
+ int32 height;
+ height = 1 + b2Max(height1, height2);
+ b2Assert(node->height == height);
+
+ b2AABB aabb;
+ aabb.Combine(m_nodes[child1].aabb, m_nodes[child2].aabb);
+
+ b2Assert(aabb.lowerBound == node->aabb.lowerBound);
+ b2Assert(aabb.upperBound == node->aabb.upperBound);
+
+ ValidateMetrics(child1);
+ ValidateMetrics(child2);
+}
+
+void b2DynamicTree::Validate() const
+{
+ ValidateStructure(m_root);
+ ValidateMetrics(m_root);
+
+ int32 freeCount = 0;
+ int32 freeIndex = m_freeList;
+ while (freeIndex != b2_nullNode)
+ {
+ b2Assert(0 <= freeIndex && freeIndex < m_nodeCapacity);
+ freeIndex = m_nodes[freeIndex].next;
+ ++freeCount;
+ }
+
+ b2Assert(GetHeight() == ComputeHeight());
+
+ b2Assert(m_nodeCount + freeCount == m_nodeCapacity);
+}
+
+int32 b2DynamicTree::GetMaxBalance() const
+{
+ int32 maxBalance = 0;
+ for (int32 i = 0; i < m_nodeCapacity; ++i)
+ {
+ const b2TreeNode* node = m_nodes + i;
+ if (node->height <= 1)
+ {
+ continue;
+ }
+
+ b2Assert(node->IsLeaf() == false);
+
+ int32 child1 = node->child1;
+ int32 child2 = node->child2;
+ int32 balance = b2Abs(m_nodes[child2].height - m_nodes[child1].height);
+ maxBalance = b2Max(maxBalance, balance);
+ }
+
+ return maxBalance;
+}
+
+void b2DynamicTree::RebuildBottomUp()
+{
+ int32* nodes = (int32*)b2Alloc(m_nodeCount * sizeof(int32));
+ int32 count = 0;
+
+ // Build array of leaves. Free the rest.
+ for (int32 i = 0; i < m_nodeCapacity; ++i)
+ {
+ if (m_nodes[i].height < 0)
+ {
+ // free node in pool
+ continue;
+ }
+
+ if (m_nodes[i].IsLeaf())
+ {
+ m_nodes[i].parent = b2_nullNode;
+ nodes[count] = i;
+ ++count;
+ }
+ else
+ {
+ FreeNode(i);
+ }
+ }
+
+ while (count > 1)
+ {
+ float32 minCost = b2_maxFloat;
+ int32 iMin = -1, jMin = -1;
+ for (int32 i = 0; i < count; ++i)
+ {
+ b2AABB aabbi = m_nodes[nodes[i]].aabb;
+
+ for (int32 j = i + 1; j < count; ++j)
+ {
+ b2AABB aabbj = m_nodes[nodes[j]].aabb;
+ b2AABB b;
+ b.Combine(aabbi, aabbj);
+ float32 cost = b.GetPerimeter();
+ if (cost < minCost)
+ {
+ iMin = i;
+ jMin = j;
+ minCost = cost;
+ }
+ }
+ }
+
+ int32 index1 = nodes[iMin];
+ int32 index2 = nodes[jMin];
+ b2TreeNode* child1 = m_nodes + index1;
+ b2TreeNode* child2 = m_nodes + index2;
+
+ int32 parentIndex = AllocateNode();
+ b2TreeNode* parent = m_nodes + parentIndex;
+ parent->child1 = index1;
+ parent->child2 = index2;
+ parent->height = 1 + b2Max(child1->height, child2->height);
+ parent->aabb.Combine(child1->aabb, child2->aabb);
+ parent->parent = b2_nullNode;
+
+ child1->parent = parentIndex;
+ child2->parent = parentIndex;
+
+ nodes[jMin] = nodes[count-1];
+ nodes[iMin] = parentIndex;
+ --count;
+ }
+
+ m_root = nodes[0];
+ b2Free(nodes);
+
+ Validate();
+}
diff --git a/tests/box2d/Box2D/Collision/b2DynamicTree.h b/tests/box2d/Box2D/Collision/b2DynamicTree.h new file mode 100755 index 00000000..a9bfbf37 --- /dev/null +++ b/tests/box2d/Box2D/Collision/b2DynamicTree.h @@ -0,0 +1,284 @@ +/*
+* Copyright (c) 2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_DYNAMIC_TREE_H
+#define B2_DYNAMIC_TREE_H
+
+#include <Box2D/Collision/b2Collision.h>
+#include <Box2D/Common/b2GrowableStack.h>
+
+#define b2_nullNode (-1)
+
+/// A node in the dynamic tree. The client does not interact with this directly.
+struct b2TreeNode
+{
+ bool IsLeaf() const
+ {
+ return child1 == b2_nullNode;
+ }
+
+ /// Enlarged AABB
+ b2AABB aabb;
+
+ void* userData;
+
+ union
+ {
+ int32 parent;
+ int32 next;
+ };
+
+ int32 child1;
+ int32 child2;
+
+ // leaf = 0, free node = -1
+ int32 height;
+};
+
+/// A dynamic AABB tree broad-phase, inspired by Nathanael Presson's btDbvt.
+/// A dynamic tree arranges data in a binary tree to accelerate
+/// queries such as volume queries and ray casts. Leafs are proxies
+/// with an AABB. In the tree we expand the proxy AABB by b2_fatAABBFactor
+/// so that the proxy AABB is bigger than the client object. This allows the client
+/// object to move by small amounts without triggering a tree update.
+///
+/// Nodes are pooled and relocatable, so we use node indices rather than pointers.
+class b2DynamicTree
+{
+public:
+ /// Constructing the tree initializes the node pool.
+ b2DynamicTree();
+
+ /// Destroy the tree, freeing the node pool.
+ ~b2DynamicTree();
+
+ /// Create a proxy. Provide a tight fitting AABB and a userData pointer.
+ int32 CreateProxy(const b2AABB& aabb, void* userData);
+
+ /// Destroy a proxy. This asserts if the id is invalid.
+ void DestroyProxy(int32 proxyId);
+
+ /// Move a proxy with a swepted AABB. If the proxy has moved outside of its fattened AABB,
+ /// then the proxy is removed from the tree and re-inserted. Otherwise
+ /// the function returns immediately.
+ /// @return true if the proxy was re-inserted.
+ bool MoveProxy(int32 proxyId, const b2AABB& aabb1, const b2Vec2& displacement);
+
+ /// Get proxy user data.
+ /// @return the proxy user data or 0 if the id is invalid.
+ void* GetUserData(int32 proxyId) const;
+
+ /// Get the fat AABB for a proxy.
+ const b2AABB& GetFatAABB(int32 proxyId) const;
+
+ /// Query an AABB for overlapping proxies. The callback class
+ /// is called for each proxy that overlaps the supplied AABB.
+ template <typename T>
+ void Query(T* callback, const b2AABB& aabb) const;
+
+ /// Ray-cast against the proxies in the tree. This relies on the callback
+ /// to perform a exact ray-cast in the case were the proxy contains a shape.
+ /// The callback also performs the any collision filtering. This has performance
+ /// roughly equal to k * log(n), where k is the number of collisions and n is the
+ /// number of proxies in the tree.
+ /// @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).
+ /// @param callback a callback class that is called for each proxy that is hit by the ray.
+ template <typename T>
+ void RayCast(T* callback, const b2RayCastInput& input) const;
+
+ /// Validate this tree. For testing.
+ void Validate() const;
+
+ /// Compute the height of the binary tree in O(N) time. Should not be
+ /// called often.
+ int32 GetHeight() const;
+
+ /// Get the maximum balance of an node in the tree. The balance is the difference
+ /// in height of the two children of a node.
+ int32 GetMaxBalance() const;
+
+ /// Get the ratio of the sum of the node areas to the root area.
+ float32 GetAreaRatio() const;
+
+ /// Build an optimal tree. Very expensive. For testing.
+ void RebuildBottomUp();
+
+private:
+
+ int32 AllocateNode();
+ void FreeNode(int32 node);
+
+ void InsertLeaf(int32 node);
+ void RemoveLeaf(int32 node);
+
+ int32 Balance(int32 index);
+
+ int32 ComputeHeight() const;
+ int32 ComputeHeight(int32 nodeId) const;
+
+ void ValidateStructure(int32 index) const;
+ void ValidateMetrics(int32 index) const;
+
+ int32 m_root;
+
+ b2TreeNode* m_nodes;
+ int32 m_nodeCount;
+ int32 m_nodeCapacity;
+
+ int32 m_freeList;
+
+ /// This is used to incrementally traverse the tree for re-balancing.
+ uint32 m_path;
+
+ int32 m_insertionCount;
+};
+
+inline void* b2DynamicTree::GetUserData(int32 proxyId) const
+{
+ b2Assert(0 <= proxyId && proxyId < m_nodeCapacity);
+ return m_nodes[proxyId].userData;
+}
+
+inline const b2AABB& b2DynamicTree::GetFatAABB(int32 proxyId) const
+{
+ b2Assert(0 <= proxyId && proxyId < m_nodeCapacity);
+ return m_nodes[proxyId].aabb;
+}
+
+template <typename T>
+inline void b2DynamicTree::Query(T* callback, const b2AABB& aabb) const
+{
+ b2GrowableStack<int32, 256> stack;
+ stack.Push(m_root);
+
+ while (stack.GetCount() > 0)
+ {
+ int32 nodeId = stack.Pop();
+ if (nodeId == b2_nullNode)
+ {
+ continue;
+ }
+
+ const b2TreeNode* node = m_nodes + nodeId;
+
+ if (b2TestOverlap(node->aabb, aabb))
+ {
+ if (node->IsLeaf())
+ {
+ bool proceed = callback->QueryCallback(nodeId);
+ if (proceed == false)
+ {
+ return;
+ }
+ }
+ else
+ {
+ stack.Push(node->child1);
+ stack.Push(node->child2);
+ }
+ }
+ }
+}
+
+template <typename T>
+inline void b2DynamicTree::RayCast(T* callback, const b2RayCastInput& input) const
+{
+ b2Vec2 p1 = input.p1;
+ b2Vec2 p2 = input.p2;
+ b2Vec2 r = p2 - p1;
+ b2Assert(r.LengthSquared() > 0.0f);
+ r.Normalize();
+
+ // v is perpendicular to the segment.
+ b2Vec2 v = b2Cross(1.0f, r);
+ b2Vec2 abs_v = b2Abs(v);
+
+ // Separating axis for segment (Gino, p80).
+ // |dot(v, p1 - c)| > dot(|v|, h)
+
+ float32 maxFraction = input.maxFraction;
+
+ // Build a bounding box for the segment.
+ b2AABB segmentAABB;
+ {
+ b2Vec2 t = p1 + maxFraction * (p2 - p1);
+ segmentAABB.lowerBound = b2Min(p1, t);
+ segmentAABB.upperBound = b2Max(p1, t);
+ }
+
+ b2GrowableStack<int32, 256> stack;
+ stack.Push(m_root);
+
+ while (stack.GetCount() > 0)
+ {
+ int32 nodeId = stack.Pop();
+ if (nodeId == b2_nullNode)
+ {
+ continue;
+ }
+
+ const b2TreeNode* node = m_nodes + nodeId;
+
+ if (b2TestOverlap(node->aabb, segmentAABB) == false)
+ {
+ continue;
+ }
+
+ // Separating axis for segment (Gino, p80).
+ // |dot(v, p1 - c)| > dot(|v|, h)
+ b2Vec2 c = node->aabb.GetCenter();
+ b2Vec2 h = node->aabb.GetExtents();
+ float32 separation = b2Abs(b2Dot(v, p1 - c)) - b2Dot(abs_v, h);
+ if (separation > 0.0f)
+ {
+ continue;
+ }
+
+ if (node->IsLeaf())
+ {
+ b2RayCastInput subInput;
+ subInput.p1 = input.p1;
+ subInput.p2 = input.p2;
+ subInput.maxFraction = maxFraction;
+
+ float32 value = callback->RayCastCallback(subInput, nodeId);
+
+ if (value == 0.0f)
+ {
+ // The client has terminated the ray cast.
+ return;
+ }
+
+ if (value > 0.0f)
+ {
+ // Update segment bounding box.
+ maxFraction = value;
+ b2Vec2 t = p1 + maxFraction * (p2 - p1);
+ segmentAABB.lowerBound = b2Min(p1, t);
+ segmentAABB.upperBound = b2Max(p1, t);
+ }
+ }
+ else
+ {
+ stack.Push(node->child1);
+ stack.Push(node->child2);
+ }
+ }
+}
+
+#endif
diff --git a/tests/box2d/Box2D/Collision/b2TimeOfImpact.cpp b/tests/box2d/Box2D/Collision/b2TimeOfImpact.cpp new file mode 100755 index 00000000..5c33e828 --- /dev/null +++ b/tests/box2d/Box2D/Collision/b2TimeOfImpact.cpp @@ -0,0 +1,483 @@ +/*
+* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Collision/b2Collision.h>
+#include <Box2D/Collision/b2Distance.h>
+#include <Box2D/Collision/b2TimeOfImpact.h>
+#include <Box2D/Collision/Shapes/b2CircleShape.h>
+#include <Box2D/Collision/Shapes/b2PolygonShape.h>
+
+#include <cstdio>
+using namespace std;
+
+int32 b2_toiCalls, b2_toiIters, b2_toiMaxIters;
+int32 b2_toiRootIters, b2_toiMaxRootIters;
+
+struct b2SeparationFunction
+{
+ enum Type
+ {
+ e_points,
+ e_faceA,
+ e_faceB
+ };
+
+ // TODO_ERIN might not need to return the separation
+
+ float32 Initialize(const b2SimplexCache* cache,
+ const b2DistanceProxy* proxyA, const b2Sweep& sweepA,
+ const b2DistanceProxy* proxyB, const b2Sweep& sweepB,
+ float32 t1)
+ {
+ m_proxyA = proxyA;
+ m_proxyB = proxyB;
+ int32 count = cache->count;
+ b2Assert(0 < count && count < 3);
+
+ m_sweepA = sweepA;
+ m_sweepB = sweepB;
+
+ b2Transform xfA, xfB;
+ m_sweepA.GetTransform(&xfA, t1);
+ m_sweepB.GetTransform(&xfB, t1);
+
+ if (count == 1)
+ {
+ m_type = e_points;
+ b2Vec2 localPointA = m_proxyA->GetVertex(cache->indexA[0]);
+ b2Vec2 localPointB = m_proxyB->GetVertex(cache->indexB[0]);
+ b2Vec2 pointA = b2Mul(xfA, localPointA);
+ b2Vec2 pointB = b2Mul(xfB, localPointB);
+ m_axis = pointB - pointA;
+ float32 s = m_axis.Normalize();
+ return s;
+ }
+ else if (cache->indexA[0] == cache->indexA[1])
+ {
+ // Two points on B and one on A.
+ m_type = e_faceB;
+ b2Vec2 localPointB1 = proxyB->GetVertex(cache->indexB[0]);
+ b2Vec2 localPointB2 = proxyB->GetVertex(cache->indexB[1]);
+
+ m_axis = b2Cross(localPointB2 - localPointB1, 1.0f);
+ m_axis.Normalize();
+ b2Vec2 normal = b2Mul(xfB.q, m_axis);
+
+ m_localPoint = 0.5f * (localPointB1 + localPointB2);
+ b2Vec2 pointB = b2Mul(xfB, m_localPoint);
+
+ b2Vec2 localPointA = proxyA->GetVertex(cache->indexA[0]);
+ b2Vec2 pointA = b2Mul(xfA, localPointA);
+
+ float32 s = b2Dot(pointA - pointB, normal);
+ if (s < 0.0f)
+ {
+ m_axis = -m_axis;
+ s = -s;
+ }
+ return s;
+ }
+ else
+ {
+ // Two points on A and one or two points on B.
+ m_type = e_faceA;
+ b2Vec2 localPointA1 = m_proxyA->GetVertex(cache->indexA[0]);
+ b2Vec2 localPointA2 = m_proxyA->GetVertex(cache->indexA[1]);
+
+ m_axis = b2Cross(localPointA2 - localPointA1, 1.0f);
+ m_axis.Normalize();
+ b2Vec2 normal = b2Mul(xfA.q, m_axis);
+
+ m_localPoint = 0.5f * (localPointA1 + localPointA2);
+ b2Vec2 pointA = b2Mul(xfA, m_localPoint);
+
+ b2Vec2 localPointB = m_proxyB->GetVertex(cache->indexB[0]);
+ b2Vec2 pointB = b2Mul(xfB, localPointB);
+
+ float32 s = b2Dot(pointB - pointA, normal);
+ if (s < 0.0f)
+ {
+ m_axis = -m_axis;
+ s = -s;
+ }
+ return s;
+ }
+ }
+
+ float32 FindMinSeparation(int32* indexA, int32* indexB, float32 t) const
+ {
+ b2Transform xfA, xfB;
+ m_sweepA.GetTransform(&xfA, t);
+ m_sweepB.GetTransform(&xfB, t);
+
+ switch (m_type)
+ {
+ case e_points:
+ {
+ b2Vec2 axisA = b2MulT(xfA.q, m_axis);
+ b2Vec2 axisB = b2MulT(xfB.q, -m_axis);
+
+ *indexA = m_proxyA->GetSupport(axisA);
+ *indexB = m_proxyB->GetSupport(axisB);
+
+ b2Vec2 localPointA = m_proxyA->GetVertex(*indexA);
+ b2Vec2 localPointB = m_proxyB->GetVertex(*indexB);
+
+ b2Vec2 pointA = b2Mul(xfA, localPointA);
+ b2Vec2 pointB = b2Mul(xfB, localPointB);
+
+ float32 separation = b2Dot(pointB - pointA, m_axis);
+ return separation;
+ }
+
+ case e_faceA:
+ {
+ b2Vec2 normal = b2Mul(xfA.q, m_axis);
+ b2Vec2 pointA = b2Mul(xfA, m_localPoint);
+
+ b2Vec2 axisB = b2MulT(xfB.q, -normal);
+
+ *indexA = -1;
+ *indexB = m_proxyB->GetSupport(axisB);
+
+ b2Vec2 localPointB = m_proxyB->GetVertex(*indexB);
+ b2Vec2 pointB = b2Mul(xfB, localPointB);
+
+ float32 separation = b2Dot(pointB - pointA, normal);
+ return separation;
+ }
+
+ case e_faceB:
+ {
+ b2Vec2 normal = b2Mul(xfB.q, m_axis);
+ b2Vec2 pointB = b2Mul(xfB, m_localPoint);
+
+ b2Vec2 axisA = b2MulT(xfA.q, -normal);
+
+ *indexB = -1;
+ *indexA = m_proxyA->GetSupport(axisA);
+
+ b2Vec2 localPointA = m_proxyA->GetVertex(*indexA);
+ b2Vec2 pointA = b2Mul(xfA, localPointA);
+
+ float32 separation = b2Dot(pointA - pointB, normal);
+ return separation;
+ }
+
+ default:
+ b2Assert(false);
+ *indexA = -1;
+ *indexB = -1;
+ return 0.0f;
+ }
+ }
+
+ float32 Evaluate(int32 indexA, int32 indexB, float32 t) const
+ {
+ b2Transform xfA, xfB;
+ m_sweepA.GetTransform(&xfA, t);
+ m_sweepB.GetTransform(&xfB, t);
+
+ switch (m_type)
+ {
+ case e_points:
+ {
+ b2Vec2 axisA = b2MulT(xfA.q, m_axis);
+ b2Vec2 axisB = b2MulT(xfB.q, -m_axis);
+
+ b2Vec2 localPointA = m_proxyA->GetVertex(indexA);
+ b2Vec2 localPointB = m_proxyB->GetVertex(indexB);
+
+ b2Vec2 pointA = b2Mul(xfA, localPointA);
+ b2Vec2 pointB = b2Mul(xfB, localPointB);
+ float32 separation = b2Dot(pointB - pointA, m_axis);
+
+ return separation;
+ }
+
+ case e_faceA:
+ {
+ b2Vec2 normal = b2Mul(xfA.q, m_axis);
+ b2Vec2 pointA = b2Mul(xfA, m_localPoint);
+
+ b2Vec2 axisB = b2MulT(xfB.q, -normal);
+
+ b2Vec2 localPointB = m_proxyB->GetVertex(indexB);
+ b2Vec2 pointB = b2Mul(xfB, localPointB);
+
+ float32 separation = b2Dot(pointB - pointA, normal);
+ return separation;
+ }
+
+ case e_faceB:
+ {
+ b2Vec2 normal = b2Mul(xfB.q, m_axis);
+ b2Vec2 pointB = b2Mul(xfB, m_localPoint);
+
+ b2Vec2 axisA = b2MulT(xfA.q, -normal);
+
+ b2Vec2 localPointA = m_proxyA->GetVertex(indexA);
+ b2Vec2 pointA = b2Mul(xfA, localPointA);
+
+ float32 separation = b2Dot(pointA - pointB, normal);
+ return separation;
+ }
+
+ default:
+ b2Assert(false);
+ return 0.0f;
+ }
+ }
+
+ const b2DistanceProxy* m_proxyA;
+ const b2DistanceProxy* m_proxyB;
+ b2Sweep m_sweepA, m_sweepB;
+ Type m_type;
+ b2Vec2 m_localPoint;
+ b2Vec2 m_axis;
+};
+
+// CCD via the local separating axis method. This seeks progression
+// by computing the largest time at which separation is maintained.
+void b2TimeOfImpact(b2TOIOutput* output, const b2TOIInput* input)
+{
+ ++b2_toiCalls;
+
+ output->state = b2TOIOutput::e_unknown;
+ output->t = input->tMax;
+
+ const b2DistanceProxy* proxyA = &input->proxyA;
+ const b2DistanceProxy* proxyB = &input->proxyB;
+
+ b2Sweep sweepA = input->sweepA;
+ b2Sweep sweepB = input->sweepB;
+
+ // Large rotations can make the root finder fail, so we normalize the
+ // sweep angles.
+ sweepA.Normalize();
+ sweepB.Normalize();
+
+ float32 tMax = input->tMax;
+
+ float32 totalRadius = proxyA->m_radius + proxyB->m_radius;
+ float32 target = b2Max(b2_linearSlop, totalRadius - 3.0f * b2_linearSlop);
+ float32 tolerance = 0.25f * b2_linearSlop;
+ b2Assert(target > tolerance);
+
+ float32 t1 = 0.0f;
+ const int32 k_maxIterations = 20; // TODO_ERIN b2Settings
+ int32 iter = 0;
+
+ // Prepare input for distance query.
+ b2SimplexCache cache;
+ cache.count = 0;
+ b2DistanceInput distanceInput;
+ distanceInput.proxyA = input->proxyA;
+ distanceInput.proxyB = input->proxyB;
+ distanceInput.useRadii = false;
+
+ // The outer loop progressively attempts to compute new separating axes.
+ // This loop terminates when an axis is repeated (no progress is made).
+ for(;;)
+ {
+ b2Transform xfA, xfB;
+ sweepA.GetTransform(&xfA, t1);
+ sweepB.GetTransform(&xfB, t1);
+
+ // Get the distance between shapes. We can also use the results
+ // to get a separating axis.
+ distanceInput.transformA = xfA;
+ distanceInput.transformB = xfB;
+ b2DistanceOutput distanceOutput;
+ b2Distance(&distanceOutput, &cache, &distanceInput);
+
+ // If the shapes are overlapped, we give up on continuous collision.
+ if (distanceOutput.distance <= 0.0f)
+ {
+ // Failure!
+ output->state = b2TOIOutput::e_overlapped;
+ output->t = 0.0f;
+ break;
+ }
+
+ if (distanceOutput.distance < target + tolerance)
+ {
+ // Victory!
+ output->state = b2TOIOutput::e_touching;
+ output->t = t1;
+ break;
+ }
+
+ // Initialize the separating axis.
+ b2SeparationFunction fcn;
+ fcn.Initialize(&cache, proxyA, sweepA, proxyB, sweepB, t1);
+#if 0
+ // Dump the curve seen by the root finder
+ {
+ const int32 N = 100;
+ float32 dx = 1.0f / N;
+ float32 xs[N+1];
+ float32 fs[N+1];
+
+ float32 x = 0.0f;
+
+ for (int32 i = 0; i <= N; ++i)
+ {
+ sweepA.GetTransform(&xfA, x);
+ sweepB.GetTransform(&xfB, x);
+ float32 f = fcn.Evaluate(xfA, xfB) - target;
+
+ printf("%g %g\n", x, f);
+
+ xs[i] = x;
+ fs[i] = f;
+
+ x += dx;
+ }
+ }
+#endif
+
+ // Compute the TOI on the separating axis. We do this by successively
+ // resolving the deepest point. This loop is bounded by the number of vertices.
+ bool done = false;
+ float32 t2 = tMax;
+ int32 pushBackIter = 0;
+ for (;;)
+ {
+ // Find the deepest point at t2. Store the witness point indices.
+ int32 indexA, indexB;
+ float32 s2 = fcn.FindMinSeparation(&indexA, &indexB, t2);
+
+ // Is the final configuration separated?
+ if (s2 > target + tolerance)
+ {
+ // Victory!
+ output->state = b2TOIOutput::e_separated;
+ output->t = tMax;
+ done = true;
+ break;
+ }
+
+ // Has the separation reached tolerance?
+ if (s2 > target - tolerance)
+ {
+ // Advance the sweeps
+ t1 = t2;
+ break;
+ }
+
+ // Compute the initial separation of the witness points.
+ float32 s1 = fcn.Evaluate(indexA, indexB, t1);
+
+ // Check for initial overlap. This might happen if the root finder
+ // runs out of iterations.
+ if (s1 < target - tolerance)
+ {
+ output->state = b2TOIOutput::e_failed;
+ output->t = t1;
+ done = true;
+ break;
+ }
+
+ // Check for touching
+ if (s1 <= target + tolerance)
+ {
+ // Victory! t1 should hold the TOI (could be 0.0).
+ output->state = b2TOIOutput::e_touching;
+ output->t = t1;
+ done = true;
+ break;
+ }
+
+ // Compute 1D root of: f(x) - target = 0
+ int32 rootIterCount = 0;
+ float32 a1 = t1, a2 = t2;
+ for (;;)
+ {
+ // Use a mix of the secant rule and bisection.
+ float32 t;
+ if (rootIterCount & 1)
+ {
+ // Secant rule to improve convergence.
+ t = a1 + (target - s1) * (a2 - a1) / (s2 - s1);
+ }
+ else
+ {
+ // Bisection to guarantee progress.
+ t = 0.5f * (a1 + a2);
+ }
+
+ float32 s = fcn.Evaluate(indexA, indexB, t);
+
+ if (b2Abs(s - target) < tolerance)
+ {
+ // t2 holds a tentative value for t1
+ t2 = t;
+ break;
+ }
+
+ // Ensure we continue to bracket the root.
+ if (s > target)
+ {
+ a1 = t;
+ s1 = s;
+ }
+ else
+ {
+ a2 = t;
+ s2 = s;
+ }
+
+ ++rootIterCount;
+ ++b2_toiRootIters;
+
+ if (rootIterCount == 50)
+ {
+ break;
+ }
+ }
+
+ b2_toiMaxRootIters = b2Max(b2_toiMaxRootIters, rootIterCount);
+
+ ++pushBackIter;
+
+ if (pushBackIter == b2_maxPolygonVertices)
+ {
+ break;
+ }
+ }
+
+ ++iter;
+ ++b2_toiIters;
+
+ if (done)
+ {
+ break;
+ }
+
+ if (iter == k_maxIterations)
+ {
+ // Root finder got stuck. Semi-victory.
+ output->state = b2TOIOutput::e_failed;
+ output->t = t1;
+ break;
+ }
+ }
+
+ b2_toiMaxIters = b2Max(b2_toiMaxIters, iter);
+}
diff --git a/tests/box2d/Box2D/Collision/b2TimeOfImpact.h b/tests/box2d/Box2D/Collision/b2TimeOfImpact.h new file mode 100755 index 00000000..179a1700 --- /dev/null +++ b/tests/box2d/Box2D/Collision/b2TimeOfImpact.h @@ -0,0 +1,58 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_TIME_OF_IMPACT_H
+#define B2_TIME_OF_IMPACT_H
+
+#include <Box2D/Common/b2Math.h>
+#include <Box2D/Collision/b2Distance.h>
+
+/// Input parameters for b2TimeOfImpact
+struct b2TOIInput
+{
+ b2DistanceProxy proxyA;
+ b2DistanceProxy proxyB;
+ b2Sweep sweepA;
+ b2Sweep sweepB;
+ float32 tMax; // defines sweep interval [0, tMax]
+};
+
+// Output parameters for b2TimeOfImpact.
+struct b2TOIOutput
+{
+ enum State
+ {
+ e_unknown,
+ e_failed,
+ e_overlapped,
+ e_touching,
+ e_separated
+ };
+
+ State state;
+ float32 t;
+};
+
+/// Compute the upper bound on time before two shapes penetrate. Time is represented as
+/// a fraction between [0,tMax]. This uses a swept separating axis and may miss some intermediate,
+/// non-tunneling collision. If you change the time interval, you should call this function
+/// again.
+/// Note: use b2Distance to compute the contact point and normal at the time of impact.
+void b2TimeOfImpact(b2TOIOutput* output, const b2TOIInput* input);
+
+#endif
diff --git a/tests/box2d/Box2D/Common/b2BlockAllocator.cpp b/tests/box2d/Box2D/Common/b2BlockAllocator.cpp new file mode 100755 index 00000000..f5060daa --- /dev/null +++ b/tests/box2d/Box2D/Common/b2BlockAllocator.cpp @@ -0,0 +1,217 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Common/b2BlockAllocator.h>
+#include <cstdlib>
+#include <climits>
+#include <cstring>
+#include <memory>
+using namespace std;
+
+int32 b2BlockAllocator::s_blockSizes[b2_blockSizes] =
+{
+ 16, // 0
+ 32, // 1
+ 64, // 2
+ 96, // 3
+ 128, // 4
+ 160, // 5
+ 192, // 6
+ 224, // 7
+ 256, // 8
+ 320, // 9
+ 384, // 10
+ 448, // 11
+ 512, // 12
+ 640, // 13
+};
+uint8 b2BlockAllocator::s_blockSizeLookup[b2_maxBlockSize + 1];
+bool b2BlockAllocator::s_blockSizeLookupInitialized;
+
+struct b2Chunk
+{
+ int32 blockSize;
+ b2Block* blocks;
+};
+
+struct b2Block
+{
+ b2Block* next;
+};
+
+b2BlockAllocator::b2BlockAllocator()
+{
+ b2Assert(b2_blockSizes < UCHAR_MAX);
+
+ m_chunkSpace = b2_chunkArrayIncrement;
+ m_chunkCount = 0;
+ m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk));
+
+ memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk));
+ memset(m_freeLists, 0, sizeof(m_freeLists));
+
+ if (s_blockSizeLookupInitialized == false)
+ {
+ int32 j = 0;
+ for (int32 i = 1; i <= b2_maxBlockSize; ++i)
+ {
+ b2Assert(j < b2_blockSizes);
+ if (i <= s_blockSizes[j])
+ {
+ s_blockSizeLookup[i] = (uint8)j;
+ }
+ else
+ {
+ ++j;
+ s_blockSizeLookup[i] = (uint8)j;
+ }
+ }
+
+ s_blockSizeLookupInitialized = true;
+ }
+}
+
+b2BlockAllocator::~b2BlockAllocator()
+{
+ for (int32 i = 0; i < m_chunkCount; ++i)
+ {
+ b2Free(m_chunks[i].blocks);
+ }
+
+ b2Free(m_chunks);
+}
+
+void* b2BlockAllocator::Allocate(int32 size)
+{
+ if (size == 0)
+ return NULL;
+
+ b2Assert(0 < size);
+
+ if (size > b2_maxBlockSize)
+ {
+ return b2Alloc(size);
+ }
+
+ int32 index = s_blockSizeLookup[size];
+ b2Assert(0 <= index && index < b2_blockSizes);
+
+ if (m_freeLists[index])
+ {
+ b2Block* block = m_freeLists[index];
+ m_freeLists[index] = block->next;
+ return block;
+ }
+ else
+ {
+ if (m_chunkCount == m_chunkSpace)
+ {
+ b2Chunk* oldChunks = m_chunks;
+ m_chunkSpace += b2_chunkArrayIncrement;
+ m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk));
+ memcpy(m_chunks, oldChunks, m_chunkCount * sizeof(b2Chunk));
+ memset(m_chunks + m_chunkCount, 0, b2_chunkArrayIncrement * sizeof(b2Chunk));
+ b2Free(oldChunks);
+ }
+
+ b2Chunk* chunk = m_chunks + m_chunkCount;
+ chunk->blocks = (b2Block*)b2Alloc(b2_chunkSize);
+#if defined(_DEBUG)
+ memset(chunk->blocks, 0xcd, b2_chunkSize);
+#endif
+ int32 blockSize = s_blockSizes[index];
+ chunk->blockSize = blockSize;
+ int32 blockCount = b2_chunkSize / blockSize;
+ b2Assert(blockCount * blockSize <= b2_chunkSize);
+ for (int32 i = 0; i < blockCount - 1; ++i)
+ {
+ b2Block* block = (b2Block*)((int8*)chunk->blocks + blockSize * i);
+ b2Block* next = (b2Block*)((int8*)chunk->blocks + blockSize * (i + 1));
+ block->next = next;
+ }
+ b2Block* last = (b2Block*)((int8*)chunk->blocks + blockSize * (blockCount - 1));
+ last->next = NULL;
+
+ m_freeLists[index] = chunk->blocks->next;
+ ++m_chunkCount;
+
+ return chunk->blocks;
+ }
+}
+
+void b2BlockAllocator::Free(void* p, int32 size)
+{
+ if (size == 0)
+ {
+ return;
+ }
+
+ b2Assert(0 < size);
+
+ if (size > b2_maxBlockSize)
+ {
+ b2Free(p);
+ return;
+ }
+
+ int32 index = s_blockSizeLookup[size];
+ b2Assert(0 <= index && index < b2_blockSizes);
+
+#ifdef _DEBUG
+ // Verify the memory address and size is valid.
+ int32 blockSize = s_blockSizes[index];
+ bool found = false;
+ for (int32 i = 0; i < m_chunkCount; ++i)
+ {
+ b2Chunk* chunk = m_chunks + i;
+ if (chunk->blockSize != blockSize)
+ {
+ b2Assert( (int8*)p + blockSize <= (int8*)chunk->blocks ||
+ (int8*)chunk->blocks + b2_chunkSize <= (int8*)p);
+ }
+ else
+ {
+ if ((int8*)chunk->blocks <= (int8*)p && (int8*)p + blockSize <= (int8*)chunk->blocks + b2_chunkSize)
+ {
+ found = true;
+ }
+ }
+ }
+
+ b2Assert(found);
+
+ memset(p, 0xfd, blockSize);
+#endif
+
+ b2Block* block = (b2Block*)p;
+ block->next = m_freeLists[index];
+ m_freeLists[index] = block;
+}
+
+void b2BlockAllocator::Clear()
+{
+ for (int32 i = 0; i < m_chunkCount; ++i)
+ {
+ b2Free(m_chunks[i].blocks);
+ }
+
+ m_chunkCount = 0;
+ memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk));
+
+ memset(m_freeLists, 0, sizeof(m_freeLists));
+}
diff --git a/tests/box2d/Box2D/Common/b2BlockAllocator.h b/tests/box2d/Box2D/Common/b2BlockAllocator.h new file mode 100755 index 00000000..8ba29a5e --- /dev/null +++ b/tests/box2d/Box2D/Common/b2BlockAllocator.h @@ -0,0 +1,62 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_BLOCK_ALLOCATOR_H
+#define B2_BLOCK_ALLOCATOR_H
+
+#include <Box2D/Common/b2Settings.h>
+
+const int32 b2_chunkSize = 16 * 1024;
+const int32 b2_maxBlockSize = 640;
+const int32 b2_blockSizes = 14;
+const int32 b2_chunkArrayIncrement = 128;
+
+struct b2Block;
+struct b2Chunk;
+
+/// This is a small object allocator used for allocating small
+/// objects that persist for more than one time step.
+/// See: http://www.codeproject.com/useritems/Small_Block_Allocator.asp
+class b2BlockAllocator
+{
+public:
+ b2BlockAllocator();
+ ~b2BlockAllocator();
+
+ /// Allocate memory. This will use b2Alloc if the size is larger than b2_maxBlockSize.
+ void* Allocate(int32 size);
+
+ /// Free memory. This will use b2Free if the size is larger than b2_maxBlockSize.
+ void Free(void* p, int32 size);
+
+ void Clear();
+
+private:
+
+ b2Chunk* m_chunks;
+ int32 m_chunkCount;
+ int32 m_chunkSpace;
+
+ b2Block* m_freeLists[b2_blockSizes];
+
+ static int32 s_blockSizes[b2_blockSizes];
+ static uint8 s_blockSizeLookup[b2_maxBlockSize + 1];
+ static bool s_blockSizeLookupInitialized;
+};
+
+#endif
diff --git a/tests/box2d/Box2D/Common/b2Draw.cpp b/tests/box2d/Box2D/Common/b2Draw.cpp new file mode 100755 index 00000000..327b5807 --- /dev/null +++ b/tests/box2d/Box2D/Common/b2Draw.cpp @@ -0,0 +1,44 @@ +/*
+* Copyright (c) 2011 Erin Catto http://box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Common/b2Draw.h>
+
+b2Draw::b2Draw()
+{
+ m_drawFlags = 0;
+}
+
+void b2Draw::SetFlags(uint32 flags)
+{
+ m_drawFlags = flags;
+}
+
+uint32 b2Draw::GetFlags() const
+{
+ return m_drawFlags;
+}
+
+void b2Draw::AppendFlags(uint32 flags)
+{
+ m_drawFlags |= flags;
+}
+
+void b2Draw::ClearFlags(uint32 flags)
+{
+ m_drawFlags &= ~flags;
+}
diff --git a/tests/box2d/Box2D/Common/b2Draw.h b/tests/box2d/Box2D/Common/b2Draw.h new file mode 100755 index 00000000..a27f335a --- /dev/null +++ b/tests/box2d/Box2D/Common/b2Draw.h @@ -0,0 +1,85 @@ +/*
+* Copyright (c) 2011 Erin Catto http://box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Common/b2Math.h>
+
+/// Color for debug drawing. Each value has the range [0,1].
+// emscripten - b2Color: rearrange member variables to be on separate lines
+struct b2Color
+{
+ b2Color() {}
+ b2Color(float32 r, float32 g, float32 b) : r(r), g(g), b(b) {}
+ void Set(float32 ri, float32 gi, float32 bi) { r = ri; g = gi; b = bi; }
+ float32 r;
+ float32 g;
+ float32 b;
+};
+
+/// Implement and register this class with a b2World to provide debug drawing of physics
+/// entities in your game.
+// emscripten - b2Draw: make virtual functions non-pure
+class b2Draw
+{
+public:
+ b2Draw();
+
+ virtual ~b2Draw() {}
+
+ enum
+ {
+ e_shapeBit = 0x0001, ///< draw shapes
+ e_jointBit = 0x0002, ///< draw joint connections
+ e_aabbBit = 0x0004, ///< draw axis aligned bounding boxes
+ e_pairBit = 0x0008, ///< draw broad-phase pairs
+ e_centerOfMassBit = 0x0010 ///< draw center of mass frame
+ };
+
+ /// Set the drawing flags.
+ void SetFlags(uint32 flags);
+
+ /// Get the drawing flags.
+ uint32 GetFlags() const;
+
+ /// Append flags to the current flags.
+ void AppendFlags(uint32 flags);
+
+ /// Clear flags from the current flags.
+ void ClearFlags(uint32 flags);
+
+ /// Draw a closed polygon provided in CCW order.
+ virtual void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) {}
+
+ /// Draw a solid closed polygon provided in CCW order.
+ virtual void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) {}
+
+ /// Draw a circle.
+ virtual void DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color) {}
+
+ /// Draw a solid circle.
+ virtual void DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color) {}
+
+ /// Draw a line segment.
+ virtual void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) {}
+
+ /// Draw a transform. Choose your own length scale.
+ /// @param xf a transform.
+ virtual void DrawTransform(const b2Transform& xf) {}
+
+protected:
+ uint32 m_drawFlags;
+};
diff --git a/tests/box2d/Box2D/Common/b2GrowableStack.h b/tests/box2d/Box2D/Common/b2GrowableStack.h new file mode 100755 index 00000000..a36d3bbb --- /dev/null +++ b/tests/box2d/Box2D/Common/b2GrowableStack.h @@ -0,0 +1,87 @@ +/*
+* Copyright (c) 2010 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_GROWABLE_STACK_H
+#define B2_GROWABLE_STACK_H
+#include <Box2D/Common/b2Settings.h>
+#ifndef EM_NO_LIBCPP
+#include <cstring>
+#endif
+
+/// This is a growable LIFO stack with an initial capacity of N.
+/// If the stack size exceeds the initial capacity, the heap is used
+/// to increase the size of the stack.
+template <typename T, int32 N>
+class b2GrowableStack
+{
+public:
+ b2GrowableStack()
+ {
+ m_stack = m_array;
+ m_count = 0;
+ m_capacity = N;
+ }
+
+ ~b2GrowableStack()
+ {
+ if (m_stack != m_array)
+ {
+ b2Free(m_stack);
+ m_stack = NULL;
+ }
+ }
+
+ void Push(const T& element)
+ {
+ if (m_count == m_capacity)
+ {
+ T* old = m_stack;
+ m_capacity *= 2;
+ m_stack = (T*)b2Alloc(m_capacity * sizeof(T));
+ std::memcpy(m_stack, old, m_count * sizeof(T));
+ if (old != m_array)
+ {
+ b2Free(old);
+ }
+ }
+
+ m_stack[m_count] = element;
+ ++m_count;
+ }
+
+ T Pop()
+ {
+ b2Assert(m_count > 0);
+ --m_count;
+ return m_stack[m_count];
+ }
+
+ int32 GetCount()
+ {
+ return m_count;
+ }
+
+private:
+ T* m_stack;
+ T m_array[N];
+ int32 m_count;
+ int32 m_capacity;
+};
+
+
+#endif
diff --git a/tests/box2d/Box2D/Common/b2Math.cpp b/tests/box2d/Box2D/Common/b2Math.cpp new file mode 100755 index 00000000..4974fe18 --- /dev/null +++ b/tests/box2d/Box2D/Common/b2Math.cpp @@ -0,0 +1,94 @@ +/*
+* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Common/b2Math.h>
+
+const b2Vec2 b2Vec2_zero(0.0f, 0.0f);
+
+/// Solve A * x = b, where b is a column vector. This is more efficient
+/// than computing the inverse in one-shot cases.
+b2Vec3 b2Mat33::Solve33(const b2Vec3& b) const
+{
+ float32 det = b2Dot(ex, b2Cross(ey, ez));
+ if (det != 0.0f)
+ {
+ det = 1.0f / det;
+ }
+ b2Vec3 x;
+ x.x = det * b2Dot(b, b2Cross(ey, ez));
+ x.y = det * b2Dot(ex, b2Cross(b, ez));
+ x.z = det * b2Dot(ex, b2Cross(ey, b));
+ return x;
+}
+
+/// Solve A * x = b, where b is a column vector. This is more efficient
+/// than computing the inverse in one-shot cases.
+b2Vec2 b2Mat33::Solve22(const b2Vec2& b) const
+{
+ float32 a11 = ex.x, a12 = ey.x, a21 = ex.y, a22 = ey.y;
+ float32 det = a11 * a22 - a12 * a21;
+ if (det != 0.0f)
+ {
+ det = 1.0f / det;
+ }
+ b2Vec2 x;
+ x.x = det * (a22 * b.x - a12 * b.y);
+ x.y = det * (a11 * b.y - a21 * b.x);
+ return x;
+}
+
+///
+void b2Mat33::GetInverse22(b2Mat33* M) const
+{
+ float32 a = ex.x, b = ey.x, c = ex.y, d = ey.y;
+ float32 det = a * d - b * c;
+ if (det != 0.0f)
+ {
+ det = 1.0f / det;
+ }
+
+ M->ex.x = det * d; M->ey.x = -det * b; M->ex.z = 0.0f;
+ M->ex.y = -det * c; M->ey.y = det * a; M->ey.z = 0.0f;
+ M->ez.x = 0.0f; M->ez.y = 0.0f; M->ez.z = 0.0f;
+}
+
+/// Returns the zero matrix if singular.
+void b2Mat33::GetSymInverse33(b2Mat33* M) const
+{
+ float32 det = b2Dot(ex, b2Cross(ey, ez));
+ if (det != 0.0f)
+ {
+ det = 1.0f / det;
+ }
+
+ float32 a11 = ex.x, a12 = ey.x, a13 = ez.x;
+ float32 a22 = ey.y, a23 = ez.y;
+ float32 a33 = ez.z;
+
+ M->ex.x = det * (a22 * a33 - a23 * a23);
+ M->ex.y = det * (a13 * a23 - a12 * a33);
+ M->ex.z = det * (a12 * a23 - a13 * a22);
+
+ M->ey.x = M->ex.y;
+ M->ey.y = det * (a11 * a33 - a13 * a13);
+ M->ey.z = det * (a13 * a12 - a11 * a23);
+
+ M->ez.x = M->ex.z;
+ M->ez.y = M->ey.z;
+ M->ez.z = det * (a11 * a22 - a12 * a12);
+}
diff --git a/tests/box2d/Box2D/Common/b2Math.h b/tests/box2d/Box2D/Common/b2Math.h new file mode 100755 index 00000000..84382a6f --- /dev/null +++ b/tests/box2d/Box2D/Common/b2Math.h @@ -0,0 +1,739 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_MATH_H
+#define B2_MATH_H
+
+#include <Box2D/Common/b2Settings.h>
+
+#ifdef EM_NO_LIBCPP
+#include <math.h>
+#include <float.h>
+#include <stddef.h>
+#include <limits.h>
+#else
+#include <cmath>
+#include <cfloat>
+#include <cstddef>
+#include <limits>
+#endif
+
+/// This function is used to ensure that a floating point number is
+/// not a NaN or infinity.
+inline bool b2IsValid(float32 x)
+{
+ if (x != x)
+ {
+ // NaN.
+ return false;
+ }
+
+ float32 infinity = std::numeric_limits<float32>::infinity();
+ return -infinity < x && x < infinity;
+}
+
+/// This is a approximate yet fast inverse square-root.
+inline float32 b2InvSqrt(float32 x)
+{
+ union
+ {
+ float32 x;
+ int32 i;
+ } convert;
+
+ convert.x = x;
+ float32 xhalf = 0.5f * x;
+ convert.i = 0x5f3759df - (convert.i >> 1);
+ x = convert.x;
+ x = x * (1.5f - xhalf * x * x);
+ return x;
+}
+
+#define b2Sqrt(x) std::sqrt(x)
+#define b2Atan2(y, x) std::atan2(y, x)
+
+/// A 2D column vector.
+struct b2Vec2
+{
+ /// Default constructor does nothing (for performance).
+ b2Vec2() {}
+
+ /// Construct using coordinates.
+ b2Vec2(float32 x, float32 y) : x(x), y(y) {}
+
+ /// Set this vector to all zeros.
+ void SetZero() { x = 0.0f; y = 0.0f; }
+
+ /// Set this vector to some specified coordinates.
+ void Set(float32 x_, float32 y_) { x = x_; y = y_; }
+
+ /// Negate this vector.
+ b2Vec2 operator -() const { b2Vec2 v; v.Set(-x, -y); return v; }
+
+ /// Read from and indexed element.
+ float32 operator () (int32 i) const
+ {
+ return (&x)[i];
+ }
+
+ /// Write to an indexed element.
+ float32& operator () (int32 i)
+ {
+ return (&x)[i];
+ }
+
+ /// Add a vector to this vector.
+ void operator += (const b2Vec2& v)
+ {
+ x += v.x; y += v.y;
+ }
+
+ /// Subtract a vector from this vector.
+ void operator -= (const b2Vec2& v)
+ {
+ x -= v.x; y -= v.y;
+ }
+
+ /// Multiply this vector by a scalar.
+ void operator *= (float32 a)
+ {
+ x *= a; y *= a;
+ }
+
+ /// Get the length of this vector (the norm).
+ float32 Length() const
+ {
+ return b2Sqrt(x * x + y * y);
+ }
+
+ /// Get the length squared. For performance, use this instead of
+ /// b2Vec2::Length (if possible).
+ float32 LengthSquared() const
+ {
+ return x * x + y * y;
+ }
+
+ /// Convert this vector into a unit vector. Returns the length.
+ float32 Normalize()
+ {
+ float32 length = Length();
+ if (length < b2_epsilon)
+ {
+ return 0.0f;
+ }
+ float32 invLength = 1.0f / length;
+ x *= invLength;
+ y *= invLength;
+
+ return length;
+ }
+
+ /// Does this vector contain finite coordinates?
+ bool IsValid() const
+ {
+ return b2IsValid(x) && b2IsValid(y);
+ }
+
+ /// Get the skew vector such that dot(skew_vec, other) == cross(vec, other)
+ b2Vec2 Skew() const
+ {
+ return b2Vec2(-y, x);
+ }
+
+ float32 x;
+ float32 y;
+};
+
+/// A 2D column vector with 3 elements.
+struct b2Vec3
+{
+ /// Default constructor does nothing (for performance).
+ b2Vec3() {}
+
+ /// Construct using coordinates.
+ b2Vec3(float32 x, float32 y, float32 z) : x(x), y(y), z(z) {}
+
+ /// Set this vector to all zeros.
+ void SetZero() { x = 0.0f; y = 0.0f; z = 0.0f; }
+
+ /// Set this vector to some specified coordinates.
+ void Set(float32 x_, float32 y_, float32 z_) { x = x_; y = y_; z = z_; }
+
+ /// Negate this vector.
+ b2Vec3 operator -() const { b2Vec3 v; v.Set(-x, -y, -z); return v; }
+
+ /// Add a vector to this vector.
+ void operator += (const b2Vec3& v)
+ {
+ x += v.x; y += v.y; z += v.z;
+ }
+
+ /// Subtract a vector from this vector.
+ void operator -= (const b2Vec3& v)
+ {
+ x -= v.x; y -= v.y; z -= v.z;
+ }
+
+ /// Multiply this vector by a scalar.
+ void operator *= (float32 s)
+ {
+ x *= s; y *= s; z *= s;
+ }
+
+ float32 x, y, z;
+};
+
+/// A 2-by-2 matrix. Stored in column-major order.
+struct b2Mat22
+{
+ /// The default constructor does nothing (for performance).
+ b2Mat22() {}
+
+ /// Construct this matrix using columns.
+ b2Mat22(const b2Vec2& c1, const b2Vec2& c2)
+ {
+ ex = c1;
+ ey = c2;
+ }
+
+ /// Construct this matrix using scalars.
+ b2Mat22(float32 a11, float32 a12, float32 a21, float32 a22)
+ {
+ ex.x = a11; ex.y = a21;
+ ey.x = a12; ey.y = a22;
+ }
+
+ /// Initialize this matrix using columns.
+ void Set(const b2Vec2& c1, const b2Vec2& c2)
+ {
+ ex = c1;
+ ey = c2;
+ }
+
+ /// Set this to the identity matrix.
+ void SetIdentity()
+ {
+ ex.x = 1.0f; ey.x = 0.0f;
+ ex.y = 0.0f; ey.y = 1.0f;
+ }
+
+ /// Set this matrix to all zeros.
+ void SetZero()
+ {
+ ex.x = 0.0f; ey.x = 0.0f;
+ ex.y = 0.0f; ey.y = 0.0f;
+ }
+
+ b2Mat22 GetInverse() const
+ {
+ float32 a = ex.x, b = ey.x, c = ex.y, d = ey.y;
+ b2Mat22 B;
+ float32 det = a * d - b * c;
+ if (det != 0.0f)
+ {
+ det = 1.0f / det;
+ }
+ B.ex.x = det * d; B.ey.x = -det * b;
+ B.ex.y = -det * c; B.ey.y = det * a;
+ return B;
+ }
+
+ /// Solve A * x = b, where b is a column vector. This is more efficient
+ /// than computing the inverse in one-shot cases.
+ b2Vec2 Solve(const b2Vec2& b) const
+ {
+ float32 a11 = ex.x, a12 = ey.x, a21 = ex.y, a22 = ey.y;
+ float32 det = a11 * a22 - a12 * a21;
+ if (det != 0.0f)
+ {
+ det = 1.0f / det;
+ }
+ b2Vec2 x;
+ x.x = det * (a22 * b.x - a12 * b.y);
+ x.y = det * (a11 * b.y - a21 * b.x);
+ return x;
+ }
+
+ b2Vec2 ex, ey;
+};
+
+/// A 3-by-3 matrix. Stored in column-major order.
+struct b2Mat33
+{
+ /// The default constructor does nothing (for performance).
+ b2Mat33() {}
+
+ /// Construct this matrix using columns.
+ b2Mat33(const b2Vec3& c1, const b2Vec3& c2, const b2Vec3& c3)
+ {
+ ex = c1;
+ ey = c2;
+ ez = c3;
+ }
+
+ /// Set this matrix to all zeros.
+ void SetZero()
+ {
+ ex.SetZero();
+ ey.SetZero();
+ ez.SetZero();
+ }
+
+ /// Solve A * x = b, where b is a column vector. This is more efficient
+ /// than computing the inverse in one-shot cases.
+ b2Vec3 Solve33(const b2Vec3& b) const;
+
+ /// Solve A * x = b, where b is a column vector. This is more efficient
+ /// than computing the inverse in one-shot cases. Solve only the upper
+ /// 2-by-2 matrix equation.
+ b2Vec2 Solve22(const b2Vec2& b) const;
+
+ /// Get the inverse of this matrix as a 2-by-2.
+ /// Returns the zero matrix if singular.
+ void GetInverse22(b2Mat33* M) const;
+
+ /// Get the symmetric inverse of this matrix as a 3-by-3.
+ /// Returns the zero matrix if singular.
+ void GetSymInverse33(b2Mat33* M) const;
+
+ b2Vec3 ex, ey, ez;
+};
+
+/// Rotation
+struct b2Rot
+{
+ b2Rot() {}
+
+ /// Initialize from an angle in radians
+ explicit b2Rot(float32 angle)
+ {
+ /// TODO_ERIN optimize
+ s = sinf(angle);
+ c = cosf(angle);
+ }
+
+ /// Set using an angle in radians.
+ void Set(float32 angle)
+ {
+ /// TODO_ERIN optimize
+ s = sinf(angle);
+ c = cosf(angle);
+ }
+
+ /// Set to the identity rotation
+ void SetIdentity()
+ {
+ s = 0.0f;
+ c = 1.0f;
+ }
+
+ /// Get the angle in radians
+ float32 GetAngle() const
+ {
+ return b2Atan2(s, c);
+ }
+
+ /// Get the x-axis
+ b2Vec2 GetXAxis() const
+ {
+ return b2Vec2(c, s);
+ }
+
+ /// Get the u-axis
+ b2Vec2 GetYAxis() const
+ {
+ return b2Vec2(-s, c);
+ }
+
+ /// Sine and cosine
+ float32 s, c;
+};
+
+/// A transform contains translation and rotation. It is used to represent
+/// the position and orientation of rigid frames.
+struct b2Transform
+{
+ /// The default constructor does nothing.
+ b2Transform() {}
+
+ /// Initialize using a position vector and a rotation.
+ b2Transform(const b2Vec2& position, const b2Rot& rotation) : p(position), q(rotation) {}
+
+ /// Set this to the identity transform.
+ void SetIdentity()
+ {
+ p.SetZero();
+ q.SetIdentity();
+ }
+
+ /// Set this based on the position and angle.
+ void Set(const b2Vec2& position, float32 angle)
+ {
+ p = position;
+ q.Set(angle);
+ }
+
+ b2Vec2 p;
+ b2Rot q;
+};
+
+/// This describes the motion of a body/shape for TOI computation.
+/// Shapes are defined with respect to the body origin, which may
+/// no coincide with the center of mass. However, to support dynamics
+/// we must interpolate the center of mass position.
+struct b2Sweep
+{
+ /// Get the interpolated transform at a specific time.
+ /// @param beta is a factor in [0,1], where 0 indicates alpha0.
+ void GetTransform(b2Transform* xfb, float32 beta) const;
+
+ /// Advance the sweep forward, yielding a new initial state.
+ /// @param alpha the new initial time.
+ void Advance(float32 alpha);
+
+ /// Normalize the angles.
+ void Normalize();
+
+ b2Vec2 localCenter; ///< local center of mass position
+ b2Vec2 c0, c; ///< center world positions
+ float32 a0, a; ///< world angles
+
+ /// Fraction of the current time step in the range [0,1]
+ /// c0 and a0 are the positions at alpha0.
+ float32 alpha0;
+};
+
+/// Useful constant
+extern const b2Vec2 b2Vec2_zero;
+
+/// Perform the dot product on two vectors.
+inline float32 b2Dot(const b2Vec2& a, const b2Vec2& b)
+{
+ return a.x * b.x + a.y * b.y;
+}
+
+/// Perform the cross product on two vectors. In 2D this produces a scalar.
+inline float32 b2Cross(const b2Vec2& a, const b2Vec2& b)
+{
+ return a.x * b.y - a.y * b.x;
+}
+
+/// Perform the cross product on a vector and a scalar. In 2D this produces
+/// a vector.
+inline b2Vec2 b2Cross(const b2Vec2& a, float32 s)
+{
+ return b2Vec2(s * a.y, -s * a.x);
+}
+
+/// Perform the cross product on a scalar and a vector. In 2D this produces
+/// a vector.
+inline b2Vec2 b2Cross(float32 s, const b2Vec2& a)
+{
+ return b2Vec2(-s * a.y, s * a.x);
+}
+
+/// Multiply a matrix times a vector. If a rotation matrix is provided,
+/// then this transforms the vector from one frame to another.
+inline b2Vec2 b2Mul(const b2Mat22& A, const b2Vec2& v)
+{
+ return b2Vec2(A.ex.x * v.x + A.ey.x * v.y, A.ex.y * v.x + A.ey.y * v.y);
+}
+
+/// Multiply a matrix transpose times a vector. If a rotation matrix is provided,
+/// then this transforms the vector from one frame to another (inverse transform).
+inline b2Vec2 b2MulT(const b2Mat22& A, const b2Vec2& v)
+{
+ return b2Vec2(b2Dot(v, A.ex), b2Dot(v, A.ey));
+}
+
+/// Add two vectors component-wise.
+inline b2Vec2 operator + (const b2Vec2& a, const b2Vec2& b)
+{
+ return b2Vec2(a.x + b.x, a.y + b.y);
+}
+
+/// Subtract two vectors component-wise.
+inline b2Vec2 operator - (const b2Vec2& a, const b2Vec2& b)
+{
+ return b2Vec2(a.x - b.x, a.y - b.y);
+}
+
+inline b2Vec2 operator * (float32 s, const b2Vec2& a)
+{
+ return b2Vec2(s * a.x, s * a.y);
+}
+
+inline bool operator == (const b2Vec2& a, const b2Vec2& b)
+{
+ return a.x == b.x && a.y == b.y;
+}
+
+inline float32 b2Distance(const b2Vec2& a, const b2Vec2& b)
+{
+ b2Vec2 c = a - b;
+ return c.Length();
+}
+
+inline float32 b2DistanceSquared(const b2Vec2& a, const b2Vec2& b)
+{
+ b2Vec2 c = a - b;
+ return b2Dot(c, c);
+}
+
+inline b2Vec3 operator * (float32 s, const b2Vec3& a)
+{
+ return b2Vec3(s * a.x, s * a.y, s * a.z);
+}
+
+/// Add two vectors component-wise.
+inline b2Vec3 operator + (const b2Vec3& a, const b2Vec3& b)
+{
+ return b2Vec3(a.x + b.x, a.y + b.y, a.z + b.z);
+}
+
+/// Subtract two vectors component-wise.
+inline b2Vec3 operator - (const b2Vec3& a, const b2Vec3& b)
+{
+ return b2Vec3(a.x - b.x, a.y - b.y, a.z - b.z);
+}
+
+/// Perform the dot product on two vectors.
+inline float32 b2Dot(const b2Vec3& a, const b2Vec3& b)
+{
+ return a.x * b.x + a.y * b.y + a.z * b.z;
+}
+
+/// Perform the cross product on two vectors.
+inline b2Vec3 b2Cross(const b2Vec3& a, const b2Vec3& b)
+{
+ return b2Vec3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x);
+}
+
+inline b2Mat22 operator + (const b2Mat22& A, const b2Mat22& B)
+{
+ return b2Mat22(A.ex + B.ex, A.ey + B.ey);
+}
+
+// A * B
+inline b2Mat22 b2Mul(const b2Mat22& A, const b2Mat22& B)
+{
+ return b2Mat22(b2Mul(A, B.ex), b2Mul(A, B.ey));
+}
+
+// A^T * B
+inline b2Mat22 b2MulT(const b2Mat22& A, const b2Mat22& B)
+{
+ b2Vec2 c1(b2Dot(A.ex, B.ex), b2Dot(A.ey, B.ex));
+ b2Vec2 c2(b2Dot(A.ex, B.ey), b2Dot(A.ey, B.ey));
+ return b2Mat22(c1, c2);
+}
+
+/// Multiply a matrix times a vector.
+inline b2Vec3 b2Mul(const b2Mat33& A, const b2Vec3& v)
+{
+ return v.x * A.ex + v.y * A.ey + v.z * A.ez;
+}
+
+/// Multiply a matrix times a vector.
+inline b2Vec2 b2Mul22(const b2Mat33& A, const b2Vec2& v)
+{
+ return b2Vec2(A.ex.x * v.x + A.ey.x * v.y, A.ex.y * v.x + A.ey.y * v.y);
+}
+
+/// Multiply two rotations: q * r
+inline b2Rot b2Mul(const b2Rot& q, const b2Rot& r)
+{
+ // [qc -qs] * [rc -rs] = [qc*rc-qs*rs -qc*rs-qs*rc]
+ // [qs qc] [rs rc] [qs*rc+qc*rs -qs*rs+qc*rc]
+ // s = qs * rc + qc * rs
+ // c = qc * rc - qs * rs
+ b2Rot qr;
+ qr.s = q.s * r.c + q.c * r.s;
+ qr.c = q.c * r.c - q.s * r.s;
+ return qr;
+}
+
+/// Transpose multiply two rotations: qT * r
+inline b2Rot b2MulT(const b2Rot& q, const b2Rot& r)
+{
+ // [ qc qs] * [rc -rs] = [qc*rc+qs*rs -qc*rs+qs*rc]
+ // [-qs qc] [rs rc] [-qs*rc+qc*rs qs*rs+qc*rc]
+ // s = qc * rs - qs * rc
+ // c = qc * rc + qs * rs
+ b2Rot qr;
+ qr.s = q.c * r.s - q.s * r.c;
+ qr.c = q.c * r.c + q.s * r.s;
+ return qr;
+}
+
+/// Rotate a vector
+inline b2Vec2 b2Mul(const b2Rot& q, const b2Vec2& v)
+{
+ return b2Vec2(q.c * v.x - q.s * v.y, q.s * v.x + q.c * v.y);
+}
+
+/// Inverse rotate a vector
+inline b2Vec2 b2MulT(const b2Rot& q, const b2Vec2& v)
+{
+ return b2Vec2(q.c * v.x + q.s * v.y, -q.s * v.x + q.c * v.y);
+}
+
+inline b2Vec2 b2Mul(const b2Transform& T, const b2Vec2& v)
+{
+ float32 x = (T.q.c * v.x - T.q.s * v.y) + T.p.x;
+ float32 y = (T.q.s * v.x + T.q.c * v.y) + T.p.y;
+
+ return b2Vec2(x, y);
+}
+
+inline b2Vec2 b2MulT(const b2Transform& T, const b2Vec2& v)
+{
+ float32 px = v.x - T.p.x;
+ float32 py = v.y - T.p.y;
+ float32 x = (T.q.c * px + T.q.s * py);
+ float32 y = (-T.q.s * px + T.q.c * py);
+
+ return b2Vec2(x, y);
+}
+
+// v2 = A.q.Rot(B.q.Rot(v1) + B.p) + A.p
+// = (A.q * B.q).Rot(v1) + A.q.Rot(B.p) + A.p
+inline b2Transform b2Mul(const b2Transform& A, const b2Transform& B)
+{
+ b2Transform C;
+ C.q = b2Mul(A.q, B.q);
+ C.p = b2Mul(A.q, B.p) + A.p;
+ return C;
+}
+
+// v2 = A.q' * (B.q * v1 + B.p - A.p)
+// = A.q' * B.q * v1 + A.q' * (B.p - A.p)
+inline b2Transform b2MulT(const b2Transform& A, const b2Transform& B)
+{
+ b2Transform C;
+ C.q = b2MulT(A.q, B.q);
+ C.p = b2MulT(A.q, B.p - A.p);
+ return C;
+}
+
+template <typename T>
+inline T b2Abs(T a)
+{
+ return a > T(0) ? a : -a;
+}
+
+inline b2Vec2 b2Abs(const b2Vec2& a)
+{
+ return b2Vec2(b2Abs(a.x), b2Abs(a.y));
+}
+
+inline b2Mat22 b2Abs(const b2Mat22& A)
+{
+ return b2Mat22(b2Abs(A.ex), b2Abs(A.ey));
+}
+
+template <typename T>
+inline T b2Min(T a, T b)
+{
+ return a < b ? a : b;
+}
+
+inline b2Vec2 b2Min(const b2Vec2& a, const b2Vec2& b)
+{
+ return b2Vec2(b2Min(a.x, b.x), b2Min(a.y, b.y));
+}
+
+template <typename T>
+inline T b2Max(T a, T b)
+{
+ return a > b ? a : b;
+}
+
+inline b2Vec2 b2Max(const b2Vec2& a, const b2Vec2& b)
+{
+ return b2Vec2(b2Max(a.x, b.x), b2Max(a.y, b.y));
+}
+
+template <typename T>
+inline T b2Clamp(T a, T low, T high)
+{
+ return b2Max(low, b2Min(a, high));
+}
+
+inline b2Vec2 b2Clamp(const b2Vec2& a, const b2Vec2& low, const b2Vec2& high)
+{
+ return b2Max(low, b2Min(a, high));
+}
+
+template<typename T> inline void b2Swap(T& a, T& b)
+{
+ T tmp = a;
+ a = b;
+ b = tmp;
+}
+
+/// "Next Largest Power of 2
+/// Given a binary integer value x, the next largest power of 2 can be computed by a SWAR algorithm
+/// that recursively "folds" the upper bits into the lower bits. This process yields a bit vector with
+/// the same most significant 1 as x, but all 1's below it. Adding 1 to that value yields the next
+/// largest power of 2. For a 32-bit value:"
+inline uint32 b2NextPowerOfTwo(uint32 x)
+{
+ x |= (x >> 1);
+ x |= (x >> 2);
+ x |= (x >> 4);
+ x |= (x >> 8);
+ x |= (x >> 16);
+ return x + 1;
+}
+
+inline bool b2IsPowerOfTwo(uint32 x)
+{
+ bool result = x > 0 && (x & (x - 1)) == 0;
+ return result;
+}
+
+inline void b2Sweep::GetTransform(b2Transform* xf, float32 beta) const
+{
+ xf->p = (1.0f - beta) * c0 + beta * c;
+ float32 angle = (1.0f - beta) * a0 + beta * a;
+ xf->q.Set(angle);
+
+ // Shift to origin
+ xf->p -= b2Mul(xf->q, localCenter);
+}
+
+inline void b2Sweep::Advance(float32 alpha)
+{
+ b2Assert(alpha0 < 1.0f);
+ float32 beta = (alpha - alpha0) / (1.0f - alpha0);
+ c0 = (1.0f - beta) * c0 + beta * c;
+ a0 = (1.0f - beta) * a0 + beta * a;
+ alpha0 = alpha;
+}
+
+/// Normalize an angle in radians to be between -pi and pi
+inline void b2Sweep::Normalize()
+{
+ float32 twoPi = 2.0f * b2_pi;
+ float32 d = twoPi * floorf(a0 / twoPi);
+ a0 -= d;
+ a -= d;
+}
+
+#endif
diff --git a/tests/box2d/Box2D/Common/b2Settings.cpp b/tests/box2d/Box2D/Common/b2Settings.cpp new file mode 100755 index 00000000..05a32230 --- /dev/null +++ b/tests/box2d/Box2D/Common/b2Settings.cpp @@ -0,0 +1,44 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Common/b2Settings.h>
+#include <cstdlib>
+#include <cstdio>
+#include <cstdarg>
+
+b2Version b2_version = {2, 2, 1};
+
+// Memory allocators. Modify these to use your own allocator.
+void* b2Alloc(int32 size)
+{
+ return malloc(size);
+}
+
+void b2Free(void* mem)
+{
+ free(mem);
+}
+
+// You can modify this to use your logging facility.
+void b2Log(const char* string, ...)
+{
+ va_list args;
+ va_start(args, string);
+ vprintf(string, args);
+ va_end(args);
+}
\ No newline at end of file diff --git a/tests/box2d/Box2D/Common/b2Settings.h b/tests/box2d/Box2D/Common/b2Settings.h new file mode 100755 index 00000000..391b6f84 --- /dev/null +++ b/tests/box2d/Box2D/Common/b2Settings.h @@ -0,0 +1,155 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_SETTINGS_H
+#define B2_SETTINGS_H
+
+#ifdef EM_NO_LIBCPP
+#include <assert.h>
+#include <math.h>
+#else
+#include <cassert>
+#include <cmath>
+#endif
+
+#define B2_NOT_USED(x) ((void)(x))
+#define b2Assert(A) assert(A)
+
+typedef signed char int8;
+typedef signed short int16;
+typedef signed int int32;
+typedef unsigned char uint8;
+typedef unsigned short uint16;
+typedef unsigned int uint32;
+typedef float float32;
+typedef double float64;
+
+#define b2_maxFloat FLT_MAX
+#define b2_epsilon FLT_EPSILON
+#define b2_pi 3.14159265359f
+
+/// @file
+/// Global tuning constants based on meters-kilograms-seconds (MKS) units.
+///
+
+// Collision
+
+/// The maximum number of contact points between two convex shapes. Do
+/// not change this value.
+#define b2_maxManifoldPoints 2
+
+/// The maximum number of vertices on a convex polygon. You cannot increase
+/// this too much because b2BlockAllocator has a maximum object size.
+#define b2_maxPolygonVertices 8
+
+/// This is used to fatten AABBs in the dynamic tree. This allows proxies
+/// to move by a small amount without triggering a tree adjustment.
+/// This is in meters.
+#define b2_aabbExtension 0.1f
+
+/// This is used to fatten AABBs in the dynamic tree. This is used to predict
+/// the future position based on the current displacement.
+/// This is a dimensionless multiplier.
+#define b2_aabbMultiplier 2.0f
+
+/// A small length used as a collision and constraint tolerance. Usually it is
+/// chosen to be numerically significant, but visually insignificant.
+#define b2_linearSlop 0.005f
+
+/// A small angle used as a collision and constraint tolerance. Usually it is
+/// chosen to be numerically significant, but visually insignificant.
+#define b2_angularSlop (2.0f / 180.0f * b2_pi)
+
+/// The radius of the polygon/edge shape skin. This should not be modified. Making
+/// this smaller means polygons will have an insufficient buffer for continuous collision.
+/// Making it larger may create artifacts for vertex collision.
+#define b2_polygonRadius (2.0f * b2_linearSlop)
+
+/// Maximum number of sub-steps per contact in continuous physics simulation.
+#define b2_maxSubSteps 8
+
+
+// Dynamics
+
+/// Maximum number of contacts to be handled to solve a TOI impact.
+#define b2_maxTOIContacts 32
+
+/// A velocity threshold for elastic collisions. Any collision with a relative linear
+/// velocity below this threshold will be treated as inelastic.
+#define b2_velocityThreshold 1.0f
+
+/// The maximum linear position correction used when solving constraints. This helps to
+/// prevent overshoot.
+#define b2_maxLinearCorrection 0.2f
+
+/// The maximum angular position correction used when solving constraints. This helps to
+/// prevent overshoot.
+#define b2_maxAngularCorrection (8.0f / 180.0f * b2_pi)
+
+/// The maximum linear velocity of a body. This limit is very large and is used
+/// to prevent numerical problems. You shouldn't need to adjust this.
+#define b2_maxTranslation 2.0f
+#define b2_maxTranslationSquared (b2_maxTranslation * b2_maxTranslation)
+
+/// The maximum angular velocity of a body. This limit is very large and is used
+/// to prevent numerical problems. You shouldn't need to adjust this.
+#define b2_maxRotation (0.5f * b2_pi)
+#define b2_maxRotationSquared (b2_maxRotation * b2_maxRotation)
+
+/// This scale factor controls how fast overlap is resolved. Ideally this would be 1 so
+/// that overlap is removed in one time step. However using values close to 1 often lead
+/// to overshoot.
+#define b2_baumgarte 0.2f
+#define b2_toiBaugarte 0.75f
+
+
+// Sleep
+
+/// The time that a body must be still before it will go to sleep.
+#define b2_timeToSleep 0.5f
+
+/// A body cannot sleep if its linear velocity is above this tolerance.
+#define b2_linearSleepTolerance 0.01f
+
+/// A body cannot sleep if its angular velocity is above this tolerance.
+#define b2_angularSleepTolerance (2.0f / 180.0f * b2_pi)
+
+// Memory Allocation
+
+/// Implement this function to use your own memory allocator.
+void* b2Alloc(int32 size);
+
+/// If you implement b2Alloc, you should also implement this function.
+void b2Free(void* mem);
+
+/// Logging function.
+void b2Log(const char* string, ...);
+
+/// Version numbering scheme.
+/// See http://en.wikipedia.org/wiki/Software_versioning
+struct b2Version
+{
+ int32 major; ///< significant changes
+ int32 minor; ///< incremental changes
+ int32 revision; ///< bug fixes
+};
+
+/// Current version.
+extern b2Version b2_version;
+
+#endif
diff --git a/tests/box2d/Box2D/Common/b2StackAllocator.cpp b/tests/box2d/Box2D/Common/b2StackAllocator.cpp new file mode 100755 index 00000000..4a862835 --- /dev/null +++ b/tests/box2d/Box2D/Common/b2StackAllocator.cpp @@ -0,0 +1,83 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Common/b2StackAllocator.h>
+#include <Box2D/Common/b2Math.h>
+
+b2StackAllocator::b2StackAllocator()
+{
+ m_index = 0;
+ m_allocation = 0;
+ m_maxAllocation = 0;
+ m_entryCount = 0;
+}
+
+b2StackAllocator::~b2StackAllocator()
+{
+ b2Assert(m_index == 0);
+ b2Assert(m_entryCount == 0);
+}
+
+void* b2StackAllocator::Allocate(int32 size)
+{
+ b2Assert(m_entryCount < b2_maxStackEntries);
+
+ b2StackEntry* entry = m_entries + m_entryCount;
+ entry->size = size;
+ if (m_index + size > b2_stackSize)
+ {
+ entry->data = (char*)b2Alloc(size);
+ entry->usedMalloc = true;
+ }
+ else
+ {
+ entry->data = m_data + m_index;
+ entry->usedMalloc = false;
+ m_index += size;
+ }
+
+ m_allocation += size;
+ m_maxAllocation = b2Max(m_maxAllocation, m_allocation);
+ ++m_entryCount;
+
+ return entry->data;
+}
+
+void b2StackAllocator::Free(void* p)
+{
+ b2Assert(m_entryCount > 0);
+ b2StackEntry* entry = m_entries + m_entryCount - 1;
+ b2Assert(p == entry->data);
+ if (entry->usedMalloc)
+ {
+ b2Free(p);
+ }
+ else
+ {
+ m_index -= entry->size;
+ }
+ m_allocation -= entry->size;
+ --m_entryCount;
+
+ p = NULL;
+}
+
+int32 b2StackAllocator::GetMaxAllocation() const
+{
+ return m_maxAllocation;
+}
diff --git a/tests/box2d/Box2D/Common/b2StackAllocator.h b/tests/box2d/Box2D/Common/b2StackAllocator.h new file mode 100755 index 00000000..796c51df --- /dev/null +++ b/tests/box2d/Box2D/Common/b2StackAllocator.h @@ -0,0 +1,60 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_STACK_ALLOCATOR_H
+#define B2_STACK_ALLOCATOR_H
+
+#include <Box2D/Common/b2Settings.h>
+
+const int32 b2_stackSize = 100 * 1024; // 100k
+const int32 b2_maxStackEntries = 32;
+
+struct b2StackEntry
+{
+ char* data;
+ int32 size;
+ bool usedMalloc;
+};
+
+// This is a stack allocator used for fast per step allocations.
+// You must nest allocate/free pairs. The code will assert
+// if you try to interleave multiple allocate/free pairs.
+class b2StackAllocator
+{
+public:
+ b2StackAllocator();
+ ~b2StackAllocator();
+
+ void* Allocate(int32 size);
+ void Free(void* p);
+
+ int32 GetMaxAllocation() const;
+
+private:
+
+ char m_data[b2_stackSize];
+ int32 m_index;
+
+ int32 m_allocation;
+ int32 m_maxAllocation;
+
+ b2StackEntry m_entries[b2_maxStackEntries];
+ int32 m_entryCount;
+};
+
+#endif
diff --git a/tests/box2d/Box2D/Common/b2Timer.cpp b/tests/box2d/Box2D/Common/b2Timer.cpp new file mode 100755 index 00000000..ea3479f1 --- /dev/null +++ b/tests/box2d/Box2D/Common/b2Timer.cpp @@ -0,0 +1,100 @@ +/*
+* Copyright (c) 2011 Erin Catto http://box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Common/b2Timer.h>
+
+#if defined(_WIN32)
+
+float64 b2Timer::s_invFrequency = 0.0f;
+
+#include <windows.h>
+
+b2Timer::b2Timer()
+{
+ LARGE_INTEGER largeInteger;
+
+ if (s_invFrequency == 0.0f)
+ {
+ QueryPerformanceFrequency(&largeInteger);
+ s_invFrequency = float64(largeInteger.QuadPart);
+ if (s_invFrequency > 0.0f)
+ {
+ s_invFrequency = 1000.0f / s_invFrequency;
+ }
+ }
+
+ QueryPerformanceCounter(&largeInteger);
+ m_start = float64(largeInteger.QuadPart);
+}
+
+void b2Timer::Reset()
+{
+ LARGE_INTEGER largeInteger;
+ QueryPerformanceCounter(&largeInteger);
+ m_start = float64(largeInteger.QuadPart);
+}
+
+float32 b2Timer::GetMilliseconds() const
+{
+ LARGE_INTEGER largeInteger;
+ QueryPerformanceCounter(&largeInteger);
+ float64 count = float64(largeInteger.QuadPart);
+ float32 ms = float32(s_invFrequency * (count - m_start));
+ return ms;
+}
+
+#elif defined(__linux__) || defined (__APPLE__)
+
+#include <sys/time.h>
+
+b2Timer::b2Timer()
+{
+ Reset();
+}
+
+void b2Timer::Reset()
+{
+ timeval t;
+ gettimeofday(&t, 0);
+ m_start_sec = t.tv_sec;
+ m_start_msec = t.tv_usec * 0.001f;
+}
+
+float32 b2Timer::GetMilliseconds() const
+{
+ timeval t;
+ gettimeofday(&t, 0);
+ return (t.tv_sec - m_start_sec) * 1000 + t.tv_usec * 0.001f - m_start_msec;
+}
+
+#else
+
+b2Timer::b2Timer()
+{
+}
+
+void b2Timer::Reset()
+{
+}
+
+float32 b2Timer::GetMilliseconds() const
+{
+ return 0.0f;
+}
+
+#endif
diff --git a/tests/box2d/Box2D/Common/b2Timer.h b/tests/box2d/Box2D/Common/b2Timer.h new file mode 100755 index 00000000..19bde287 --- /dev/null +++ b/tests/box2d/Box2D/Common/b2Timer.h @@ -0,0 +1,45 @@ +/*
+* Copyright (c) 2011 Erin Catto http://box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Common/b2Settings.h>
+
+/// Timer for profiling. This has platform specific code and may
+/// not work on every platform.
+class b2Timer
+{
+public:
+
+ /// Constructor
+ b2Timer();
+
+ /// Reset the timer.
+ void Reset();
+
+ /// Get the time since construction or the last reset.
+ float32 GetMilliseconds() const;
+
+private:
+
+#if defined(_WIN32)
+ float64 m_start;
+ static float64 s_invFrequency;
+#elif defined(__linux__) || defined (__APPLE__)
+ unsigned long m_start_sec;
+ unsigned long m_start_msec;
+#endif
+};
diff --git a/tests/box2d/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.cpp b/tests/box2d/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.cpp new file mode 100755 index 00000000..3886dfd7 --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.cpp @@ -0,0 +1,54 @@ +/*
+* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Dynamics/Contacts/b2ChainAndCircleContact.h>
+#include <Box2D/Common/b2BlockAllocator.h>
+#include <Box2D/Dynamics/b2Fixture.h>
+#include <Box2D/Collision/Shapes/b2ChainShape.h>
+#include <Box2D/Collision/Shapes/b2EdgeShape.h>
+
+#include <new>
+using namespace std;
+
+b2Contact* b2ChainAndCircleContact::Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator)
+{
+ void* mem = allocator->Allocate(sizeof(b2ChainAndCircleContact));
+ return new (mem) b2ChainAndCircleContact(fixtureA, indexA, fixtureB, indexB);
+}
+
+void b2ChainAndCircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)
+{
+ ((b2ChainAndCircleContact*)contact)->~b2ChainAndCircleContact();
+ allocator->Free(contact, sizeof(b2ChainAndCircleContact));
+}
+
+b2ChainAndCircleContact::b2ChainAndCircleContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB)
+: b2Contact(fixtureA, indexA, fixtureB, indexB)
+{
+ b2Assert(m_fixtureA->GetType() == b2Shape::e_chain);
+ b2Assert(m_fixtureB->GetType() == b2Shape::e_circle);
+}
+
+void b2ChainAndCircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB)
+{
+ b2ChainShape* chain = (b2ChainShape*)m_fixtureA->GetShape();
+ b2EdgeShape edge;
+ chain->GetChildEdge(&edge, m_indexA);
+ b2CollideEdgeAndCircle( manifold, &edge, xfA,
+ (b2CircleShape*)m_fixtureB->GetShape(), xfB);
+}
diff --git a/tests/box2d/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.h b/tests/box2d/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.h new file mode 100755 index 00000000..2dad0b64 --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.h @@ -0,0 +1,39 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_CHAIN_AND_CIRCLE_CONTACT_H
+#define B2_CHAIN_AND_CIRCLE_CONTACT_H
+
+#include <Box2D/Dynamics/Contacts/b2Contact.h>
+
+class b2BlockAllocator;
+
+class b2ChainAndCircleContact : public b2Contact
+{
+public:
+ static b2Contact* Create( b2Fixture* fixtureA, int32 indexA,
+ b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator);
+ static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);
+
+ b2ChainAndCircleContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB);
+ ~b2ChainAndCircleContact() {}
+
+ void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB);
+};
+
+#endif
diff --git a/tests/box2d/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.cpp b/tests/box2d/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.cpp new file mode 100755 index 00000000..02bcaaf6 --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.cpp @@ -0,0 +1,54 @@ +/*
+* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.h>
+#include <Box2D/Common/b2BlockAllocator.h>
+#include <Box2D/Dynamics/b2Fixture.h>
+#include <Box2D/Collision/Shapes/b2ChainShape.h>
+#include <Box2D/Collision/Shapes/b2EdgeShape.h>
+
+#include <new>
+using namespace std;
+
+b2Contact* b2ChainAndPolygonContact::Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator)
+{
+ void* mem = allocator->Allocate(sizeof(b2ChainAndPolygonContact));
+ return new (mem) b2ChainAndPolygonContact(fixtureA, indexA, fixtureB, indexB);
+}
+
+void b2ChainAndPolygonContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)
+{
+ ((b2ChainAndPolygonContact*)contact)->~b2ChainAndPolygonContact();
+ allocator->Free(contact, sizeof(b2ChainAndPolygonContact));
+}
+
+b2ChainAndPolygonContact::b2ChainAndPolygonContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB)
+: b2Contact(fixtureA, indexA, fixtureB, indexB)
+{
+ b2Assert(m_fixtureA->GetType() == b2Shape::e_chain);
+ b2Assert(m_fixtureB->GetType() == b2Shape::e_polygon);
+}
+
+void b2ChainAndPolygonContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB)
+{
+ b2ChainShape* chain = (b2ChainShape*)m_fixtureA->GetShape();
+ b2EdgeShape edge;
+ chain->GetChildEdge(&edge, m_indexA);
+ b2CollideEdgeAndPolygon( manifold, &edge, xfA,
+ (b2PolygonShape*)m_fixtureB->GetShape(), xfB);
+}
diff --git a/tests/box2d/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.h b/tests/box2d/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.h new file mode 100755 index 00000000..8f30ee86 --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.h @@ -0,0 +1,39 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_CHAIN_AND_POLYGON_CONTACT_H
+#define B2_CHAIN_AND_POLYGON_CONTACT_H
+
+#include <Box2D/Dynamics/Contacts/b2Contact.h>
+
+class b2BlockAllocator;
+
+class b2ChainAndPolygonContact : public b2Contact
+{
+public:
+ static b2Contact* Create( b2Fixture* fixtureA, int32 indexA,
+ b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator);
+ static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);
+
+ b2ChainAndPolygonContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB);
+ ~b2ChainAndPolygonContact() {}
+
+ void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB);
+};
+
+#endif
diff --git a/tests/box2d/Box2D/Dynamics/Contacts/b2CircleContact.cpp b/tests/box2d/Box2D/Dynamics/Contacts/b2CircleContact.cpp new file mode 100755 index 00000000..584ef2f1 --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Contacts/b2CircleContact.cpp @@ -0,0 +1,53 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Dynamics/Contacts/b2CircleContact.h>
+#include <Box2D/Dynamics/b2Body.h>
+#include <Box2D/Dynamics/b2Fixture.h>
+#include <Box2D/Dynamics/b2WorldCallbacks.h>
+#include <Box2D/Common/b2BlockAllocator.h>
+#include <Box2D/Collision/b2TimeOfImpact.h>
+
+#include <new>
+using namespace std;
+
+b2Contact* b2CircleContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator)
+{
+ void* mem = allocator->Allocate(sizeof(b2CircleContact));
+ return new (mem) b2CircleContact(fixtureA, fixtureB);
+}
+
+void b2CircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)
+{
+ ((b2CircleContact*)contact)->~b2CircleContact();
+ allocator->Free(contact, sizeof(b2CircleContact));
+}
+
+b2CircleContact::b2CircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB)
+ : b2Contact(fixtureA, 0, fixtureB, 0)
+{
+ b2Assert(m_fixtureA->GetType() == b2Shape::e_circle);
+ b2Assert(m_fixtureB->GetType() == b2Shape::e_circle);
+}
+
+void b2CircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB)
+{
+ b2CollideCircles(manifold,
+ (b2CircleShape*)m_fixtureA->GetShape(), xfA,
+ (b2CircleShape*)m_fixtureB->GetShape(), xfB);
+}
diff --git a/tests/box2d/Box2D/Dynamics/Contacts/b2CircleContact.h b/tests/box2d/Box2D/Dynamics/Contacts/b2CircleContact.h new file mode 100755 index 00000000..aac1f0bd --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Contacts/b2CircleContact.h @@ -0,0 +1,39 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_CIRCLE_CONTACT_H
+#define B2_CIRCLE_CONTACT_H
+
+#include <Box2D/Dynamics/Contacts/b2Contact.h>
+
+class b2BlockAllocator;
+
+class b2CircleContact : public b2Contact
+{
+public:
+ static b2Contact* Create( b2Fixture* fixtureA, int32 indexA,
+ b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator);
+ static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);
+
+ b2CircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB);
+ ~b2CircleContact() {}
+
+ void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB);
+};
+
+#endif
diff --git a/tests/box2d/Box2D/Dynamics/Contacts/b2Contact.cpp b/tests/box2d/Box2D/Dynamics/Contacts/b2Contact.cpp new file mode 100755 index 00000000..557af7f0 --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Contacts/b2Contact.cpp @@ -0,0 +1,240 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Dynamics/Contacts/b2Contact.h>
+#include <Box2D/Dynamics/Contacts/b2CircleContact.h>
+#include <Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.h>
+#include <Box2D/Dynamics/Contacts/b2PolygonContact.h>
+#include <Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h>
+#include <Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.h>
+#include <Box2D/Dynamics/Contacts/b2ChainAndCircleContact.h>
+#include <Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.h>
+#include <Box2D/Dynamics/Contacts/b2ContactSolver.h>
+
+#include <Box2D/Collision/b2Collision.h>
+#include <Box2D/Collision/b2TimeOfImpact.h>
+#include <Box2D/Collision/Shapes/b2Shape.h>
+#include <Box2D/Common/b2BlockAllocator.h>
+#include <Box2D/Dynamics/b2Body.h>
+#include <Box2D/Dynamics/b2Fixture.h>
+#include <Box2D/Dynamics/b2World.h>
+
+b2ContactRegister b2Contact::s_registers[b2Shape::e_typeCount][b2Shape::e_typeCount];
+bool b2Contact::s_initialized = false;
+
+void b2Contact::InitializeRegisters()
+{
+ AddType(b2CircleContact::Create, b2CircleContact::Destroy, b2Shape::e_circle, b2Shape::e_circle);
+ AddType(b2PolygonAndCircleContact::Create, b2PolygonAndCircleContact::Destroy, b2Shape::e_polygon, b2Shape::e_circle);
+ AddType(b2PolygonContact::Create, b2PolygonContact::Destroy, b2Shape::e_polygon, b2Shape::e_polygon);
+ AddType(b2EdgeAndCircleContact::Create, b2EdgeAndCircleContact::Destroy, b2Shape::e_edge, b2Shape::e_circle);
+ AddType(b2EdgeAndPolygonContact::Create, b2EdgeAndPolygonContact::Destroy, b2Shape::e_edge, b2Shape::e_polygon);
+ AddType(b2ChainAndCircleContact::Create, b2ChainAndCircleContact::Destroy, b2Shape::e_chain, b2Shape::e_circle);
+ AddType(b2ChainAndPolygonContact::Create, b2ChainAndPolygonContact::Destroy, b2Shape::e_chain, b2Shape::e_polygon);
+}
+
+void b2Contact::AddType(b2ContactCreateFcn* createFcn, b2ContactDestroyFcn* destoryFcn,
+ b2Shape::Type type1, b2Shape::Type type2)
+{
+ b2Assert(0 <= type1 && type1 < b2Shape::e_typeCount);
+ b2Assert(0 <= type2 && type2 < b2Shape::e_typeCount);
+
+ s_registers[type1][type2].createFcn = createFcn;
+ s_registers[type1][type2].destroyFcn = destoryFcn;
+ s_registers[type1][type2].primary = true;
+
+ if (type1 != type2)
+ {
+ s_registers[type2][type1].createFcn = createFcn;
+ s_registers[type2][type1].destroyFcn = destoryFcn;
+ s_registers[type2][type1].primary = false;
+ }
+}
+
+b2Contact* b2Contact::Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator)
+{
+ if (s_initialized == false)
+ {
+ InitializeRegisters();
+ s_initialized = true;
+ }
+
+ b2Shape::Type type1 = fixtureA->GetType();
+ b2Shape::Type type2 = fixtureB->GetType();
+
+ b2Assert(0 <= type1 && type1 < b2Shape::e_typeCount);
+ b2Assert(0 <= type2 && type2 < b2Shape::e_typeCount);
+
+ b2ContactCreateFcn* createFcn = s_registers[type1][type2].createFcn;
+ if (createFcn)
+ {
+ if (s_registers[type1][type2].primary)
+ {
+ return createFcn(fixtureA, indexA, fixtureB, indexB, allocator);
+ }
+ else
+ {
+ return createFcn(fixtureB, indexB, fixtureA, indexA, allocator);
+ }
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+void b2Contact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)
+{
+ b2Assert(s_initialized == true);
+
+ if (contact->m_manifold.pointCount > 0)
+ {
+ contact->GetFixtureA()->GetBody()->SetAwake(true);
+ contact->GetFixtureB()->GetBody()->SetAwake(true);
+ }
+
+ b2Shape::Type typeA = contact->GetFixtureA()->GetType();
+ b2Shape::Type typeB = contact->GetFixtureB()->GetType();
+
+ b2Assert(0 <= typeA && typeB < b2Shape::e_typeCount);
+ b2Assert(0 <= typeA && typeB < b2Shape::e_typeCount);
+
+ b2ContactDestroyFcn* destroyFcn = s_registers[typeA][typeB].destroyFcn;
+ destroyFcn(contact, allocator);
+}
+
+b2Contact::b2Contact(b2Fixture* fA, int32 indexA, b2Fixture* fB, int32 indexB)
+{
+ m_flags = e_enabledFlag;
+
+ m_fixtureA = fA;
+ m_fixtureB = fB;
+
+ m_indexA = indexA;
+ m_indexB = indexB;
+
+ m_manifold.pointCount = 0;
+
+ m_prev = NULL;
+ m_next = NULL;
+
+ m_nodeA.contact = NULL;
+ m_nodeA.prev = NULL;
+ m_nodeA.next = NULL;
+ m_nodeA.other = NULL;
+
+ m_nodeB.contact = NULL;
+ m_nodeB.prev = NULL;
+ m_nodeB.next = NULL;
+ m_nodeB.other = NULL;
+
+ m_toiCount = 0;
+
+ m_friction = b2MixFriction(m_fixtureA->m_friction, m_fixtureB->m_friction);
+ m_restitution = b2MixRestitution(m_fixtureA->m_restitution, m_fixtureB->m_restitution);
+}
+
+// Update the contact manifold and touching status.
+// Note: do not assume the fixture AABBs are overlapping or are valid.
+void b2Contact::Update(b2ContactListener* listener)
+{
+ b2Manifold oldManifold = m_manifold;
+
+ // Re-enable this contact.
+ m_flags |= e_enabledFlag;
+
+ bool touching = false;
+ bool wasTouching = (m_flags & e_touchingFlag) == e_touchingFlag;
+
+ bool sensorA = m_fixtureA->IsSensor();
+ bool sensorB = m_fixtureB->IsSensor();
+ bool sensor = sensorA || sensorB;
+
+ b2Body* bodyA = m_fixtureA->GetBody();
+ b2Body* bodyB = m_fixtureB->GetBody();
+ const b2Transform& xfA = bodyA->GetTransform();
+ const b2Transform& xfB = bodyB->GetTransform();
+
+ // Is this contact a sensor?
+ if (sensor)
+ {
+ const b2Shape* shapeA = m_fixtureA->GetShape();
+ const b2Shape* shapeB = m_fixtureB->GetShape();
+ touching = b2TestOverlap(shapeA, m_indexA, shapeB, m_indexB, xfA, xfB);
+
+ // Sensors don't generate manifolds.
+ m_manifold.pointCount = 0;
+ }
+ else
+ {
+ Evaluate(&m_manifold, xfA, xfB);
+ touching = m_manifold.pointCount > 0;
+
+ // Match old contact ids to new contact ids and copy the
+ // stored impulses to warm start the solver.
+ for (int32 i = 0; i < m_manifold.pointCount; ++i)
+ {
+ b2ManifoldPoint* mp2 = m_manifold.points + i;
+ mp2->normalImpulse = 0.0f;
+ mp2->tangentImpulse = 0.0f;
+ b2ContactID id2 = mp2->id;
+
+ for (int32 j = 0; j < oldManifold.pointCount; ++j)
+ {
+ b2ManifoldPoint* mp1 = oldManifold.points + j;
+
+ if (mp1->id.key == id2.key)
+ {
+ mp2->normalImpulse = mp1->normalImpulse;
+ mp2->tangentImpulse = mp1->tangentImpulse;
+ break;
+ }
+ }
+ }
+
+ if (touching != wasTouching)
+ {
+ bodyA->SetAwake(true);
+ bodyB->SetAwake(true);
+ }
+ }
+
+ if (touching)
+ {
+ m_flags |= e_touchingFlag;
+ }
+ else
+ {
+ m_flags &= ~e_touchingFlag;
+ }
+
+ if (wasTouching == false && touching == true && listener)
+ {
+ listener->BeginContact(this);
+ }
+
+ if (wasTouching == true && touching == false && listener)
+ {
+ listener->EndContact(this);
+ }
+
+ if (sensor == false && touching && listener)
+ {
+ listener->PreSolve(this, &oldManifold);
+ }
+}
diff --git a/tests/box2d/Box2D/Dynamics/Contacts/b2Contact.h b/tests/box2d/Box2D/Dynamics/Contacts/b2Contact.h new file mode 100755 index 00000000..7c132f92 --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Contacts/b2Contact.h @@ -0,0 +1,334 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_CONTACT_H
+#define B2_CONTACT_H
+
+#include <Box2D/Common/b2Math.h>
+#include <Box2D/Collision/b2Collision.h>
+#include <Box2D/Collision/Shapes/b2Shape.h>
+#include <Box2D/Dynamics/b2Fixture.h>
+
+class b2Body;
+class b2Contact;
+class b2Fixture;
+class b2World;
+class b2BlockAllocator;
+class b2StackAllocator;
+class b2ContactListener;
+
+/// Friction mixing law. The idea is to allow either fixture to drive the restitution to zero.
+/// For example, anything slides on ice.
+inline float32 b2MixFriction(float32 friction1, float32 friction2)
+{
+ return std::sqrt(friction1 * friction2);
+}
+
+/// Restitution mixing law. The idea is allow for anything to bounce off an inelastic surface.
+/// For example, a superball bounces on anything.
+inline float32 b2MixRestitution(float32 restitution1, float32 restitution2)
+{
+ return restitution1 > restitution2 ? restitution1 : restitution2;
+}
+
+typedef b2Contact* b2ContactCreateFcn( b2Fixture* fixtureA, int32 indexA,
+ b2Fixture* fixtureB, int32 indexB,
+ b2BlockAllocator* allocator);
+typedef void b2ContactDestroyFcn(b2Contact* contact, b2BlockAllocator* allocator);
+
+struct b2ContactRegister
+{
+ b2ContactCreateFcn* createFcn;
+ b2ContactDestroyFcn* destroyFcn;
+ bool primary;
+};
+
+/// A contact edge is used to connect bodies and contacts together
+/// in a contact graph where each body is a node and each contact
+/// is an edge. A contact edge belongs to a doubly linked list
+/// maintained in each attached body. Each contact has two contact
+/// nodes, one for each attached body.
+// emscripten - b2ContactEdge: add constructor
+struct b2ContactEdge
+{
+ b2Body* other; ///< provides quick access to the other body attached.
+ b2Contact* contact; ///< the contact
+ b2ContactEdge* prev; ///< the previous contact edge in the body's contact list
+ b2ContactEdge* next; ///< the next contact edge in the body's contact list
+
+ b2ContactEdge() {}
+};
+
+/// The class manages contact between two shapes. A contact exists for each overlapping
+/// AABB in the broad-phase (except if filtered). Therefore a contact object may exist
+/// that has no contact points.
+class b2Contact
+{
+public:
+
+ /// Get the contact manifold. Do not modify the manifold unless you understand the
+ /// internals of Box2D.
+ b2Manifold* GetManifold();
+ const b2Manifold* GetManifold() const;
+
+ /// Get the world manifold.
+ void GetWorldManifold(b2WorldManifold* worldManifold) const;
+
+ /// Is this contact touching?
+ bool IsTouching() const;
+
+ /// Enable/disable this contact. This can be used inside the pre-solve
+ /// contact listener. The contact is only disabled for the current
+ /// time step (or sub-step in continuous collisions).
+ void SetEnabled(bool flag);
+
+ /// Has this contact been disabled?
+ bool IsEnabled() const;
+
+ /// Get the next contact in the world's contact list.
+ b2Contact* GetNext();
+ const b2Contact* GetNext() const;
+
+ /// Get fixture A in this contact.
+ b2Fixture* GetFixtureA();
+ const b2Fixture* GetFixtureA() const;
+
+ /// Get the child primitive index for fixture A.
+ int32 GetChildIndexA() const;
+
+ /// Get fixture B in this contact.
+ b2Fixture* GetFixtureB();
+ const b2Fixture* GetFixtureB() const;
+
+ /// Get the child primitive index for fixture B.
+ int32 GetChildIndexB() const;
+
+ /// Override the default friction mixture. You can call this in b2ContactListener::PreSolve.
+ /// This value persists until set or reset.
+ void SetFriction(float32 friction);
+
+ /// Get the friction.
+ float32 GetFriction() const;
+
+ /// Reset the friction mixture to the default value.
+ void ResetFriction();
+
+ /// Override the default restitution mixture. You can call this in b2ContactListener::PreSolve.
+ /// The value persists until you set or reset.
+ void SetRestitution(float32 restitution);
+
+ /// Get the restitution.
+ float32 GetRestitution() const;
+
+ /// Reset the restitution to the default value.
+ void ResetRestitution();
+
+ /// Evaluate this contact with your own manifold and transforms.
+ virtual void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) = 0;
+
+protected:
+ friend class b2ContactManager;
+ friend class b2World;
+ friend class b2ContactSolver;
+ friend class b2Body;
+ friend class b2Fixture;
+
+ // Flags stored in m_flags
+ enum
+ {
+ // Used when crawling contact graph when forming islands.
+ e_islandFlag = 0x0001,
+
+ // Set when the shapes are touching.
+ e_touchingFlag = 0x0002,
+
+ // This contact can be disabled (by user)
+ e_enabledFlag = 0x0004,
+
+ // This contact needs filtering because a fixture filter was changed.
+ e_filterFlag = 0x0008,
+
+ // This bullet contact had a TOI event
+ e_bulletHitFlag = 0x0010,
+
+ // This contact has a valid TOI in m_toi
+ e_toiFlag = 0x0020
+ };
+
+ /// Flag this contact for filtering. Filtering will occur the next time step.
+ void FlagForFiltering();
+
+ static void AddType(b2ContactCreateFcn* createFcn, b2ContactDestroyFcn* destroyFcn,
+ b2Shape::Type typeA, b2Shape::Type typeB);
+ static void InitializeRegisters();
+ static b2Contact* Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator);
+ static void Destroy(b2Contact* contact, b2Shape::Type typeA, b2Shape::Type typeB, b2BlockAllocator* allocator);
+ static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);
+
+ b2Contact() : m_fixtureA(NULL), m_fixtureB(NULL) {}
+ b2Contact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB);
+ virtual ~b2Contact() {}
+
+ void Update(b2ContactListener* listener);
+
+ static b2ContactRegister s_registers[b2Shape::e_typeCount][b2Shape::e_typeCount];
+ static bool s_initialized;
+
+ uint32 m_flags;
+
+ // World pool and list pointers.
+ b2Contact* m_prev;
+ b2Contact* m_next;
+
+ // Nodes for connecting bodies.
+ b2ContactEdge m_nodeA;
+ b2ContactEdge m_nodeB;
+
+ b2Fixture* m_fixtureA;
+ b2Fixture* m_fixtureB;
+
+ int32 m_indexA;
+ int32 m_indexB;
+
+ b2Manifold m_manifold;
+
+ int32 m_toiCount;
+ float32 m_toi;
+
+ float32 m_friction;
+ float32 m_restitution;
+};
+
+inline b2Manifold* b2Contact::GetManifold()
+{
+ return &m_manifold;
+}
+
+inline const b2Manifold* b2Contact::GetManifold() const
+{
+ return &m_manifold;
+}
+
+inline void b2Contact::GetWorldManifold(b2WorldManifold* worldManifold) const
+{
+ const b2Body* bodyA = m_fixtureA->GetBody();
+ const b2Body* bodyB = m_fixtureB->GetBody();
+ const b2Shape* shapeA = m_fixtureA->GetShape();
+ const b2Shape* shapeB = m_fixtureB->GetShape();
+
+ worldManifold->Initialize(&m_manifold, bodyA->GetTransform(), shapeA->m_radius, bodyB->GetTransform(), shapeB->m_radius);
+}
+
+inline void b2Contact::SetEnabled(bool flag)
+{
+ if (flag)
+ {
+ m_flags |= e_enabledFlag;
+ }
+ else
+ {
+ m_flags &= ~e_enabledFlag;
+ }
+}
+
+inline bool b2Contact::IsEnabled() const
+{
+ return (m_flags & e_enabledFlag) == e_enabledFlag;
+}
+
+inline bool b2Contact::IsTouching() const
+{
+ return (m_flags & e_touchingFlag) == e_touchingFlag;
+}
+
+inline b2Contact* b2Contact::GetNext()
+{
+ return m_next;
+}
+
+inline const b2Contact* b2Contact::GetNext() const
+{
+ return m_next;
+}
+
+inline b2Fixture* b2Contact::GetFixtureA()
+{
+ return m_fixtureA;
+}
+
+inline const b2Fixture* b2Contact::GetFixtureA() const
+{
+ return m_fixtureA;
+}
+
+inline b2Fixture* b2Contact::GetFixtureB()
+{
+ return m_fixtureB;
+}
+
+inline int32 b2Contact::GetChildIndexA() const
+{
+ return m_indexA;
+}
+
+inline const b2Fixture* b2Contact::GetFixtureB() const
+{
+ return m_fixtureB;
+}
+
+inline int32 b2Contact::GetChildIndexB() const
+{
+ return m_indexB;
+}
+
+inline void b2Contact::FlagForFiltering()
+{
+ m_flags |= e_filterFlag;
+}
+
+inline void b2Contact::SetFriction(float32 friction)
+{
+ m_friction = friction;
+}
+
+inline float32 b2Contact::GetFriction() const
+{
+ return m_friction;
+}
+
+inline void b2Contact::ResetFriction()
+{
+ m_friction = b2MixFriction(m_fixtureA->m_friction, m_fixtureB->m_friction);
+}
+
+inline void b2Contact::SetRestitution(float32 restitution)
+{
+ m_restitution = restitution;
+}
+
+inline float32 b2Contact::GetRestitution() const
+{
+ return m_restitution;
+}
+
+inline void b2Contact::ResetRestitution()
+{
+ m_restitution = b2MixRestitution(m_fixtureA->m_restitution, m_fixtureB->m_restitution);
+}
+
+#endif
diff --git a/tests/box2d/Box2D/Dynamics/Contacts/b2ContactSolver.cpp b/tests/box2d/Box2D/Dynamics/Contacts/b2ContactSolver.cpp new file mode 100755 index 00000000..c990d7fb --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Contacts/b2ContactSolver.cpp @@ -0,0 +1,832 @@ +/*
+* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Dynamics/Contacts/b2ContactSolver.h>
+
+#include <Box2D/Dynamics/Contacts/b2Contact.h>
+#include <Box2D/Dynamics/b2Body.h>
+#include <Box2D/Dynamics/b2Fixture.h>
+#include <Box2D/Dynamics/b2World.h>
+#include <Box2D/Common/b2StackAllocator.h>
+
+#define B2_DEBUG_SOLVER 0
+
+struct b2ContactPositionConstraint
+{
+ b2Vec2 localPoints[b2_maxManifoldPoints];
+ b2Vec2 localNormal;
+ b2Vec2 localPoint;
+ int32 indexA;
+ int32 indexB;
+ float32 invMassA, invMassB;
+ b2Vec2 localCenterA, localCenterB;
+ float32 invIA, invIB;
+ b2Manifold::Type type;
+ float32 radiusA, radiusB;
+ int32 pointCount;
+};
+
+b2ContactSolver::b2ContactSolver(b2ContactSolverDef* def)
+{
+ m_step = def->step;
+ m_allocator = def->allocator;
+ m_count = def->count;
+ m_positionConstraints = (b2ContactPositionConstraint*)m_allocator->Allocate(m_count * sizeof(b2ContactPositionConstraint));
+ m_velocityConstraints = (b2ContactVelocityConstraint*)m_allocator->Allocate(m_count * sizeof(b2ContactVelocityConstraint));
+ m_positions = def->positions;
+ m_velocities = def->velocities;
+ m_contacts = def->contacts;
+
+ // Initialize position independent portions of the constraints.
+ for (int32 i = 0; i < m_count; ++i)
+ {
+ b2Contact* contact = m_contacts[i];
+
+ b2Fixture* fixtureA = contact->m_fixtureA;
+ b2Fixture* fixtureB = contact->m_fixtureB;
+ b2Shape* shapeA = fixtureA->GetShape();
+ b2Shape* shapeB = fixtureB->GetShape();
+ float32 radiusA = shapeA->m_radius;
+ float32 radiusB = shapeB->m_radius;
+ b2Body* bodyA = fixtureA->GetBody();
+ b2Body* bodyB = fixtureB->GetBody();
+ b2Manifold* manifold = contact->GetManifold();
+
+ int32 pointCount = manifold->pointCount;
+ b2Assert(pointCount > 0);
+
+ b2ContactVelocityConstraint* vc = m_velocityConstraints + i;
+ vc->friction = contact->m_friction;
+ vc->restitution = contact->m_restitution;
+ vc->indexA = bodyA->m_islandIndex;
+ vc->indexB = bodyB->m_islandIndex;
+ vc->invMassA = bodyA->m_invMass;
+ vc->invMassB = bodyB->m_invMass;
+ vc->invIA = bodyA->m_invI;
+ vc->invIB = bodyB->m_invI;
+ vc->contactIndex = i;
+ vc->pointCount = pointCount;
+ vc->K.SetZero();
+ vc->normalMass.SetZero();
+
+ b2ContactPositionConstraint* pc = m_positionConstraints + i;
+ pc->indexA = bodyA->m_islandIndex;
+ pc->indexB = bodyB->m_islandIndex;
+ pc->invMassA = bodyA->m_invMass;
+ pc->invMassB = bodyB->m_invMass;
+ pc->localCenterA = bodyA->m_sweep.localCenter;
+ pc->localCenterB = bodyB->m_sweep.localCenter;
+ pc->invIA = bodyA->m_invI;
+ pc->invIB = bodyB->m_invI;
+ pc->localNormal = manifold->localNormal;
+ pc->localPoint = manifold->localPoint;
+ pc->pointCount = pointCount;
+ pc->radiusA = radiusA;
+ pc->radiusB = radiusB;
+ pc->type = manifold->type;
+
+ for (int32 j = 0; j < pointCount; ++j)
+ {
+ b2ManifoldPoint* cp = manifold->points + j;
+ b2VelocityConstraintPoint* vcp = vc->points + j;
+
+ if (m_step.warmStarting)
+ {
+ vcp->normalImpulse = m_step.dtRatio * cp->normalImpulse;
+ vcp->tangentImpulse = m_step.dtRatio * cp->tangentImpulse;
+ }
+ else
+ {
+ vcp->normalImpulse = 0.0f;
+ vcp->tangentImpulse = 0.0f;
+ }
+
+ vcp->rA.SetZero();
+ vcp->rB.SetZero();
+ vcp->normalMass = 0.0f;
+ vcp->tangentMass = 0.0f;
+ vcp->velocityBias = 0.0f;
+
+ pc->localPoints[j] = cp->localPoint;
+ }
+ }
+}
+
+b2ContactSolver::~b2ContactSolver()
+{
+ m_allocator->Free(m_velocityConstraints);
+ m_allocator->Free(m_positionConstraints);
+}
+
+// Initialize position dependent portions of the velocity constraints.
+void b2ContactSolver::InitializeVelocityConstraints()
+{
+ for (int32 i = 0; i < m_count; ++i)
+ {
+ b2ContactVelocityConstraint* vc = m_velocityConstraints + i;
+ b2ContactPositionConstraint* pc = m_positionConstraints + i;
+
+ float32 radiusA = pc->radiusA;
+ float32 radiusB = pc->radiusB;
+ b2Manifold* manifold = m_contacts[vc->contactIndex]->GetManifold();
+
+ int32 indexA = vc->indexA;
+ int32 indexB = vc->indexB;
+
+ float32 mA = vc->invMassA;
+ float32 mB = vc->invMassB;
+ float32 iA = vc->invIA;
+ float32 iB = vc->invIB;
+ b2Vec2 localCenterA = pc->localCenterA;
+ b2Vec2 localCenterB = pc->localCenterB;
+
+ b2Vec2 cA = m_positions[indexA].c;
+ float32 aA = m_positions[indexA].a;
+ b2Vec2 vA = m_velocities[indexA].v;
+ float32 wA = m_velocities[indexA].w;
+
+ b2Vec2 cB = m_positions[indexB].c;
+ float32 aB = m_positions[indexB].a;
+ b2Vec2 vB = m_velocities[indexB].v;
+ float32 wB = m_velocities[indexB].w;
+
+ b2Assert(manifold->pointCount > 0);
+
+ b2Transform xfA, xfB;
+ xfA.q.Set(aA);
+ xfB.q.Set(aB);
+ xfA.p = cA - b2Mul(xfA.q, localCenterA);
+ xfB.p = cB - b2Mul(xfB.q, localCenterB);
+
+ b2WorldManifold worldManifold;
+ worldManifold.Initialize(manifold, xfA, radiusA, xfB, radiusB);
+
+ vc->normal = worldManifold.normal;
+
+ int32 pointCount = vc->pointCount;
+ for (int32 j = 0; j < pointCount; ++j)
+ {
+ b2VelocityConstraintPoint* vcp = vc->points + j;
+
+ vcp->rA = worldManifold.points[j] - cA;
+ vcp->rB = worldManifold.points[j] - cB;
+
+ float32 rnA = b2Cross(vcp->rA, vc->normal);
+ float32 rnB = b2Cross(vcp->rB, vc->normal);
+
+ float32 kNormal = mA + mB + iA * rnA * rnA + iB * rnB * rnB;
+
+ vcp->normalMass = kNormal > 0.0f ? 1.0f / kNormal : 0.0f;
+
+ b2Vec2 tangent = b2Cross(vc->normal, 1.0f);
+
+ float32 rtA = b2Cross(vcp->rA, tangent);
+ float32 rtB = b2Cross(vcp->rB, tangent);
+
+ float32 kTangent = mA + mB + iA * rtA * rtA + iB * rtB * rtB;
+
+ vcp->tangentMass = kTangent > 0.0f ? 1.0f / kTangent : 0.0f;
+
+ // Setup a velocity bias for restitution.
+ vcp->velocityBias = 0.0f;
+ float32 vRel = b2Dot(vc->normal, vB + b2Cross(wB, vcp->rB) - vA - b2Cross(wA, vcp->rA));
+ if (vRel < -b2_velocityThreshold)
+ {
+ vcp->velocityBias = -vc->restitution * vRel;
+ }
+ }
+
+ // If we have two points, then prepare the block solver.
+ if (vc->pointCount == 2)
+ {
+ b2VelocityConstraintPoint* vcp1 = vc->points + 0;
+ b2VelocityConstraintPoint* vcp2 = vc->points + 1;
+
+ float32 rn1A = b2Cross(vcp1->rA, vc->normal);
+ float32 rn1B = b2Cross(vcp1->rB, vc->normal);
+ float32 rn2A = b2Cross(vcp2->rA, vc->normal);
+ float32 rn2B = b2Cross(vcp2->rB, vc->normal);
+
+ float32 k11 = mA + mB + iA * rn1A * rn1A + iB * rn1B * rn1B;
+ float32 k22 = mA + mB + iA * rn2A * rn2A + iB * rn2B * rn2B;
+ float32 k12 = mA + mB + iA * rn1A * rn2A + iB * rn1B * rn2B;
+
+ // Ensure a reasonable condition number.
+ const float32 k_maxConditionNumber = 1000.0f;
+ if (k11 * k11 < k_maxConditionNumber * (k11 * k22 - k12 * k12))
+ {
+ // K is safe to invert.
+ vc->K.ex.Set(k11, k12);
+ vc->K.ey.Set(k12, k22);
+ vc->normalMass = vc->K.GetInverse();
+ }
+ else
+ {
+ // The constraints are redundant, just use one.
+ // TODO_ERIN use deepest?
+ vc->pointCount = 1;
+ }
+ }
+ }
+}
+
+void b2ContactSolver::WarmStart()
+{
+ // Warm start.
+ for (int32 i = 0; i < m_count; ++i)
+ {
+ b2ContactVelocityConstraint* vc = m_velocityConstraints + i;
+
+ int32 indexA = vc->indexA;
+ int32 indexB = vc->indexB;
+ float32 mA = vc->invMassA;
+ float32 iA = vc->invIA;
+ float32 mB = vc->invMassB;
+ float32 iB = vc->invIB;
+ int32 pointCount = vc->pointCount;
+
+ b2Vec2 vA = m_velocities[indexA].v;
+ float32 wA = m_velocities[indexA].w;
+ b2Vec2 vB = m_velocities[indexB].v;
+ float32 wB = m_velocities[indexB].w;
+
+ b2Vec2 normal = vc->normal;
+ b2Vec2 tangent = b2Cross(normal, 1.0f);
+
+ for (int32 j = 0; j < pointCount; ++j)
+ {
+ b2VelocityConstraintPoint* vcp = vc->points + j;
+ b2Vec2 P = vcp->normalImpulse * normal + vcp->tangentImpulse * tangent;
+ wA -= iA * b2Cross(vcp->rA, P);
+ vA -= mA * P;
+ wB += iB * b2Cross(vcp->rB, P);
+ vB += mB * P;
+ }
+
+ m_velocities[indexA].v = vA;
+ m_velocities[indexA].w = wA;
+ m_velocities[indexB].v = vB;
+ m_velocities[indexB].w = wB;
+ }
+}
+
+void b2ContactSolver::SolveVelocityConstraints()
+{
+ for (int32 i = 0; i < m_count; ++i)
+ {
+ b2ContactVelocityConstraint* vc = m_velocityConstraints + i;
+
+ int32 indexA = vc->indexA;
+ int32 indexB = vc->indexB;
+ float32 mA = vc->invMassA;
+ float32 iA = vc->invIA;
+ float32 mB = vc->invMassB;
+ float32 iB = vc->invIB;
+ int32 pointCount = vc->pointCount;
+
+ b2Vec2 vA = m_velocities[indexA].v;
+ float32 wA = m_velocities[indexA].w;
+ b2Vec2 vB = m_velocities[indexB].v;
+ float32 wB = m_velocities[indexB].w;
+
+ b2Vec2 normal = vc->normal;
+ b2Vec2 tangent = b2Cross(normal, 1.0f);
+ float32 friction = vc->friction;
+
+ b2Assert(pointCount == 1 || pointCount == 2);
+
+ // Solve tangent constraints first because non-penetration is more important
+ // than friction.
+ for (int32 j = 0; j < pointCount; ++j)
+ {
+ b2VelocityConstraintPoint* vcp = vc->points + j;
+
+ // Relative velocity at contact
+ b2Vec2 dv = vB + b2Cross(wB, vcp->rB) - vA - b2Cross(wA, vcp->rA);
+
+ // Compute tangent force
+ float32 vt = b2Dot(dv, tangent);
+ float32 lambda = vcp->tangentMass * (-vt);
+
+ // b2Clamp the accumulated force
+ float32 maxFriction = friction * vcp->normalImpulse;
+ float32 newImpulse = b2Clamp(vcp->tangentImpulse + lambda, -maxFriction, maxFriction);
+ lambda = newImpulse - vcp->tangentImpulse;
+ vcp->tangentImpulse = newImpulse;
+
+ // Apply contact impulse
+ b2Vec2 P = lambda * tangent;
+
+ vA -= mA * P;
+ wA -= iA * b2Cross(vcp->rA, P);
+
+ vB += mB * P;
+ wB += iB * b2Cross(vcp->rB, P);
+ }
+
+ // Solve normal constraints
+ if (vc->pointCount == 1)
+ {
+ b2VelocityConstraintPoint* vcp = vc->points + 0;
+
+ // Relative velocity at contact
+ b2Vec2 dv = vB + b2Cross(wB, vcp->rB) - vA - b2Cross(wA, vcp->rA);
+
+ // Compute normal impulse
+ float32 vn = b2Dot(dv, normal);
+ float32 lambda = -vcp->normalMass * (vn - vcp->velocityBias);
+
+ // b2Clamp the accumulated impulse
+ float32 newImpulse = b2Max(vcp->normalImpulse + lambda, 0.0f);
+ lambda = newImpulse - vcp->normalImpulse;
+ vcp->normalImpulse = newImpulse;
+
+ // Apply contact impulse
+ b2Vec2 P = lambda * normal;
+ vA -= mA * P;
+ wA -= iA * b2Cross(vcp->rA, P);
+
+ vB += mB * P;
+ wB += iB * b2Cross(vcp->rB, P);
+ }
+ else
+ {
+ // Block solver developed in collaboration with Dirk Gregorius (back in 01/07 on Box2D_Lite).
+ // Build the mini LCP for this contact patch
+ //
+ // vn = A * x + b, vn >= 0, , vn >= 0, x >= 0 and vn_i * x_i = 0 with i = 1..2
+ //
+ // A = J * W * JT and J = ( -n, -r1 x n, n, r2 x n )
+ // b = vn0 - velocityBias
+ //
+ // The system is solved using the "Total enumeration method" (s. Murty). The complementary constraint vn_i * x_i
+ // implies that we must have in any solution either vn_i = 0 or x_i = 0. So for the 2D contact problem the cases
+ // vn1 = 0 and vn2 = 0, x1 = 0 and x2 = 0, x1 = 0 and vn2 = 0, x2 = 0 and vn1 = 0 need to be tested. The first valid
+ // solution that satisfies the problem is chosen.
+ //
+ // In order to account of the accumulated impulse 'a' (because of the iterative nature of the solver which only requires
+ // that the accumulated impulse is clamped and not the incremental impulse) we change the impulse variable (x_i).
+ //
+ // Substitute:
+ //
+ // x = a + d
+ //
+ // a := old total impulse
+ // x := new total impulse
+ // d := incremental impulse
+ //
+ // For the current iteration we extend the formula for the incremental impulse
+ // to compute the new total impulse:
+ //
+ // vn = A * d + b
+ // = A * (x - a) + b
+ // = A * x + b - A * a
+ // = A * x + b'
+ // b' = b - A * a;
+
+ b2VelocityConstraintPoint* cp1 = vc->points + 0;
+ b2VelocityConstraintPoint* cp2 = vc->points + 1;
+
+ b2Vec2 a(cp1->normalImpulse, cp2->normalImpulse);
+ b2Assert(a.x >= 0.0f && a.y >= 0.0f);
+
+ // Relative velocity at contact
+ b2Vec2 dv1 = vB + b2Cross(wB, cp1->rB) - vA - b2Cross(wA, cp1->rA);
+ b2Vec2 dv2 = vB + b2Cross(wB, cp2->rB) - vA - b2Cross(wA, cp2->rA);
+
+ // Compute normal velocity
+ float32 vn1 = b2Dot(dv1, normal);
+ float32 vn2 = b2Dot(dv2, normal);
+
+ b2Vec2 b;
+ b.x = vn1 - cp1->velocityBias;
+ b.y = vn2 - cp2->velocityBias;
+
+ // Compute b'
+ b -= b2Mul(vc->K, a);
+
+ const float32 k_errorTol = 1e-3f;
+ B2_NOT_USED(k_errorTol);
+
+ for (;;)
+ {
+ //
+ // Case 1: vn = 0
+ //
+ // 0 = A * x + b'
+ //
+ // Solve for x:
+ //
+ // x = - inv(A) * b'
+ //
+ b2Vec2 x = - b2Mul(vc->normalMass, b);
+
+ if (x.x >= 0.0f && x.y >= 0.0f)
+ {
+ // Get the incremental impulse
+ b2Vec2 d = x - a;
+
+ // Apply incremental impulse
+ b2Vec2 P1 = d.x * normal;
+ b2Vec2 P2 = d.y * normal;
+ vA -= mA * (P1 + P2);
+ wA -= iA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2));
+
+ vB += mB * (P1 + P2);
+ wB += iB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2));
+
+ // Accumulate
+ cp1->normalImpulse = x.x;
+ cp2->normalImpulse = x.y;
+
+#if B2_DEBUG_SOLVER == 1
+ // Postconditions
+ dv1 = vB + b2Cross(wB, cp1->rB) - vA - b2Cross(wA, cp1->rA);
+ dv2 = vB + b2Cross(wB, cp2->rB) - vA - b2Cross(wA, cp2->rA);
+
+ // Compute normal velocity
+ vn1 = b2Dot(dv1, normal);
+ vn2 = b2Dot(dv2, normal);
+
+ b2Assert(b2Abs(vn1 - cp1->velocityBias) < k_errorTol);
+ b2Assert(b2Abs(vn2 - cp2->velocityBias) < k_errorTol);
+#endif
+ break;
+ }
+
+ //
+ // Case 2: vn1 = 0 and x2 = 0
+ //
+ // 0 = a11 * x1 + a12 * 0 + b1'
+ // vn2 = a21 * x1 + a22 * 0 + b2'
+ //
+ x.x = - cp1->normalMass * b.x;
+ x.y = 0.0f;
+ vn1 = 0.0f;
+ vn2 = vc->K.ex.y * x.x + b.y;
+
+ if (x.x >= 0.0f && vn2 >= 0.0f)
+ {
+ // Get the incremental impulse
+ b2Vec2 d = x - a;
+
+ // Apply incremental impulse
+ b2Vec2 P1 = d.x * normal;
+ b2Vec2 P2 = d.y * normal;
+ vA -= mA * (P1 + P2);
+ wA -= iA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2));
+
+ vB += mB * (P1 + P2);
+ wB += iB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2));
+
+ // Accumulate
+ cp1->normalImpulse = x.x;
+ cp2->normalImpulse = x.y;
+
+#if B2_DEBUG_SOLVER == 1
+ // Postconditions
+ dv1 = vB + b2Cross(wB, cp1->rB) - vA - b2Cross(wA, cp1->rA);
+
+ // Compute normal velocity
+ vn1 = b2Dot(dv1, normal);
+
+ b2Assert(b2Abs(vn1 - cp1->velocityBias) < k_errorTol);
+#endif
+ break;
+ }
+
+
+ //
+ // Case 3: vn2 = 0 and x1 = 0
+ //
+ // vn1 = a11 * 0 + a12 * x2 + b1'
+ // 0 = a21 * 0 + a22 * x2 + b2'
+ //
+ x.x = 0.0f;
+ x.y = - cp2->normalMass * b.y;
+ vn1 = vc->K.ey.x * x.y + b.x;
+ vn2 = 0.0f;
+
+ if (x.y >= 0.0f && vn1 >= 0.0f)
+ {
+ // Resubstitute for the incremental impulse
+ b2Vec2 d = x - a;
+
+ // Apply incremental impulse
+ b2Vec2 P1 = d.x * normal;
+ b2Vec2 P2 = d.y * normal;
+ vA -= mA * (P1 + P2);
+ wA -= iA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2));
+
+ vB += mB * (P1 + P2);
+ wB += iB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2));
+
+ // Accumulate
+ cp1->normalImpulse = x.x;
+ cp2->normalImpulse = x.y;
+
+#if B2_DEBUG_SOLVER == 1
+ // Postconditions
+ dv2 = vB + b2Cross(wB, cp2->rB) - vA - b2Cross(wA, cp2->rA);
+
+ // Compute normal velocity
+ vn2 = b2Dot(dv2, normal);
+
+ b2Assert(b2Abs(vn2 - cp2->velocityBias) < k_errorTol);
+#endif
+ break;
+ }
+
+ //
+ // Case 4: x1 = 0 and x2 = 0
+ //
+ // vn1 = b1
+ // vn2 = b2;
+ x.x = 0.0f;
+ x.y = 0.0f;
+ vn1 = b.x;
+ vn2 = b.y;
+
+ if (vn1 >= 0.0f && vn2 >= 0.0f )
+ {
+ // Resubstitute for the incremental impulse
+ b2Vec2 d = x - a;
+
+ // Apply incremental impulse
+ b2Vec2 P1 = d.x * normal;
+ b2Vec2 P2 = d.y * normal;
+ vA -= mA * (P1 + P2);
+ wA -= iA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2));
+
+ vB += mB * (P1 + P2);
+ wB += iB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2));
+
+ // Accumulate
+ cp1->normalImpulse = x.x;
+ cp2->normalImpulse = x.y;
+
+ break;
+ }
+
+ // No solution, give up. This is hit sometimes, but it doesn't seem to matter.
+ break;
+ }
+ }
+
+ m_velocities[indexA].v = vA;
+ m_velocities[indexA].w = wA;
+ m_velocities[indexB].v = vB;
+ m_velocities[indexB].w = wB;
+ }
+}
+
+void b2ContactSolver::StoreImpulses()
+{
+ for (int32 i = 0; i < m_count; ++i)
+ {
+ b2ContactVelocityConstraint* vc = m_velocityConstraints + i;
+ b2Manifold* manifold = m_contacts[vc->contactIndex]->GetManifold();
+
+ for (int32 j = 0; j < vc->pointCount; ++j)
+ {
+ manifold->points[j].normalImpulse = vc->points[j].normalImpulse;
+ manifold->points[j].tangentImpulse = vc->points[j].tangentImpulse;
+ }
+ }
+}
+
+struct b2PositionSolverManifold
+{
+ void Initialize(b2ContactPositionConstraint* pc, const b2Transform& xfA, const b2Transform& xfB, int32 index)
+ {
+ b2Assert(pc->pointCount > 0);
+
+ switch (pc->type)
+ {
+ case b2Manifold::e_circles:
+ {
+ b2Vec2 pointA = b2Mul(xfA, pc->localPoint);
+ b2Vec2 pointB = b2Mul(xfB, pc->localPoints[0]);
+ normal = pointB - pointA;
+ normal.Normalize();
+ point = 0.5f * (pointA + pointB);
+ separation = b2Dot(pointB - pointA, normal) - pc->radiusA - pc->radiusB;
+ }
+ break;
+
+ case b2Manifold::e_faceA:
+ {
+ normal = b2Mul(xfA.q, pc->localNormal);
+ b2Vec2 planePoint = b2Mul(xfA, pc->localPoint);
+
+ b2Vec2 clipPoint = b2Mul(xfB, pc->localPoints[index]);
+ separation = b2Dot(clipPoint - planePoint, normal) - pc->radiusA - pc->radiusB;
+ point = clipPoint;
+ }
+ break;
+
+ case b2Manifold::e_faceB:
+ {
+ normal = b2Mul(xfB.q, pc->localNormal);
+ b2Vec2 planePoint = b2Mul(xfB, pc->localPoint);
+
+ b2Vec2 clipPoint = b2Mul(xfA, pc->localPoints[index]);
+ separation = b2Dot(clipPoint - planePoint, normal) - pc->radiusA - pc->radiusB;
+ point = clipPoint;
+
+ // Ensure normal points from A to B
+ normal = -normal;
+ }
+ break;
+ }
+ }
+
+ b2Vec2 normal;
+ b2Vec2 point;
+ float32 separation;
+};
+
+// Sequential solver.
+bool b2ContactSolver::SolvePositionConstraints()
+{
+ float32 minSeparation = 0.0f;
+
+ for (int32 i = 0; i < m_count; ++i)
+ {
+ b2ContactPositionConstraint* pc = m_positionConstraints + i;
+
+ int32 indexA = pc->indexA;
+ int32 indexB = pc->indexB;
+ b2Vec2 localCenterA = pc->localCenterA;
+ float32 mA = pc->invMassA;
+ float32 iA = pc->invIA;
+ b2Vec2 localCenterB = pc->localCenterB;
+ float32 mB = pc->invMassB;
+ float32 iB = pc->invIB;
+ int32 pointCount = pc->pointCount;
+
+ b2Vec2 cA = m_positions[indexA].c;
+ float32 aA = m_positions[indexA].a;
+
+ b2Vec2 cB = m_positions[indexB].c;
+ float32 aB = m_positions[indexB].a;
+
+ // Solve normal constraints
+ for (int32 j = 0; j < pointCount; ++j)
+ {
+ b2Transform xfA, xfB;
+ xfA.q.Set(aA);
+ xfB.q.Set(aB);
+ xfA.p = cA - b2Mul(xfA.q, localCenterA);
+ xfB.p = cB - b2Mul(xfB.q, localCenterB);
+
+ b2PositionSolverManifold psm;
+ psm.Initialize(pc, xfA, xfB, j);
+ b2Vec2 normal = psm.normal;
+
+ b2Vec2 point = psm.point;
+ float32 separation = psm.separation;
+
+ b2Vec2 rA = point - cA;
+ b2Vec2 rB = point - cB;
+
+ // Track max constraint error.
+ minSeparation = b2Min(minSeparation, separation);
+
+ // Prevent large corrections and allow slop.
+ float32 C = b2Clamp(b2_baumgarte * (separation + b2_linearSlop), -b2_maxLinearCorrection, 0.0f);
+
+ // Compute the effective mass.
+ float32 rnA = b2Cross(rA, normal);
+ float32 rnB = b2Cross(rB, normal);
+ float32 K = mA + mB + iA * rnA * rnA + iB * rnB * rnB;
+
+ // Compute normal impulse
+ float32 impulse = K > 0.0f ? - C / K : 0.0f;
+
+ b2Vec2 P = impulse * normal;
+
+ cA -= mA * P;
+ aA -= iA * b2Cross(rA, P);
+
+ cB += mB * P;
+ aB += iB * b2Cross(rB, P);
+ }
+
+ m_positions[indexA].c = cA;
+ m_positions[indexA].a = aA;
+
+ m_positions[indexB].c = cB;
+ m_positions[indexB].a = aB;
+ }
+
+ // We can't expect minSpeparation >= -b2_linearSlop because we don't
+ // push the separation above -b2_linearSlop.
+ return minSeparation >= -3.0f * b2_linearSlop;
+}
+
+// Sequential position solver for position constraints.
+bool b2ContactSolver::SolveTOIPositionConstraints(int32 toiIndexA, int32 toiIndexB)
+{
+ float32 minSeparation = 0.0f;
+
+ for (int32 i = 0; i < m_count; ++i)
+ {
+ b2ContactPositionConstraint* pc = m_positionConstraints + i;
+
+ int32 indexA = pc->indexA;
+ int32 indexB = pc->indexB;
+ b2Vec2 localCenterA = pc->localCenterA;
+ b2Vec2 localCenterB = pc->localCenterB;
+ int32 pointCount = pc->pointCount;
+
+ float32 mA = 0.0f;
+ float32 iA = 0.0f;
+ if (indexA == toiIndexA || indexA == toiIndexB)
+ {
+ mA = pc->invMassA;
+ iA = pc->invIA;
+ }
+
+ float32 mB = pc->invMassB;
+ float32 iB = pc->invIB;
+ if (indexB == toiIndexA || indexB == toiIndexB)
+ {
+ mB = pc->invMassB;
+ iB = pc->invIB;
+ }
+
+ b2Vec2 cA = m_positions[indexA].c;
+ float32 aA = m_positions[indexA].a;
+
+ b2Vec2 cB = m_positions[indexB].c;
+ float32 aB = m_positions[indexB].a;
+
+ // Solve normal constraints
+ for (int32 j = 0; j < pointCount; ++j)
+ {
+ b2Transform xfA, xfB;
+ xfA.q.Set(aA);
+ xfB.q.Set(aB);
+ xfA.p = cA - b2Mul(xfA.q, localCenterA);
+ xfB.p = cB - b2Mul(xfB.q, localCenterB);
+
+ b2PositionSolverManifold psm;
+ psm.Initialize(pc, xfA, xfB, j);
+ b2Vec2 normal = psm.normal;
+
+ b2Vec2 point = psm.point;
+ float32 separation = psm.separation;
+
+ b2Vec2 rA = point - cA;
+ b2Vec2 rB = point - cB;
+
+ // Track max constraint error.
+ minSeparation = b2Min(minSeparation, separation);
+
+ // Prevent large corrections and allow slop.
+ float32 C = b2Clamp(b2_toiBaugarte * (separation + b2_linearSlop), -b2_maxLinearCorrection, 0.0f);
+
+ // Compute the effective mass.
+ float32 rnA = b2Cross(rA, normal);
+ float32 rnB = b2Cross(rB, normal);
+ float32 K = mA + mB + iA * rnA * rnA + iB * rnB * rnB;
+
+ // Compute normal impulse
+ float32 impulse = K > 0.0f ? - C / K : 0.0f;
+
+ b2Vec2 P = impulse * normal;
+
+ cA -= mA * P;
+ aA -= iA * b2Cross(rA, P);
+
+ cB += mB * P;
+ aB += iB * b2Cross(rB, P);
+ }
+
+ m_positions[indexA].c = cA;
+ m_positions[indexA].a = aA;
+
+ m_positions[indexB].c = cB;
+ m_positions[indexB].a = aB;
+ }
+
+ // We can't expect minSpeparation >= -b2_linearSlop because we don't
+ // push the separation above -b2_linearSlop.
+ return minSeparation >= -1.5f * b2_linearSlop;
+}
diff --git a/tests/box2d/Box2D/Dynamics/Contacts/b2ContactSolver.h b/tests/box2d/Box2D/Dynamics/Contacts/b2ContactSolver.h new file mode 100755 index 00000000..ca9de04d --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Contacts/b2ContactSolver.h @@ -0,0 +1,94 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_CONTACT_SOLVER_H
+#define B2_CONTACT_SOLVER_H
+
+#include <Box2D/Common/b2Math.h>
+#include <Box2D/Collision/b2Collision.h>
+#include <Box2D/Dynamics/b2TimeStep.h>
+
+class b2Contact;
+class b2Body;
+class b2StackAllocator;
+struct b2ContactPositionConstraint;
+
+struct b2VelocityConstraintPoint
+{
+ b2Vec2 rA;
+ b2Vec2 rB;
+ float32 normalImpulse;
+ float32 tangentImpulse;
+ float32 normalMass;
+ float32 tangentMass;
+ float32 velocityBias;
+};
+
+struct b2ContactVelocityConstraint
+{
+ b2VelocityConstraintPoint points[b2_maxManifoldPoints];
+ b2Vec2 normal;
+ b2Mat22 normalMass;
+ b2Mat22 K;
+ int32 indexA;
+ int32 indexB;
+ float32 invMassA, invMassB;
+ float32 invIA, invIB;
+ float32 friction;
+ float32 restitution;
+ int32 pointCount;
+ int32 contactIndex;
+};
+
+struct b2ContactSolverDef
+{
+ b2TimeStep step;
+ b2Contact** contacts;
+ int32 count;
+ b2Position* positions;
+ b2Velocity* velocities;
+ b2StackAllocator* allocator;
+};
+
+class b2ContactSolver
+{
+public:
+ b2ContactSolver(b2ContactSolverDef* def);
+ ~b2ContactSolver();
+
+ void InitializeVelocityConstraints();
+
+ void WarmStart();
+ void SolveVelocityConstraints();
+ void StoreImpulses();
+
+ bool SolvePositionConstraints();
+ bool SolveTOIPositionConstraints(int32 toiIndexA, int32 toiIndexB);
+
+ b2TimeStep m_step;
+ b2Position* m_positions;
+ b2Velocity* m_velocities;
+ b2StackAllocator* m_allocator;
+ b2ContactPositionConstraint* m_positionConstraints;
+ b2ContactVelocityConstraint* m_velocityConstraints;
+ b2Contact** m_contacts;
+ int m_count;
+};
+
+#endif
+
diff --git a/tests/box2d/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.cpp b/tests/box2d/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.cpp new file mode 100755 index 00000000..04336507 --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.cpp @@ -0,0 +1,50 @@ +/*
+* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h>
+#include <Box2D/Common/b2BlockAllocator.h>
+#include <Box2D/Dynamics/b2Fixture.h>
+
+#include <new>
+using namespace std;
+
+b2Contact* b2EdgeAndCircleContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator)
+{
+ void* mem = allocator->Allocate(sizeof(b2EdgeAndCircleContact));
+ return new (mem) b2EdgeAndCircleContact(fixtureA, fixtureB);
+}
+
+void b2EdgeAndCircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)
+{
+ ((b2EdgeAndCircleContact*)contact)->~b2EdgeAndCircleContact();
+ allocator->Free(contact, sizeof(b2EdgeAndCircleContact));
+}
+
+b2EdgeAndCircleContact::b2EdgeAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB)
+: b2Contact(fixtureA, 0, fixtureB, 0)
+{
+ b2Assert(m_fixtureA->GetType() == b2Shape::e_edge);
+ b2Assert(m_fixtureB->GetType() == b2Shape::e_circle);
+}
+
+void b2EdgeAndCircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB)
+{
+ b2CollideEdgeAndCircle( manifold,
+ (b2EdgeShape*)m_fixtureA->GetShape(), xfA,
+ (b2CircleShape*)m_fixtureB->GetShape(), xfB);
+}
diff --git a/tests/box2d/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h b/tests/box2d/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h new file mode 100755 index 00000000..11b61b88 --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h @@ -0,0 +1,39 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_EDGE_AND_CIRCLE_CONTACT_H
+#define B2_EDGE_AND_CIRCLE_CONTACT_H
+
+#include <Box2D/Dynamics/Contacts/b2Contact.h>
+
+class b2BlockAllocator;
+
+class b2EdgeAndCircleContact : public b2Contact
+{
+public:
+ static b2Contact* Create( b2Fixture* fixtureA, int32 indexA,
+ b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator);
+ static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);
+
+ b2EdgeAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB);
+ ~b2EdgeAndCircleContact() {}
+
+ void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB);
+};
+
+#endif
diff --git a/tests/box2d/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.cpp b/tests/box2d/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.cpp new file mode 100755 index 00000000..8bac536a --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.cpp @@ -0,0 +1,50 @@ +/*
+* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.h>
+#include <Box2D/Common/b2BlockAllocator.h>
+#include <Box2D/Dynamics/b2Fixture.h>
+
+#include <new>
+using namespace std;
+
+b2Contact* b2EdgeAndPolygonContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator)
+{
+ void* mem = allocator->Allocate(sizeof(b2EdgeAndPolygonContact));
+ return new (mem) b2EdgeAndPolygonContact(fixtureA, fixtureB);
+}
+
+void b2EdgeAndPolygonContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)
+{
+ ((b2EdgeAndPolygonContact*)contact)->~b2EdgeAndPolygonContact();
+ allocator->Free(contact, sizeof(b2EdgeAndPolygonContact));
+}
+
+b2EdgeAndPolygonContact::b2EdgeAndPolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB)
+: b2Contact(fixtureA, 0, fixtureB, 0)
+{
+ b2Assert(m_fixtureA->GetType() == b2Shape::e_edge);
+ b2Assert(m_fixtureB->GetType() == b2Shape::e_polygon);
+}
+
+void b2EdgeAndPolygonContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB)
+{
+ b2CollideEdgeAndPolygon( manifold,
+ (b2EdgeShape*)m_fixtureA->GetShape(), xfA,
+ (b2PolygonShape*)m_fixtureB->GetShape(), xfB);
+}
diff --git a/tests/box2d/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.h b/tests/box2d/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.h new file mode 100755 index 00000000..74b27ee0 --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.h @@ -0,0 +1,39 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_EDGE_AND_POLYGON_CONTACT_H
+#define B2_EDGE_AND_POLYGON_CONTACT_H
+
+#include <Box2D/Dynamics/Contacts/b2Contact.h>
+
+class b2BlockAllocator;
+
+class b2EdgeAndPolygonContact : public b2Contact
+{
+public:
+ static b2Contact* Create( b2Fixture* fixtureA, int32 indexA,
+ b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator);
+ static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);
+
+ b2EdgeAndPolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB);
+ ~b2EdgeAndPolygonContact() {}
+
+ void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB);
+};
+
+#endif
diff --git a/tests/box2d/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.cpp b/tests/box2d/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.cpp new file mode 100755 index 00000000..880f83e2 --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.cpp @@ -0,0 +1,50 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.h>
+#include <Box2D/Common/b2BlockAllocator.h>
+#include <Box2D/Dynamics/b2Fixture.h>
+
+#include <new>
+using namespace std;
+
+b2Contact* b2PolygonAndCircleContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator)
+{
+ void* mem = allocator->Allocate(sizeof(b2PolygonAndCircleContact));
+ return new (mem) b2PolygonAndCircleContact(fixtureA, fixtureB);
+}
+
+void b2PolygonAndCircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)
+{
+ ((b2PolygonAndCircleContact*)contact)->~b2PolygonAndCircleContact();
+ allocator->Free(contact, sizeof(b2PolygonAndCircleContact));
+}
+
+b2PolygonAndCircleContact::b2PolygonAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB)
+: b2Contact(fixtureA, 0, fixtureB, 0)
+{
+ b2Assert(m_fixtureA->GetType() == b2Shape::e_polygon);
+ b2Assert(m_fixtureB->GetType() == b2Shape::e_circle);
+}
+
+void b2PolygonAndCircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB)
+{
+ b2CollidePolygonAndCircle( manifold,
+ (b2PolygonShape*)m_fixtureA->GetShape(), xfA,
+ (b2CircleShape*)m_fixtureB->GetShape(), xfB);
+}
diff --git a/tests/box2d/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.h b/tests/box2d/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.h new file mode 100755 index 00000000..6beca16a --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.h @@ -0,0 +1,38 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_POLYGON_AND_CIRCLE_CONTACT_H
+#define B2_POLYGON_AND_CIRCLE_CONTACT_H
+
+#include <Box2D/Dynamics/Contacts/b2Contact.h>
+
+class b2BlockAllocator;
+
+class b2PolygonAndCircleContact : public b2Contact
+{
+public:
+ static b2Contact* Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator);
+ static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);
+
+ b2PolygonAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB);
+ ~b2PolygonAndCircleContact() {}
+
+ void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB);
+};
+
+#endif
diff --git a/tests/box2d/Box2D/Dynamics/Contacts/b2PolygonContact.cpp b/tests/box2d/Box2D/Dynamics/Contacts/b2PolygonContact.cpp new file mode 100755 index 00000000..52e1be87 --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Contacts/b2PolygonContact.cpp @@ -0,0 +1,53 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Dynamics/Contacts/b2PolygonContact.h>
+#include <Box2D/Common/b2BlockAllocator.h>
+#include <Box2D/Collision/b2TimeOfImpact.h>
+#include <Box2D/Dynamics/b2Body.h>
+#include <Box2D/Dynamics/b2Fixture.h>
+#include <Box2D/Dynamics/b2WorldCallbacks.h>
+
+#include <new>
+using namespace std;
+
+b2Contact* b2PolygonContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator)
+{
+ void* mem = allocator->Allocate(sizeof(b2PolygonContact));
+ return new (mem) b2PolygonContact(fixtureA, fixtureB);
+}
+
+void b2PolygonContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)
+{
+ ((b2PolygonContact*)contact)->~b2PolygonContact();
+ allocator->Free(contact, sizeof(b2PolygonContact));
+}
+
+b2PolygonContact::b2PolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB)
+ : b2Contact(fixtureA, 0, fixtureB, 0)
+{
+ b2Assert(m_fixtureA->GetType() == b2Shape::e_polygon);
+ b2Assert(m_fixtureB->GetType() == b2Shape::e_polygon);
+}
+
+void b2PolygonContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB)
+{
+ b2CollidePolygons( manifold,
+ (b2PolygonShape*)m_fixtureA->GetShape(), xfA,
+ (b2PolygonShape*)m_fixtureB->GetShape(), xfB);
+}
diff --git a/tests/box2d/Box2D/Dynamics/Contacts/b2PolygonContact.h b/tests/box2d/Box2D/Dynamics/Contacts/b2PolygonContact.h new file mode 100755 index 00000000..45932148 --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Contacts/b2PolygonContact.h @@ -0,0 +1,39 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_POLYGON_CONTACT_H
+#define B2_POLYGON_CONTACT_H
+
+#include <Box2D/Dynamics/Contacts/b2Contact.h>
+
+class b2BlockAllocator;
+
+class b2PolygonContact : public b2Contact
+{
+public:
+ static b2Contact* Create( b2Fixture* fixtureA, int32 indexA,
+ b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator);
+ static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);
+
+ b2PolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB);
+ ~b2PolygonContact() {}
+
+ void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB);
+};
+
+#endif
diff --git a/tests/box2d/Box2D/Dynamics/Joints/b2DistanceJoint.cpp b/tests/box2d/Box2D/Dynamics/Joints/b2DistanceJoint.cpp new file mode 100755 index 00000000..1ced7d9d --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Joints/b2DistanceJoint.cpp @@ -0,0 +1,260 @@ +/*
+* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Dynamics/Joints/b2DistanceJoint.h>
+#include <Box2D/Dynamics/b2Body.h>
+#include <Box2D/Dynamics/b2TimeStep.h>
+
+// 1-D constrained system
+// m (v2 - v1) = lambda
+// v2 + (beta/h) * x1 + gamma * lambda = 0, gamma has units of inverse mass.
+// x2 = x1 + h * v2
+
+// 1-D mass-damper-spring system
+// m (v2 - v1) + h * d * v2 + h * k *
+
+// C = norm(p2 - p1) - L
+// u = (p2 - p1) / norm(p2 - p1)
+// Cdot = dot(u, v2 + cross(w2, r2) - v1 - cross(w1, r1))
+// J = [-u -cross(r1, u) u cross(r2, u)]
+// K = J * invM * JT
+// = invMass1 + invI1 * cross(r1, u)^2 + invMass2 + invI2 * cross(r2, u)^2
+
+void b2DistanceJointDef::Initialize(b2Body* b1, b2Body* b2,
+ const b2Vec2& anchor1, const b2Vec2& anchor2)
+{
+ bodyA = b1;
+ bodyB = b2;
+ localAnchorA = bodyA->GetLocalPoint(anchor1);
+ localAnchorB = bodyB->GetLocalPoint(anchor2);
+ b2Vec2 d = anchor2 - anchor1;
+ length = d.Length();
+}
+
+b2DistanceJoint::b2DistanceJoint(const b2DistanceJointDef* def)
+: b2Joint(def)
+{
+ m_localAnchorA = def->localAnchorA;
+ m_localAnchorB = def->localAnchorB;
+ m_length = def->length;
+ m_frequencyHz = def->frequencyHz;
+ m_dampingRatio = def->dampingRatio;
+ m_impulse = 0.0f;
+ m_gamma = 0.0f;
+ m_bias = 0.0f;
+}
+
+void b2DistanceJoint::InitVelocityConstraints(const b2SolverData& data)
+{
+ m_indexA = m_bodyA->m_islandIndex;
+ m_indexB = m_bodyB->m_islandIndex;
+ m_localCenterA = m_bodyA->m_sweep.localCenter;
+ m_localCenterB = m_bodyB->m_sweep.localCenter;
+ m_invMassA = m_bodyA->m_invMass;
+ m_invMassB = m_bodyB->m_invMass;
+ m_invIA = m_bodyA->m_invI;
+ m_invIB = m_bodyB->m_invI;
+
+ b2Vec2 cA = data.positions[m_indexA].c;
+ float32 aA = data.positions[m_indexA].a;
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+
+ b2Vec2 cB = data.positions[m_indexB].c;
+ float32 aB = data.positions[m_indexB].a;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ b2Rot qA(aA), qB(aB);
+
+ m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
+ m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
+ m_u = cB + m_rB - cA - m_rA;
+
+ // Handle singularity.
+ float32 length = m_u.Length();
+ if (length > b2_linearSlop)
+ {
+ m_u *= 1.0f / length;
+ }
+ else
+ {
+ m_u.Set(0.0f, 0.0f);
+ }
+
+ float32 crAu = b2Cross(m_rA, m_u);
+ float32 crBu = b2Cross(m_rB, m_u);
+ float32 invMass = m_invMassA + m_invIA * crAu * crAu + m_invMassB + m_invIB * crBu * crBu;
+
+ // Compute the effective mass matrix.
+ m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f;
+
+ if (m_frequencyHz > 0.0f)
+ {
+ float32 C = length - m_length;
+
+ // Frequency
+ float32 omega = 2.0f * b2_pi * m_frequencyHz;
+
+ // Damping coefficient
+ float32 d = 2.0f * m_mass * m_dampingRatio * omega;
+
+ // Spring stiffness
+ float32 k = m_mass * omega * omega;
+
+ // magic formulas
+ float32 h = data.step.dt;
+ m_gamma = h * (d + h * k);
+ m_gamma = m_gamma != 0.0f ? 1.0f / m_gamma : 0.0f;
+ m_bias = C * h * k * m_gamma;
+
+ invMass += m_gamma;
+ m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f;
+ }
+ else
+ {
+ m_gamma = 0.0f;
+ m_bias = 0.0f;
+ }
+
+ if (data.step.warmStarting)
+ {
+ // Scale the impulse to support a variable time step.
+ m_impulse *= data.step.dtRatio;
+
+ b2Vec2 P = m_impulse * m_u;
+ vA -= m_invMassA * P;
+ wA -= m_invIA * b2Cross(m_rA, P);
+ vB += m_invMassB * P;
+ wB += m_invIB * b2Cross(m_rB, P);
+ }
+ else
+ {
+ m_impulse = 0.0f;
+ }
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+void b2DistanceJoint::SolveVelocityConstraints(const b2SolverData& data)
+{
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ // Cdot = dot(u, v + cross(w, r))
+ b2Vec2 vpA = vA + b2Cross(wA, m_rA);
+ b2Vec2 vpB = vB + b2Cross(wB, m_rB);
+ float32 Cdot = b2Dot(m_u, vpB - vpA);
+
+ float32 impulse = -m_mass * (Cdot + m_bias + m_gamma * m_impulse);
+ m_impulse += impulse;
+
+ b2Vec2 P = impulse * m_u;
+ vA -= m_invMassA * P;
+ wA -= m_invIA * b2Cross(m_rA, P);
+ vB += m_invMassB * P;
+ wB += m_invIB * b2Cross(m_rB, P);
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+bool b2DistanceJoint::SolvePositionConstraints(const b2SolverData& data)
+{
+ if (m_frequencyHz > 0.0f)
+ {
+ // There is no position correction for soft distance constraints.
+ return true;
+ }
+
+ b2Vec2 cA = data.positions[m_indexA].c;
+ float32 aA = data.positions[m_indexA].a;
+ b2Vec2 cB = data.positions[m_indexB].c;
+ float32 aB = data.positions[m_indexB].a;
+
+ b2Rot qA(aA), qB(aB);
+
+ b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
+ b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
+ b2Vec2 u = cB + rB - cA - rA;
+
+ float32 length = u.Normalize();
+ float32 C = length - m_length;
+ C = b2Clamp(C, -b2_maxLinearCorrection, b2_maxLinearCorrection);
+
+ float32 impulse = -m_mass * C;
+ b2Vec2 P = impulse * u;
+
+ cA -= m_invMassA * P;
+ aA -= m_invIA * b2Cross(rA, P);
+ cB += m_invMassB * P;
+ aB += m_invIB * b2Cross(rB, P);
+
+ data.positions[m_indexA].c = cA;
+ data.positions[m_indexA].a = aA;
+ data.positions[m_indexB].c = cB;
+ data.positions[m_indexB].a = aB;
+
+ return b2Abs(C) < b2_linearSlop;
+}
+
+b2Vec2 b2DistanceJoint::GetAnchorA() const
+{
+ return m_bodyA->GetWorldPoint(m_localAnchorA);
+}
+
+b2Vec2 b2DistanceJoint::GetAnchorB() const
+{
+ return m_bodyB->GetWorldPoint(m_localAnchorB);
+}
+
+b2Vec2 b2DistanceJoint::GetReactionForce(float32 inv_dt) const
+{
+ b2Vec2 F = (inv_dt * m_impulse) * m_u;
+ return F;
+}
+
+float32 b2DistanceJoint::GetReactionTorque(float32 inv_dt) const
+{
+ B2_NOT_USED(inv_dt);
+ return 0.0f;
+}
+
+void b2DistanceJoint::Dump()
+{
+ int32 indexA = m_bodyA->m_islandIndex;
+ int32 indexB = m_bodyB->m_islandIndex;
+
+ b2Log(" b2DistanceJointDef jd;\n");
+ b2Log(" jd.bodyA = bodies[%d];\n", indexA);
+ b2Log(" jd.bodyB = bodies[%d];\n", indexB);
+ b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
+ b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y);
+ b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y);
+ b2Log(" jd.length = %.15lef;\n", m_length);
+ b2Log(" jd.frequencyHz = %.15lef;\n", m_frequencyHz);
+ b2Log(" jd.dampingRatio = %.15lef;\n", m_dampingRatio);
+ b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
+}
diff --git a/tests/box2d/Box2D/Dynamics/Joints/b2DistanceJoint.h b/tests/box2d/Box2D/Dynamics/Joints/b2DistanceJoint.h new file mode 100755 index 00000000..63eadd93 --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Joints/b2DistanceJoint.h @@ -0,0 +1,180 @@ +/*
+* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_DISTANCE_JOINT_H
+#define B2_DISTANCE_JOINT_H
+
+#include <Box2D/Dynamics/Joints/b2Joint.h>
+
+/// Distance joint definition. This requires defining an
+/// anchor point on both bodies and the non-zero length of the
+/// distance joint. The definition uses local anchor points
+/// so that the initial configuration can violate the constraint
+/// slightly. This helps when saving and loading a game.
+/// @warning Do not use a zero or short length.
+// emscripten - b2DistanceJointDef: add functions to set/get base class members
+struct b2DistanceJointDef : public b2JointDef
+{
+ b2DistanceJointDef()
+ {
+ type = e_distanceJoint;
+ localAnchorA.Set(0.0f, 0.0f);
+ localAnchorB.Set(0.0f, 0.0f);
+ length = 1.0f;
+ frequencyHz = 0.0f;
+ dampingRatio = 0.0f;
+ }
+
+ /// Initialize the bodies, anchors, and length using the world
+ /// anchors.
+ void Initialize(b2Body* bodyA, b2Body* bodyB,
+ const b2Vec2& anchorA, const b2Vec2& anchorB);
+
+ /// The local anchor point relative to bodyA's origin.
+ b2Vec2 localAnchorA;
+
+ /// The local anchor point relative to bodyB's origin.
+ b2Vec2 localAnchorB;
+
+ /// The natural length between the anchor points.
+ float32 length;
+
+ /// The mass-spring-damper frequency in Hertz. A value of 0
+ /// disables softness.
+ float32 frequencyHz;
+
+ /// The damping ratio. 0 = no damping, 1 = critical damping.
+ float32 dampingRatio;
+
+ // to generate javascript bindings
+ void set_bodyA(b2Body* b) { bodyA = b; }
+ void set_bodyB(b2Body* b) { bodyB = b; }
+ void set_collideConnected(bool b) { collideConnected = b; }
+ b2Body* get_bodyA(b2Body* b) { return bodyA; }
+ b2Body* get_bodyB(b2Body* b) { return bodyB; }
+ bool get_collideConnected(bool b) { return collideConnected; }
+};
+
+/// A distance joint constrains two points on two bodies
+/// to remain at a fixed distance from each other. You can view
+/// this as a massless, rigid rod.
+// emscripten - b2DistanceJoint: make constructor public
+class b2DistanceJoint : public b2Joint
+{
+public:
+
+ b2Vec2 GetAnchorA() const;
+ b2Vec2 GetAnchorB() const;
+
+ /// Get the reaction force given the inverse time step.
+ /// Unit is N.
+ b2Vec2 GetReactionForce(float32 inv_dt) const;
+
+ /// Get the reaction torque given the inverse time step.
+ /// Unit is N*m. This is always zero for a distance joint.
+ float32 GetReactionTorque(float32 inv_dt) const;
+
+ /// The local anchor point relative to bodyA's origin.
+ const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; }
+
+ /// The local anchor point relative to bodyB's origin.
+ const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; }
+
+ /// Set/get the natural length.
+ /// Manipulating the length can lead to non-physical behavior when the frequency is zero.
+ void SetLength(float32 length);
+ float32 GetLength() const;
+
+ /// Set/get frequency in Hz.
+ void SetFrequency(float32 hz);
+ float32 GetFrequency() const;
+
+ /// Set/get damping ratio.
+ void SetDampingRatio(float32 ratio);
+ float32 GetDampingRatio() const;
+
+ /// Dump joint to dmLog
+ void Dump();
+
+ b2DistanceJoint(const b2DistanceJointDef* data);
+
+protected:
+
+ friend class b2Joint;
+
+ void InitVelocityConstraints(const b2SolverData& data);
+ void SolveVelocityConstraints(const b2SolverData& data);
+ bool SolvePositionConstraints(const b2SolverData& data);
+
+ float32 m_frequencyHz;
+ float32 m_dampingRatio;
+ float32 m_bias;
+
+ // Solver shared
+ b2Vec2 m_localAnchorA;
+ b2Vec2 m_localAnchorB;
+ float32 m_gamma;
+ float32 m_impulse;
+ float32 m_length;
+
+ // Solver temp
+ int32 m_indexA;
+ int32 m_indexB;
+ b2Vec2 m_u;
+ b2Vec2 m_rA;
+ b2Vec2 m_rB;
+ b2Vec2 m_localCenterA;
+ b2Vec2 m_localCenterB;
+ float32 m_invMassA;
+ float32 m_invMassB;
+ float32 m_invIA;
+ float32 m_invIB;
+ float32 m_mass;
+};
+
+inline void b2DistanceJoint::SetLength(float32 length)
+{
+ m_length = length;
+}
+
+inline float32 b2DistanceJoint::GetLength() const
+{
+ return m_length;
+}
+
+inline void b2DistanceJoint::SetFrequency(float32 hz)
+{
+ m_frequencyHz = hz;
+}
+
+inline float32 b2DistanceJoint::GetFrequency() const
+{
+ return m_frequencyHz;
+}
+
+inline void b2DistanceJoint::SetDampingRatio(float32 ratio)
+{
+ m_dampingRatio = ratio;
+}
+
+inline float32 b2DistanceJoint::GetDampingRatio() const
+{
+ return m_dampingRatio;
+}
+
+#endif
diff --git a/tests/box2d/Box2D/Dynamics/Joints/b2FrictionJoint.cpp b/tests/box2d/Box2D/Dynamics/Joints/b2FrictionJoint.cpp new file mode 100755 index 00000000..075e72bb --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Joints/b2FrictionJoint.cpp @@ -0,0 +1,251 @@ +/*
+* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Dynamics/Joints/b2FrictionJoint.h>
+#include <Box2D/Dynamics/b2Body.h>
+#include <Box2D/Dynamics/b2TimeStep.h>
+
+// Point-to-point constraint
+// Cdot = v2 - v1
+// = v2 + cross(w2, r2) - v1 - cross(w1, r1)
+// J = [-I -r1_skew I r2_skew ]
+// Identity used:
+// w k % (rx i + ry j) = w * (-ry i + rx j)
+
+// Angle constraint
+// Cdot = w2 - w1
+// J = [0 0 -1 0 0 1]
+// K = invI1 + invI2
+
+void b2FrictionJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor)
+{
+ bodyA = bA;
+ bodyB = bB;
+ localAnchorA = bodyA->GetLocalPoint(anchor);
+ localAnchorB = bodyB->GetLocalPoint(anchor);
+}
+
+b2FrictionJoint::b2FrictionJoint(const b2FrictionJointDef* def)
+: b2Joint(def)
+{
+ m_localAnchorA = def->localAnchorA;
+ m_localAnchorB = def->localAnchorB;
+
+ m_linearImpulse.SetZero();
+ m_angularImpulse = 0.0f;
+
+ m_maxForce = def->maxForce;
+ m_maxTorque = def->maxTorque;
+}
+
+void b2FrictionJoint::InitVelocityConstraints(const b2SolverData& data)
+{
+ m_indexA = m_bodyA->m_islandIndex;
+ m_indexB = m_bodyB->m_islandIndex;
+ m_localCenterA = m_bodyA->m_sweep.localCenter;
+ m_localCenterB = m_bodyB->m_sweep.localCenter;
+ m_invMassA = m_bodyA->m_invMass;
+ m_invMassB = m_bodyB->m_invMass;
+ m_invIA = m_bodyA->m_invI;
+ m_invIB = m_bodyB->m_invI;
+
+ float32 aA = data.positions[m_indexA].a;
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+
+ float32 aB = data.positions[m_indexB].a;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ b2Rot qA(aA), qB(aB);
+
+ // Compute the effective mass matrix.
+ m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
+ m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
+
+ // J = [-I -r1_skew I r2_skew]
+ // [ 0 -1 0 1]
+ // r_skew = [-ry; rx]
+
+ // Matlab
+ // K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB]
+ // [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB]
+ // [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB]
+
+ float32 mA = m_invMassA, mB = m_invMassB;
+ float32 iA = m_invIA, iB = m_invIB;
+
+ b2Mat22 K;
+ K.ex.x = mA + mB + iA * m_rA.y * m_rA.y + iB * m_rB.y * m_rB.y;
+ K.ex.y = -iA * m_rA.x * m_rA.y - iB * m_rB.x * m_rB.y;
+ K.ey.x = K.ex.y;
+ K.ey.y = mA + mB + iA * m_rA.x * m_rA.x + iB * m_rB.x * m_rB.x;
+
+ m_linearMass = K.GetInverse();
+
+ m_angularMass = iA + iB;
+ if (m_angularMass > 0.0f)
+ {
+ m_angularMass = 1.0f / m_angularMass;
+ }
+
+ if (data.step.warmStarting)
+ {
+ // Scale impulses to support a variable time step.
+ m_linearImpulse *= data.step.dtRatio;
+ m_angularImpulse *= data.step.dtRatio;
+
+ b2Vec2 P(m_linearImpulse.x, m_linearImpulse.y);
+ vA -= mA * P;
+ wA -= iA * (b2Cross(m_rA, P) + m_angularImpulse);
+ vB += mB * P;
+ wB += iB * (b2Cross(m_rB, P) + m_angularImpulse);
+ }
+ else
+ {
+ m_linearImpulse.SetZero();
+ m_angularImpulse = 0.0f;
+ }
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+void b2FrictionJoint::SolveVelocityConstraints(const b2SolverData& data)
+{
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ float32 mA = m_invMassA, mB = m_invMassB;
+ float32 iA = m_invIA, iB = m_invIB;
+
+ float32 h = data.step.dt;
+
+ // Solve angular friction
+ {
+ float32 Cdot = wB - wA;
+ float32 impulse = -m_angularMass * Cdot;
+
+ float32 oldImpulse = m_angularImpulse;
+ float32 maxImpulse = h * m_maxTorque;
+ m_angularImpulse = b2Clamp(m_angularImpulse + impulse, -maxImpulse, maxImpulse);
+ impulse = m_angularImpulse - oldImpulse;
+
+ wA -= iA * impulse;
+ wB += iB * impulse;
+ }
+
+ // Solve linear friction
+ {
+ b2Vec2 Cdot = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA);
+
+ b2Vec2 impulse = -b2Mul(m_linearMass, Cdot);
+ b2Vec2 oldImpulse = m_linearImpulse;
+ m_linearImpulse += impulse;
+
+ float32 maxImpulse = h * m_maxForce;
+
+ if (m_linearImpulse.LengthSquared() > maxImpulse * maxImpulse)
+ {
+ m_linearImpulse.Normalize();
+ m_linearImpulse *= maxImpulse;
+ }
+
+ impulse = m_linearImpulse - oldImpulse;
+
+ vA -= mA * impulse;
+ wA -= iA * b2Cross(m_rA, impulse);
+
+ vB += mB * impulse;
+ wB += iB * b2Cross(m_rB, impulse);
+ }
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+bool b2FrictionJoint::SolvePositionConstraints(const b2SolverData& data)
+{
+ B2_NOT_USED(data);
+
+ return true;
+}
+
+b2Vec2 b2FrictionJoint::GetAnchorA() const
+{
+ return m_bodyA->GetWorldPoint(m_localAnchorA);
+}
+
+b2Vec2 b2FrictionJoint::GetAnchorB() const
+{
+ return m_bodyB->GetWorldPoint(m_localAnchorB);
+}
+
+b2Vec2 b2FrictionJoint::GetReactionForce(float32 inv_dt) const
+{
+ return inv_dt * m_linearImpulse;
+}
+
+float32 b2FrictionJoint::GetReactionTorque(float32 inv_dt) const
+{
+ return inv_dt * m_angularImpulse;
+}
+
+void b2FrictionJoint::SetMaxForce(float32 force)
+{
+ b2Assert(b2IsValid(force) && force >= 0.0f);
+ m_maxForce = force;
+}
+
+float32 b2FrictionJoint::GetMaxForce() const
+{
+ return m_maxForce;
+}
+
+void b2FrictionJoint::SetMaxTorque(float32 torque)
+{
+ b2Assert(b2IsValid(torque) && torque >= 0.0f);
+ m_maxTorque = torque;
+}
+
+float32 b2FrictionJoint::GetMaxTorque() const
+{
+ return m_maxTorque;
+}
+
+void b2FrictionJoint::Dump()
+{
+ int32 indexA = m_bodyA->m_islandIndex;
+ int32 indexB = m_bodyB->m_islandIndex;
+
+ b2Log(" b2FrictionJointDef jd;\n");
+ b2Log(" jd.bodyA = bodies[%d];\n", indexA);
+ b2Log(" jd.bodyB = bodies[%d];\n", indexB);
+ b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
+ b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y);
+ b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y);
+ b2Log(" jd.maxForce = %.15lef;\n", m_maxForce);
+ b2Log(" jd.maxTorque = %.15lef;\n", m_maxTorque);
+ b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
+}
diff --git a/tests/box2d/Box2D/Dynamics/Joints/b2FrictionJoint.h b/tests/box2d/Box2D/Dynamics/Joints/b2FrictionJoint.h new file mode 100755 index 00000000..7e261fc9 --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Joints/b2FrictionJoint.h @@ -0,0 +1,129 @@ +/*
+* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_FRICTION_JOINT_H
+#define B2_FRICTION_JOINT_H
+
+#include <Box2D/Dynamics/Joints/b2Joint.h>
+
+/// Friction joint definition.
+// emscripten - b2FrictionJointDef: add functions to set/get base class members
+struct b2FrictionJointDef : public b2JointDef
+{
+ b2FrictionJointDef()
+ {
+ type = e_frictionJoint;
+ localAnchorA.SetZero();
+ localAnchorB.SetZero();
+ maxForce = 0.0f;
+ maxTorque = 0.0f;
+ }
+
+ /// Initialize the bodies, anchors, axis, and reference angle using the world
+ /// anchor and world axis.
+ void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor);
+
+ /// The local anchor point relative to bodyA's origin.
+ b2Vec2 localAnchorA;
+
+ /// The local anchor point relative to bodyB's origin.
+ b2Vec2 localAnchorB;
+
+ /// The maximum friction force in N.
+ float32 maxForce;
+
+ /// The maximum friction torque in N-m.
+ float32 maxTorque;
+
+ // to generate javascript bindings
+ void set_bodyA(b2Body* b) { bodyA = b; }
+ void set_bodyB(b2Body* b) { bodyB = b; }
+ void set_collideConnected(bool b) { collideConnected = b; }
+ b2Body* get_bodyA(b2Body* b) { return bodyA; }
+ b2Body* get_bodyB(b2Body* b) { return bodyB; }
+ bool get_collideConnected(bool b) { return collideConnected; }
+};
+
+/// Friction joint. This is used for top-down friction.
+/// It provides 2D translational friction and angular friction.
+// emscripten - b2FrictionJoint: make constructor public
+class b2FrictionJoint : public b2Joint
+{
+public:
+ b2Vec2 GetAnchorA() const;
+ b2Vec2 GetAnchorB() const;
+
+ b2Vec2 GetReactionForce(float32 inv_dt) const;
+ float32 GetReactionTorque(float32 inv_dt) const;
+
+ /// The local anchor point relative to bodyA's origin.
+ const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; }
+
+ /// The local anchor point relative to bodyB's origin.
+ const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; }
+
+ /// Set the maximum friction force in N.
+ void SetMaxForce(float32 force);
+
+ /// Get the maximum friction force in N.
+ float32 GetMaxForce() const;
+
+ /// Set the maximum friction torque in N*m.
+ void SetMaxTorque(float32 torque);
+
+ /// Get the maximum friction torque in N*m.
+ float32 GetMaxTorque() const;
+
+ /// Dump joint to dmLog
+ void Dump();
+
+ b2FrictionJoint(const b2FrictionJointDef* def);
+
+protected:
+
+ friend class b2Joint;
+
+ void InitVelocityConstraints(const b2SolverData& data);
+ void SolveVelocityConstraints(const b2SolverData& data);
+ bool SolvePositionConstraints(const b2SolverData& data);
+
+ b2Vec2 m_localAnchorA;
+ b2Vec2 m_localAnchorB;
+
+ // Solver shared
+ b2Vec2 m_linearImpulse;
+ float32 m_angularImpulse;
+ float32 m_maxForce;
+ float32 m_maxTorque;
+
+ // Solver temp
+ int32 m_indexA;
+ int32 m_indexB;
+ b2Vec2 m_rA;
+ b2Vec2 m_rB;
+ b2Vec2 m_localCenterA;
+ b2Vec2 m_localCenterB;
+ float32 m_invMassA;
+ float32 m_invMassB;
+ float32 m_invIA;
+ float32 m_invIB;
+ b2Mat22 m_linearMass;
+ float32 m_angularMass;
+};
+
+#endif
diff --git a/tests/box2d/Box2D/Dynamics/Joints/b2GearJoint.cpp b/tests/box2d/Box2D/Dynamics/Joints/b2GearJoint.cpp new file mode 100755 index 00000000..201f0123 --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Joints/b2GearJoint.cpp @@ -0,0 +1,423 @@ +/*
+* Copyright (c) 2007-2011 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Dynamics/Joints/b2GearJoint.h>
+#include <Box2D/Dynamics/Joints/b2RevoluteJoint.h>
+#include <Box2D/Dynamics/Joints/b2PrismaticJoint.h>
+#include <Box2D/Dynamics/b2Body.h>
+#include <Box2D/Dynamics/b2TimeStep.h>
+
+// Gear Joint:
+// C0 = (coordinate1 + ratio * coordinate2)_initial
+// C = (coordinate1 + ratio * coordinate2) - C0 = 0
+// J = [J1 ratio * J2]
+// K = J * invM * JT
+// = J1 * invM1 * J1T + ratio * ratio * J2 * invM2 * J2T
+//
+// Revolute:
+// coordinate = rotation
+// Cdot = angularVelocity
+// J = [0 0 1]
+// K = J * invM * JT = invI
+//
+// Prismatic:
+// coordinate = dot(p - pg, ug)
+// Cdot = dot(v + cross(w, r), ug)
+// J = [ug cross(r, ug)]
+// K = J * invM * JT = invMass + invI * cross(r, ug)^2
+
+b2GearJoint::b2GearJoint(const b2GearJointDef* def)
+: b2Joint(def)
+{
+ m_joint1 = def->joint1;
+ m_joint2 = def->joint2;
+
+ m_typeA = m_joint1->GetType();
+ m_typeB = m_joint2->GetType();
+
+ b2Assert(m_typeA == e_revoluteJoint || m_typeA == e_prismaticJoint);
+ b2Assert(m_typeB == e_revoluteJoint || m_typeB == e_prismaticJoint);
+
+ float32 coordinateA, coordinateB;
+
+ // TODO_ERIN there might be some problem with the joint edges in b2Joint.
+
+ m_bodyC = m_joint1->GetBodyA();
+ m_bodyA = m_joint1->GetBodyB();
+
+ // Get geometry of joint1
+ b2Transform xfA = m_bodyA->m_xf;
+ float32 aA = m_bodyA->m_sweep.a;
+ b2Transform xfC = m_bodyC->m_xf;
+ float32 aC = m_bodyC->m_sweep.a;
+
+ if (m_typeA == e_revoluteJoint)
+ {
+ b2RevoluteJoint* revolute = (b2RevoluteJoint*)def->joint1;
+ m_localAnchorC = revolute->m_localAnchorA;
+ m_localAnchorA = revolute->m_localAnchorB;
+ m_referenceAngleA = revolute->m_referenceAngle;
+ m_localAxisC.SetZero();
+
+ coordinateA = aA - aC - m_referenceAngleA;
+ }
+ else
+ {
+ b2PrismaticJoint* prismatic = (b2PrismaticJoint*)def->joint1;
+ m_localAnchorC = prismatic->m_localAnchorA;
+ m_localAnchorA = prismatic->m_localAnchorB;
+ m_referenceAngleA = prismatic->m_referenceAngle;
+ m_localAxisC = prismatic->m_localXAxisA;
+
+ b2Vec2 pC = m_localAnchorC;
+ b2Vec2 pA = b2MulT(xfC.q, b2Mul(xfA.q, m_localAnchorA) + (xfA.p - xfC.p));
+ coordinateA = b2Dot(pA - pC, m_localAxisC);
+ }
+
+ m_bodyD = m_joint2->GetBodyA();
+ m_bodyB = m_joint2->GetBodyB();
+
+ // Get geometry of joint2
+ b2Transform xfB = m_bodyB->m_xf;
+ float32 aB = m_bodyB->m_sweep.a;
+ b2Transform xfD = m_bodyD->m_xf;
+ float32 aD = m_bodyD->m_sweep.a;
+
+ if (m_typeB == e_revoluteJoint)
+ {
+ b2RevoluteJoint* revolute = (b2RevoluteJoint*)def->joint2;
+ m_localAnchorD = revolute->m_localAnchorA;
+ m_localAnchorB = revolute->m_localAnchorB;
+ m_referenceAngleB = revolute->m_referenceAngle;
+ m_localAxisD.SetZero();
+
+ coordinateB = aB - aD - m_referenceAngleB;
+ }
+ else
+ {
+ b2PrismaticJoint* prismatic = (b2PrismaticJoint*)def->joint2;
+ m_localAnchorD = prismatic->m_localAnchorA;
+ m_localAnchorB = prismatic->m_localAnchorB;
+ m_referenceAngleB = prismatic->m_referenceAngle;
+ m_localAxisD = prismatic->m_localXAxisA;
+
+ b2Vec2 pD = m_localAnchorD;
+ b2Vec2 pB = b2MulT(xfD.q, b2Mul(xfB.q, m_localAnchorB) + (xfB.p - xfD.p));
+ coordinateB = b2Dot(pB - pD, m_localAxisD);
+ }
+
+ m_ratio = def->ratio;
+
+ m_constant = coordinateA + m_ratio * coordinateB;
+
+ m_impulse = 0.0f;
+}
+
+void b2GearJoint::InitVelocityConstraints(const b2SolverData& data)
+{
+ m_indexA = m_bodyA->m_islandIndex;
+ m_indexB = m_bodyB->m_islandIndex;
+ m_indexC = m_bodyC->m_islandIndex;
+ m_indexD = m_bodyD->m_islandIndex;
+ m_lcA = m_bodyA->m_sweep.localCenter;
+ m_lcB = m_bodyB->m_sweep.localCenter;
+ m_lcC = m_bodyC->m_sweep.localCenter;
+ m_lcD = m_bodyD->m_sweep.localCenter;
+ m_mA = m_bodyA->m_invMass;
+ m_mB = m_bodyB->m_invMass;
+ m_mC = m_bodyC->m_invMass;
+ m_mD = m_bodyD->m_invMass;
+ m_iA = m_bodyA->m_invI;
+ m_iB = m_bodyB->m_invI;
+ m_iC = m_bodyC->m_invI;
+ m_iD = m_bodyD->m_invI;
+
+ b2Vec2 cA = data.positions[m_indexA].c;
+ float32 aA = data.positions[m_indexA].a;
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+
+ b2Vec2 cB = data.positions[m_indexB].c;
+ float32 aB = data.positions[m_indexB].a;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ b2Vec2 cC = data.positions[m_indexC].c;
+ float32 aC = data.positions[m_indexC].a;
+ b2Vec2 vC = data.velocities[m_indexC].v;
+ float32 wC = data.velocities[m_indexC].w;
+
+ b2Vec2 cD = data.positions[m_indexD].c;
+ float32 aD = data.positions[m_indexD].a;
+ b2Vec2 vD = data.velocities[m_indexD].v;
+ float32 wD = data.velocities[m_indexD].w;
+
+ b2Rot qA(aA), qB(aB), qC(aC), qD(aD);
+
+ m_mass = 0.0f;
+
+ if (m_typeA == e_revoluteJoint)
+ {
+ m_JvAC.SetZero();
+ m_JwA = 1.0f;
+ m_JwC = 1.0f;
+ m_mass += m_iA + m_iC;
+ }
+ else
+ {
+ b2Vec2 u = b2Mul(qC, m_localAxisC);
+ b2Vec2 rC = b2Mul(qC, m_localAnchorC - m_lcC);
+ b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_lcA);
+ m_JvAC = u;
+ m_JwC = b2Cross(rC, u);
+ m_JwA = b2Cross(rA, u);
+ m_mass += m_mC + m_mA + m_iC * m_JwC * m_JwC + m_iA * m_JwA * m_JwA;
+ }
+
+ if (m_typeB == e_revoluteJoint)
+ {
+ m_JvBD.SetZero();
+ m_JwB = m_ratio;
+ m_JwD = m_ratio;
+ m_mass += m_ratio * m_ratio * (m_iB + m_iD);
+ }
+ else
+ {
+ b2Vec2 u = b2Mul(qD, m_localAxisD);
+ b2Vec2 rD = b2Mul(qD, m_localAnchorD - m_lcD);
+ b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_lcB);
+ m_JvBD = m_ratio * u;
+ m_JwD = m_ratio * b2Cross(rD, u);
+ m_JwB = m_ratio * b2Cross(rB, u);
+ m_mass += m_ratio * m_ratio * (m_mD + m_mB) + m_iD * m_JwD * m_JwD + m_iB * m_JwB * m_JwB;
+ }
+
+ // Compute effective mass.
+ m_mass = m_mass > 0.0f ? 1.0f / m_mass : 0.0f;
+
+ if (data.step.warmStarting)
+ {
+ vA += (m_mA * m_impulse) * m_JvAC;
+ wA += m_iA * m_impulse * m_JwA;
+ vB += (m_mB * m_impulse) * m_JvBD;
+ wB += m_iB * m_impulse * m_JwB;
+ vC -= (m_mC * m_impulse) * m_JvAC;
+ wC -= m_iC * m_impulse * m_JwC;
+ vD -= (m_mD * m_impulse) * m_JvBD;
+ wD -= m_iD * m_impulse * m_JwD;
+ }
+ else
+ {
+ m_impulse = 0.0f;
+ }
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+ data.velocities[m_indexC].v = vC;
+ data.velocities[m_indexC].w = wC;
+ data.velocities[m_indexD].v = vD;
+ data.velocities[m_indexD].w = wD;
+}
+
+void b2GearJoint::SolveVelocityConstraints(const b2SolverData& data)
+{
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+ b2Vec2 vC = data.velocities[m_indexC].v;
+ float32 wC = data.velocities[m_indexC].w;
+ b2Vec2 vD = data.velocities[m_indexD].v;
+ float32 wD = data.velocities[m_indexD].w;
+
+ float32 Cdot = b2Dot(m_JvAC, vA - vC) + b2Dot(m_JvBD, vB - vD);
+ Cdot += (m_JwA * wA - m_JwC * wC) + (m_JwB * wB - m_JwD * wD);
+
+ float32 impulse = -m_mass * Cdot;
+ m_impulse += impulse;
+
+ vA += (m_mA * impulse) * m_JvAC;
+ wA += m_iA * impulse * m_JwA;
+ vB += (m_mB * impulse) * m_JvBD;
+ wB += m_iB * impulse * m_JwB;
+ vC -= (m_mC * impulse) * m_JvAC;
+ wC -= m_iC * impulse * m_JwC;
+ vD -= (m_mD * impulse) * m_JvBD;
+ wD -= m_iD * impulse * m_JwD;
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+ data.velocities[m_indexC].v = vC;
+ data.velocities[m_indexC].w = wC;
+ data.velocities[m_indexD].v = vD;
+ data.velocities[m_indexD].w = wD;
+}
+
+bool b2GearJoint::SolvePositionConstraints(const b2SolverData& data)
+{
+ b2Vec2 cA = data.positions[m_indexA].c;
+ float32 aA = data.positions[m_indexA].a;
+ b2Vec2 cB = data.positions[m_indexB].c;
+ float32 aB = data.positions[m_indexB].a;
+ b2Vec2 cC = data.positions[m_indexC].c;
+ float32 aC = data.positions[m_indexC].a;
+ b2Vec2 cD = data.positions[m_indexD].c;
+ float32 aD = data.positions[m_indexD].a;
+
+ b2Rot qA(aA), qB(aB), qC(aC), qD(aD);
+
+ float32 linearError = 0.0f;
+
+ float32 coordinateA, coordinateB;
+
+ b2Vec2 JvAC, JvBD;
+ float32 JwA, JwB, JwC, JwD;
+ float32 mass = 0.0f;
+
+ if (m_typeA == e_revoluteJoint)
+ {
+ JvAC.SetZero();
+ JwA = 1.0f;
+ JwC = 1.0f;
+ mass += m_iA + m_iC;
+
+ coordinateA = aA - aC - m_referenceAngleA;
+ }
+ else
+ {
+ b2Vec2 u = b2Mul(qC, m_localAxisC);
+ b2Vec2 rC = b2Mul(qC, m_localAnchorC - m_lcC);
+ b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_lcA);
+ JvAC = u;
+ JwC = b2Cross(rC, u);
+ JwA = b2Cross(rA, u);
+ mass += m_mC + m_mA + m_iC * JwC * JwC + m_iA * JwA * JwA;
+
+ b2Vec2 pC = m_localAnchorC - m_lcC;
+ b2Vec2 pA = b2MulT(qC, rA + (cA - cC));
+ coordinateA = b2Dot(pA - pC, m_localAxisC);
+ }
+
+ if (m_typeB == e_revoluteJoint)
+ {
+ JvBD.SetZero();
+ JwB = m_ratio;
+ JwD = m_ratio;
+ mass += m_ratio * m_ratio * (m_iB + m_iD);
+
+ coordinateB = aB - aD - m_referenceAngleB;
+ }
+ else
+ {
+ b2Vec2 u = b2Mul(qD, m_localAxisD);
+ b2Vec2 rD = b2Mul(qD, m_localAnchorD - m_lcD);
+ b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_lcB);
+ JvBD = m_ratio * u;
+ JwD = m_ratio * b2Cross(rD, u);
+ JwB = m_ratio * b2Cross(rB, u);
+ mass += m_ratio * m_ratio * (m_mD + m_mB) + m_iD * JwD * JwD + m_iB * JwB * JwB;
+
+ b2Vec2 pD = m_localAnchorD - m_lcD;
+ b2Vec2 pB = b2MulT(qD, rB + (cB - cD));
+ coordinateB = b2Dot(pB - pD, m_localAxisD);
+ }
+
+ float32 C = (coordinateA + m_ratio * coordinateB) - m_constant;
+
+ float32 impulse = 0.0f;
+ if (mass > 0.0f)
+ {
+ impulse = -C / mass;
+ }
+
+ cA += m_mA * impulse * JvAC;
+ aA += m_iA * impulse * JwA;
+ cB += m_mB * impulse * JvBD;
+ aB += m_iB * impulse * JwB;
+ cC -= m_mC * impulse * JvAC;
+ aC -= m_iC * impulse * JwC;
+ cD -= m_mD * impulse * JvBD;
+ aD -= m_iD * impulse * JwD;
+
+ data.positions[m_indexA].c = cA;
+ data.positions[m_indexA].a = aA;
+ data.positions[m_indexB].c = cB;
+ data.positions[m_indexB].a = aB;
+ data.positions[m_indexC].c = cC;
+ data.positions[m_indexC].a = aC;
+ data.positions[m_indexD].c = cD;
+ data.positions[m_indexD].a = aD;
+
+ // TODO_ERIN not implemented
+ return linearError < b2_linearSlop;
+}
+
+b2Vec2 b2GearJoint::GetAnchorA() const
+{
+ return m_bodyA->GetWorldPoint(m_localAnchorA);
+}
+
+b2Vec2 b2GearJoint::GetAnchorB() const
+{
+ return m_bodyB->GetWorldPoint(m_localAnchorB);
+}
+
+b2Vec2 b2GearJoint::GetReactionForce(float32 inv_dt) const
+{
+ b2Vec2 P = m_impulse * m_JvAC;
+ return inv_dt * P;
+}
+
+float32 b2GearJoint::GetReactionTorque(float32 inv_dt) const
+{
+ float32 L = m_impulse * m_JwA;
+ return inv_dt * L;
+}
+
+void b2GearJoint::SetRatio(float32 ratio)
+{
+ b2Assert(b2IsValid(ratio));
+ m_ratio = ratio;
+}
+
+float32 b2GearJoint::GetRatio() const
+{
+ return m_ratio;
+}
+
+void b2GearJoint::Dump()
+{
+ int32 indexA = m_bodyA->m_islandIndex;
+ int32 indexB = m_bodyB->m_islandIndex;
+
+ int32 index1 = m_joint1->m_index;
+ int32 index2 = m_joint2->m_index;
+
+ b2Log(" b2GearJointDef jd;\n");
+ b2Log(" jd.bodyA = bodies[%d];\n", indexA);
+ b2Log(" jd.bodyB = bodies[%d];\n", indexB);
+ b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
+ b2Log(" jd.joint1 = joints[%d];\n", index1);
+ b2Log(" jd.joint2 = joints[%d];\n", index2);
+ b2Log(" jd.ratio = %.15lef;\n", m_ratio);
+ b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
+}
diff --git a/tests/box2d/Box2D/Dynamics/Joints/b2GearJoint.h b/tests/box2d/Box2D/Dynamics/Joints/b2GearJoint.h new file mode 100755 index 00000000..97283e13 --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Joints/b2GearJoint.h @@ -0,0 +1,136 @@ +/*
+* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_GEAR_JOINT_H
+#define B2_GEAR_JOINT_H
+
+#include <Box2D/Dynamics/Joints/b2Joint.h>
+
+/// Gear joint definition. This definition requires two existing
+/// revolute or prismatic joints (any combination will work).
+// emscripten - b2GearJointDef: add functions to set/get base class members
+struct b2GearJointDef : public b2JointDef
+{
+ b2GearJointDef()
+ {
+ type = e_gearJoint;
+ joint1 = NULL;
+ joint2 = NULL;
+ ratio = 1.0f;
+ }
+
+ /// The first revolute/prismatic joint attached to the gear joint.
+ b2Joint* joint1;
+
+ /// The second revolute/prismatic joint attached to the gear joint.
+ b2Joint* joint2;
+
+ /// The gear ratio.
+ /// @see b2GearJoint for explanation.
+ float32 ratio;
+
+ // to generate javascript bindings
+ void set_bodyA(b2Body* b) { bodyA = b; }
+ void set_bodyB(b2Body* b) { bodyB = b; }
+ void set_collideConnected(bool b) { collideConnected = b; }
+ b2Body* get_bodyA(b2Body* b) { return bodyA; }
+ b2Body* get_bodyB(b2Body* b) { return bodyB; }
+ bool get_collideConnected(bool b) { return collideConnected; }
+};
+
+/// A gear joint is used to connect two joints together. Either joint
+/// can be a revolute or prismatic joint. You specify a gear ratio
+/// to bind the motions together:
+/// coordinate1 + ratio * coordinate2 = constant
+/// The ratio can be negative or positive. If one joint is a revolute joint
+/// and the other joint is a prismatic joint, then the ratio will have units
+/// of length or units of 1/length.
+/// @warning You have to manually destroy the gear joint if joint1 or joint2
+/// is destroyed.
+// emscripten - b2GearJoint: make constructor public
+class b2GearJoint : public b2Joint
+{
+public:
+ b2Vec2 GetAnchorA() const;
+ b2Vec2 GetAnchorB() const;
+
+ b2Vec2 GetReactionForce(float32 inv_dt) const;
+ float32 GetReactionTorque(float32 inv_dt) const;
+
+ /// Get the first joint.
+ b2Joint* GetJoint1() { return m_joint1; }
+
+ /// Get the second joint.
+ b2Joint* GetJoint2() { return m_joint2; }
+
+ /// Set/Get the gear ratio.
+ void SetRatio(float32 ratio);
+ float32 GetRatio() const;
+
+ /// Dump joint to dmLog
+ void Dump();
+
+ b2GearJoint(const b2GearJointDef* data);
+
+protected:
+
+ friend class b2Joint;
+
+ void InitVelocityConstraints(const b2SolverData& data);
+ void SolveVelocityConstraints(const b2SolverData& data);
+ bool SolvePositionConstraints(const b2SolverData& data);
+
+ b2Joint* m_joint1;
+ b2Joint* m_joint2;
+
+ b2JointType m_typeA;
+ b2JointType m_typeB;
+
+ // Body A is connected to body C
+ // Body B is connected to body D
+ b2Body* m_bodyC;
+ b2Body* m_bodyD;
+
+ // Solver shared
+ b2Vec2 m_localAnchorA;
+ b2Vec2 m_localAnchorB;
+ b2Vec2 m_localAnchorC;
+ b2Vec2 m_localAnchorD;
+
+ b2Vec2 m_localAxisC;
+ b2Vec2 m_localAxisD;
+
+ float32 m_referenceAngleA;
+ float32 m_referenceAngleB;
+
+ float32 m_constant;
+ float32 m_ratio;
+
+ float32 m_impulse;
+
+ // Solver temp
+ int32 m_indexA, m_indexB, m_indexC, m_indexD;
+ b2Vec2 m_lcA, m_lcB, m_lcC, m_lcD;
+ float32 m_mA, m_mB, m_mC, m_mD;
+ float32 m_iA, m_iB, m_iC, m_iD;
+ b2Vec2 m_JvAC, m_JvBD;
+ float32 m_JwA, m_JwB, m_JwC, m_JwD;
+ float32 m_mass;
+};
+
+#endif
diff --git a/tests/box2d/Box2D/Dynamics/Joints/b2Joint.cpp b/tests/box2d/Box2D/Dynamics/Joints/b2Joint.cpp new file mode 100755 index 00000000..85322f77 --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Joints/b2Joint.cpp @@ -0,0 +1,199 @@ +/*
+* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Dynamics/Joints/b2Joint.h>
+#include <Box2D/Dynamics/Joints/b2DistanceJoint.h>
+#include <Box2D/Dynamics/Joints/b2WheelJoint.h>
+#include <Box2D/Dynamics/Joints/b2MouseJoint.h>
+#include <Box2D/Dynamics/Joints/b2RevoluteJoint.h>
+#include <Box2D/Dynamics/Joints/b2PrismaticJoint.h>
+#include <Box2D/Dynamics/Joints/b2PulleyJoint.h>
+#include <Box2D/Dynamics/Joints/b2GearJoint.h>
+#include <Box2D/Dynamics/Joints/b2WeldJoint.h>
+#include <Box2D/Dynamics/Joints/b2FrictionJoint.h>
+#include <Box2D/Dynamics/Joints/b2RopeJoint.h>
+#include <Box2D/Dynamics/b2Body.h>
+#include <Box2D/Dynamics/b2World.h>
+#include <Box2D/Common/b2BlockAllocator.h>
+
+#include <new>
+
+b2Joint* b2Joint::Create(const b2JointDef* def, b2BlockAllocator* allocator)
+{
+ b2Joint* joint = NULL;
+
+ switch (def->type)
+ {
+ case e_distanceJoint:
+ {
+ void* mem = allocator->Allocate(sizeof(b2DistanceJoint));
+ joint = new (mem) b2DistanceJoint((b2DistanceJointDef*)def);
+ }
+ break;
+
+ case e_mouseJoint:
+ {
+ void* mem = allocator->Allocate(sizeof(b2MouseJoint));
+ joint = new (mem) b2MouseJoint((b2MouseJointDef*)def);
+ }
+ break;
+
+ case e_prismaticJoint:
+ {
+ void* mem = allocator->Allocate(sizeof(b2PrismaticJoint));
+ joint = new (mem) b2PrismaticJoint((b2PrismaticJointDef*)def);
+ }
+ break;
+
+ case e_revoluteJoint:
+ {
+ void* mem = allocator->Allocate(sizeof(b2RevoluteJoint));
+ joint = new (mem) b2RevoluteJoint((b2RevoluteJointDef*)def);
+ }
+ break;
+
+ case e_pulleyJoint:
+ {
+ void* mem = allocator->Allocate(sizeof(b2PulleyJoint));
+ joint = new (mem) b2PulleyJoint((b2PulleyJointDef*)def);
+ }
+ break;
+
+ case e_gearJoint:
+ {
+ void* mem = allocator->Allocate(sizeof(b2GearJoint));
+ joint = new (mem) b2GearJoint((b2GearJointDef*)def);
+ }
+ break;
+
+ case e_wheelJoint:
+ {
+ void* mem = allocator->Allocate(sizeof(b2WheelJoint));
+ joint = new (mem) b2WheelJoint((b2WheelJointDef*)def);
+ }
+ break;
+
+ case e_weldJoint:
+ {
+ void* mem = allocator->Allocate(sizeof(b2WeldJoint));
+ joint = new (mem) b2WeldJoint((b2WeldJointDef*)def);
+ }
+ break;
+
+ case e_frictionJoint:
+ {
+ void* mem = allocator->Allocate(sizeof(b2FrictionJoint));
+ joint = new (mem) b2FrictionJoint((b2FrictionJointDef*)def);
+ }
+ break;
+
+ case e_ropeJoint:
+ {
+ void* mem = allocator->Allocate(sizeof(b2RopeJoint));
+ joint = new (mem) b2RopeJoint((b2RopeJointDef*)def);
+ }
+ break;
+
+ default:
+ b2Assert(false);
+ break;
+ }
+
+ return joint;
+}
+
+void b2Joint::Destroy(b2Joint* joint, b2BlockAllocator* allocator)
+{
+ joint->~b2Joint();
+ switch (joint->m_type)
+ {
+ case e_distanceJoint:
+ allocator->Free(joint, sizeof(b2DistanceJoint));
+ break;
+
+ case e_mouseJoint:
+ allocator->Free(joint, sizeof(b2MouseJoint));
+ break;
+
+ case e_prismaticJoint:
+ allocator->Free(joint, sizeof(b2PrismaticJoint));
+ break;
+
+ case e_revoluteJoint:
+ allocator->Free(joint, sizeof(b2RevoluteJoint));
+ break;
+
+ case e_pulleyJoint:
+ allocator->Free(joint, sizeof(b2PulleyJoint));
+ break;
+
+ case e_gearJoint:
+ allocator->Free(joint, sizeof(b2GearJoint));
+ break;
+
+ case e_wheelJoint:
+ allocator->Free(joint, sizeof(b2WheelJoint));
+ break;
+
+ case e_weldJoint:
+ allocator->Free(joint, sizeof(b2WeldJoint));
+ break;
+
+ case e_frictionJoint:
+ allocator->Free(joint, sizeof(b2FrictionJoint));
+ break;
+
+ case e_ropeJoint:
+ allocator->Free(joint, sizeof(b2RopeJoint));
+ break;
+
+ default:
+ b2Assert(false);
+ break;
+ }
+}
+
+b2Joint::b2Joint(const b2JointDef* def)
+{
+ b2Assert(def->bodyA != def->bodyB);
+
+ m_type = def->type;
+ m_prev = NULL;
+ m_next = NULL;
+ m_bodyA = def->bodyA;
+ m_bodyB = def->bodyB;
+ m_index = 0;
+ m_collideConnected = def->collideConnected;
+ m_islandFlag = false;
+ m_userData = def->userData;
+
+ m_edgeA.joint = NULL;
+ m_edgeA.other = NULL;
+ m_edgeA.prev = NULL;
+ m_edgeA.next = NULL;
+
+ m_edgeB.joint = NULL;
+ m_edgeB.other = NULL;
+ m_edgeB.prev = NULL;
+ m_edgeB.next = NULL;
+}
+
+bool b2Joint::IsActive() const
+{
+ return m_bodyA->IsActive() && m_bodyB->IsActive();
+}
diff --git a/tests/box2d/Box2D/Dynamics/Joints/b2Joint.h b/tests/box2d/Box2D/Dynamics/Joints/b2Joint.h new file mode 100755 index 00000000..90154ccb --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Joints/b2Joint.h @@ -0,0 +1,222 @@ +/*
+* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_JOINT_H
+#define B2_JOINT_H
+
+#include <Box2D/Common/b2Math.h>
+
+class b2Body;
+class b2Joint;
+struct b2SolverData;
+class b2BlockAllocator;
+
+enum b2JointType
+{
+ e_unknownJoint,
+ e_revoluteJoint,
+ e_prismaticJoint,
+ e_distanceJoint,
+ e_pulleyJoint,
+ e_mouseJoint,
+ e_gearJoint,
+ e_wheelJoint,
+ e_weldJoint,
+ e_frictionJoint,
+ e_ropeJoint
+};
+
+enum b2LimitState
+{
+ e_inactiveLimit,
+ e_atLowerLimit,
+ e_atUpperLimit,
+ e_equalLimits
+};
+
+struct b2Jacobian
+{
+ b2Vec2 linear;
+ float32 angularA;
+ float32 angularB;
+};
+
+/// A joint edge is used to connect bodies and joints together
+/// in a joint graph where each body is a node and each joint
+/// is an edge. A joint edge belongs to a doubly linked list
+/// maintained in each attached body. Each joint has two joint
+/// nodes, one for each attached body.
+struct b2JointEdge
+{
+ b2Body* other; ///< provides quick access to the other body attached.
+ b2Joint* joint; ///< the joint
+ b2JointEdge* prev; ///< the previous joint edge in the body's joint list
+ b2JointEdge* next; ///< the next joint edge in the body's joint list
+};
+
+/// Joint definitions are used to construct joints.
+struct b2JointDef
+{
+ b2JointDef()
+ {
+ type = e_unknownJoint;
+ userData = NULL;
+ bodyA = NULL;
+ bodyB = NULL;
+ collideConnected = false;
+ }
+
+ /// The joint type is set automatically for concrete joint types.
+ b2JointType type;
+
+ /// Use this to attach application specific data to your joints.
+ void* userData;
+
+ /// The first attached body.
+ b2Body* bodyA;
+
+ /// The second attached body.
+ b2Body* bodyB;
+
+ /// Set this flag to true if the attached bodies should collide.
+ bool collideConnected;
+};
+
+/// The base joint class. Joints are used to constraint two bodies together in
+/// various fashions. Some joints also feature limits and motors.
+class b2Joint
+{
+public:
+
+ /// Get the type of the concrete joint.
+ b2JointType GetType() const;
+
+ /// Get the first body attached to this joint.
+ b2Body* GetBodyA();
+
+ /// Get the second body attached to this joint.
+ b2Body* GetBodyB();
+
+ /// Get the anchor point on bodyA in world coordinates.
+ virtual b2Vec2 GetAnchorA() const = 0;
+
+ /// Get the anchor point on bodyB in world coordinates.
+ virtual b2Vec2 GetAnchorB() const = 0;
+
+ /// Get the reaction force on bodyB at the joint anchor in Newtons.
+ virtual b2Vec2 GetReactionForce(float32 inv_dt) const = 0;
+
+ /// Get the reaction torque on bodyB in N*m.
+ virtual float32 GetReactionTorque(float32 inv_dt) const = 0;
+
+ /// Get the next joint the world joint list.
+ b2Joint* GetNext();
+ const b2Joint* GetNext() const;
+
+ /// Get the user data pointer.
+ void* GetUserData() const;
+
+ /// Set the user data pointer.
+ void SetUserData(void* data);
+
+ /// Short-cut function to determine if either body is inactive.
+ bool IsActive() const;
+
+ /// Get collide connected.
+ /// Note: modifying the collide connect flag won't work correctly because
+ /// the flag is only checked when fixture AABBs begin to overlap.
+ bool GetCollideConnected() const;
+
+ /// Dump this joint to the log file.
+ virtual void Dump() { b2Log("// Dump is not supported for this joint type.\n"); }
+
+protected:
+ friend class b2World;
+ friend class b2Body;
+ friend class b2Island;
+ friend class b2GearJoint;
+
+ static b2Joint* Create(const b2JointDef* def, b2BlockAllocator* allocator);
+ static void Destroy(b2Joint* joint, b2BlockAllocator* allocator);
+
+ b2Joint(const b2JointDef* def);
+ virtual ~b2Joint() {}
+
+ virtual void InitVelocityConstraints(const b2SolverData& data) = 0;
+ virtual void SolveVelocityConstraints(const b2SolverData& data) = 0;
+
+ // This returns true if the position errors are within tolerance.
+ virtual bool SolvePositionConstraints(const b2SolverData& data) = 0;
+
+ b2JointType m_type;
+ b2Joint* m_prev;
+ b2Joint* m_next;
+ b2JointEdge m_edgeA;
+ b2JointEdge m_edgeB;
+ b2Body* m_bodyA;
+ b2Body* m_bodyB;
+
+ int32 m_index;
+
+ bool m_islandFlag;
+ bool m_collideConnected;
+
+ void* m_userData;
+};
+
+inline b2JointType b2Joint::GetType() const
+{
+ return m_type;
+}
+
+inline b2Body* b2Joint::GetBodyA()
+{
+ return m_bodyA;
+}
+
+inline b2Body* b2Joint::GetBodyB()
+{
+ return m_bodyB;
+}
+
+inline b2Joint* b2Joint::GetNext()
+{
+ return m_next;
+}
+
+inline const b2Joint* b2Joint::GetNext() const
+{
+ return m_next;
+}
+
+inline void* b2Joint::GetUserData() const
+{
+ return m_userData;
+}
+
+inline void b2Joint::SetUserData(void* data)
+{
+ m_userData = data;
+}
+
+inline bool b2Joint::GetCollideConnected() const
+{
+ return m_collideConnected;
+}
+
+#endif
diff --git a/tests/box2d/Box2D/Dynamics/Joints/b2MouseJoint.cpp b/tests/box2d/Box2D/Dynamics/Joints/b2MouseJoint.cpp new file mode 100755 index 00000000..be7c3834 --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Joints/b2MouseJoint.cpp @@ -0,0 +1,217 @@ +/*
+* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Dynamics/Joints/b2MouseJoint.h>
+#include <Box2D/Dynamics/b2Body.h>
+#include <Box2D/Dynamics/b2TimeStep.h>
+
+// p = attached point, m = mouse point
+// C = p - m
+// Cdot = v
+// = v + cross(w, r)
+// J = [I r_skew]
+// Identity used:
+// w k % (rx i + ry j) = w * (-ry i + rx j)
+
+b2MouseJoint::b2MouseJoint(const b2MouseJointDef* def)
+: b2Joint(def)
+{
+ b2Assert(def->target.IsValid());
+ b2Assert(b2IsValid(def->maxForce) && def->maxForce >= 0.0f);
+ b2Assert(b2IsValid(def->frequencyHz) && def->frequencyHz >= 0.0f);
+ b2Assert(b2IsValid(def->dampingRatio) && def->dampingRatio >= 0.0f);
+
+ m_targetA = def->target;
+ m_localAnchorB = b2MulT(m_bodyB->GetTransform(), m_targetA);
+
+ m_maxForce = def->maxForce;
+ m_impulse.SetZero();
+
+ m_frequencyHz = def->frequencyHz;
+ m_dampingRatio = def->dampingRatio;
+
+ m_beta = 0.0f;
+ m_gamma = 0.0f;
+}
+
+void b2MouseJoint::SetTarget(const b2Vec2& target)
+{
+ if (m_bodyB->IsAwake() == false)
+ {
+ m_bodyB->SetAwake(true);
+ }
+ m_targetA = target;
+}
+
+const b2Vec2& b2MouseJoint::GetTarget() const
+{
+ return m_targetA;
+}
+
+void b2MouseJoint::SetMaxForce(float32 force)
+{
+ m_maxForce = force;
+}
+
+float32 b2MouseJoint::GetMaxForce() const
+{
+ return m_maxForce;
+}
+
+void b2MouseJoint::SetFrequency(float32 hz)
+{
+ m_frequencyHz = hz;
+}
+
+float32 b2MouseJoint::GetFrequency() const
+{
+ return m_frequencyHz;
+}
+
+void b2MouseJoint::SetDampingRatio(float32 ratio)
+{
+ m_dampingRatio = ratio;
+}
+
+float32 b2MouseJoint::GetDampingRatio() const
+{
+ return m_dampingRatio;
+}
+
+void b2MouseJoint::InitVelocityConstraints(const b2SolverData& data)
+{
+ m_indexB = m_bodyB->m_islandIndex;
+ m_localCenterB = m_bodyB->m_sweep.localCenter;
+ m_invMassB = m_bodyB->m_invMass;
+ m_invIB = m_bodyB->m_invI;
+
+ b2Vec2 cB = data.positions[m_indexB].c;
+ float32 aB = data.positions[m_indexB].a;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ b2Rot qB(aB);
+
+ float32 mass = m_bodyB->GetMass();
+
+ // Frequency
+ float32 omega = 2.0f * b2_pi * m_frequencyHz;
+
+ // Damping coefficient
+ float32 d = 2.0f * mass * m_dampingRatio * omega;
+
+ // Spring stiffness
+ float32 k = mass * (omega * omega);
+
+ // magic formulas
+ // gamma has units of inverse mass.
+ // beta has units of inverse time.
+ float32 h = data.step.dt;
+ b2Assert(d + h * k > b2_epsilon);
+ m_gamma = h * (d + h * k);
+ if (m_gamma != 0.0f)
+ {
+ m_gamma = 1.0f / m_gamma;
+ }
+ m_beta = h * k * m_gamma;
+
+ // Compute the effective mass matrix.
+ m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
+
+ // K = [(1/m1 + 1/m2) * eye(2) - skew(r1) * invI1 * skew(r1) - skew(r2) * invI2 * skew(r2)]
+ // = [1/m1+1/m2 0 ] + invI1 * [r1.y*r1.y -r1.x*r1.y] + invI2 * [r1.y*r1.y -r1.x*r1.y]
+ // [ 0 1/m1+1/m2] [-r1.x*r1.y r1.x*r1.x] [-r1.x*r1.y r1.x*r1.x]
+ b2Mat22 K;
+ K.ex.x = m_invMassB + m_invIB * m_rB.y * m_rB.y + m_gamma;
+ K.ex.y = -m_invIB * m_rB.x * m_rB.y;
+ K.ey.x = K.ex.y;
+ K.ey.y = m_invMassB + m_invIB * m_rB.x * m_rB.x + m_gamma;
+
+ m_mass = K.GetInverse();
+
+ m_C = cB + m_rB - m_targetA;
+ m_C *= m_beta;
+
+ // Cheat with some damping
+ wB *= 0.98f;
+
+ if (data.step.warmStarting)
+ {
+ m_impulse *= data.step.dtRatio;
+ vB += m_invMassB * m_impulse;
+ wB += m_invIB * b2Cross(m_rB, m_impulse);
+ }
+ else
+ {
+ m_impulse.SetZero();
+ }
+
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+void b2MouseJoint::SolveVelocityConstraints(const b2SolverData& data)
+{
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ // Cdot = v + cross(w, r)
+ b2Vec2 Cdot = vB + b2Cross(wB, m_rB);
+ b2Vec2 impulse = b2Mul(m_mass, -(Cdot + m_C + m_gamma * m_impulse));
+
+ b2Vec2 oldImpulse = m_impulse;
+ m_impulse += impulse;
+ float32 maxImpulse = data.step.dt * m_maxForce;
+ if (m_impulse.LengthSquared() > maxImpulse * maxImpulse)
+ {
+ m_impulse *= maxImpulse / m_impulse.Length();
+ }
+ impulse = m_impulse - oldImpulse;
+
+ vB += m_invMassB * impulse;
+ wB += m_invIB * b2Cross(m_rB, impulse);
+
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+bool b2MouseJoint::SolvePositionConstraints(const b2SolverData& data)
+{
+ B2_NOT_USED(data);
+ return true;
+}
+
+b2Vec2 b2MouseJoint::GetAnchorA() const
+{
+ return m_targetA;
+}
+
+b2Vec2 b2MouseJoint::GetAnchorB() const
+{
+ return m_bodyB->GetWorldPoint(m_localAnchorB);
+}
+
+b2Vec2 b2MouseJoint::GetReactionForce(float32 inv_dt) const
+{
+ return inv_dt * m_impulse;
+}
+
+float32 b2MouseJoint::GetReactionTorque(float32 inv_dt) const
+{
+ return inv_dt * 0.0f;
+}
diff --git a/tests/box2d/Box2D/Dynamics/Joints/b2MouseJoint.h b/tests/box2d/Box2D/Dynamics/Joints/b2MouseJoint.h new file mode 100755 index 00000000..f6df2b31 --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Joints/b2MouseJoint.h @@ -0,0 +1,136 @@ +/*
+* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_MOUSE_JOINT_H
+#define B2_MOUSE_JOINT_H
+
+#include <Box2D/Dynamics/Joints/b2Joint.h>
+
+/// Mouse joint definition. This requires a world target point,
+/// tuning parameters, and the time step.
+// emscripten - b2MouseJointDef: add functions to set/get base class members
+struct b2MouseJointDef : public b2JointDef
+{
+ b2MouseJointDef()
+ {
+ type = e_mouseJoint;
+ target.Set(0.0f, 0.0f);
+ maxForce = 0.0f;
+ frequencyHz = 5.0f;
+ dampingRatio = 0.7f;
+ }
+
+ /// The initial world target point. This is assumed
+ /// to coincide with the body anchor initially.
+ b2Vec2 target;
+
+ /// The maximum constraint force that can be exerted
+ /// to move the candidate body. Usually you will express
+ /// as some multiple of the weight (multiplier * mass * gravity).
+ float32 maxForce;
+
+ /// The response speed.
+ float32 frequencyHz;
+
+ /// The damping ratio. 0 = no damping, 1 = critical damping.
+ float32 dampingRatio;
+
+ // to generate javascript bindings
+ void set_bodyA(b2Body* b) { bodyA = b; }
+ void set_bodyB(b2Body* b) { bodyB = b; }
+ void set_collideConnected(bool b) { collideConnected = b; }
+ b2Body* get_bodyA(b2Body* b) { return bodyA; }
+ b2Body* get_bodyB(b2Body* b) { return bodyB; }
+ bool get_collideConnected(bool b) { return collideConnected; }
+};
+
+/// A mouse joint is used to make a point on a body track a
+/// specified world point. This a soft constraint with a maximum
+/// force. This allows the constraint to stretch and without
+/// applying huge forces.
+/// NOTE: this joint is not documented in the manual because it was
+/// developed to be used in the testbed. If you want to learn how to
+/// use the mouse joint, look at the testbed.
+// emscripten - b2MouseJoint: make constructor public
+class b2MouseJoint : public b2Joint
+{
+public:
+
+ /// Implements b2Joint.
+ b2Vec2 GetAnchorA() const;
+
+ /// Implements b2Joint.
+ b2Vec2 GetAnchorB() const;
+
+ /// Implements b2Joint.
+ b2Vec2 GetReactionForce(float32 inv_dt) const;
+
+ /// Implements b2Joint.
+ float32 GetReactionTorque(float32 inv_dt) const;
+
+ /// Use this to update the target point.
+ void SetTarget(const b2Vec2& target);
+ const b2Vec2& GetTarget() const;
+
+ /// Set/get the maximum force in Newtons.
+ void SetMaxForce(float32 force);
+ float32 GetMaxForce() const;
+
+ /// Set/get the frequency in Hertz.
+ void SetFrequency(float32 hz);
+ float32 GetFrequency() const;
+
+ /// Set/get the damping ratio (dimensionless).
+ void SetDampingRatio(float32 ratio);
+ float32 GetDampingRatio() const;
+
+ /// The mouse joint does not support dumping.
+ void Dump() { b2Log("Mouse joint dumping is not supported.\n"); }
+
+ b2MouseJoint(const b2MouseJointDef* def);
+
+protected:
+ friend class b2Joint;
+
+ void InitVelocityConstraints(const b2SolverData& data);
+ void SolveVelocityConstraints(const b2SolverData& data);
+ bool SolvePositionConstraints(const b2SolverData& data);
+
+ b2Vec2 m_localAnchorB;
+ b2Vec2 m_targetA;
+ float32 m_frequencyHz;
+ float32 m_dampingRatio;
+ float32 m_beta;
+
+ // Solver shared
+ b2Vec2 m_impulse;
+ float32 m_maxForce;
+ float32 m_gamma;
+
+ // Solver temp
+ int32 m_indexA;
+ int32 m_indexB;
+ b2Vec2 m_rB;
+ b2Vec2 m_localCenterB;
+ float32 m_invMassB;
+ float32 m_invIB;
+ b2Mat22 m_mass;
+ b2Vec2 m_C;
+};
+
+#endif
diff --git a/tests/box2d/Box2D/Dynamics/Joints/b2PrismaticJoint.cpp b/tests/box2d/Box2D/Dynamics/Joints/b2PrismaticJoint.cpp new file mode 100755 index 00000000..88a38807 --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Joints/b2PrismaticJoint.cpp @@ -0,0 +1,637 @@ +/*
+* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Dynamics/Joints/b2PrismaticJoint.h>
+#include <Box2D/Dynamics/b2Body.h>
+#include <Box2D/Dynamics/b2TimeStep.h>
+
+// Linear constraint (point-to-line)
+// d = p2 - p1 = x2 + r2 - x1 - r1
+// C = dot(perp, d)
+// Cdot = dot(d, cross(w1, perp)) + dot(perp, v2 + cross(w2, r2) - v1 - cross(w1, r1))
+// = -dot(perp, v1) - dot(cross(d + r1, perp), w1) + dot(perp, v2) + dot(cross(r2, perp), v2)
+// J = [-perp, -cross(d + r1, perp), perp, cross(r2,perp)]
+//
+// Angular constraint
+// C = a2 - a1 + a_initial
+// Cdot = w2 - w1
+// J = [0 0 -1 0 0 1]
+//
+// K = J * invM * JT
+//
+// J = [-a -s1 a s2]
+// [0 -1 0 1]
+// a = perp
+// s1 = cross(d + r1, a) = cross(p2 - x1, a)
+// s2 = cross(r2, a) = cross(p2 - x2, a)
+
+
+// Motor/Limit linear constraint
+// C = dot(ax1, d)
+// Cdot = = -dot(ax1, v1) - dot(cross(d + r1, ax1), w1) + dot(ax1, v2) + dot(cross(r2, ax1), v2)
+// J = [-ax1 -cross(d+r1,ax1) ax1 cross(r2,ax1)]
+
+// Block Solver
+// We develop a block solver that includes the joint limit. This makes the limit stiff (inelastic) even
+// when the mass has poor distribution (leading to large torques about the joint anchor points).
+//
+// The Jacobian has 3 rows:
+// J = [-uT -s1 uT s2] // linear
+// [0 -1 0 1] // angular
+// [-vT -a1 vT a2] // limit
+//
+// u = perp
+// v = axis
+// s1 = cross(d + r1, u), s2 = cross(r2, u)
+// a1 = cross(d + r1, v), a2 = cross(r2, v)
+
+// M * (v2 - v1) = JT * df
+// J * v2 = bias
+//
+// v2 = v1 + invM * JT * df
+// J * (v1 + invM * JT * df) = bias
+// K * df = bias - J * v1 = -Cdot
+// K = J * invM * JT
+// Cdot = J * v1 - bias
+//
+// Now solve for f2.
+// df = f2 - f1
+// K * (f2 - f1) = -Cdot
+// f2 = invK * (-Cdot) + f1
+//
+// Clamp accumulated limit impulse.
+// lower: f2(3) = max(f2(3), 0)
+// upper: f2(3) = min(f2(3), 0)
+//
+// Solve for correct f2(1:2)
+// K(1:2, 1:2) * f2(1:2) = -Cdot(1:2) - K(1:2,3) * f2(3) + K(1:2,1:3) * f1
+// = -Cdot(1:2) - K(1:2,3) * f2(3) + K(1:2,1:2) * f1(1:2) + K(1:2,3) * f1(3)
+// K(1:2, 1:2) * f2(1:2) = -Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3)) + K(1:2,1:2) * f1(1:2)
+// f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2)
+//
+// Now compute impulse to be applied:
+// df = f2 - f1
+
+void b2PrismaticJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor, const b2Vec2& axis)
+{
+ bodyA = bA;
+ bodyB = bB;
+ localAnchorA = bodyA->GetLocalPoint(anchor);
+ localAnchorB = bodyB->GetLocalPoint(anchor);
+ localAxisA = bodyA->GetLocalVector(axis);
+ referenceAngle = bodyB->GetAngle() - bodyA->GetAngle();
+}
+
+b2PrismaticJoint::b2PrismaticJoint(const b2PrismaticJointDef* def)
+: b2Joint(def)
+{
+ m_localAnchorA = def->localAnchorA;
+ m_localAnchorB = def->localAnchorB;
+ m_localXAxisA = def->localAxisA;
+ m_localXAxisA.Normalize();
+ m_localYAxisA = b2Cross(1.0f, m_localXAxisA);
+ m_referenceAngle = def->referenceAngle;
+
+ m_impulse.SetZero();
+ m_motorMass = 0.0;
+ m_motorImpulse = 0.0f;
+
+ m_lowerTranslation = def->lowerTranslation;
+ m_upperTranslation = def->upperTranslation;
+ m_maxMotorForce = def->maxMotorForce;
+ m_motorSpeed = def->motorSpeed;
+ m_enableLimit = def->enableLimit;
+ m_enableMotor = def->enableMotor;
+ m_limitState = e_inactiveLimit;
+
+ m_axis.SetZero();
+ m_perp.SetZero();
+}
+
+void b2PrismaticJoint::InitVelocityConstraints(const b2SolverData& data)
+{
+ m_indexA = m_bodyA->m_islandIndex;
+ m_indexB = m_bodyB->m_islandIndex;
+ m_localCenterA = m_bodyA->m_sweep.localCenter;
+ m_localCenterB = m_bodyB->m_sweep.localCenter;
+ m_invMassA = m_bodyA->m_invMass;
+ m_invMassB = m_bodyB->m_invMass;
+ m_invIA = m_bodyA->m_invI;
+ m_invIB = m_bodyB->m_invI;
+
+ b2Vec2 cA = data.positions[m_indexA].c;
+ float32 aA = data.positions[m_indexA].a;
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+
+ b2Vec2 cB = data.positions[m_indexB].c;
+ float32 aB = data.positions[m_indexB].a;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ b2Rot qA(aA), qB(aB);
+
+ // Compute the effective masses.
+ b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
+ b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
+ b2Vec2 d = (cB - cA) + rB - rA;
+
+ float32 mA = m_invMassA, mB = m_invMassB;
+ float32 iA = m_invIA, iB = m_invIB;
+
+ // Compute motor Jacobian and effective mass.
+ {
+ m_axis = b2Mul(qA, m_localXAxisA);
+ m_a1 = b2Cross(d + rA, m_axis);
+ m_a2 = b2Cross(rB, m_axis);
+
+ m_motorMass = mA + mB + iA * m_a1 * m_a1 + iB * m_a2 * m_a2;
+ if (m_motorMass > 0.0f)
+ {
+ m_motorMass = 1.0f / m_motorMass;
+ }
+ }
+
+ // Prismatic constraint.
+ {
+ m_perp = b2Mul(qA, m_localYAxisA);
+
+ m_s1 = b2Cross(d + rA, m_perp);
+ m_s2 = b2Cross(rB, m_perp);
+
+ float32 k11 = mA + mB + iA * m_s1 * m_s1 + iB * m_s2 * m_s2;
+ float32 k12 = iA * m_s1 + iB * m_s2;
+ float32 k13 = iA * m_s1 * m_a1 + iB * m_s2 * m_a2;
+ float32 k22 = iA + iB;
+ if (k22 == 0.0f)
+ {
+ // For bodies with fixed rotation.
+ k22 = 1.0f;
+ }
+ float32 k23 = iA * m_a1 + iB * m_a2;
+ float32 k33 = mA + mB + iA * m_a1 * m_a1 + iB * m_a2 * m_a2;
+
+ m_K.ex.Set(k11, k12, k13);
+ m_K.ey.Set(k12, k22, k23);
+ m_K.ez.Set(k13, k23, k33);
+ }
+
+ // Compute motor and limit terms.
+ if (m_enableLimit)
+ {
+ float32 jointTranslation = b2Dot(m_axis, d);
+ if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop)
+ {
+ m_limitState = e_equalLimits;
+ }
+ else if (jointTranslation <= m_lowerTranslation)
+ {
+ if (m_limitState != e_atLowerLimit)
+ {
+ m_limitState = e_atLowerLimit;
+ m_impulse.z = 0.0f;
+ }
+ }
+ else if (jointTranslation >= m_upperTranslation)
+ {
+ if (m_limitState != e_atUpperLimit)
+ {
+ m_limitState = e_atUpperLimit;
+ m_impulse.z = 0.0f;
+ }
+ }
+ else
+ {
+ m_limitState = e_inactiveLimit;
+ m_impulse.z = 0.0f;
+ }
+ }
+ else
+ {
+ m_limitState = e_inactiveLimit;
+ m_impulse.z = 0.0f;
+ }
+
+ if (m_enableMotor == false)
+ {
+ m_motorImpulse = 0.0f;
+ }
+
+ if (data.step.warmStarting)
+ {
+ // Account for variable time step.
+ m_impulse *= data.step.dtRatio;
+ m_motorImpulse *= data.step.dtRatio;
+
+ b2Vec2 P = m_impulse.x * m_perp + (m_motorImpulse + m_impulse.z) * m_axis;
+ float32 LA = m_impulse.x * m_s1 + m_impulse.y + (m_motorImpulse + m_impulse.z) * m_a1;
+ float32 LB = m_impulse.x * m_s2 + m_impulse.y + (m_motorImpulse + m_impulse.z) * m_a2;
+
+ vA -= mA * P;
+ wA -= iA * LA;
+
+ vB += mB * P;
+ wB += iB * LB;
+ }
+ else
+ {
+ m_impulse.SetZero();
+ m_motorImpulse = 0.0f;
+ }
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+void b2PrismaticJoint::SolveVelocityConstraints(const b2SolverData& data)
+{
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ float32 mA = m_invMassA, mB = m_invMassB;
+ float32 iA = m_invIA, iB = m_invIB;
+
+ // Solve linear motor constraint.
+ if (m_enableMotor && m_limitState != e_equalLimits)
+ {
+ float32 Cdot = b2Dot(m_axis, vB - vA) + m_a2 * wB - m_a1 * wA;
+ float32 impulse = m_motorMass * (m_motorSpeed - Cdot);
+ float32 oldImpulse = m_motorImpulse;
+ float32 maxImpulse = data.step.dt * m_maxMotorForce;
+ m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse);
+ impulse = m_motorImpulse - oldImpulse;
+
+ b2Vec2 P = impulse * m_axis;
+ float32 LA = impulse * m_a1;
+ float32 LB = impulse * m_a2;
+
+ vA -= mA * P;
+ wA -= iA * LA;
+
+ vB += mB * P;
+ wB += iB * LB;
+ }
+
+ b2Vec2 Cdot1;
+ Cdot1.x = b2Dot(m_perp, vB - vA) + m_s2 * wB - m_s1 * wA;
+ Cdot1.y = wB - wA;
+
+ if (m_enableLimit && m_limitState != e_inactiveLimit)
+ {
+ // Solve prismatic and limit constraint in block form.
+ float32 Cdot2;
+ Cdot2 = b2Dot(m_axis, vB - vA) + m_a2 * wB - m_a1 * wA;
+ b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2);
+
+ b2Vec3 f1 = m_impulse;
+ b2Vec3 df = m_K.Solve33(-Cdot);
+ m_impulse += df;
+
+ if (m_limitState == e_atLowerLimit)
+ {
+ m_impulse.z = b2Max(m_impulse.z, 0.0f);
+ }
+ else if (m_limitState == e_atUpperLimit)
+ {
+ m_impulse.z = b2Min(m_impulse.z, 0.0f);
+ }
+
+ // f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2)
+ b2Vec2 b = -Cdot1 - (m_impulse.z - f1.z) * b2Vec2(m_K.ez.x, m_K.ez.y);
+ b2Vec2 f2r = m_K.Solve22(b) + b2Vec2(f1.x, f1.y);
+ m_impulse.x = f2r.x;
+ m_impulse.y = f2r.y;
+
+ df = m_impulse - f1;
+
+ b2Vec2 P = df.x * m_perp + df.z * m_axis;
+ float32 LA = df.x * m_s1 + df.y + df.z * m_a1;
+ float32 LB = df.x * m_s2 + df.y + df.z * m_a2;
+
+ vA -= mA * P;
+ wA -= iA * LA;
+
+ vB += mB * P;
+ wB += iB * LB;
+ }
+ else
+ {
+ // Limit is inactive, just solve the prismatic constraint in block form.
+ b2Vec2 df = m_K.Solve22(-Cdot1);
+ m_impulse.x += df.x;
+ m_impulse.y += df.y;
+
+ b2Vec2 P = df.x * m_perp;
+ float32 LA = df.x * m_s1 + df.y;
+ float32 LB = df.x * m_s2 + df.y;
+
+ vA -= mA * P;
+ wA -= iA * LA;
+
+ vB += mB * P;
+ wB += iB * LB;
+
+ b2Vec2 Cdot10 = Cdot1;
+
+ Cdot1.x = b2Dot(m_perp, vB - vA) + m_s2 * wB - m_s1 * wA;
+ Cdot1.y = wB - wA;
+
+ if (b2Abs(Cdot1.x) > 0.01f || b2Abs(Cdot1.y) > 0.01f)
+ {
+ b2Vec2 test = b2Mul22(m_K, df);
+ Cdot1.x += 0.0f;
+ }
+ }
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+bool b2PrismaticJoint::SolvePositionConstraints(const b2SolverData& data)
+{
+ b2Vec2 cA = data.positions[m_indexA].c;
+ float32 aA = data.positions[m_indexA].a;
+ b2Vec2 cB = data.positions[m_indexB].c;
+ float32 aB = data.positions[m_indexB].a;
+
+ b2Rot qA(aA), qB(aB);
+
+ float32 mA = m_invMassA, mB = m_invMassB;
+ float32 iA = m_invIA, iB = m_invIB;
+
+ // Compute fresh Jacobians
+ b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
+ b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
+ b2Vec2 d = cB + rB - cA - rA;
+
+ b2Vec2 axis = b2Mul(qA, m_localXAxisA);
+ float32 a1 = b2Cross(d + rA, axis);
+ float32 a2 = b2Cross(rB, axis);
+ b2Vec2 perp = b2Mul(qA, m_localYAxisA);
+
+ float32 s1 = b2Cross(d + rA, perp);
+ float32 s2 = b2Cross(rB, perp);
+
+ b2Vec3 impulse;
+ b2Vec2 C1;
+ C1.x = b2Dot(perp, d);
+ C1.y = aB - aA - m_referenceAngle;
+
+ float32 linearError = b2Abs(C1.x);
+ float32 angularError = b2Abs(C1.y);
+
+ bool active = false;
+ float32 C2 = 0.0f;
+ if (m_enableLimit)
+ {
+ float32 translation = b2Dot(axis, d);
+ if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop)
+ {
+ // Prevent large angular corrections
+ C2 = b2Clamp(translation, -b2_maxLinearCorrection, b2_maxLinearCorrection);
+ linearError = b2Max(linearError, b2Abs(translation));
+ active = true;
+ }
+ else if (translation <= m_lowerTranslation)
+ {
+ // Prevent large linear corrections and allow some slop.
+ C2 = b2Clamp(translation - m_lowerTranslation + b2_linearSlop, -b2_maxLinearCorrection, 0.0f);
+ linearError = b2Max(linearError, m_lowerTranslation - translation);
+ active = true;
+ }
+ else if (translation >= m_upperTranslation)
+ {
+ // Prevent large linear corrections and allow some slop.
+ C2 = b2Clamp(translation - m_upperTranslation - b2_linearSlop, 0.0f, b2_maxLinearCorrection);
+ linearError = b2Max(linearError, translation - m_upperTranslation);
+ active = true;
+ }
+ }
+
+ if (active)
+ {
+ float32 k11 = mA + mB + iA * s1 * s1 + iB * s2 * s2;
+ float32 k12 = iA * s1 + iB * s2;
+ float32 k13 = iA * s1 * a1 + iB * s2 * a2;
+ float32 k22 = iA + iB;
+ if (k22 == 0.0f)
+ {
+ // For fixed rotation
+ k22 = 1.0f;
+ }
+ float32 k23 = iA * a1 + iB * a2;
+ float32 k33 = mA + mB + iA * a1 * a1 + iB * a2 * a2;
+
+ b2Mat33 K;
+ K.ex.Set(k11, k12, k13);
+ K.ey.Set(k12, k22, k23);
+ K.ez.Set(k13, k23, k33);
+
+ b2Vec3 C;
+ C.x = C1.x;
+ C.y = C1.y;
+ C.z = C2;
+
+ impulse = K.Solve33(-C);
+ }
+ else
+ {
+ float32 k11 = mA + mB + iA * s1 * s1 + iB * s2 * s2;
+ float32 k12 = iA * s1 + iB * s2;
+ float32 k22 = iA + iB;
+ if (k22 == 0.0f)
+ {
+ k22 = 1.0f;
+ }
+
+ b2Mat22 K;
+ K.ex.Set(k11, k12);
+ K.ey.Set(k12, k22);
+
+ b2Vec2 impulse1 = K.Solve(-C1);
+ impulse.x = impulse1.x;
+ impulse.y = impulse1.y;
+ impulse.z = 0.0f;
+ }
+
+ b2Vec2 P = impulse.x * perp + impulse.z * axis;
+ float32 LA = impulse.x * s1 + impulse.y + impulse.z * a1;
+ float32 LB = impulse.x * s2 + impulse.y + impulse.z * a2;
+
+ cA -= mA * P;
+ aA -= iA * LA;
+ cB += mB * P;
+ aB += iB * LB;
+
+ data.positions[m_indexA].c = cA;
+ data.positions[m_indexA].a = aA;
+ data.positions[m_indexB].c = cB;
+ data.positions[m_indexB].a = aB;
+
+ return linearError <= b2_linearSlop && angularError <= b2_angularSlop;
+}
+
+b2Vec2 b2PrismaticJoint::GetAnchorA() const
+{
+ return m_bodyA->GetWorldPoint(m_localAnchorA);
+}
+
+b2Vec2 b2PrismaticJoint::GetAnchorB() const
+{
+ return m_bodyB->GetWorldPoint(m_localAnchorB);
+}
+
+b2Vec2 b2PrismaticJoint::GetReactionForce(float32 inv_dt) const
+{
+ return inv_dt * (m_impulse.x * m_perp + (m_motorImpulse + m_impulse.z) * m_axis);
+}
+
+float32 b2PrismaticJoint::GetReactionTorque(float32 inv_dt) const
+{
+ return inv_dt * m_impulse.y;
+}
+
+float32 b2PrismaticJoint::GetJointTranslation() const
+{
+ b2Vec2 pA = m_bodyA->GetWorldPoint(m_localAnchorA);
+ b2Vec2 pB = m_bodyB->GetWorldPoint(m_localAnchorB);
+ b2Vec2 d = pB - pA;
+ b2Vec2 axis = m_bodyA->GetWorldVector(m_localXAxisA);
+
+ float32 translation = b2Dot(d, axis);
+ return translation;
+}
+
+float32 b2PrismaticJoint::GetJointSpeed() const
+{
+ b2Body* bA = m_bodyA;
+ b2Body* bB = m_bodyB;
+
+ b2Vec2 rA = b2Mul(bA->m_xf.q, m_localAnchorA - bA->m_sweep.localCenter);
+ b2Vec2 rB = b2Mul(bB->m_xf.q, m_localAnchorB - bB->m_sweep.localCenter);
+ b2Vec2 p1 = bA->m_sweep.c + rA;
+ b2Vec2 p2 = bB->m_sweep.c + rB;
+ b2Vec2 d = p2 - p1;
+ b2Vec2 axis = b2Mul(bA->m_xf.q, m_localXAxisA);
+
+ b2Vec2 vA = bA->m_linearVelocity;
+ b2Vec2 vB = bB->m_linearVelocity;
+ float32 wA = bA->m_angularVelocity;
+ float32 wB = bB->m_angularVelocity;
+
+ float32 speed = b2Dot(d, b2Cross(wA, axis)) + b2Dot(axis, vB + b2Cross(wB, rB) - vA - b2Cross(wA, rA));
+ return speed;
+}
+
+bool b2PrismaticJoint::IsLimitEnabled() const
+{
+ return m_enableLimit;
+}
+
+void b2PrismaticJoint::EnableLimit(bool flag)
+{
+ if (flag != m_enableLimit)
+ {
+ m_bodyA->SetAwake(true);
+ m_bodyB->SetAwake(true);
+ m_enableLimit = flag;
+ m_impulse.z = 0.0f;
+ }
+}
+
+float32 b2PrismaticJoint::GetLowerLimit() const
+{
+ return m_lowerTranslation;
+}
+
+float32 b2PrismaticJoint::GetUpperLimit() const
+{
+ return m_upperTranslation;
+}
+
+void b2PrismaticJoint::SetLimits(float32 lower, float32 upper)
+{
+ b2Assert(lower <= upper);
+ if (lower != m_lowerTranslation || upper != m_upperTranslation)
+ {
+ m_bodyA->SetAwake(true);
+ m_bodyB->SetAwake(true);
+ m_lowerTranslation = lower;
+ m_upperTranslation = upper;
+ m_impulse.z = 0.0f;
+ }
+}
+
+bool b2PrismaticJoint::IsMotorEnabled() const
+{
+ return m_enableMotor;
+}
+
+void b2PrismaticJoint::EnableMotor(bool flag)
+{
+ m_bodyA->SetAwake(true);
+ m_bodyB->SetAwake(true);
+ m_enableMotor = flag;
+}
+
+void b2PrismaticJoint::SetMotorSpeed(float32 speed)
+{
+ m_bodyA->SetAwake(true);
+ m_bodyB->SetAwake(true);
+ m_motorSpeed = speed;
+}
+
+void b2PrismaticJoint::SetMaxMotorForce(float32 force)
+{
+ m_bodyA->SetAwake(true);
+ m_bodyB->SetAwake(true);
+ m_maxMotorForce = force;
+}
+
+float32 b2PrismaticJoint::GetMotorForce(float32 inv_dt) const
+{
+ return inv_dt * m_motorImpulse;
+}
+
+void b2PrismaticJoint::Dump()
+{
+ int32 indexA = m_bodyA->m_islandIndex;
+ int32 indexB = m_bodyB->m_islandIndex;
+
+ b2Log(" b2PrismaticJointDef jd;\n");
+ b2Log(" jd.bodyA = bodies[%d];\n", indexA);
+ b2Log(" jd.bodyB = bodies[%d];\n", indexB);
+ b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
+ b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y);
+ b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y);
+ b2Log(" jd.localAxisA.Set(%.15lef, %.15lef);\n", m_localXAxisA.x, m_localXAxisA.y);
+ b2Log(" jd.referenceAngle = %.15lef;\n", m_referenceAngle);
+ b2Log(" jd.enableLimit = bool(%d);\n", m_enableLimit);
+ b2Log(" jd.lowerTranslation = %.15lef;\n", m_lowerTranslation);
+ b2Log(" jd.upperTranslation = %.15lef;\n", m_upperTranslation);
+ b2Log(" jd.enableMotor = bool(%d);\n", m_enableMotor);
+ b2Log(" jd.motorSpeed = %.15lef;\n", m_motorSpeed);
+ b2Log(" jd.maxMotorForce = %.15lef;\n", m_maxMotorForce);
+ b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
+}
diff --git a/tests/box2d/Box2D/Dynamics/Joints/b2PrismaticJoint.h b/tests/box2d/Box2D/Dynamics/Joints/b2PrismaticJoint.h new file mode 100755 index 00000000..b1b50a88 --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Joints/b2PrismaticJoint.h @@ -0,0 +1,207 @@ +/*
+* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_PRISMATIC_JOINT_H
+#define B2_PRISMATIC_JOINT_H
+
+#include <Box2D/Dynamics/Joints/b2Joint.h>
+
+/// Prismatic joint definition. This requires defining a line of
+/// motion using an axis and an anchor point. The definition uses local
+/// anchor points and a local axis so that the initial configuration
+/// can violate the constraint slightly. The joint translation is zero
+/// when the local anchor points coincide in world space. Using local
+/// anchors and a local axis helps when saving and loading a game.
+// emscripten - b2PrismaticJointDef: add functions to set/get base class members
+struct b2PrismaticJointDef : public b2JointDef
+{
+ b2PrismaticJointDef()
+ {
+ type = e_prismaticJoint;
+ localAnchorA.SetZero();
+ localAnchorB.SetZero();
+ localAxisA.Set(1.0f, 0.0f);
+ referenceAngle = 0.0f;
+ enableLimit = false;
+ lowerTranslation = 0.0f;
+ upperTranslation = 0.0f;
+ enableMotor = false;
+ maxMotorForce = 0.0f;
+ motorSpeed = 0.0f;
+ }
+
+ /// Initialize the bodies, anchors, axis, and reference angle using the world
+ /// anchor and unit world axis.
+ void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor, const b2Vec2& axis);
+
+ /// The local anchor point relative to bodyA's origin.
+ b2Vec2 localAnchorA;
+
+ /// The local anchor point relative to bodyB's origin.
+ b2Vec2 localAnchorB;
+
+ /// The local translation unit axis in bodyA.
+ b2Vec2 localAxisA;
+
+ /// The constrained angle between the bodies: bodyB_angle - bodyA_angle.
+ float32 referenceAngle;
+
+ /// Enable/disable the joint limit.
+ bool enableLimit;
+
+ /// The lower translation limit, usually in meters.
+ float32 lowerTranslation;
+
+ /// The upper translation limit, usually in meters.
+ float32 upperTranslation;
+
+ /// Enable/disable the joint motor.
+ bool enableMotor;
+
+ /// The maximum motor torque, usually in N-m.
+ float32 maxMotorForce;
+
+ /// The desired motor speed in radians per second.
+ float32 motorSpeed;
+
+ // to generate javascript bindings
+ void set_bodyA(b2Body* b) { bodyA = b; }
+ void set_bodyB(b2Body* b) { bodyB = b; }
+ void set_collideConnected(bool b) { collideConnected = b; }
+ b2Body* get_bodyA(b2Body* b) { return bodyA; }
+ b2Body* get_bodyB(b2Body* b) { return bodyB; }
+ bool get_collideConnected(bool b) { return collideConnected; }
+};
+
+/// A prismatic joint. This joint provides one degree of freedom: translation
+/// along an axis fixed in bodyA. Relative rotation is prevented. You can
+/// use a joint limit to restrict the range of motion and a joint motor to
+/// drive the motion or to model joint friction.
+// emscripten - b2PrismaticJoint: make constructor public
+class b2PrismaticJoint : public b2Joint
+{
+public:
+ b2Vec2 GetAnchorA() const;
+ b2Vec2 GetAnchorB() const;
+
+ b2Vec2 GetReactionForce(float32 inv_dt) const;
+ float32 GetReactionTorque(float32 inv_dt) const;
+
+ /// The local anchor point relative to bodyA's origin.
+ const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; }
+
+ /// The local anchor point relative to bodyB's origin.
+ const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; }
+
+ /// The local joint axis relative to bodyA.
+ const b2Vec2& GetLocalAxisA() const { return m_localXAxisA; }
+
+ /// Get the reference angle.
+ float32 GetReferenceAngle() const { return m_referenceAngle; }
+
+ /// Get the current joint translation, usually in meters.
+ float32 GetJointTranslation() const;
+
+ /// Get the current joint translation speed, usually in meters per second.
+ float32 GetJointSpeed() const;
+
+ /// Is the joint limit enabled?
+ bool IsLimitEnabled() const;
+
+ /// Enable/disable the joint limit.
+ void EnableLimit(bool flag);
+
+ /// Get the lower joint limit, usually in meters.
+ float32 GetLowerLimit() const;
+
+ /// Get the upper joint limit, usually in meters.
+ float32 GetUpperLimit() const;
+
+ /// Set the joint limits, usually in meters.
+ void SetLimits(float32 lower, float32 upper);
+
+ /// Is the joint motor enabled?
+ bool IsMotorEnabled() const;
+
+ /// Enable/disable the joint motor.
+ void EnableMotor(bool flag);
+
+ /// Set the motor speed, usually in meters per second.
+ void SetMotorSpeed(float32 speed);
+
+ /// Get the motor speed, usually in meters per second.
+ float32 GetMotorSpeed() const;
+
+ /// Set the maximum motor force, usually in N.
+ void SetMaxMotorForce(float32 force);
+ float32 GetMaxMotorForce() const { return m_maxMotorForce; }
+
+ /// Get the current motor force given the inverse time step, usually in N.
+ float32 GetMotorForce(float32 inv_dt) const;
+
+ /// Dump to b2Log
+ void Dump();
+
+ b2PrismaticJoint(const b2PrismaticJointDef* def);
+
+protected:
+ friend class b2Joint;
+ friend class b2GearJoint;
+
+ void InitVelocityConstraints(const b2SolverData& data);
+ void SolveVelocityConstraints(const b2SolverData& data);
+ bool SolvePositionConstraints(const b2SolverData& data);
+
+ // Solver shared
+ b2Vec2 m_localAnchorA;
+ b2Vec2 m_localAnchorB;
+ b2Vec2 m_localXAxisA;
+ b2Vec2 m_localYAxisA;
+ float32 m_referenceAngle;
+ b2Vec3 m_impulse;
+ float32 m_motorImpulse;
+ float32 m_lowerTranslation;
+ float32 m_upperTranslation;
+ float32 m_maxMotorForce;
+ float32 m_motorSpeed;
+ bool m_enableLimit;
+ bool m_enableMotor;
+ b2LimitState m_limitState;
+
+ // Solver temp
+ int32 m_indexA;
+ int32 m_indexB;
+ b2Vec2 m_localCenterA;
+ b2Vec2 m_localCenterB;
+ float32 m_invMassA;
+ float32 m_invMassB;
+ float32 m_invIA;
+ float32 m_invIB;
+ b2Vec2 m_axis, m_perp;
+ float32 m_s1, m_s2;
+ float32 m_a1, m_a2;
+ b2Mat33 m_K;
+ float32 m_motorMass;
+};
+
+inline float32 b2PrismaticJoint::GetMotorSpeed() const
+{
+ return m_motorSpeed;
+}
+
+#endif
diff --git a/tests/box2d/Box2D/Dynamics/Joints/b2PulleyJoint.cpp b/tests/box2d/Box2D/Dynamics/Joints/b2PulleyJoint.cpp new file mode 100755 index 00000000..e0bb7da5 --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Joints/b2PulleyJoint.cpp @@ -0,0 +1,332 @@ +/*
+* Copyright (c) 2007 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Dynamics/Joints/b2PulleyJoint.h>
+#include <Box2D/Dynamics/b2Body.h>
+#include <Box2D/Dynamics/b2TimeStep.h>
+
+// Pulley:
+// length1 = norm(p1 - s1)
+// length2 = norm(p2 - s2)
+// C0 = (length1 + ratio * length2)_initial
+// C = C0 - (length1 + ratio * length2)
+// u1 = (p1 - s1) / norm(p1 - s1)
+// u2 = (p2 - s2) / norm(p2 - s2)
+// Cdot = -dot(u1, v1 + cross(w1, r1)) - ratio * dot(u2, v2 + cross(w2, r2))
+// J = -[u1 cross(r1, u1) ratio * u2 ratio * cross(r2, u2)]
+// K = J * invM * JT
+// = invMass1 + invI1 * cross(r1, u1)^2 + ratio^2 * (invMass2 + invI2 * cross(r2, u2)^2)
+
+void b2PulleyJointDef::Initialize(b2Body* bA, b2Body* bB,
+ const b2Vec2& groundA, const b2Vec2& groundB,
+ const b2Vec2& anchorA, const b2Vec2& anchorB,
+ float32 r)
+{
+ bodyA = bA;
+ bodyB = bB;
+ groundAnchorA = groundA;
+ groundAnchorB = groundB;
+ localAnchorA = bodyA->GetLocalPoint(anchorA);
+ localAnchorB = bodyB->GetLocalPoint(anchorB);
+ b2Vec2 dA = anchorA - groundA;
+ lengthA = dA.Length();
+ b2Vec2 dB = anchorB - groundB;
+ lengthB = dB.Length();
+ ratio = r;
+ b2Assert(ratio > b2_epsilon);
+}
+
+b2PulleyJoint::b2PulleyJoint(const b2PulleyJointDef* def)
+: b2Joint(def)
+{
+ m_groundAnchorA = def->groundAnchorA;
+ m_groundAnchorB = def->groundAnchorB;
+ m_localAnchorA = def->localAnchorA;
+ m_localAnchorB = def->localAnchorB;
+
+ m_lengthA = def->lengthA;
+ m_lengthB = def->lengthB;
+
+ b2Assert(def->ratio != 0.0f);
+ m_ratio = def->ratio;
+
+ m_constant = def->lengthA + m_ratio * def->lengthB;
+
+ m_impulse = 0.0f;
+}
+
+void b2PulleyJoint::InitVelocityConstraints(const b2SolverData& data)
+{
+ m_indexA = m_bodyA->m_islandIndex;
+ m_indexB = m_bodyB->m_islandIndex;
+ m_localCenterA = m_bodyA->m_sweep.localCenter;
+ m_localCenterB = m_bodyB->m_sweep.localCenter;
+ m_invMassA = m_bodyA->m_invMass;
+ m_invMassB = m_bodyB->m_invMass;
+ m_invIA = m_bodyA->m_invI;
+ m_invIB = m_bodyB->m_invI;
+
+ b2Vec2 cA = data.positions[m_indexA].c;
+ float32 aA = data.positions[m_indexA].a;
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+
+ b2Vec2 cB = data.positions[m_indexB].c;
+ float32 aB = data.positions[m_indexB].a;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ b2Rot qA(aA), qB(aB);
+
+ m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
+ m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
+
+ // Get the pulley axes.
+ m_uA = cA + m_rA - m_groundAnchorA;
+ m_uB = cB + m_rB - m_groundAnchorB;
+
+ float32 lengthA = m_uA.Length();
+ float32 lengthB = m_uB.Length();
+
+ if (lengthA > 10.0f * b2_linearSlop)
+ {
+ m_uA *= 1.0f / lengthA;
+ }
+ else
+ {
+ m_uA.SetZero();
+ }
+
+ if (lengthB > 10.0f * b2_linearSlop)
+ {
+ m_uB *= 1.0f / lengthB;
+ }
+ else
+ {
+ m_uB.SetZero();
+ }
+
+ // Compute effective mass.
+ float32 ruA = b2Cross(m_rA, m_uA);
+ float32 ruB = b2Cross(m_rB, m_uB);
+
+ float32 mA = m_invMassA + m_invIA * ruA * ruA;
+ float32 mB = m_invMassB + m_invIB * ruB * ruB;
+
+ m_mass = mA + m_ratio * m_ratio * mB;
+
+ if (m_mass > 0.0f)
+ {
+ m_mass = 1.0f / m_mass;
+ }
+
+ if (data.step.warmStarting)
+ {
+ // Scale impulses to support variable time steps.
+ m_impulse *= data.step.dtRatio;
+
+ // Warm starting.
+ b2Vec2 PA = -(m_impulse) * m_uA;
+ b2Vec2 PB = (-m_ratio * m_impulse) * m_uB;
+
+ vA += m_invMassA * PA;
+ wA += m_invIA * b2Cross(m_rA, PA);
+ vB += m_invMassB * PB;
+ wB += m_invIB * b2Cross(m_rB, PB);
+ }
+ else
+ {
+ m_impulse = 0.0f;
+ }
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+void b2PulleyJoint::SolveVelocityConstraints(const b2SolverData& data)
+{
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ b2Vec2 vpA = vA + b2Cross(wA, m_rA);
+ b2Vec2 vpB = vB + b2Cross(wB, m_rB);
+
+ float32 Cdot = -b2Dot(m_uA, vpA) - m_ratio * b2Dot(m_uB, vpB);
+ float32 impulse = -m_mass * Cdot;
+ m_impulse += impulse;
+
+ b2Vec2 PA = -impulse * m_uA;
+ b2Vec2 PB = -m_ratio * impulse * m_uB;
+ vA += m_invMassA * PA;
+ wA += m_invIA * b2Cross(m_rA, PA);
+ vB += m_invMassB * PB;
+ wB += m_invIB * b2Cross(m_rB, PB);
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+bool b2PulleyJoint::SolvePositionConstraints(const b2SolverData& data)
+{
+ b2Vec2 cA = data.positions[m_indexA].c;
+ float32 aA = data.positions[m_indexA].a;
+ b2Vec2 cB = data.positions[m_indexB].c;
+ float32 aB = data.positions[m_indexB].a;
+
+ b2Rot qA(aA), qB(aB);
+
+ b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
+ b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
+
+ // Get the pulley axes.
+ b2Vec2 uA = cA + rA - m_groundAnchorA;
+ b2Vec2 uB = cB + rB - m_groundAnchorB;
+
+ float32 lengthA = uA.Length();
+ float32 lengthB = uB.Length();
+
+ if (lengthA > 10.0f * b2_linearSlop)
+ {
+ uA *= 1.0f / lengthA;
+ }
+ else
+ {
+ uA.SetZero();
+ }
+
+ if (lengthB > 10.0f * b2_linearSlop)
+ {
+ uB *= 1.0f / lengthB;
+ }
+ else
+ {
+ uB.SetZero();
+ }
+
+ // Compute effective mass.
+ float32 ruA = b2Cross(rA, uA);
+ float32 ruB = b2Cross(rB, uB);
+
+ float32 mA = m_invMassA + m_invIA * ruA * ruA;
+ float32 mB = m_invMassB + m_invIB * ruB * ruB;
+
+ float32 mass = mA + m_ratio * m_ratio * mB;
+
+ if (mass > 0.0f)
+ {
+ mass = 1.0f / mass;
+ }
+
+ float32 C = m_constant - lengthA - m_ratio * lengthB;
+ float32 linearError = b2Abs(C);
+
+ float32 impulse = -mass * C;
+
+ b2Vec2 PA = -impulse * uA;
+ b2Vec2 PB = -m_ratio * impulse * uB;
+
+ cA += m_invMassA * PA;
+ aA += m_invIA * b2Cross(rA, PA);
+ cB += m_invMassB * PB;
+ aB += m_invIB * b2Cross(rB, PB);
+
+ data.positions[m_indexA].c = cA;
+ data.positions[m_indexA].a = aA;
+ data.positions[m_indexB].c = cB;
+ data.positions[m_indexB].a = aB;
+
+ return linearError < b2_linearSlop;
+}
+
+b2Vec2 b2PulleyJoint::GetAnchorA() const
+{
+ return m_bodyA->GetWorldPoint(m_localAnchorA);
+}
+
+b2Vec2 b2PulleyJoint::GetAnchorB() const
+{
+ return m_bodyB->GetWorldPoint(m_localAnchorB);
+}
+
+b2Vec2 b2PulleyJoint::GetReactionForce(float32 inv_dt) const
+{
+ b2Vec2 P = m_impulse * m_uB;
+ return inv_dt * P;
+}
+
+float32 b2PulleyJoint::GetReactionTorque(float32 inv_dt) const
+{
+ B2_NOT_USED(inv_dt);
+ return 0.0f;
+}
+
+b2Vec2 b2PulleyJoint::GetGroundAnchorA() const
+{
+ return m_groundAnchorA;
+}
+
+b2Vec2 b2PulleyJoint::GetGroundAnchorB() const
+{
+ return m_groundAnchorB;
+}
+
+float32 b2PulleyJoint::GetLengthA() const
+{
+ b2Vec2 p = m_bodyA->GetWorldPoint(m_localAnchorA);
+ b2Vec2 s = m_groundAnchorA;
+ b2Vec2 d = p - s;
+ return d.Length();
+}
+
+float32 b2PulleyJoint::GetLengthB() const
+{
+ b2Vec2 p = m_bodyB->GetWorldPoint(m_localAnchorB);
+ b2Vec2 s = m_groundAnchorB;
+ b2Vec2 d = p - s;
+ return d.Length();
+}
+
+float32 b2PulleyJoint::GetRatio() const
+{
+ return m_ratio;
+}
+
+void b2PulleyJoint::Dump()
+{
+ int32 indexA = m_bodyA->m_islandIndex;
+ int32 indexB = m_bodyB->m_islandIndex;
+
+ b2Log(" b2PulleyJointDef jd;\n");
+ b2Log(" jd.bodyA = bodies[%d];\n", indexA);
+ b2Log(" jd.bodyB = bodies[%d];\n", indexB);
+ b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
+ b2Log(" jd.groundAnchorA.Set(%.15lef, %.15lef);\n", m_groundAnchorA.x, m_groundAnchorA.y);
+ b2Log(" jd.groundAnchorB.Set(%.15lef, %.15lef);\n", m_groundAnchorB.x, m_groundAnchorB.y);
+ b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y);
+ b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y);
+ b2Log(" jd.lengthA = %.15lef;\n", m_lengthA);
+ b2Log(" jd.lengthB = %.15lef;\n", m_lengthB);
+ b2Log(" jd.ratio = %.15lef;\n", m_ratio);
+ b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
+}
diff --git a/tests/box2d/Box2D/Dynamics/Joints/b2PulleyJoint.h b/tests/box2d/Box2D/Dynamics/Joints/b2PulleyJoint.h new file mode 100755 index 00000000..d27583c9 --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Joints/b2PulleyJoint.h @@ -0,0 +1,154 @@ +/*
+* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_PULLEY_JOINT_H
+#define B2_PULLEY_JOINT_H
+
+#include <Box2D/Dynamics/Joints/b2Joint.h>
+
+const float32 b2_minPulleyLength = 2.0f;
+
+/// Pulley joint definition. This requires two ground anchors,
+/// two dynamic body anchor points, and a pulley ratio.
+// emscripten - b2PulleyJointDef: add functions to set/get base class members
+struct b2PulleyJointDef : public b2JointDef
+{
+ b2PulleyJointDef()
+ {
+ type = e_pulleyJoint;
+ groundAnchorA.Set(-1.0f, 1.0f);
+ groundAnchorB.Set(1.0f, 1.0f);
+ localAnchorA.Set(-1.0f, 0.0f);
+ localAnchorB.Set(1.0f, 0.0f);
+ lengthA = 0.0f;
+ lengthB = 0.0f;
+ ratio = 1.0f;
+ collideConnected = true;
+ }
+
+ /// Initialize the bodies, anchors, lengths, max lengths, and ratio using the world anchors.
+ void Initialize(b2Body* bodyA, b2Body* bodyB,
+ const b2Vec2& groundAnchorA, const b2Vec2& groundAnchorB,
+ const b2Vec2& anchorA, const b2Vec2& anchorB,
+ float32 ratio);
+
+ /// The first ground anchor in world coordinates. This point never moves.
+ b2Vec2 groundAnchorA;
+
+ /// The second ground anchor in world coordinates. This point never moves.
+ b2Vec2 groundAnchorB;
+
+ /// The local anchor point relative to bodyA's origin.
+ b2Vec2 localAnchorA;
+
+ /// The local anchor point relative to bodyB's origin.
+ b2Vec2 localAnchorB;
+
+ /// The a reference length for the segment attached to bodyA.
+ float32 lengthA;
+
+ /// The a reference length for the segment attached to bodyB.
+ float32 lengthB;
+
+ /// The pulley ratio, used to simulate a block-and-tackle.
+ float32 ratio;
+
+ // to generate javascript bindings
+ void set_bodyA(b2Body* b) { bodyA = b; }
+ void set_bodyB(b2Body* b) { bodyB = b; }
+ void set_collideConnected(bool b) { collideConnected = b; }
+ b2Body* get_bodyA(b2Body* b) { return bodyA; }
+ b2Body* get_bodyB(b2Body* b) { return bodyB; }
+ bool get_collideConnected(bool b) { return collideConnected; }
+};
+
+/// The pulley joint is connected to two bodies and two fixed ground points.
+/// The pulley supports a ratio such that:
+/// length1 + ratio * length2 <= constant
+/// Yes, the force transmitted is scaled by the ratio.
+/// Warning: the pulley joint can get a bit squirrelly by itself. They often
+/// work better when combined with prismatic joints. You should also cover the
+/// the anchor points with static shapes to prevent one side from going to
+/// zero length.
+// emscripten - b2PulleyJoint: make constructor public
+class b2PulleyJoint : public b2Joint
+{
+public:
+ b2Vec2 GetAnchorA() const;
+ b2Vec2 GetAnchorB() const;
+
+ b2Vec2 GetReactionForce(float32 inv_dt) const;
+ float32 GetReactionTorque(float32 inv_dt) const;
+
+ /// Get the first ground anchor.
+ b2Vec2 GetGroundAnchorA() const;
+
+ /// Get the second ground anchor.
+ b2Vec2 GetGroundAnchorB() const;
+
+ /// Get the current length of the segment attached to bodyA.
+ float32 GetLengthA() const;
+
+ /// Get the current length of the segment attached to bodyB.
+ float32 GetLengthB() const;
+
+ /// Get the pulley ratio.
+ float32 GetRatio() const;
+
+ /// Dump joint to dmLog
+ void Dump();
+
+ b2PulleyJoint(const b2PulleyJointDef* data);
+
+protected:
+
+ friend class b2Joint;
+
+ void InitVelocityConstraints(const b2SolverData& data);
+ void SolveVelocityConstraints(const b2SolverData& data);
+ bool SolvePositionConstraints(const b2SolverData& data);
+
+ b2Vec2 m_groundAnchorA;
+ b2Vec2 m_groundAnchorB;
+ float32 m_lengthA;
+ float32 m_lengthB;
+
+ // Solver shared
+ b2Vec2 m_localAnchorA;
+ b2Vec2 m_localAnchorB;
+ float32 m_constant;
+ float32 m_ratio;
+ float32 m_impulse;
+
+ // Solver temp
+ int32 m_indexA;
+ int32 m_indexB;
+ b2Vec2 m_uA;
+ b2Vec2 m_uB;
+ b2Vec2 m_rA;
+ b2Vec2 m_rB;
+ b2Vec2 m_localCenterA;
+ b2Vec2 m_localCenterB;
+ float32 m_invMassA;
+ float32 m_invMassB;
+ float32 m_invIA;
+ float32 m_invIB;
+ float32 m_mass;
+};
+
+#endif
diff --git a/tests/box2d/Box2D/Dynamics/Joints/b2RevoluteJoint.cpp b/tests/box2d/Box2D/Dynamics/Joints/b2RevoluteJoint.cpp new file mode 100755 index 00000000..ffb17252 --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Joints/b2RevoluteJoint.cpp @@ -0,0 +1,504 @@ +/*
+* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Dynamics/Joints/b2RevoluteJoint.h>
+#include <Box2D/Dynamics/b2Body.h>
+#include <Box2D/Dynamics/b2TimeStep.h>
+
+// Point-to-point constraint
+// C = p2 - p1
+// Cdot = v2 - v1
+// = v2 + cross(w2, r2) - v1 - cross(w1, r1)
+// J = [-I -r1_skew I r2_skew ]
+// Identity used:
+// w k % (rx i + ry j) = w * (-ry i + rx j)
+
+// Motor constraint
+// Cdot = w2 - w1
+// J = [0 0 -1 0 0 1]
+// K = invI1 + invI2
+
+void b2RevoluteJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor)
+{
+ bodyA = bA;
+ bodyB = bB;
+ localAnchorA = bodyA->GetLocalPoint(anchor);
+ localAnchorB = bodyB->GetLocalPoint(anchor);
+ referenceAngle = bodyB->GetAngle() - bodyA->GetAngle();
+}
+
+b2RevoluteJoint::b2RevoluteJoint(const b2RevoluteJointDef* def)
+: b2Joint(def)
+{
+ m_localAnchorA = def->localAnchorA;
+ m_localAnchorB = def->localAnchorB;
+ m_referenceAngle = def->referenceAngle;
+
+ m_impulse.SetZero();
+ m_motorImpulse = 0.0f;
+
+ m_lowerAngle = def->lowerAngle;
+ m_upperAngle = def->upperAngle;
+ m_maxMotorTorque = def->maxMotorTorque;
+ m_motorSpeed = def->motorSpeed;
+ m_enableLimit = def->enableLimit;
+ m_enableMotor = def->enableMotor;
+ m_limitState = e_inactiveLimit;
+}
+
+void b2RevoluteJoint::InitVelocityConstraints(const b2SolverData& data)
+{
+ m_indexA = m_bodyA->m_islandIndex;
+ m_indexB = m_bodyB->m_islandIndex;
+ m_localCenterA = m_bodyA->m_sweep.localCenter;
+ m_localCenterB = m_bodyB->m_sweep.localCenter;
+ m_invMassA = m_bodyA->m_invMass;
+ m_invMassB = m_bodyB->m_invMass;
+ m_invIA = m_bodyA->m_invI;
+ m_invIB = m_bodyB->m_invI;
+
+ b2Vec2 cA = data.positions[m_indexA].c;
+ float32 aA = data.positions[m_indexA].a;
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+
+ b2Vec2 cB = data.positions[m_indexB].c;
+ float32 aB = data.positions[m_indexB].a;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ b2Rot qA(aA), qB(aB);
+
+ m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
+ m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
+
+ // J = [-I -r1_skew I r2_skew]
+ // [ 0 -1 0 1]
+ // r_skew = [-ry; rx]
+
+ // Matlab
+ // K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB]
+ // [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB]
+ // [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB]
+
+ float32 mA = m_invMassA, mB = m_invMassB;
+ float32 iA = m_invIA, iB = m_invIB;
+
+ bool fixedRotation = (iA + iB == 0.0f);
+
+ m_mass.ex.x = mA + mB + m_rA.y * m_rA.y * iA + m_rB.y * m_rB.y * iB;
+ m_mass.ey.x = -m_rA.y * m_rA.x * iA - m_rB.y * m_rB.x * iB;
+ m_mass.ez.x = -m_rA.y * iA - m_rB.y * iB;
+ m_mass.ex.y = m_mass.ey.x;
+ m_mass.ey.y = mA + mB + m_rA.x * m_rA.x * iA + m_rB.x * m_rB.x * iB;
+ m_mass.ez.y = m_rA.x * iA + m_rB.x * iB;
+ m_mass.ex.z = m_mass.ez.x;
+ m_mass.ey.z = m_mass.ez.y;
+ m_mass.ez.z = iA + iB;
+
+ m_motorMass = iA + iB;
+ if (m_motorMass > 0.0f)
+ {
+ m_motorMass = 1.0f / m_motorMass;
+ }
+
+ if (m_enableMotor == false || fixedRotation)
+ {
+ m_motorImpulse = 0.0f;
+ }
+
+ if (m_enableLimit && fixedRotation == false)
+ {
+ float32 jointAngle = aB - aA - m_referenceAngle;
+ if (b2Abs(m_upperAngle - m_lowerAngle) < 2.0f * b2_angularSlop)
+ {
+ m_limitState = e_equalLimits;
+ }
+ else if (jointAngle <= m_lowerAngle)
+ {
+ if (m_limitState != e_atLowerLimit)
+ {
+ m_impulse.z = 0.0f;
+ }
+ m_limitState = e_atLowerLimit;
+ }
+ else if (jointAngle >= m_upperAngle)
+ {
+ if (m_limitState != e_atUpperLimit)
+ {
+ m_impulse.z = 0.0f;
+ }
+ m_limitState = e_atUpperLimit;
+ }
+ else
+ {
+ m_limitState = e_inactiveLimit;
+ m_impulse.z = 0.0f;
+ }
+ }
+ else
+ {
+ m_limitState = e_inactiveLimit;
+ }
+
+ if (data.step.warmStarting)
+ {
+ // Scale impulses to support a variable time step.
+ m_impulse *= data.step.dtRatio;
+ m_motorImpulse *= data.step.dtRatio;
+
+ b2Vec2 P(m_impulse.x, m_impulse.y);
+
+ vA -= mA * P;
+ wA -= iA * (b2Cross(m_rA, P) + m_motorImpulse + m_impulse.z);
+
+ vB += mB * P;
+ wB += iB * (b2Cross(m_rB, P) + m_motorImpulse + m_impulse.z);
+ }
+ else
+ {
+ m_impulse.SetZero();
+ m_motorImpulse = 0.0f;
+ }
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+void b2RevoluteJoint::SolveVelocityConstraints(const b2SolverData& data)
+{
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ float32 mA = m_invMassA, mB = m_invMassB;
+ float32 iA = m_invIA, iB = m_invIB;
+
+ bool fixedRotation = (iA + iB == 0.0f);
+
+ // Solve motor constraint.
+ if (m_enableMotor && m_limitState != e_equalLimits && fixedRotation == false)
+ {
+ float32 Cdot = wB - wA - m_motorSpeed;
+ float32 impulse = -m_motorMass * Cdot;
+ float32 oldImpulse = m_motorImpulse;
+ float32 maxImpulse = data.step.dt * m_maxMotorTorque;
+ m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse);
+ impulse = m_motorImpulse - oldImpulse;
+
+ wA -= iA * impulse;
+ wB += iB * impulse;
+ }
+
+ // Solve limit constraint.
+ if (m_enableLimit && m_limitState != e_inactiveLimit && fixedRotation == false)
+ {
+ b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA);
+ float32 Cdot2 = wB - wA;
+ b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2);
+
+ b2Vec3 impulse = -m_mass.Solve33(Cdot);
+
+ if (m_limitState == e_equalLimits)
+ {
+ m_impulse += impulse;
+ }
+ else if (m_limitState == e_atLowerLimit)
+ {
+ float32 newImpulse = m_impulse.z + impulse.z;
+ if (newImpulse < 0.0f)
+ {
+ b2Vec2 rhs = -Cdot1 + m_impulse.z * b2Vec2(m_mass.ez.x, m_mass.ez.y);
+ b2Vec2 reduced = m_mass.Solve22(rhs);
+ impulse.x = reduced.x;
+ impulse.y = reduced.y;
+ impulse.z = -m_impulse.z;
+ m_impulse.x += reduced.x;
+ m_impulse.y += reduced.y;
+ m_impulse.z = 0.0f;
+ }
+ else
+ {
+ m_impulse += impulse;
+ }
+ }
+ else if (m_limitState == e_atUpperLimit)
+ {
+ float32 newImpulse = m_impulse.z + impulse.z;
+ if (newImpulse > 0.0f)
+ {
+ b2Vec2 rhs = -Cdot1 + m_impulse.z * b2Vec2(m_mass.ez.x, m_mass.ez.y);
+ b2Vec2 reduced = m_mass.Solve22(rhs);
+ impulse.x = reduced.x;
+ impulse.y = reduced.y;
+ impulse.z = -m_impulse.z;
+ m_impulse.x += reduced.x;
+ m_impulse.y += reduced.y;
+ m_impulse.z = 0.0f;
+ }
+ else
+ {
+ m_impulse += impulse;
+ }
+ }
+
+ b2Vec2 P(impulse.x, impulse.y);
+
+ vA -= mA * P;
+ wA -= iA * (b2Cross(m_rA, P) + impulse.z);
+
+ vB += mB * P;
+ wB += iB * (b2Cross(m_rB, P) + impulse.z);
+ }
+ else
+ {
+ // Solve point-to-point constraint
+ b2Vec2 Cdot = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA);
+ b2Vec2 impulse = m_mass.Solve22(-Cdot);
+
+ m_impulse.x += impulse.x;
+ m_impulse.y += impulse.y;
+
+ vA -= mA * impulse;
+ wA -= iA * b2Cross(m_rA, impulse);
+
+ vB += mB * impulse;
+ wB += iB * b2Cross(m_rB, impulse);
+ }
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+bool b2RevoluteJoint::SolvePositionConstraints(const b2SolverData& data)
+{
+ b2Vec2 cA = data.positions[m_indexA].c;
+ float32 aA = data.positions[m_indexA].a;
+ b2Vec2 cB = data.positions[m_indexB].c;
+ float32 aB = data.positions[m_indexB].a;
+
+ b2Rot qA(aA), qB(aB);
+
+ float32 angularError = 0.0f;
+ float32 positionError = 0.0f;
+
+ bool fixedRotation = (m_invIA + m_invIB == 0.0f);
+
+ // Solve angular limit constraint.
+ if (m_enableLimit && m_limitState != e_inactiveLimit && fixedRotation == false)
+ {
+ float32 angle = aB - aA - m_referenceAngle;
+ float32 limitImpulse = 0.0f;
+
+ if (m_limitState == e_equalLimits)
+ {
+ // Prevent large angular corrections
+ float32 C = b2Clamp(angle - m_lowerAngle, -b2_maxAngularCorrection, b2_maxAngularCorrection);
+ limitImpulse = -m_motorMass * C;
+ angularError = b2Abs(C);
+ }
+ else if (m_limitState == e_atLowerLimit)
+ {
+ float32 C = angle - m_lowerAngle;
+ angularError = -C;
+
+ // Prevent large angular corrections and allow some slop.
+ C = b2Clamp(C + b2_angularSlop, -b2_maxAngularCorrection, 0.0f);
+ limitImpulse = -m_motorMass * C;
+ }
+ else if (m_limitState == e_atUpperLimit)
+ {
+ float32 C = angle - m_upperAngle;
+ angularError = C;
+
+ // Prevent large angular corrections and allow some slop.
+ C = b2Clamp(C - b2_angularSlop, 0.0f, b2_maxAngularCorrection);
+ limitImpulse = -m_motorMass * C;
+ }
+
+ aA -= m_invIA * limitImpulse;
+ aB += m_invIB * limitImpulse;
+ }
+
+ // Solve point-to-point constraint.
+ {
+ qA.Set(aA);
+ qB.Set(aB);
+ b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
+ b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
+
+ b2Vec2 C = cB + rB - cA - rA;
+ positionError = C.Length();
+
+ float32 mA = m_invMassA, mB = m_invMassB;
+ float32 iA = m_invIA, iB = m_invIB;
+
+ b2Mat22 K;
+ K.ex.x = mA + mB + iA * rA.y * rA.y + iB * rB.y * rB.y;
+ K.ex.y = -iA * rA.x * rA.y - iB * rB.x * rB.y;
+ K.ey.x = K.ex.y;
+ K.ey.y = mA + mB + iA * rA.x * rA.x + iB * rB.x * rB.x;
+
+ b2Vec2 impulse = -K.Solve(C);
+
+ cA -= mA * impulse;
+ aA -= iA * b2Cross(rA, impulse);
+
+ cB += mB * impulse;
+ aB += iB * b2Cross(rB, impulse);
+ }
+
+ data.positions[m_indexA].c = cA;
+ data.positions[m_indexA].a = aA;
+ data.positions[m_indexB].c = cB;
+ data.positions[m_indexB].a = aB;
+
+ return positionError <= b2_linearSlop && angularError <= b2_angularSlop;
+}
+
+b2Vec2 b2RevoluteJoint::GetAnchorA() const
+{
+ return m_bodyA->GetWorldPoint(m_localAnchorA);
+}
+
+b2Vec2 b2RevoluteJoint::GetAnchorB() const
+{
+ return m_bodyB->GetWorldPoint(m_localAnchorB);
+}
+
+b2Vec2 b2RevoluteJoint::GetReactionForce(float32 inv_dt) const
+{
+ b2Vec2 P(m_impulse.x, m_impulse.y);
+ return inv_dt * P;
+}
+
+float32 b2RevoluteJoint::GetReactionTorque(float32 inv_dt) const
+{
+ return inv_dt * m_impulse.z;
+}
+
+float32 b2RevoluteJoint::GetJointAngle() const
+{
+ b2Body* bA = m_bodyA;
+ b2Body* bB = m_bodyB;
+ return bB->m_sweep.a - bA->m_sweep.a - m_referenceAngle;
+}
+
+float32 b2RevoluteJoint::GetJointSpeed() const
+{
+ b2Body* bA = m_bodyA;
+ b2Body* bB = m_bodyB;
+ return bB->m_angularVelocity - bA->m_angularVelocity;
+}
+
+bool b2RevoluteJoint::IsMotorEnabled() const
+{
+ return m_enableMotor;
+}
+
+void b2RevoluteJoint::EnableMotor(bool flag)
+{
+ m_bodyA->SetAwake(true);
+ m_bodyB->SetAwake(true);
+ m_enableMotor = flag;
+}
+
+float32 b2RevoluteJoint::GetMotorTorque(float32 inv_dt) const
+{
+ return inv_dt * m_motorImpulse;
+}
+
+void b2RevoluteJoint::SetMotorSpeed(float32 speed)
+{
+ m_bodyA->SetAwake(true);
+ m_bodyB->SetAwake(true);
+ m_motorSpeed = speed;
+}
+
+void b2RevoluteJoint::SetMaxMotorTorque(float32 torque)
+{
+ m_bodyA->SetAwake(true);
+ m_bodyB->SetAwake(true);
+ m_maxMotorTorque = torque;
+}
+
+bool b2RevoluteJoint::IsLimitEnabled() const
+{
+ return m_enableLimit;
+}
+
+void b2RevoluteJoint::EnableLimit(bool flag)
+{
+ if (flag != m_enableLimit)
+ {
+ m_bodyA->SetAwake(true);
+ m_bodyB->SetAwake(true);
+ m_enableLimit = flag;
+ m_impulse.z = 0.0f;
+ }
+}
+
+float32 b2RevoluteJoint::GetLowerLimit() const
+{
+ return m_lowerAngle;
+}
+
+float32 b2RevoluteJoint::GetUpperLimit() const
+{
+ return m_upperAngle;
+}
+
+void b2RevoluteJoint::SetLimits(float32 lower, float32 upper)
+{
+ b2Assert(lower <= upper);
+
+ if (lower != m_lowerAngle || upper != m_upperAngle)
+ {
+ m_bodyA->SetAwake(true);
+ m_bodyB->SetAwake(true);
+ m_impulse.z = 0.0f;
+ m_lowerAngle = lower;
+ m_upperAngle = upper;
+ }
+}
+
+void b2RevoluteJoint::Dump()
+{
+ int32 indexA = m_bodyA->m_islandIndex;
+ int32 indexB = m_bodyB->m_islandIndex;
+
+ b2Log(" b2RevoluteJointDef jd;\n");
+ b2Log(" jd.bodyA = bodies[%d];\n", indexA);
+ b2Log(" jd.bodyB = bodies[%d];\n", indexB);
+ b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
+ b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y);
+ b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y);
+ b2Log(" jd.referenceAngle = %.15lef;\n", m_referenceAngle);
+ b2Log(" jd.enableLimit = bool(%d);\n", m_enableLimit);
+ b2Log(" jd.lowerAngle = %.15lef;\n", m_lowerAngle);
+ b2Log(" jd.upperAngle = %.15lef;\n", m_upperAngle);
+ b2Log(" jd.enableMotor = bool(%d);\n", m_enableMotor);
+ b2Log(" jd.motorSpeed = %.15lef;\n", m_motorSpeed);
+ b2Log(" jd.maxMotorTorque = %.15lef;\n", m_maxMotorTorque);
+ b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
+}
diff --git a/tests/box2d/Box2D/Dynamics/Joints/b2RevoluteJoint.h b/tests/box2d/Box2D/Dynamics/Joints/b2RevoluteJoint.h new file mode 100755 index 00000000..672ef169 --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Joints/b2RevoluteJoint.h @@ -0,0 +1,214 @@ +/*
+* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_REVOLUTE_JOINT_H
+#define B2_REVOLUTE_JOINT_H
+
+#include <Box2D/Dynamics/Joints/b2Joint.h>
+
+/// Revolute joint definition. This requires defining an
+/// anchor point where the bodies are joined. The definition
+/// uses local anchor points so that the initial configuration
+/// can violate the constraint slightly. You also need to
+/// specify the initial relative angle for joint limits. This
+/// helps when saving and loading a game.
+/// The local anchor points are measured from the body's origin
+/// rather than the center of mass because:
+/// 1. you might not know where the center of mass will be.
+/// 2. if you add/remove shapes from a body and recompute the mass,
+/// the joints will be broken.
+// emscripten - b2RevoluteJointDef: add functions to set/get base class members
+struct b2RevoluteJointDef : public b2JointDef
+{
+ b2RevoluteJointDef()
+ {
+ type = e_revoluteJoint;
+ localAnchorA.Set(0.0f, 0.0f);
+ localAnchorB.Set(0.0f, 0.0f);
+ referenceAngle = 0.0f;
+ lowerAngle = 0.0f;
+ upperAngle = 0.0f;
+ maxMotorTorque = 0.0f;
+ motorSpeed = 0.0f;
+ enableLimit = false;
+ enableMotor = false;
+ }
+
+ /// Initialize the bodies, anchors, and reference angle using a world
+ /// anchor point.
+ void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor);
+
+ /// The local anchor point relative to bodyA's origin.
+ b2Vec2 localAnchorA;
+
+ /// The local anchor point relative to bodyB's origin.
+ b2Vec2 localAnchorB;
+
+ /// The bodyB angle minus bodyA angle in the reference state (radians).
+ float32 referenceAngle;
+
+ /// A flag to enable joint limits.
+ bool enableLimit;
+
+ /// The lower angle for the joint limit (radians).
+ float32 lowerAngle;
+
+ /// The upper angle for the joint limit (radians).
+ float32 upperAngle;
+
+ /// A flag to enable the joint motor.
+ bool enableMotor;
+
+ /// The desired motor speed. Usually in radians per second.
+ float32 motorSpeed;
+
+ /// The maximum motor torque used to achieve the desired motor speed.
+ /// Usually in N-m.
+ float32 maxMotorTorque;
+
+ // to generate javascript bindings
+ void set_bodyA(b2Body* b) { bodyA = b; }
+ void set_bodyB(b2Body* b) { bodyB = b; }
+ void set_collideConnected(bool b) { collideConnected = b; }
+ b2Body* get_bodyA(b2Body* b) { return bodyA; }
+ b2Body* get_bodyB(b2Body* b) { return bodyB; }
+ bool get_collideConnected(bool b) { return collideConnected; }
+};
+
+/// A revolute joint constrains two bodies to share a common point while they
+/// are free to rotate about the point. The relative rotation about the shared
+/// point is the joint angle. You can limit the relative rotation with
+/// a joint limit that specifies a lower and upper angle. You can use a motor
+/// to drive the relative rotation about the shared point. A maximum motor torque
+/// is provided so that infinite forces are not generated.
+// emscripten - b2RevoluteJoint: make constructor public
+class b2RevoluteJoint : public b2Joint
+{
+public:
+ b2Vec2 GetAnchorA() const;
+ b2Vec2 GetAnchorB() const;
+
+ /// The local anchor point relative to bodyA's origin.
+ const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; }
+
+ /// The local anchor point relative to bodyB's origin.
+ const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; }
+
+ /// Get the reference angle.
+ float32 GetReferenceAngle() const { return m_referenceAngle; }
+
+ /// Get the current joint angle in radians.
+ float32 GetJointAngle() const;
+
+ /// Get the current joint angle speed in radians per second.
+ float32 GetJointSpeed() const;
+
+ /// Is the joint limit enabled?
+ bool IsLimitEnabled() const;
+
+ /// Enable/disable the joint limit.
+ void EnableLimit(bool flag);
+
+ /// Get the lower joint limit in radians.
+ float32 GetLowerLimit() const;
+
+ /// Get the upper joint limit in radians.
+ float32 GetUpperLimit() const;
+
+ /// Set the joint limits in radians.
+ void SetLimits(float32 lower, float32 upper);
+
+ /// Is the joint motor enabled?
+ bool IsMotorEnabled() const;
+
+ /// Enable/disable the joint motor.
+ void EnableMotor(bool flag);
+
+ /// Set the motor speed in radians per second.
+ void SetMotorSpeed(float32 speed);
+
+ /// Get the motor speed in radians per second.
+ float32 GetMotorSpeed() const;
+
+ /// Set the maximum motor torque, usually in N-m.
+ void SetMaxMotorTorque(float32 torque);
+ float32 GetMaxMotorTorque() const { return m_maxMotorTorque; }
+
+ /// Get the reaction force given the inverse time step.
+ /// Unit is N.
+ b2Vec2 GetReactionForce(float32 inv_dt) const;
+
+ /// Get the reaction torque due to the joint limit given the inverse time step.
+ /// Unit is N*m.
+ float32 GetReactionTorque(float32 inv_dt) const;
+
+ /// Get the current motor torque given the inverse time step.
+ /// Unit is N*m.
+ float32 GetMotorTorque(float32 inv_dt) const;
+
+ /// Dump to b2Log.
+ void Dump();
+
+ b2RevoluteJoint(const b2RevoluteJointDef* def);
+
+protected:
+
+ friend class b2Joint;
+ friend class b2GearJoint;
+
+ void InitVelocityConstraints(const b2SolverData& data);
+ void SolveVelocityConstraints(const b2SolverData& data);
+ bool SolvePositionConstraints(const b2SolverData& data);
+
+ // Solver shared
+ b2Vec2 m_localAnchorA;
+ b2Vec2 m_localAnchorB;
+ b2Vec3 m_impulse;
+ float32 m_motorImpulse;
+
+ bool m_enableMotor;
+ float32 m_maxMotorTorque;
+ float32 m_motorSpeed;
+
+ bool m_enableLimit;
+ float32 m_referenceAngle;
+ float32 m_lowerAngle;
+ float32 m_upperAngle;
+
+ // Solver temp
+ int32 m_indexA;
+ int32 m_indexB;
+ b2Vec2 m_rA;
+ b2Vec2 m_rB;
+ b2Vec2 m_localCenterA;
+ b2Vec2 m_localCenterB;
+ float32 m_invMassA;
+ float32 m_invMassB;
+ float32 m_invIA;
+ float32 m_invIB;
+ b2Mat33 m_mass; // effective mass for point-to-point constraint.
+ float32 m_motorMass; // effective mass for motor/limit angular constraint.
+ b2LimitState m_limitState;
+};
+
+inline float32 b2RevoluteJoint::GetMotorSpeed() const
+{
+ return m_motorSpeed;
+}
+
+#endif
diff --git a/tests/box2d/Box2D/Dynamics/Joints/b2RopeJoint.cpp b/tests/box2d/Box2D/Dynamics/Joints/b2RopeJoint.cpp new file mode 100755 index 00000000..107ce1fa --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Joints/b2RopeJoint.cpp @@ -0,0 +1,241 @@ +/*
+* Copyright (c) 2007-2011 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Dynamics/Joints/b2RopeJoint.h>
+#include <Box2D/Dynamics/b2Body.h>
+#include <Box2D/Dynamics/b2TimeStep.h>
+
+
+// Limit:
+// C = norm(pB - pA) - L
+// u = (pB - pA) / norm(pB - pA)
+// Cdot = dot(u, vB + cross(wB, rB) - vA - cross(wA, rA))
+// J = [-u -cross(rA, u) u cross(rB, u)]
+// K = J * invM * JT
+// = invMassA + invIA * cross(rA, u)^2 + invMassB + invIB * cross(rB, u)^2
+
+b2RopeJoint::b2RopeJoint(const b2RopeJointDef* def)
+: b2Joint(def)
+{
+ m_localAnchorA = def->localAnchorA;
+ m_localAnchorB = def->localAnchorB;
+
+ m_maxLength = def->maxLength;
+
+ m_mass = 0.0f;
+ m_impulse = 0.0f;
+ m_state = e_inactiveLimit;
+ m_length = 0.0f;
+}
+
+void b2RopeJoint::InitVelocityConstraints(const b2SolverData& data)
+{
+ m_indexA = m_bodyA->m_islandIndex;
+ m_indexB = m_bodyB->m_islandIndex;
+ m_localCenterA = m_bodyA->m_sweep.localCenter;
+ m_localCenterB = m_bodyB->m_sweep.localCenter;
+ m_invMassA = m_bodyA->m_invMass;
+ m_invMassB = m_bodyB->m_invMass;
+ m_invIA = m_bodyA->m_invI;
+ m_invIB = m_bodyB->m_invI;
+
+ b2Vec2 cA = data.positions[m_indexA].c;
+ float32 aA = data.positions[m_indexA].a;
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+
+ b2Vec2 cB = data.positions[m_indexB].c;
+ float32 aB = data.positions[m_indexB].a;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ b2Rot qA(aA), qB(aB);
+
+ m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
+ m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
+ m_u = cB + m_rB - cA - m_rA;
+
+ m_length = m_u.Length();
+
+ float32 C = m_length - m_maxLength;
+ if (C > 0.0f)
+ {
+ m_state = e_atUpperLimit;
+ }
+ else
+ {
+ m_state = e_inactiveLimit;
+ }
+
+ if (m_length > b2_linearSlop)
+ {
+ m_u *= 1.0f / m_length;
+ }
+ else
+ {
+ m_u.SetZero();
+ m_mass = 0.0f;
+ m_impulse = 0.0f;
+ return;
+ }
+
+ // Compute effective mass.
+ float32 crA = b2Cross(m_rA, m_u);
+ float32 crB = b2Cross(m_rB, m_u);
+ float32 invMass = m_invMassA + m_invIA * crA * crA + m_invMassB + m_invIB * crB * crB;
+
+ m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f;
+
+ if (data.step.warmStarting)
+ {
+ // Scale the impulse to support a variable time step.
+ m_impulse *= data.step.dtRatio;
+
+ b2Vec2 P = m_impulse * m_u;
+ vA -= m_invMassA * P;
+ wA -= m_invIA * b2Cross(m_rA, P);
+ vB += m_invMassB * P;
+ wB += m_invIB * b2Cross(m_rB, P);
+ }
+ else
+ {
+ m_impulse = 0.0f;
+ }
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+void b2RopeJoint::SolveVelocityConstraints(const b2SolverData& data)
+{
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ // Cdot = dot(u, v + cross(w, r))
+ b2Vec2 vpA = vA + b2Cross(wA, m_rA);
+ b2Vec2 vpB = vB + b2Cross(wB, m_rB);
+ float32 C = m_length - m_maxLength;
+ float32 Cdot = b2Dot(m_u, vpB - vpA);
+
+ // Predictive constraint.
+ if (C < 0.0f)
+ {
+ Cdot += data.step.inv_dt * C;
+ }
+
+ float32 impulse = -m_mass * Cdot;
+ float32 oldImpulse = m_impulse;
+ m_impulse = b2Min(0.0f, m_impulse + impulse);
+ impulse = m_impulse - oldImpulse;
+
+ b2Vec2 P = impulse * m_u;
+ vA -= m_invMassA * P;
+ wA -= m_invIA * b2Cross(m_rA, P);
+ vB += m_invMassB * P;
+ wB += m_invIB * b2Cross(m_rB, P);
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+bool b2RopeJoint::SolvePositionConstraints(const b2SolverData& data)
+{
+ b2Vec2 cA = data.positions[m_indexA].c;
+ float32 aA = data.positions[m_indexA].a;
+ b2Vec2 cB = data.positions[m_indexB].c;
+ float32 aB = data.positions[m_indexB].a;
+
+ b2Rot qA(aA), qB(aB);
+
+ b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
+ b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
+ b2Vec2 u = cB + rB - cA - rA;
+
+ float32 length = u.Normalize();
+ float32 C = length - m_maxLength;
+
+ C = b2Clamp(C, 0.0f, b2_maxLinearCorrection);
+
+ float32 impulse = -m_mass * C;
+ b2Vec2 P = impulse * u;
+
+ cA -= m_invMassA * P;
+ aA -= m_invIA * b2Cross(rA, P);
+ cB += m_invMassB * P;
+ aB += m_invIB * b2Cross(rB, P);
+
+ data.positions[m_indexA].c = cA;
+ data.positions[m_indexA].a = aA;
+ data.positions[m_indexB].c = cB;
+ data.positions[m_indexB].a = aB;
+
+ return length - m_maxLength < b2_linearSlop;
+}
+
+b2Vec2 b2RopeJoint::GetAnchorA() const
+{
+ return m_bodyA->GetWorldPoint(m_localAnchorA);
+}
+
+b2Vec2 b2RopeJoint::GetAnchorB() const
+{
+ return m_bodyB->GetWorldPoint(m_localAnchorB);
+}
+
+b2Vec2 b2RopeJoint::GetReactionForce(float32 inv_dt) const
+{
+ b2Vec2 F = (inv_dt * m_impulse) * m_u;
+ return F;
+}
+
+float32 b2RopeJoint::GetReactionTorque(float32 inv_dt) const
+{
+ B2_NOT_USED(inv_dt);
+ return 0.0f;
+}
+
+float32 b2RopeJoint::GetMaxLength() const
+{
+ return m_maxLength;
+}
+
+b2LimitState b2RopeJoint::GetLimitState() const
+{
+ return m_state;
+}
+
+void b2RopeJoint::Dump()
+{
+ int32 indexA = m_bodyA->m_islandIndex;
+ int32 indexB = m_bodyB->m_islandIndex;
+
+ b2Log(" b2RopeJointDef jd;\n");
+ b2Log(" jd.bodyA = bodies[%d];\n", indexA);
+ b2Log(" jd.bodyB = bodies[%d];\n", indexB);
+ b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
+ b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y);
+ b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y);
+ b2Log(" jd.maxLength = %.15lef;\n", m_maxLength);
+ b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
+}
diff --git a/tests/box2d/Box2D/Dynamics/Joints/b2RopeJoint.h b/tests/box2d/Box2D/Dynamics/Joints/b2RopeJoint.h new file mode 100755 index 00000000..eb67a998 --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Joints/b2RopeJoint.h @@ -0,0 +1,125 @@ +/*
+* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_ROPE_JOINT_H
+#define B2_ROPE_JOINT_H
+
+#include <Box2D/Dynamics/Joints/b2Joint.h>
+
+/// Rope joint definition. This requires two body anchor points and
+/// a maximum lengths.
+/// Note: by default the connected objects will not collide.
+/// see collideConnected in b2JointDef.
+// emscripten - b2RopeJointDef: add functions to set/get base class members
+struct b2RopeJointDef : public b2JointDef
+{
+ b2RopeJointDef()
+ {
+ type = e_ropeJoint;
+ localAnchorA.Set(-1.0f, 0.0f);
+ localAnchorB.Set(1.0f, 0.0f);
+ maxLength = 0.0f;
+ }
+
+ /// The local anchor point relative to bodyA's origin.
+ b2Vec2 localAnchorA;
+
+ /// The local anchor point relative to bodyB's origin.
+ b2Vec2 localAnchorB;
+
+ /// The maximum length of the rope.
+ /// Warning: this must be larger than b2_linearSlop or
+ /// the joint will have no effect.
+ float32 maxLength;
+
+ // to generate javascript bindings
+ void set_bodyA(b2Body* b) { bodyA = b; }
+ void set_bodyB(b2Body* b) { bodyB = b; }
+ void set_collideConnected(bool b) { collideConnected = b; }
+ b2Body* get_bodyA(b2Body* b) { return bodyA; }
+ b2Body* get_bodyB(b2Body* b) { return bodyB; }
+ bool get_collideConnected(bool b) { return collideConnected; }
+};
+
+/// A rope joint enforces a maximum distance between two points
+/// on two bodies. It has no other effect.
+/// Warning: if you attempt to change the maximum length during
+/// the simulation you will get some non-physical behavior.
+/// A model that would allow you to dynamically modify the length
+/// would have some sponginess, so I chose not to implement it
+/// that way. See b2DistanceJoint if you want to dynamically
+/// control length.
+// emscripten - b2RopeJoint: make constructor public
+class b2RopeJoint : public b2Joint
+{
+public:
+ b2Vec2 GetAnchorA() const;
+ b2Vec2 GetAnchorB() const;
+
+ b2Vec2 GetReactionForce(float32 inv_dt) const;
+ float32 GetReactionTorque(float32 inv_dt) const;
+
+ /// The local anchor point relative to bodyA's origin.
+ const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; }
+
+ /// The local anchor point relative to bodyB's origin.
+ const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; }
+
+ /// Set/Get the maximum length of the rope.
+ void SetMaxLength(float32 length) { m_maxLength = length; }
+ float32 GetMaxLength() const;
+
+ b2LimitState GetLimitState() const;
+
+ /// Dump joint to dmLog
+ void Dump();
+
+ b2RopeJoint(const b2RopeJointDef* data);
+
+protected:
+
+ friend class b2Joint;
+
+ void InitVelocityConstraints(const b2SolverData& data);
+ void SolveVelocityConstraints(const b2SolverData& data);
+ bool SolvePositionConstraints(const b2SolverData& data);
+
+ // Solver shared
+ b2Vec2 m_localAnchorA;
+ b2Vec2 m_localAnchorB;
+ float32 m_maxLength;
+ float32 m_length;
+ float32 m_impulse;
+
+ // Solver temp
+ int32 m_indexA;
+ int32 m_indexB;
+ b2Vec2 m_u;
+ b2Vec2 m_rA;
+ b2Vec2 m_rB;
+ b2Vec2 m_localCenterA;
+ b2Vec2 m_localCenterB;
+ float32 m_invMassA;
+ float32 m_invMassB;
+ float32 m_invIA;
+ float32 m_invIB;
+ float32 m_mass;
+ b2LimitState m_state;
+};
+
+#endif
diff --git a/tests/box2d/Box2D/Dynamics/Joints/b2WeldJoint.cpp b/tests/box2d/Box2D/Dynamics/Joints/b2WeldJoint.cpp new file mode 100755 index 00000000..9a86686e --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Joints/b2WeldJoint.cpp @@ -0,0 +1,330 @@ +/*
+* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Dynamics/Joints/b2WeldJoint.h>
+#include <Box2D/Dynamics/b2Body.h>
+#include <Box2D/Dynamics/b2TimeStep.h>
+
+// Point-to-point constraint
+// C = p2 - p1
+// Cdot = v2 - v1
+// = v2 + cross(w2, r2) - v1 - cross(w1, r1)
+// J = [-I -r1_skew I r2_skew ]
+// Identity used:
+// w k % (rx i + ry j) = w * (-ry i + rx j)
+
+// Angle constraint
+// C = angle2 - angle1 - referenceAngle
+// Cdot = w2 - w1
+// J = [0 0 -1 0 0 1]
+// K = invI1 + invI2
+
+void b2WeldJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor)
+{
+ bodyA = bA;
+ bodyB = bB;
+ localAnchorA = bodyA->GetLocalPoint(anchor);
+ localAnchorB = bodyB->GetLocalPoint(anchor);
+ referenceAngle = bodyB->GetAngle() - bodyA->GetAngle();
+}
+
+b2WeldJoint::b2WeldJoint(const b2WeldJointDef* def)
+: b2Joint(def)
+{
+ m_localAnchorA = def->localAnchorA;
+ m_localAnchorB = def->localAnchorB;
+ m_referenceAngle = def->referenceAngle;
+ m_frequencyHz = def->frequencyHz;
+ m_dampingRatio = def->dampingRatio;
+
+ m_impulse.SetZero();
+}
+
+void b2WeldJoint::InitVelocityConstraints(const b2SolverData& data)
+{
+ m_indexA = m_bodyA->m_islandIndex;
+ m_indexB = m_bodyB->m_islandIndex;
+ m_localCenterA = m_bodyA->m_sweep.localCenter;
+ m_localCenterB = m_bodyB->m_sweep.localCenter;
+ m_invMassA = m_bodyA->m_invMass;
+ m_invMassB = m_bodyB->m_invMass;
+ m_invIA = m_bodyA->m_invI;
+ m_invIB = m_bodyB->m_invI;
+
+ b2Vec2 cA = data.positions[m_indexA].c;
+ float32 aA = data.positions[m_indexA].a;
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+
+ b2Vec2 cB = data.positions[m_indexB].c;
+ float32 aB = data.positions[m_indexB].a;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ b2Rot qA(aA), qB(aB);
+
+ m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
+ m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
+
+ // J = [-I -r1_skew I r2_skew]
+ // [ 0 -1 0 1]
+ // r_skew = [-ry; rx]
+
+ // Matlab
+ // K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB]
+ // [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB]
+ // [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB]
+
+ float32 mA = m_invMassA, mB = m_invMassB;
+ float32 iA = m_invIA, iB = m_invIB;
+
+ b2Mat33 K;
+ K.ex.x = mA + mB + m_rA.y * m_rA.y * iA + m_rB.y * m_rB.y * iB;
+ K.ey.x = -m_rA.y * m_rA.x * iA - m_rB.y * m_rB.x * iB;
+ K.ez.x = -m_rA.y * iA - m_rB.y * iB;
+ K.ex.y = K.ey.x;
+ K.ey.y = mA + mB + m_rA.x * m_rA.x * iA + m_rB.x * m_rB.x * iB;
+ K.ez.y = m_rA.x * iA + m_rB.x * iB;
+ K.ex.z = K.ez.x;
+ K.ey.z = K.ez.y;
+ K.ez.z = iA + iB;
+
+ if (m_frequencyHz > 0.0f)
+ {
+ K.GetInverse22(&m_mass);
+
+ float32 invM = iA + iB;
+ float32 m = invM > 0.0f ? 1.0f / invM : 0.0f;
+
+ float32 C = aB - aA - m_referenceAngle;
+
+ // Frequency
+ float32 omega = 2.0f * b2_pi * m_frequencyHz;
+
+ // Damping coefficient
+ float32 d = 2.0f * m * m_dampingRatio * omega;
+
+ // Spring stiffness
+ float32 k = m * omega * omega;
+
+ // magic formulas
+ float32 h = data.step.dt;
+ m_gamma = h * (d + h * k);
+ m_gamma = m_gamma != 0.0f ? 1.0f / m_gamma : 0.0f;
+ m_bias = C * h * k * m_gamma;
+
+ invM += m_gamma;
+ m_mass.ez.z = invM != 0.0f ? 1.0f / invM : 0.0f;
+ }
+ else
+ {
+ K.GetSymInverse33(&m_mass);
+ m_gamma = 0.0f;
+ m_bias = 0.0f;
+ }
+
+ if (data.step.warmStarting)
+ {
+ // Scale impulses to support a variable time step.
+ m_impulse *= data.step.dtRatio;
+
+ b2Vec2 P(m_impulse.x, m_impulse.y);
+
+ vA -= mA * P;
+ wA -= iA * (b2Cross(m_rA, P) + m_impulse.z);
+
+ vB += mB * P;
+ wB += iB * (b2Cross(m_rB, P) + m_impulse.z);
+ }
+ else
+ {
+ m_impulse.SetZero();
+ }
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+void b2WeldJoint::SolveVelocityConstraints(const b2SolverData& data)
+{
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ float32 mA = m_invMassA, mB = m_invMassB;
+ float32 iA = m_invIA, iB = m_invIB;
+
+ if (m_frequencyHz > 0.0f)
+ {
+ float32 Cdot2 = wB - wA;
+
+ float32 impulse2 = -m_mass.ez.z * (Cdot2 + m_bias + m_gamma * m_impulse.z);
+ m_impulse.z += impulse2;
+
+ wA -= iA * impulse2;
+ wB += iB * impulse2;
+
+ b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA);
+
+ b2Vec2 impulse1 = -b2Mul22(m_mass, Cdot1);
+ m_impulse.x += impulse1.x;
+ m_impulse.y += impulse1.y;
+
+ b2Vec2 P = impulse1;
+
+ vA -= mA * P;
+ wA -= iA * b2Cross(m_rA, P);
+
+ vB += mB * P;
+ wB += iB * b2Cross(m_rB, P);
+ }
+ else
+ {
+ b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA);
+ float32 Cdot2 = wB - wA;
+ b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2);
+
+ b2Vec3 impulse = -b2Mul(m_mass, Cdot);
+ m_impulse += impulse;
+
+ b2Vec2 P(impulse.x, impulse.y);
+
+ vA -= mA * P;
+ wA -= iA * (b2Cross(m_rA, P) + impulse.z);
+
+ vB += mB * P;
+ wB += iB * (b2Cross(m_rB, P) + impulse.z);
+ }
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+bool b2WeldJoint::SolvePositionConstraints(const b2SolverData& data)
+{
+ b2Vec2 cA = data.positions[m_indexA].c;
+ float32 aA = data.positions[m_indexA].a;
+ b2Vec2 cB = data.positions[m_indexB].c;
+ float32 aB = data.positions[m_indexB].a;
+
+ b2Rot qA(aA), qB(aB);
+
+ float32 mA = m_invMassA, mB = m_invMassB;
+ float32 iA = m_invIA, iB = m_invIB;
+
+ b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
+ b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
+
+ float32 positionError, angularError;
+
+ b2Mat33 K;
+ K.ex.x = mA + mB + rA.y * rA.y * iA + rB.y * rB.y * iB;
+ K.ey.x = -rA.y * rA.x * iA - rB.y * rB.x * iB;
+ K.ez.x = -rA.y * iA - rB.y * iB;
+ K.ex.y = K.ey.x;
+ K.ey.y = mA + mB + rA.x * rA.x * iA + rB.x * rB.x * iB;
+ K.ez.y = rA.x * iA + rB.x * iB;
+ K.ex.z = K.ez.x;
+ K.ey.z = K.ez.y;
+ K.ez.z = iA + iB;
+
+ if (m_frequencyHz > 0.0f)
+ {
+ b2Vec2 C1 = cB + rB - cA - rA;
+
+ positionError = C1.Length();
+ angularError = 0.0f;
+
+ b2Vec2 P = -K.Solve22(C1);
+
+ cA -= mA * P;
+ aA -= iA * b2Cross(rA, P);
+
+ cB += mB * P;
+ aB += iB * b2Cross(rB, P);
+ }
+ else
+ {
+ b2Vec2 C1 = cB + rB - cA - rA;
+ float32 C2 = aB - aA - m_referenceAngle;
+
+ positionError = C1.Length();
+ angularError = b2Abs(C2);
+
+ b2Vec3 C(C1.x, C1.y, C2);
+
+ b2Vec3 impulse = -K.Solve33(C);
+ b2Vec2 P(impulse.x, impulse.y);
+
+ cA -= mA * P;
+ aA -= iA * (b2Cross(rA, P) + impulse.z);
+
+ cB += mB * P;
+ aB += iB * (b2Cross(rB, P) + impulse.z);
+ }
+
+ data.positions[m_indexA].c = cA;
+ data.positions[m_indexA].a = aA;
+ data.positions[m_indexB].c = cB;
+ data.positions[m_indexB].a = aB;
+
+ return positionError <= b2_linearSlop && angularError <= b2_angularSlop;
+}
+
+b2Vec2 b2WeldJoint::GetAnchorA() const
+{
+ return m_bodyA->GetWorldPoint(m_localAnchorA);
+}
+
+b2Vec2 b2WeldJoint::GetAnchorB() const
+{
+ return m_bodyB->GetWorldPoint(m_localAnchorB);
+}
+
+b2Vec2 b2WeldJoint::GetReactionForce(float32 inv_dt) const
+{
+ b2Vec2 P(m_impulse.x, m_impulse.y);
+ return inv_dt * P;
+}
+
+float32 b2WeldJoint::GetReactionTorque(float32 inv_dt) const
+{
+ return inv_dt * m_impulse.z;
+}
+
+void b2WeldJoint::Dump()
+{
+ int32 indexA = m_bodyA->m_islandIndex;
+ int32 indexB = m_bodyB->m_islandIndex;
+
+ b2Log(" b2WeldJointDef jd;\n");
+ b2Log(" jd.bodyA = bodies[%d];\n", indexA);
+ b2Log(" jd.bodyB = bodies[%d];\n", indexB);
+ b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
+ b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y);
+ b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y);
+ b2Log(" jd.referenceAngle = %.15lef;\n", m_referenceAngle);
+ b2Log(" jd.frequencyHz = %.15lef;\n", m_frequencyHz);
+ b2Log(" jd.dampingRatio = %.15lef;\n", m_dampingRatio);
+ b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
+}
diff --git a/tests/box2d/Box2D/Dynamics/Joints/b2WeldJoint.h b/tests/box2d/Box2D/Dynamics/Joints/b2WeldJoint.h new file mode 100755 index 00000000..02f33d4f --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Joints/b2WeldJoint.h @@ -0,0 +1,136 @@ +/*
+* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_WELD_JOINT_H
+#define B2_WELD_JOINT_H
+
+#include <Box2D/Dynamics/Joints/b2Joint.h>
+
+/// Weld joint definition. You need to specify local anchor points
+/// where they are attached and the relative body angle. The position
+/// of the anchor points is important for computing the reaction torque.
+// emscripten - b2WeldJointDef: add functions to set/get base class members
+struct b2WeldJointDef : public b2JointDef
+{
+ b2WeldJointDef()
+ {
+ type = e_weldJoint;
+ localAnchorA.Set(0.0f, 0.0f);
+ localAnchorB.Set(0.0f, 0.0f);
+ referenceAngle = 0.0f;
+ frequencyHz = 0.0f;
+ dampingRatio = 0.0f;
+ }
+
+ /// Initialize the bodies, anchors, and reference angle using a world
+ /// anchor point.
+ void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor);
+
+ /// The local anchor point relative to bodyA's origin.
+ b2Vec2 localAnchorA;
+
+ /// The local anchor point relative to bodyB's origin.
+ b2Vec2 localAnchorB;
+
+ /// The bodyB angle minus bodyA angle in the reference state (radians).
+ float32 referenceAngle;
+
+ /// The mass-spring-damper frequency in Hertz. Rotation only.
+ /// Disable softness with a value of 0.
+ float32 frequencyHz;
+
+ /// The damping ratio. 0 = no damping, 1 = critical damping.
+ float32 dampingRatio;
+
+ // to generate javascript bindings
+ void set_bodyA(b2Body* b) { bodyA = b; }
+ void set_bodyB(b2Body* b) { bodyB = b; }
+ void set_collideConnected(bool b) { collideConnected = b; }
+ b2Body* get_bodyA(b2Body* b) { return bodyA; }
+ b2Body* get_bodyB(b2Body* b) { return bodyB; }
+ bool get_collideConnected(bool b) { return collideConnected; }
+};
+
+/// A weld joint essentially glues two bodies together. A weld joint may
+/// distort somewhat because the island constraint solver is approximate.
+// emscripten - b2WeldJoint: make constructor public
+class b2WeldJoint : public b2Joint
+{
+public:
+ b2Vec2 GetAnchorA() const;
+ b2Vec2 GetAnchorB() const;
+
+ b2Vec2 GetReactionForce(float32 inv_dt) const;
+ float32 GetReactionTorque(float32 inv_dt) const;
+
+ /// The local anchor point relative to bodyA's origin.
+ const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; }
+
+ /// The local anchor point relative to bodyB's origin.
+ const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; }
+
+ /// Get the reference angle.
+ float32 GetReferenceAngle() const { return m_referenceAngle; }
+
+ /// Set/get frequency in Hz.
+ void SetFrequency(float32 hz) { m_frequencyHz = hz; }
+ float32 GetFrequency() const { return m_frequencyHz; }
+
+ /// Set/get damping ratio.
+ void SetDampingRatio(float32 ratio) { m_dampingRatio = ratio; }
+ float32 GetDampingRatio() const { return m_dampingRatio; }
+
+ /// Dump to b2Log
+ void Dump();
+
+ b2WeldJoint(const b2WeldJointDef* def);
+
+protected:
+
+ friend class b2Joint;
+
+ void InitVelocityConstraints(const b2SolverData& data);
+ void SolveVelocityConstraints(const b2SolverData& data);
+ bool SolvePositionConstraints(const b2SolverData& data);
+
+ float32 m_frequencyHz;
+ float32 m_dampingRatio;
+ float32 m_bias;
+
+ // Solver shared
+ b2Vec2 m_localAnchorA;
+ b2Vec2 m_localAnchorB;
+ float32 m_referenceAngle;
+ float32 m_gamma;
+ b2Vec3 m_impulse;
+
+ // Solver temp
+ int32 m_indexA;
+ int32 m_indexB;
+ b2Vec2 m_rA;
+ b2Vec2 m_rB;
+ b2Vec2 m_localCenterA;
+ b2Vec2 m_localCenterB;
+ float32 m_invMassA;
+ float32 m_invMassB;
+ float32 m_invIA;
+ float32 m_invIB;
+ b2Mat33 m_mass;
+};
+
+#endif
diff --git a/tests/box2d/Box2D/Dynamics/Joints/b2WheelJoint.cpp b/tests/box2d/Box2D/Dynamics/Joints/b2WheelJoint.cpp new file mode 100755 index 00000000..998c627d --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Joints/b2WheelJoint.cpp @@ -0,0 +1,419 @@ +/*
+* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Dynamics/Joints/b2WheelJoint.h>
+#include <Box2D/Dynamics/b2Body.h>
+#include <Box2D/Dynamics/b2TimeStep.h>
+
+// Linear constraint (point-to-line)
+// d = pB - pA = xB + rB - xA - rA
+// C = dot(ay, d)
+// Cdot = dot(d, cross(wA, ay)) + dot(ay, vB + cross(wB, rB) - vA - cross(wA, rA))
+// = -dot(ay, vA) - dot(cross(d + rA, ay), wA) + dot(ay, vB) + dot(cross(rB, ay), vB)
+// J = [-ay, -cross(d + rA, ay), ay, cross(rB, ay)]
+
+// Spring linear constraint
+// C = dot(ax, d)
+// Cdot = = -dot(ax, vA) - dot(cross(d + rA, ax), wA) + dot(ax, vB) + dot(cross(rB, ax), vB)
+// J = [-ax -cross(d+rA, ax) ax cross(rB, ax)]
+
+// Motor rotational constraint
+// Cdot = wB - wA
+// J = [0 0 -1 0 0 1]
+
+void b2WheelJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor, const b2Vec2& axis)
+{
+ bodyA = bA;
+ bodyB = bB;
+ localAnchorA = bodyA->GetLocalPoint(anchor);
+ localAnchorB = bodyB->GetLocalPoint(anchor);
+ localAxisA = bodyA->GetLocalVector(axis);
+}
+
+b2WheelJoint::b2WheelJoint(const b2WheelJointDef* def)
+: b2Joint(def)
+{
+ m_localAnchorA = def->localAnchorA;
+ m_localAnchorB = def->localAnchorB;
+ m_localXAxisA = def->localAxisA;
+ m_localYAxisA = b2Cross(1.0f, m_localXAxisA);
+
+ m_mass = 0.0f;
+ m_impulse = 0.0f;
+ m_motorMass = 0.0;
+ m_motorImpulse = 0.0f;
+ m_springMass = 0.0f;
+ m_springImpulse = 0.0f;
+
+ m_maxMotorTorque = def->maxMotorTorque;
+ m_motorSpeed = def->motorSpeed;
+ m_enableMotor = def->enableMotor;
+
+ m_frequencyHz = def->frequencyHz;
+ m_dampingRatio = def->dampingRatio;
+
+ m_bias = 0.0f;
+ m_gamma = 0.0f;
+
+ m_ax.SetZero();
+ m_ay.SetZero();
+}
+
+void b2WheelJoint::InitVelocityConstraints(const b2SolverData& data)
+{
+ m_indexA = m_bodyA->m_islandIndex;
+ m_indexB = m_bodyB->m_islandIndex;
+ m_localCenterA = m_bodyA->m_sweep.localCenter;
+ m_localCenterB = m_bodyB->m_sweep.localCenter;
+ m_invMassA = m_bodyA->m_invMass;
+ m_invMassB = m_bodyB->m_invMass;
+ m_invIA = m_bodyA->m_invI;
+ m_invIB = m_bodyB->m_invI;
+
+ float32 mA = m_invMassA, mB = m_invMassB;
+ float32 iA = m_invIA, iB = m_invIB;
+
+ b2Vec2 cA = data.positions[m_indexA].c;
+ float32 aA = data.positions[m_indexA].a;
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+
+ b2Vec2 cB = data.positions[m_indexB].c;
+ float32 aB = data.positions[m_indexB].a;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ b2Rot qA(aA), qB(aB);
+
+ // Compute the effective masses.
+ b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
+ b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
+ b2Vec2 d = cB + rB - cA - rA;
+
+ // Point to line constraint
+ {
+ m_ay = b2Mul(qA, m_localYAxisA);
+ m_sAy = b2Cross(d + rA, m_ay);
+ m_sBy = b2Cross(rB, m_ay);
+
+ m_mass = mA + mB + iA * m_sAy * m_sAy + iB * m_sBy * m_sBy;
+
+ if (m_mass > 0.0f)
+ {
+ m_mass = 1.0f / m_mass;
+ }
+ }
+
+ // Spring constraint
+ m_springMass = 0.0f;
+ m_bias = 0.0f;
+ m_gamma = 0.0f;
+ if (m_frequencyHz > 0.0f)
+ {
+ m_ax = b2Mul(qA, m_localXAxisA);
+ m_sAx = b2Cross(d + rA, m_ax);
+ m_sBx = b2Cross(rB, m_ax);
+
+ float32 invMass = mA + mB + iA * m_sAx * m_sAx + iB * m_sBx * m_sBx;
+
+ if (invMass > 0.0f)
+ {
+ m_springMass = 1.0f / invMass;
+
+ float32 C = b2Dot(d, m_ax);
+
+ // Frequency
+ float32 omega = 2.0f * b2_pi * m_frequencyHz;
+
+ // Damping coefficient
+ float32 d = 2.0f * m_springMass * m_dampingRatio * omega;
+
+ // Spring stiffness
+ float32 k = m_springMass * omega * omega;
+
+ // magic formulas
+ float32 h = data.step.dt;
+ m_gamma = h * (d + h * k);
+ if (m_gamma > 0.0f)
+ {
+ m_gamma = 1.0f / m_gamma;
+ }
+
+ m_bias = C * h * k * m_gamma;
+
+ m_springMass = invMass + m_gamma;
+ if (m_springMass > 0.0f)
+ {
+ m_springMass = 1.0f / m_springMass;
+ }
+ }
+ }
+ else
+ {
+ m_springImpulse = 0.0f;
+ }
+
+ // Rotational motor
+ if (m_enableMotor)
+ {
+ m_motorMass = iA + iB;
+ if (m_motorMass > 0.0f)
+ {
+ m_motorMass = 1.0f / m_motorMass;
+ }
+ }
+ else
+ {
+ m_motorMass = 0.0f;
+ m_motorImpulse = 0.0f;
+ }
+
+ if (data.step.warmStarting)
+ {
+ // Account for variable time step.
+ m_impulse *= data.step.dtRatio;
+ m_springImpulse *= data.step.dtRatio;
+ m_motorImpulse *= data.step.dtRatio;
+
+ b2Vec2 P = m_impulse * m_ay + m_springImpulse * m_ax;
+ float32 LA = m_impulse * m_sAy + m_springImpulse * m_sAx + m_motorImpulse;
+ float32 LB = m_impulse * m_sBy + m_springImpulse * m_sBx + m_motorImpulse;
+
+ vA -= m_invMassA * P;
+ wA -= m_invIA * LA;
+
+ vB += m_invMassB * P;
+ wB += m_invIB * LB;
+ }
+ else
+ {
+ m_impulse = 0.0f;
+ m_springImpulse = 0.0f;
+ m_motorImpulse = 0.0f;
+ }
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+void b2WheelJoint::SolveVelocityConstraints(const b2SolverData& data)
+{
+ float32 mA = m_invMassA, mB = m_invMassB;
+ float32 iA = m_invIA, iB = m_invIB;
+
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ // Solve spring constraint
+ {
+ float32 Cdot = b2Dot(m_ax, vB - vA) + m_sBx * wB - m_sAx * wA;
+ float32 impulse = -m_springMass * (Cdot + m_bias + m_gamma * m_springImpulse);
+ m_springImpulse += impulse;
+
+ b2Vec2 P = impulse * m_ax;
+ float32 LA = impulse * m_sAx;
+ float32 LB = impulse * m_sBx;
+
+ vA -= mA * P;
+ wA -= iA * LA;
+
+ vB += mB * P;
+ wB += iB * LB;
+ }
+
+ // Solve rotational motor constraint
+ {
+ float32 Cdot = wB - wA - m_motorSpeed;
+ float32 impulse = -m_motorMass * Cdot;
+
+ float32 oldImpulse = m_motorImpulse;
+ float32 maxImpulse = data.step.dt * m_maxMotorTorque;
+ m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse);
+ impulse = m_motorImpulse - oldImpulse;
+
+ wA -= iA * impulse;
+ wB += iB * impulse;
+ }
+
+ // Solve point to line constraint
+ {
+ float32 Cdot = b2Dot(m_ay, vB - vA) + m_sBy * wB - m_sAy * wA;
+ float32 impulse = -m_mass * Cdot;
+ m_impulse += impulse;
+
+ b2Vec2 P = impulse * m_ay;
+ float32 LA = impulse * m_sAy;
+ float32 LB = impulse * m_sBy;
+
+ vA -= mA * P;
+ wA -= iA * LA;
+
+ vB += mB * P;
+ wB += iB * LB;
+ }
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+bool b2WheelJoint::SolvePositionConstraints(const b2SolverData& data)
+{
+ b2Vec2 cA = data.positions[m_indexA].c;
+ float32 aA = data.positions[m_indexA].a;
+ b2Vec2 cB = data.positions[m_indexB].c;
+ float32 aB = data.positions[m_indexB].a;
+
+ b2Rot qA(aA), qB(aB);
+
+ b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
+ b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
+ b2Vec2 d = (cB - cA) + rB - rA;
+
+ b2Vec2 ay = b2Mul(qA, m_localYAxisA);
+
+ float32 sAy = b2Cross(d + rA, ay);
+ float32 sBy = b2Cross(rB, ay);
+
+ float32 C = b2Dot(d, ay);
+
+ float32 k = m_invMassA + m_invMassB + m_invIA * m_sAy * m_sAy + m_invIB * m_sBy * m_sBy;
+
+ float32 impulse;
+ if (k != 0.0f)
+ {
+ impulse = - C / k;
+ }
+ else
+ {
+ impulse = 0.0f;
+ }
+
+ b2Vec2 P = impulse * ay;
+ float32 LA = impulse * sAy;
+ float32 LB = impulse * sBy;
+
+ cA -= m_invMassA * P;
+ aA -= m_invIA * LA;
+ cB += m_invMassB * P;
+ aB += m_invIB * LB;
+
+ data.positions[m_indexA].c = cA;
+ data.positions[m_indexA].a = aA;
+ data.positions[m_indexB].c = cB;
+ data.positions[m_indexB].a = aB;
+
+ return b2Abs(C) <= b2_linearSlop;
+}
+
+b2Vec2 b2WheelJoint::GetAnchorA() const
+{
+ return m_bodyA->GetWorldPoint(m_localAnchorA);
+}
+
+b2Vec2 b2WheelJoint::GetAnchorB() const
+{
+ return m_bodyB->GetWorldPoint(m_localAnchorB);
+}
+
+b2Vec2 b2WheelJoint::GetReactionForce(float32 inv_dt) const
+{
+ return inv_dt * (m_impulse * m_ay + m_springImpulse * m_ax);
+}
+
+float32 b2WheelJoint::GetReactionTorque(float32 inv_dt) const
+{
+ return inv_dt * m_motorImpulse;
+}
+
+float32 b2WheelJoint::GetJointTranslation() const
+{
+ b2Body* bA = m_bodyA;
+ b2Body* bB = m_bodyB;
+
+ b2Vec2 pA = bA->GetWorldPoint(m_localAnchorA);
+ b2Vec2 pB = bB->GetWorldPoint(m_localAnchorB);
+ b2Vec2 d = pB - pA;
+ b2Vec2 axis = bA->GetWorldVector(m_localXAxisA);
+
+ float32 translation = b2Dot(d, axis);
+ return translation;
+}
+
+float32 b2WheelJoint::GetJointSpeed() const
+{
+ float32 wA = m_bodyA->m_angularVelocity;
+ float32 wB = m_bodyB->m_angularVelocity;
+ return wB - wA;
+}
+
+bool b2WheelJoint::IsMotorEnabled() const
+{
+ return m_enableMotor;
+}
+
+void b2WheelJoint::EnableMotor(bool flag)
+{
+ m_bodyA->SetAwake(true);
+ m_bodyB->SetAwake(true);
+ m_enableMotor = flag;
+}
+
+void b2WheelJoint::SetMotorSpeed(float32 speed)
+{
+ m_bodyA->SetAwake(true);
+ m_bodyB->SetAwake(true);
+ m_motorSpeed = speed;
+}
+
+void b2WheelJoint::SetMaxMotorTorque(float32 torque)
+{
+ m_bodyA->SetAwake(true);
+ m_bodyB->SetAwake(true);
+ m_maxMotorTorque = torque;
+}
+
+float32 b2WheelJoint::GetMotorTorque(float32 inv_dt) const
+{
+ return inv_dt * m_motorImpulse;
+}
+
+void b2WheelJoint::Dump()
+{
+ int32 indexA = m_bodyA->m_islandIndex;
+ int32 indexB = m_bodyB->m_islandIndex;
+
+ b2Log(" b2WheelJointDef jd;\n");
+ b2Log(" jd.bodyA = bodies[%d];\n", indexA);
+ b2Log(" jd.bodyB = bodies[%d];\n", indexB);
+ b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
+ b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y);
+ b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y);
+ b2Log(" jd.localAxisA.Set(%.15lef, %.15lef);\n", m_localXAxisA.x, m_localXAxisA.y);
+ b2Log(" jd.enableMotor = bool(%d);\n", m_enableMotor);
+ b2Log(" jd.motorSpeed = %.15lef;\n", m_motorSpeed);
+ b2Log(" jd.maxMotorTorque = %.15lef;\n", m_maxMotorTorque);
+ b2Log(" jd.frequencyHz = %.15lef;\n", m_frequencyHz);
+ b2Log(" jd.dampingRatio = %.15lef;\n", m_dampingRatio);
+ b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
+}
diff --git a/tests/box2d/Box2D/Dynamics/Joints/b2WheelJoint.h b/tests/box2d/Box2D/Dynamics/Joints/b2WheelJoint.h new file mode 100755 index 00000000..00afa6ac --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/Joints/b2WheelJoint.h @@ -0,0 +1,224 @@ +/*
+* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_WHEEL_JOINT_H
+#define B2_WHEEL_JOINT_H
+
+#include <Box2D/Dynamics/Joints/b2Joint.h>
+
+/// Wheel joint definition. This requires defining a line of
+/// motion using an axis and an anchor point. The definition uses local
+/// anchor points and a local axis so that the initial configuration
+/// can violate the constraint slightly. The joint translation is zero
+/// when the local anchor points coincide in world space. Using local
+/// anchors and a local axis helps when saving and loading a game.
+// emscripten - b2WheelJointDef: add functions to set/get base class members
+struct b2WheelJointDef : public b2JointDef
+{
+ b2WheelJointDef()
+ {
+ type = e_wheelJoint;
+ localAnchorA.SetZero();
+ localAnchorB.SetZero();
+ localAxisA.Set(1.0f, 0.0f);
+ enableMotor = false;
+ maxMotorTorque = 0.0f;
+ motorSpeed = 0.0f;
+ frequencyHz = 2.0f;
+ dampingRatio = 0.7f;
+ }
+
+ /// Initialize the bodies, anchors, axis, and reference angle using the world
+ /// anchor and world axis.
+ void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor, const b2Vec2& axis);
+
+ /// The local anchor point relative to bodyA's origin.
+ b2Vec2 localAnchorA;
+
+ /// The local anchor point relative to bodyB's origin.
+ b2Vec2 localAnchorB;
+
+ /// The local translation axis in bodyA.
+ b2Vec2 localAxisA;
+
+ /// Enable/disable the joint motor.
+ bool enableMotor;
+
+ /// The maximum motor torque, usually in N-m.
+ float32 maxMotorTorque;
+
+ /// The desired motor speed in radians per second.
+ float32 motorSpeed;
+
+ /// Suspension frequency, zero indicates no suspension
+ float32 frequencyHz;
+
+ /// Suspension damping ratio, one indicates critical damping
+ float32 dampingRatio;
+
+ // to generate javascript bindings
+ void set_bodyA(b2Body* b) { bodyA = b; }
+ void set_bodyB(b2Body* b) { bodyB = b; }
+ void set_collideConnected(bool b) { collideConnected = b; }
+ b2Body* get_bodyA(b2Body* b) { return bodyA; }
+ b2Body* get_bodyB(b2Body* b) { return bodyB; }
+ bool get_collideConnected(bool b) { return collideConnected; }
+};
+
+/// A wheel joint. This joint provides two degrees of freedom: translation
+/// along an axis fixed in bodyA and rotation in the plane. You can use a
+/// joint limit to restrict the range of motion and a joint motor to drive
+/// the rotation or to model rotational friction.
+/// This joint is designed for vehicle suspensions.
+// emscripten - b2WheelJoint: make constructor public
+class b2WheelJoint : public b2Joint
+{
+public:
+ void GetDefinition(b2WheelJointDef* def) const;
+
+ b2Vec2 GetAnchorA() const;
+ b2Vec2 GetAnchorB() const;
+
+ b2Vec2 GetReactionForce(float32 inv_dt) const;
+ float32 GetReactionTorque(float32 inv_dt) const;
+
+ /// The local anchor point relative to bodyA's origin.
+ const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; }
+
+ /// The local anchor point relative to bodyB's origin.
+ const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; }
+
+ /// The local joint axis relative to bodyA.
+ const b2Vec2& GetLocalAxisA() const { return m_localXAxisA; }
+
+ /// Get the current joint translation, usually in meters.
+ float32 GetJointTranslation() const;
+
+ /// Get the current joint translation speed, usually in meters per second.
+ float32 GetJointSpeed() const;
+
+ /// Is the joint motor enabled?
+ bool IsMotorEnabled() const;
+
+ /// Enable/disable the joint motor.
+ void EnableMotor(bool flag);
+
+ /// Set the motor speed, usually in radians per second.
+ void SetMotorSpeed(float32 speed);
+
+ /// Get the motor speed, usually in radians per second.
+ float32 GetMotorSpeed() const;
+
+ /// Set/Get the maximum motor force, usually in N-m.
+ void SetMaxMotorTorque(float32 torque);
+ float32 GetMaxMotorTorque() const;
+
+ /// Get the current motor torque given the inverse time step, usually in N-m.
+ float32 GetMotorTorque(float32 inv_dt) const;
+
+ /// Set/Get the spring frequency in hertz. Setting the frequency to zero disables the spring.
+ void SetSpringFrequencyHz(float32 hz);
+ float32 GetSpringFrequencyHz() const;
+
+ /// Set/Get the spring damping ratio
+ void SetSpringDampingRatio(float32 ratio);
+ float32 GetSpringDampingRatio() const;
+
+ /// Dump to b2Log
+ void Dump();
+
+ b2WheelJoint(const b2WheelJointDef* def);
+
+protected:
+
+ friend class b2Joint;
+
+ void InitVelocityConstraints(const b2SolverData& data);
+ void SolveVelocityConstraints(const b2SolverData& data);
+ bool SolvePositionConstraints(const b2SolverData& data);
+
+ float32 m_frequencyHz;
+ float32 m_dampingRatio;
+
+ // Solver shared
+ b2Vec2 m_localAnchorA;
+ b2Vec2 m_localAnchorB;
+ b2Vec2 m_localXAxisA;
+ b2Vec2 m_localYAxisA;
+
+ float32 m_impulse;
+ float32 m_motorImpulse;
+ float32 m_springImpulse;
+
+ float32 m_maxMotorTorque;
+ float32 m_motorSpeed;
+ bool m_enableMotor;
+
+ // Solver temp
+ int32 m_indexA;
+ int32 m_indexB;
+ b2Vec2 m_localCenterA;
+ b2Vec2 m_localCenterB;
+ float32 m_invMassA;
+ float32 m_invMassB;
+ float32 m_invIA;
+ float32 m_invIB;
+
+ b2Vec2 m_ax, m_ay;
+ float32 m_sAx, m_sBx;
+ float32 m_sAy, m_sBy;
+
+ float32 m_mass;
+ float32 m_motorMass;
+ float32 m_springMass;
+
+ float32 m_bias;
+ float32 m_gamma;
+};
+
+inline float32 b2WheelJoint::GetMotorSpeed() const
+{
+ return m_motorSpeed;
+}
+
+inline float32 b2WheelJoint::GetMaxMotorTorque() const
+{
+ return m_maxMotorTorque;
+}
+
+inline void b2WheelJoint::SetSpringFrequencyHz(float32 hz)
+{
+ m_frequencyHz = hz;
+}
+
+inline float32 b2WheelJoint::GetSpringFrequencyHz() const
+{
+ return m_frequencyHz;
+}
+
+inline void b2WheelJoint::SetSpringDampingRatio(float32 ratio)
+{
+ m_dampingRatio = ratio;
+}
+
+inline float32 b2WheelJoint::GetSpringDampingRatio() const
+{
+ return m_dampingRatio;
+}
+
+#endif
diff --git a/tests/box2d/Box2D/Dynamics/b2Body.cpp b/tests/box2d/Box2D/Dynamics/b2Body.cpp new file mode 100755 index 00000000..b50bf45a --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/b2Body.cpp @@ -0,0 +1,514 @@ +/*
+* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Dynamics/b2Body.h>
+#include <Box2D/Dynamics/b2Fixture.h>
+#include <Box2D/Dynamics/b2World.h>
+#include <Box2D/Dynamics/Contacts/b2Contact.h>
+#include <Box2D/Dynamics/Joints/b2Joint.h>
+
+b2Body::b2Body(const b2BodyDef* bd, b2World* world)
+{
+ b2Assert(bd->position.IsValid());
+ b2Assert(bd->linearVelocity.IsValid());
+ b2Assert(b2IsValid(bd->angle));
+ b2Assert(b2IsValid(bd->angularVelocity));
+ b2Assert(b2IsValid(bd->angularDamping) && bd->angularDamping >= 0.0f);
+ b2Assert(b2IsValid(bd->linearDamping) && bd->linearDamping >= 0.0f);
+
+ m_flags = 0;
+
+ if (bd->bullet)
+ {
+ m_flags |= e_bulletFlag;
+ }
+ if (bd->fixedRotation)
+ {
+ m_flags |= e_fixedRotationFlag;
+ }
+ if (bd->allowSleep)
+ {
+ m_flags |= e_autoSleepFlag;
+ }
+ if (bd->awake)
+ {
+ m_flags |= e_awakeFlag;
+ }
+ if (bd->active)
+ {
+ m_flags |= e_activeFlag;
+ }
+
+ m_world = world;
+
+ m_xf.p = bd->position;
+ m_xf.q.Set(bd->angle);
+
+ m_sweep.localCenter.SetZero();
+ m_sweep.c0 = m_xf.p;
+ m_sweep.c = m_xf.p;
+ m_sweep.a0 = bd->angle;
+ m_sweep.a = bd->angle;
+ m_sweep.alpha0 = 0.0f;
+
+ m_jointList = NULL;
+ m_contactList = NULL;
+ m_prev = NULL;
+ m_next = NULL;
+
+ m_linearVelocity = bd->linearVelocity;
+ m_angularVelocity = bd->angularVelocity;
+
+ m_linearDamping = bd->linearDamping;
+ m_angularDamping = bd->angularDamping;
+ m_gravityScale = bd->gravityScale;
+
+ m_force.SetZero();
+ m_torque = 0.0f;
+
+ m_sleepTime = 0.0f;
+
+ m_type = bd->type;
+
+ if (m_type == b2_dynamicBody)
+ {
+ m_mass = 1.0f;
+ m_invMass = 1.0f;
+ }
+ else
+ {
+ m_mass = 0.0f;
+ m_invMass = 0.0f;
+ }
+
+ m_I = 0.0f;
+ m_invI = 0.0f;
+
+ m_userData = bd->userData;
+
+ m_fixtureList = NULL;
+ m_fixtureCount = 0;
+}
+
+b2Body::~b2Body()
+{
+ // shapes and joints are destroyed in b2World::Destroy
+}
+
+void b2Body::SetType(b2BodyType type)
+{
+ b2Assert(m_world->IsLocked() == false);
+ if (m_world->IsLocked() == true)
+ {
+ return;
+ }
+
+ if (m_type == type)
+ {
+ return;
+ }
+
+ m_type = type;
+
+ ResetMassData();
+
+ if (m_type == b2_staticBody)
+ {
+ m_linearVelocity.SetZero();
+ m_angularVelocity = 0.0f;
+ m_sweep.a0 = m_sweep.a;
+ m_sweep.c0 = m_sweep.c;
+ SynchronizeFixtures();
+ }
+
+ SetAwake(true);
+
+ m_force.SetZero();
+ m_torque = 0.0f;
+
+ // Since the body type changed, we need to flag contacts for filtering.
+ for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
+ {
+ f->Refilter();
+ }
+}
+
+b2Fixture* b2Body::CreateFixture(const b2FixtureDef* def)
+{
+ b2Assert(m_world->IsLocked() == false);
+ if (m_world->IsLocked() == true)
+ {
+ return NULL;
+ }
+
+ b2BlockAllocator* allocator = &m_world->m_blockAllocator;
+
+ void* memory = allocator->Allocate(sizeof(b2Fixture));
+ b2Fixture* fixture = new (memory) b2Fixture;
+ fixture->Create(allocator, this, def);
+
+ if (m_flags & e_activeFlag)
+ {
+ b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
+ fixture->CreateProxies(broadPhase, m_xf);
+ }
+
+ fixture->m_next = m_fixtureList;
+ m_fixtureList = fixture;
+ ++m_fixtureCount;
+
+ fixture->m_body = this;
+
+ // Adjust mass properties if needed.
+ if (fixture->m_density > 0.0f)
+ {
+ ResetMassData();
+ }
+
+ // Let the world know we have a new fixture. This will cause new contacts
+ // to be created at the beginning of the next time step.
+ m_world->m_flags |= b2World::e_newFixture;
+
+ return fixture;
+}
+
+b2Fixture* b2Body::CreateFixture(const b2Shape* shape, float32 density)
+{
+ b2FixtureDef def;
+ def.shape = shape;
+ def.density = density;
+
+ return CreateFixture(&def);
+}
+
+void b2Body::DestroyFixture(b2Fixture* fixture)
+{
+ b2Assert(m_world->IsLocked() == false);
+ if (m_world->IsLocked() == true)
+ {
+ return;
+ }
+
+ b2Assert(fixture->m_body == this);
+
+ // Remove the fixture from this body's singly linked list.
+ b2Assert(m_fixtureCount > 0);
+ b2Fixture** node = &m_fixtureList;
+ bool found = false;
+ while (*node != NULL)
+ {
+ if (*node == fixture)
+ {
+ *node = fixture->m_next;
+ found = true;
+ break;
+ }
+
+ node = &(*node)->m_next;
+ }
+
+ // You tried to remove a shape that is not attached to this body.
+ b2Assert(found);
+
+ // Destroy any contacts associated with the fixture.
+ b2ContactEdge* edge = m_contactList;
+ while (edge)
+ {
+ b2Contact* c = edge->contact;
+ edge = edge->next;
+
+ b2Fixture* fixtureA = c->GetFixtureA();
+ b2Fixture* fixtureB = c->GetFixtureB();
+
+ if (fixture == fixtureA || fixture == fixtureB)
+ {
+ // This destroys the contact and removes it from
+ // this body's contact list.
+ m_world->m_contactManager.Destroy(c);
+ }
+ }
+
+ b2BlockAllocator* allocator = &m_world->m_blockAllocator;
+
+ if (m_flags & e_activeFlag)
+ {
+ b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
+ fixture->DestroyProxies(broadPhase);
+ }
+
+ fixture->Destroy(allocator);
+ fixture->m_body = NULL;
+ fixture->m_next = NULL;
+ fixture->~b2Fixture();
+ allocator->Free(fixture, sizeof(b2Fixture));
+
+ --m_fixtureCount;
+
+ // Reset the mass data.
+ ResetMassData();
+}
+
+void b2Body::ResetMassData()
+{
+ // Compute mass data from shapes. Each shape has its own density.
+ m_mass = 0.0f;
+ m_invMass = 0.0f;
+ m_I = 0.0f;
+ m_invI = 0.0f;
+ m_sweep.localCenter.SetZero();
+
+ // Static and kinematic bodies have zero mass.
+ if (m_type == b2_staticBody || m_type == b2_kinematicBody)
+ {
+ m_sweep.c0 = m_xf.p;
+ m_sweep.c = m_xf.p;
+ m_sweep.a0 = m_sweep.a;
+ return;
+ }
+
+ b2Assert(m_type == b2_dynamicBody);
+
+ // Accumulate mass over all fixtures.
+ b2Vec2 localCenter = b2Vec2_zero;
+ for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
+ {
+ if (f->m_density == 0.0f)
+ {
+ continue;
+ }
+
+ b2MassData massData;
+ f->GetMassData(&massData);
+ m_mass += massData.mass;
+ localCenter += massData.mass * massData.center;
+ m_I += massData.I;
+ }
+
+ // Compute center of mass.
+ if (m_mass > 0.0f)
+ {
+ m_invMass = 1.0f / m_mass;
+ localCenter *= m_invMass;
+ }
+ else
+ {
+ // Force all dynamic bodies to have a positive mass.
+ m_mass = 1.0f;
+ m_invMass = 1.0f;
+ }
+
+ if (m_I > 0.0f && (m_flags & e_fixedRotationFlag) == 0)
+ {
+ // Center the inertia about the center of mass.
+ m_I -= m_mass * b2Dot(localCenter, localCenter);
+ b2Assert(m_I > 0.0f);
+ m_invI = 1.0f / m_I;
+
+ }
+ else
+ {
+ m_I = 0.0f;
+ m_invI = 0.0f;
+ }
+
+ // Move center of mass.
+ b2Vec2 oldCenter = m_sweep.c;
+ m_sweep.localCenter = localCenter;
+ m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter);
+
+ // Update center of mass velocity.
+ m_linearVelocity += b2Cross(m_angularVelocity, m_sweep.c - oldCenter);
+}
+
+void b2Body::SetMassData(const b2MassData* massData)
+{
+ b2Assert(m_world->IsLocked() == false);
+ if (m_world->IsLocked() == true)
+ {
+ return;
+ }
+
+ if (m_type != b2_dynamicBody)
+ {
+ return;
+ }
+
+ m_invMass = 0.0f;
+ m_I = 0.0f;
+ m_invI = 0.0f;
+
+ m_mass = massData->mass;
+ if (m_mass <= 0.0f)
+ {
+ m_mass = 1.0f;
+ }
+
+ m_invMass = 1.0f / m_mass;
+
+ if (massData->I > 0.0f && (m_flags & b2Body::e_fixedRotationFlag) == 0)
+ {
+ m_I = massData->I - m_mass * b2Dot(massData->center, massData->center);
+ b2Assert(m_I > 0.0f);
+ m_invI = 1.0f / m_I;
+ }
+
+ // Move center of mass.
+ b2Vec2 oldCenter = m_sweep.c;
+ m_sweep.localCenter = massData->center;
+ m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter);
+
+ // Update center of mass velocity.
+ m_linearVelocity += b2Cross(m_angularVelocity, m_sweep.c - oldCenter);
+}
+
+bool b2Body::ShouldCollide(const b2Body* other) const
+{
+ // At least one body should be dynamic.
+ if (m_type != b2_dynamicBody && other->m_type != b2_dynamicBody)
+ {
+ return false;
+ }
+
+ // Does a joint prevent collision?
+ for (b2JointEdge* jn = m_jointList; jn; jn = jn->next)
+ {
+ if (jn->other == other)
+ {
+ if (jn->joint->m_collideConnected == false)
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+void b2Body::SetTransform(const b2Vec2& position, float32 angle)
+{
+ b2Assert(m_world->IsLocked() == false);
+ if (m_world->IsLocked() == true)
+ {
+ return;
+ }
+
+ m_xf.q.Set(angle);
+ m_xf.p = position;
+
+ m_sweep.c = b2Mul(m_xf, m_sweep.localCenter);
+ m_sweep.a = angle;
+
+ m_sweep.c0 = m_sweep.c;
+ m_sweep.a0 = angle;
+
+ b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
+ for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
+ {
+ f->Synchronize(broadPhase, m_xf, m_xf);
+ }
+
+ m_world->m_contactManager.FindNewContacts();
+}
+
+void b2Body::SynchronizeFixtures()
+{
+ b2Transform xf1;
+ xf1.q.Set(m_sweep.a0);
+ xf1.p = m_sweep.c0 - b2Mul(xf1.q, m_sweep.localCenter);
+
+ b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
+ for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
+ {
+ f->Synchronize(broadPhase, xf1, m_xf);
+ }
+}
+
+void b2Body::SetActive(bool flag)
+{
+ b2Assert(m_world->IsLocked() == false);
+
+ if (flag == IsActive())
+ {
+ return;
+ }
+
+ if (flag)
+ {
+ m_flags |= e_activeFlag;
+
+ // Create all proxies.
+ b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
+ for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
+ {
+ f->CreateProxies(broadPhase, m_xf);
+ }
+
+ // Contacts are created the next time step.
+ }
+ else
+ {
+ m_flags &= ~e_activeFlag;
+
+ // Destroy all proxies.
+ b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
+ for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
+ {
+ f->DestroyProxies(broadPhase);
+ }
+
+ // Destroy the attached contacts.
+ b2ContactEdge* ce = m_contactList;
+ while (ce)
+ {
+ b2ContactEdge* ce0 = ce;
+ ce = ce->next;
+ m_world->m_contactManager.Destroy(ce0->contact);
+ }
+ m_contactList = NULL;
+ }
+}
+
+void b2Body::Dump()
+{
+ int32 bodyIndex = m_islandIndex;
+
+ b2Log("{\n");
+ b2Log(" b2BodyDef bd;\n");
+ b2Log(" bd.type = b2BodyType(%d);\n", m_type);
+ b2Log(" bd.position.Set(%.15lef, %.15lef);\n", m_xf.p.x, m_xf.p.y);
+ b2Log(" bd.angle = %.15lef;\n", m_sweep.a);
+ b2Log(" bd.linearVelocity.Set(%.15lef, %.15lef);\n", m_linearVelocity.x, m_linearVelocity.y);
+ b2Log(" bd.angularVelocity = %.15lef;\n", m_angularVelocity);
+ b2Log(" bd.linearDamping = %.15lef;\n", m_linearDamping);
+ b2Log(" bd.angularDamping = %.15lef;\n", m_angularDamping);
+ b2Log(" bd.allowSleep = bool(%d);\n", m_flags & e_autoSleepFlag);
+ b2Log(" bd.awake = bool(%d);\n", m_flags & e_awakeFlag);
+ b2Log(" bd.fixedRotation = bool(%d);\n", m_flags & e_fixedRotationFlag);
+ b2Log(" bd.bullet = bool(%d);\n", m_flags & e_bulletFlag);
+ b2Log(" bd.active = bool(%d);\n", m_flags & e_activeFlag);
+ b2Log(" bd.gravityScale = %.15lef;\n", m_gravityScale);
+ b2Log(" bodies[%d] = m_world->CreateBody(&bd);\n", m_islandIndex);
+ b2Log("\n");
+ for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
+ {
+ b2Log(" {\n");
+ f->Dump(bodyIndex);
+ b2Log(" }\n");
+ }
+ b2Log("}\n");
+}
\ No newline at end of file diff --git a/tests/box2d/Box2D/Dynamics/b2Body.h b/tests/box2d/Box2D/Dynamics/b2Body.h new file mode 100755 index 00000000..3b1be1c3 --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/b2Body.h @@ -0,0 +1,848 @@ +/*
+* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_BODY_H
+#define B2_BODY_H
+
+#include <Box2D/Common/b2Math.h>
+#include <Box2D/Collision/Shapes/b2Shape.h>
+#ifndef EM_NO_LIBCPP
+#include <memory>
+#endif
+
+class b2Fixture;
+class b2Joint;
+class b2Contact;
+class b2Controller;
+class b2World;
+struct b2FixtureDef;
+struct b2JointEdge;
+struct b2ContactEdge;
+
+/// The body type.
+/// static: zero mass, zero velocity, may be manually moved
+/// kinematic: zero mass, non-zero velocity set by user, moved by solver
+/// dynamic: positive mass, non-zero velocity determined by forces, moved by solver
+enum b2BodyType
+{
+ b2_staticBody = 0,
+ b2_kinematicBody,
+ b2_dynamicBody
+
+ // TODO_ERIN
+ //b2_bulletBody,
+};
+
+/// A body definition holds all the data needed to construct a rigid body.
+/// You can safely re-use body definitions. Shapes are added to a body after construction.
+struct b2BodyDef
+{
+ /// This constructor sets the body definition default values.
+ b2BodyDef()
+ {
+ userData = NULL;
+ position.Set(0.0f, 0.0f);
+ angle = 0.0f;
+ linearVelocity.Set(0.0f, 0.0f);
+ angularVelocity = 0.0f;
+ linearDamping = 0.0f;
+ angularDamping = 0.0f;
+ allowSleep = true;
+ awake = true;
+ fixedRotation = false;
+ bullet = false;
+ type = b2_staticBody;
+ active = true;
+ gravityScale = 1.0f;
+ }
+
+ /// The body type: static, kinematic, or dynamic.
+ /// Note: if a dynamic body would have zero mass, the mass is set to one.
+ b2BodyType type;
+
+ /// The world position of the body. Avoid creating bodies at the origin
+ /// since this can lead to many overlapping shapes.
+ b2Vec2 position;
+
+ /// The world angle of the body in radians.
+ float32 angle;
+
+ /// The linear velocity of the body's origin in world co-ordinates.
+ b2Vec2 linearVelocity;
+
+ /// The angular velocity of the body.
+ float32 angularVelocity;
+
+ /// Linear damping is use to reduce the linear velocity. The damping parameter
+ /// can be larger than 1.0f but the damping effect becomes sensitive to the
+ /// time step when the damping parameter is large.
+ float32 linearDamping;
+
+ /// Angular damping is use to reduce the angular velocity. The damping parameter
+ /// can be larger than 1.0f but the damping effect becomes sensitive to the
+ /// time step when the damping parameter is large.
+ float32 angularDamping;
+
+ /// Set this flag to false if this body should never fall asleep. Note that
+ /// this increases CPU usage.
+ bool allowSleep;
+
+ /// Is this body initially awake or sleeping?
+ bool awake;
+
+ /// Should this body be prevented from rotating? Useful for characters.
+ bool fixedRotation;
+
+ /// Is this a fast moving body that should be prevented from tunneling through
+ /// other moving bodies? Note that all bodies are prevented from tunneling through
+ /// kinematic and static bodies. This setting is only considered on dynamic bodies.
+ /// @warning You should use this flag sparingly since it increases processing time.
+ bool bullet;
+
+ /// Does this body start out active?
+ bool active;
+
+ /// Use this to store application specific body data.
+ void* userData;
+
+ /// Scale the gravity applied to this body.
+ float32 gravityScale;
+};
+
+/// A rigid body. These are created via b2World::CreateBody.
+class b2Body
+{
+public:
+ /// Creates a fixture and attach it to this body. Use this function if you need
+ /// to set some fixture parameters, like friction. Otherwise you can create the
+ /// fixture directly from a shape.
+ /// If the density is non-zero, this function automatically updates the mass of the body.
+ /// Contacts are not created until the next time step.
+ /// @param def the fixture definition.
+ /// @warning This function is locked during callbacks.
+ b2Fixture* CreateFixture(const b2FixtureDef* def);
+
+ /// Creates a fixture from a shape and attach it to this body.
+ /// This is a convenience function. Use b2FixtureDef if you need to set parameters
+ /// like friction, restitution, user data, or filtering.
+ /// If the density is non-zero, this function automatically updates the mass of the body.
+ /// @param shape the shape to be cloned.
+ /// @param density the shape density (set to zero for static bodies).
+ /// @warning This function is locked during callbacks.
+ b2Fixture* CreateFixture(const b2Shape* shape, float32 density);
+
+ /// Destroy a fixture. This removes the fixture from the broad-phase and
+ /// destroys all contacts associated with this fixture. This will
+ /// automatically adjust the mass of the body if the body is dynamic and the
+ /// fixture has positive density.
+ /// All fixtures attached to a body are implicitly destroyed when the body is destroyed.
+ /// @param fixture the fixture to be removed.
+ /// @warning This function is locked during callbacks.
+ void DestroyFixture(b2Fixture* fixture);
+
+ /// Set the position of the body's origin and rotation.
+ /// This breaks any contacts and wakes the other bodies.
+ /// Manipulating a body's transform may cause non-physical behavior.
+ /// @param position the world position of the body's local origin.
+ /// @param angle the world rotation in radians.
+ void SetTransform(const b2Vec2& position, float32 angle);
+
+ /// Get the body transform for the body's origin.
+ /// @return the world transform of the body's origin.
+ const b2Transform& GetTransform() const;
+
+ /// Get the world body origin position.
+ /// @return the world position of the body's origin.
+ const b2Vec2& GetPosition() const;
+
+ /// Get the angle in radians.
+ /// @return the current world rotation angle in radians.
+ float32 GetAngle() const;
+
+ /// Get the world position of the center of mass.
+ const b2Vec2& GetWorldCenter() const;
+
+ /// Get the local position of the center of mass.
+ const b2Vec2& GetLocalCenter() const;
+
+ /// Set the linear velocity of the center of mass.
+ /// @param v the new linear velocity of the center of mass.
+ void SetLinearVelocity(const b2Vec2& v);
+
+ /// Get the linear velocity of the center of mass.
+ /// @return the linear velocity of the center of mass.
+ b2Vec2 GetLinearVelocity() const;
+
+ /// Set the angular velocity.
+ /// @param omega the new angular velocity in radians/second.
+ void SetAngularVelocity(float32 omega);
+
+ /// Get the angular velocity.
+ /// @return the angular velocity in radians/second.
+ float32 GetAngularVelocity() const;
+
+ /// Apply a force at a world point. If the force is not
+ /// applied at the center of mass, it will generate a torque and
+ /// affect the angular velocity. This wakes up the body.
+ /// @param force the world force vector, usually in Newtons (N).
+ /// @param point the world position of the point of application.
+ void ApplyForce(const b2Vec2& force, const b2Vec2& point);
+
+ /// Apply a force to the center of mass. This wakes up the body.
+ /// @param force the world force vector, usually in Newtons (N).
+ void ApplyForceToCenter(const b2Vec2& force);
+
+ /// Apply a torque. This affects the angular velocity
+ /// without affecting the linear velocity of the center of mass.
+ /// This wakes up the body.
+ /// @param torque about the z-axis (out of the screen), usually in N-m.
+ void ApplyTorque(float32 torque);
+
+ /// Apply an impulse at a point. This immediately modifies the velocity.
+ /// It also modifies the angular velocity if the point of application
+ /// is not at the center of mass. This wakes up the body.
+ /// @param impulse the world impulse vector, usually in N-seconds or kg-m/s.
+ /// @param point the world position of the point of application.
+ void ApplyLinearImpulse(const b2Vec2& impulse, const b2Vec2& point);
+
+ /// Apply an angular impulse.
+ /// @param impulse the angular impulse in units of kg*m*m/s
+ void ApplyAngularImpulse(float32 impulse);
+
+ /// Get the total mass of the body.
+ /// @return the mass, usually in kilograms (kg).
+ float32 GetMass() const;
+
+ /// Get the rotational inertia of the body about the local origin.
+ /// @return the rotational inertia, usually in kg-m^2.
+ float32 GetInertia() const;
+
+ /// Get the mass data of the body.
+ /// @return a struct containing the mass, inertia and center of the body.
+ void GetMassData(b2MassData* data) const;
+
+ /// Set the mass properties to override the mass properties of the fixtures.
+ /// Note that this changes the center of mass position.
+ /// Note that creating or destroying fixtures can also alter the mass.
+ /// This function has no effect if the body isn't dynamic.
+ /// @param massData the mass properties.
+ void SetMassData(const b2MassData* data);
+
+ /// This resets the mass properties to the sum of the mass properties of the fixtures.
+ /// This normally does not need to be called unless you called SetMassData to override
+ /// the mass and you later want to reset the mass.
+ void ResetMassData();
+
+ /// Get the world coordinates of a point given the local coordinates.
+ /// @param localPoint a point on the body measured relative the the body's origin.
+ /// @return the same point expressed in world coordinates.
+ b2Vec2 GetWorldPoint(const b2Vec2& localPoint) const;
+
+ /// Get the world coordinates of a vector given the local coordinates.
+ /// @param localVector a vector fixed in the body.
+ /// @return the same vector expressed in world coordinates.
+ b2Vec2 GetWorldVector(const b2Vec2& localVector) const;
+
+ /// Gets a local point relative to the body's origin given a world point.
+ /// @param a point in world coordinates.
+ /// @return the corresponding local point relative to the body's origin.
+ b2Vec2 GetLocalPoint(const b2Vec2& worldPoint) const;
+
+ /// Gets a local vector given a world vector.
+ /// @param a vector in world coordinates.
+ /// @return the corresponding local vector.
+ b2Vec2 GetLocalVector(const b2Vec2& worldVector) const;
+
+ /// Get the world linear velocity of a world point attached to this body.
+ /// @param a point in world coordinates.
+ /// @return the world velocity of a point.
+ b2Vec2 GetLinearVelocityFromWorldPoint(const b2Vec2& worldPoint) const;
+
+ /// Get the world velocity of a local point.
+ /// @param a point in local coordinates.
+ /// @return the world velocity of a point.
+ b2Vec2 GetLinearVelocityFromLocalPoint(const b2Vec2& localPoint) const;
+
+ /// Get the linear damping of the body.
+ float32 GetLinearDamping() const;
+
+ /// Set the linear damping of the body.
+ void SetLinearDamping(float32 linearDamping);
+
+ /// Get the angular damping of the body.
+ float32 GetAngularDamping() const;
+
+ /// Set the angular damping of the body.
+ void SetAngularDamping(float32 angularDamping);
+
+ /// Get the gravity scale of the body.
+ float32 GetGravityScale() const;
+
+ /// Set the gravity scale of the body.
+ void SetGravityScale(float32 scale);
+
+ /// Set the type of this body. This may alter the mass and velocity.
+ void SetType(b2BodyType type);
+
+ /// Get the type of this body.
+ b2BodyType GetType() const;
+
+ /// Should this body be treated like a bullet for continuous collision detection?
+ void SetBullet(bool flag);
+
+ /// Is this body treated like a bullet for continuous collision detection?
+ bool IsBullet() const;
+
+ /// You can disable sleeping on this body. If you disable sleeping, the
+ /// body will be woken.
+ void SetSleepingAllowed(bool flag);
+
+ /// Is this body allowed to sleep
+ bool IsSleepingAllowed() const;
+
+ /// Set the sleep state of the body. A sleeping body has very
+ /// low CPU cost.
+ /// @param flag set to true to put body to sleep, false to wake it.
+ void SetAwake(bool flag);
+
+ /// Get the sleeping state of this body.
+ /// @return true if the body is sleeping.
+ bool IsAwake() const;
+
+ /// Set the active state of the body. An inactive body is not
+ /// simulated and cannot be collided with or woken up.
+ /// If you pass a flag of true, all fixtures will be added to the
+ /// broad-phase.
+ /// If you pass a flag of false, all fixtures will be removed from
+ /// the broad-phase and all contacts will be destroyed.
+ /// Fixtures and joints are otherwise unaffected. You may continue
+ /// to create/destroy fixtures and joints on inactive bodies.
+ /// Fixtures on an inactive body are implicitly inactive and will
+ /// not participate in collisions, ray-casts, or queries.
+ /// Joints connected to an inactive body are implicitly inactive.
+ /// An inactive body is still owned by a b2World object and remains
+ /// in the body list.
+ void SetActive(bool flag);
+
+ /// Get the active state of the body.
+ bool IsActive() const;
+
+ /// Set this body to have fixed rotation. This causes the mass
+ /// to be reset.
+ void SetFixedRotation(bool flag);
+
+ /// Does this body have fixed rotation?
+ bool IsFixedRotation() const;
+
+ /// Get the list of all fixtures attached to this body.
+ b2Fixture* GetFixtureList();
+ const b2Fixture* GetFixtureList() const;
+
+ /// Get the list of all joints attached to this body.
+ b2JointEdge* GetJointList();
+ const b2JointEdge* GetJointList() const;
+
+ /// Get the list of all contacts attached to this body.
+ /// @warning this list changes during the time step and you may
+ /// miss some collisions if you don't use b2ContactListener.
+ b2ContactEdge* GetContactList();
+ const b2ContactEdge* GetContactList() const;
+
+ /// Get the next body in the world's body list.
+ b2Body* GetNext();
+ const b2Body* GetNext() const;
+
+ /// Get the user data pointer that was provided in the body definition.
+ void* GetUserData() const;
+
+ /// Set the user data. Use this to store your application specific data.
+ void SetUserData(void* data);
+
+ /// Get the parent world of this body.
+ b2World* GetWorld();
+ const b2World* GetWorld() const;
+
+ /// Dump this body to a log file
+ void Dump();
+
+private:
+
+ friend class b2World;
+ friend class b2Island;
+ friend class b2ContactManager;
+ friend class b2ContactSolver;
+ friend class b2Contact;
+
+ friend class b2DistanceJoint;
+ friend class b2GearJoint;
+ friend class b2WheelJoint;
+ friend class b2MouseJoint;
+ friend class b2PrismaticJoint;
+ friend class b2PulleyJoint;
+ friend class b2RevoluteJoint;
+ friend class b2WeldJoint;
+ friend class b2FrictionJoint;
+ friend class b2RopeJoint;
+
+ // m_flags
+ enum
+ {
+ e_islandFlag = 0x0001,
+ e_awakeFlag = 0x0002,
+ e_autoSleepFlag = 0x0004,
+ e_bulletFlag = 0x0008,
+ e_fixedRotationFlag = 0x0010,
+ e_activeFlag = 0x0020,
+ e_toiFlag = 0x0040
+ };
+
+ b2Body(const b2BodyDef* bd, b2World* world);
+ ~b2Body();
+
+ void SynchronizeFixtures();
+ void SynchronizeTransform();
+
+ // This is used to prevent connected bodies from colliding.
+ // It may lie, depending on the collideConnected flag.
+ bool ShouldCollide(const b2Body* other) const;
+
+ void Advance(float32 t);
+
+ b2BodyType m_type;
+
+ uint16 m_flags;
+
+ int32 m_islandIndex;
+
+ b2Transform m_xf; // the body origin transform
+ b2Sweep m_sweep; // the swept motion for CCD
+
+ b2Vec2 m_linearVelocity;
+ float32 m_angularVelocity;
+
+ b2Vec2 m_force;
+ float32 m_torque;
+
+ b2World* m_world;
+ b2Body* m_prev;
+ b2Body* m_next;
+
+ b2Fixture* m_fixtureList;
+ int32 m_fixtureCount;
+
+ b2JointEdge* m_jointList;
+ b2ContactEdge* m_contactList;
+
+ float32 m_mass, m_invMass;
+
+ // Rotational inertia about the center of mass.
+ float32 m_I, m_invI;
+
+ float32 m_linearDamping;
+ float32 m_angularDamping;
+ float32 m_gravityScale;
+
+ float32 m_sleepTime;
+
+ void* m_userData;
+};
+
+inline b2BodyType b2Body::GetType() const
+{
+ return m_type;
+}
+
+inline const b2Transform& b2Body::GetTransform() const
+{
+ return m_xf;
+}
+
+inline const b2Vec2& b2Body::GetPosition() const
+{
+ return m_xf.p;
+}
+
+inline float32 b2Body::GetAngle() const
+{
+ return m_sweep.a;
+}
+
+inline const b2Vec2& b2Body::GetWorldCenter() const
+{
+ return m_sweep.c;
+}
+
+inline const b2Vec2& b2Body::GetLocalCenter() const
+{
+ return m_sweep.localCenter;
+}
+
+inline void b2Body::SetLinearVelocity(const b2Vec2& v)
+{
+ if (m_type == b2_staticBody)
+ {
+ return;
+ }
+
+ if (b2Dot(v,v) > 0.0f)
+ {
+ SetAwake(true);
+ }
+
+ m_linearVelocity = v;
+}
+
+inline b2Vec2 b2Body::GetLinearVelocity() const
+{
+ return m_linearVelocity;
+}
+
+inline void b2Body::SetAngularVelocity(float32 w)
+{
+ if (m_type == b2_staticBody)
+ {
+ return;
+ }
+
+ if (w * w > 0.0f)
+ {
+ SetAwake(true);
+ }
+
+ m_angularVelocity = w;
+}
+
+inline float32 b2Body::GetAngularVelocity() const
+{
+ return m_angularVelocity;
+}
+
+inline float32 b2Body::GetMass() const
+{
+ return m_mass;
+}
+
+inline float32 b2Body::GetInertia() const
+{
+ return m_I + m_mass * b2Dot(m_sweep.localCenter, m_sweep.localCenter);
+}
+
+inline void b2Body::GetMassData(b2MassData* data) const
+{
+ data->mass = m_mass;
+ data->I = m_I + m_mass * b2Dot(m_sweep.localCenter, m_sweep.localCenter);
+ data->center = m_sweep.localCenter;
+}
+
+inline b2Vec2 b2Body::GetWorldPoint(const b2Vec2& localPoint) const
+{
+ return b2Mul(m_xf, localPoint);
+}
+
+inline b2Vec2 b2Body::GetWorldVector(const b2Vec2& localVector) const
+{
+ return b2Mul(m_xf.q, localVector);
+}
+
+inline b2Vec2 b2Body::GetLocalPoint(const b2Vec2& worldPoint) const
+{
+ return b2MulT(m_xf, worldPoint);
+}
+
+inline b2Vec2 b2Body::GetLocalVector(const b2Vec2& worldVector) const
+{
+ return b2MulT(m_xf.q, worldVector);
+}
+
+inline b2Vec2 b2Body::GetLinearVelocityFromWorldPoint(const b2Vec2& worldPoint) const
+{
+ return m_linearVelocity + b2Cross(m_angularVelocity, worldPoint - m_sweep.c);
+}
+
+inline b2Vec2 b2Body::GetLinearVelocityFromLocalPoint(const b2Vec2& localPoint) const
+{
+ return GetLinearVelocityFromWorldPoint(GetWorldPoint(localPoint));
+}
+
+inline float32 b2Body::GetLinearDamping() const
+{
+ return m_linearDamping;
+}
+
+inline void b2Body::SetLinearDamping(float32 linearDamping)
+{
+ m_linearDamping = linearDamping;
+}
+
+inline float32 b2Body::GetAngularDamping() const
+{
+ return m_angularDamping;
+}
+
+inline void b2Body::SetAngularDamping(float32 angularDamping)
+{
+ m_angularDamping = angularDamping;
+}
+
+inline float32 b2Body::GetGravityScale() const
+{
+ return m_gravityScale;
+}
+
+inline void b2Body::SetGravityScale(float32 scale)
+{
+ m_gravityScale = scale;
+}
+
+inline void b2Body::SetBullet(bool flag)
+{
+ if (flag)
+ {
+ m_flags |= e_bulletFlag;
+ }
+ else
+ {
+ m_flags &= ~e_bulletFlag;
+ }
+}
+
+inline bool b2Body::IsBullet() const
+{
+ return (m_flags & e_bulletFlag) == e_bulletFlag;
+}
+
+inline void b2Body::SetAwake(bool flag)
+{
+ if (flag)
+ {
+ if ((m_flags & e_awakeFlag) == 0)
+ {
+ m_flags |= e_awakeFlag;
+ m_sleepTime = 0.0f;
+ }
+ }
+ else
+ {
+ m_flags &= ~e_awakeFlag;
+ m_sleepTime = 0.0f;
+ m_linearVelocity.SetZero();
+ m_angularVelocity = 0.0f;
+ m_force.SetZero();
+ m_torque = 0.0f;
+ }
+}
+
+inline bool b2Body::IsAwake() const
+{
+ return (m_flags & e_awakeFlag) == e_awakeFlag;
+}
+
+inline bool b2Body::IsActive() const
+{
+ return (m_flags & e_activeFlag) == e_activeFlag;
+}
+
+inline void b2Body::SetFixedRotation(bool flag)
+{
+ if (flag)
+ {
+ m_flags |= e_fixedRotationFlag;
+ }
+ else
+ {
+ m_flags &= ~e_fixedRotationFlag;
+ }
+
+ ResetMassData();
+}
+
+inline bool b2Body::IsFixedRotation() const
+{
+ return (m_flags & e_fixedRotationFlag) == e_fixedRotationFlag;
+}
+
+inline void b2Body::SetSleepingAllowed(bool flag)
+{
+ if (flag)
+ {
+ m_flags |= e_autoSleepFlag;
+ }
+ else
+ {
+ m_flags &= ~e_autoSleepFlag;
+ SetAwake(true);
+ }
+}
+
+inline bool b2Body::IsSleepingAllowed() const
+{
+ return (m_flags & e_autoSleepFlag) == e_autoSleepFlag;
+}
+
+inline b2Fixture* b2Body::GetFixtureList()
+{
+ return m_fixtureList;
+}
+
+inline const b2Fixture* b2Body::GetFixtureList() const
+{
+ return m_fixtureList;
+}
+
+inline b2JointEdge* b2Body::GetJointList()
+{
+ return m_jointList;
+}
+
+inline const b2JointEdge* b2Body::GetJointList() const
+{
+ return m_jointList;
+}
+
+inline b2ContactEdge* b2Body::GetContactList()
+{
+ return m_contactList;
+}
+
+inline const b2ContactEdge* b2Body::GetContactList() const
+{
+ return m_contactList;
+}
+
+inline b2Body* b2Body::GetNext()
+{
+ return m_next;
+}
+
+inline const b2Body* b2Body::GetNext() const
+{
+ return m_next;
+}
+
+inline void b2Body::SetUserData(void* data)
+{
+ m_userData = data;
+}
+
+inline void* b2Body::GetUserData() const
+{
+ return m_userData;
+}
+
+inline void b2Body::ApplyForce(const b2Vec2& force, const b2Vec2& point)
+{
+ if (m_type != b2_dynamicBody)
+ {
+ return;
+ }
+
+ if (IsAwake() == false)
+ {
+ SetAwake(true);
+ }
+
+ m_force += force;
+ m_torque += b2Cross(point - m_sweep.c, force);
+}
+
+inline void b2Body::ApplyForceToCenter(const b2Vec2& force)
+{
+ if (m_type != b2_dynamicBody)
+ {
+ return;
+ }
+
+ if (IsAwake() == false)
+ {
+ SetAwake(true);
+ }
+
+ m_force += force;
+}
+
+inline void b2Body::ApplyTorque(float32 torque)
+{
+ if (m_type != b2_dynamicBody)
+ {
+ return;
+ }
+
+ if (IsAwake() == false)
+ {
+ SetAwake(true);
+ }
+
+ m_torque += torque;
+}
+
+inline void b2Body::ApplyLinearImpulse(const b2Vec2& impulse, const b2Vec2& point)
+{
+ if (m_type != b2_dynamicBody)
+ {
+ return;
+ }
+
+ if (IsAwake() == false)
+ {
+ SetAwake(true);
+ }
+ m_linearVelocity += m_invMass * impulse;
+ m_angularVelocity += m_invI * b2Cross(point - m_sweep.c, impulse);
+}
+
+inline void b2Body::ApplyAngularImpulse(float32 impulse)
+{
+ if (m_type != b2_dynamicBody)
+ {
+ return;
+ }
+
+ if (IsAwake() == false)
+ {
+ SetAwake(true);
+ }
+ m_angularVelocity += m_invI * impulse;
+}
+
+inline void b2Body::SynchronizeTransform()
+{
+ m_xf.q.Set(m_sweep.a);
+ m_xf.p = m_sweep.c - b2Mul(m_xf.q, m_sweep.localCenter);
+}
+
+inline void b2Body::Advance(float32 alpha)
+{
+ // Advance to the new safe time. This doesn't sync the broad-phase.
+ m_sweep.Advance(alpha);
+ m_sweep.c = m_sweep.c0;
+ m_sweep.a = m_sweep.a0;
+ m_xf.q.Set(m_sweep.a);
+ m_xf.p = m_sweep.c - b2Mul(m_xf.q, m_sweep.localCenter);
+}
+
+inline b2World* b2Body::GetWorld()
+{
+ return m_world;
+}
+
+inline const b2World* b2Body::GetWorld() const
+{
+ return m_world;
+}
+
+#endif
diff --git a/tests/box2d/Box2D/Dynamics/b2ContactManager.cpp b/tests/box2d/Box2D/Dynamics/b2ContactManager.cpp new file mode 100755 index 00000000..5ac12b35 --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/b2ContactManager.cpp @@ -0,0 +1,293 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Dynamics/b2ContactManager.h>
+#include <Box2D/Dynamics/b2Body.h>
+#include <Box2D/Dynamics/b2Fixture.h>
+#include <Box2D/Dynamics/b2WorldCallbacks.h>
+#include <Box2D/Dynamics/Contacts/b2Contact.h>
+
+b2ContactFilter b2_defaultFilter;
+b2ContactListener b2_defaultListener;
+
+b2ContactManager::b2ContactManager()
+{
+ m_contactList = NULL;
+ m_contactCount = 0;
+ m_contactFilter = &b2_defaultFilter;
+ m_contactListener = &b2_defaultListener;
+ m_allocator = NULL;
+}
+
+void b2ContactManager::Destroy(b2Contact* c)
+{
+ b2Fixture* fixtureA = c->GetFixtureA();
+ b2Fixture* fixtureB = c->GetFixtureB();
+ b2Body* bodyA = fixtureA->GetBody();
+ b2Body* bodyB = fixtureB->GetBody();
+
+ if (m_contactListener && c->IsTouching())
+ {
+ m_contactListener->EndContact(c);
+ }
+
+ // Remove from the world.
+ 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 == m_contactList)
+ {
+ m_contactList = c->m_next;
+ }
+
+ // Remove from body 1
+ if (c->m_nodeA.prev)
+ {
+ c->m_nodeA.prev->next = c->m_nodeA.next;
+ }
+
+ if (c->m_nodeA.next)
+ {
+ c->m_nodeA.next->prev = c->m_nodeA.prev;
+ }
+
+ if (&c->m_nodeA == bodyA->m_contactList)
+ {
+ bodyA->m_contactList = c->m_nodeA.next;
+ }
+
+ // Remove from body 2
+ if (c->m_nodeB.prev)
+ {
+ c->m_nodeB.prev->next = c->m_nodeB.next;
+ }
+
+ if (c->m_nodeB.next)
+ {
+ c->m_nodeB.next->prev = c->m_nodeB.prev;
+ }
+
+ if (&c->m_nodeB == bodyB->m_contactList)
+ {
+ bodyB->m_contactList = c->m_nodeB.next;
+ }
+
+ // Call the factory.
+ b2Contact::Destroy(c, m_allocator);
+ --m_contactCount;
+}
+
+// This is the top level collision call for the time step. Here
+// all the narrow phase collision is processed for the world
+// contact list.
+void b2ContactManager::Collide()
+{
+ // Update awake contacts.
+ b2Contact* c = m_contactList;
+ while (c)
+ {
+ b2Fixture* fixtureA = c->GetFixtureA();
+ b2Fixture* fixtureB = c->GetFixtureB();
+ int32 indexA = c->GetChildIndexA();
+ int32 indexB = c->GetChildIndexB();
+ b2Body* bodyA = fixtureA->GetBody();
+ b2Body* bodyB = fixtureB->GetBody();
+
+ // Is this contact flagged for filtering?
+ if (c->m_flags & b2Contact::e_filterFlag)
+ {
+ // Should these bodies collide?
+ if (bodyB->ShouldCollide(bodyA) == false)
+ {
+ b2Contact* cNuke = c;
+ c = cNuke->GetNext();
+ Destroy(cNuke);
+ continue;
+ }
+
+ // Check user filtering.
+ if (m_contactFilter && m_contactFilter->ShouldCollide(fixtureA, fixtureB) == false)
+ {
+ b2Contact* cNuke = c;
+ c = cNuke->GetNext();
+ Destroy(cNuke);
+ continue;
+ }
+
+ // Clear the filtering flag.
+ c->m_flags &= ~b2Contact::e_filterFlag;
+ }
+
+ bool activeA = bodyA->IsAwake() && bodyA->m_type != b2_staticBody;
+ bool activeB = bodyB->IsAwake() && bodyB->m_type != b2_staticBody;
+
+ // At least one body must be awake and it must be dynamic or kinematic.
+ if (activeA == false && activeB == false)
+ {
+ c = c->GetNext();
+ continue;
+ }
+
+ int32 proxyIdA = fixtureA->m_proxies[indexA].proxyId;
+ int32 proxyIdB = fixtureB->m_proxies[indexB].proxyId;
+ bool overlap = m_broadPhase.TestOverlap(proxyIdA, proxyIdB);
+
+ // Here we destroy contacts that cease to overlap in the broad-phase.
+ if (overlap == false)
+ {
+ b2Contact* cNuke = c;
+ c = cNuke->GetNext();
+ Destroy(cNuke);
+ continue;
+ }
+
+ // The contact persists.
+ c->Update(m_contactListener);
+ c = c->GetNext();
+ }
+}
+
+void b2ContactManager::FindNewContacts()
+{
+ m_broadPhase.UpdatePairs(this);
+}
+
+void b2ContactManager::AddPair(void* proxyUserDataA, void* proxyUserDataB)
+{
+ b2FixtureProxy* proxyA = (b2FixtureProxy*)proxyUserDataA;
+ b2FixtureProxy* proxyB = (b2FixtureProxy*)proxyUserDataB;
+
+ b2Fixture* fixtureA = proxyA->fixture;
+ b2Fixture* fixtureB = proxyB->fixture;
+
+ int32 indexA = proxyA->childIndex;
+ int32 indexB = proxyB->childIndex;
+
+ b2Body* bodyA = fixtureA->GetBody();
+ b2Body* bodyB = fixtureB->GetBody();
+
+ // Are the fixtures on the same body?
+ if (bodyA == bodyB)
+ {
+ return;
+ }
+
+ // TODO_ERIN use a hash table to remove a potential bottleneck when both
+ // bodies have a lot of contacts.
+ // Does a contact already exist?
+ b2ContactEdge* edge = bodyB->GetContactList();
+ while (edge)
+ {
+ if (edge->other == bodyA)
+ {
+ b2Fixture* fA = edge->contact->GetFixtureA();
+ b2Fixture* fB = edge->contact->GetFixtureB();
+ int32 iA = edge->contact->GetChildIndexA();
+ int32 iB = edge->contact->GetChildIndexB();
+
+ if (fA == fixtureA && fB == fixtureB && iA == indexA && iB == indexB)
+ {
+ // A contact already exists.
+ return;
+ }
+
+ if (fA == fixtureB && fB == fixtureA && iA == indexB && iB == indexA)
+ {
+ // A contact already exists.
+ return;
+ }
+ }
+
+ edge = edge->next;
+ }
+
+ // Does a joint override collision? Is at least one body dynamic?
+ if (bodyB->ShouldCollide(bodyA) == false)
+ {
+ return;
+ }
+
+ // Check user filtering.
+ if (m_contactFilter && m_contactFilter->ShouldCollide(fixtureA, fixtureB) == false)
+ {
+ return;
+ }
+
+ // Call the factory.
+ b2Contact* c = b2Contact::Create(fixtureA, indexA, fixtureB, indexB, m_allocator);
+ if (c == NULL)
+ {
+ return;
+ }
+
+ // Contact creation may swap fixtures.
+ fixtureA = c->GetFixtureA();
+ fixtureB = c->GetFixtureB();
+ indexA = c->GetChildIndexA();
+ indexB = c->GetChildIndexB();
+ bodyA = fixtureA->GetBody();
+ bodyB = fixtureB->GetBody();
+
+ // Insert into the world.
+ c->m_prev = NULL;
+ c->m_next = m_contactList;
+ if (m_contactList != NULL)
+ {
+ m_contactList->m_prev = c;
+ }
+ m_contactList = c;
+
+ // Connect to island graph.
+
+ // Connect to body A
+ c->m_nodeA.contact = c;
+ c->m_nodeA.other = bodyB;
+
+ c->m_nodeA.prev = NULL;
+ c->m_nodeA.next = bodyA->m_contactList;
+ if (bodyA->m_contactList != NULL)
+ {
+ bodyA->m_contactList->prev = &c->m_nodeA;
+ }
+ bodyA->m_contactList = &c->m_nodeA;
+
+ // Connect to body B
+ c->m_nodeB.contact = c;
+ c->m_nodeB.other = bodyA;
+
+ c->m_nodeB.prev = NULL;
+ c->m_nodeB.next = bodyB->m_contactList;
+ if (bodyB->m_contactList != NULL)
+ {
+ bodyB->m_contactList->prev = &c->m_nodeB;
+ }
+ bodyB->m_contactList = &c->m_nodeB;
+
+ // Wake up the bodies
+ bodyA->SetAwake(true);
+ bodyB->SetAwake(true);
+
+ ++m_contactCount;
+}
diff --git a/tests/box2d/Box2D/Dynamics/b2ContactManager.h b/tests/box2d/Box2D/Dynamics/b2ContactManager.h new file mode 100755 index 00000000..dc1f77fe --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/b2ContactManager.h @@ -0,0 +1,52 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_CONTACT_MANAGER_H
+#define B2_CONTACT_MANAGER_H
+
+#include <Box2D/Collision/b2BroadPhase.h>
+
+class b2Contact;
+class b2ContactFilter;
+class b2ContactListener;
+class b2BlockAllocator;
+
+// Delegate of b2World.
+class b2ContactManager
+{
+public:
+ b2ContactManager();
+
+ // Broad-phase callback.
+ void AddPair(void* proxyUserDataA, void* proxyUserDataB);
+
+ void FindNewContacts();
+
+ void Destroy(b2Contact* c);
+
+ void Collide();
+
+ b2BroadPhase m_broadPhase;
+ b2Contact* m_contactList;
+ int32 m_contactCount;
+ b2ContactFilter* m_contactFilter;
+ b2ContactListener* m_contactListener;
+ b2BlockAllocator* m_allocator;
+};
+
+#endif
diff --git a/tests/box2d/Box2D/Dynamics/b2Fixture.cpp b/tests/box2d/Box2D/Dynamics/b2Fixture.cpp new file mode 100755 index 00000000..77537b27 --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/b2Fixture.cpp @@ -0,0 +1,303 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Dynamics/b2Fixture.h>
+#include <Box2D/Dynamics/Contacts/b2Contact.h>
+#include <Box2D/Dynamics/b2World.h>
+#include <Box2D/Collision/Shapes/b2CircleShape.h>
+#include <Box2D/Collision/Shapes/b2EdgeShape.h>
+#include <Box2D/Collision/Shapes/b2PolygonShape.h>
+#include <Box2D/Collision/Shapes/b2ChainShape.h>
+#include <Box2D/Collision/b2BroadPhase.h>
+#include <Box2D/Collision/b2Collision.h>
+#include <Box2D/Common/b2BlockAllocator.h>
+
+b2Fixture::b2Fixture()
+{
+ m_userData = NULL;
+ m_body = NULL;
+ m_next = NULL;
+ m_proxies = NULL;
+ m_proxyCount = 0;
+ m_shape = NULL;
+ m_density = 0.0f;
+}
+
+void b2Fixture::Create(b2BlockAllocator* allocator, b2Body* body, const b2FixtureDef* def)
+{
+ m_userData = def->userData;
+ m_friction = def->friction;
+ m_restitution = def->restitution;
+
+ m_body = body;
+ m_next = NULL;
+
+ m_filter = def->filter;
+
+ m_isSensor = def->isSensor;
+
+ m_shape = def->shape->Clone(allocator);
+
+ // Reserve proxy space
+ int32 childCount = m_shape->GetChildCount();
+ m_proxies = (b2FixtureProxy*)allocator->Allocate(childCount * sizeof(b2FixtureProxy));
+ for (int32 i = 0; i < childCount; ++i)
+ {
+ m_proxies[i].fixture = NULL;
+ m_proxies[i].proxyId = b2BroadPhase::e_nullProxy;
+ }
+ m_proxyCount = 0;
+
+ m_density = def->density;
+}
+
+void b2Fixture::Destroy(b2BlockAllocator* allocator)
+{
+ // The proxies must be destroyed before calling this.
+ b2Assert(m_proxyCount == 0);
+
+ // Free the proxy array.
+ int32 childCount = m_shape->GetChildCount();
+ allocator->Free(m_proxies, childCount * sizeof(b2FixtureProxy));
+ m_proxies = NULL;
+
+ // Free the child shape.
+ switch (m_shape->m_type)
+ {
+ case b2Shape::e_circle:
+ {
+ b2CircleShape* s = (b2CircleShape*)m_shape;
+ s->~b2CircleShape();
+ allocator->Free(s, sizeof(b2CircleShape));
+ }
+ break;
+
+ case b2Shape::e_edge:
+ {
+ b2EdgeShape* s = (b2EdgeShape*)m_shape;
+ s->~b2EdgeShape();
+ allocator->Free(s, sizeof(b2EdgeShape));
+ }
+ break;
+
+ case b2Shape::e_polygon:
+ {
+ b2PolygonShape* s = (b2PolygonShape*)m_shape;
+ s->~b2PolygonShape();
+ allocator->Free(s, sizeof(b2PolygonShape));
+ }
+ break;
+
+ case b2Shape::e_chain:
+ {
+ b2ChainShape* s = (b2ChainShape*)m_shape;
+ s->~b2ChainShape();
+ allocator->Free(s, sizeof(b2ChainShape));
+ }
+ break;
+
+ default:
+ b2Assert(false);
+ break;
+ }
+
+ m_shape = NULL;
+}
+
+void b2Fixture::CreateProxies(b2BroadPhase* broadPhase, const b2Transform& xf)
+{
+ b2Assert(m_proxyCount == 0);
+
+ // Create proxies in the broad-phase.
+ m_proxyCount = m_shape->GetChildCount();
+
+ for (int32 i = 0; i < m_proxyCount; ++i)
+ {
+ b2FixtureProxy* proxy = m_proxies + i;
+ m_shape->ComputeAABB(&proxy->aabb, xf, i);
+ proxy->proxyId = broadPhase->CreateProxy(proxy->aabb, proxy);
+ proxy->fixture = this;
+ proxy->childIndex = i;
+ }
+}
+
+void b2Fixture::DestroyProxies(b2BroadPhase* broadPhase)
+{
+ // Destroy proxies in the broad-phase.
+ for (int32 i = 0; i < m_proxyCount; ++i)
+ {
+ b2FixtureProxy* proxy = m_proxies + i;
+ broadPhase->DestroyProxy(proxy->proxyId);
+ proxy->proxyId = b2BroadPhase::e_nullProxy;
+ }
+
+ m_proxyCount = 0;
+}
+
+void b2Fixture::Synchronize(b2BroadPhase* broadPhase, const b2Transform& transform1, const b2Transform& transform2)
+{
+ if (m_proxyCount == 0)
+ {
+ return;
+ }
+
+ for (int32 i = 0; i < m_proxyCount; ++i)
+ {
+ b2FixtureProxy* proxy = m_proxies + i;
+
+ // Compute an AABB that covers the swept shape (may miss some rotation effect).
+ b2AABB aabb1, aabb2;
+ m_shape->ComputeAABB(&aabb1, transform1, proxy->childIndex);
+ m_shape->ComputeAABB(&aabb2, transform2, proxy->childIndex);
+
+ proxy->aabb.Combine(aabb1, aabb2);
+
+ b2Vec2 displacement = transform2.p - transform1.p;
+
+ broadPhase->MoveProxy(proxy->proxyId, proxy->aabb, displacement);
+ }
+}
+
+void b2Fixture::SetFilterData(const b2Filter& filter)
+{
+ m_filter = filter;
+
+ Refilter();
+}
+
+void b2Fixture::Refilter()
+{
+ if (m_body == NULL)
+ {
+ return;
+ }
+
+ // Flag associated contacts for filtering.
+ b2ContactEdge* edge = m_body->GetContactList();
+ while (edge)
+ {
+ b2Contact* contact = edge->contact;
+ b2Fixture* fixtureA = contact->GetFixtureA();
+ b2Fixture* fixtureB = contact->GetFixtureB();
+ if (fixtureA == this || fixtureB == this)
+ {
+ contact->FlagForFiltering();
+ }
+
+ edge = edge->next;
+ }
+
+ b2World* world = m_body->GetWorld();
+
+ if (world == NULL)
+ {
+ return;
+ }
+
+ // Touch each proxy so that new pairs may be created
+ b2BroadPhase* broadPhase = &world->m_contactManager.m_broadPhase;
+ for (int32 i = 0; i < m_proxyCount; ++i)
+ {
+ broadPhase->TouchProxy(m_proxies[i].proxyId);
+ }
+}
+
+void b2Fixture::SetSensor(bool sensor)
+{
+ if (sensor != m_isSensor)
+ {
+ m_body->SetAwake(true);
+ m_isSensor = sensor;
+ }
+}
+
+void b2Fixture::Dump(int32 bodyIndex)
+{
+ b2Log(" b2FixtureDef fd;\n");
+ b2Log(" fd.friction = %.15lef;\n", m_friction);
+ b2Log(" fd.restitution = %.15lef;\n", m_restitution);
+ b2Log(" fd.density = %.15lef;\n", m_density);
+ b2Log(" fd.isSensor = bool(%d);\n", m_isSensor);
+ b2Log(" fd.filter.categoryBits = uint16(%d);\n", m_filter.categoryBits);
+ b2Log(" fd.filter.maskBits = uint16(%d);\n", m_filter.maskBits);
+ b2Log(" fd.filter.groupIndex = int16(%d);\n", m_filter.groupIndex);
+
+ switch (m_shape->m_type)
+ {
+ case b2Shape::e_circle:
+ {
+ b2CircleShape* s = (b2CircleShape*)m_shape;
+ b2Log(" b2CircleShape shape;\n");
+ b2Log(" shape.m_radius = %.15lef;\n", s->m_radius);
+ b2Log(" shape.m_p.Set(%.15lef, %.15lef);\n", s->m_p.x, s->m_p.y);
+ }
+ break;
+
+ case b2Shape::e_edge:
+ {
+ b2EdgeShape* s = (b2EdgeShape*)m_shape;
+ b2Log(" b2EdgeShape shape;\n");
+ b2Log(" shape.m_radius = %.15lef;\n", s->m_radius);
+ b2Log(" shape.m_vertex0.Set(%.15lef, %.15lef);\n", s->m_vertex0.x, s->m_vertex0.y);
+ b2Log(" shape.m_vertex1.Set(%.15lef, %.15lef);\n", s->m_vertex1.x, s->m_vertex1.y);
+ b2Log(" shape.m_vertex2.Set(%.15lef, %.15lef);\n", s->m_vertex2.x, s->m_vertex2.y);
+ b2Log(" shape.m_vertex3.Set(%.15lef, %.15lef);\n", s->m_vertex3.x, s->m_vertex3.y);
+ b2Log(" shape.m_hasVertex0 = bool(%d);\n", s->m_hasVertex0);
+ b2Log(" shape.m_hasVertex3 = bool(%d);\n", s->m_hasVertex3);
+ }
+ break;
+
+ case b2Shape::e_polygon:
+ {
+ b2PolygonShape* s = (b2PolygonShape*)m_shape;
+ b2Log(" b2PolygonShape shape;\n");
+ b2Log(" b2Vec2 vs[%d];\n", b2_maxPolygonVertices);
+ for (int32 i = 0; i < s->m_vertexCount; ++i)
+ {
+ b2Log(" vs[%d].Set(%.15lef, %.15lef);\n", i, s->m_vertices[i].x, s->m_vertices[i].y);
+ }
+ b2Log(" shape.Set(vs, %d);\n", s->m_vertexCount);
+ }
+ break;
+
+ case b2Shape::e_chain:
+ {
+ b2ChainShape* s = (b2ChainShape*)m_shape;
+ b2Log(" b2ChainShape shape;\n");
+ b2Log(" b2Vec2 vs[%d];\n", s->m_count);
+ for (int32 i = 0; i < s->m_count; ++i)
+ {
+ b2Log(" vs[%d].Set(%.15lef, %.15lef);\n", i, s->m_vertices[i].x, s->m_vertices[i].y);
+ }
+ b2Log(" shape.CreateChain(vs, %d);\n", s->m_count);
+ b2Log(" shape.m_prevVertex.Set(%.15lef, %.15lef);\n", s->m_prevVertex.x, s->m_prevVertex.y);
+ b2Log(" shape.m_nextVertex.Set(%.15lef, %.15lef);\n", s->m_nextVertex.x, s->m_nextVertex.y);
+ b2Log(" shape.m_hasPrevVertex = bool(%d);\n", s->m_hasPrevVertex);
+ b2Log(" shape.m_hasNextVertex = bool(%d);\n", s->m_hasNextVertex);
+ }
+ break;
+
+ default:
+ return;
+ }
+
+ b2Log("\n");
+ b2Log(" fd.shape = &shape;\n");
+ b2Log("\n");
+ b2Log(" bodies[%d]->CreateFixture(&fd);\n", bodyIndex);
+}
diff --git a/tests/box2d/Box2D/Dynamics/b2Fixture.h b/tests/box2d/Box2D/Dynamics/b2Fixture.h new file mode 100755 index 00000000..d92751fd --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/b2Fixture.h @@ -0,0 +1,348 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_FIXTURE_H
+#define B2_FIXTURE_H
+
+#include <Box2D/Dynamics/b2Body.h>
+#include <Box2D/Collision/b2Collision.h>
+#include <Box2D/Collision/Shapes/b2Shape.h>
+
+class b2BlockAllocator;
+class b2Body;
+class b2BroadPhase;
+class b2Fixture;
+
+/// This holds contact filtering data.
+struct b2Filter
+{
+ b2Filter()
+ {
+ categoryBits = 0x0001;
+ maskBits = 0xFFFF;
+ groupIndex = 0;
+ }
+
+ /// The collision category bits. Normally you would just set one bit.
+ uint16 categoryBits;
+
+ /// The collision mask bits. This states the categories that this
+ /// shape would accept for collision.
+ uint16 maskBits;
+
+ /// Collision groups allow a certain group of objects to never collide (negative)
+ /// or always collide (positive). Zero means no collision group. Non-zero group
+ /// filtering always wins against the mask bits.
+ int16 groupIndex;
+};
+
+/// A fixture definition is used to create a fixture. This class defines an
+/// abstract fixture definition. You can reuse fixture definitions safely.
+struct b2FixtureDef
+{
+ /// The constructor sets the default fixture definition values.
+ b2FixtureDef()
+ {
+ shape = NULL;
+ userData = NULL;
+ friction = 0.2f;
+ restitution = 0.0f;
+ density = 0.0f;
+ isSensor = false;
+ }
+
+ /// The shape, this must be set. The shape will be cloned, so you
+ /// can create the shape on the stack.
+ const b2Shape* shape;
+
+ /// Use this to store application specific fixture data.
+ void* userData;
+
+ /// The friction coefficient, usually in the range [0,1].
+ float32 friction;
+
+ /// The restitution (elasticity) usually in the range [0,1].
+ float32 restitution;
+
+ /// The density, usually in kg/m^2.
+ float32 density;
+
+ /// A sensor shape collects contact information but never generates a collision
+ /// response.
+ bool isSensor;
+
+ /// Contact filtering data.
+ b2Filter filter;
+};
+
+/// This proxy is used internally to connect fixtures to the broad-phase.
+struct b2FixtureProxy
+{
+ b2AABB aabb;
+ b2Fixture* fixture;
+ int32 childIndex;
+ int32 proxyId;
+};
+
+/// A fixture is used to attach a shape to a body for collision detection. A fixture
+/// inherits its transform from its parent. Fixtures hold additional non-geometric data
+/// such as friction, collision filters, etc.
+/// Fixtures are created via b2Body::CreateFixture.
+/// @warning you cannot reuse fixtures.
+// emscripten - b2Fixture: make constructor public
+class b2Fixture
+{
+public:
+ /// Get the type of the child shape. You can use this to down cast to the concrete shape.
+ /// @return the shape type.
+ b2Shape::Type GetType() const;
+
+ /// Get the child shape. You can modify the child shape, however you should not change the
+ /// number of vertices because this will crash some collision caching mechanisms.
+ /// Manipulating the shape may lead to non-physical behavior.
+ b2Shape* GetShape();
+ const b2Shape* GetShape() const;
+
+ /// Set if this fixture is a sensor.
+ void SetSensor(bool sensor);
+
+ /// Is this fixture a sensor (non-solid)?
+ /// @return the true if the shape is a sensor.
+ bool IsSensor() const;
+
+ /// Set the contact filtering data. This will not update contacts until the next time
+ /// step when either parent body is active and awake.
+ /// This automatically calls Refilter.
+ void SetFilterData(const b2Filter& filter);
+
+ /// Get the contact filtering data.
+ const b2Filter& GetFilterData() const;
+
+ /// Call this if you want to establish collision that was previously disabled by b2ContactFilter::ShouldCollide.
+ void Refilter();
+
+ /// Get the parent body of this fixture. This is NULL if the fixture is not attached.
+ /// @return the parent body.
+ b2Body* GetBody();
+ const b2Body* GetBody() const;
+
+ /// Get the next fixture in the parent body's fixture list.
+ /// @return the next shape.
+ b2Fixture* GetNext();
+ const b2Fixture* GetNext() const;
+
+ /// Get the user data that was assigned in the fixture definition. Use this to
+ /// store your application specific data.
+ void* GetUserData() const;
+
+ /// Set the user data. Use this to store your application specific data.
+ void SetUserData(void* data);
+
+ /// Test a point for containment in this fixture.
+ /// @param p a point in world coordinates.
+ bool TestPoint(const b2Vec2& p) const;
+
+ /// Cast a ray against this shape.
+ /// @param output the ray-cast results.
+ /// @param input the ray-cast input parameters.
+ bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, int32 childIndex) const;
+
+ /// Get the mass data for this fixture. The mass data is based on the density and
+ /// the shape. The rotational inertia is about the shape's origin. This operation
+ /// may be expensive.
+ void GetMassData(b2MassData* massData) const;
+
+ /// Set the density of this fixture. This will _not_ automatically adjust the mass
+ /// of the body. You must call b2Body::ResetMassData to update the body's mass.
+ void SetDensity(float32 density);
+
+ /// Get the density of this fixture.
+ float32 GetDensity() const;
+
+ /// Get the coefficient of friction.
+ float32 GetFriction() const;
+
+ /// Set the coefficient of friction. This will _not_ change the friction of
+ /// existing contacts.
+ void SetFriction(float32 friction);
+
+ /// Get the coefficient of restitution.
+ float32 GetRestitution() const;
+
+ /// Set the coefficient of restitution. This will _not_ change the restitution of
+ /// existing contacts.
+ void SetRestitution(float32 restitution);
+
+ /// Get the fixture's AABB. This AABB may be enlarge and/or stale.
+ /// If you need a more accurate AABB, compute it using the shape and
+ /// the body transform.
+ const b2AABB& GetAABB(int32 childIndex) const;
+
+ /// Dump this fixture to the log file.
+ void Dump(int32 bodyIndex);
+
+protected:
+
+ friend class b2Body;
+ friend class b2World;
+ friend class b2Contact;
+ friend class b2ContactManager;
+
+public:
+ b2Fixture();
+
+protected:
+ // We need separation create/destroy functions from the constructor/destructor because
+ // the destructor cannot access the allocator (no destructor arguments allowed by C++).
+ void Create(b2BlockAllocator* allocator, b2Body* body, const b2FixtureDef* def);
+ void Destroy(b2BlockAllocator* allocator);
+
+ // These support body activation/deactivation.
+ void CreateProxies(b2BroadPhase* broadPhase, const b2Transform& xf);
+ void DestroyProxies(b2BroadPhase* broadPhase);
+
+ void Synchronize(b2BroadPhase* broadPhase, const b2Transform& xf1, const b2Transform& xf2);
+
+ float32 m_density;
+
+ b2Fixture* m_next;
+ b2Body* m_body;
+
+ b2Shape* m_shape;
+
+ float32 m_friction;
+ float32 m_restitution;
+
+ b2FixtureProxy* m_proxies;
+ int32 m_proxyCount;
+
+ b2Filter m_filter;
+
+ bool m_isSensor;
+
+ void* m_userData;
+};
+
+inline b2Shape::Type b2Fixture::GetType() const
+{
+ return m_shape->GetType();
+}
+
+inline b2Shape* b2Fixture::GetShape()
+{
+ return m_shape;
+}
+
+inline const b2Shape* b2Fixture::GetShape() const
+{
+ return m_shape;
+}
+
+inline bool b2Fixture::IsSensor() const
+{
+ return m_isSensor;
+}
+
+inline const b2Filter& b2Fixture::GetFilterData() const
+{
+ return m_filter;
+}
+
+inline void* b2Fixture::GetUserData() const
+{
+ return m_userData;
+}
+
+inline void b2Fixture::SetUserData(void* data)
+{
+ m_userData = data;
+}
+
+inline b2Body* b2Fixture::GetBody()
+{
+ return m_body;
+}
+
+inline const b2Body* b2Fixture::GetBody() const
+{
+ return m_body;
+}
+
+inline b2Fixture* b2Fixture::GetNext()
+{
+ return m_next;
+}
+
+inline const b2Fixture* b2Fixture::GetNext() const
+{
+ return m_next;
+}
+
+inline void b2Fixture::SetDensity(float32 density)
+{
+ b2Assert(b2IsValid(density) && density >= 0.0f);
+ m_density = density;
+}
+
+inline float32 b2Fixture::GetDensity() const
+{
+ return m_density;
+}
+
+inline float32 b2Fixture::GetFriction() const
+{
+ return m_friction;
+}
+
+inline void b2Fixture::SetFriction(float32 friction)
+{
+ m_friction = friction;
+}
+
+inline float32 b2Fixture::GetRestitution() const
+{
+ return m_restitution;
+}
+
+inline void b2Fixture::SetRestitution(float32 restitution)
+{
+ m_restitution = restitution;
+}
+
+inline bool b2Fixture::TestPoint(const b2Vec2& p) const
+{
+ return m_shape->TestPoint(m_body->GetTransform(), p);
+}
+
+inline bool b2Fixture::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, int32 childIndex) const
+{
+ return m_shape->RayCast(output, input, m_body->GetTransform(), childIndex);
+}
+
+inline void b2Fixture::GetMassData(b2MassData* massData) const
+{
+ m_shape->ComputeMass(massData, m_density);
+}
+
+inline const b2AABB& b2Fixture::GetAABB(int32 childIndex) const
+{
+ b2Assert(0 <= childIndex && childIndex < m_proxyCount);
+ return m_proxies[childIndex].aabb;
+}
+
+#endif
diff --git a/tests/box2d/Box2D/Dynamics/b2Island.cpp b/tests/box2d/Box2D/Dynamics/b2Island.cpp new file mode 100755 index 00000000..0e2129cf --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/b2Island.cpp @@ -0,0 +1,539 @@ +/*
+* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Collision/b2Distance.h>
+#include <Box2D/Dynamics/b2Island.h>
+#include <Box2D/Dynamics/b2Body.h>
+#include <Box2D/Dynamics/b2Fixture.h>
+#include <Box2D/Dynamics/b2World.h>
+#include <Box2D/Dynamics/Contacts/b2Contact.h>
+#include <Box2D/Dynamics/Contacts/b2ContactSolver.h>
+#include <Box2D/Dynamics/Joints/b2Joint.h>
+#include <Box2D/Common/b2StackAllocator.h>
+#include <Box2D/Common/b2Timer.h>
+
+/*
+Position Correction Notes
+=========================
+I tried the several algorithms for position correction of the 2D revolute joint.
+I looked at these systems:
+- simple pendulum (1m diameter sphere on massless 5m stick) with initial angular velocity of 100 rad/s.
+- suspension bridge with 30 1m long planks of length 1m.
+- multi-link chain with 30 1m long links.
+
+Here are the algorithms:
+
+Baumgarte - A fraction of the position error is added to the velocity error. There is no
+separate position solver.
+
+Pseudo Velocities - After the velocity solver and position integration,
+the position error, Jacobian, and effective mass are recomputed. Then
+the velocity constraints are solved with pseudo velocities and a fraction
+of the position error is added to the pseudo velocity error. The pseudo
+velocities are initialized to zero and there is no warm-starting. After
+the position solver, the pseudo velocities are added to the positions.
+This is also called the First Order World method or the Position LCP method.
+
+Modified Nonlinear Gauss-Seidel (NGS) - Like Pseudo Velocities except the
+position error is re-computed for each constraint and the positions are updated
+after the constraint is solved. The radius vectors (aka Jacobians) are
+re-computed too (otherwise the algorithm has horrible instability). The pseudo
+velocity states are not needed because they are effectively zero at the beginning
+of each iteration. Since we have the current position error, we allow the
+iterations to terminate early if the error becomes smaller than b2_linearSlop.
+
+Full NGS or just NGS - Like Modified NGS except the effective mass are re-computed
+each time a constraint is solved.
+
+Here are the results:
+Baumgarte - this is the cheapest algorithm but it has some stability problems,
+especially with the bridge. The chain links separate easily close to the root
+and they jitter as they struggle to pull together. This is one of the most common
+methods in the field. The big drawback is that the position correction artificially
+affects the momentum, thus leading to instabilities and false bounce. I used a
+bias factor of 0.2. A larger bias factor makes the bridge less stable, a smaller
+factor makes joints and contacts more spongy.
+
+Pseudo Velocities - the is more stable than the Baumgarte method. The bridge is
+stable. However, joints still separate with large angular velocities. Drag the
+simple pendulum in a circle quickly and the joint will separate. The chain separates
+easily and does not recover. I used a bias factor of 0.2. A larger value lead to
+the bridge collapsing when a heavy cube drops on it.
+
+Modified NGS - this algorithm is better in some ways than Baumgarte and Pseudo
+Velocities, but in other ways it is worse. The bridge and chain are much more
+stable, but the simple pendulum goes unstable at high angular velocities.
+
+Full NGS - stable in all tests. The joints display good stiffness. The bridge
+still sags, but this is better than infinite forces.
+
+Recommendations
+Pseudo Velocities are not really worthwhile because the bridge and chain cannot
+recover from joint separation. In other cases the benefit over Baumgarte is small.
+
+Modified NGS is not a robust method for the revolute joint due to the violent
+instability seen in the simple pendulum. Perhaps it is viable with other constraint
+types, especially scalar constraints where the effective mass is a scalar.
+
+This leaves Baumgarte and Full NGS. Baumgarte has small, but manageable instabilities
+and is very fast. I don't think we can escape Baumgarte, especially in highly
+demanding cases where high constraint fidelity is not needed.
+
+Full NGS is robust and easy on the eyes. I recommend this as an option for
+higher fidelity simulation and certainly for suspension bridges and long chains.
+Full NGS might be a good choice for ragdolls, especially motorized ragdolls where
+joint separation can be problematic. The number of NGS iterations can be reduced
+for better performance without harming robustness much.
+
+Each joint in a can be handled differently in the position solver. So I recommend
+a system where the user can select the algorithm on a per joint basis. I would
+probably default to the slower Full NGS and let the user select the faster
+Baumgarte method in performance critical scenarios.
+*/
+
+/*
+Cache Performance
+
+The Box2D solvers are dominated by cache misses. Data structures are designed
+to increase the number of cache hits. Much of misses are due to random access
+to body data. The constraint structures are iterated over linearly, which leads
+to few cache misses.
+
+The bodies are not accessed during iteration. Instead read only data, such as
+the mass values are stored with the constraints. The mutable data are the constraint
+impulses and the bodies velocities/positions. The impulses are held inside the
+constraint structures. The body velocities/positions are held in compact, temporary
+arrays to increase the number of cache hits. Linear and angular velocity are
+stored in a single array since multiple arrays lead to multiple misses.
+*/
+
+/*
+2D Rotation
+
+R = [cos(theta) -sin(theta)]
+ [sin(theta) cos(theta) ]
+
+thetaDot = omega
+
+Let q1 = cos(theta), q2 = sin(theta).
+R = [q1 -q2]
+ [q2 q1]
+
+q1Dot = -thetaDot * q2
+q2Dot = thetaDot * q1
+
+q1_new = q1_old - dt * w * q2
+q2_new = q2_old + dt * w * q1
+then normalize.
+
+This might be faster than computing sin+cos.
+However, we can compute sin+cos of the same angle fast.
+*/
+
+b2Island::b2Island(
+ int32 bodyCapacity,
+ int32 contactCapacity,
+ int32 jointCapacity,
+ b2StackAllocator* allocator,
+ b2ContactListener* listener)
+{
+ m_bodyCapacity = bodyCapacity;
+ m_contactCapacity = contactCapacity;
+ m_jointCapacity = jointCapacity;
+ m_bodyCount = 0;
+ m_contactCount = 0;
+ m_jointCount = 0;
+
+ m_allocator = allocator;
+ m_listener = listener;
+
+ m_bodies = (b2Body**)m_allocator->Allocate(bodyCapacity * sizeof(b2Body*));
+ m_contacts = (b2Contact**)m_allocator->Allocate(contactCapacity * sizeof(b2Contact*));
+ m_joints = (b2Joint**)m_allocator->Allocate(jointCapacity * sizeof(b2Joint*));
+
+ m_velocities = (b2Velocity*)m_allocator->Allocate(m_bodyCapacity * sizeof(b2Velocity));
+ m_positions = (b2Position*)m_allocator->Allocate(m_bodyCapacity * sizeof(b2Position));
+}
+
+b2Island::~b2Island()
+{
+ // Warning: the order should reverse the constructor order.
+ m_allocator->Free(m_positions);
+ m_allocator->Free(m_velocities);
+ m_allocator->Free(m_joints);
+ m_allocator->Free(m_contacts);
+ m_allocator->Free(m_bodies);
+}
+
+void b2Island::Solve(b2Profile* profile, const b2TimeStep& step, const b2Vec2& gravity, bool allowSleep)
+{
+ b2Timer timer;
+
+ float32 h = step.dt;
+
+ // Integrate velocities and apply damping. Initialize the body state.
+ for (int32 i = 0; i < m_bodyCount; ++i)
+ {
+ b2Body* b = m_bodies[i];
+
+ b2Vec2 c = b->m_sweep.c;
+ float32 a = b->m_sweep.a;
+ b2Vec2 v = b->m_linearVelocity;
+ float32 w = b->m_angularVelocity;
+
+ // Store positions for continuous collision.
+ b->m_sweep.c0 = b->m_sweep.c;
+ b->m_sweep.a0 = b->m_sweep.a;
+
+ if (b->m_type == b2_dynamicBody)
+ {
+ // Integrate velocities.
+ v += h * (b->m_gravityScale * gravity + b->m_invMass * b->m_force);
+ w += h * b->m_invI * b->m_torque;
+
+ // Apply damping.
+ // ODE: dv/dt + c * v = 0
+ // Solution: v(t) = v0 * exp(-c * t)
+ // Time step: v(t + dt) = v0 * exp(-c * (t + dt)) = v0 * exp(-c * t) * exp(-c * dt) = v * exp(-c * dt)
+ // v2 = exp(-c * dt) * v1
+ // Taylor expansion:
+ // v2 = (1.0f - c * dt) * v1
+ v *= b2Clamp(1.0f - h * b->m_linearDamping, 0.0f, 1.0f);
+ w *= b2Clamp(1.0f - h * b->m_angularDamping, 0.0f, 1.0f);
+ }
+
+ m_positions[i].c = c;
+ m_positions[i].a = a;
+ m_velocities[i].v = v;
+ m_velocities[i].w = w;
+ }
+
+ timer.Reset();
+
+ // Solver data
+ b2SolverData solverData;
+ solverData.step = step;
+ solverData.positions = m_positions;
+ solverData.velocities = m_velocities;
+
+ // Initialize velocity constraints.
+ b2ContactSolverDef contactSolverDef;
+ contactSolverDef.step = step;
+ contactSolverDef.contacts = m_contacts;
+ contactSolverDef.count = m_contactCount;
+ contactSolverDef.positions = m_positions;
+ contactSolverDef.velocities = m_velocities;
+ contactSolverDef.allocator = m_allocator;
+
+ b2ContactSolver contactSolver(&contactSolverDef);
+ contactSolver.InitializeVelocityConstraints();
+
+ if (step.warmStarting)
+ {
+ contactSolver.WarmStart();
+ }
+
+ for (int32 i = 0; i < m_jointCount; ++i)
+ {
+ m_joints[i]->InitVelocityConstraints(solverData);
+ }
+
+ profile->solveInit = timer.GetMilliseconds();
+
+ // Solve velocity constraints
+ timer.Reset();
+ for (int32 i = 0; i < step.velocityIterations; ++i)
+ {
+ for (int32 j = 0; j < m_jointCount; ++j)
+ {
+ m_joints[j]->SolveVelocityConstraints(solverData);
+ }
+
+ contactSolver.SolveVelocityConstraints();
+ }
+
+ // Store impulses for warm starting
+ contactSolver.StoreImpulses();
+ profile->solveVelocity = timer.GetMilliseconds();
+
+ // Integrate positions
+ for (int32 i = 0; i < m_bodyCount; ++i)
+ {
+ b2Vec2 c = m_positions[i].c;
+ float32 a = m_positions[i].a;
+ b2Vec2 v = m_velocities[i].v;
+ float32 w = m_velocities[i].w;
+
+ // Check for large velocities
+ b2Vec2 translation = h * v;
+ if (b2Dot(translation, translation) > b2_maxTranslationSquared)
+ {
+ float32 ratio = b2_maxTranslation / translation.Length();
+ v *= ratio;
+ }
+
+ float32 rotation = h * w;
+ if (rotation * rotation > b2_maxRotationSquared)
+ {
+ float32 ratio = b2_maxRotation / b2Abs(rotation);
+ w *= ratio;
+ }
+
+ // Integrate
+ c += h * v;
+ a += h * w;
+
+ m_positions[i].c = c;
+ m_positions[i].a = a;
+ m_velocities[i].v = v;
+ m_velocities[i].w = w;
+ }
+
+ // Solve position constraints
+ timer.Reset();
+ bool positionSolved = false;
+ for (int32 i = 0; i < step.positionIterations; ++i)
+ {
+ bool contactsOkay = contactSolver.SolvePositionConstraints();
+
+ bool jointsOkay = true;
+ for (int32 i = 0; i < m_jointCount; ++i)
+ {
+ bool jointOkay = m_joints[i]->SolvePositionConstraints(solverData);
+ jointsOkay = jointsOkay && jointOkay;
+ }
+
+ if (contactsOkay && jointsOkay)
+ {
+ // Exit early if the position errors are small.
+ positionSolved = true;
+ break;
+ }
+ }
+
+ // Copy state buffers back to the bodies
+ for (int32 i = 0; i < m_bodyCount; ++i)
+ {
+ b2Body* body = m_bodies[i];
+ body->m_sweep.c = m_positions[i].c;
+ body->m_sweep.a = m_positions[i].a;
+ body->m_linearVelocity = m_velocities[i].v;
+ body->m_angularVelocity = m_velocities[i].w;
+ body->SynchronizeTransform();
+ }
+
+ profile->solvePosition = timer.GetMilliseconds();
+
+ Report(contactSolver.m_velocityConstraints);
+
+ if (allowSleep)
+ {
+ float32 minSleepTime = b2_maxFloat;
+
+ const float32 linTolSqr = b2_linearSleepTolerance * b2_linearSleepTolerance;
+ const float32 angTolSqr = b2_angularSleepTolerance * b2_angularSleepTolerance;
+
+ for (int32 i = 0; i < m_bodyCount; ++i)
+ {
+ b2Body* b = m_bodies[i];
+ if (b->GetType() == b2_staticBody)
+ {
+ continue;
+ }
+
+ if ((b->m_flags & b2Body::e_autoSleepFlag) == 0 ||
+ b->m_angularVelocity * b->m_angularVelocity > angTolSqr ||
+ b2Dot(b->m_linearVelocity, b->m_linearVelocity) > linTolSqr)
+ {
+ b->m_sleepTime = 0.0f;
+ minSleepTime = 0.0f;
+ }
+ else
+ {
+ b->m_sleepTime += h;
+ minSleepTime = b2Min(minSleepTime, b->m_sleepTime);
+ }
+ }
+
+ if (minSleepTime >= b2_timeToSleep && positionSolved)
+ {
+ for (int32 i = 0; i < m_bodyCount; ++i)
+ {
+ b2Body* b = m_bodies[i];
+ b->SetAwake(false);
+ }
+ }
+ }
+}
+
+void b2Island::SolveTOI(const b2TimeStep& subStep, int32 toiIndexA, int32 toiIndexB)
+{
+ b2Assert(toiIndexA < m_bodyCount);
+ b2Assert(toiIndexB < m_bodyCount);
+
+ // Initialize the body state.
+ for (int32 i = 0; i < m_bodyCount; ++i)
+ {
+ b2Body* b = m_bodies[i];
+ m_positions[i].c = b->m_sweep.c;
+ m_positions[i].a = b->m_sweep.a;
+ m_velocities[i].v = b->m_linearVelocity;
+ m_velocities[i].w = b->m_angularVelocity;
+ }
+
+ b2ContactSolverDef contactSolverDef;
+ contactSolverDef.contacts = m_contacts;
+ contactSolverDef.count = m_contactCount;
+ contactSolverDef.allocator = m_allocator;
+ contactSolverDef.step = subStep;
+ contactSolverDef.positions = m_positions;
+ contactSolverDef.velocities = m_velocities;
+ b2ContactSolver contactSolver(&contactSolverDef);
+
+ // Solve position constraints.
+ for (int32 i = 0; i < subStep.positionIterations; ++i)
+ {
+ bool contactsOkay = contactSolver.SolveTOIPositionConstraints(toiIndexA, toiIndexB);
+ if (contactsOkay)
+ {
+ break;
+ }
+ }
+
+#if 0
+ // Is the new position really safe?
+ for (int32 i = 0; i < m_contactCount; ++i)
+ {
+ b2Contact* c = m_contacts[i];
+ b2Fixture* fA = c->GetFixtureA();
+ b2Fixture* fB = c->GetFixtureB();
+
+ b2Body* bA = fA->GetBody();
+ b2Body* bB = fB->GetBody();
+
+ int32 indexA = c->GetChildIndexA();
+ int32 indexB = c->GetChildIndexB();
+
+ b2DistanceInput input;
+ input.proxyA.Set(fA->GetShape(), indexA);
+ input.proxyB.Set(fB->GetShape(), indexB);
+ input.transformA = bA->GetTransform();
+ input.transformB = bB->GetTransform();
+ input.useRadii = false;
+
+ b2DistanceOutput output;
+ b2SimplexCache cache;
+ cache.count = 0;
+ b2Distance(&output, &cache, &input);
+
+ if (output.distance == 0 || cache.count == 3)
+ {
+ cache.count += 0;
+ }
+ }
+#endif
+
+ // Leap of faith to new safe state.
+ m_bodies[toiIndexA]->m_sweep.c0 = m_positions[toiIndexA].c;
+ m_bodies[toiIndexA]->m_sweep.a0 = m_positions[toiIndexA].a;
+ m_bodies[toiIndexB]->m_sweep.c0 = m_positions[toiIndexB].c;
+ m_bodies[toiIndexB]->m_sweep.a0 = m_positions[toiIndexB].a;
+
+ // No warm starting is needed for TOI events because warm
+ // starting impulses were applied in the discrete solver.
+ contactSolver.InitializeVelocityConstraints();
+
+ // Solve velocity constraints.
+ for (int32 i = 0; i < subStep.velocityIterations; ++i)
+ {
+ contactSolver.SolveVelocityConstraints();
+ }
+
+ // Don't store the TOI contact forces for warm starting
+ // because they can be quite large.
+
+ float32 h = subStep.dt;
+
+ // Integrate positions
+ for (int32 i = 0; i < m_bodyCount; ++i)
+ {
+ b2Vec2 c = m_positions[i].c;
+ float32 a = m_positions[i].a;
+ b2Vec2 v = m_velocities[i].v;
+ float32 w = m_velocities[i].w;
+
+ // Check for large velocities
+ b2Vec2 translation = h * v;
+ if (b2Dot(translation, translation) > b2_maxTranslationSquared)
+ {
+ float32 ratio = b2_maxTranslation / translation.Length();
+ v *= ratio;
+ }
+
+ float32 rotation = h * w;
+ if (rotation * rotation > b2_maxRotationSquared)
+ {
+ float32 ratio = b2_maxRotation / b2Abs(rotation);
+ w *= ratio;
+ }
+
+ // Integrate
+ c += h * v;
+ a += h * w;
+
+ m_positions[i].c = c;
+ m_positions[i].a = a;
+ m_velocities[i].v = v;
+ m_velocities[i].w = w;
+
+ // Sync bodies
+ b2Body* body = m_bodies[i];
+ body->m_sweep.c = c;
+ body->m_sweep.a = a;
+ body->m_linearVelocity = v;
+ body->m_angularVelocity = w;
+ body->SynchronizeTransform();
+ }
+
+ Report(contactSolver.m_velocityConstraints);
+}
+
+void b2Island::Report(const b2ContactVelocityConstraint* constraints)
+{
+ if (m_listener == NULL)
+ {
+ return;
+ }
+
+ for (int32 i = 0; i < m_contactCount; ++i)
+ {
+ b2Contact* c = m_contacts[i];
+
+ const b2ContactVelocityConstraint* vc = constraints + i;
+
+ b2ContactImpulse impulse;
+ impulse.count = vc->pointCount;
+ for (int32 j = 0; j < vc->pointCount; ++j)
+ {
+ impulse.normalImpulses[j] = vc->points[j].normalImpulse;
+ impulse.tangentImpulses[j] = vc->points[j].tangentImpulse;
+ }
+
+ m_listener->PostSolve(c, &impulse);
+ }
+}
diff --git a/tests/box2d/Box2D/Dynamics/b2Island.h b/tests/box2d/Box2D/Dynamics/b2Island.h new file mode 100755 index 00000000..ef3d9b1d --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/b2Island.h @@ -0,0 +1,93 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_ISLAND_H
+#define B2_ISLAND_H
+
+#include <Box2D/Common/b2Math.h>
+#include <Box2D/Dynamics/b2Body.h>
+#include <Box2D/Dynamics/b2TimeStep.h>
+
+class b2Contact;
+class b2Joint;
+class b2StackAllocator;
+class b2ContactListener;
+struct b2ContactVelocityConstraint;
+struct b2Profile;
+
+/// This is an internal class.
+class b2Island
+{
+public:
+ b2Island(int32 bodyCapacity, int32 contactCapacity, int32 jointCapacity,
+ b2StackAllocator* allocator, b2ContactListener* listener);
+ ~b2Island();
+
+ void Clear()
+ {
+ m_bodyCount = 0;
+ m_contactCount = 0;
+ m_jointCount = 0;
+ }
+
+ void Solve(b2Profile* profile, const b2TimeStep& step, const b2Vec2& gravity, bool allowSleep);
+
+ void SolveTOI(const b2TimeStep& subStep, int32 toiIndexA, int32 toiIndexB);
+
+ void Add(b2Body* body)
+ {
+ b2Assert(m_bodyCount < m_bodyCapacity);
+ body->m_islandIndex = m_bodyCount;
+ m_bodies[m_bodyCount] = body;
+ ++m_bodyCount;
+ }
+
+ void Add(b2Contact* contact)
+ {
+ b2Assert(m_contactCount < m_contactCapacity);
+ m_contacts[m_contactCount++] = contact;
+ }
+
+ void Add(b2Joint* joint)
+ {
+ b2Assert(m_jointCount < m_jointCapacity);
+ m_joints[m_jointCount++] = joint;
+ }
+
+ void Report(const b2ContactVelocityConstraint* constraints);
+
+ b2StackAllocator* m_allocator;
+ b2ContactListener* m_listener;
+
+ b2Body** m_bodies;
+ b2Contact** m_contacts;
+ b2Joint** m_joints;
+
+ b2Position* m_positions;
+ b2Velocity* m_velocities;
+
+ int32 m_bodyCount;
+ int32 m_jointCount;
+ int32 m_contactCount;
+
+ int32 m_bodyCapacity;
+ int32 m_contactCapacity;
+ int32 m_jointCapacity;
+};
+
+#endif
diff --git a/tests/box2d/Box2D/Dynamics/b2TimeStep.h b/tests/box2d/Box2D/Dynamics/b2TimeStep.h new file mode 100755 index 00000000..abe6fb6e --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/b2TimeStep.h @@ -0,0 +1,70 @@ +/*
+* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_TIME_STEP_H
+#define B2_TIME_STEP_H
+
+#include <Box2D/Common/b2Math.h>
+
+/// Profiling data. Times are in milliseconds.
+struct b2Profile
+{
+ float32 step;
+ float32 collide;
+ float32 solve;
+ float32 solveInit;
+ float32 solveVelocity;
+ float32 solvePosition;
+ float32 broadphase;
+ float32 solveTOI;
+};
+
+/// This is an internal structure.
+struct b2TimeStep
+{
+ float32 dt; // time step
+ float32 inv_dt; // inverse time step (0 if dt == 0).
+ float32 dtRatio; // dt * inv_dt0
+ int32 velocityIterations;
+ int32 positionIterations;
+ bool warmStarting;
+};
+
+/// This is an internal structure.
+struct b2Position
+{
+ b2Vec2 c;
+ float32 a;
+};
+
+/// This is an internal structure.
+struct b2Velocity
+{
+ b2Vec2 v;
+ float32 w;
+};
+
+/// Solver Data
+struct b2SolverData
+{
+ b2TimeStep step;
+ b2Position* positions;
+ b2Velocity* velocities;
+};
+
+#endif
diff --git a/tests/box2d/Box2D/Dynamics/b2World.cpp b/tests/box2d/Box2D/Dynamics/b2World.cpp new file mode 100755 index 00000000..baacded4 --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/b2World.cpp @@ -0,0 +1,1316 @@ +/*
+* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Dynamics/b2World.h>
+#include <Box2D/Dynamics/b2Body.h>
+#include <Box2D/Dynamics/b2Fixture.h>
+#include <Box2D/Dynamics/b2Island.h>
+#include <Box2D/Dynamics/Joints/b2PulleyJoint.h>
+#include <Box2D/Dynamics/Contacts/b2Contact.h>
+#include <Box2D/Dynamics/Contacts/b2ContactSolver.h>
+#include <Box2D/Collision/b2Collision.h>
+#include <Box2D/Collision/b2BroadPhase.h>
+#include <Box2D/Collision/Shapes/b2CircleShape.h>
+#include <Box2D/Collision/Shapes/b2EdgeShape.h>
+#include <Box2D/Collision/Shapes/b2ChainShape.h>
+#include <Box2D/Collision/Shapes/b2PolygonShape.h>
+#include <Box2D/Collision/b2TimeOfImpact.h>
+#include <Box2D/Common/b2Draw.h>
+#include <Box2D/Common/b2Timer.h>
+#include <new>
+
+b2World::b2World(const b2Vec2& gravity)
+{
+ m_destructionListener = NULL;
+ m_debugDraw = NULL;
+
+ m_bodyList = NULL;
+ m_jointList = NULL;
+
+ m_bodyCount = 0;
+ m_jointCount = 0;
+
+ m_warmStarting = true;
+ m_continuousPhysics = true;
+ m_subStepping = false;
+
+ m_stepComplete = true;
+
+ m_allowSleep = true;
+ m_gravity = gravity;
+
+ m_flags = e_clearForces;
+
+ m_inv_dt0 = 0.0f;
+
+ m_contactManager.m_allocator = &m_blockAllocator;
+
+ memset(&m_profile, 0, sizeof(b2Profile));
+}
+
+b2World::~b2World()
+{
+ // Some shapes allocate using b2Alloc.
+ b2Body* b = m_bodyList;
+ while (b)
+ {
+ b2Body* bNext = b->m_next;
+
+ b2Fixture* f = b->m_fixtureList;
+ while (f)
+ {
+ b2Fixture* fNext = f->m_next;
+ f->m_proxyCount = 0;
+ f->Destroy(&m_blockAllocator);
+ f = fNext;
+ }
+
+ b = bNext;
+ }
+}
+
+void b2World::SetDestructionListener(b2DestructionListener* listener)
+{
+ m_destructionListener = listener;
+}
+
+void b2World::SetContactFilter(b2ContactFilter* filter)
+{
+ m_contactManager.m_contactFilter = filter;
+}
+
+void b2World::SetContactListener(b2ContactListener* listener)
+{
+ m_contactManager.m_contactListener = listener;
+}
+
+void b2World::SetDebugDraw(b2Draw* debugDraw)
+{
+ m_debugDraw = debugDraw;
+}
+
+b2Body* b2World::CreateBody(const b2BodyDef* def)
+{
+ b2Assert(IsLocked() == false);
+ if (IsLocked())
+ {
+ return NULL;
+ }
+
+ void* mem = m_blockAllocator.Allocate(sizeof(b2Body));
+ b2Body* b = new (mem) b2Body(def, this);
+
+ // Add to world doubly linked list.
+ b->m_prev = NULL;
+ b->m_next = m_bodyList;
+ if (m_bodyList)
+ {
+ m_bodyList->m_prev = b;
+ }
+ m_bodyList = b;
+ ++m_bodyCount;
+
+ return b;
+}
+
+void b2World::DestroyBody(b2Body* b)
+{
+ b2Assert(m_bodyCount > 0);
+ b2Assert(IsLocked() == false);
+ if (IsLocked())
+ {
+ return;
+ }
+
+ // Delete the attached joints.
+ b2JointEdge* je = b->m_jointList;
+ while (je)
+ {
+ b2JointEdge* je0 = je;
+ je = je->next;
+
+ if (m_destructionListener)
+ {
+ m_destructionListener->SayGoodbye(je0->joint);
+ }
+
+ DestroyJoint(je0->joint);
+
+ b->m_jointList = je;
+ }
+ b->m_jointList = NULL;
+
+ // Delete the attached contacts.
+ b2ContactEdge* ce = b->m_contactList;
+ while (ce)
+ {
+ b2ContactEdge* ce0 = ce;
+ ce = ce->next;
+ m_contactManager.Destroy(ce0->contact);
+ }
+ b->m_contactList = NULL;
+
+ // Delete the attached fixtures. This destroys broad-phase proxies.
+ b2Fixture* f = b->m_fixtureList;
+ while (f)
+ {
+ b2Fixture* f0 = f;
+ f = f->m_next;
+
+ if (m_destructionListener)
+ {
+ m_destructionListener->SayGoodbye(f0);
+ }
+
+ f0->DestroyProxies(&m_contactManager.m_broadPhase);
+ f0->Destroy(&m_blockAllocator);
+ f0->~b2Fixture();
+ m_blockAllocator.Free(f0, sizeof(b2Fixture));
+
+ b->m_fixtureList = f;
+ b->m_fixtureCount -= 1;
+ }
+ b->m_fixtureList = NULL;
+ b->m_fixtureCount = 0;
+
+ // Remove world body list.
+ 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 == m_bodyList)
+ {
+ m_bodyList = b->m_next;
+ }
+
+ --m_bodyCount;
+ b->~b2Body();
+ m_blockAllocator.Free(b, sizeof(b2Body));
+}
+
+b2Joint* b2World::CreateJoint(const b2JointDef* def)
+{
+ b2Assert(IsLocked() == false);
+ if (IsLocked())
+ {
+ return NULL;
+ }
+
+ b2Joint* j = b2Joint::Create(def, &m_blockAllocator);
+
+ // Connect to the world list.
+ j->m_prev = NULL;
+ j->m_next = m_jointList;
+ if (m_jointList)
+ {
+ m_jointList->m_prev = j;
+ }
+ m_jointList = j;
+ ++m_jointCount;
+
+ // Connect to the bodies' doubly linked lists.
+ j->m_edgeA.joint = j;
+ j->m_edgeA.other = j->m_bodyB;
+ j->m_edgeA.prev = NULL;
+ j->m_edgeA.next = j->m_bodyA->m_jointList;
+ if (j->m_bodyA->m_jointList) j->m_bodyA->m_jointList->prev = &j->m_edgeA;
+ j->m_bodyA->m_jointList = &j->m_edgeA;
+
+ j->m_edgeB.joint = j;
+ j->m_edgeB.other = j->m_bodyA;
+ j->m_edgeB.prev = NULL;
+ j->m_edgeB.next = j->m_bodyB->m_jointList;
+ if (j->m_bodyB->m_jointList) j->m_bodyB->m_jointList->prev = &j->m_edgeB;
+ j->m_bodyB->m_jointList = &j->m_edgeB;
+
+ b2Body* bodyA = def->bodyA;
+ b2Body* bodyB = def->bodyB;
+
+ // If the joint prevents collisions, then flag any contacts for filtering.
+ if (def->collideConnected == false)
+ {
+ b2ContactEdge* edge = bodyB->GetContactList();
+ while (edge)
+ {
+ if (edge->other == bodyA)
+ {
+ // Flag the contact for filtering at the next time step (where either
+ // body is awake).
+ edge->contact->FlagForFiltering();
+ }
+
+ edge = edge->next;
+ }
+ }
+
+ // Note: creating a joint doesn't wake the bodies.
+
+ return j;
+}
+
+void b2World::DestroyJoint(b2Joint* j)
+{
+ b2Assert(IsLocked() == false);
+ if (IsLocked())
+ {
+ return;
+ }
+
+ bool collideConnected = j->m_collideConnected;
+
+ // Remove from the doubly linked list.
+ 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 == m_jointList)
+ {
+ m_jointList = j->m_next;
+ }
+
+ // Disconnect from island graph.
+ b2Body* bodyA = j->m_bodyA;
+ b2Body* bodyB = j->m_bodyB;
+
+ // Wake up connected bodies.
+ bodyA->SetAwake(true);
+ bodyB->SetAwake(true);
+
+ // Remove from body 1.
+ if (j->m_edgeA.prev)
+ {
+ j->m_edgeA.prev->next = j->m_edgeA.next;
+ }
+
+ if (j->m_edgeA.next)
+ {
+ j->m_edgeA.next->prev = j->m_edgeA.prev;
+ }
+
+ if (&j->m_edgeA == bodyA->m_jointList)
+ {
+ bodyA->m_jointList = j->m_edgeA.next;
+ }
+
+ j->m_edgeA.prev = NULL;
+ j->m_edgeA.next = NULL;
+
+ // Remove from body 2
+ if (j->m_edgeB.prev)
+ {
+ j->m_edgeB.prev->next = j->m_edgeB.next;
+ }
+
+ if (j->m_edgeB.next)
+ {
+ j->m_edgeB.next->prev = j->m_edgeB.prev;
+ }
+
+ if (&j->m_edgeB == bodyB->m_jointList)
+ {
+ bodyB->m_jointList = j->m_edgeB.next;
+ }
+
+ j->m_edgeB.prev = NULL;
+ j->m_edgeB.next = NULL;
+
+ b2Joint::Destroy(j, &m_blockAllocator);
+
+ b2Assert(m_jointCount > 0);
+ --m_jointCount;
+
+ // If the joint prevents collisions, then flag any contacts for filtering.
+ if (collideConnected == false)
+ {
+ b2ContactEdge* edge = bodyB->GetContactList();
+ while (edge)
+ {
+ if (edge->other == bodyA)
+ {
+ // Flag the contact for filtering at the next time step (where either
+ // body is awake).
+ edge->contact->FlagForFiltering();
+ }
+
+ edge = edge->next;
+ }
+ }
+}
+
+//
+void b2World::SetAllowSleeping(bool flag)
+{
+ if (flag == m_allowSleep)
+ {
+ return;
+ }
+
+ m_allowSleep = flag;
+ if (m_allowSleep == false)
+ {
+ for (b2Body* b = m_bodyList; b; b = b->m_next)
+ {
+ b->SetAwake(true);
+ }
+ }
+}
+
+// Find islands, integrate and solve constraints, solve position constraints
+void b2World::Solve(const b2TimeStep& step)
+{
+ m_profile.solveInit = 0.0f;
+ m_profile.solveVelocity = 0.0f;
+ m_profile.solvePosition = 0.0f;
+
+ // Size the island for the worst case.
+ b2Island island(m_bodyCount,
+ m_contactManager.m_contactCount,
+ m_jointCount,
+ &m_stackAllocator,
+ m_contactManager.m_contactListener);
+
+ // Clear all the island flags.
+ for (b2Body* b = m_bodyList; b; b = b->m_next)
+ {
+ b->m_flags &= ~b2Body::e_islandFlag;
+ }
+ for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next)
+ {
+ c->m_flags &= ~b2Contact::e_islandFlag;
+ }
+ for (b2Joint* j = m_jointList; j; j = j->m_next)
+ {
+ j->m_islandFlag = false;
+ }
+
+ // Build and simulate all awake islands.
+ int32 stackSize = m_bodyCount;
+ b2Body** stack = (b2Body**)m_stackAllocator.Allocate(stackSize * sizeof(b2Body*));
+ for (b2Body* seed = m_bodyList; seed; seed = seed->m_next)
+ {
+ if (seed->m_flags & b2Body::e_islandFlag)
+ {
+ continue;
+ }
+
+ if (seed->IsAwake() == false || seed->IsActive() == false)
+ {
+ continue;
+ }
+
+ // The seed can be dynamic or kinematic.
+ if (seed->GetType() == b2_staticBody)
+ {
+ continue;
+ }
+
+ // Reset island and stack.
+ island.Clear();
+ int32 stackCount = 0;
+ stack[stackCount++] = seed;
+ seed->m_flags |= b2Body::e_islandFlag;
+
+ // Perform a depth first search (DFS) on the constraint graph.
+ while (stackCount > 0)
+ {
+ // Grab the next body off the stack and add it to the island.
+ b2Body* b = stack[--stackCount];
+ b2Assert(b->IsActive() == true);
+ island.Add(b);
+
+ // Make sure the body is awake.
+ b->SetAwake(true);
+
+ // To keep islands as small as possible, we don't
+ // propagate islands across static bodies.
+ if (b->GetType() == b2_staticBody)
+ {
+ continue;
+ }
+
+ // Search all contacts connected to this body.
+ for (b2ContactEdge* ce = b->m_contactList; ce; ce = ce->next)
+ {
+ b2Contact* contact = ce->contact;
+
+ // Has this contact already been added to an island?
+ if (contact->m_flags & b2Contact::e_islandFlag)
+ {
+ continue;
+ }
+
+ // Is this contact solid and touching?
+ if (contact->IsEnabled() == false ||
+ contact->IsTouching() == false)
+ {
+ continue;
+ }
+
+ // Skip sensors.
+ bool sensorA = contact->m_fixtureA->m_isSensor;
+ bool sensorB = contact->m_fixtureB->m_isSensor;
+ if (sensorA || sensorB)
+ {
+ continue;
+ }
+
+ island.Add(contact);
+ contact->m_flags |= b2Contact::e_islandFlag;
+
+ b2Body* other = ce->other;
+
+ // Was the other body already added to this island?
+ if (other->m_flags & b2Body::e_islandFlag)
+ {
+ continue;
+ }
+
+ b2Assert(stackCount < stackSize);
+ stack[stackCount++] = other;
+ other->m_flags |= b2Body::e_islandFlag;
+ }
+
+ // Search all joints connect to this body.
+ for (b2JointEdge* je = b->m_jointList; je; je = je->next)
+ {
+ if (je->joint->m_islandFlag == true)
+ {
+ continue;
+ }
+
+ b2Body* other = je->other;
+
+ // Don't simulate joints connected to inactive bodies.
+ if (other->IsActive() == false)
+ {
+ continue;
+ }
+
+ island.Add(je->joint);
+ je->joint->m_islandFlag = true;
+
+ if (other->m_flags & b2Body::e_islandFlag)
+ {
+ continue;
+ }
+
+ b2Assert(stackCount < stackSize);
+ stack[stackCount++] = other;
+ other->m_flags |= b2Body::e_islandFlag;
+ }
+ }
+
+ b2Profile profile;
+ island.Solve(&profile, step, m_gravity, m_allowSleep);
+ m_profile.solveInit += profile.solveInit;
+ m_profile.solveVelocity += profile.solveVelocity;
+ m_profile.solvePosition += profile.solvePosition;
+
+ // Post solve cleanup.
+ for (int32 i = 0; i < island.m_bodyCount; ++i)
+ {
+ // Allow static bodies to participate in other islands.
+ b2Body* b = island.m_bodies[i];
+ if (b->GetType() == b2_staticBody)
+ {
+ b->m_flags &= ~b2Body::e_islandFlag;
+ }
+ }
+ }
+
+ m_stackAllocator.Free(stack);
+
+ {
+ b2Timer timer;
+ // Synchronize fixtures, check for out of range bodies.
+ for (b2Body* b = m_bodyList; b; b = b->GetNext())
+ {
+ // If a body was not in an island then it did not move.
+ if ((b->m_flags & b2Body::e_islandFlag) == 0)
+ {
+ continue;
+ }
+
+ if (b->GetType() == b2_staticBody)
+ {
+ continue;
+ }
+
+ // Update fixtures (for broad-phase).
+ b->SynchronizeFixtures();
+ }
+
+ // Look for new contacts.
+ m_contactManager.FindNewContacts();
+ m_profile.broadphase = timer.GetMilliseconds();
+ }
+}
+
+// Find TOI contacts and solve them.
+void b2World::SolveTOI(const b2TimeStep& step)
+{
+ b2Island island(2 * b2_maxTOIContacts, b2_maxTOIContacts, 0, &m_stackAllocator, m_contactManager.m_contactListener);
+
+ if (m_stepComplete)
+ {
+ for (b2Body* b = m_bodyList; b; b = b->m_next)
+ {
+ b->m_flags &= ~b2Body::e_islandFlag;
+ b->m_sweep.alpha0 = 0.0f;
+ }
+
+ for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next)
+ {
+ // Invalidate TOI
+ c->m_flags &= ~(b2Contact::e_toiFlag | b2Contact::e_islandFlag);
+ c->m_toiCount = 0;
+ c->m_toi = 1.0f;
+ }
+ }
+
+ // Find TOI events and solve them.
+ for (;;)
+ {
+ // Find the first TOI.
+ b2Contact* minContact = NULL;
+ float32 minAlpha = 1.0f;
+
+ for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next)
+ {
+ // Is this contact disabled?
+ if (c->IsEnabled() == false)
+ {
+ continue;
+ }
+
+ // Prevent excessive sub-stepping.
+ if (c->m_toiCount > b2_maxSubSteps)
+ {
+ continue;
+ }
+
+ float32 alpha = 1.0f;
+ if (c->m_flags & b2Contact::e_toiFlag)
+ {
+ // This contact has a valid cached TOI.
+ alpha = c->m_toi;
+ }
+ else
+ {
+ b2Fixture* fA = c->GetFixtureA();
+ b2Fixture* fB = c->GetFixtureB();
+
+ // Is there a sensor?
+ if (fA->IsSensor() || fB->IsSensor())
+ {
+ continue;
+ }
+
+ b2Body* bA = fA->GetBody();
+ b2Body* bB = fB->GetBody();
+
+ b2BodyType typeA = bA->m_type;
+ b2BodyType typeB = bB->m_type;
+ b2Assert(typeA == b2_dynamicBody || typeB == b2_dynamicBody);
+
+ bool activeA = bA->IsAwake() && typeA != b2_staticBody;
+ bool activeB = bB->IsAwake() && typeB != b2_staticBody;
+
+ // Is at least one body active (awake and dynamic or kinematic)?
+ if (activeA == false && activeB == false)
+ {
+ continue;
+ }
+
+ bool collideA = bA->IsBullet() || typeA != b2_dynamicBody;
+ bool collideB = bB->IsBullet() || typeB != b2_dynamicBody;
+
+ // Are these two non-bullet dynamic bodies?
+ if (collideA == false && collideB == false)
+ {
+ continue;
+ }
+
+ // Compute the TOI for this contact.
+ // Put the sweeps onto the same time interval.
+ float32 alpha0 = bA->m_sweep.alpha0;
+
+ if (bA->m_sweep.alpha0 < bB->m_sweep.alpha0)
+ {
+ alpha0 = bB->m_sweep.alpha0;
+ bA->m_sweep.Advance(alpha0);
+ }
+ else if (bB->m_sweep.alpha0 < bA->m_sweep.alpha0)
+ {
+ alpha0 = bA->m_sweep.alpha0;
+ bB->m_sweep.Advance(alpha0);
+ }
+
+ b2Assert(alpha0 < 1.0f);
+
+ int32 indexA = c->GetChildIndexA();
+ int32 indexB = c->GetChildIndexB();
+
+ // Compute the time of impact in interval [0, minTOI]
+ b2TOIInput input;
+ input.proxyA.Set(fA->GetShape(), indexA);
+ input.proxyB.Set(fB->GetShape(), indexB);
+ input.sweepA = bA->m_sweep;
+ input.sweepB = bB->m_sweep;
+ input.tMax = 1.0f;
+
+ b2TOIOutput output;
+ b2TimeOfImpact(&output, &input);
+
+ // Beta is the fraction of the remaining portion of the .
+ float32 beta = output.t;
+ if (output.state == b2TOIOutput::e_touching)
+ {
+ alpha = b2Min(alpha0 + (1.0f - alpha0) * beta, 1.0f);
+ }
+ else
+ {
+ alpha = 1.0f;
+ }
+
+ c->m_toi = alpha;
+ c->m_flags |= b2Contact::e_toiFlag;
+ }
+
+ if (alpha < minAlpha)
+ {
+ // This is the minimum TOI found so far.
+ minContact = c;
+ minAlpha = alpha;
+ }
+ }
+
+ if (minContact == NULL || 1.0f - 10.0f * b2_epsilon < minAlpha)
+ {
+ // No more TOI events. Done!
+ m_stepComplete = true;
+ break;
+ }
+
+ // Advance the bodies to the TOI.
+ b2Fixture* fA = minContact->GetFixtureA();
+ b2Fixture* fB = minContact->GetFixtureB();
+ b2Body* bA = fA->GetBody();
+ b2Body* bB = fB->GetBody();
+
+ b2Sweep backup1 = bA->m_sweep;
+ b2Sweep backup2 = bB->m_sweep;
+
+ bA->Advance(minAlpha);
+ bB->Advance(minAlpha);
+
+ // The TOI contact likely has some new contact points.
+ minContact->Update(m_contactManager.m_contactListener);
+ minContact->m_flags &= ~b2Contact::e_toiFlag;
+ ++minContact->m_toiCount;
+
+ // Is the contact solid?
+ if (minContact->IsEnabled() == false || minContact->IsTouching() == false)
+ {
+ // Restore the sweeps.
+ minContact->SetEnabled(false);
+ bA->m_sweep = backup1;
+ bB->m_sweep = backup2;
+ bA->SynchronizeTransform();
+ bB->SynchronizeTransform();
+ continue;
+ }
+
+ bA->SetAwake(true);
+ bB->SetAwake(true);
+
+ // Build the island
+ island.Clear();
+ island.Add(bA);
+ island.Add(bB);
+ island.Add(minContact);
+
+ bA->m_flags |= b2Body::e_islandFlag;
+ bB->m_flags |= b2Body::e_islandFlag;
+ minContact->m_flags |= b2Contact::e_islandFlag;
+
+ // Get contacts on bodyA and bodyB.
+ b2Body* bodies[2] = {bA, bB};
+ for (int32 i = 0; i < 2; ++i)
+ {
+ b2Body* body = bodies[i];
+ if (body->m_type == b2_dynamicBody)
+ {
+ for (b2ContactEdge* ce = body->m_contactList; ce; ce = ce->next)
+ {
+ if (island.m_bodyCount == island.m_bodyCapacity)
+ {
+ break;
+ }
+
+ if (island.m_contactCount == island.m_contactCapacity)
+ {
+ break;
+ }
+
+ b2Contact* contact = ce->contact;
+
+ // Has this contact already been added to the island?
+ if (contact->m_flags & b2Contact::e_islandFlag)
+ {
+ continue;
+ }
+
+ // Only add static, kinematic, or bullet bodies.
+ b2Body* other = ce->other;
+ if (other->m_type == b2_dynamicBody &&
+ body->IsBullet() == false && other->IsBullet() == false)
+ {
+ continue;
+ }
+
+ // Skip sensors.
+ bool sensorA = contact->m_fixtureA->m_isSensor;
+ bool sensorB = contact->m_fixtureB->m_isSensor;
+ if (sensorA || sensorB)
+ {
+ continue;
+ }
+
+ // Tentatively advance the body to the TOI.
+ b2Sweep backup = other->m_sweep;
+ if ((other->m_flags & b2Body::e_islandFlag) == 0)
+ {
+ other->Advance(minAlpha);
+ }
+
+ // Update the contact points
+ contact->Update(m_contactManager.m_contactListener);
+
+ // Was the contact disabled by the user?
+ if (contact->IsEnabled() == false)
+ {
+ other->m_sweep = backup;
+ other->SynchronizeTransform();
+ continue;
+ }
+
+ // Are there contact points?
+ if (contact->IsTouching() == false)
+ {
+ other->m_sweep = backup;
+ other->SynchronizeTransform();
+ continue;
+ }
+
+ // Add the contact to the island
+ contact->m_flags |= b2Contact::e_islandFlag;
+ island.Add(contact);
+
+ // Has the other body already been added to the island?
+ if (other->m_flags & b2Body::e_islandFlag)
+ {
+ continue;
+ }
+
+ // Add the other body to the island.
+ other->m_flags |= b2Body::e_islandFlag;
+
+ if (other->m_type != b2_staticBody)
+ {
+ other->SetAwake(true);
+ }
+
+ island.Add(other);
+ }
+ }
+ }
+
+ b2TimeStep subStep;
+ subStep.dt = (1.0f - minAlpha) * step.dt;
+ subStep.inv_dt = 1.0f / subStep.dt;
+ subStep.dtRatio = 1.0f;
+ subStep.positionIterations = 20;
+ subStep.velocityIterations = step.velocityIterations;
+ subStep.warmStarting = false;
+ island.SolveTOI(subStep, bA->m_islandIndex, bB->m_islandIndex);
+
+ // Reset island flags and synchronize broad-phase proxies.
+ for (int32 i = 0; i < island.m_bodyCount; ++i)
+ {
+ b2Body* body = island.m_bodies[i];
+ body->m_flags &= ~b2Body::e_islandFlag;
+
+ if (body->m_type != b2_dynamicBody)
+ {
+ continue;
+ }
+
+ body->SynchronizeFixtures();
+
+ // Invalidate all contact TOIs on this displaced body.
+ for (b2ContactEdge* ce = body->m_contactList; ce; ce = ce->next)
+ {
+ ce->contact->m_flags &= ~(b2Contact::e_toiFlag | b2Contact::e_islandFlag);
+ }
+ }
+
+ // Commit fixture proxy movements to the broad-phase so that new contacts are created.
+ // Also, some contacts can be destroyed.
+ m_contactManager.FindNewContacts();
+
+ if (m_subStepping)
+ {
+ m_stepComplete = false;
+ break;
+ }
+ }
+}
+
+void b2World::Step(float32 dt, int32 velocityIterations, int32 positionIterations)
+{
+ b2Timer stepTimer;
+
+ // If new fixtures were added, we need to find the new contacts.
+ if (m_flags & e_newFixture)
+ {
+ m_contactManager.FindNewContacts();
+ m_flags &= ~e_newFixture;
+ }
+
+ m_flags |= e_locked;
+
+ b2TimeStep step;
+ step.dt = dt;
+ step.velocityIterations = velocityIterations;
+ step.positionIterations = positionIterations;
+ if (dt > 0.0f)
+ {
+ step.inv_dt = 1.0f / dt;
+ }
+ else
+ {
+ step.inv_dt = 0.0f;
+ }
+
+ step.dtRatio = m_inv_dt0 * dt;
+
+ step.warmStarting = m_warmStarting;
+
+ // Update contacts. This is where some contacts are destroyed.
+ {
+ b2Timer timer;
+ m_contactManager.Collide();
+ m_profile.collide = timer.GetMilliseconds();
+ }
+
+ // Integrate velocities, solve velocity constraints, and integrate positions.
+ if (m_stepComplete && step.dt > 0.0f)
+ {
+ b2Timer timer;
+ Solve(step);
+ m_profile.solve = timer.GetMilliseconds();
+ }
+
+ // Handle TOI events.
+ if (m_continuousPhysics && step.dt > 0.0f)
+ {
+ b2Timer timer;
+ SolveTOI(step);
+ m_profile.solveTOI = timer.GetMilliseconds();
+ }
+
+ if (step.dt > 0.0f)
+ {
+ m_inv_dt0 = step.inv_dt;
+ }
+
+ if (m_flags & e_clearForces)
+ {
+ ClearForces();
+ }
+
+ m_flags &= ~e_locked;
+
+ m_profile.step = stepTimer.GetMilliseconds();
+}
+
+void b2World::ClearForces()
+{
+ for (b2Body* body = m_bodyList; body; body = body->GetNext())
+ {
+ body->m_force.SetZero();
+ body->m_torque = 0.0f;
+ }
+}
+
+struct b2WorldQueryWrapper
+{
+ bool QueryCallback(int32 proxyId)
+ {
+ b2FixtureProxy* proxy = (b2FixtureProxy*)broadPhase->GetUserData(proxyId);
+ return callback->ReportFixture(proxy->fixture);
+ }
+
+ const b2BroadPhase* broadPhase;
+ b2QueryCallback* callback;
+};
+
+void b2World::QueryAABB(b2QueryCallback* callback, const b2AABB& aabb) const
+{
+ b2WorldQueryWrapper wrapper;
+ wrapper.broadPhase = &m_contactManager.m_broadPhase;
+ wrapper.callback = callback;
+ m_contactManager.m_broadPhase.Query(&wrapper, aabb);
+}
+
+struct b2WorldRayCastWrapper
+{
+ float32 RayCastCallback(const b2RayCastInput& input, int32 proxyId)
+ {
+ void* userData = broadPhase->GetUserData(proxyId);
+ b2FixtureProxy* proxy = (b2FixtureProxy*)userData;
+ b2Fixture* fixture = proxy->fixture;
+ int32 index = proxy->childIndex;
+ b2RayCastOutput output;
+ bool hit = fixture->RayCast(&output, input, index);
+
+ if (hit)
+ {
+ float32 fraction = output.fraction;
+ b2Vec2 point = (1.0f - fraction) * input.p1 + fraction * input.p2;
+ return callback->ReportFixture(fixture, point, output.normal, fraction);
+ }
+
+ return input.maxFraction;
+ }
+
+ const b2BroadPhase* broadPhase;
+ b2RayCastCallback* callback;
+};
+
+void b2World::RayCast(b2RayCastCallback* callback, const b2Vec2& point1, const b2Vec2& point2) const
+{
+ b2WorldRayCastWrapper wrapper;
+ wrapper.broadPhase = &m_contactManager.m_broadPhase;
+ wrapper.callback = callback;
+ b2RayCastInput input;
+ input.maxFraction = 1.0f;
+ input.p1 = point1;
+ input.p2 = point2;
+ m_contactManager.m_broadPhase.RayCast(&wrapper, input);
+}
+
+void b2World::DrawShape(b2Fixture* fixture, const b2Transform& xf, const b2Color& color)
+{
+ switch (fixture->GetType())
+ {
+ case b2Shape::e_circle:
+ {
+ b2CircleShape* circle = (b2CircleShape*)fixture->GetShape();
+
+ b2Vec2 center = b2Mul(xf, circle->m_p);
+ float32 radius = circle->m_radius;
+ b2Vec2 axis = b2Mul(xf.q, b2Vec2(1.0f, 0.0f));
+
+ m_debugDraw->DrawSolidCircle(center, radius, axis, color);
+ }
+ break;
+
+ case b2Shape::e_edge:
+ {
+ b2EdgeShape* edge = (b2EdgeShape*)fixture->GetShape();
+ b2Vec2 v1 = b2Mul(xf, edge->m_vertex1);
+ b2Vec2 v2 = b2Mul(xf, edge->m_vertex2);
+ m_debugDraw->DrawSegment(v1, v2, color);
+ }
+ break;
+
+ case b2Shape::e_chain:
+ {
+ b2ChainShape* chain = (b2ChainShape*)fixture->GetShape();
+ int32 count = chain->m_count;
+ const b2Vec2* vertices = chain->m_vertices;
+
+ b2Vec2 v1 = b2Mul(xf, vertices[0]);
+ for (int32 i = 1; i < count; ++i)
+ {
+ b2Vec2 v2 = b2Mul(xf, vertices[i]);
+ m_debugDraw->DrawSegment(v1, v2, color);
+ m_debugDraw->DrawCircle(v1, 0.05f, color);
+ v1 = v2;
+ }
+ }
+ break;
+
+ case b2Shape::e_polygon:
+ {
+ b2PolygonShape* poly = (b2PolygonShape*)fixture->GetShape();
+ int32 vertexCount = poly->m_vertexCount;
+ b2Assert(vertexCount <= b2_maxPolygonVertices);
+ b2Vec2 vertices[b2_maxPolygonVertices];
+
+ for (int32 i = 0; i < vertexCount; ++i)
+ {
+ vertices[i] = b2Mul(xf, poly->m_vertices[i]);
+ }
+
+ m_debugDraw->DrawSolidPolygon(vertices, vertexCount, color);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void b2World::DrawJoint(b2Joint* joint)
+{
+ b2Body* bodyA = joint->GetBodyA();
+ b2Body* bodyB = joint->GetBodyB();
+ const b2Transform& xf1 = bodyA->GetTransform();
+ const b2Transform& xf2 = bodyB->GetTransform();
+ b2Vec2 x1 = xf1.p;
+ b2Vec2 x2 = xf2.p;
+ b2Vec2 p1 = joint->GetAnchorA();
+ b2Vec2 p2 = joint->GetAnchorB();
+
+ b2Color color(0.5f, 0.8f, 0.8f);
+
+ switch (joint->GetType())
+ {
+ case e_distanceJoint:
+ m_debugDraw->DrawSegment(p1, p2, color);
+ break;
+
+ case e_pulleyJoint:
+ {
+ b2PulleyJoint* pulley = (b2PulleyJoint*)joint;
+ b2Vec2 s1 = pulley->GetGroundAnchorA();
+ b2Vec2 s2 = pulley->GetGroundAnchorB();
+ m_debugDraw->DrawSegment(s1, p1, color);
+ m_debugDraw->DrawSegment(s2, p2, color);
+ m_debugDraw->DrawSegment(s1, s2, color);
+ }
+ break;
+
+ case e_mouseJoint:
+ // don't draw this
+ break;
+
+ default:
+ m_debugDraw->DrawSegment(x1, p1, color);
+ m_debugDraw->DrawSegment(p1, p2, color);
+ m_debugDraw->DrawSegment(x2, p2, color);
+ }
+}
+
+void b2World::DrawDebugData()
+{
+ if (m_debugDraw == NULL)
+ {
+ return;
+ }
+
+ uint32 flags = m_debugDraw->GetFlags();
+
+ if (flags & b2Draw::e_shapeBit)
+ {
+ for (b2Body* b = m_bodyList; b; b = b->GetNext())
+ {
+ const b2Transform& xf = b->GetTransform();
+ for (b2Fixture* f = b->GetFixtureList(); f; f = f->GetNext())
+ {
+ if (b->IsActive() == false)
+ {
+ DrawShape(f, xf, b2Color(0.5f, 0.5f, 0.3f));
+ }
+ else if (b->GetType() == b2_staticBody)
+ {
+ DrawShape(f, xf, b2Color(0.5f, 0.9f, 0.5f));
+ }
+ else if (b->GetType() == b2_kinematicBody)
+ {
+ DrawShape(f, xf, b2Color(0.5f, 0.5f, 0.9f));
+ }
+ else if (b->IsAwake() == false)
+ {
+ DrawShape(f, xf, b2Color(0.6f, 0.6f, 0.6f));
+ }
+ else
+ {
+ DrawShape(f, xf, b2Color(0.9f, 0.7f, 0.7f));
+ }
+ }
+ }
+ }
+
+ if (flags & b2Draw::e_jointBit)
+ {
+ for (b2Joint* j = m_jointList; j; j = j->GetNext())
+ {
+ DrawJoint(j);
+ }
+ }
+
+ if (flags & b2Draw::e_pairBit)
+ {
+ b2Color color(0.3f, 0.9f, 0.9f);
+ for (b2Contact* c = m_contactManager.m_contactList; c; c = c->GetNext())
+ {
+ //b2Fixture* fixtureA = c->GetFixtureA();
+ //b2Fixture* fixtureB = c->GetFixtureB();
+
+ //b2Vec2 cA = fixtureA->GetAABB().GetCenter();
+ //b2Vec2 cB = fixtureB->GetAABB().GetCenter();
+
+ //m_debugDraw->DrawSegment(cA, cB, color);
+ }
+ }
+
+ if (flags & b2Draw::e_aabbBit)
+ {
+ b2Color color(0.9f, 0.3f, 0.9f);
+ b2BroadPhase* bp = &m_contactManager.m_broadPhase;
+
+ for (b2Body* b = m_bodyList; b; b = b->GetNext())
+ {
+ if (b->IsActive() == false)
+ {
+ continue;
+ }
+
+ for (b2Fixture* f = b->GetFixtureList(); f; f = f->GetNext())
+ {
+ for (int32 i = 0; i < f->m_proxyCount; ++i)
+ {
+ b2FixtureProxy* proxy = f->m_proxies + i;
+ b2AABB aabb = bp->GetFatAABB(proxy->proxyId);
+ b2Vec2 vs[4];
+ vs[0].Set(aabb.lowerBound.x, aabb.lowerBound.y);
+ vs[1].Set(aabb.upperBound.x, aabb.lowerBound.y);
+ vs[2].Set(aabb.upperBound.x, aabb.upperBound.y);
+ vs[3].Set(aabb.lowerBound.x, aabb.upperBound.y);
+
+ m_debugDraw->DrawPolygon(vs, 4, color);
+ }
+ }
+ }
+ }
+
+ if (flags & b2Draw::e_centerOfMassBit)
+ {
+ for (b2Body* b = m_bodyList; b; b = b->GetNext())
+ {
+ b2Transform xf = b->GetTransform();
+ xf.p = b->GetWorldCenter();
+ m_debugDraw->DrawTransform(xf);
+ }
+ }
+}
+
+int32 b2World::GetProxyCount() const
+{
+ return m_contactManager.m_broadPhase.GetProxyCount();
+}
+
+int32 b2World::GetTreeHeight() const
+{
+ return m_contactManager.m_broadPhase.GetTreeHeight();
+}
+
+int32 b2World::GetTreeBalance() const
+{
+ return m_contactManager.m_broadPhase.GetTreeBalance();
+}
+
+float32 b2World::GetTreeQuality() const
+{
+ return m_contactManager.m_broadPhase.GetTreeQuality();
+}
+
+void b2World::Dump()
+{
+ if ((m_flags & e_locked) == e_locked)
+ {
+ return;
+ }
+
+ b2Log("b2Vec2 g(%.15lef, %.15lef);\n", m_gravity.x, m_gravity.y);
+ b2Log("m_world->SetGravity(g);\n");
+
+ b2Log("b2Body** bodies = (b2Body**)b2Alloc(%d * sizeof(b2Body*));\n", m_bodyCount);
+ b2Log("b2Joint** joints = (b2Joint**)b2Alloc(%d * sizeof(b2Joint*));\n", m_jointCount);
+ int32 i = 0;
+ for (b2Body* b = m_bodyList; b; b = b->m_next)
+ {
+ b->m_islandIndex = i;
+ b->Dump();
+ ++i;
+ }
+
+ i = 0;
+ for (b2Joint* j = m_jointList; j; j = j->m_next)
+ {
+ j->m_index = i;
+ ++i;
+ }
+
+ // First pass on joints, skip gear joints.
+ for (b2Joint* j = m_jointList; j; j = j->m_next)
+ {
+ if (j->m_type == e_gearJoint)
+ {
+ continue;
+ }
+
+ b2Log("{\n");
+ j->Dump();
+ b2Log("}\n");
+ }
+
+ // Second pass on joints, only gear joints.
+ for (b2Joint* j = m_jointList; j; j = j->m_next)
+ {
+ if (j->m_type != e_gearJoint)
+ {
+ continue;
+ }
+
+ b2Log("{\n");
+ j->Dump();
+ b2Log("}\n");
+ }
+
+ b2Log("b2Free(joints);\n");
+ b2Log("b2Free(bodies);\n");
+ b2Log("joints = NULL;\n");
+ b2Log("bodies = NULL;\n");
+}
diff --git a/tests/box2d/Box2D/Dynamics/b2World.h b/tests/box2d/Box2D/Dynamics/b2World.h new file mode 100755 index 00000000..eba75727 --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/b2World.h @@ -0,0 +1,349 @@ +/* +* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_WORLD_H +#define B2_WORLD_H + +#include <Box2D/Common/b2Math.h> +#include <Box2D/Common/b2BlockAllocator.h> +#include <Box2D/Common/b2StackAllocator.h> +#include <Box2D/Dynamics/b2ContactManager.h> +#include <Box2D/Dynamics/b2WorldCallbacks.h> +#include <Box2D/Dynamics/b2TimeStep.h> + +struct b2AABB; +struct b2BodyDef; +struct b2Color; +struct b2JointDef; +class b2Body; +class b2Draw; +class b2Fixture; +class b2Joint; + +/// The world class manages all physics entities, dynamic simulation, +/// and asynchronous queries. The world also contains efficient memory +/// management facilities. +class b2World +{ +public: + /// Construct a world object. + /// @param gravity the world gravity vector. + b2World(const b2Vec2& gravity); + + /// Destruct the world. All physics entities are destroyed and all heap memory is released. + ~b2World(); + + /// Register a destruction listener. The listener is owned by you and must + /// remain in scope. + void SetDestructionListener(b2DestructionListener* listener); + + /// Register a contact filter to provide specific control over collision. + /// Otherwise the default filter is used (b2_defaultFilter). The listener is + /// owned by you and must remain in scope. + void SetContactFilter(b2ContactFilter* filter); + + /// Register a contact event listener. The listener is owned by you and must + /// remain in scope. + void SetContactListener(b2ContactListener* listener); + + /// Register a routine for debug drawing. The debug draw functions are called + /// inside with b2World::DrawDebugData method. The debug draw object is owned + /// by you and must remain in scope. + void SetDebugDraw(b2Draw* debugDraw); + + /// Create a rigid body given a definition. No reference to the definition + /// is retained. + /// @warning This function is locked during callbacks. + b2Body* CreateBody(const b2BodyDef* def); + + /// Destroy a rigid body given a definition. No reference to the definition + /// is retained. This function is locked during callbacks. + /// @warning This automatically deletes all associated shapes and joints. + /// @warning This function is locked during callbacks. + void DestroyBody(b2Body* body); + + /// Create a joint to constrain bodies together. No reference to the definition + /// is retained. This may cause the connected bodies to cease colliding. + /// @warning This function is locked during callbacks. + b2Joint* CreateJoint(const b2JointDef* def); + + /// Destroy a joint. This may cause the connected bodies to begin colliding. + /// @warning This function is locked during callbacks. + void DestroyJoint(b2Joint* joint); + + /// Take a time step. This performs collision detection, integration, + /// and constraint solution. + /// @param timeStep the amount of time to simulate, this should not vary. + /// @param velocityIterations for the velocity constraint solver. + /// @param positionIterations for the position constraint solver. + void Step( float32 timeStep, + int32 velocityIterations, + int32 positionIterations); + + /// Manually clear the force buffer on all bodies. By default, forces are cleared automatically + /// after each call to Step. The default behavior is modified by calling SetAutoClearForces. + /// The purpose of this function is to support sub-stepping. Sub-stepping is often used to maintain + /// a fixed sized time step under a variable frame-rate. + /// When you perform sub-stepping you will disable auto clearing of forces and instead call + /// ClearForces after all sub-steps are complete in one pass of your game loop. + /// @see SetAutoClearForces + void ClearForces(); + + /// Call this to draw shapes and other debug draw data. + void DrawDebugData(); + + /// Query the world for all fixtures that potentially overlap the + /// provided AABB. + /// @param callback a user implemented callback class. + /// @param aabb the query box. + void QueryAABB(b2QueryCallback* callback, const b2AABB& aabb) const; + + /// Ray-cast the world for all fixtures in the path of the ray. Your callback + /// controls whether you get the closest point, any point, or n-points. + /// The ray-cast ignores shapes that contain the starting point. + /// @param callback a user implemented callback class. + /// @param point1 the ray starting point + /// @param point2 the ray ending point + void RayCast(b2RayCastCallback* callback, const b2Vec2& point1, const b2Vec2& point2) const; + + /// Get the world body list. With the returned body, use b2Body::GetNext to get + /// the next body in the world list. A NULL body indicates the end of the list. + /// @return the head of the world body list. + b2Body* GetBodyList(); + const b2Body* GetBodyList() const; + + /// Get the world joint list. With the returned joint, use b2Joint::GetNext to get + /// the next joint in the world list. A NULL joint indicates the end of the list. + /// @return the head of the world joint list. + b2Joint* GetJointList(); + const b2Joint* GetJointList() const; + + /// Get the world contact list. With the returned contact, use b2Contact::GetNext to get + /// the next contact in the world list. A NULL contact indicates the end of the list. + /// @return the head of the world contact list. + /// @warning contacts are created and destroyed in the middle of a time step. + /// Use b2ContactListener to avoid missing contacts. + b2Contact* GetContactList(); + const b2Contact* GetContactList() const; + + /// Enable/disable sleep. + void SetAllowSleeping(bool flag); + bool GetAllowSleeping() const { return m_allowSleep; } + + /// Enable/disable warm starting. For testing. + void SetWarmStarting(bool flag) { m_warmStarting = flag; } + bool GetWarmStarting() const { return m_warmStarting; } + + /// Enable/disable continuous physics. For testing. + void SetContinuousPhysics(bool flag) { m_continuousPhysics = flag; } + bool GetContinuousPhysics() const { return m_continuousPhysics; } + + /// Enable/disable single stepped continuous physics. For testing. + void SetSubStepping(bool flag) { m_subStepping = flag; } + bool GetSubStepping() const { return m_subStepping; } + + /// Get the number of broad-phase proxies. + int32 GetProxyCount() const; + + /// Get the number of bodies. + int32 GetBodyCount() const; + + /// Get the number of joints. + int32 GetJointCount() const; + + /// Get the number of contacts (each may have 0 or more contact points). + int32 GetContactCount() const; + + /// Get the height of the dynamic tree. + int32 GetTreeHeight() const; + + /// Get the balance of the dynamic tree. + int32 GetTreeBalance() const; + + /// Get the quality metric of the dynamic tree. The smaller the better. + /// The minimum is 1. + float32 GetTreeQuality() const; + + /// Change the global gravity vector. + void SetGravity(const b2Vec2& gravity); + + /// Get the global gravity vector. + b2Vec2 GetGravity() const; + + /// Is the world locked (in the middle of a time step). + bool IsLocked() const; + + /// Set flag to control automatic clearing of forces after each time step. + void SetAutoClearForces(bool flag); + + /// Get the flag that controls automatic clearing of forces after each time step. + bool GetAutoClearForces() const; + + /// Get the contact manager for testing. + const b2ContactManager& GetContactManager() const; + + /// Get the current profile. + const b2Profile& GetProfile() const; + + /// Dump the world into the log file. + /// @warning this should be called outside of a time step. + void Dump(); + +private: + + // m_flags + enum + { + e_newFixture = 0x0001, + e_locked = 0x0002, + e_clearForces = 0x0004 + }; + + friend class b2Body; + friend class b2Fixture; + friend class b2ContactManager; + friend class b2Controller; + + void Solve(const b2TimeStep& step); + void SolveTOI(const b2TimeStep& step); + + void DrawJoint(b2Joint* joint); + void DrawShape(b2Fixture* shape, const b2Transform& xf, const b2Color& color); + + b2BlockAllocator m_blockAllocator; + b2StackAllocator m_stackAllocator; + + int32 m_flags; + + b2ContactManager m_contactManager; + + b2Body* m_bodyList; + b2Joint* m_jointList; + + int32 m_bodyCount; + int32 m_jointCount; + + b2Vec2 m_gravity; + bool m_allowSleep; + + b2DestructionListener* m_destructionListener; + b2Draw* m_debugDraw; + + // This is used to compute the time step ratio to + // support a variable time step. + float32 m_inv_dt0; + + // These are for debugging the solver. + bool m_warmStarting; + bool m_continuousPhysics; + bool m_subStepping; + + bool m_stepComplete; + + b2Profile m_profile; +}; + +inline b2Body* b2World::GetBodyList() +{ + return m_bodyList; +} + +inline const b2Body* b2World::GetBodyList() const +{ + return m_bodyList; +} + +inline b2Joint* b2World::GetJointList() +{ + return m_jointList; +} + +inline const b2Joint* b2World::GetJointList() const +{ + return m_jointList; +} + +inline b2Contact* b2World::GetContactList() +{ + return m_contactManager.m_contactList; +} + +inline const b2Contact* b2World::GetContactList() const +{ + return m_contactManager.m_contactList; +} + +inline int32 b2World::GetBodyCount() const +{ + return m_bodyCount; +} + +inline int32 b2World::GetJointCount() const +{ + return m_jointCount; +} + +inline int32 b2World::GetContactCount() const +{ + return m_contactManager.m_contactCount; +} + +inline void b2World::SetGravity(const b2Vec2& gravity) +{ + m_gravity = gravity; +} + +inline b2Vec2 b2World::GetGravity() const +{ + return m_gravity; +} + +inline bool b2World::IsLocked() const +{ + return (m_flags & e_locked) == e_locked; +} + +inline void b2World::SetAutoClearForces(bool flag) +{ + if (flag) + { + m_flags |= e_clearForces; + } + else + { + m_flags &= ~e_clearForces; + } +} + +/// Get the flag that controls automatic clearing of forces after each time step. +inline bool b2World::GetAutoClearForces() const +{ + return (m_flags & e_clearForces) == e_clearForces; +} + +inline const b2ContactManager& b2World::GetContactManager() const +{ + return m_contactManager; +} + +inline const b2Profile& b2World::GetProfile() const +{ + return m_profile; +} + +#endif diff --git a/tests/box2d/Box2D/Dynamics/b2WorldCallbacks.cpp b/tests/box2d/Box2D/Dynamics/b2WorldCallbacks.cpp new file mode 100755 index 00000000..82b28cc0 --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/b2WorldCallbacks.cpp @@ -0,0 +1,36 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Dynamics/b2WorldCallbacks.h>
+#include <Box2D/Dynamics/b2Fixture.h>
+
+// Return true if contact calculations should be performed between these two shapes.
+// If you implement your own collision filter you may want to build from this implementation.
+bool b2ContactFilter::ShouldCollide(b2Fixture* fixtureA, b2Fixture* fixtureB)
+{
+ const b2Filter& filterA = fixtureA->GetFilterData();
+ const b2Filter& filterB = fixtureB->GetFilterData();
+
+ if (filterA.groupIndex == filterB.groupIndex && filterA.groupIndex != 0)
+ {
+ return filterA.groupIndex > 0;
+ }
+
+ bool collide = (filterA.maskBits & filterB.categoryBits) != 0 && (filterA.categoryBits & filterB.maskBits) != 0;
+ return collide;
+}
diff --git a/tests/box2d/Box2D/Dynamics/b2WorldCallbacks.h b/tests/box2d/Box2D/Dynamics/b2WorldCallbacks.h new file mode 100755 index 00000000..a64c1abe --- /dev/null +++ b/tests/box2d/Box2D/Dynamics/b2WorldCallbacks.h @@ -0,0 +1,163 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_WORLD_CALLBACKS_H
+#define B2_WORLD_CALLBACKS_H
+
+#include <Box2D/Common/b2Settings.h>
+
+struct b2Vec2;
+struct b2Transform;
+class b2Fixture;
+class b2Body;
+class b2Joint;
+class b2Contact;
+struct b2ContactResult;
+struct b2Manifold;
+
+/// Joints and fixtures are destroyed when their associated
+/// body is destroyed. Implement this listener so that you
+/// may nullify references to these joints and shapes.
+// emscripten - b2DestructionListener: add constructor and make virtual functions non-pure
+class b2DestructionListener
+{
+public:
+ b2DestructionListener() {}
+ virtual ~b2DestructionListener() {}
+
+ /// Called when any joint is about to be destroyed due
+ /// to the destruction of one of its attached bodies.
+ virtual void SayGoodbye(b2Joint* joint) {}
+
+ /// Called when any fixture is about to be destroyed due
+ /// to the destruction of its parent body.
+ virtual void SayGoodbye(b2Fixture* fixture) {}
+};
+
+/// Implement this class to provide collision filtering. In other words, you can implement
+/// this class if you want finer control over contact creation.
+class b2ContactFilter
+{
+public:
+ virtual ~b2ContactFilter() {}
+
+ /// Return true if contact calculations should be performed between these two shapes.
+ /// @warning for performance reasons this is only called when the AABBs begin to overlap.
+ virtual bool ShouldCollide(b2Fixture* fixtureA, b2Fixture* fixtureB);
+};
+
+/// Contact impulses for reporting. Impulses are used instead of forces because
+/// sub-step forces may approach infinity for rigid body collisions. These
+/// match up one-to-one with the contact points in b2Manifold.
+struct b2ContactImpulse
+{
+ float32 normalImpulses[b2_maxManifoldPoints];
+ float32 tangentImpulses[b2_maxManifoldPoints];
+ int32 count;
+};
+
+/// Implement this class to get contact information. You can use these results for
+/// things like sounds and game logic. You can also get contact results by
+/// traversing the contact lists after the time step. However, you might miss
+/// some contacts because continuous physics leads to sub-stepping.
+/// Additionally you may receive multiple callbacks for the same contact in a
+/// single time step.
+/// You should strive to make your callbacks efficient because there may be
+/// many callbacks per time step.
+/// @warning You cannot create/destroy Box2D entities inside these callbacks.
+// emscripten - b2ContactListener: add constructor and make virtual functions non-pure
+class b2ContactListener
+{
+public:
+ b2ContactListener() {}
+ virtual ~b2ContactListener() {}
+
+ /// Called when two fixtures begin to touch.
+ virtual void BeginContact(b2Contact* contact) { B2_NOT_USED(contact); }
+
+ /// Called when two fixtures cease to touch.
+ virtual void EndContact(b2Contact* contact) { B2_NOT_USED(contact); }
+
+ /// This is called after a contact is updated. This allows you to inspect a
+ /// contact before it goes to the solver. If you are careful, you can modify the
+ /// contact manifold (e.g. disable contact).
+ /// A copy of the old manifold is provided so that you can detect changes.
+ /// Note: this is called only for awake bodies.
+ /// Note: this is called even when the number of contact points is zero.
+ /// Note: this is not called for sensors.
+ /// Note: if you set the number of contact points to zero, you will not
+ /// get an EndContact callback. However, you may get a BeginContact callback
+ /// the next step.
+ virtual void PreSolve(b2Contact* contact, const b2Manifold* oldManifold)
+ {
+ B2_NOT_USED(contact);
+ B2_NOT_USED(oldManifold);
+ }
+
+ /// This lets you inspect a contact after the solver is finished. This is useful
+ /// for inspecting impulses.
+ /// Note: the contact manifold does not include time of impact impulses, which can be
+ /// arbitrarily large if the sub-step is small. Hence the impulse is provided explicitly
+ /// in a separate data structure.
+ /// Note: this is only called for contacts that are touching, solid, and awake.
+ virtual void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse)
+ {
+ B2_NOT_USED(contact);
+ B2_NOT_USED(impulse);
+ }
+};
+
+/// Callback class for AABB queries.
+/// See b2World::Query
+// emscripten - b2QueryCallback: add constructor and make virtual functions non-pure
+class b2QueryCallback
+{
+public:
+ b2QueryCallback() {}
+ virtual ~b2QueryCallback() {}
+
+ /// Called for each fixture found in the query AABB.
+ /// @return false to terminate the query.
+ virtual bool ReportFixture(b2Fixture* fixture) { return false; }
+};
+
+/// Callback class for ray casts.
+/// See b2World::RayCast
+// emscripten - b2RayCastCallback: add constructor and make virtual functions non-pure
+class b2RayCastCallback
+{
+public:
+ b2RayCastCallback() {}
+ virtual ~b2RayCastCallback() {}
+
+ /// Called for each fixture found in the query. You control how the ray cast
+ /// proceeds by returning a float:
+ /// return -1: ignore this fixture and continue
+ /// return 0: terminate the ray cast
+ /// return fraction: clip the ray to this point
+ /// return 1: don't clip the ray and continue
+ /// @param fixture the fixture hit by the ray
+ /// @param point the point of initial intersection
+ /// @param normal the normal vector at the point of intersection
+ /// @return -1 to filter, 0 to terminate, fraction to clip the ray for
+ /// closest hit, 1 to continue
+ virtual float32 ReportFixture( b2Fixture* fixture, const b2Vec2& point,
+ const b2Vec2& normal, float32 fraction) { return 0; }
+};
+
+#endif
diff --git a/tests/box2d/Box2D/Rope/b2Rope.cpp b/tests/box2d/Box2D/Rope/b2Rope.cpp new file mode 100755 index 00000000..97578b26 --- /dev/null +++ b/tests/box2d/Box2D/Rope/b2Rope.cpp @@ -0,0 +1,259 @@ +/*
+* Copyright (c) 2011 Erin Catto http://box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Rope/b2Rope.h>
+#include <Box2D/Common/b2Draw.h>
+
+b2Rope::b2Rope()
+{
+ m_count = 0;
+ m_ps = NULL;
+ m_p0s = NULL;
+ m_vs = NULL;
+ m_ims = NULL;
+ m_Ls = NULL;
+ m_as = NULL;
+ m_gravity.SetZero();
+ m_k2 = 1.0f;
+ m_k3 = 0.1f;
+}
+
+b2Rope::~b2Rope()
+{
+ b2Free(m_ps);
+ b2Free(m_p0s);
+ b2Free(m_vs);
+ b2Free(m_ims);
+ b2Free(m_Ls);
+ b2Free(m_as);
+}
+
+void b2Rope::Initialize(const b2RopeDef* def)
+{
+ b2Assert(def->count >= 3);
+ m_count = def->count;
+ m_ps = (b2Vec2*)b2Alloc(m_count * sizeof(b2Vec2));
+ m_p0s = (b2Vec2*)b2Alloc(m_count * sizeof(b2Vec2));
+ m_vs = (b2Vec2*)b2Alloc(m_count * sizeof(b2Vec2));
+ m_ims = (float32*)b2Alloc(m_count * sizeof(float32));
+
+ for (int32 i = 0; i < m_count; ++i)
+ {
+ m_ps[i] = def->vertices[i];
+ m_p0s[i] = def->vertices[i];
+ m_vs[i].SetZero();
+
+ float32 m = def->masses[i];
+ if (m > 0.0f)
+ {
+ m_ims[i] = 1.0f / m;
+ }
+ else
+ {
+ m_ims[i] = 0.0f;
+ }
+ }
+
+ int32 count2 = m_count - 1;
+ int32 count3 = m_count - 2;
+ m_Ls = (float32*)b2Alloc(count2 * sizeof(float32));
+ m_as = (float32*)b2Alloc(count3 * sizeof(float32));
+
+ for (int32 i = 0; i < count2; ++i)
+ {
+ b2Vec2 p1 = m_ps[i];
+ b2Vec2 p2 = m_ps[i+1];
+ m_Ls[i] = b2Distance(p1, p2);
+ }
+
+ for (int32 i = 0; i < count3; ++i)
+ {
+ b2Vec2 p1 = m_ps[i];
+ b2Vec2 p2 = m_ps[i + 1];
+ b2Vec2 p3 = m_ps[i + 2];
+
+ b2Vec2 d1 = p2 - p1;
+ b2Vec2 d2 = p3 - p2;
+
+ float32 a = b2Cross(d1, d2);
+ float32 b = b2Dot(d1, d2);
+
+ m_as[i] = b2Atan2(a, b);
+ }
+
+ m_gravity = def->gravity;
+ m_damping = def->damping;
+ m_k2 = def->k2;
+ m_k3 = def->k3;
+}
+
+void b2Rope::Step(float32 h, int32 iterations)
+{
+ if (h == 0.0)
+ {
+ return;
+ }
+
+ float32 d = expf(- h * m_damping);
+
+ for (int32 i = 0; i < m_count; ++i)
+ {
+ m_p0s[i] = m_ps[i];
+ if (m_ims[i] > 0.0f)
+ {
+ m_vs[i] += h * m_gravity;
+ }
+ m_vs[i] *= d;
+ m_ps[i] += h * m_vs[i];
+
+ }
+
+ for (int32 i = 0; i < iterations; ++i)
+ {
+ SolveC2();
+ SolveC3();
+ SolveC2();
+ }
+
+ float32 inv_h = 1.0f / h;
+ for (int32 i = 0; i < m_count; ++i)
+ {
+ m_vs[i] = inv_h * (m_ps[i] - m_p0s[i]);
+ }
+}
+
+void b2Rope::SolveC2()
+{
+ int32 count2 = m_count - 1;
+
+ for (int32 i = 0; i < count2; ++i)
+ {
+ b2Vec2 p1 = m_ps[i];
+ b2Vec2 p2 = m_ps[i + 1];
+
+ b2Vec2 d = p2 - p1;
+ float32 L = d.Normalize();
+
+ float32 im1 = m_ims[i];
+ float32 im2 = m_ims[i + 1];
+
+ if (im1 + im2 == 0.0f)
+ {
+ continue;
+ }
+
+ float32 s1 = im1 / (im1 + im2);
+ float32 s2 = im2 / (im1 + im2);
+
+ p1 -= m_k2 * s1 * (m_Ls[i] - L) * d;
+ p2 += m_k2 * s2 * (m_Ls[i] - L) * d;
+
+ m_ps[i] = p1;
+ m_ps[i + 1] = p2;
+ }
+}
+
+void b2Rope::SetAngle(float32 angle)
+{
+ int32 count3 = m_count - 2;
+ for (int32 i = 0; i < count3; ++i)
+ {
+ m_as[i] = angle;
+ }
+}
+
+void b2Rope::SolveC3()
+{
+ int32 count3 = m_count - 2;
+
+ for (int32 i = 0; i < count3; ++i)
+ {
+ b2Vec2 p1 = m_ps[i];
+ b2Vec2 p2 = m_ps[i + 1];
+ b2Vec2 p3 = m_ps[i + 2];
+
+ float32 m1 = m_ims[i];
+ float32 m2 = m_ims[i + 1];
+ float32 m3 = m_ims[i + 2];
+
+ b2Vec2 d1 = p2 - p1;
+ b2Vec2 d2 = p3 - p2;
+
+ float32 L1sqr = d1.LengthSquared();
+ float32 L2sqr = d2.LengthSquared();
+
+ if (L1sqr * L2sqr == 0.0f)
+ {
+ continue;
+ }
+
+ float32 a = b2Cross(d1, d2);
+ float32 b = b2Dot(d1, d2);
+
+ float32 angle = b2Atan2(a, b);
+
+ b2Vec2 Jd1 = (-1.0f / L1sqr) * d1.Skew();
+ b2Vec2 Jd2 = (1.0f / L2sqr) * d2.Skew();
+
+ b2Vec2 J1 = -Jd1;
+ b2Vec2 J2 = Jd1 - Jd2;
+ b2Vec2 J3 = Jd2;
+
+ float32 mass = m1 * b2Dot(J1, J1) + m2 * b2Dot(J2, J2) + m3 * b2Dot(J3, J3);
+ if (mass == 0.0f)
+ {
+ continue;
+ }
+
+ mass = 1.0f / mass;
+
+ float32 C = angle - m_as[i];
+
+ while (C > b2_pi)
+ {
+ angle -= 2 * b2_pi;
+ C = angle - m_as[i];
+ }
+
+ while (C < -b2_pi)
+ {
+ angle += 2.0f * b2_pi;
+ C = angle - m_as[i];
+ }
+
+ float32 impulse = - m_k3 * mass * C;
+
+ p1 += (m1 * impulse) * J1;
+ p2 += (m2 * impulse) * J2;
+ p3 += (m3 * impulse) * J3;
+
+ m_ps[i] = p1;
+ m_ps[i + 1] = p2;
+ m_ps[i + 2] = p3;
+ }
+}
+
+void b2Rope::Draw(b2Draw* draw) const
+{
+ b2Color c(0.4f, 0.5f, 0.7f);
+
+ for (int32 i = 0; i < m_count - 1; ++i)
+ {
+ draw->DrawSegment(m_ps[i], m_ps[i+1], c);
+ }
+}
diff --git a/tests/box2d/Box2D/Rope/b2Rope.h b/tests/box2d/Box2D/Rope/b2Rope.h new file mode 100755 index 00000000..bc5375dd --- /dev/null +++ b/tests/box2d/Box2D/Rope/b2Rope.h @@ -0,0 +1,115 @@ +/*
+* Copyright (c) 2011 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_ROPE_H
+#define B2_ROPE_H
+
+#include <Box2D/Common/b2Math.h>
+
+class b2Draw;
+
+///
+struct b2RopeDef
+{
+ b2RopeDef()
+ {
+ vertices = NULL;
+ count = 0;
+ masses = NULL;
+ gravity.SetZero();
+ damping = 0.1f;
+ k2 = 0.9f;
+ k3 = 0.1f;
+ }
+
+ ///
+ b2Vec2* vertices;
+
+ ///
+ int32 count;
+
+ ///
+ float32* masses;
+
+ ///
+ b2Vec2 gravity;
+
+ ///
+ float32 damping;
+
+ /// Stretching stiffness
+ float32 k2;
+
+ /// Bending stiffness. Values above 0.5 can make the simulation blow up.
+ float32 k3;
+};
+
+///
+class b2Rope
+{
+public:
+ b2Rope();
+ ~b2Rope();
+
+ ///
+ void Initialize(const b2RopeDef* def);
+
+ ///
+ void Step(float32 timeStep, int32 iterations);
+
+ ///
+ int32 GetVertexCount() const
+ {
+ return m_count;
+ }
+
+ ///
+ const b2Vec2* GetVertices() const
+ {
+ return m_ps;
+ }
+
+ ///
+ void Draw(b2Draw* draw) const;
+
+ ///
+ void SetAngle(float32 angle);
+
+private:
+
+ void SolveC2();
+ void SolveC3();
+
+ int32 m_count;
+ b2Vec2* m_ps;
+ b2Vec2* m_p0s;
+ b2Vec2* m_vs;
+
+ float32* m_ims;
+
+ float32* m_Ls;
+ float32* m_as;
+
+ b2Vec2 m_gravity;
+ float32 m_damping;
+
+ float32 m_k2;
+ float32 m_k3;
+};
+
+#endif
diff --git a/tests/box2d/Build/Readme.txt b/tests/box2d/Build/Readme.txt new file mode 100755 index 00000000..f28e90b3 --- /dev/null +++ b/tests/box2d/Build/Readme.txt @@ -0,0 +1 @@ +You should use CMake to target this directory for build files.
\ No newline at end of file diff --git a/tests/box2d/Build/vs2010/Box2D.sln b/tests/box2d/Build/vs2010/Box2D.sln new file mode 100755 index 00000000..e6fd1a02 --- /dev/null +++ b/tests/box2d/Build/vs2010/Box2D.sln @@ -0,0 +1,74 @@ +
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Box2D", "Box2D.vcxproj", "{98400D17-43A5-1A40-95BE-C53AC78E7694}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FreeGLUT", "FreeGLUT.vcxproj", "{BCA4569B-A486-E443-9EE2-07D4CB3CFBA8}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GLUI", "GLUI.vcxproj", "{6F01DB00-32F0-A842-9B60-3ABA75A2D458}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HelloWorld", "HelloWorld.vcxproj", "{259F29FB-40F1-F04D-940B-BCEA3ED16B75}"
+ ProjectSection(ProjectDependencies) = postProject
+ {98400D17-43A5-1A40-95BE-C53AC78E7694} = {98400D17-43A5-1A40-95BE-C53AC78E7694}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Testbed", "Testbed.vcxproj", "{3FC8974C-9179-4D4E-A5E0-79E3C836548F}"
+ ProjectSection(ProjectDependencies) = postProject
+ {98400D17-43A5-1A40-95BE-C53AC78E7694} = {98400D17-43A5-1A40-95BE-C53AC78E7694}
+ {BCA4569B-A486-E443-9EE2-07D4CB3CFBA8} = {BCA4569B-A486-E443-9EE2-07D4CB3CFBA8}
+ {6F01DB00-32F0-A842-9B60-3ABA75A2D458} = {6F01DB00-32F0-A842-9B60-3ABA75A2D458}
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {98400D17-43A5-1A40-95BE-C53AC78E7694}.Debug|Win32.ActiveCfg = Debug|Win32
+ {98400D17-43A5-1A40-95BE-C53AC78E7694}.Debug|Win32.Build.0 = Debug|Win32
+ {98400D17-43A5-1A40-95BE-C53AC78E7694}.Debug|x64.ActiveCfg = Debug|x64
+ {98400D17-43A5-1A40-95BE-C53AC78E7694}.Debug|x64.Build.0 = Debug|x64
+ {98400D17-43A5-1A40-95BE-C53AC78E7694}.Release|Win32.ActiveCfg = Release|Win32
+ {98400D17-43A5-1A40-95BE-C53AC78E7694}.Release|Win32.Build.0 = Release|Win32
+ {98400D17-43A5-1A40-95BE-C53AC78E7694}.Release|x64.ActiveCfg = Release|x64
+ {98400D17-43A5-1A40-95BE-C53AC78E7694}.Release|x64.Build.0 = Release|x64
+ {BCA4569B-A486-E443-9EE2-07D4CB3CFBA8}.Debug|Win32.ActiveCfg = Debug|Win32
+ {BCA4569B-A486-E443-9EE2-07D4CB3CFBA8}.Debug|Win32.Build.0 = Debug|Win32
+ {BCA4569B-A486-E443-9EE2-07D4CB3CFBA8}.Debug|x64.ActiveCfg = Debug|x64
+ {BCA4569B-A486-E443-9EE2-07D4CB3CFBA8}.Debug|x64.Build.0 = Debug|x64
+ {BCA4569B-A486-E443-9EE2-07D4CB3CFBA8}.Release|Win32.ActiveCfg = Release|Win32
+ {BCA4569B-A486-E443-9EE2-07D4CB3CFBA8}.Release|Win32.Build.0 = Release|Win32
+ {BCA4569B-A486-E443-9EE2-07D4CB3CFBA8}.Release|x64.ActiveCfg = Release|x64
+ {BCA4569B-A486-E443-9EE2-07D4CB3CFBA8}.Release|x64.Build.0 = Release|x64
+ {6F01DB00-32F0-A842-9B60-3ABA75A2D458}.Debug|Win32.ActiveCfg = Debug|Win32
+ {6F01DB00-32F0-A842-9B60-3ABA75A2D458}.Debug|Win32.Build.0 = Debug|Win32
+ {6F01DB00-32F0-A842-9B60-3ABA75A2D458}.Debug|x64.ActiveCfg = Debug|x64
+ {6F01DB00-32F0-A842-9B60-3ABA75A2D458}.Debug|x64.Build.0 = Debug|x64
+ {6F01DB00-32F0-A842-9B60-3ABA75A2D458}.Release|Win32.ActiveCfg = Release|Win32
+ {6F01DB00-32F0-A842-9B60-3ABA75A2D458}.Release|Win32.Build.0 = Release|Win32
+ {6F01DB00-32F0-A842-9B60-3ABA75A2D458}.Release|x64.ActiveCfg = Release|x64
+ {6F01DB00-32F0-A842-9B60-3ABA75A2D458}.Release|x64.Build.0 = Release|x64
+ {259F29FB-40F1-F04D-940B-BCEA3ED16B75}.Debug|Win32.ActiveCfg = Debug|Win32
+ {259F29FB-40F1-F04D-940B-BCEA3ED16B75}.Debug|Win32.Build.0 = Debug|Win32
+ {259F29FB-40F1-F04D-940B-BCEA3ED16B75}.Debug|x64.ActiveCfg = Debug|x64
+ {259F29FB-40F1-F04D-940B-BCEA3ED16B75}.Debug|x64.Build.0 = Debug|x64
+ {259F29FB-40F1-F04D-940B-BCEA3ED16B75}.Release|Win32.ActiveCfg = Release|Win32
+ {259F29FB-40F1-F04D-940B-BCEA3ED16B75}.Release|Win32.Build.0 = Release|Win32
+ {259F29FB-40F1-F04D-940B-BCEA3ED16B75}.Release|x64.ActiveCfg = Release|x64
+ {259F29FB-40F1-F04D-940B-BCEA3ED16B75}.Release|x64.Build.0 = Release|x64
+ {3FC8974C-9179-4D4E-A5E0-79E3C836548F}.Debug|Win32.ActiveCfg = Debug|Win32
+ {3FC8974C-9179-4D4E-A5E0-79E3C836548F}.Debug|Win32.Build.0 = Debug|Win32
+ {3FC8974C-9179-4D4E-A5E0-79E3C836548F}.Debug|x64.ActiveCfg = Debug|x64
+ {3FC8974C-9179-4D4E-A5E0-79E3C836548F}.Debug|x64.Build.0 = Debug|x64
+ {3FC8974C-9179-4D4E-A5E0-79E3C836548F}.Release|Win32.ActiveCfg = Release|Win32
+ {3FC8974C-9179-4D4E-A5E0-79E3C836548F}.Release|Win32.Build.0 = Release|Win32
+ {3FC8974C-9179-4D4E-A5E0-79E3C836548F}.Release|x64.ActiveCfg = Release|x64
+ {3FC8974C-9179-4D4E-A5E0-79E3C836548F}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/tests/box2d/Build/vs2010/Box2D.vcxproj b/tests/box2d/Build/vs2010/Box2D.vcxproj new file mode 100755 index 00000000..9e0460e2 --- /dev/null +++ b/tests/box2d/Build/vs2010/Box2D.vcxproj @@ -0,0 +1,340 @@ +<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{98400D17-43A5-1A40-95BE-C53AC78E7694}</ProjectGuid>
+ <RootNamespace>Box2D</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">bin\Debug\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">obj\x32\Debug\Box2D\</IntDir>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Box2D</TargetName>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">bin\Debug\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">obj\x64\Debug\Box2D\</IntDir>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Box2D</TargetName>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">bin\Release\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">obj\x32\Release\Box2D\</IntDir>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Box2D</TargetName>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">bin\Release\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">obj\x64\Release\Box2D\</IntDir>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Box2D</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <ProgramDataBaseFileName>$(OutDir)Box2D.pdb</ProgramDataBaseFileName>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Lib>
+ <OutputFile>$(OutDir)Box2D.lib</OutputFile>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Lib>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <ProgramDataBaseFileName>$(OutDir)Box2D.pdb</ProgramDataBaseFileName>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Lib>
+ <OutputFile>$(OutDir)Box2D.lib</OutputFile>
+ <TargetMachine>MachineX64</TargetMachine>
+ </Lib>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <AdditionalIncludeDirectories>..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>false</MinimalRebuild>
+ <StringPooling>true</StringPooling>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>
+ </DebugInformationFormat>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Lib>
+ <OutputFile>$(OutDir)Box2D.lib</OutputFile>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Lib>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <AdditionalIncludeDirectories>..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>false</MinimalRebuild>
+ <StringPooling>true</StringPooling>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>
+ </DebugInformationFormat>
+ <ExceptionHandling>false</ExceptionHandling>
+ <FloatingPointModel>Fast</FloatingPointModel>
+ <RuntimeTypeInfo>false</RuntimeTypeInfo>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Lib>
+ <OutputFile>$(OutDir)Box2D.lib</OutputFile>
+ <TargetMachine>MachineX64</TargetMachine>
+ </Lib>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\Box2D\Box2D.h" />
+ <ClInclude Include="..\..\Box2D\Collision\b2BroadPhase.h" />
+ <ClInclude Include="..\..\Box2D\Collision\b2Collision.h" />
+ <ClInclude Include="..\..\Box2D\Collision\b2Distance.h" />
+ <ClInclude Include="..\..\Box2D\Collision\b2DynamicTree.h" />
+ <ClInclude Include="..\..\Box2D\Collision\b2TimeOfImpact.h" />
+ <ClInclude Include="..\..\Box2D\Collision\Shapes\b2ChainShape.h" />
+ <ClInclude Include="..\..\Box2D\Collision\Shapes\b2CircleShape.h" />
+ <ClInclude Include="..\..\Box2D\Collision\Shapes\b2EdgeShape.h" />
+ <ClInclude Include="..\..\Box2D\Collision\Shapes\b2PolygonShape.h" />
+ <ClInclude Include="..\..\Box2D\Collision\Shapes\b2Shape.h" />
+ <ClInclude Include="..\..\Box2D\Common\b2BlockAllocator.h" />
+ <ClInclude Include="..\..\Box2D\Common\b2Draw.h" />
+ <ClInclude Include="..\..\Box2D\Common\b2GrowableStack.h" />
+ <ClInclude Include="..\..\Box2D\Common\b2Math.h" />
+ <ClInclude Include="..\..\Box2D\Common\b2Settings.h" />
+ <ClInclude Include="..\..\Box2D\Common\b2StackAllocator.h" />
+ <ClInclude Include="..\..\Box2D\Common\b2Timer.h" />
+ <ClInclude Include="..\..\Box2D\Dynamics\b2Body.h" />
+ <ClInclude Include="..\..\Box2D\Dynamics\b2ContactManager.h" />
+ <ClInclude Include="..\..\Box2D\Dynamics\b2Fixture.h" />
+ <ClInclude Include="..\..\Box2D\Dynamics\b2Island.h" />
+ <ClInclude Include="..\..\Box2D\Dynamics\b2TimeStep.h" />
+ <ClInclude Include="..\..\Box2D\Dynamics\b2World.h" />
+ <ClInclude Include="..\..\Box2D\Dynamics\b2WorldCallbacks.h" />
+ <ClInclude Include="..\..\Box2D\Dynamics\Contacts\b2ChainAndCircleContact.h" />
+ <ClInclude Include="..\..\Box2D\Dynamics\Contacts\b2ChainAndPolygonContact.h" />
+ <ClInclude Include="..\..\Box2D\Dynamics\Contacts\b2CircleContact.h" />
+ <ClInclude Include="..\..\Box2D\Dynamics\Contacts\b2Contact.h" />
+ <ClInclude Include="..\..\Box2D\Dynamics\Contacts\b2ContactSolver.h" />
+ <ClInclude Include="..\..\Box2D\Dynamics\Contacts\b2EdgeAndCircleContact.h" />
+ <ClInclude Include="..\..\Box2D\Dynamics\Contacts\b2EdgeAndPolygonContact.h" />
+ <ClInclude Include="..\..\Box2D\Dynamics\Contacts\b2PolygonAndCircleContact.h" />
+ <ClInclude Include="..\..\Box2D\Dynamics\Contacts\b2PolygonContact.h" />
+ <ClInclude Include="..\..\Box2D\Dynamics\Joints\b2DistanceJoint.h" />
+ <ClInclude Include="..\..\Box2D\Dynamics\Joints\b2FrictionJoint.h" />
+ <ClInclude Include="..\..\Box2D\Dynamics\Joints\b2GearJoint.h" />
+ <ClInclude Include="..\..\Box2D\Dynamics\Joints\b2Joint.h" />
+ <ClInclude Include="..\..\Box2D\Dynamics\Joints\b2MouseJoint.h" />
+ <ClInclude Include="..\..\Box2D\Dynamics\Joints\b2PrismaticJoint.h" />
+ <ClInclude Include="..\..\Box2D\Dynamics\Joints\b2PulleyJoint.h" />
+ <ClInclude Include="..\..\Box2D\Dynamics\Joints\b2RevoluteJoint.h" />
+ <ClInclude Include="..\..\Box2D\Dynamics\Joints\b2RopeJoint.h" />
+ <ClInclude Include="..\..\Box2D\Dynamics\Joints\b2WeldJoint.h" />
+ <ClInclude Include="..\..\Box2D\Dynamics\Joints\b2WheelJoint.h" />
+ <ClInclude Include="..\..\Box2D\Rope\b2Rope.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\Box2D\Collision\b2BroadPhase.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Collision\b2CollideCircle.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Collision\b2CollideEdge.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Collision\b2CollidePolygon.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Collision\b2Collision.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Collision\b2Distance.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Collision\b2DynamicTree.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Collision\b2TimeOfImpact.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Collision\Shapes\b2ChainShape.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Collision\Shapes\b2CircleShape.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Collision\Shapes\b2EdgeShape.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Collision\Shapes\b2PolygonShape.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Common\b2BlockAllocator.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Common\b2Draw.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Common\b2Math.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Common\b2Settings.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Common\b2StackAllocator.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Common\b2Timer.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\b2Body.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\b2ContactManager.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\b2Fixture.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\b2Island.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\b2World.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\b2WorldCallbacks.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Contacts\b2ChainAndCircleContact.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Contacts\b2ChainAndPolygonContact.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Contacts\b2CircleContact.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Contacts\b2Contact.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Contacts\b2ContactSolver.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Contacts\b2EdgeAndCircleContact.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Contacts\b2EdgeAndPolygonContact.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Contacts\b2PolygonAndCircleContact.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Contacts\b2PolygonContact.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Joints\b2DistanceJoint.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Joints\b2FrictionJoint.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Joints\b2GearJoint.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Joints\b2Joint.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Joints\b2MouseJoint.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Joints\b2PrismaticJoint.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Joints\b2PulleyJoint.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Joints\b2RevoluteJoint.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Joints\b2RopeJoint.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Joints\b2WeldJoint.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Joints\b2WheelJoint.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Rope\b2Rope.cpp">
+ </ClCompile>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
\ No newline at end of file diff --git a/tests/box2d/Build/vs2010/Box2D.vcxproj.filters b/tests/box2d/Build/vs2010/Box2D.vcxproj.filters new file mode 100755 index 00000000..6576c6ba --- /dev/null +++ b/tests/box2d/Build/vs2010/Box2D.vcxproj.filters @@ -0,0 +1,301 @@ +<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Collision">
+ <UniqueIdentifier>{EE06093C-52B3-9A42-A586-8CCC65597D57}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Collision\Shapes">
+ <UniqueIdentifier>{4A368771-7ADC-A143-B42F-58CB8448EA17}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Common">
+ <UniqueIdentifier>{17132958-D902-9D46-A032-A2DD9E3FAED5}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Dynamics">
+ <UniqueIdentifier>{C815CFE9-147A-D443-8BB0-31FC775E62F4}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Dynamics\Contacts">
+ <UniqueIdentifier>{BE9A720A-8AF8-9C4C-A4FE-3F2BACAF8A59}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Dynamics\Joints">
+ <UniqueIdentifier>{CFBD1F37-CEEA-CA41-9715-5C0ACDD84298}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Rope">
+ <UniqueIdentifier>{064F8909-BE63-9844-86F5-4B9354A16847}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\Box2D\Box2D.h" />
+ <ClInclude Include="..\..\Box2D\Collision\b2BroadPhase.h">
+ <Filter>Collision</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Collision\b2Collision.h">
+ <Filter>Collision</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Collision\b2Distance.h">
+ <Filter>Collision</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Collision\b2DynamicTree.h">
+ <Filter>Collision</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Collision\b2TimeOfImpact.h">
+ <Filter>Collision</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Collision\Shapes\b2ChainShape.h">
+ <Filter>Collision\Shapes</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Collision\Shapes\b2CircleShape.h">
+ <Filter>Collision\Shapes</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Collision\Shapes\b2EdgeShape.h">
+ <Filter>Collision\Shapes</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Collision\Shapes\b2PolygonShape.h">
+ <Filter>Collision\Shapes</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Collision\Shapes\b2Shape.h">
+ <Filter>Collision\Shapes</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Common\b2BlockAllocator.h">
+ <Filter>Common</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Common\b2Draw.h">
+ <Filter>Common</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Common\b2GrowableStack.h">
+ <Filter>Common</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Common\b2Math.h">
+ <Filter>Common</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Common\b2Settings.h">
+ <Filter>Common</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Common\b2StackAllocator.h">
+ <Filter>Common</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Common\b2Timer.h">
+ <Filter>Common</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Dynamics\b2Body.h">
+ <Filter>Dynamics</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Dynamics\b2ContactManager.h">
+ <Filter>Dynamics</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Dynamics\b2Fixture.h">
+ <Filter>Dynamics</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Dynamics\b2Island.h">
+ <Filter>Dynamics</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Dynamics\b2TimeStep.h">
+ <Filter>Dynamics</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Dynamics\b2World.h">
+ <Filter>Dynamics</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Dynamics\b2WorldCallbacks.h">
+ <Filter>Dynamics</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Dynamics\Contacts\b2ChainAndCircleContact.h">
+ <Filter>Dynamics\Contacts</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Dynamics\Contacts\b2ChainAndPolygonContact.h">
+ <Filter>Dynamics\Contacts</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Dynamics\Contacts\b2CircleContact.h">
+ <Filter>Dynamics\Contacts</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Dynamics\Contacts\b2Contact.h">
+ <Filter>Dynamics\Contacts</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Dynamics\Contacts\b2ContactSolver.h">
+ <Filter>Dynamics\Contacts</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Dynamics\Contacts\b2EdgeAndCircleContact.h">
+ <Filter>Dynamics\Contacts</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Dynamics\Contacts\b2EdgeAndPolygonContact.h">
+ <Filter>Dynamics\Contacts</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Dynamics\Contacts\b2PolygonAndCircleContact.h">
+ <Filter>Dynamics\Contacts</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Dynamics\Contacts\b2PolygonContact.h">
+ <Filter>Dynamics\Contacts</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Dynamics\Joints\b2DistanceJoint.h">
+ <Filter>Dynamics\Joints</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Dynamics\Joints\b2FrictionJoint.h">
+ <Filter>Dynamics\Joints</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Dynamics\Joints\b2GearJoint.h">
+ <Filter>Dynamics\Joints</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Dynamics\Joints\b2Joint.h">
+ <Filter>Dynamics\Joints</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Dynamics\Joints\b2MouseJoint.h">
+ <Filter>Dynamics\Joints</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Dynamics\Joints\b2PrismaticJoint.h">
+ <Filter>Dynamics\Joints</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Dynamics\Joints\b2PulleyJoint.h">
+ <Filter>Dynamics\Joints</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Dynamics\Joints\b2RevoluteJoint.h">
+ <Filter>Dynamics\Joints</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Dynamics\Joints\b2RopeJoint.h">
+ <Filter>Dynamics\Joints</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Dynamics\Joints\b2WeldJoint.h">
+ <Filter>Dynamics\Joints</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Dynamics\Joints\b2WheelJoint.h">
+ <Filter>Dynamics\Joints</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Box2D\Rope\b2Rope.h">
+ <Filter>Rope</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\Box2D\Collision\b2BroadPhase.cpp">
+ <Filter>Collision</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Collision\b2CollideCircle.cpp">
+ <Filter>Collision</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Collision\b2CollideEdge.cpp">
+ <Filter>Collision</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Collision\b2CollidePolygon.cpp">
+ <Filter>Collision</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Collision\b2Collision.cpp">
+ <Filter>Collision</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Collision\b2Distance.cpp">
+ <Filter>Collision</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Collision\b2DynamicTree.cpp">
+ <Filter>Collision</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Collision\b2TimeOfImpact.cpp">
+ <Filter>Collision</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Collision\Shapes\b2ChainShape.cpp">
+ <Filter>Collision\Shapes</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Collision\Shapes\b2CircleShape.cpp">
+ <Filter>Collision\Shapes</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Collision\Shapes\b2EdgeShape.cpp">
+ <Filter>Collision\Shapes</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Collision\Shapes\b2PolygonShape.cpp">
+ <Filter>Collision\Shapes</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Common\b2BlockAllocator.cpp">
+ <Filter>Common</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Common\b2Draw.cpp">
+ <Filter>Common</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Common\b2Math.cpp">
+ <Filter>Common</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Common\b2Settings.cpp">
+ <Filter>Common</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Common\b2StackAllocator.cpp">
+ <Filter>Common</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Common\b2Timer.cpp">
+ <Filter>Common</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\b2Body.cpp">
+ <Filter>Dynamics</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\b2ContactManager.cpp">
+ <Filter>Dynamics</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\b2Fixture.cpp">
+ <Filter>Dynamics</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\b2Island.cpp">
+ <Filter>Dynamics</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\b2World.cpp">
+ <Filter>Dynamics</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\b2WorldCallbacks.cpp">
+ <Filter>Dynamics</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Contacts\b2ChainAndCircleContact.cpp">
+ <Filter>Dynamics\Contacts</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Contacts\b2ChainAndPolygonContact.cpp">
+ <Filter>Dynamics\Contacts</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Contacts\b2CircleContact.cpp">
+ <Filter>Dynamics\Contacts</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Contacts\b2Contact.cpp">
+ <Filter>Dynamics\Contacts</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Contacts\b2ContactSolver.cpp">
+ <Filter>Dynamics\Contacts</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Contacts\b2EdgeAndCircleContact.cpp">
+ <Filter>Dynamics\Contacts</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Contacts\b2EdgeAndPolygonContact.cpp">
+ <Filter>Dynamics\Contacts</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Contacts\b2PolygonAndCircleContact.cpp">
+ <Filter>Dynamics\Contacts</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Contacts\b2PolygonContact.cpp">
+ <Filter>Dynamics\Contacts</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Joints\b2DistanceJoint.cpp">
+ <Filter>Dynamics\Joints</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Joints\b2FrictionJoint.cpp">
+ <Filter>Dynamics\Joints</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Joints\b2GearJoint.cpp">
+ <Filter>Dynamics\Joints</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Joints\b2Joint.cpp">
+ <Filter>Dynamics\Joints</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Joints\b2MouseJoint.cpp">
+ <Filter>Dynamics\Joints</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Joints\b2PrismaticJoint.cpp">
+ <Filter>Dynamics\Joints</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Joints\b2PulleyJoint.cpp">
+ <Filter>Dynamics\Joints</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Joints\b2RevoluteJoint.cpp">
+ <Filter>Dynamics\Joints</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Joints\b2RopeJoint.cpp">
+ <Filter>Dynamics\Joints</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Joints\b2WeldJoint.cpp">
+ <Filter>Dynamics\Joints</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Dynamics\Joints\b2WheelJoint.cpp">
+ <Filter>Dynamics\Joints</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Box2D\Rope\b2Rope.cpp">
+ <Filter>Rope</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project>
diff --git a/tests/box2d/Build/vs2010/FreeGLUT.vcxproj b/tests/box2d/Build/vs2010/FreeGLUT.vcxproj new file mode 100755 index 00000000..68214339 --- /dev/null +++ b/tests/box2d/Build/vs2010/FreeGLUT.vcxproj @@ -0,0 +1,250 @@ +<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{BCA4569B-A486-E443-9EE2-07D4CB3CFBA8}</ProjectGuid>
+ <RootNamespace>FreeGLUT</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">bin\Debug\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">obj\x32\Debug\FreeGLUT\</IntDir>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">FreeGLUT</TargetName>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">bin\Debug\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">obj\x64\Debug\FreeGLUT\</IntDir>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">FreeGLUT</TargetName>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">bin\Release\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">obj\x32\Release\FreeGLUT\</IntDir>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">FreeGLUT</TargetName>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">bin\Release\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">obj\x64\Release\FreeGLUT\</IntDir>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">FreeGLUT</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <ProgramDataBaseFileName>$(OutDir)FreeGLUT.pdb</ProgramDataBaseFileName>
+ <CompileAs>CompileAsC</CompileAs>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Lib>
+ <OutputFile>$(OutDir)FreeGLUT.lib</OutputFile>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Lib>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <ProgramDataBaseFileName>$(OutDir)FreeGLUT.pdb</ProgramDataBaseFileName>
+ <CompileAs>CompileAsC</CompileAs>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Lib>
+ <OutputFile>$(OutDir)FreeGLUT.lib</OutputFile>
+ <TargetMachine>MachineX64</TargetMachine>
+ </Lib>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>false</MinimalRebuild>
+ <StringPooling>true</StringPooling>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>
+ </DebugInformationFormat>
+ <CompileAs>CompileAsC</CompileAs>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Lib>
+ <OutputFile>$(OutDir)FreeGLUT.lib</OutputFile>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Lib>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>false</MinimalRebuild>
+ <StringPooling>true</StringPooling>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>
+ </DebugInformationFormat>
+ <CompileAs>CompileAsC</CompileAs>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Lib>
+ <OutputFile>$(OutDir)FreeGLUT.lib</OutputFile>
+ <TargetMachine>MachineX64</TargetMachine>
+ </Lib>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\freeglut\freeglut.h" />
+ <ClInclude Include="..\..\freeglut\freeglut_ext.h" />
+ <ClInclude Include="..\..\freeglut\freeglut_internal.h" />
+ <ClInclude Include="..\..\freeglut\freeglut_std.h" />
+ <ClInclude Include="..\..\freeglut\freeglut_teapot_data.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\freeglut\freeglut_callbacks.c">
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_cursor.c">
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_display.c">
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_ext.c">
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_font.c">
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_font_data.c">
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_gamemode.c">
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_geometry.c">
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_glutfont_definitions.c">
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_init.c">
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_input_devices.c">
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_joystick.c">
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_main.c">
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_menu.c">
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_misc.c">
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_overlay.c">
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_spaceball.c">
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_state.c">
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_stroke_mono_roman.c">
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_stroke_roman.c">
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_structure.c">
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_teapot.c">
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_videoresize.c">
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_window.c">
+ </ClCompile>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
\ No newline at end of file diff --git a/tests/box2d/Build/vs2010/FreeGLUT.vcxproj.filters b/tests/box2d/Build/vs2010/FreeGLUT.vcxproj.filters new file mode 100755 index 00000000..d4cd78c4 --- /dev/null +++ b/tests/box2d/Build/vs2010/FreeGLUT.vcxproj.filters @@ -0,0 +1,102 @@ +<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Headers">
+ <UniqueIdentifier>{CF400ACD-5E78-A54C-B6AC-3BF8A203852D}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Sources">
+ <UniqueIdentifier>{28BB812D-7BF4-C741-8D3C-0C93BDD09371}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\freeglut\freeglut.h">
+ <Filter>Headers</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\freeglut\freeglut_ext.h">
+ <Filter>Headers</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\freeglut\freeglut_internal.h">
+ <Filter>Headers</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\freeglut\freeglut_std.h">
+ <Filter>Headers</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\freeglut\freeglut_teapot_data.h">
+ <Filter>Headers</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\freeglut\freeglut_callbacks.c">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_cursor.c">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_display.c">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_ext.c">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_font.c">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_font_data.c">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_gamemode.c">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_geometry.c">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_glutfont_definitions.c">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_init.c">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_input_devices.c">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_joystick.c">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_main.c">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_menu.c">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_misc.c">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_overlay.c">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_spaceball.c">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_state.c">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_stroke_mono_roman.c">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_stroke_roman.c">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_structure.c">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_teapot.c">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_videoresize.c">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\freeglut\freeglut_window.c">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project>
diff --git a/tests/box2d/Build/vs2010/GLUI.vcxproj b/tests/box2d/Build/vs2010/GLUI.vcxproj new file mode 100755 index 00000000..a526d3a1 --- /dev/null +++ b/tests/box2d/Build/vs2010/GLUI.vcxproj @@ -0,0 +1,275 @@ +<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{6F01DB00-32F0-A842-9B60-3ABA75A2D458}</ProjectGuid>
+ <RootNamespace>GLUI</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">bin\Debug\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">obj\x32\Debug\GLUI\</IntDir>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">GLUI</TargetName>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">bin\Debug\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">obj\x64\Debug\GLUI\</IntDir>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">GLUI</TargetName>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">bin\Release\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">obj\x32\Release\GLUI\</IntDir>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">GLUI</TargetName>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">bin\Release\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">obj\x64\Release\GLUI\</IntDir>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">GLUI</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <AdditionalOptions>/W1 %(AdditionalOptions)</AdditionalOptions>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <ProgramDataBaseFileName>$(OutDir)GLUI.pdb</ProgramDataBaseFileName>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Lib>
+ <OutputFile>$(OutDir)GLUI.lib</OutputFile>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Lib>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <AdditionalOptions>/W1 %(AdditionalOptions)</AdditionalOptions>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <ProgramDataBaseFileName>$(OutDir)GLUI.pdb</ProgramDataBaseFileName>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Lib>
+ <OutputFile>$(OutDir)GLUI.lib</OutputFile>
+ <TargetMachine>MachineX64</TargetMachine>
+ </Lib>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <AdditionalOptions>/W1 %(AdditionalOptions)</AdditionalOptions>
+ <Optimization>Full</Optimization>
+ <AdditionalIncludeDirectories>..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>false</MinimalRebuild>
+ <StringPooling>true</StringPooling>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>
+ </DebugInformationFormat>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Lib>
+ <OutputFile>$(OutDir)GLUI.lib</OutputFile>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Lib>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <AdditionalOptions>/W1 %(AdditionalOptions)</AdditionalOptions>
+ <Optimization>Full</Optimization>
+ <AdditionalIncludeDirectories>..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>false</MinimalRebuild>
+ <StringPooling>true</StringPooling>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>
+ </DebugInformationFormat>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Lib>
+ <OutputFile>$(OutDir)GLUI.lib</OutputFile>
+ <TargetMachine>MachineX64</TargetMachine>
+ </Lib>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\glui\algebra3.h" />
+ <ClInclude Include="..\..\glui\arcball.h" />
+ <ClInclude Include="..\..\glui\glui.h" />
+ <ClInclude Include="..\..\glui\glui_internal.h" />
+ <ClInclude Include="..\..\glui\glui_internal_control.h" />
+ <ClInclude Include="..\..\glui\quaternion.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\glui\algebra3.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\glui\arcball.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_add_controls.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_bitmaps.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_bitmap_img_data.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_button.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_checkbox.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_column.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_commandline.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_control.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_edittext.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_filebrowser.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_list.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_listbox.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_mouse_iaction.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_node.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_panel.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_radio.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_rollout.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_rotation.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_scrollbar.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_separator.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_spinner.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_statictext.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_string.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_textbox.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_translation.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_tree.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_treepanel.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_window.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\glui\quaternion.cpp">
+ </ClCompile>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
\ No newline at end of file diff --git a/tests/box2d/Build/vs2010/GLUI.vcxproj.filters b/tests/box2d/Build/vs2010/GLUI.vcxproj.filters new file mode 100755 index 00000000..587ea867 --- /dev/null +++ b/tests/box2d/Build/vs2010/GLUI.vcxproj.filters @@ -0,0 +1,129 @@ +<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Headers">
+ <UniqueIdentifier>{7EE70127-33D6-EE45-A170-6D9CD2ECBA05}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Sources">
+ <UniqueIdentifier>{392FBE2C-081A-8743-83E6-1344CBD265D1}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\glui\algebra3.h">
+ <Filter>Headers</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\glui\arcball.h">
+ <Filter>Headers</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\glui\glui.h">
+ <Filter>Headers</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\glui\glui_internal.h">
+ <Filter>Headers</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\glui\glui_internal_control.h">
+ <Filter>Headers</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\glui\quaternion.h">
+ <Filter>Headers</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\glui\algebra3.cpp">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\glui\arcball.cpp">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui.cpp">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_add_controls.cpp">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_bitmaps.cpp">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_bitmap_img_data.cpp">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_button.cpp">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_checkbox.cpp">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_column.cpp">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_commandline.cpp">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_control.cpp">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_edittext.cpp">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_filebrowser.cpp">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_list.cpp">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_listbox.cpp">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_mouse_iaction.cpp">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_node.cpp">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_panel.cpp">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_radio.cpp">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_rollout.cpp">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_rotation.cpp">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_scrollbar.cpp">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_separator.cpp">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_spinner.cpp">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_statictext.cpp">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_string.cpp">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_textbox.cpp">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_translation.cpp">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_tree.cpp">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_treepanel.cpp">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\glui\glui_window.cpp">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\glui\quaternion.cpp">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project>
diff --git a/tests/box2d/Build/vs2010/HelloWorld.vcxproj b/tests/box2d/Build/vs2010/HelloWorld.vcxproj new file mode 100755 index 00000000..8ebf4c62 --- /dev/null +++ b/tests/box2d/Build/vs2010/HelloWorld.vcxproj @@ -0,0 +1,209 @@ +<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{259F29FB-40F1-F04D-940B-BCEA3ED16B75}</ProjectGuid>
+ <RootNamespace>HelloWorld</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">bin\Debug\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">obj\x32\Debug\HelloWorld\</IntDir>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">HelloWorld</TargetName>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">bin\Debug\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">obj\x64\Debug\HelloWorld\</IntDir>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">HelloWorld</TargetName>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">bin\Release\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">obj\x32\Release\HelloWorld\</IntDir>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">HelloWorld</TargetName>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">bin\Release\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">obj\x64\Release\HelloWorld\</IntDir>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">HelloWorld</TargetName>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <ProgramDataBaseFileName>$(OutDir)HelloWorld.pdb</ProgramDataBaseFileName>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>bin\Debug\Box2D.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)HelloWorld.exe</OutputFile>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EntryPointSymbol>mainCRTStartup</EntryPointSymbol>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <ProgramDataBaseFileName>$(OutDir)HelloWorld.pdb</ProgramDataBaseFileName>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>bin\Debug\Box2D.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)HelloWorld.exe</OutputFile>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EntryPointSymbol>mainCRTStartup</EntryPointSymbol>
+ <TargetMachine>MachineX64</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <AdditionalIncludeDirectories>..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>false</MinimalRebuild>
+ <StringPooling>true</StringPooling>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>
+ </DebugInformationFormat>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>bin\Release\Box2D.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)HelloWorld.exe</OutputFile>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <EntryPointSymbol>mainCRTStartup</EntryPointSymbol>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <AdditionalIncludeDirectories>..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>false</MinimalRebuild>
+ <StringPooling>true</StringPooling>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>
+ </DebugInformationFormat>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>bin\Release\Box2D.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)HelloWorld.exe</OutputFile>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <EntryPointSymbol>mainCRTStartup</EntryPointSymbol>
+ <TargetMachine>MachineX64</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\HelloWorld\Helloworld.cpp">
+ </ClCompile>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
\ No newline at end of file diff --git a/tests/box2d/Build/vs2010/HelloWorld.vcxproj.filters b/tests/box2d/Build/vs2010/HelloWorld.vcxproj.filters new file mode 100755 index 00000000..1cbc00cb --- /dev/null +++ b/tests/box2d/Build/vs2010/HelloWorld.vcxproj.filters @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <ClCompile Include="..\..\HelloWorld\Helloworld.cpp" />
+ </ItemGroup>
+</Project>
diff --git a/tests/box2d/Build/vs2010/Testbed.vcxproj b/tests/box2d/Build/vs2010/Testbed.vcxproj new file mode 100755 index 00000000..1723c9ab --- /dev/null +++ b/tests/box2d/Build/vs2010/Testbed.vcxproj @@ -0,0 +1,265 @@ +<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{3FC8974C-9179-4D4E-A5E0-79E3C836548F}</ProjectGuid>
+ <RootNamespace>Testbed</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">bin\Debug\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">obj\x32\Debug\Testbed\</IntDir>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Testbed</TargetName>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">bin\Debug\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">obj\x64\Debug\Testbed\</IntDir>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Testbed</TargetName>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">bin\Release\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">obj\x32\Release\Testbed\</IntDir>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Testbed</TargetName>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">bin\Release\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">obj\x64\Release\Testbed\</IntDir>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Testbed</TargetName>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <ProgramDataBaseFileName>$(OutDir)Testbed.pdb</ProgramDataBaseFileName>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>bin\Debug\Box2D.lib;bin\Debug\FreeGLUT.lib;bin\Debug\GLUI.lib;glu32.lib;opengl32.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)Testbed.exe</OutputFile>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EntryPointSymbol>mainCRTStartup</EntryPointSymbol>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <ProgramDataBaseFileName>$(OutDir)Testbed.pdb</ProgramDataBaseFileName>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>bin\Debug\Box2D.lib;bin\Debug\FreeGLUT.lib;bin\Debug\GLUI.lib;glu32.lib;opengl32.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)Testbed.exe</OutputFile>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EntryPointSymbol>mainCRTStartup</EntryPointSymbol>
+ <TargetMachine>MachineX64</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <AdditionalIncludeDirectories>..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>false</MinimalRebuild>
+ <StringPooling>true</StringPooling>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>
+ </DebugInformationFormat>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>bin\Release\Box2D.lib;bin\Release\FreeGLUT.lib;bin\Release\GLUI.lib;glu32.lib;opengl32.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)Testbed.exe</OutputFile>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <EntryPointSymbol>mainCRTStartup</EntryPointSymbol>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <AdditionalIncludeDirectories>..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>false</MinimalRebuild>
+ <StringPooling>true</StringPooling>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>
+ </DebugInformationFormat>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>bin\Release\Box2D.lib;bin\Release\FreeGLUT.lib;bin\Release\GLUI.lib;glu32.lib;opengl32.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)Testbed.exe</OutputFile>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <EntryPointSymbol>mainCRTStartup</EntryPointSymbol>
+ <TargetMachine>MachineX64</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\Testbed\Framework\Render.h" />
+ <ClInclude Include="..\..\Testbed\Framework\Test.h" />
+ <ClInclude Include="..\..\Testbed\Tests\AddPair.h" />
+ <ClInclude Include="..\..\Testbed\Tests\ApplyForce.h" />
+ <ClInclude Include="..\..\Testbed\Tests\BodyTypes.h" />
+ <ClInclude Include="..\..\Testbed\Tests\Breakable.h" />
+ <ClInclude Include="..\..\Testbed\Tests\Bridge.h" />
+ <ClInclude Include="..\..\Testbed\Tests\BulletTest.h" />
+ <ClInclude Include="..\..\Testbed\Tests\Cantilever.h" />
+ <ClInclude Include="..\..\Testbed\Tests\Car.h" />
+ <ClInclude Include="..\..\Testbed\Tests\Chain.h" />
+ <ClInclude Include="..\..\Testbed\Tests\CharacterCollision.h" />
+ <ClInclude Include="..\..\Testbed\Tests\CollisionFiltering.h" />
+ <ClInclude Include="..\..\Testbed\Tests\CollisionProcessing.h" />
+ <ClInclude Include="..\..\Testbed\Tests\CompoundShapes.h" />
+ <ClInclude Include="..\..\Testbed\Tests\Confined.h" />
+ <ClInclude Include="..\..\Testbed\Tests\ContinuousTest.h" />
+ <ClInclude Include="..\..\Testbed\Tests\Cord.h" />
+ <ClInclude Include="..\..\Testbed\Tests\DistanceTest.h" />
+ <ClInclude Include="..\..\Testbed\Tests\Dominos.h" />
+ <ClInclude Include="..\..\Testbed\Tests\DumpShell.h" />
+ <ClInclude Include="..\..\Testbed\Tests\DynamicTreeTest.h" />
+ <ClInclude Include="..\..\Testbed\Tests\EdgeShapes.h" />
+ <ClInclude Include="..\..\Testbed\Tests\EdgeTest.h" />
+ <ClInclude Include="..\..\Testbed\Tests\Gears.h" />
+ <ClInclude Include="..\..\Testbed\Tests\OneSidedPlatform.h" />
+ <ClInclude Include="..\..\Testbed\Tests\Pinball.h" />
+ <ClInclude Include="..\..\Testbed\Tests\PolyCollision.h" />
+ <ClInclude Include="..\..\Testbed\Tests\PolyShapes.h" />
+ <ClInclude Include="..\..\Testbed\Tests\Prismatic.h" />
+ <ClInclude Include="..\..\Testbed\Tests\Pulleys.h" />
+ <ClInclude Include="..\..\Testbed\Tests\Pyramid.h" />
+ <ClInclude Include="..\..\Testbed\Tests\RayCast.h" />
+ <ClInclude Include="..\..\Testbed\Tests\Revolute.h" />
+ <ClInclude Include="..\..\Testbed\Tests\Rope.h" />
+ <ClInclude Include="..\..\Testbed\Tests\RopeJoint.h" />
+ <ClInclude Include="..\..\Testbed\Tests\SensorTest.h" />
+ <ClInclude Include="..\..\Testbed\Tests\ShapeEditing.h" />
+ <ClInclude Include="..\..\Testbed\Tests\SliderCrank.h" />
+ <ClInclude Include="..\..\Testbed\Tests\SphereStack.h" />
+ <ClInclude Include="..\..\Testbed\Tests\TheoJansen.h" />
+ <ClInclude Include="..\..\Testbed\Tests\Tiles.h" />
+ <ClInclude Include="..\..\Testbed\Tests\TimeOfImpact.h" />
+ <ClInclude Include="..\..\Testbed\Tests\Tumbler.h" />
+ <ClInclude Include="..\..\Testbed\Tests\VaryingFriction.h" />
+ <ClInclude Include="..\..\Testbed\Tests\VaryingRestitution.h" />
+ <ClInclude Include="..\..\Testbed\Tests\VerticalStack.h" />
+ <ClInclude Include="..\..\Testbed\Tests\Web.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\Testbed\Framework\Main.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Testbed\Framework\Render.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Testbed\Framework\Test.cpp">
+ </ClCompile>
+ <ClCompile Include="..\..\Testbed\Tests\TestEntries.cpp">
+ </ClCompile>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
\ No newline at end of file diff --git a/tests/box2d/Build/vs2010/Testbed.vcxproj.filters b/tests/box2d/Build/vs2010/Testbed.vcxproj.filters new file mode 100755 index 00000000..52961731 --- /dev/null +++ b/tests/box2d/Build/vs2010/Testbed.vcxproj.filters @@ -0,0 +1,171 @@ +<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Framework">
+ <UniqueIdentifier>{F5D5D9E8-9CBD-914E-B539-B995BEA73920}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Tests">
+ <UniqueIdentifier>{CF6BC554-9DC6-4547-9F18-A1BA2F3345BF}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\Testbed\Framework\Render.h">
+ <Filter>Framework</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Framework\Test.h">
+ <Filter>Framework</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\AddPair.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\ApplyForce.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\BodyTypes.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\Breakable.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\Bridge.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\BulletTest.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\Cantilever.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\Car.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\Chain.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\CharacterCollision.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\CollisionFiltering.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\CollisionProcessing.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\CompoundShapes.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\Confined.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\ContinuousTest.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\Cord.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\DistanceTest.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\Dominos.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\DumpShell.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\DynamicTreeTest.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\EdgeShapes.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\EdgeTest.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\Gears.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\OneSidedPlatform.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\Pinball.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\PolyCollision.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\PolyShapes.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\Prismatic.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\Pulleys.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\Pyramid.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\RayCast.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\Revolute.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\Rope.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\RopeJoint.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\SensorTest.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\ShapeEditing.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\SliderCrank.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\SphereStack.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\TheoJansen.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\Tiles.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\TimeOfImpact.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\VaryingFriction.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\VaryingRestitution.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\VerticalStack.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\Web.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Testbed\Tests\Tumbler.h">
+ <Filter>Tests</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\Testbed\Framework\Main.cpp">
+ <Filter>Framework</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Testbed\Framework\Render.cpp">
+ <Filter>Framework</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Testbed\Framework\Test.cpp">
+ <Filter>Framework</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\Testbed\Tests\TestEntries.cpp">
+ <Filter>Tests</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project>
\ No newline at end of file diff --git a/tests/box2d/Build/xcode4/Box2D.xcodeproj/project.pbxproj b/tests/box2d/Build/xcode4/Box2D.xcodeproj/project.pbxproj new file mode 100755 index 00000000..a8bd2490 --- /dev/null +++ b/tests/box2d/Build/xcode4/Box2D.xcodeproj/project.pbxproj @@ -0,0 +1,1210 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 80BB8987141C3E5900F1753A /* Box2D.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8923141C3E5900F1753A /* Box2D.h */; }; + 80BB8988141C3E5900F1753A /* b2BroadPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8927141C3E5900F1753A /* b2BroadPhase.cpp */; }; + 80BB8989141C3E5900F1753A /* b2BroadPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8928141C3E5900F1753A /* b2BroadPhase.h */; }; + 80BB898A141C3E5900F1753A /* b2CollideCircle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8929141C3E5900F1753A /* b2CollideCircle.cpp */; }; + 80BB898B141C3E5900F1753A /* b2CollideEdge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB892A141C3E5900F1753A /* b2CollideEdge.cpp */; }; + 80BB898C141C3E5900F1753A /* b2CollidePolygon.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB892B141C3E5900F1753A /* b2CollidePolygon.cpp */; }; + 80BB898D141C3E5900F1753A /* b2Collision.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB892C141C3E5900F1753A /* b2Collision.cpp */; }; + 80BB898E141C3E5900F1753A /* b2Collision.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB892D141C3E5900F1753A /* b2Collision.h */; }; + 80BB898F141C3E5900F1753A /* b2Distance.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB892E141C3E5900F1753A /* b2Distance.cpp */; }; + 80BB8990141C3E5900F1753A /* b2Distance.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB892F141C3E5900F1753A /* b2Distance.h */; }; + 80BB8991141C3E5900F1753A /* b2DynamicTree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8930141C3E5900F1753A /* b2DynamicTree.cpp */; }; + 80BB8992141C3E5900F1753A /* b2DynamicTree.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8931141C3E5900F1753A /* b2DynamicTree.h */; }; + 80BB8993141C3E5900F1753A /* b2TimeOfImpact.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8932141C3E5900F1753A /* b2TimeOfImpact.cpp */; }; + 80BB8994141C3E5900F1753A /* b2TimeOfImpact.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8933141C3E5900F1753A /* b2TimeOfImpact.h */; }; + 80BB8995141C3E5900F1753A /* b2ChainShape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8935141C3E5900F1753A /* b2ChainShape.cpp */; }; + 80BB8996141C3E5900F1753A /* b2ChainShape.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8936141C3E5900F1753A /* b2ChainShape.h */; }; + 80BB8997141C3E5900F1753A /* b2CircleShape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8937141C3E5900F1753A /* b2CircleShape.cpp */; }; + 80BB8998141C3E5900F1753A /* b2CircleShape.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8938141C3E5900F1753A /* b2CircleShape.h */; }; + 80BB8999141C3E5900F1753A /* b2EdgeShape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8939141C3E5900F1753A /* b2EdgeShape.cpp */; }; + 80BB899A141C3E5900F1753A /* b2EdgeShape.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB893A141C3E5900F1753A /* b2EdgeShape.h */; }; + 80BB899B141C3E5900F1753A /* b2PolygonShape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB893B141C3E5900F1753A /* b2PolygonShape.cpp */; }; + 80BB899C141C3E5900F1753A /* b2PolygonShape.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB893C141C3E5900F1753A /* b2PolygonShape.h */; }; + 80BB899D141C3E5900F1753A /* b2Shape.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB893D141C3E5900F1753A /* b2Shape.h */; }; + 80BB899E141C3E5900F1753A /* b2BlockAllocator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB893F141C3E5900F1753A /* b2BlockAllocator.cpp */; }; + 80BB899F141C3E5900F1753A /* b2BlockAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8940141C3E5900F1753A /* b2BlockAllocator.h */; }; + 80BB89A0141C3E5900F1753A /* b2Draw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8941141C3E5900F1753A /* b2Draw.cpp */; }; + 80BB89A1141C3E5900F1753A /* b2Draw.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8942141C3E5900F1753A /* b2Draw.h */; }; + 80BB89A2141C3E5900F1753A /* b2GrowableStack.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8943141C3E5900F1753A /* b2GrowableStack.h */; }; + 80BB89A3141C3E5900F1753A /* b2Math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8944141C3E5900F1753A /* b2Math.cpp */; }; + 80BB89A4141C3E5900F1753A /* b2Math.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8945141C3E5900F1753A /* b2Math.h */; }; + 80BB89A5141C3E5900F1753A /* b2Settings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8946141C3E5900F1753A /* b2Settings.cpp */; }; + 80BB89A6141C3E5900F1753A /* b2Settings.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8947141C3E5900F1753A /* b2Settings.h */; }; + 80BB89A7141C3E5900F1753A /* b2StackAllocator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8948141C3E5900F1753A /* b2StackAllocator.cpp */; }; + 80BB89A8141C3E5900F1753A /* b2StackAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8949141C3E5900F1753A /* b2StackAllocator.h */; }; + 80BB89A9141C3E5900F1753A /* b2Timer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB894A141C3E5900F1753A /* b2Timer.cpp */; }; + 80BB89AA141C3E5900F1753A /* b2Timer.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB894B141C3E5900F1753A /* b2Timer.h */; }; + 80BB89AB141C3E5900F1753A /* b2Body.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB894D141C3E5900F1753A /* b2Body.cpp */; }; + 80BB89AC141C3E5900F1753A /* b2Body.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB894E141C3E5900F1753A /* b2Body.h */; }; + 80BB89AD141C3E5900F1753A /* b2ContactManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB894F141C3E5900F1753A /* b2ContactManager.cpp */; }; + 80BB89AE141C3E5900F1753A /* b2ContactManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8950141C3E5900F1753A /* b2ContactManager.h */; }; + 80BB89AF141C3E5900F1753A /* b2Fixture.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8951141C3E5900F1753A /* b2Fixture.cpp */; }; + 80BB89B0141C3E5900F1753A /* b2Fixture.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8952141C3E5900F1753A /* b2Fixture.h */; }; + 80BB89B1141C3E5900F1753A /* b2Island.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8953141C3E5900F1753A /* b2Island.cpp */; }; + 80BB89B2141C3E5900F1753A /* b2Island.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8954141C3E5900F1753A /* b2Island.h */; }; + 80BB89B3141C3E5900F1753A /* b2TimeStep.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8955141C3E5900F1753A /* b2TimeStep.h */; }; + 80BB89B4141C3E5900F1753A /* b2World.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8956141C3E5900F1753A /* b2World.cpp */; }; + 80BB89B5141C3E5900F1753A /* b2World.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8957141C3E5900F1753A /* b2World.h */; }; + 80BB89B6141C3E5900F1753A /* b2WorldCallbacks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8958141C3E5900F1753A /* b2WorldCallbacks.cpp */; }; + 80BB89B7141C3E5900F1753A /* b2WorldCallbacks.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8959141C3E5900F1753A /* b2WorldCallbacks.h */; }; + 80BB89B8141C3E5900F1753A /* b2ChainAndCircleContact.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB895B141C3E5900F1753A /* b2ChainAndCircleContact.cpp */; }; + 80BB89B9141C3E5900F1753A /* b2ChainAndCircleContact.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB895C141C3E5900F1753A /* b2ChainAndCircleContact.h */; }; + 80BB89BA141C3E5900F1753A /* b2ChainAndPolygonContact.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB895D141C3E5900F1753A /* b2ChainAndPolygonContact.cpp */; }; + 80BB89BB141C3E5900F1753A /* b2ChainAndPolygonContact.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB895E141C3E5900F1753A /* b2ChainAndPolygonContact.h */; }; + 80BB89BC141C3E5900F1753A /* b2CircleContact.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB895F141C3E5900F1753A /* b2CircleContact.cpp */; }; + 80BB89BD141C3E5900F1753A /* b2CircleContact.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8960141C3E5900F1753A /* b2CircleContact.h */; }; + 80BB89BE141C3E5900F1753A /* b2Contact.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8961141C3E5900F1753A /* b2Contact.cpp */; }; + 80BB89BF141C3E5900F1753A /* b2Contact.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8962141C3E5900F1753A /* b2Contact.h */; }; + 80BB89C0141C3E5900F1753A /* b2ContactSolver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8963141C3E5900F1753A /* b2ContactSolver.cpp */; }; + 80BB89C1141C3E5900F1753A /* b2ContactSolver.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8964141C3E5900F1753A /* b2ContactSolver.h */; }; + 80BB89C2141C3E5900F1753A /* b2EdgeAndCircleContact.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8965141C3E5900F1753A /* b2EdgeAndCircleContact.cpp */; }; + 80BB89C3141C3E5900F1753A /* b2EdgeAndCircleContact.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8966141C3E5900F1753A /* b2EdgeAndCircleContact.h */; }; + 80BB89C4141C3E5900F1753A /* b2EdgeAndPolygonContact.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8967141C3E5900F1753A /* b2EdgeAndPolygonContact.cpp */; }; + 80BB89C5141C3E5900F1753A /* b2EdgeAndPolygonContact.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8968141C3E5900F1753A /* b2EdgeAndPolygonContact.h */; }; + 80BB89C6141C3E5900F1753A /* b2PolygonAndCircleContact.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8969141C3E5900F1753A /* b2PolygonAndCircleContact.cpp */; }; + 80BB89C7141C3E5900F1753A /* b2PolygonAndCircleContact.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB896A141C3E5900F1753A /* b2PolygonAndCircleContact.h */; }; + 80BB89C8141C3E5900F1753A /* b2PolygonContact.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB896B141C3E5900F1753A /* b2PolygonContact.cpp */; }; + 80BB89C9141C3E5900F1753A /* b2PolygonContact.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB896C141C3E5900F1753A /* b2PolygonContact.h */; }; + 80BB89CA141C3E5900F1753A /* b2DistanceJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB896E141C3E5900F1753A /* b2DistanceJoint.cpp */; }; + 80BB89CB141C3E5900F1753A /* b2DistanceJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB896F141C3E5900F1753A /* b2DistanceJoint.h */; }; + 80BB89CC141C3E5900F1753A /* b2FrictionJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8970141C3E5900F1753A /* b2FrictionJoint.cpp */; }; + 80BB89CD141C3E5900F1753A /* b2FrictionJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8971141C3E5900F1753A /* b2FrictionJoint.h */; }; + 80BB89CE141C3E5900F1753A /* b2GearJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8972141C3E5900F1753A /* b2GearJoint.cpp */; }; + 80BB89CF141C3E5900F1753A /* b2GearJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8973141C3E5900F1753A /* b2GearJoint.h */; }; + 80BB89D0141C3E5900F1753A /* b2Joint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8974141C3E5900F1753A /* b2Joint.cpp */; }; + 80BB89D1141C3E5900F1753A /* b2Joint.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8975141C3E5900F1753A /* b2Joint.h */; }; + 80BB89D2141C3E5900F1753A /* b2MouseJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8976141C3E5900F1753A /* b2MouseJoint.cpp */; }; + 80BB89D3141C3E5900F1753A /* b2MouseJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8977141C3E5900F1753A /* b2MouseJoint.h */; }; + 80BB89D4141C3E5900F1753A /* b2PrismaticJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8978141C3E5900F1753A /* b2PrismaticJoint.cpp */; }; + 80BB89D5141C3E5900F1753A /* b2PrismaticJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8979141C3E5900F1753A /* b2PrismaticJoint.h */; }; + 80BB89D6141C3E5900F1753A /* b2PulleyJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB897A141C3E5900F1753A /* b2PulleyJoint.cpp */; }; + 80BB89D7141C3E5900F1753A /* b2PulleyJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB897B141C3E5900F1753A /* b2PulleyJoint.h */; }; + 80BB89D8141C3E5900F1753A /* b2RevoluteJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB897C141C3E5900F1753A /* b2RevoluteJoint.cpp */; }; + 80BB89D9141C3E5900F1753A /* b2RevoluteJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB897D141C3E5900F1753A /* b2RevoluteJoint.h */; }; + 80BB89DA141C3E5900F1753A /* b2RopeJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB897E141C3E5900F1753A /* b2RopeJoint.cpp */; }; + 80BB89DB141C3E5900F1753A /* b2RopeJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB897F141C3E5900F1753A /* b2RopeJoint.h */; }; + 80BB89DC141C3E5900F1753A /* b2WeldJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8980141C3E5900F1753A /* b2WeldJoint.cpp */; }; + 80BB89DD141C3E5900F1753A /* b2WeldJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8981141C3E5900F1753A /* b2WeldJoint.h */; }; + 80BB89DE141C3E5900F1753A /* b2WheelJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8982141C3E5900F1753A /* b2WheelJoint.cpp */; }; + 80BB89DF141C3E5900F1753A /* b2WheelJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8983141C3E5900F1753A /* b2WheelJoint.h */; }; + 80BB89E0141C3E5900F1753A /* b2Rope.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8985141C3E5900F1753A /* b2Rope.cpp */; }; + 80BB89E1141C3E5900F1753A /* b2Rope.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8986141C3E5900F1753A /* b2Rope.h */; }; + 80BB8A0B141C3E6900F1753A /* algebra3.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89E3141C3E6900F1753A /* algebra3.cpp */; }; + 80BB8A0C141C3E6900F1753A /* algebra3.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB89E4141C3E6900F1753A /* algebra3.h */; }; + 80BB8A0D141C3E6900F1753A /* arcball.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89E5141C3E6900F1753A /* arcball.cpp */; }; + 80BB8A0E141C3E6900F1753A /* arcball.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB89E6141C3E6900F1753A /* arcball.h */; }; + 80BB8A0F141C3E6900F1753A /* glui.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89E8141C3E6900F1753A /* glui.cpp */; }; + 80BB8A10141C3E6900F1753A /* glui.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB89E9141C3E6900F1753A /* glui.h */; }; + 80BB8A11141C3E6900F1753A /* glui_add_controls.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89EA141C3E6900F1753A /* glui_add_controls.cpp */; }; + 80BB8A12141C3E6900F1753A /* glui_bitmap_img_data.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89EB141C3E6900F1753A /* glui_bitmap_img_data.cpp */; }; + 80BB8A13141C3E6900F1753A /* glui_bitmaps.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89EC141C3E6900F1753A /* glui_bitmaps.cpp */; }; + 80BB8A14141C3E6900F1753A /* glui_button.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89ED141C3E6900F1753A /* glui_button.cpp */; }; + 80BB8A15141C3E6900F1753A /* glui_checkbox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89EE141C3E6900F1753A /* glui_checkbox.cpp */; }; + 80BB8A16141C3E6900F1753A /* glui_column.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89EF141C3E6900F1753A /* glui_column.cpp */; }; + 80BB8A17141C3E6900F1753A /* glui_commandline.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89F0141C3E6900F1753A /* glui_commandline.cpp */; }; + 80BB8A18141C3E6900F1753A /* glui_control.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89F1141C3E6900F1753A /* glui_control.cpp */; }; + 80BB8A19141C3E6900F1753A /* glui_edittext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89F2141C3E6900F1753A /* glui_edittext.cpp */; }; + 80BB8A1A141C3E6900F1753A /* glui_filebrowser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89F3141C3E6900F1753A /* glui_filebrowser.cpp */; }; + 80BB8A1B141C3E6900F1753A /* glui_internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB89F4141C3E6900F1753A /* glui_internal.h */; }; + 80BB8A1C141C3E6900F1753A /* glui_internal_control.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB89F5141C3E6900F1753A /* glui_internal_control.h */; }; + 80BB8A1D141C3E6900F1753A /* glui_list.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89F6141C3E6900F1753A /* glui_list.cpp */; }; + 80BB8A1E141C3E6900F1753A /* glui_listbox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89F7141C3E6900F1753A /* glui_listbox.cpp */; }; + 80BB8A1F141C3E6900F1753A /* glui_mouse_iaction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89F8141C3E6900F1753A /* glui_mouse_iaction.cpp */; }; + 80BB8A20141C3E6900F1753A /* glui_node.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89F9141C3E6900F1753A /* glui_node.cpp */; }; + 80BB8A21141C3E6900F1753A /* glui_panel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89FA141C3E6900F1753A /* glui_panel.cpp */; }; + 80BB8A22141C3E6900F1753A /* glui_radio.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89FB141C3E6900F1753A /* glui_radio.cpp */; }; + 80BB8A23141C3E6900F1753A /* glui_rollout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89FC141C3E6900F1753A /* glui_rollout.cpp */; }; + 80BB8A24141C3E6900F1753A /* glui_rotation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89FD141C3E6900F1753A /* glui_rotation.cpp */; }; + 80BB8A25141C3E6900F1753A /* glui_scrollbar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89FE141C3E6900F1753A /* glui_scrollbar.cpp */; }; + 80BB8A26141C3E6900F1753A /* glui_separator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB89FF141C3E6900F1753A /* glui_separator.cpp */; }; + 80BB8A27141C3E6900F1753A /* glui_spinner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8A00141C3E6900F1753A /* glui_spinner.cpp */; }; + 80BB8A28141C3E6900F1753A /* glui_statictext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8A01141C3E6900F1753A /* glui_statictext.cpp */; }; + 80BB8A29141C3E6900F1753A /* glui_string.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8A02141C3E6900F1753A /* glui_string.cpp */; }; + 80BB8A2A141C3E6900F1753A /* glui_textbox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8A03141C3E6900F1753A /* glui_textbox.cpp */; }; + 80BB8A2B141C3E6900F1753A /* glui_translation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8A04141C3E6900F1753A /* glui_translation.cpp */; }; + 80BB8A2C141C3E6900F1753A /* glui_tree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8A05141C3E6900F1753A /* glui_tree.cpp */; }; + 80BB8A2D141C3E6900F1753A /* glui_treepanel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8A06141C3E6900F1753A /* glui_treepanel.cpp */; }; + 80BB8A2E141C3E6900F1753A /* glui_window.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8A07141C3E6900F1753A /* glui_window.cpp */; }; + 80BB8A2F141C3E6900F1753A /* quaternion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8A08141C3E6900F1753A /* quaternion.cpp */; }; + 80BB8A30141C3E6900F1753A /* quaternion.h in Headers */ = {isa = PBXBuildFile; fileRef = 80BB8A09141C3E6900F1753A /* quaternion.h */; }; + 80BB8A34141C3E7B00F1753A /* HelloWorld.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8A33141C3E7B00F1753A /* HelloWorld.cpp */; }; + 80BB8A6B141C3E8600F1753A /* Main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8A38141C3E8500F1753A /* Main.cpp */; }; + 80BB8A6C141C3E8600F1753A /* Render.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8A39141C3E8500F1753A /* Render.cpp */; }; + 80BB8A6D141C3E8600F1753A /* Test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8A3B141C3E8500F1753A /* Test.cpp */; }; + 80BB8A6E141C3E8600F1753A /* TestEntries.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 80BB8A63141C3E8600F1753A /* TestEntries.cpp */; }; + 80BB8A75141C3F4C00F1753A /* libBox2D.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 80FF01D2141C3D980059E59D /* libBox2D.a */; }; + 80BB8A76141C3F7600F1753A /* libBox2D.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 80FF01D2141C3D980059E59D /* libBox2D.a */; }; + 80BB8A77141C3F7600F1753A /* libGLUI.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 80BB8901141C3E1800F1753A /* libGLUI.a */; }; + 80BB8A79141C3F9C00F1753A /* GLUT.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 80BB8A78141C3F9C00F1753A /* GLUT.framework */; }; + 80BB8A7B141C3FA700F1753A /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 80BB8A7A141C3FA700F1753A /* OpenGL.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 80BB8A6F141C3EA100F1753A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 80FF01C9141C3D980059E59D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 80FF01D1141C3D980059E59D; + remoteInfo = Box2D; + }; + 80BB8A71141C3EA800F1753A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 80FF01C9141C3D980059E59D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 80FF01D1141C3D980059E59D; + remoteInfo = Box2D; + }; + 80BB8A73141C3EA800F1753A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 80FF01C9141C3D980059E59D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 80BB8900141C3E1800F1753A; + remoteInfo = GLUI; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 80BB8908141C3E2600F1753A /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; + 80BB8916141C3E3600F1753A /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 80154ACD141DED6B00C8251F /* Tumbler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Tumbler.h; sourceTree = "<group>"; }; + 80BB8901141C3E1800F1753A /* libGLUI.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libGLUI.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 80BB890A141C3E2700F1753A /* HelloWorld */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = HelloWorld; sourceTree = BUILT_PRODUCTS_DIR; }; + 80BB8918141C3E3600F1753A /* Testbed */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = Testbed; sourceTree = BUILT_PRODUCTS_DIR; }; + 80BB8923141C3E5900F1753A /* Box2D.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Box2D.h; sourceTree = "<group>"; }; + 80BB8924141C3E5900F1753A /* Box2DConfig.cmake */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Box2DConfig.cmake; sourceTree = "<group>"; }; + 80BB8925141C3E5900F1753A /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; }; + 80BB8927141C3E5900F1753A /* b2BroadPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2BroadPhase.cpp; sourceTree = "<group>"; }; + 80BB8928141C3E5900F1753A /* b2BroadPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2BroadPhase.h; sourceTree = "<group>"; }; + 80BB8929141C3E5900F1753A /* b2CollideCircle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2CollideCircle.cpp; sourceTree = "<group>"; }; + 80BB892A141C3E5900F1753A /* b2CollideEdge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2CollideEdge.cpp; sourceTree = "<group>"; }; + 80BB892B141C3E5900F1753A /* b2CollidePolygon.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2CollidePolygon.cpp; sourceTree = "<group>"; }; + 80BB892C141C3E5900F1753A /* b2Collision.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Collision.cpp; sourceTree = "<group>"; }; + 80BB892D141C3E5900F1753A /* b2Collision.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Collision.h; sourceTree = "<group>"; }; + 80BB892E141C3E5900F1753A /* b2Distance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Distance.cpp; sourceTree = "<group>"; }; + 80BB892F141C3E5900F1753A /* b2Distance.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Distance.h; sourceTree = "<group>"; }; + 80BB8930141C3E5900F1753A /* b2DynamicTree.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2DynamicTree.cpp; sourceTree = "<group>"; }; + 80BB8931141C3E5900F1753A /* b2DynamicTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2DynamicTree.h; sourceTree = "<group>"; }; + 80BB8932141C3E5900F1753A /* b2TimeOfImpact.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2TimeOfImpact.cpp; sourceTree = "<group>"; }; + 80BB8933141C3E5900F1753A /* b2TimeOfImpact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2TimeOfImpact.h; sourceTree = "<group>"; }; + 80BB8935141C3E5900F1753A /* b2ChainShape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2ChainShape.cpp; sourceTree = "<group>"; }; + 80BB8936141C3E5900F1753A /* b2ChainShape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2ChainShape.h; sourceTree = "<group>"; }; + 80BB8937141C3E5900F1753A /* b2CircleShape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2CircleShape.cpp; sourceTree = "<group>"; }; + 80BB8938141C3E5900F1753A /* b2CircleShape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2CircleShape.h; sourceTree = "<group>"; }; + 80BB8939141C3E5900F1753A /* b2EdgeShape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2EdgeShape.cpp; sourceTree = "<group>"; }; + 80BB893A141C3E5900F1753A /* b2EdgeShape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2EdgeShape.h; sourceTree = "<group>"; }; + 80BB893B141C3E5900F1753A /* b2PolygonShape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2PolygonShape.cpp; sourceTree = "<group>"; }; + 80BB893C141C3E5900F1753A /* b2PolygonShape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2PolygonShape.h; sourceTree = "<group>"; }; + 80BB893D141C3E5900F1753A /* b2Shape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Shape.h; sourceTree = "<group>"; }; + 80BB893F141C3E5900F1753A /* b2BlockAllocator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2BlockAllocator.cpp; sourceTree = "<group>"; }; + 80BB8940141C3E5900F1753A /* b2BlockAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2BlockAllocator.h; sourceTree = "<group>"; }; + 80BB8941141C3E5900F1753A /* b2Draw.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Draw.cpp; sourceTree = "<group>"; }; + 80BB8942141C3E5900F1753A /* b2Draw.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Draw.h; sourceTree = "<group>"; }; + 80BB8943141C3E5900F1753A /* b2GrowableStack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2GrowableStack.h; sourceTree = "<group>"; }; + 80BB8944141C3E5900F1753A /* b2Math.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Math.cpp; sourceTree = "<group>"; }; + 80BB8945141C3E5900F1753A /* b2Math.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Math.h; sourceTree = "<group>"; }; + 80BB8946141C3E5900F1753A /* b2Settings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Settings.cpp; sourceTree = "<group>"; }; + 80BB8947141C3E5900F1753A /* b2Settings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Settings.h; sourceTree = "<group>"; }; + 80BB8948141C3E5900F1753A /* b2StackAllocator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2StackAllocator.cpp; sourceTree = "<group>"; }; + 80BB8949141C3E5900F1753A /* b2StackAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2StackAllocator.h; sourceTree = "<group>"; }; + 80BB894A141C3E5900F1753A /* b2Timer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Timer.cpp; sourceTree = "<group>"; }; + 80BB894B141C3E5900F1753A /* b2Timer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Timer.h; sourceTree = "<group>"; }; + 80BB894D141C3E5900F1753A /* b2Body.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Body.cpp; sourceTree = "<group>"; }; + 80BB894E141C3E5900F1753A /* b2Body.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Body.h; sourceTree = "<group>"; }; + 80BB894F141C3E5900F1753A /* b2ContactManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2ContactManager.cpp; sourceTree = "<group>"; }; + 80BB8950141C3E5900F1753A /* b2ContactManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2ContactManager.h; sourceTree = "<group>"; }; + 80BB8951141C3E5900F1753A /* b2Fixture.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Fixture.cpp; sourceTree = "<group>"; }; + 80BB8952141C3E5900F1753A /* b2Fixture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Fixture.h; sourceTree = "<group>"; }; + 80BB8953141C3E5900F1753A /* b2Island.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Island.cpp; sourceTree = "<group>"; }; + 80BB8954141C3E5900F1753A /* b2Island.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Island.h; sourceTree = "<group>"; }; + 80BB8955141C3E5900F1753A /* b2TimeStep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2TimeStep.h; sourceTree = "<group>"; }; + 80BB8956141C3E5900F1753A /* b2World.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2World.cpp; sourceTree = "<group>"; }; + 80BB8957141C3E5900F1753A /* b2World.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2World.h; sourceTree = "<group>"; }; + 80BB8958141C3E5900F1753A /* b2WorldCallbacks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2WorldCallbacks.cpp; sourceTree = "<group>"; }; + 80BB8959141C3E5900F1753A /* b2WorldCallbacks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2WorldCallbacks.h; sourceTree = "<group>"; }; + 80BB895B141C3E5900F1753A /* b2ChainAndCircleContact.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2ChainAndCircleContact.cpp; sourceTree = "<group>"; }; + 80BB895C141C3E5900F1753A /* b2ChainAndCircleContact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2ChainAndCircleContact.h; sourceTree = "<group>"; }; + 80BB895D141C3E5900F1753A /* b2ChainAndPolygonContact.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2ChainAndPolygonContact.cpp; sourceTree = "<group>"; }; + 80BB895E141C3E5900F1753A /* b2ChainAndPolygonContact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2ChainAndPolygonContact.h; sourceTree = "<group>"; }; + 80BB895F141C3E5900F1753A /* b2CircleContact.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2CircleContact.cpp; sourceTree = "<group>"; }; + 80BB8960141C3E5900F1753A /* b2CircleContact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2CircleContact.h; sourceTree = "<group>"; }; + 80BB8961141C3E5900F1753A /* b2Contact.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Contact.cpp; sourceTree = "<group>"; }; + 80BB8962141C3E5900F1753A /* b2Contact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Contact.h; sourceTree = "<group>"; }; + 80BB8963141C3E5900F1753A /* b2ContactSolver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2ContactSolver.cpp; sourceTree = "<group>"; }; + 80BB8964141C3E5900F1753A /* b2ContactSolver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2ContactSolver.h; sourceTree = "<group>"; }; + 80BB8965141C3E5900F1753A /* b2EdgeAndCircleContact.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2EdgeAndCircleContact.cpp; sourceTree = "<group>"; }; + 80BB8966141C3E5900F1753A /* b2EdgeAndCircleContact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2EdgeAndCircleContact.h; sourceTree = "<group>"; }; + 80BB8967141C3E5900F1753A /* b2EdgeAndPolygonContact.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2EdgeAndPolygonContact.cpp; sourceTree = "<group>"; }; + 80BB8968141C3E5900F1753A /* b2EdgeAndPolygonContact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2EdgeAndPolygonContact.h; sourceTree = "<group>"; }; + 80BB8969141C3E5900F1753A /* b2PolygonAndCircleContact.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2PolygonAndCircleContact.cpp; sourceTree = "<group>"; }; + 80BB896A141C3E5900F1753A /* b2PolygonAndCircleContact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2PolygonAndCircleContact.h; sourceTree = "<group>"; }; + 80BB896B141C3E5900F1753A /* b2PolygonContact.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2PolygonContact.cpp; sourceTree = "<group>"; }; + 80BB896C141C3E5900F1753A /* b2PolygonContact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2PolygonContact.h; sourceTree = "<group>"; }; + 80BB896E141C3E5900F1753A /* b2DistanceJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2DistanceJoint.cpp; sourceTree = "<group>"; }; + 80BB896F141C3E5900F1753A /* b2DistanceJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2DistanceJoint.h; sourceTree = "<group>"; }; + 80BB8970141C3E5900F1753A /* b2FrictionJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2FrictionJoint.cpp; sourceTree = "<group>"; }; + 80BB8971141C3E5900F1753A /* b2FrictionJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2FrictionJoint.h; sourceTree = "<group>"; }; + 80BB8972141C3E5900F1753A /* b2GearJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2GearJoint.cpp; sourceTree = "<group>"; }; + 80BB8973141C3E5900F1753A /* b2GearJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2GearJoint.h; sourceTree = "<group>"; }; + 80BB8974141C3E5900F1753A /* b2Joint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Joint.cpp; sourceTree = "<group>"; }; + 80BB8975141C3E5900F1753A /* b2Joint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Joint.h; sourceTree = "<group>"; }; + 80BB8976141C3E5900F1753A /* b2MouseJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2MouseJoint.cpp; sourceTree = "<group>"; }; + 80BB8977141C3E5900F1753A /* b2MouseJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2MouseJoint.h; sourceTree = "<group>"; }; + 80BB8978141C3E5900F1753A /* b2PrismaticJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2PrismaticJoint.cpp; sourceTree = "<group>"; }; + 80BB8979141C3E5900F1753A /* b2PrismaticJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2PrismaticJoint.h; sourceTree = "<group>"; }; + 80BB897A141C3E5900F1753A /* b2PulleyJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2PulleyJoint.cpp; sourceTree = "<group>"; }; + 80BB897B141C3E5900F1753A /* b2PulleyJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2PulleyJoint.h; sourceTree = "<group>"; }; + 80BB897C141C3E5900F1753A /* b2RevoluteJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2RevoluteJoint.cpp; sourceTree = "<group>"; }; + 80BB897D141C3E5900F1753A /* b2RevoluteJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2RevoluteJoint.h; sourceTree = "<group>"; }; + 80BB897E141C3E5900F1753A /* b2RopeJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2RopeJoint.cpp; sourceTree = "<group>"; }; + 80BB897F141C3E5900F1753A /* b2RopeJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2RopeJoint.h; sourceTree = "<group>"; }; + 80BB8980141C3E5900F1753A /* b2WeldJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2WeldJoint.cpp; sourceTree = "<group>"; }; + 80BB8981141C3E5900F1753A /* b2WeldJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2WeldJoint.h; sourceTree = "<group>"; }; + 80BB8982141C3E5900F1753A /* b2WheelJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2WheelJoint.cpp; sourceTree = "<group>"; }; + 80BB8983141C3E5900F1753A /* b2WheelJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2WheelJoint.h; sourceTree = "<group>"; }; + 80BB8985141C3E5900F1753A /* b2Rope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2Rope.cpp; sourceTree = "<group>"; }; + 80BB8986141C3E5900F1753A /* b2Rope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2Rope.h; sourceTree = "<group>"; }; + 80BB89E3141C3E6900F1753A /* algebra3.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = algebra3.cpp; sourceTree = "<group>"; }; + 80BB89E4141C3E6900F1753A /* algebra3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = algebra3.h; sourceTree = "<group>"; }; + 80BB89E5141C3E6900F1753A /* arcball.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = arcball.cpp; sourceTree = "<group>"; }; + 80BB89E6141C3E6900F1753A /* arcball.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = arcball.h; sourceTree = "<group>"; }; + 80BB89E7141C3E6900F1753A /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; }; + 80BB89E8141C3E6900F1753A /* glui.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui.cpp; sourceTree = "<group>"; }; + 80BB89E9141C3E6900F1753A /* glui.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = glui.h; sourceTree = "<group>"; }; + 80BB89EA141C3E6900F1753A /* glui_add_controls.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_add_controls.cpp; sourceTree = "<group>"; }; + 80BB89EB141C3E6900F1753A /* glui_bitmap_img_data.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_bitmap_img_data.cpp; sourceTree = "<group>"; }; + 80BB89EC141C3E6900F1753A /* glui_bitmaps.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_bitmaps.cpp; sourceTree = "<group>"; }; + 80BB89ED141C3E6900F1753A /* glui_button.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_button.cpp; sourceTree = "<group>"; }; + 80BB89EE141C3E6900F1753A /* glui_checkbox.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_checkbox.cpp; sourceTree = "<group>"; }; + 80BB89EF141C3E6900F1753A /* glui_column.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_column.cpp; sourceTree = "<group>"; }; + 80BB89F0141C3E6900F1753A /* glui_commandline.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_commandline.cpp; sourceTree = "<group>"; }; + 80BB89F1141C3E6900F1753A /* glui_control.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_control.cpp; sourceTree = "<group>"; }; + 80BB89F2141C3E6900F1753A /* glui_edittext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_edittext.cpp; sourceTree = "<group>"; }; + 80BB89F3141C3E6900F1753A /* glui_filebrowser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_filebrowser.cpp; sourceTree = "<group>"; }; + 80BB89F4141C3E6900F1753A /* glui_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = glui_internal.h; sourceTree = "<group>"; }; + 80BB89F5141C3E6900F1753A /* glui_internal_control.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = glui_internal_control.h; sourceTree = "<group>"; }; + 80BB89F6141C3E6900F1753A /* glui_list.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_list.cpp; sourceTree = "<group>"; }; + 80BB89F7141C3E6900F1753A /* glui_listbox.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_listbox.cpp; sourceTree = "<group>"; }; + 80BB89F8141C3E6900F1753A /* glui_mouse_iaction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_mouse_iaction.cpp; sourceTree = "<group>"; }; + 80BB89F9141C3E6900F1753A /* glui_node.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_node.cpp; sourceTree = "<group>"; }; + 80BB89FA141C3E6900F1753A /* glui_panel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_panel.cpp; sourceTree = "<group>"; }; + 80BB89FB141C3E6900F1753A /* glui_radio.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_radio.cpp; sourceTree = "<group>"; }; + 80BB89FC141C3E6900F1753A /* glui_rollout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_rollout.cpp; sourceTree = "<group>"; }; + 80BB89FD141C3E6900F1753A /* glui_rotation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_rotation.cpp; sourceTree = "<group>"; }; + 80BB89FE141C3E6900F1753A /* glui_scrollbar.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_scrollbar.cpp; sourceTree = "<group>"; }; + 80BB89FF141C3E6900F1753A /* glui_separator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_separator.cpp; sourceTree = "<group>"; }; + 80BB8A00141C3E6900F1753A /* glui_spinner.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_spinner.cpp; sourceTree = "<group>"; }; + 80BB8A01141C3E6900F1753A /* glui_statictext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_statictext.cpp; sourceTree = "<group>"; }; + 80BB8A02141C3E6900F1753A /* glui_string.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_string.cpp; sourceTree = "<group>"; }; + 80BB8A03141C3E6900F1753A /* glui_textbox.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_textbox.cpp; sourceTree = "<group>"; }; + 80BB8A04141C3E6900F1753A /* glui_translation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_translation.cpp; sourceTree = "<group>"; }; + 80BB8A05141C3E6900F1753A /* glui_tree.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_tree.cpp; sourceTree = "<group>"; }; + 80BB8A06141C3E6900F1753A /* glui_treepanel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_treepanel.cpp; sourceTree = "<group>"; }; + 80BB8A07141C3E6900F1753A /* glui_window.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glui_window.cpp; sourceTree = "<group>"; }; + 80BB8A08141C3E6900F1753A /* quaternion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = quaternion.cpp; sourceTree = "<group>"; }; + 80BB8A09141C3E6900F1753A /* quaternion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = quaternion.h; sourceTree = "<group>"; }; + 80BB8A0A141C3E6900F1753A /* readme.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = readme.txt; sourceTree = "<group>"; }; + 80BB8A32141C3E7B00F1753A /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; }; + 80BB8A33141C3E7B00F1753A /* HelloWorld.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HelloWorld.cpp; sourceTree = "<group>"; }; + 80BB8A36141C3E8500F1753A /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; }; + 80BB8A38141C3E8500F1753A /* Main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Main.cpp; sourceTree = "<group>"; }; + 80BB8A39141C3E8500F1753A /* Render.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Render.cpp; sourceTree = "<group>"; }; + 80BB8A3A141C3E8500F1753A /* Render.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Render.h; sourceTree = "<group>"; }; + 80BB8A3B141C3E8500F1753A /* Test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Test.cpp; sourceTree = "<group>"; }; + 80BB8A3C141C3E8500F1753A /* Test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Test.h; sourceTree = "<group>"; }; + 80BB8A3E141C3E8500F1753A /* AddPair.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AddPair.h; sourceTree = "<group>"; }; + 80BB8A3F141C3E8500F1753A /* ApplyForce.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ApplyForce.h; sourceTree = "<group>"; }; + 80BB8A40141C3E8500F1753A /* BodyTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BodyTypes.h; sourceTree = "<group>"; }; + 80BB8A41141C3E8500F1753A /* Breakable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Breakable.h; sourceTree = "<group>"; }; + 80BB8A42141C3E8500F1753A /* Bridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Bridge.h; sourceTree = "<group>"; }; + 80BB8A43141C3E8500F1753A /* BulletTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BulletTest.h; sourceTree = "<group>"; }; + 80BB8A44141C3E8500F1753A /* Cantilever.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Cantilever.h; sourceTree = "<group>"; }; + 80BB8A45141C3E8500F1753A /* Car.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Car.h; sourceTree = "<group>"; }; + 80BB8A46141C3E8500F1753A /* Chain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Chain.h; sourceTree = "<group>"; }; + 80BB8A47141C3E8500F1753A /* CharacterCollision.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CharacterCollision.h; sourceTree = "<group>"; }; + 80BB8A48141C3E8500F1753A /* CollisionFiltering.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CollisionFiltering.h; sourceTree = "<group>"; }; + 80BB8A49141C3E8500F1753A /* CollisionProcessing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CollisionProcessing.h; sourceTree = "<group>"; }; + 80BB8A4A141C3E8500F1753A /* CompoundShapes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CompoundShapes.h; sourceTree = "<group>"; }; + 80BB8A4B141C3E8600F1753A /* Confined.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Confined.h; sourceTree = "<group>"; }; + 80BB8A4C141C3E8600F1753A /* ContinuousTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContinuousTest.h; sourceTree = "<group>"; }; + 80BB8A4D141C3E8600F1753A /* DistanceTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DistanceTest.h; sourceTree = "<group>"; }; + 80BB8A4E141C3E8600F1753A /* Dominos.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Dominos.h; sourceTree = "<group>"; }; + 80BB8A4F141C3E8600F1753A /* DumpShell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DumpShell.h; sourceTree = "<group>"; }; + 80BB8A50141C3E8600F1753A /* DynamicTreeTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DynamicTreeTest.h; sourceTree = "<group>"; }; + 80BB8A51141C3E8600F1753A /* EdgeShapes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EdgeShapes.h; sourceTree = "<group>"; }; + 80BB8A52141C3E8600F1753A /* EdgeTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EdgeTest.h; sourceTree = "<group>"; }; + 80BB8A53141C3E8600F1753A /* Gears.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Gears.h; sourceTree = "<group>"; }; + 80BB8A54141C3E8600F1753A /* OneSidedPlatform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OneSidedPlatform.h; sourceTree = "<group>"; }; + 80BB8A55141C3E8600F1753A /* Pinball.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Pinball.h; sourceTree = "<group>"; }; + 80BB8A56141C3E8600F1753A /* PolyCollision.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PolyCollision.h; sourceTree = "<group>"; }; + 80BB8A57141C3E8600F1753A /* PolyShapes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PolyShapes.h; sourceTree = "<group>"; }; + 80BB8A58141C3E8600F1753A /* Prismatic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Prismatic.h; sourceTree = "<group>"; }; + 80BB8A59141C3E8600F1753A /* Pulleys.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Pulleys.h; sourceTree = "<group>"; }; + 80BB8A5A141C3E8600F1753A /* Pyramid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Pyramid.h; sourceTree = "<group>"; }; + 80BB8A5B141C3E8600F1753A /* RayCast.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RayCast.h; sourceTree = "<group>"; }; + 80BB8A5C141C3E8600F1753A /* Revolute.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Revolute.h; sourceTree = "<group>"; }; + 80BB8A5D141C3E8600F1753A /* Rope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Rope.h; sourceTree = "<group>"; }; + 80BB8A5E141C3E8600F1753A /* RopeJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RopeJoint.h; sourceTree = "<group>"; }; + 80BB8A5F141C3E8600F1753A /* SensorTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SensorTest.h; sourceTree = "<group>"; }; + 80BB8A60141C3E8600F1753A /* ShapeEditing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShapeEditing.h; sourceTree = "<group>"; }; + 80BB8A61141C3E8600F1753A /* SliderCrank.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SliderCrank.h; sourceTree = "<group>"; }; + 80BB8A62141C3E8600F1753A /* SphereStack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SphereStack.h; sourceTree = "<group>"; }; + 80BB8A63141C3E8600F1753A /* TestEntries.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TestEntries.cpp; sourceTree = "<group>"; }; + 80BB8A64141C3E8600F1753A /* TheoJansen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TheoJansen.h; sourceTree = "<group>"; }; + 80BB8A65141C3E8600F1753A /* Tiles.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Tiles.h; sourceTree = "<group>"; }; + 80BB8A66141C3E8600F1753A /* TimeOfImpact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TimeOfImpact.h; sourceTree = "<group>"; }; + 80BB8A67141C3E8600F1753A /* VaryingFriction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VaryingFriction.h; sourceTree = "<group>"; }; + 80BB8A68141C3E8600F1753A /* VaryingRestitution.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VaryingRestitution.h; sourceTree = "<group>"; }; + 80BB8A69141C3E8600F1753A /* VerticalStack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VerticalStack.h; sourceTree = "<group>"; }; + 80BB8A6A141C3E8600F1753A /* Web.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Web.h; sourceTree = "<group>"; }; + 80BB8A78141C3F9C00F1753A /* GLUT.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GLUT.framework; path = System/Library/Frameworks/GLUT.framework; sourceTree = SDKROOT; }; + 80BB8A7A141C3FA700F1753A /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; + 80FF01D2141C3D980059E59D /* libBox2D.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libBox2D.a; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 80BB88FE141C3E1800F1753A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 80BB8907141C3E2600F1753A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 80BB8A75141C3F4C00F1753A /* libBox2D.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 80BB8915141C3E3600F1753A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 80BB8A7B141C3FA700F1753A /* OpenGL.framework in Frameworks */, + 80BB8A79141C3F9C00F1753A /* GLUT.framework in Frameworks */, + 80BB8A76141C3F7600F1753A /* libBox2D.a in Frameworks */, + 80BB8A77141C3F7600F1753A /* libGLUI.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 80FF01CF141C3D980059E59D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 80BB8922141C3E5900F1753A /* Box2D */ = { + isa = PBXGroup; + children = ( + 80BB8923141C3E5900F1753A /* Box2D.h */, + 80BB8924141C3E5900F1753A /* Box2DConfig.cmake */, + 80BB8925141C3E5900F1753A /* CMakeLists.txt */, + 80BB8926141C3E5900F1753A /* Collision */, + 80BB893E141C3E5900F1753A /* Common */, + 80BB894C141C3E5900F1753A /* Dynamics */, + 80BB8984141C3E5900F1753A /* Rope */, + ); + name = Box2D; + path = ../../Box2D; + sourceTree = "<group>"; + }; + 80BB8926141C3E5900F1753A /* Collision */ = { + isa = PBXGroup; + children = ( + 80BB8927141C3E5900F1753A /* b2BroadPhase.cpp */, + 80BB8928141C3E5900F1753A /* b2BroadPhase.h */, + 80BB8929141C3E5900F1753A /* b2CollideCircle.cpp */, + 80BB892A141C3E5900F1753A /* b2CollideEdge.cpp */, + 80BB892B141C3E5900F1753A /* b2CollidePolygon.cpp */, + 80BB892C141C3E5900F1753A /* b2Collision.cpp */, + 80BB892D141C3E5900F1753A /* b2Collision.h */, + 80BB892E141C3E5900F1753A /* b2Distance.cpp */, + 80BB892F141C3E5900F1753A /* b2Distance.h */, + 80BB8930141C3E5900F1753A /* b2DynamicTree.cpp */, + 80BB8931141C3E5900F1753A /* b2DynamicTree.h */, + 80BB8932141C3E5900F1753A /* b2TimeOfImpact.cpp */, + 80BB8933141C3E5900F1753A /* b2TimeOfImpact.h */, + 80BB8934141C3E5900F1753A /* Shapes */, + ); + path = Collision; + sourceTree = "<group>"; + }; + 80BB8934141C3E5900F1753A /* Shapes */ = { + isa = PBXGroup; + children = ( + 80BB8935141C3E5900F1753A /* b2ChainShape.cpp */, + 80BB8936141C3E5900F1753A /* b2ChainShape.h */, + 80BB8937141C3E5900F1753A /* b2CircleShape.cpp */, + 80BB8938141C3E5900F1753A /* b2CircleShape.h */, + 80BB8939141C3E5900F1753A /* b2EdgeShape.cpp */, + 80BB893A141C3E5900F1753A /* b2EdgeShape.h */, + 80BB893B141C3E5900F1753A /* b2PolygonShape.cpp */, + 80BB893C141C3E5900F1753A /* b2PolygonShape.h */, + 80BB893D141C3E5900F1753A /* b2Shape.h */, + ); + path = Shapes; + sourceTree = "<group>"; + }; + 80BB893E141C3E5900F1753A /* Common */ = { + isa = PBXGroup; + children = ( + 80BB893F141C3E5900F1753A /* b2BlockAllocator.cpp */, + 80BB8940141C3E5900F1753A /* b2BlockAllocator.h */, + 80BB8941141C3E5900F1753A /* b2Draw.cpp */, + 80BB8942141C3E5900F1753A /* b2Draw.h */, + 80BB8943141C3E5900F1753A /* b2GrowableStack.h */, + 80BB8944141C3E5900F1753A /* b2Math.cpp */, + 80BB8945141C3E5900F1753A /* b2Math.h */, + 80BB8946141C3E5900F1753A /* b2Settings.cpp */, + 80BB8947141C3E5900F1753A /* b2Settings.h */, + 80BB8948141C3E5900F1753A /* b2StackAllocator.cpp */, + 80BB8949141C3E5900F1753A /* b2StackAllocator.h */, + 80BB894A141C3E5900F1753A /* b2Timer.cpp */, + 80BB894B141C3E5900F1753A /* b2Timer.h */, + ); + path = Common; + sourceTree = "<group>"; + }; + 80BB894C141C3E5900F1753A /* Dynamics */ = { + isa = PBXGroup; + children = ( + 80BB894D141C3E5900F1753A /* b2Body.cpp */, + 80BB894E141C3E5900F1753A /* b2Body.h */, + 80BB894F141C3E5900F1753A /* b2ContactManager.cpp */, + 80BB8950141C3E5900F1753A /* b2ContactManager.h */, + 80BB8951141C3E5900F1753A /* b2Fixture.cpp */, + 80BB8952141C3E5900F1753A /* b2Fixture.h */, + 80BB8953141C3E5900F1753A /* b2Island.cpp */, + 80BB8954141C3E5900F1753A /* b2Island.h */, + 80BB8955141C3E5900F1753A /* b2TimeStep.h */, + 80BB8956141C3E5900F1753A /* b2World.cpp */, + 80BB8957141C3E5900F1753A /* b2World.h */, + 80BB8958141C3E5900F1753A /* b2WorldCallbacks.cpp */, + 80BB8959141C3E5900F1753A /* b2WorldCallbacks.h */, + 80BB895A141C3E5900F1753A /* Contacts */, + 80BB896D141C3E5900F1753A /* Joints */, + ); + path = Dynamics; + sourceTree = "<group>"; + }; + 80BB895A141C3E5900F1753A /* Contacts */ = { + isa = PBXGroup; + children = ( + 80BB895B141C3E5900F1753A /* b2ChainAndCircleContact.cpp */, + 80BB895C141C3E5900F1753A /* b2ChainAndCircleContact.h */, + 80BB895D141C3E5900F1753A /* b2ChainAndPolygonContact.cpp */, + 80BB895E141C3E5900F1753A /* b2ChainAndPolygonContact.h */, + 80BB895F141C3E5900F1753A /* b2CircleContact.cpp */, + 80BB8960141C3E5900F1753A /* b2CircleContact.h */, + 80BB8961141C3E5900F1753A /* b2Contact.cpp */, + 80BB8962141C3E5900F1753A /* b2Contact.h */, + 80BB8963141C3E5900F1753A /* b2ContactSolver.cpp */, + 80BB8964141C3E5900F1753A /* b2ContactSolver.h */, + 80BB8965141C3E5900F1753A /* b2EdgeAndCircleContact.cpp */, + 80BB8966141C3E5900F1753A /* b2EdgeAndCircleContact.h */, + 80BB8967141C3E5900F1753A /* b2EdgeAndPolygonContact.cpp */, + 80BB8968141C3E5900F1753A /* b2EdgeAndPolygonContact.h */, + 80BB8969141C3E5900F1753A /* b2PolygonAndCircleContact.cpp */, + 80BB896A141C3E5900F1753A /* b2PolygonAndCircleContact.h */, + 80BB896B141C3E5900F1753A /* b2PolygonContact.cpp */, + 80BB896C141C3E5900F1753A /* b2PolygonContact.h */, + ); + path = Contacts; + sourceTree = "<group>"; + }; + 80BB896D141C3E5900F1753A /* Joints */ = { + isa = PBXGroup; + children = ( + 80BB896E141C3E5900F1753A /* b2DistanceJoint.cpp */, + 80BB896F141C3E5900F1753A /* b2DistanceJoint.h */, + 80BB8970141C3E5900F1753A /* b2FrictionJoint.cpp */, + 80BB8971141C3E5900F1753A /* b2FrictionJoint.h */, + 80BB8972141C3E5900F1753A /* b2GearJoint.cpp */, + 80BB8973141C3E5900F1753A /* b2GearJoint.h */, + 80BB8974141C3E5900F1753A /* b2Joint.cpp */, + 80BB8975141C3E5900F1753A /* b2Joint.h */, + 80BB8976141C3E5900F1753A /* b2MouseJoint.cpp */, + 80BB8977141C3E5900F1753A /* b2MouseJoint.h */, + 80BB8978141C3E5900F1753A /* b2PrismaticJoint.cpp */, + 80BB8979141C3E5900F1753A /* b2PrismaticJoint.h */, + 80BB897A141C3E5900F1753A /* b2PulleyJoint.cpp */, + 80BB897B141C3E5900F1753A /* b2PulleyJoint.h */, + 80BB897C141C3E5900F1753A /* b2RevoluteJoint.cpp */, + 80BB897D141C3E5900F1753A /* b2RevoluteJoint.h */, + 80BB897E141C3E5900F1753A /* b2RopeJoint.cpp */, + 80BB897F141C3E5900F1753A /* b2RopeJoint.h */, + 80BB8980141C3E5900F1753A /* b2WeldJoint.cpp */, + 80BB8981141C3E5900F1753A /* b2WeldJoint.h */, + 80BB8982141C3E5900F1753A /* b2WheelJoint.cpp */, + 80BB8983141C3E5900F1753A /* b2WheelJoint.h */, + ); + path = Joints; + sourceTree = "<group>"; + }; + 80BB8984141C3E5900F1753A /* Rope */ = { + isa = PBXGroup; + children = ( + 80BB8985141C3E5900F1753A /* b2Rope.cpp */, + 80BB8986141C3E5900F1753A /* b2Rope.h */, + ); + path = Rope; + sourceTree = "<group>"; + }; + 80BB89E2141C3E6900F1753A /* glui */ = { + isa = PBXGroup; + children = ( + 80BB89E3141C3E6900F1753A /* algebra3.cpp */, + 80BB89E4141C3E6900F1753A /* algebra3.h */, + 80BB89E5141C3E6900F1753A /* arcball.cpp */, + 80BB89E6141C3E6900F1753A /* arcball.h */, + 80BB89E7141C3E6900F1753A /* CMakeLists.txt */, + 80BB89E8141C3E6900F1753A /* glui.cpp */, + 80BB89E9141C3E6900F1753A /* glui.h */, + 80BB89EA141C3E6900F1753A /* glui_add_controls.cpp */, + 80BB89EB141C3E6900F1753A /* glui_bitmap_img_data.cpp */, + 80BB89EC141C3E6900F1753A /* glui_bitmaps.cpp */, + 80BB89ED141C3E6900F1753A /* glui_button.cpp */, + 80BB89EE141C3E6900F1753A /* glui_checkbox.cpp */, + 80BB89EF141C3E6900F1753A /* glui_column.cpp */, + 80BB89F0141C3E6900F1753A /* glui_commandline.cpp */, + 80BB89F1141C3E6900F1753A /* glui_control.cpp */, + 80BB89F2141C3E6900F1753A /* glui_edittext.cpp */, + 80BB89F3141C3E6900F1753A /* glui_filebrowser.cpp */, + 80BB89F4141C3E6900F1753A /* glui_internal.h */, + 80BB89F5141C3E6900F1753A /* glui_internal_control.h */, + 80BB89F6141C3E6900F1753A /* glui_list.cpp */, + 80BB89F7141C3E6900F1753A /* glui_listbox.cpp */, + 80BB89F8141C3E6900F1753A /* glui_mouse_iaction.cpp */, + 80BB89F9141C3E6900F1753A /* glui_node.cpp */, + 80BB89FA141C3E6900F1753A /* glui_panel.cpp */, + 80BB89FB141C3E6900F1753A /* glui_radio.cpp */, + 80BB89FC141C3E6900F1753A /* glui_rollout.cpp */, + 80BB89FD141C3E6900F1753A /* glui_rotation.cpp */, + 80BB89FE141C3E6900F1753A /* glui_scrollbar.cpp */, + 80BB89FF141C3E6900F1753A /* glui_separator.cpp */, + 80BB8A00141C3E6900F1753A /* glui_spinner.cpp */, + 80BB8A01141C3E6900F1753A /* glui_statictext.cpp */, + 80BB8A02141C3E6900F1753A /* glui_string.cpp */, + 80BB8A03141C3E6900F1753A /* glui_textbox.cpp */, + 80BB8A04141C3E6900F1753A /* glui_translation.cpp */, + 80BB8A05141C3E6900F1753A /* glui_tree.cpp */, + 80BB8A06141C3E6900F1753A /* glui_treepanel.cpp */, + 80BB8A07141C3E6900F1753A /* glui_window.cpp */, + 80BB8A08141C3E6900F1753A /* quaternion.cpp */, + 80BB8A09141C3E6900F1753A /* quaternion.h */, + 80BB8A0A141C3E6900F1753A /* readme.txt */, + ); + name = glui; + path = ../../glui; + sourceTree = "<group>"; + }; + 80BB8A31141C3E7B00F1753A /* HelloWorld */ = { + isa = PBXGroup; + children = ( + 80BB8A32141C3E7B00F1753A /* CMakeLists.txt */, + 80BB8A33141C3E7B00F1753A /* HelloWorld.cpp */, + ); + name = HelloWorld; + path = ../../HelloWorld; + sourceTree = "<group>"; + }; + 80BB8A35141C3E8500F1753A /* Testbed */ = { + isa = PBXGroup; + children = ( + 80BB8A36141C3E8500F1753A /* CMakeLists.txt */, + 80BB8A37141C3E8500F1753A /* Framework */, + 80BB8A3D141C3E8500F1753A /* Tests */, + ); + name = Testbed; + path = ../../Testbed; + sourceTree = "<group>"; + }; + 80BB8A37141C3E8500F1753A /* Framework */ = { + isa = PBXGroup; + children = ( + 80BB8A38141C3E8500F1753A /* Main.cpp */, + 80BB8A39141C3E8500F1753A /* Render.cpp */, + 80BB8A3A141C3E8500F1753A /* Render.h */, + 80BB8A3B141C3E8500F1753A /* Test.cpp */, + 80BB8A3C141C3E8500F1753A /* Test.h */, + ); + path = Framework; + sourceTree = "<group>"; + }; + 80BB8A3D141C3E8500F1753A /* Tests */ = { + isa = PBXGroup; + children = ( + 80BB8A3E141C3E8500F1753A /* AddPair.h */, + 80BB8A3F141C3E8500F1753A /* ApplyForce.h */, + 80BB8A40141C3E8500F1753A /* BodyTypes.h */, + 80BB8A41141C3E8500F1753A /* Breakable.h */, + 80BB8A42141C3E8500F1753A /* Bridge.h */, + 80BB8A43141C3E8500F1753A /* BulletTest.h */, + 80BB8A44141C3E8500F1753A /* Cantilever.h */, + 80BB8A45141C3E8500F1753A /* Car.h */, + 80BB8A46141C3E8500F1753A /* Chain.h */, + 80BB8A47141C3E8500F1753A /* CharacterCollision.h */, + 80BB8A48141C3E8500F1753A /* CollisionFiltering.h */, + 80BB8A49141C3E8500F1753A /* CollisionProcessing.h */, + 80BB8A4A141C3E8500F1753A /* CompoundShapes.h */, + 80BB8A4B141C3E8600F1753A /* Confined.h */, + 80BB8A4C141C3E8600F1753A /* ContinuousTest.h */, + 80BB8A4D141C3E8600F1753A /* DistanceTest.h */, + 80BB8A4E141C3E8600F1753A /* Dominos.h */, + 80BB8A4F141C3E8600F1753A /* DumpShell.h */, + 80BB8A50141C3E8600F1753A /* DynamicTreeTest.h */, + 80BB8A51141C3E8600F1753A /* EdgeShapes.h */, + 80BB8A52141C3E8600F1753A /* EdgeTest.h */, + 80BB8A53141C3E8600F1753A /* Gears.h */, + 80BB8A54141C3E8600F1753A /* OneSidedPlatform.h */, + 80BB8A55141C3E8600F1753A /* Pinball.h */, + 80BB8A56141C3E8600F1753A /* PolyCollision.h */, + 80BB8A57141C3E8600F1753A /* PolyShapes.h */, + 80BB8A58141C3E8600F1753A /* Prismatic.h */, + 80BB8A59141C3E8600F1753A /* Pulleys.h */, + 80BB8A5A141C3E8600F1753A /* Pyramid.h */, + 80BB8A5B141C3E8600F1753A /* RayCast.h */, + 80BB8A5C141C3E8600F1753A /* Revolute.h */, + 80BB8A5D141C3E8600F1753A /* Rope.h */, + 80BB8A5E141C3E8600F1753A /* RopeJoint.h */, + 80BB8A5F141C3E8600F1753A /* SensorTest.h */, + 80BB8A60141C3E8600F1753A /* ShapeEditing.h */, + 80BB8A61141C3E8600F1753A /* SliderCrank.h */, + 80BB8A62141C3E8600F1753A /* SphereStack.h */, + 80BB8A63141C3E8600F1753A /* TestEntries.cpp */, + 80BB8A64141C3E8600F1753A /* TheoJansen.h */, + 80BB8A65141C3E8600F1753A /* Tiles.h */, + 80BB8A66141C3E8600F1753A /* TimeOfImpact.h */, + 80154ACD141DED6B00C8251F /* Tumbler.h */, + 80BB8A67141C3E8600F1753A /* VaryingFriction.h */, + 80BB8A68141C3E8600F1753A /* VaryingRestitution.h */, + 80BB8A69141C3E8600F1753A /* VerticalStack.h */, + 80BB8A6A141C3E8600F1753A /* Web.h */, + ); + path = Tests; + sourceTree = "<group>"; + }; + 80FF01C7141C3D980059E59D = { + isa = PBXGroup; + children = ( + 80BB8A7A141C3FA700F1753A /* OpenGL.framework */, + 80BB8A78141C3F9C00F1753A /* GLUT.framework */, + 80BB8A35141C3E8500F1753A /* Testbed */, + 80BB8A31141C3E7B00F1753A /* HelloWorld */, + 80BB89E2141C3E6900F1753A /* glui */, + 80BB8922141C3E5900F1753A /* Box2D */, + 80FF01D3141C3D980059E59D /* Products */, + ); + sourceTree = "<group>"; + }; + 80FF01D3141C3D980059E59D /* Products */ = { + isa = PBXGroup; + children = ( + 80FF01D2141C3D980059E59D /* libBox2D.a */, + 80BB8901141C3E1800F1753A /* libGLUI.a */, + 80BB890A141C3E2700F1753A /* HelloWorld */, + 80BB8918141C3E3600F1753A /* Testbed */, + ); + name = Products; + sourceTree = "<group>"; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 80BB88FF141C3E1800F1753A /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 80BB8A0C141C3E6900F1753A /* algebra3.h in Headers */, + 80BB8A0E141C3E6900F1753A /* arcball.h in Headers */, + 80BB8A10141C3E6900F1753A /* glui.h in Headers */, + 80BB8A1B141C3E6900F1753A /* glui_internal.h in Headers */, + 80BB8A1C141C3E6900F1753A /* glui_internal_control.h in Headers */, + 80BB8A30141C3E6900F1753A /* quaternion.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 80FF01D0141C3D980059E59D /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 80BB8987141C3E5900F1753A /* Box2D.h in Headers */, + 80BB8989141C3E5900F1753A /* b2BroadPhase.h in Headers */, + 80BB898E141C3E5900F1753A /* b2Collision.h in Headers */, + 80BB8990141C3E5900F1753A /* b2Distance.h in Headers */, + 80BB8992141C3E5900F1753A /* b2DynamicTree.h in Headers */, + 80BB8994141C3E5900F1753A /* b2TimeOfImpact.h in Headers */, + 80BB8996141C3E5900F1753A /* b2ChainShape.h in Headers */, + 80BB8998141C3E5900F1753A /* b2CircleShape.h in Headers */, + 80BB899A141C3E5900F1753A /* b2EdgeShape.h in Headers */, + 80BB899C141C3E5900F1753A /* b2PolygonShape.h in Headers */, + 80BB899D141C3E5900F1753A /* b2Shape.h in Headers */, + 80BB899F141C3E5900F1753A /* b2BlockAllocator.h in Headers */, + 80BB89A1141C3E5900F1753A /* b2Draw.h in Headers */, + 80BB89A2141C3E5900F1753A /* b2GrowableStack.h in Headers */, + 80BB89A4141C3E5900F1753A /* b2Math.h in Headers */, + 80BB89A6141C3E5900F1753A /* b2Settings.h in Headers */, + 80BB89A8141C3E5900F1753A /* b2StackAllocator.h in Headers */, + 80BB89AA141C3E5900F1753A /* b2Timer.h in Headers */, + 80BB89AC141C3E5900F1753A /* b2Body.h in Headers */, + 80BB89AE141C3E5900F1753A /* b2ContactManager.h in Headers */, + 80BB89B0141C3E5900F1753A /* b2Fixture.h in Headers */, + 80BB89B2141C3E5900F1753A /* b2Island.h in Headers */, + 80BB89B3141C3E5900F1753A /* b2TimeStep.h in Headers */, + 80BB89B5141C3E5900F1753A /* b2World.h in Headers */, + 80BB89B7141C3E5900F1753A /* b2WorldCallbacks.h in Headers */, + 80BB89B9141C3E5900F1753A /* b2ChainAndCircleContact.h in Headers */, + 80BB89BB141C3E5900F1753A /* b2ChainAndPolygonContact.h in Headers */, + 80BB89BD141C3E5900F1753A /* b2CircleContact.h in Headers */, + 80BB89BF141C3E5900F1753A /* b2Contact.h in Headers */, + 80BB89C1141C3E5900F1753A /* b2ContactSolver.h in Headers */, + 80BB89C3141C3E5900F1753A /* b2EdgeAndCircleContact.h in Headers */, + 80BB89C5141C3E5900F1753A /* b2EdgeAndPolygonContact.h in Headers */, + 80BB89C7141C3E5900F1753A /* b2PolygonAndCircleContact.h in Headers */, + 80BB89C9141C3E5900F1753A /* b2PolygonContact.h in Headers */, + 80BB89CB141C3E5900F1753A /* b2DistanceJoint.h in Headers */, + 80BB89CD141C3E5900F1753A /* b2FrictionJoint.h in Headers */, + 80BB89CF141C3E5900F1753A /* b2GearJoint.h in Headers */, + 80BB89D1141C3E5900F1753A /* b2Joint.h in Headers */, + 80BB89D3141C3E5900F1753A /* b2MouseJoint.h in Headers */, + 80BB89D5141C3E5900F1753A /* b2PrismaticJoint.h in Headers */, + 80BB89D7141C3E5900F1753A /* b2PulleyJoint.h in Headers */, + 80BB89D9141C3E5900F1753A /* b2RevoluteJoint.h in Headers */, + 80BB89DB141C3E5900F1753A /* b2RopeJoint.h in Headers */, + 80BB89DD141C3E5900F1753A /* b2WeldJoint.h in Headers */, + 80BB89DF141C3E5900F1753A /* b2WheelJoint.h in Headers */, + 80BB89E1141C3E5900F1753A /* b2Rope.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 80BB8900141C3E1800F1753A /* GLUI */ = { + isa = PBXNativeTarget; + buildConfigurationList = 80BB8904141C3E1800F1753A /* Build configuration list for PBXNativeTarget "GLUI" */; + buildPhases = ( + 80BB88FD141C3E1800F1753A /* Sources */, + 80BB88FE141C3E1800F1753A /* Frameworks */, + 80BB88FF141C3E1800F1753A /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = GLUI; + productName = GLUI; + productReference = 80BB8901141C3E1800F1753A /* libGLUI.a */; + productType = "com.apple.product-type.library.static"; + }; + 80BB8909141C3E2600F1753A /* HelloWorld */ = { + isa = PBXNativeTarget; + buildConfigurationList = 80BB8911141C3E2700F1753A /* Build configuration list for PBXNativeTarget "HelloWorld" */; + buildPhases = ( + 80BB8906141C3E2600F1753A /* Sources */, + 80BB8907141C3E2600F1753A /* Frameworks */, + 80BB8908141C3E2600F1753A /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + 80BB8A70141C3EA100F1753A /* PBXTargetDependency */, + ); + name = HelloWorld; + productName = HelloWorld; + productReference = 80BB890A141C3E2700F1753A /* HelloWorld */; + productType = "com.apple.product-type.tool"; + }; + 80BB8917141C3E3600F1753A /* Testbed */ = { + isa = PBXNativeTarget; + buildConfigurationList = 80BB891F141C3E3600F1753A /* Build configuration list for PBXNativeTarget "Testbed" */; + buildPhases = ( + 80BB8914141C3E3600F1753A /* Sources */, + 80BB8915141C3E3600F1753A /* Frameworks */, + 80BB8916141C3E3600F1753A /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + 80BB8A72141C3EA800F1753A /* PBXTargetDependency */, + 80BB8A74141C3EA800F1753A /* PBXTargetDependency */, + ); + name = Testbed; + productName = Testbed; + productReference = 80BB8918141C3E3600F1753A /* Testbed */; + productType = "com.apple.product-type.tool"; + }; + 80FF01D1141C3D980059E59D /* Box2D */ = { + isa = PBXNativeTarget; + buildConfigurationList = 80FF01D6141C3D980059E59D /* Build configuration list for PBXNativeTarget "Box2D" */; + buildPhases = ( + 80FF01CE141C3D980059E59D /* Sources */, + 80FF01CF141C3D980059E59D /* Frameworks */, + 80FF01D0141C3D980059E59D /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Box2D; + productName = Box2D; + productReference = 80FF01D2141C3D980059E59D /* libBox2D.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 80FF01C9141C3D980059E59D /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 80FF01CC141C3D980059E59D /* Build configuration list for PBXProject "Box2D" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 80FF01C7141C3D980059E59D; + productRefGroup = 80FF01D3141C3D980059E59D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 80FF01D1141C3D980059E59D /* Box2D */, + 80BB8900141C3E1800F1753A /* GLUI */, + 80BB8909141C3E2600F1753A /* HelloWorld */, + 80BB8917141C3E3600F1753A /* Testbed */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 80BB88FD141C3E1800F1753A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 80BB8A0B141C3E6900F1753A /* algebra3.cpp in Sources */, + 80BB8A0D141C3E6900F1753A /* arcball.cpp in Sources */, + 80BB8A0F141C3E6900F1753A /* glui.cpp in Sources */, + 80BB8A11141C3E6900F1753A /* glui_add_controls.cpp in Sources */, + 80BB8A12141C3E6900F1753A /* glui_bitmap_img_data.cpp in Sources */, + 80BB8A13141C3E6900F1753A /* glui_bitmaps.cpp in Sources */, + 80BB8A14141C3E6900F1753A /* glui_button.cpp in Sources */, + 80BB8A15141C3E6900F1753A /* glui_checkbox.cpp in Sources */, + 80BB8A16141C3E6900F1753A /* glui_column.cpp in Sources */, + 80BB8A17141C3E6900F1753A /* glui_commandline.cpp in Sources */, + 80BB8A18141C3E6900F1753A /* glui_control.cpp in Sources */, + 80BB8A19141C3E6900F1753A /* glui_edittext.cpp in Sources */, + 80BB8A1A141C3E6900F1753A /* glui_filebrowser.cpp in Sources */, + 80BB8A1D141C3E6900F1753A /* glui_list.cpp in Sources */, + 80BB8A1E141C3E6900F1753A /* glui_listbox.cpp in Sources */, + 80BB8A1F141C3E6900F1753A /* glui_mouse_iaction.cpp in Sources */, + 80BB8A20141C3E6900F1753A /* glui_node.cpp in Sources */, + 80BB8A21141C3E6900F1753A /* glui_panel.cpp in Sources */, + 80BB8A22141C3E6900F1753A /* glui_radio.cpp in Sources */, + 80BB8A23141C3E6900F1753A /* glui_rollout.cpp in Sources */, + 80BB8A24141C3E6900F1753A /* glui_rotation.cpp in Sources */, + 80BB8A25141C3E6900F1753A /* glui_scrollbar.cpp in Sources */, + 80BB8A26141C3E6900F1753A /* glui_separator.cpp in Sources */, + 80BB8A27141C3E6900F1753A /* glui_spinner.cpp in Sources */, + 80BB8A28141C3E6900F1753A /* glui_statictext.cpp in Sources */, + 80BB8A29141C3E6900F1753A /* glui_string.cpp in Sources */, + 80BB8A2A141C3E6900F1753A /* glui_textbox.cpp in Sources */, + 80BB8A2B141C3E6900F1753A /* glui_translation.cpp in Sources */, + 80BB8A2C141C3E6900F1753A /* glui_tree.cpp in Sources */, + 80BB8A2D141C3E6900F1753A /* glui_treepanel.cpp in Sources */, + 80BB8A2E141C3E6900F1753A /* glui_window.cpp in Sources */, + 80BB8A2F141C3E6900F1753A /* quaternion.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 80BB8906141C3E2600F1753A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 80BB8A34141C3E7B00F1753A /* HelloWorld.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 80BB8914141C3E3600F1753A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 80BB8A6B141C3E8600F1753A /* Main.cpp in Sources */, + 80BB8A6C141C3E8600F1753A /* Render.cpp in Sources */, + 80BB8A6D141C3E8600F1753A /* Test.cpp in Sources */, + 80BB8A6E141C3E8600F1753A /* TestEntries.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 80FF01CE141C3D980059E59D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 80BB8988141C3E5900F1753A /* b2BroadPhase.cpp in Sources */, + 80BB898A141C3E5900F1753A /* b2CollideCircle.cpp in Sources */, + 80BB898B141C3E5900F1753A /* b2CollideEdge.cpp in Sources */, + 80BB898C141C3E5900F1753A /* b2CollidePolygon.cpp in Sources */, + 80BB898D141C3E5900F1753A /* b2Collision.cpp in Sources */, + 80BB898F141C3E5900F1753A /* b2Distance.cpp in Sources */, + 80BB8991141C3E5900F1753A /* b2DynamicTree.cpp in Sources */, + 80BB8993141C3E5900F1753A /* b2TimeOfImpact.cpp in Sources */, + 80BB8995141C3E5900F1753A /* b2ChainShape.cpp in Sources */, + 80BB8997141C3E5900F1753A /* b2CircleShape.cpp in Sources */, + 80BB8999141C3E5900F1753A /* b2EdgeShape.cpp in Sources */, + 80BB899B141C3E5900F1753A /* b2PolygonShape.cpp in Sources */, + 80BB899E141C3E5900F1753A /* b2BlockAllocator.cpp in Sources */, + 80BB89A0141C3E5900F1753A /* b2Draw.cpp in Sources */, + 80BB89A3141C3E5900F1753A /* b2Math.cpp in Sources */, + 80BB89A5141C3E5900F1753A /* b2Settings.cpp in Sources */, + 80BB89A7141C3E5900F1753A /* b2StackAllocator.cpp in Sources */, + 80BB89A9141C3E5900F1753A /* b2Timer.cpp in Sources */, + 80BB89AB141C3E5900F1753A /* b2Body.cpp in Sources */, + 80BB89AD141C3E5900F1753A /* b2ContactManager.cpp in Sources */, + 80BB89AF141C3E5900F1753A /* b2Fixture.cpp in Sources */, + 80BB89B1141C3E5900F1753A /* b2Island.cpp in Sources */, + 80BB89B4141C3E5900F1753A /* b2World.cpp in Sources */, + 80BB89B6141C3E5900F1753A /* b2WorldCallbacks.cpp in Sources */, + 80BB89B8141C3E5900F1753A /* b2ChainAndCircleContact.cpp in Sources */, + 80BB89BA141C3E5900F1753A /* b2ChainAndPolygonContact.cpp in Sources */, + 80BB89BC141C3E5900F1753A /* b2CircleContact.cpp in Sources */, + 80BB89BE141C3E5900F1753A /* b2Contact.cpp in Sources */, + 80BB89C0141C3E5900F1753A /* b2ContactSolver.cpp in Sources */, + 80BB89C2141C3E5900F1753A /* b2EdgeAndCircleContact.cpp in Sources */, + 80BB89C4141C3E5900F1753A /* b2EdgeAndPolygonContact.cpp in Sources */, + 80BB89C6141C3E5900F1753A /* b2PolygonAndCircleContact.cpp in Sources */, + 80BB89C8141C3E5900F1753A /* b2PolygonContact.cpp in Sources */, + 80BB89CA141C3E5900F1753A /* b2DistanceJoint.cpp in Sources */, + 80BB89CC141C3E5900F1753A /* b2FrictionJoint.cpp in Sources */, + 80BB89CE141C3E5900F1753A /* b2GearJoint.cpp in Sources */, + 80BB89D0141C3E5900F1753A /* b2Joint.cpp in Sources */, + 80BB89D2141C3E5900F1753A /* b2MouseJoint.cpp in Sources */, + 80BB89D4141C3E5900F1753A /* b2PrismaticJoint.cpp in Sources */, + 80BB89D6141C3E5900F1753A /* b2PulleyJoint.cpp in Sources */, + 80BB89D8141C3E5900F1753A /* b2RevoluteJoint.cpp in Sources */, + 80BB89DA141C3E5900F1753A /* b2RopeJoint.cpp in Sources */, + 80BB89DC141C3E5900F1753A /* b2WeldJoint.cpp in Sources */, + 80BB89DE141C3E5900F1753A /* b2WheelJoint.cpp in Sources */, + 80BB89E0141C3E5900F1753A /* b2Rope.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 80BB8A70141C3EA100F1753A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 80FF01D1141C3D980059E59D /* Box2D */; + targetProxy = 80BB8A6F141C3EA100F1753A /* PBXContainerItemProxy */; + }; + 80BB8A72141C3EA800F1753A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 80FF01D1141C3D980059E59D /* Box2D */; + targetProxy = 80BB8A71141C3EA800F1753A /* PBXContainerItemProxy */; + }; + 80BB8A74141C3EA800F1753A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 80BB8900141C3E1800F1753A /* GLUI */; + targetProxy = 80BB8A73141C3EA800F1753A /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 80BB8902141C3E1800F1753A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + EXECUTABLE_PREFIX = lib; + GCC_WARN_INHIBIT_ALL_WARNINGS = YES; + GCC_WARN_UNUSED_VALUE = NO; + GCC_WARN_UNUSED_VARIABLE = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 80BB8903141C3E1800F1753A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + EXECUTABLE_PREFIX = lib; + GCC_WARN_INHIBIT_ALL_WARNINGS = YES; + GCC_WARN_UNUSED_VALUE = NO; + GCC_WARN_UNUSED_VARIABLE = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + 80BB8912141C3E2700F1753A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 80BB8913141C3E2700F1753A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + 80BB8920141C3E3600F1753A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_WARN_UNUSED_VALUE = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 80BB8921141C3E3600F1753A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_WARN_UNUSED_VALUE = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + 80FF01D4141C3D980059E59D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ../..; + MACOSX_DEPLOYMENT_TARGET = 10.7; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + 80FF01D5141C3D980059E59D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ../..; + MACOSX_DEPLOYMENT_TARGET = 10.7; + SDKROOT = macosx; + }; + name = Release; + }; + 80FF01D7141C3D980059E59D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + EXECUTABLE_PREFIX = lib; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 80FF01D8141C3D980059E59D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + EXECUTABLE_PREFIX = lib; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 80BB8904141C3E1800F1753A /* Build configuration list for PBXNativeTarget "GLUI" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 80BB8902141C3E1800F1753A /* Debug */, + 80BB8903141C3E1800F1753A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 80BB8911141C3E2700F1753A /* Build configuration list for PBXNativeTarget "HelloWorld" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 80BB8912141C3E2700F1753A /* Debug */, + 80BB8913141C3E2700F1753A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 80BB891F141C3E3600F1753A /* Build configuration list for PBXNativeTarget "Testbed" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 80BB8920141C3E3600F1753A /* Debug */, + 80BB8921141C3E3600F1753A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 80FF01CC141C3D980059E59D /* Build configuration list for PBXProject "Box2D" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 80FF01D4141C3D980059E59D /* Debug */, + 80FF01D5141C3D980059E59D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 80FF01D6141C3D980059E59D /* Build configuration list for PBXNativeTarget "Box2D" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 80FF01D7141C3D980059E59D /* Debug */, + 80FF01D8141C3D980059E59D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 80FF01C9141C3D980059E59D /* Project object */; +} diff --git a/tests/box2d/Build/xcode4/Box2D.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/tests/box2d/Build/xcode4/Box2D.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100755 index 00000000..9641d889 --- /dev/null +++ b/tests/box2d/Build/xcode4/Box2D.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Workspace + version = "1.0"> + <FileRef + location = "self:Box2D.xcodeproj"> + </FileRef> +</Workspace> diff --git a/tests/box2d/Building.txt b/tests/box2d/Building.txt new file mode 100755 index 00000000..fa3741f1 --- /dev/null +++ b/tests/box2d/Building.txt @@ -0,0 +1,37 @@ +The Build folder contains custom made project files for Visual Studio 2010 and XCode4.
+
+For other platforms you need to run premake in this directory. You can get premake here:
+http://industriousone.com/premake
+
+For example, on Linux, you would type:
+premake4 gmake
+
+This will create a gmake folder in the Build directory. From there you can run:
+make config="debug"
+
+If you have build problems, you can post a question here:
+http://box2d.org/forum/viewforum.php?f=7
+
+=============== OLD METHOD ====================
+
+Box2D uses CMake to describe the build in a platform independent manner.
+
+First download and install cmake from cmake.org
+
+For Microsoft Visual Studio:
+- Run the cmake-gui
+- Set the source directory to the path of Box2D on your PC (the folder that contains this file).
+- Set the build directory to be the path of Box2D/Build on your PC.
+- Press the Configure button and select your version of Visual Studio.
+- You may have to press the Configure button again.
+- Press the Generate button.
+- Open Box2D/Build/Box2D.sln.
+- Set the Testbed or HelloWorld as your startup project.
+- Press F5 or Ctrl-F5 to run.
+
+For Unix platforms, say the following on a terminal: (Replace $BOX2DPATH with the directory where this file is located.)
+ cd $BOX2DPATH/Build
+ cmake -DBOX2D_INSTALL=ON -DBOX2D_BUILD_SHARED=ON ..
+ make
+ make install
+You might want to add -DCMAKE_INSTALL_PREFIX=/opt/Box2D or similar to the cmake call to change the installation location. make install might need sudo.
diff --git a/tests/box2d/CMakeLists.txt b/tests/box2d/CMakeLists.txt new file mode 100755 index 00000000..a9dc06cb --- /dev/null +++ b/tests/box2d/CMakeLists.txt @@ -0,0 +1,35 @@ +cmake_minimum_required(VERSION 2.6) + +project(Box2D) + +if(UNIX) + set(BOX2D_INSTALL_BY_DEFAULT ON) +else(UNIX) + set(BOX2D_INSTALL_BY_DEFAULT OFF) +endif(UNIX) + +option(BOX2D_INSTALL "Install Box2D libs, includes, and CMake scripts" ${BOX2D_INSTALL_BY_DEFAULT}) +option(BOX2D_INSTALL_DOC "Install Box2D documentation" OFF) +option(BOX2D_BUILD_SHARED "Build Box2D shared libraries" OFF) +option(BOX2D_BUILD_STATIC "Build Box2D static libraries" ON) +option(BOX2D_BUILD_EXAMPLES "Build Box2D examples" ON) + +set(BOX2D_VERSION 2.1.0) + +# The Box2D library. +add_subdirectory(Box2D) + +if(BOX2D_BUILD_EXAMPLES) + # HelloWorld console example. + add_subdirectory(HelloWorld) + + # Testbed and dependencies. + find_package(OpenGL REQUIRED) + add_subdirectory(freeglut) + add_subdirectory(glui) + add_subdirectory(Testbed) +endif(BOX2D_BUILD_EXAMPLES) + +if(BOX2D_INSTALL_DOC) + install(DIRECTORY Documentation DESTINATION share/doc/Box2D PATTERN ".svn" EXCLUDE) +endif(BOX2D_INSTALL_DOC)
\ No newline at end of file diff --git a/tests/box2d/HelloWorld/CMakeLists.txt b/tests/box2d/HelloWorld/CMakeLists.txt new file mode 100755 index 00000000..c6ae2b2f --- /dev/null +++ b/tests/box2d/HelloWorld/CMakeLists.txt @@ -0,0 +1,4 @@ +# Hello World examples
+include_directories (${Box2D_SOURCE_DIR})
+add_executable(HelloWorld HelloWorld.cpp)
+target_link_libraries (HelloWorld Box2D)
diff --git a/tests/box2d/HelloWorld/HelloWorld.cpp b/tests/box2d/HelloWorld/HelloWorld.cpp new file mode 100755 index 00000000..b8e04384 --- /dev/null +++ b/tests/box2d/HelloWorld/HelloWorld.cpp @@ -0,0 +1,106 @@ +/*
+* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Box2D.h>
+
+#include <cstdio>
+using namespace std;
+
+// This is a simple example of building and running a simulation
+// using Box2D. Here we create a large ground box and a small dynamic
+// box.
+// There are no graphics for this example. Box2D is meant to be used
+// with your rendering engine in your game engine.
+int main(int argc, char** argv)
+{
+ B2_NOT_USED(argc);
+ B2_NOT_USED(argv);
+
+ // Define the gravity vector.
+ b2Vec2 gravity(0.0f, -10.0f);
+
+ // Construct a world object, which will hold and simulate the rigid bodies.
+ b2World world(gravity);
+
+ // Define the ground body.
+ b2BodyDef groundBodyDef;
+ groundBodyDef.position.Set(0.0f, -10.0f);
+
+ // Call the body factory which allocates memory for the ground body
+ // from a pool and creates the ground box shape (also from a pool).
+ // The body is also added to the world.
+ b2Body* groundBody = world.CreateBody(&groundBodyDef);
+
+ // Define the ground box shape.
+ b2PolygonShape groundBox;
+
+ // The extents are the half-widths of the box.
+ groundBox.SetAsBox(50.0f, 10.0f);
+
+ // Add the ground fixture to the ground body.
+ groundBody->CreateFixture(&groundBox, 0.0f);
+
+ // Define the dynamic body. We set its position and call the body factory.
+ b2BodyDef bodyDef;
+ bodyDef.type = b2_dynamicBody;
+ bodyDef.position.Set(0.0f, 4.0f);
+ b2Body* body = world.CreateBody(&bodyDef);
+
+ // Define another box shape for our dynamic body.
+ b2PolygonShape dynamicBox;
+ dynamicBox.SetAsBox(1.0f, 1.0f);
+
+ // Define the dynamic body fixture.
+ b2FixtureDef fixtureDef;
+ fixtureDef.shape = &dynamicBox;
+
+ // Set the box density to be non-zero, so it will be dynamic.
+ fixtureDef.density = 1.0f;
+
+ // Override the default friction.
+ fixtureDef.friction = 0.3f;
+
+ // Add the shape to the body.
+ body->CreateFixture(&fixtureDef);
+
+ // Prepare for simulation. Typically we use a time step of 1/60 of a
+ // second (60Hz) and 10 iterations. This provides a high quality simulation
+ // in most game scenarios.
+ float32 timeStep = 1.0f / 60.0f;
+ int32 velocityIterations = 6;
+ int32 positionIterations = 2;
+
+ // This is our little game loop.
+ for (int32 i = 0; i < 60; ++i)
+ {
+ // Instruct the world to perform a single step of simulation.
+ // It is generally best to keep the time step and iterations fixed.
+ world.Step(timeStep, velocityIterations, positionIterations);
+
+ // Now print the position and angle of the body.
+ b2Vec2 position = body->GetPosition();
+ float32 angle = body->GetAngle();
+
+ printf("%4.2f %4.2f %4.2f\n", position.x, position.y, angle);
+ }
+
+ // When the world destructor is called, all bodies and joints are freed. This can
+ // create orphaned pointers, so be careful about your world management.
+
+ return 0;
+}
diff --git a/tests/box2d/License.txt b/tests/box2d/License.txt new file mode 100755 index 00000000..622772e5 --- /dev/null +++ b/tests/box2d/License.txt @@ -0,0 +1,18 @@ +Copyright (c) 2006-2010 Erin Catto http://www.gphysics.com
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not
+claim that you wrote the original software. If you use this software
+in a product, an acknowledgment in the product documentation would be
+appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be
+misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
+
diff --git a/tests/box2d/Makefile b/tests/box2d/Makefile new file mode 100644 index 00000000..13f62093 --- /dev/null +++ b/tests/box2d/Makefile @@ -0,0 +1,63 @@ +# Makefile for generating a Box2D library using Emscripten. + +O = Box2D +OBJECTS = \ + $(O)/Collision/b2BroadPhase.o \ + $(O)/Collision/b2CollideCircle.o \ + $(O)/Collision/b2CollideEdge.o \ + $(O)/Collision/b2CollidePolygon.o \ + $(O)/Collision/b2Collision.o \ + $(O)/Collision/b2Distance.o \ + $(O)/Collision/b2DynamicTree.o \ + $(O)/Collision/b2TimeOfImpact.o \ + $(O)/Collision/Shapes/b2ChainShape.o \ + $(O)/Collision/Shapes/b2CircleShape.o \ + $(O)/Collision/Shapes/b2EdgeShape.o \ + $(O)/Collision/Shapes/b2PolygonShape.o \ + $(O)/Common/b2BlockAllocator.o \ + $(O)/Common/b2Draw.o \ + $(O)/Common/b2Math.o \ + $(O)/Common/b2Settings.o \ + $(O)/Common/b2StackAllocator.o \ + $(O)/Common/b2Timer.o \ + $(O)/Dynamics/b2Body.o \ + $(O)/Dynamics/b2ContactManager.o \ + $(O)/Dynamics/b2Fixture.o \ + $(O)/Dynamics/b2Island.o \ + $(O)/Dynamics/b2World.o \ + $(O)/Dynamics/b2WorldCallbacks.o \ + $(O)/Dynamics/Contacts/b2ChainAndCircleContact.o \ + $(O)/Dynamics/Contacts/b2ChainAndPolygonContact.o \ + $(O)/Dynamics/Contacts/b2CircleContact.o \ + $(O)/Dynamics/Contacts/b2Contact.o \ + $(O)/Dynamics/Contacts/b2ContactSolver.o \ + $(O)/Dynamics/Contacts/b2EdgeAndCircleContact.o \ + $(O)/Dynamics/Contacts/b2EdgeAndPolygonContact.o \ + $(O)/Dynamics/Contacts/b2PolygonAndCircleContact.o \ + $(O)/Dynamics/Contacts/b2PolygonContact.o \ + $(O)/Dynamics/Joints/b2DistanceJoint.o \ + $(O)/Dynamics/Joints/b2FrictionJoint.o \ + $(O)/Dynamics/Joints/b2GearJoint.o \ + $(O)/Dynamics/Joints/b2Joint.o \ + $(O)/Dynamics/Joints/b2MouseJoint.o \ + $(O)/Dynamics/Joints/b2PrismaticJoint.o \ + $(O)/Dynamics/Joints/b2PulleyJoint.o \ + $(O)/Dynamics/Joints/b2RevoluteJoint.o \ + $(O)/Dynamics/Joints/b2RopeJoint.o \ + $(O)/Dynamics/Joints/b2WeldJoint.o \ + $(O)/Dynamics/Joints/b2WheelJoint.o \ + $(O)/Rope/b2Rope.o + +all: box2d.o + +OPTS = -O2 + +%.o: %.cpp + $(CXX) -I. $< -o $@ $(OPTS) + +box2d.o: $(OBJECTS) + $(CXX) -o $@ $(OBJECTS) $(OPTS) + +clean: + rm box2d.o + diff --git a/tests/box2d/Readme.txt b/tests/box2d/Readme.txt new file mode 100755 index 00000000..d97240a2 --- /dev/null +++ b/tests/box2d/Readme.txt @@ -0,0 +1,19 @@ +Box2D Version 2.1
+
+Welcome to Box2D!
+
+Box2D is a 2D physics engine for games.
+
+For help with Box2D, please visit http://www.box2d.org. There is a forum there where you may post your questions.
+
+Please see Building.txt to learn how to build Box2D and run the testbed.
+
+To run the demos, set "Testbed" as your startup project and press F5. Some test bed commands are:
+- 'r' to reset the current test
+- SPACE to launch a bomb
+- arrow keys to pan
+- 'x' and 'z' to zoom in/out
+- use the mouse to click and drag objects
+
+Erin Catto
+http://www.box2d.org
diff --git a/tests/box2d/Testbed/CMakeLists.txt b/tests/box2d/Testbed/CMakeLists.txt new file mode 100755 index 00000000..b030a484 --- /dev/null +++ b/tests/box2d/Testbed/CMakeLists.txt @@ -0,0 +1,92 @@ +# Some flags for Freeglut and GLUI.
+add_definitions( -DFREEGLUT_EXPORTS -DFREEGLUT_STATIC -D_CRT_SECURE_NO_WARNINGS )
+
+# Define the framework files.
+set(Testbed_Framework_SRCS
+ Framework/Main.cpp
+ Framework/Render.cpp
+ Framework/Render.h
+ Framework/Test.cpp
+ Framework/Test.h
+)
+
+#define the test files.
+set(Testbed_Tests_SRCS
+ Tests/TestEntries.cpp
+ Tests/AddPair.h
+ Tests/ApplyForce.h
+ Tests/BodyTypes.h
+ Tests/Breakable.h
+ Tests/Bridge.h
+ Tests/BulletTest.h
+ Tests/Cantilever.h
+ Tests/Car.h
+ Tests/Chain.h
+ Tests/CharacterCollision.h
+ Tests/CollisionFiltering.h
+ Tests/CollisionProcessing.h
+ Tests/CompoundShapes.h
+ Tests/Confined.h
+ Tests/ContinuousTest.h
+ Tests/DistanceTest.h
+ Tests/Dominos.h
+ Tests/DumpShell.h
+ Tests/DynamicTreeTest.h
+ Tests/EdgeShapes.h
+ Tests/EdgeTest.h
+ Tests/Gears.h
+ Tests/OneSidedPlatform.h
+ Tests/Pinball.h
+ Tests/PolyCollision.h
+ Tests/PolyShapes.h
+ Tests/Prismatic.h
+ Tests/Pulleys.h
+ Tests/Pyramid.h
+ Tests/RayCast.h
+ Tests/Revolute.h
+ Tests/Rope.h
+ Tests/RopeJoint.h
+ Tests/SensorTest.h
+ Tests/ShapeEditing.h
+ Tests/SliderCrank.h
+ Tests/SphereStack.h
+ Tests/TheoJansen.h
+ Tests/Tiles.h
+ Tests/TimeOfImpact.h
+ Tests/VaryingFriction.h
+ Tests/VaryingRestitution.h
+ Tests/VerticalStack.h
+ Tests/Web.h
+)
+
+# These are used to create visual studio folders.
+source_group(Framework FILES ${Testbed_Framework_SRCS})
+source_group(Tests FILES ${Testbed_Tests_SRCS})
+
+include_directories (
+ ${OPENGL_INCLUDE_DIR}
+ ${Box2D_SOURCE_DIR}
+)
+
+if(APPLE)
+ # We are not using the Apple's framework version, but X11's
+ include_directories( /usr/X11/include )
+ link_directories( /usr/X11/lib )
+ set (OPENGL_LIBRARIES GL GLU GLUT X11)
+elseif(WIN32)
+ set (ADDITIONAL_LIBRARIES winmm)
+endif(APPLE)
+
+add_executable(Testbed
+ ${Testbed_Framework_SRCS}
+ ${Testbed_Tests_SRCS}
+)
+
+target_link_libraries (
+ Testbed
+ Box2D
+ freeglut_static
+ glui
+ ${ADDITIONAL_LIBRARIES}
+ ${OPENGL_LIBRARIES}
+)
diff --git a/tests/box2d/Testbed/Framework/Main.cpp b/tests/box2d/Testbed/Framework/Main.cpp new file mode 100755 index 00000000..048ed886 --- /dev/null +++ b/tests/box2d/Testbed/Framework/Main.cpp @@ -0,0 +1,447 @@ +/*
+* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "Render.h"
+#include "Test.h"
+#include "glui/glui.h"
+
+#include <cstdio>
+using namespace std;
+
+namespace
+{
+ int32 testIndex = 0;
+ int32 testSelection = 0;
+ int32 testCount = 0;
+ TestEntry* entry;
+ Test* test;
+ Settings settings;
+ int32 width = 640;
+ int32 height = 480;
+ int32 framePeriod = 16;
+ int32 mainWindow;
+ float settingsHz = 60.0;
+ GLUI *glui;
+ float32 viewZoom = 1.0f;
+ int tx, ty, tw, th;
+ bool rMouseDown;
+ b2Vec2 lastp;
+}
+
+static void Resize(int32 w, int32 h)
+{
+ width = w;
+ height = h;
+
+ GLUI_Master.get_viewport_area(&tx, &ty, &tw, &th);
+ glViewport(tx, ty, tw, th);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ float32 ratio = float32(tw) / float32(th);
+
+ b2Vec2 extents(ratio * 25.0f, 25.0f);
+ extents *= viewZoom;
+
+ b2Vec2 lower = settings.viewCenter - extents;
+ b2Vec2 upper = settings.viewCenter + extents;
+
+ // L/R/B/T
+ gluOrtho2D(lower.x, upper.x, lower.y, upper.y);
+}
+
+static b2Vec2 ConvertScreenToWorld(int32 x, int32 y)
+{
+ float32 u = x / float32(tw);
+ float32 v = (th - y) / float32(th);
+
+ float32 ratio = float32(tw) / float32(th);
+ b2Vec2 extents(ratio * 25.0f, 25.0f);
+ extents *= viewZoom;
+
+ b2Vec2 lower = settings.viewCenter - extents;
+ b2Vec2 upper = settings.viewCenter + extents;
+
+ b2Vec2 p;
+ p.x = (1.0f - u) * lower.x + u * upper.x;
+ p.y = (1.0f - v) * lower.y + v * upper.y;
+ return p;
+}
+
+// This is used to control the frame rate (60Hz).
+static void Timer(int)
+{
+ glutSetWindow(mainWindow);
+ glutPostRedisplay();
+ glutTimerFunc(framePeriod, Timer, 0);
+}
+
+static void SimulationLoop()
+{
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ test->SetTextLine(30);
+ b2Vec2 oldCenter = settings.viewCenter;
+ settings.hz = settingsHz;
+ test->Step(&settings);
+ if (oldCenter.x != settings.viewCenter.x || oldCenter.y != settings.viewCenter.y)
+ {
+ Resize(width, height);
+ }
+
+ test->DrawTitle(5, 15, entry->name);
+
+ glutSwapBuffers();
+
+ if (testSelection != testIndex)
+ {
+ testIndex = testSelection;
+ delete test;
+ entry = g_testEntries + testIndex;
+ test = entry->createFcn();
+ viewZoom = 1.0f;
+ settings.viewCenter.Set(0.0f, 20.0f);
+ Resize(width, height);
+ }
+}
+
+static void Keyboard(unsigned char key, int x, int y)
+{
+ B2_NOT_USED(x);
+ B2_NOT_USED(y);
+
+ switch (key)
+ {
+ case 27:
+#ifndef __APPLE__
+ // freeglut specific function
+ glutLeaveMainLoop();
+#endif
+ exit(0);
+ break;
+
+ // Press 'z' to zoom out.
+ case 'z':
+ viewZoom = b2Min(1.1f * viewZoom, 20.0f);
+ Resize(width, height);
+ break;
+
+ // Press 'x' to zoom in.
+ case 'x':
+ viewZoom = b2Max(0.9f * viewZoom, 0.02f);
+ Resize(width, height);
+ break;
+
+ // Press 'r' to reset.
+ case 'r':
+ delete test;
+ test = entry->createFcn();
+ break;
+
+ // Press space to launch a bomb.
+ case ' ':
+ if (test)
+ {
+ test->LaunchBomb();
+ }
+ break;
+
+ case 'p':
+ settings.pause = !settings.pause;
+ break;
+
+ // Press [ to prev test.
+ case '[':
+ --testSelection;
+ if (testSelection < 0)
+ {
+ testSelection = testCount - 1;
+ }
+ glui->sync_live();
+ break;
+
+ // Press ] to next test.
+ case ']':
+ ++testSelection;
+ if (testSelection == testCount)
+ {
+ testSelection = 0;
+ }
+ glui->sync_live();
+ break;
+
+ default:
+ if (test)
+ {
+ test->Keyboard(key);
+ }
+ }
+}
+
+static void KeyboardSpecial(int key, int x, int y)
+{
+ B2_NOT_USED(x);
+ B2_NOT_USED(y);
+
+ switch (key)
+ {
+ case GLUT_ACTIVE_SHIFT:
+ // Press left to pan left.
+ case GLUT_KEY_LEFT:
+ settings.viewCenter.x -= 0.5f;
+ Resize(width, height);
+ break;
+
+ // Press right to pan right.
+ case GLUT_KEY_RIGHT:
+ settings.viewCenter.x += 0.5f;
+ Resize(width, height);
+ break;
+
+ // Press down to pan down.
+ case GLUT_KEY_DOWN:
+ settings.viewCenter.y -= 0.5f;
+ Resize(width, height);
+ break;
+
+ // Press up to pan up.
+ case GLUT_KEY_UP:
+ settings.viewCenter.y += 0.5f;
+ Resize(width, height);
+ break;
+
+ // Press home to reset the view.
+ case GLUT_KEY_HOME:
+ viewZoom = 1.0f;
+ settings.viewCenter.Set(0.0f, 20.0f);
+ Resize(width, height);
+ break;
+ }
+}
+
+static void KeyboardUp(unsigned char key, int x, int y)
+{
+ B2_NOT_USED(x);
+ B2_NOT_USED(y);
+
+ if (test)
+ {
+ test->KeyboardUp(key);
+ }
+}
+
+static void Mouse(int32 button, int32 state, int32 x, int32 y)
+{
+ // Use the mouse to move things around.
+ if (button == GLUT_LEFT_BUTTON)
+ {
+ int mod = glutGetModifiers();
+ b2Vec2 p = ConvertScreenToWorld(x, y);
+ if (state == GLUT_DOWN)
+ {
+ b2Vec2 p = ConvertScreenToWorld(x, y);
+ if (mod == GLUT_ACTIVE_SHIFT)
+ {
+ test->ShiftMouseDown(p);
+ }
+ else
+ {
+ test->MouseDown(p);
+ }
+ }
+
+ if (state == GLUT_UP)
+ {
+ test->MouseUp(p);
+ }
+ }
+ else if (button == GLUT_RIGHT_BUTTON)
+ {
+ if (state == GLUT_DOWN)
+ {
+ lastp = ConvertScreenToWorld(x, y);
+ rMouseDown = true;
+ }
+
+ if (state == GLUT_UP)
+ {
+ rMouseDown = false;
+ }
+ }
+}
+
+static void MouseMotion(int32 x, int32 y)
+{
+ b2Vec2 p = ConvertScreenToWorld(x, y);
+ test->MouseMove(p);
+
+ if (rMouseDown)
+ {
+ b2Vec2 diff = p - lastp;
+ settings.viewCenter.x -= diff.x;
+ settings.viewCenter.y -= diff.y;
+ Resize(width, height);
+ lastp = ConvertScreenToWorld(x, y);
+ }
+}
+
+static void MouseWheel(int wheel, int direction, int x, int y)
+{
+ B2_NOT_USED(wheel);
+ B2_NOT_USED(x);
+ B2_NOT_USED(y);
+ if (direction > 0)
+ {
+ viewZoom /= 1.1f;
+ }
+ else
+ {
+ viewZoom *= 1.1f;
+ }
+ Resize(width, height);
+}
+
+static void Restart(int)
+{
+ delete test;
+ entry = g_testEntries + testIndex;
+ test = entry->createFcn();
+ Resize(width, height);
+}
+
+static void Pause(int)
+{
+ settings.pause = !settings.pause;
+}
+
+static void Exit(int code)
+{
+ // TODO: freeglut is not building on OSX
+#ifdef FREEGLUT
+ glutLeaveMainLoop();
+#endif
+ exit(code);
+}
+
+static void SingleStep(int)
+{
+ settings.pause = 1;
+ settings.singleStep = 1;
+}
+
+int main(int argc, char** argv)
+{
+ testCount = 0;
+ while (g_testEntries[testCount].createFcn != NULL)
+ {
+ ++testCount;
+ }
+
+ testIndex = b2Clamp(testIndex, 0, testCount-1);
+ testSelection = testIndex;
+
+ entry = g_testEntries + testIndex;
+ test = entry->createFcn();
+
+ glutInit(&argc, argv);
+ glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
+ glutInitWindowSize(width, height);
+ char title[32];
+ sprintf(title, "Box2D Version %d.%d.%d", b2_version.major, b2_version.minor, b2_version.revision);
+ mainWindow = glutCreateWindow(title);
+ //glutSetOption (GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS);
+
+ glutDisplayFunc(SimulationLoop);
+ GLUI_Master.set_glutReshapeFunc(Resize);
+ GLUI_Master.set_glutKeyboardFunc(Keyboard);
+ GLUI_Master.set_glutSpecialFunc(KeyboardSpecial);
+ GLUI_Master.set_glutMouseFunc(Mouse);
+#ifdef FREEGLUT
+ glutMouseWheelFunc(MouseWheel);
+#endif
+ glutMotionFunc(MouseMotion);
+
+ glutKeyboardUpFunc(KeyboardUp);
+
+ glui = GLUI_Master.create_glui_subwindow( mainWindow,
+ GLUI_SUBWINDOW_RIGHT );
+
+ glui->add_statictext("Tests");
+ GLUI_Listbox* testList =
+ glui->add_listbox("", &testSelection);
+
+ glui->add_separator();
+
+ GLUI_Spinner* velocityIterationSpinner =
+ glui->add_spinner("Vel Iters", GLUI_SPINNER_INT, &settings.velocityIterations);
+ velocityIterationSpinner->set_int_limits(1, 500);
+
+ GLUI_Spinner* positionIterationSpinner =
+ glui->add_spinner("Pos Iters", GLUI_SPINNER_INT, &settings.positionIterations);
+ positionIterationSpinner->set_int_limits(0, 100);
+
+ GLUI_Spinner* hertzSpinner =
+ glui->add_spinner("Hertz", GLUI_SPINNER_FLOAT, &settingsHz);
+
+ hertzSpinner->set_float_limits(5.0f, 200.0f);
+
+ glui->add_checkbox("Warm Starting", &settings.enableWarmStarting);
+ glui->add_checkbox("Time of Impact", &settings.enableContinuous);
+ glui->add_checkbox("Sub-Stepping", &settings.enableSubStepping);
+
+ //glui->add_separator();
+
+ GLUI_Panel* drawPanel = glui->add_panel("Draw");
+ glui->add_checkbox_to_panel(drawPanel, "Shapes", &settings.drawShapes);
+ glui->add_checkbox_to_panel(drawPanel, "Joints", &settings.drawJoints);
+ glui->add_checkbox_to_panel(drawPanel, "AABBs", &settings.drawAABBs);
+ glui->add_checkbox_to_panel(drawPanel, "Pairs", &settings.drawPairs);
+ glui->add_checkbox_to_panel(drawPanel, "Contact Points", &settings.drawContactPoints);
+ glui->add_checkbox_to_panel(drawPanel, "Contact Normals", &settings.drawContactNormals);
+ glui->add_checkbox_to_panel(drawPanel, "Contact Forces", &settings.drawContactForces);
+ glui->add_checkbox_to_panel(drawPanel, "Friction Forces", &settings.drawFrictionForces);
+ glui->add_checkbox_to_panel(drawPanel, "Center of Masses", &settings.drawCOMs);
+ glui->add_checkbox_to_panel(drawPanel, "Statistics", &settings.drawStats);
+ glui->add_checkbox_to_panel(drawPanel, "Profile", &settings.drawProfile);
+
+ int32 testCount = 0;
+ TestEntry* e = g_testEntries;
+ while (e->createFcn)
+ {
+ testList->add_item(testCount, e->name);
+ ++testCount;
+ ++e;
+ }
+
+ glui->add_button("Pause", 0, Pause);
+ glui->add_button("Single Step", 0, SingleStep);
+ glui->add_button("Restart", 0, Restart);
+
+ glui->add_button("Quit", 0,(GLUI_Update_CB)Exit);
+ glui->set_main_gfx_window( mainWindow );
+
+ // Use a timer to control the frame rate.
+ glutTimerFunc(framePeriod, Timer, 0);
+
+ glutMainLoop();
+
+ return 0;
+}
diff --git a/tests/box2d/Testbed/Framework/Render.cpp b/tests/box2d/Testbed/Framework/Render.cpp new file mode 100755 index 00000000..0533479c --- /dev/null +++ b/tests/box2d/Testbed/Framework/Render.cpp @@ -0,0 +1,197 @@ +/*
+* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "Render.h"
+
+#ifdef __APPLE__
+ #include <GLUT/glut.h>
+#else
+ #include "freeglut/freeglut.h"
+#endif
+
+#include <cstdio>
+#include <cstdarg>
+#include <cstring>
+using namespace std;
+
+void DebugDraw::DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color)
+{
+ glColor3f(color.r, color.g, color.b);
+ glBegin(GL_LINE_LOOP);
+ for (int32 i = 0; i < vertexCount; ++i)
+ {
+ glVertex2f(vertices[i].x, vertices[i].y);
+ }
+ glEnd();
+}
+
+void DebugDraw::DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color)
+{
+ glEnable(GL_BLEND);
+ glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glColor4f(0.5f * color.r, 0.5f * color.g, 0.5f * color.b, 0.5f);
+ glBegin(GL_TRIANGLE_FAN);
+ for (int32 i = 0; i < vertexCount; ++i)
+ {
+ glVertex2f(vertices[i].x, vertices[i].y);
+ }
+ glEnd();
+ glDisable(GL_BLEND);
+
+ glColor4f(color.r, color.g, color.b, 1.0f);
+ glBegin(GL_LINE_LOOP);
+ for (int32 i = 0; i < vertexCount; ++i)
+ {
+ glVertex2f(vertices[i].x, vertices[i].y);
+ }
+ glEnd();
+}
+
+void DebugDraw::DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color)
+{
+ const float32 k_segments = 16.0f;
+ const float32 k_increment = 2.0f * b2_pi / k_segments;
+ float32 theta = 0.0f;
+ glColor3f(color.r, color.g, color.b);
+ glBegin(GL_LINE_LOOP);
+ for (int32 i = 0; i < k_segments; ++i)
+ {
+ b2Vec2 v = center + radius * b2Vec2(cosf(theta), sinf(theta));
+ glVertex2f(v.x, v.y);
+ theta += k_increment;
+ }
+ glEnd();
+}
+
+void DebugDraw::DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color)
+{
+ const float32 k_segments = 16.0f;
+ const float32 k_increment = 2.0f * b2_pi / k_segments;
+ float32 theta = 0.0f;
+ glEnable(GL_BLEND);
+ glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glColor4f(0.5f * color.r, 0.5f * color.g, 0.5f * color.b, 0.5f);
+ glBegin(GL_TRIANGLE_FAN);
+ for (int32 i = 0; i < k_segments; ++i)
+ {
+ b2Vec2 v = center + radius * b2Vec2(cosf(theta), sinf(theta));
+ glVertex2f(v.x, v.y);
+ theta += k_increment;
+ }
+ glEnd();
+ glDisable(GL_BLEND);
+
+ theta = 0.0f;
+ glColor4f(color.r, color.g, color.b, 1.0f);
+ glBegin(GL_LINE_LOOP);
+ for (int32 i = 0; i < k_segments; ++i)
+ {
+ b2Vec2 v = center + radius * b2Vec2(cosf(theta), sinf(theta));
+ glVertex2f(v.x, v.y);
+ theta += k_increment;
+ }
+ glEnd();
+
+ b2Vec2 p = center + radius * axis;
+ glBegin(GL_LINES);
+ glVertex2f(center.x, center.y);
+ glVertex2f(p.x, p.y);
+ glEnd();
+}
+
+void DebugDraw::DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color)
+{
+ glColor3f(color.r, color.g, color.b);
+ glBegin(GL_LINES);
+ glVertex2f(p1.x, p1.y);
+ glVertex2f(p2.x, p2.y);
+ glEnd();
+}
+
+void DebugDraw::DrawTransform(const b2Transform& xf)
+{
+ b2Vec2 p1 = xf.p, p2;
+ const float32 k_axisScale = 0.4f;
+ glBegin(GL_LINES);
+
+ glColor3f(1.0f, 0.0f, 0.0f);
+ glVertex2f(p1.x, p1.y);
+ p2 = p1 + k_axisScale * xf.q.GetXAxis();
+ glVertex2f(p2.x, p2.y);
+
+ glColor3f(0.0f, 1.0f, 0.0f);
+ glVertex2f(p1.x, p1.y);
+ p2 = p1 + k_axisScale * xf.q.GetYAxis();
+ glVertex2f(p2.x, p2.y);
+
+ glEnd();
+}
+
+void DebugDraw::DrawPoint(const b2Vec2& p, float32 size, const b2Color& color)
+{
+ glPointSize(size);
+ glBegin(GL_POINTS);
+ glColor3f(color.r, color.g, color.b);
+ glVertex2f(p.x, p.y);
+ glEnd();
+ glPointSize(1.0f);
+}
+
+void DebugDraw::DrawString(int x, int y, const char *string, ...)
+{
+ char buffer[128];
+
+ va_list arg;
+ va_start(arg, string);
+ vsprintf(buffer, string, arg);
+ va_end(arg);
+
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ int w = glutGet(GLUT_WINDOW_WIDTH);
+ int h = glutGet(GLUT_WINDOW_HEIGHT);
+ gluOrtho2D(0, w, h, 0);
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glColor3f(0.9f, 0.6f, 0.6f);
+ glRasterPos2i(x, y);
+ int32 length = (int32)strlen(buffer);
+ for (int32 i = 0; i < length; ++i)
+ {
+ glutBitmapCharacter(GLUT_BITMAP_8_BY_13, buffer[i]);
+ }
+
+ glPopMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+}
+
+void DebugDraw::DrawAABB(b2AABB* aabb, const b2Color& c)
+{
+ glColor3f(c.r, c.g, c.b);
+ glBegin(GL_LINE_LOOP);
+ glVertex2f(aabb->lowerBound.x, aabb->lowerBound.y);
+ glVertex2f(aabb->upperBound.x, aabb->lowerBound.y);
+ glVertex2f(aabb->upperBound.x, aabb->upperBound.y);
+ glVertex2f(aabb->lowerBound.x, aabb->upperBound.y);
+ glEnd();
+}
diff --git a/tests/box2d/Testbed/Framework/Render.h b/tests/box2d/Testbed/Framework/Render.h new file mode 100755 index 00000000..a1d0e881 --- /dev/null +++ b/tests/box2d/Testbed/Framework/Render.h @@ -0,0 +1,51 @@ +/*
+* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef RENDER_H
+#define RENDER_H
+
+#include <Box2D/Box2D.h>
+
+struct b2AABB;
+
+// This class implements debug drawing callbacks that are invoked
+// inside b2World::Step.
+class DebugDraw : public b2Draw
+{
+public:
+ void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color);
+
+ void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color);
+
+ void DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color);
+
+ void DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color);
+
+ void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color);
+
+ void DrawTransform(const b2Transform& xf);
+
+ void DrawPoint(const b2Vec2& p, float32 size, const b2Color& color);
+
+ void DrawString(int x, int y, const char* string, ...);
+
+ void DrawAABB(b2AABB* aabb, const b2Color& color);
+};
+
+
+#endif
diff --git a/tests/box2d/Testbed/Framework/Test.cpp b/tests/box2d/Testbed/Framework/Test.cpp new file mode 100755 index 00000000..3c5b4ad8 --- /dev/null +++ b/tests/box2d/Testbed/Framework/Test.cpp @@ -0,0 +1,447 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "Test.h"
+#include <cstdio>
+using namespace std;
+
+void DestructionListener::SayGoodbye(b2Joint* joint)
+{
+ if (test->m_mouseJoint == joint)
+ {
+ test->m_mouseJoint = NULL;
+ }
+ else
+ {
+ test->JointDestroyed(joint);
+ }
+}
+
+Test::Test()
+{
+ b2Vec2 gravity;
+ gravity.Set(0.0f, -10.0f);
+ m_world = new b2World(gravity);
+ m_bomb = NULL;
+ m_textLine = 30;
+ m_mouseJoint = NULL;
+ m_pointCount = 0;
+
+ m_destructionListener.test = this;
+ m_world->SetDestructionListener(&m_destructionListener);
+ m_world->SetContactListener(this);
+ m_world->SetDebugDraw(&m_debugDraw);
+
+ m_bombSpawning = false;
+
+ m_stepCount = 0;
+
+ b2BodyDef bodyDef;
+ m_groundBody = m_world->CreateBody(&bodyDef);
+
+ memset(&m_maxProfile, 0, sizeof(b2Profile));
+ memset(&m_totalProfile, 0, sizeof(b2Profile));
+}
+
+Test::~Test()
+{
+ // By deleting the world, we delete the bomb, mouse joint, etc.
+ delete m_world;
+ m_world = NULL;
+}
+
+void Test::PreSolve(b2Contact* contact, const b2Manifold* oldManifold)
+{
+ const b2Manifold* manifold = contact->GetManifold();
+
+ if (manifold->pointCount == 0)
+ {
+ return;
+ }
+
+ b2Fixture* fixtureA = contact->GetFixtureA();
+ b2Fixture* fixtureB = contact->GetFixtureB();
+
+ b2PointState state1[b2_maxManifoldPoints], state2[b2_maxManifoldPoints];
+ b2GetPointStates(state1, state2, oldManifold, manifold);
+
+ b2WorldManifold worldManifold;
+ contact->GetWorldManifold(&worldManifold);
+
+ for (int32 i = 0; i < manifold->pointCount && m_pointCount < k_maxContactPoints; ++i)
+ {
+ ContactPoint* cp = m_points + m_pointCount;
+ cp->fixtureA = fixtureA;
+ cp->fixtureB = fixtureB;
+ cp->position = worldManifold.points[i];
+ cp->normal = worldManifold.normal;
+ cp->state = state2[i];
+ ++m_pointCount;
+ }
+}
+
+void Test::DrawTitle(int x, int y, const char *string)
+{
+ m_debugDraw.DrawString(x, y, string);
+}
+
+class QueryCallback : public b2QueryCallback
+{
+public:
+ QueryCallback(const b2Vec2& point)
+ {
+ m_point = point;
+ m_fixture = NULL;
+ }
+
+ bool ReportFixture(b2Fixture* fixture)
+ {
+ b2Body* body = fixture->GetBody();
+ if (body->GetType() == b2_dynamicBody)
+ {
+ bool inside = fixture->TestPoint(m_point);
+ if (inside)
+ {
+ m_fixture = fixture;
+
+ // We are done, terminate the query.
+ return false;
+ }
+ }
+
+ // Continue the query.
+ return true;
+ }
+
+ b2Vec2 m_point;
+ b2Fixture* m_fixture;
+};
+
+void Test::MouseDown(const b2Vec2& p)
+{
+ m_mouseWorld = p;
+
+ if (m_mouseJoint != NULL)
+ {
+ return;
+ }
+
+ // Make a small box.
+ b2AABB aabb;
+ b2Vec2 d;
+ d.Set(0.001f, 0.001f);
+ aabb.lowerBound = p - d;
+ aabb.upperBound = p + d;
+
+ // Query the world for overlapping shapes.
+ QueryCallback callback(p);
+ m_world->QueryAABB(&callback, aabb);
+
+ if (callback.m_fixture)
+ {
+ b2Body* body = callback.m_fixture->GetBody();
+ b2MouseJointDef md;
+ md.bodyA = m_groundBody;
+ md.bodyB = body;
+ md.target = p;
+ md.maxForce = 1000.0f * body->GetMass();
+ m_mouseJoint = (b2MouseJoint*)m_world->CreateJoint(&md);
+ body->SetAwake(true);
+ }
+}
+
+void Test::SpawnBomb(const b2Vec2& worldPt)
+{
+ m_bombSpawnPoint = worldPt;
+ m_bombSpawning = true;
+}
+
+void Test::CompleteBombSpawn(const b2Vec2& p)
+{
+ if (m_bombSpawning == false)
+ {
+ return;
+ }
+
+ const float multiplier = 30.0f;
+ b2Vec2 vel = m_bombSpawnPoint - p;
+ vel *= multiplier;
+ LaunchBomb(m_bombSpawnPoint,vel);
+ m_bombSpawning = false;
+}
+
+void Test::ShiftMouseDown(const b2Vec2& p)
+{
+ m_mouseWorld = p;
+
+ if (m_mouseJoint != NULL)
+ {
+ return;
+ }
+
+ SpawnBomb(p);
+}
+
+void Test::MouseUp(const b2Vec2& p)
+{
+ if (m_mouseJoint)
+ {
+ m_world->DestroyJoint(m_mouseJoint);
+ m_mouseJoint = NULL;
+ }
+
+ if (m_bombSpawning)
+ {
+ CompleteBombSpawn(p);
+ }
+}
+
+void Test::MouseMove(const b2Vec2& p)
+{
+ m_mouseWorld = p;
+
+ if (m_mouseJoint)
+ {
+ m_mouseJoint->SetTarget(p);
+ }
+}
+
+void Test::LaunchBomb()
+{
+ b2Vec2 p(RandomFloat(-15.0f, 15.0f), 30.0f);
+ b2Vec2 v = -5.0f * p;
+ LaunchBomb(p, v);
+}
+
+void Test::LaunchBomb(const b2Vec2& position, const b2Vec2& velocity)
+{
+ if (m_bomb)
+ {
+ m_world->DestroyBody(m_bomb);
+ m_bomb = NULL;
+ }
+
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position = position;
+ bd.bullet = true;
+ m_bomb = m_world->CreateBody(&bd);
+ m_bomb->SetLinearVelocity(velocity);
+
+ b2CircleShape circle;
+ circle.m_radius = 0.3f;
+
+ b2FixtureDef fd;
+ fd.shape = &circle;
+ fd.density = 20.0f;
+ fd.restitution = 0.0f;
+
+ b2Vec2 minV = position - b2Vec2(0.3f,0.3f);
+ b2Vec2 maxV = position + b2Vec2(0.3f,0.3f);
+
+ b2AABB aabb;
+ aabb.lowerBound = minV;
+ aabb.upperBound = maxV;
+
+ m_bomb->CreateFixture(&fd);
+}
+
+void Test::Step(Settings* settings)
+{
+ float32 timeStep = settings->hz > 0.0f ? 1.0f / settings->hz : float32(0.0f);
+
+ if (settings->pause)
+ {
+ if (settings->singleStep)
+ {
+ settings->singleStep = 0;
+ }
+ else
+ {
+ timeStep = 0.0f;
+ }
+
+ m_debugDraw.DrawString(5, m_textLine, "****PAUSED****");
+ m_textLine += 15;
+ }
+
+ uint32 flags = 0;
+ flags += settings->drawShapes * b2Draw::e_shapeBit;
+ flags += settings->drawJoints * b2Draw::e_jointBit;
+ flags += settings->drawAABBs * b2Draw::e_aabbBit;
+ flags += settings->drawPairs * b2Draw::e_pairBit;
+ flags += settings->drawCOMs * b2Draw::e_centerOfMassBit;
+ m_debugDraw.SetFlags(flags);
+
+ m_world->SetWarmStarting(settings->enableWarmStarting > 0);
+ m_world->SetContinuousPhysics(settings->enableContinuous > 0);
+ m_world->SetSubStepping(settings->enableSubStepping > 0);
+
+ m_pointCount = 0;
+
+ m_world->Step(timeStep, settings->velocityIterations, settings->positionIterations);
+
+ m_world->DrawDebugData();
+
+ if (timeStep > 0.0f)
+ {
+ ++m_stepCount;
+ }
+
+ if (settings->drawStats)
+ {
+ int32 bodyCount = m_world->GetBodyCount();
+ int32 contactCount = m_world->GetContactCount();
+ int32 jointCount = m_world->GetJointCount();
+ m_debugDraw.DrawString(5, m_textLine, "bodies/contacts/joints = %d/%d/%d", bodyCount, contactCount, jointCount);
+ m_textLine += 15;
+
+ int32 proxyCount = m_world->GetProxyCount();
+ int32 height = m_world->GetTreeHeight();
+ int32 balance = m_world->GetTreeBalance();
+ float32 quality = m_world->GetTreeQuality();
+ m_debugDraw.DrawString(5, m_textLine, "proxies/height/balance/quality = %d/%d/%d/%g", proxyCount, height, balance, quality);
+ m_textLine += 15;
+ }
+
+ // Track maximum profile times
+ {
+ const b2Profile& p = m_world->GetProfile();
+ m_maxProfile.step = b2Max(m_maxProfile.step, p.step);
+ m_maxProfile.collide = b2Max(m_maxProfile.collide, p.collide);
+ m_maxProfile.solve = b2Max(m_maxProfile.solve, p.solve);
+ m_maxProfile.solveInit = b2Max(m_maxProfile.solveInit, p.solveInit);
+ m_maxProfile.solveVelocity = b2Max(m_maxProfile.solveVelocity, p.solveVelocity);
+ m_maxProfile.solvePosition = b2Max(m_maxProfile.solvePosition, p.solvePosition);
+ m_maxProfile.solveTOI = b2Max(m_maxProfile.solveTOI, p.solveTOI);
+ m_maxProfile.broadphase = b2Max(m_maxProfile.broadphase, p.broadphase);
+
+ m_totalProfile.step += p.step;
+ m_totalProfile.collide += p.collide;
+ m_totalProfile.solve += p.solve;
+ m_totalProfile.solveInit += p.solveInit;
+ m_totalProfile.solveVelocity += p.solveVelocity;
+ m_totalProfile.solvePosition += p.solvePosition;
+ m_totalProfile.solveTOI += p.solveTOI;
+ m_totalProfile.broadphase += p.broadphase;
+ }
+
+ if (settings->drawProfile)
+ {
+ const b2Profile& p = m_world->GetProfile();
+
+ b2Profile aveProfile;
+ memset(&aveProfile, 0, sizeof(b2Profile));
+ if (m_stepCount > 0)
+ {
+ float32 scale = 1.0f / m_stepCount;
+ aveProfile.step = scale * m_totalProfile.step;
+ aveProfile.collide = scale * m_totalProfile.collide;
+ aveProfile.solve = scale * m_totalProfile.solve;
+ aveProfile.solveInit = scale * m_totalProfile.solveInit;
+ aveProfile.solveVelocity = scale * m_totalProfile.solveVelocity;
+ aveProfile.solvePosition = scale * m_totalProfile.solvePosition;
+ aveProfile.solveTOI = scale * m_totalProfile.solveTOI;
+ aveProfile.broadphase = scale * m_totalProfile.broadphase;
+ }
+
+ m_debugDraw.DrawString(5, m_textLine, "step [ave] (max) = %5.2f [%6.2f] (%6.2f)", p.step, aveProfile.step, m_maxProfile.step);
+ m_textLine += 15;
+ m_debugDraw.DrawString(5, m_textLine, "collide [ave] (max) = %5.2f [%6.2f] (%6.2f)", p.collide, aveProfile.collide, m_maxProfile.collide);
+ m_textLine += 15;
+ m_debugDraw.DrawString(5, m_textLine, "solve [ave] (max) = %5.2f [%6.2f] (%6.2f)", p.solve, aveProfile.solve, m_maxProfile.solve);
+ m_textLine += 15;
+ m_debugDraw.DrawString(5, m_textLine, "solve init [ave] (max) = %5.2f [%6.2f] (%6.2f)", p.solveInit, aveProfile.solveInit, m_maxProfile.solveInit);
+ m_textLine += 15;
+ m_debugDraw.DrawString(5, m_textLine, "solve velocity [ave] (max) = %5.2f [%6.2f] (%6.2f)", p.solveVelocity, aveProfile.solveVelocity, m_maxProfile.solveVelocity);
+ m_textLine += 15;
+ m_debugDraw.DrawString(5, m_textLine, "solve position [ave] (max) = %5.2f [%6.2f] (%6.2f)", p.solvePosition, aveProfile.solvePosition, m_maxProfile.solvePosition);
+ m_textLine += 15;
+ m_debugDraw.DrawString(5, m_textLine, "solveTOI [ave] (max) = %5.2f [%6.2f] (%6.2f)", p.solveTOI, aveProfile.solveTOI, m_maxProfile.solveTOI);
+ m_textLine += 15;
+ m_debugDraw.DrawString(5, m_textLine, "broad-phase [ave] (max) = %5.2f [%6.2f] (%6.2f)", p.broadphase, aveProfile.broadphase, m_maxProfile.broadphase);
+ m_textLine += 15;
+ }
+
+ if (m_mouseJoint)
+ {
+ b2Vec2 p1 = m_mouseJoint->GetAnchorB();
+ b2Vec2 p2 = m_mouseJoint->GetTarget();
+
+ b2Color c;
+ c.Set(0.0f, 1.0f, 0.0f);
+ m_debugDraw.DrawPoint(p1, 4.0f, c);
+ m_debugDraw.DrawPoint(p2, 4.0f, c);
+
+ c.Set(0.8f, 0.8f, 0.8f);
+ m_debugDraw.DrawSegment(p1, p2, c);
+ }
+
+ if (m_bombSpawning)
+ {
+ b2Color c;
+ c.Set(0.0f, 0.0f, 1.0f);
+ m_debugDraw.DrawPoint(m_bombSpawnPoint, 4.0f, c);
+
+ c.Set(0.8f, 0.8f, 0.8f);
+ m_debugDraw.DrawSegment(m_mouseWorld, m_bombSpawnPoint, c);
+ }
+
+ if (settings->drawContactPoints)
+ {
+ //const float32 k_impulseScale = 0.1f;
+ const float32 k_axisScale = 0.3f;
+
+ for (int32 i = 0; i < m_pointCount; ++i)
+ {
+ ContactPoint* point = m_points + i;
+
+ if (point->state == b2_addState)
+ {
+ // Add
+ m_debugDraw.DrawPoint(point->position, 10.0f, b2Color(0.3f, 0.95f, 0.3f));
+ }
+ else if (point->state == b2_persistState)
+ {
+ // Persist
+ m_debugDraw.DrawPoint(point->position, 5.0f, b2Color(0.3f, 0.3f, 0.95f));
+ }
+
+ if (settings->drawContactNormals == 1)
+ {
+ b2Vec2 p1 = point->position;
+ b2Vec2 p2 = p1 + k_axisScale * point->normal;
+ m_debugDraw.DrawSegment(p1, p2, b2Color(0.9f, 0.9f, 0.9f));
+ }
+ else if (settings->drawContactForces == 1)
+ {
+ //b2Vec2 p1 = point->position;
+ //b2Vec2 p2 = p1 + k_forceScale * point->normalForce * point->normal;
+ //DrawSegment(p1, p2, b2Color(0.9f, 0.9f, 0.3f));
+ }
+
+ if (settings->drawFrictionForces == 1)
+ {
+ //b2Vec2 tangent = b2Cross(point->normal, 1.0f);
+ //b2Vec2 p1 = point->position;
+ //b2Vec2 p2 = p1 + k_forceScale * point->tangentForce * tangent;
+ //DrawSegment(p1, p2, b2Color(0.9f, 0.9f, 0.3f));
+ }
+ }
+ }
+}
diff --git a/tests/box2d/Testbed/Framework/Test.h b/tests/box2d/Testbed/Framework/Test.h new file mode 100755 index 00000000..71e3b46e --- /dev/null +++ b/tests/box2d/Testbed/Framework/Test.h @@ -0,0 +1,189 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef TEST_H
+#define TEST_H
+
+#include <Box2D/Box2D.h>
+#include "Render.h"
+
+#include <cstdlib>
+
+class Test;
+struct Settings;
+
+typedef Test* TestCreateFcn();
+
+#define RAND_LIMIT 32767
+
+/// Random number in range [-1,1]
+inline float32 RandomFloat()
+{
+ float32 r = (float32)(std::rand() & (RAND_LIMIT));
+ r /= RAND_LIMIT;
+ r = 2.0f * r - 1.0f;
+ return r;
+}
+
+/// Random floating point number in range [lo, hi]
+inline float32 RandomFloat(float32 lo, float32 hi)
+{
+ float32 r = (float32)(std::rand() & (RAND_LIMIT));
+ r /= RAND_LIMIT;
+ r = (hi - lo) * r + lo;
+ return r;
+}
+
+/// Test settings. Some can be controlled in the GUI.
+struct Settings
+{
+ Settings() :
+ viewCenter(0.0f, 20.0f),
+ hz(60.0f),
+ velocityIterations(8),
+ positionIterations(3),
+ drawShapes(1),
+ drawJoints(1),
+ drawAABBs(0),
+ drawPairs(0),
+ drawContactPoints(0),
+ drawContactNormals(0),
+ drawContactForces(0),
+ drawFrictionForces(0),
+ drawCOMs(0),
+ drawStats(0),
+ drawProfile(0),
+ enableWarmStarting(1),
+ enableContinuous(1),
+ enableSubStepping(0),
+ pause(0),
+ singleStep(0)
+ {}
+
+ b2Vec2 viewCenter;
+ float32 hz;
+ int32 velocityIterations;
+ int32 positionIterations;
+ int32 drawShapes;
+ int32 drawJoints;
+ int32 drawAABBs;
+ int32 drawPairs;
+ int32 drawContactPoints;
+ int32 drawContactNormals;
+ int32 drawContactForces;
+ int32 drawFrictionForces;
+ int32 drawCOMs;
+ int32 drawStats;
+ int32 drawProfile;
+ int32 enableWarmStarting;
+ int32 enableContinuous;
+ int32 enableSubStepping;
+ int32 pause;
+ int32 singleStep;
+};
+
+struct TestEntry
+{
+ const char *name;
+ TestCreateFcn *createFcn;
+};
+
+extern TestEntry g_testEntries[];
+// This is called when a joint in the world is implicitly destroyed
+// because an attached body is destroyed. This gives us a chance to
+// nullify the mouse joint.
+class DestructionListener : public b2DestructionListener
+{
+public:
+ void SayGoodbye(b2Fixture* fixture) { B2_NOT_USED(fixture); }
+ void SayGoodbye(b2Joint* joint);
+
+ Test* test;
+};
+
+const int32 k_maxContactPoints = 2048;
+
+struct ContactPoint
+{
+ b2Fixture* fixtureA;
+ b2Fixture* fixtureB;
+ b2Vec2 normal;
+ b2Vec2 position;
+ b2PointState state;
+};
+
+class Test : public b2ContactListener
+{
+public:
+
+ Test();
+ virtual ~Test();
+
+ void SetTextLine(int32 line) { m_textLine = line; }
+ void DrawTitle(int x, int y, const char *string);
+ virtual void Step(Settings* settings);
+ virtual void Keyboard(unsigned char key) { B2_NOT_USED(key); }
+ virtual void KeyboardUp(unsigned char key) { B2_NOT_USED(key); }
+ void ShiftMouseDown(const b2Vec2& p);
+ virtual void MouseDown(const b2Vec2& p);
+ virtual void MouseUp(const b2Vec2& p);
+ void MouseMove(const b2Vec2& p);
+ void LaunchBomb();
+ void LaunchBomb(const b2Vec2& position, const b2Vec2& velocity);
+
+ void SpawnBomb(const b2Vec2& worldPt);
+ void CompleteBombSpawn(const b2Vec2& p);
+
+ // Let derived tests know that a joint was destroyed.
+ virtual void JointDestroyed(b2Joint* joint) { B2_NOT_USED(joint); }
+
+ // Callbacks for derived classes.
+ virtual void BeginContact(b2Contact* contact) { B2_NOT_USED(contact); }
+ virtual void EndContact(b2Contact* contact) { B2_NOT_USED(contact); }
+ virtual void PreSolve(b2Contact* contact, const b2Manifold* oldManifold);
+ virtual void PostSolve(const b2Contact* contact, const b2ContactImpulse* impulse)
+ {
+ B2_NOT_USED(contact);
+ B2_NOT_USED(impulse);
+ }
+
+protected:
+ friend class DestructionListener;
+ friend class BoundaryListener;
+ friend class ContactListener;
+
+ b2Body* m_groundBody;
+ b2AABB m_worldAABB;
+ ContactPoint m_points[k_maxContactPoints];
+ int32 m_pointCount;
+ DestructionListener m_destructionListener;
+ DebugDraw m_debugDraw;
+ int32 m_textLine;
+ b2World* m_world;
+ b2Body* m_bomb;
+ b2MouseJoint* m_mouseJoint;
+ b2Vec2 m_bombSpawnPoint;
+ bool m_bombSpawning;
+ b2Vec2 m_mouseWorld;
+ int32 m_stepCount;
+
+ b2Profile m_maxProfile;
+ b2Profile m_totalProfile;
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/AddPair.h b/tests/box2d/Testbed/Tests/AddPair.h new file mode 100755 index 00000000..8f0893ac --- /dev/null +++ b/tests/box2d/Testbed/Tests/AddPair.h @@ -0,0 +1,51 @@ +
+#ifndef AddPair_H
+#define AddPair_H
+
+class AddPair : public Test
+{
+public:
+
+ AddPair()
+ {
+ m_world->SetGravity(b2Vec2(0.0f,0.0f));
+ {
+ b2CircleShape shape;
+ shape.m_p.SetZero();
+ shape.m_radius = 0.1f;
+
+ float minX = -6.0f;
+ float maxX = 0.0f;
+ float minY = 4.0f;
+ float maxY = 6.0f;
+
+ for (int32 i = 0; i < 400; ++i)
+ {
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position = b2Vec2(RandomFloat(minX,maxX),RandomFloat(minY,maxY));
+ b2Body* body = m_world->CreateBody(&bd);
+ body->CreateFixture(&shape, 0.01f);
+ }
+ }
+
+ {
+ b2PolygonShape shape;
+ shape.SetAsBox(1.5f, 1.5f);
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(-40.0f,5.0f);
+ bd.bullet = true;
+ b2Body* body = m_world->CreateBody(&bd);
+ body->CreateFixture(&shape, 1.0f);
+ body->SetLinearVelocity(b2Vec2(150.0f, 0.0f));
+ }
+ }
+
+ static Test* Create()
+ {
+ return new AddPair;
+ }
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/ApplyForce.h b/tests/box2d/Testbed/Tests/ApplyForce.h new file mode 100755 index 00000000..c04f8642 --- /dev/null +++ b/tests/box2d/Testbed/Tests/ApplyForce.h @@ -0,0 +1,180 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef APPLY_FORCE_H
+#define APPLY_FORCE_H
+
+class ApplyForce : public Test
+{
+public:
+ ApplyForce()
+ {
+ m_world->SetGravity(b2Vec2(0.0f, 0.0f));
+
+ const float32 k_restitution = 0.4f;
+
+ b2Body* ground;
+ {
+ b2BodyDef bd;
+ bd.position.Set(0.0f, 20.0f);
+ ground = m_world->CreateBody(&bd);
+
+ b2EdgeShape shape;
+
+ b2FixtureDef sd;
+ sd.shape = &shape;
+ sd.density = 0.0f;
+ sd.restitution = k_restitution;
+
+ // Left vertical
+ shape.Set(b2Vec2(-20.0f, -20.0f), b2Vec2(-20.0f, 20.0f));
+ ground->CreateFixture(&sd);
+
+ // Right vertical
+ shape.Set(b2Vec2(20.0f, -20.0f), b2Vec2(20.0f, 20.0f));
+ ground->CreateFixture(&sd);
+
+ // Top horizontal
+ shape.Set(b2Vec2(-20.0f, 20.0f), b2Vec2(20.0f, 20.0f));
+ ground->CreateFixture(&sd);
+
+ // Bottom horizontal
+ shape.Set(b2Vec2(-20.0f, -20.0f), b2Vec2(20.0f, -20.0f));
+ ground->CreateFixture(&sd);
+ }
+
+ {
+ b2Transform xf1;
+ xf1.q.Set(0.3524f * b2_pi);
+ xf1.p = xf1.q.GetXAxis();
+
+ b2Vec2 vertices[3];
+ vertices[0] = b2Mul(xf1, b2Vec2(-1.0f, 0.0f));
+ vertices[1] = b2Mul(xf1, b2Vec2(1.0f, 0.0f));
+ vertices[2] = b2Mul(xf1, b2Vec2(0.0f, 0.5f));
+
+ b2PolygonShape poly1;
+ poly1.Set(vertices, 3);
+
+ b2FixtureDef sd1;
+ sd1.shape = &poly1;
+ sd1.density = 4.0f;
+
+ b2Transform xf2;
+ xf2.q.Set(-0.3524f * b2_pi);
+ xf2.p = -xf2.q.GetXAxis();
+
+ vertices[0] = b2Mul(xf2, b2Vec2(-1.0f, 0.0f));
+ vertices[1] = b2Mul(xf2, b2Vec2(1.0f, 0.0f));
+ vertices[2] = b2Mul(xf2, b2Vec2(0.0f, 0.5f));
+
+ b2PolygonShape poly2;
+ poly2.Set(vertices, 3);
+
+ b2FixtureDef sd2;
+ sd2.shape = &poly2;
+ sd2.density = 2.0f;
+
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.angularDamping = 5.0f;
+ bd.linearDamping = 0.1f;
+
+ bd.position.Set(0.0f, 2.0);
+ bd.angle = b2_pi;
+ bd.allowSleep = false;
+ m_body = m_world->CreateBody(&bd);
+ m_body->CreateFixture(&sd1);
+ m_body->CreateFixture(&sd2);
+ }
+
+ {
+ b2PolygonShape shape;
+ shape.SetAsBox(0.5f, 0.5f);
+
+ b2FixtureDef fd;
+ fd.shape = &shape;
+ fd.density = 1.0f;
+ fd.friction = 0.3f;
+
+ for (int i = 0; i < 10; ++i)
+ {
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+
+ bd.position.Set(0.0f, 5.0f + 1.54f * i);
+ b2Body* body = m_world->CreateBody(&bd);
+
+ body->CreateFixture(&fd);
+
+ float32 gravity = 10.0f;
+ float32 I = body->GetInertia();
+ float32 mass = body->GetMass();
+
+ // For a circle: I = 0.5 * m * r * r ==> r = sqrt(2 * I / m)
+ float32 radius = b2Sqrt(2.0f * I / mass);
+
+ b2FrictionJointDef jd;
+ jd.localAnchorA.SetZero();
+ jd.localAnchorB.SetZero();
+ jd.bodyA = ground;
+ jd.bodyB = body;
+ jd.collideConnected = true;
+ jd.maxForce = mass * gravity;
+ jd.maxTorque = mass * radius * gravity;
+
+ m_world->CreateJoint(&jd);
+ }
+ }
+ }
+
+ void Keyboard(unsigned char key)
+ {
+ switch (key)
+ {
+ case 'w':
+ {
+ b2Vec2 f = m_body->GetWorldVector(b2Vec2(0.0f, -200.0f));
+ b2Vec2 p = m_body->GetWorldPoint(b2Vec2(0.0f, 2.0f));
+ m_body->ApplyForce(f, p);
+ }
+ break;
+
+ case 'a':
+ {
+ m_body->ApplyTorque(50.0f);
+ }
+ break;
+
+ case 'd':
+ {
+ m_body->ApplyTorque(-50.0f);
+ }
+ break;
+ }
+ }
+
+ static Test* Create()
+ {
+ return new ApplyForce;
+ }
+
+ b2Body* m_body;
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/BodyTypes.h b/tests/box2d/Testbed/Tests/BodyTypes.h new file mode 100755 index 00000000..1e04b27f --- /dev/null +++ b/tests/box2d/Testbed/Tests/BodyTypes.h @@ -0,0 +1,159 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef BODY_TYPES_H
+#define BODY_TYPES_H
+
+class BodyTypes : public Test
+{
+public:
+ BodyTypes()
+ {
+ b2Body* ground = NULL;
+ {
+ b2BodyDef bd;
+ ground = m_world->CreateBody(&bd);
+
+ b2EdgeShape shape;
+ shape.Set(b2Vec2(-20.0f, 0.0f), b2Vec2(20.0f, 0.0f));
+
+ b2FixtureDef fd;
+ fd.shape = &shape;
+
+ ground->CreateFixture(&fd);
+ }
+
+ // Define attachment
+ {
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(0.0f, 3.0f);
+ m_attachment = m_world->CreateBody(&bd);
+
+ b2PolygonShape shape;
+ shape.SetAsBox(0.5f, 2.0f);
+ m_attachment->CreateFixture(&shape, 2.0f);
+ }
+
+ // Define platform
+ {
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(-4.0f, 5.0f);
+ m_platform = m_world->CreateBody(&bd);
+
+ b2PolygonShape shape;
+ shape.SetAsBox(0.5f, 4.0f, b2Vec2(4.0f, 0.0f), 0.5f * b2_pi);
+
+ b2FixtureDef fd;
+ fd.shape = &shape;
+ fd.friction = 0.6f;
+ fd.density = 2.0f;
+ m_platform->CreateFixture(&fd);
+
+ b2RevoluteJointDef rjd;
+ rjd.Initialize(m_attachment, m_platform, b2Vec2(0.0f, 5.0f));
+ rjd.maxMotorTorque = 50.0f;
+ rjd.enableMotor = true;
+ m_world->CreateJoint(&rjd);
+
+ b2PrismaticJointDef pjd;
+ pjd.Initialize(ground, m_platform, b2Vec2(0.0f, 5.0f), b2Vec2(1.0f, 0.0f));
+
+ pjd.maxMotorForce = 1000.0f;
+ pjd.enableMotor = true;
+ pjd.lowerTranslation = -10.0f;
+ pjd.upperTranslation = 10.0f;
+ pjd.enableLimit = true;
+
+ m_world->CreateJoint(&pjd);
+
+ m_speed = 3.0f;
+ }
+
+ // Create a payload
+ {
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(0.0f, 8.0f);
+ b2Body* body = m_world->CreateBody(&bd);
+
+ b2PolygonShape shape;
+ shape.SetAsBox(0.75f, 0.75f);
+
+ b2FixtureDef fd;
+ fd.shape = &shape;
+ fd.friction = 0.6f;
+ fd.density = 2.0f;
+
+ body->CreateFixture(&fd);
+ }
+ }
+
+ void Keyboard(unsigned char key)
+ {
+ switch (key)
+ {
+ case 'd':
+ m_platform->SetType(b2_dynamicBody);
+ break;
+
+ case 's':
+ m_platform->SetType(b2_staticBody);
+ break;
+
+ case 'k':
+ m_platform->SetType(b2_kinematicBody);
+ m_platform->SetLinearVelocity(b2Vec2(-m_speed, 0.0f));
+ m_platform->SetAngularVelocity(0.0f);
+ break;
+ }
+ }
+
+ void Step(Settings* settings)
+ {
+ // Drive the kinematic body.
+ if (m_platform->GetType() == b2_kinematicBody)
+ {
+ b2Vec2 p = m_platform->GetTransform().p;
+ b2Vec2 v = m_platform->GetLinearVelocity();
+
+ if ((p.x < -10.0f && v.x < 0.0f) ||
+ (p.x > 10.0f && v.x > 0.0f))
+ {
+ v.x = -v.x;
+ m_platform->SetLinearVelocity(v);
+ }
+ }
+
+ Test::Step(settings);
+ m_debugDraw.DrawString(5, m_textLine, "Keys: (d) dynamic, (s) static, (k) kinematic");
+ m_textLine += 15;
+ }
+
+ static Test* Create()
+ {
+ return new BodyTypes;
+ }
+
+ b2Body* m_attachment;
+ b2Body* m_platform;
+ float32 m_speed;
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/Breakable.h b/tests/box2d/Testbed/Tests/Breakable.h new file mode 100755 index 00000000..3fbdd476 --- /dev/null +++ b/tests/box2d/Testbed/Tests/Breakable.h @@ -0,0 +1,155 @@ +/*
+* Copyright (c) 2008-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef BREAKABLE_TEST_H
+#define BREAKABLE_TEST_H
+
+// This is used to test sensor shapes.
+class Breakable : public Test
+{
+public:
+
+ enum
+ {
+ e_count = 7
+ };
+
+ Breakable()
+ {
+ // Ground body
+ {
+ b2BodyDef bd;
+ b2Body* ground = m_world->CreateBody(&bd);
+
+ b2EdgeShape shape;
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
+ ground->CreateFixture(&shape, 0.0f);
+ }
+
+ // Breakable dynamic body
+ {
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(0.0f, 40.0f);
+ bd.angle = 0.25f * b2_pi;
+ m_body1 = m_world->CreateBody(&bd);
+
+ m_shape1.SetAsBox(0.5f, 0.5f, b2Vec2(-0.5f, 0.0f), 0.0f);
+ m_piece1 = m_body1->CreateFixture(&m_shape1, 1.0f);
+
+ m_shape2.SetAsBox(0.5f, 0.5f, b2Vec2(0.5f, 0.0f), 0.0f);
+ m_piece2 = m_body1->CreateFixture(&m_shape2, 1.0f);
+ }
+
+ m_break = false;
+ m_broke = false;
+ }
+
+ void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse)
+ {
+ if (m_broke)
+ {
+ // The body already broke.
+ return;
+ }
+
+ // Should the body break?
+ int32 count = contact->GetManifold()->pointCount;
+
+ float32 maxImpulse = 0.0f;
+ for (int32 i = 0; i < count; ++i)
+ {
+ maxImpulse = b2Max(maxImpulse, impulse->normalImpulses[i]);
+ }
+
+ if (maxImpulse > 40.0f)
+ {
+ // Flag the body for breaking.
+ m_break = true;
+ }
+ }
+
+ void Break()
+ {
+ // Create two bodies from one.
+ b2Body* body1 = m_piece1->GetBody();
+ b2Vec2 center = body1->GetWorldCenter();
+
+ body1->DestroyFixture(m_piece2);
+ m_piece2 = NULL;
+
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position = body1->GetPosition();
+ bd.angle = body1->GetAngle();
+
+ b2Body* body2 = m_world->CreateBody(&bd);
+ m_piece2 = body2->CreateFixture(&m_shape2, 1.0f);
+
+ // Compute consistent velocities for new bodies based on
+ // cached velocity.
+ b2Vec2 center1 = body1->GetWorldCenter();
+ b2Vec2 center2 = body2->GetWorldCenter();
+
+ b2Vec2 velocity1 = m_velocity + b2Cross(m_angularVelocity, center1 - center);
+ b2Vec2 velocity2 = m_velocity + b2Cross(m_angularVelocity, center2 - center);
+
+ body1->SetAngularVelocity(m_angularVelocity);
+ body1->SetLinearVelocity(velocity1);
+
+ body2->SetAngularVelocity(m_angularVelocity);
+ body2->SetLinearVelocity(velocity2);
+ }
+
+ void Step(Settings* settings)
+ {
+ if (m_break)
+ {
+ Break();
+ m_broke = true;
+ m_break = false;
+ }
+
+ // Cache velocities to improve movement on breakage.
+ if (m_broke == false)
+ {
+ m_velocity = m_body1->GetLinearVelocity();
+ m_angularVelocity = m_body1->GetAngularVelocity();
+ }
+
+ Test::Step(settings);
+ }
+
+ static Test* Create()
+ {
+ return new Breakable;
+ }
+
+ b2Body* m_body1;
+ b2Vec2 m_velocity;
+ float32 m_angularVelocity;
+ b2PolygonShape m_shape1;
+ b2PolygonShape m_shape2;
+ b2Fixture* m_piece1;
+ b2Fixture* m_piece2;
+
+ bool m_broke;
+ bool m_break;
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/Bridge.h b/tests/box2d/Testbed/Tests/Bridge.h new file mode 100755 index 00000000..ef836499 --- /dev/null +++ b/tests/box2d/Testbed/Tests/Bridge.h @@ -0,0 +1,125 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef BRIDGE_H
+#define BRIDGE_H
+
+class Bridge : public Test
+{
+public:
+
+ enum
+ {
+ e_count = 30
+ };
+
+ Bridge()
+ {
+ b2Body* ground = NULL;
+ {
+ b2BodyDef bd;
+ ground = m_world->CreateBody(&bd);
+
+ b2EdgeShape shape;
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
+ ground->CreateFixture(&shape, 0.0f);
+ }
+
+ {
+ b2PolygonShape shape;
+ shape.SetAsBox(0.5f, 0.125f);
+
+ b2FixtureDef fd;
+ fd.shape = &shape;
+ fd.density = 20.0f;
+ fd.friction = 0.2f;
+
+ b2RevoluteJointDef jd;
+
+ b2Body* prevBody = ground;
+ for (int32 i = 0; i < e_count; ++i)
+ {
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(-14.5f + 1.0f * i, 5.0f);
+ b2Body* body = m_world->CreateBody(&bd);
+ body->CreateFixture(&fd);
+
+ b2Vec2 anchor(-15.0f + 1.0f * i, 5.0f);
+ jd.Initialize(prevBody, body, anchor);
+ m_world->CreateJoint(&jd);
+
+ if (i == (e_count >> 1))
+ {
+ m_middle = body;
+ }
+ prevBody = body;
+ }
+
+ b2Vec2 anchor(-15.0f + 1.0f * e_count, 5.0f);
+ jd.Initialize(prevBody, ground, anchor);
+ m_world->CreateJoint(&jd);
+ }
+
+ for (int32 i = 0; i < 2; ++i)
+ {
+ b2Vec2 vertices[3];
+ vertices[0].Set(-0.5f, 0.0f);
+ vertices[1].Set(0.5f, 0.0f);
+ vertices[2].Set(0.0f, 1.5f);
+
+ b2PolygonShape shape;
+ shape.Set(vertices, 3);
+
+ b2FixtureDef fd;
+ fd.shape = &shape;
+ fd.density = 1.0f;
+
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(-8.0f + 8.0f * i, 12.0f);
+ b2Body* body = m_world->CreateBody(&bd);
+ body->CreateFixture(&fd);
+ }
+
+ for (int32 i = 0; i < 3; ++i)
+ {
+ b2CircleShape shape;
+ shape.m_radius = 0.5f;
+
+ b2FixtureDef fd;
+ fd.shape = &shape;
+ fd.density = 1.0f;
+
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(-6.0f + 6.0f * i, 10.0f);
+ b2Body* body = m_world->CreateBody(&bd);
+ body->CreateFixture(&fd);
+ }
+ }
+
+ static Test* Create()
+ {
+ return new Bridge;
+ }
+
+ b2Body* m_middle;
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/BulletTest.h b/tests/box2d/Testbed/Tests/BulletTest.h new file mode 100755 index 00000000..10f1f000 --- /dev/null +++ b/tests/box2d/Testbed/Tests/BulletTest.h @@ -0,0 +1,136 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef BULLET_TEST_H
+#define BULLET_TEST_H
+
+class BulletTest : public Test
+{
+public:
+
+ BulletTest()
+ {
+ {
+ b2BodyDef bd;
+ bd.position.Set(0.0f, 0.0f);
+ b2Body* body = m_world->CreateBody(&bd);
+
+ b2EdgeShape edge;
+
+ edge.Set(b2Vec2(-10.0f, 0.0f), b2Vec2(10.0f, 0.0f));
+ body->CreateFixture(&edge, 0.0f);
+
+ b2PolygonShape shape;
+ shape.SetAsBox(0.2f, 1.0f, b2Vec2(0.5f, 1.0f), 0.0f);
+ body->CreateFixture(&shape, 0.0f);
+ }
+
+ {
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(0.0f, 4.0f);
+
+ b2PolygonShape box;
+ box.SetAsBox(2.0f, 0.1f);
+
+ m_body = m_world->CreateBody(&bd);
+ m_body->CreateFixture(&box, 1.0f);
+
+ box.SetAsBox(0.25f, 0.25f);
+
+ //m_x = RandomFloat(-1.0f, 1.0f);
+ m_x = 0.20352793f;
+ bd.position.Set(m_x, 10.0f);
+ bd.bullet = true;
+
+ m_bullet = m_world->CreateBody(&bd);
+ m_bullet->CreateFixture(&box, 100.0f);
+
+ m_bullet->SetLinearVelocity(b2Vec2(0.0f, -50.0f));
+ }
+ }
+
+ void Launch()
+ {
+ m_body->SetTransform(b2Vec2(0.0f, 4.0f), 0.0f);
+ m_body->SetLinearVelocity(b2Vec2_zero);
+ m_body->SetAngularVelocity(0.0f);
+
+ m_x = RandomFloat(-1.0f, 1.0f);
+ m_bullet->SetTransform(b2Vec2(m_x, 10.0f), 0.0f);
+ m_bullet->SetLinearVelocity(b2Vec2(0.0f, -50.0f));
+ m_bullet->SetAngularVelocity(0.0f);
+
+ extern int32 b2_gjkCalls, b2_gjkIters, b2_gjkMaxIters;
+ extern int32 b2_toiCalls, b2_toiIters, b2_toiMaxIters;
+ extern int32 b2_toiRootIters, b2_toiMaxRootIters;
+
+ b2_gjkCalls = 0;
+ b2_gjkIters = 0;
+ b2_gjkMaxIters = 0;
+
+ b2_toiCalls = 0;
+ b2_toiIters = 0;
+ b2_toiMaxIters = 0;
+ b2_toiRootIters = 0;
+ b2_toiMaxRootIters = 0;
+ }
+
+ void Step(Settings* settings)
+ {
+ Test::Step(settings);
+
+ extern int32 b2_gjkCalls, b2_gjkIters, b2_gjkMaxIters;
+ extern int32 b2_toiCalls, b2_toiIters;
+ extern int32 b2_toiRootIters, b2_toiMaxRootIters;
+
+ if (b2_gjkCalls > 0)
+ {
+ m_debugDraw.DrawString(5, m_textLine, "gjk calls = %d, ave gjk iters = %3.1f, max gjk iters = %d",
+ b2_gjkCalls, b2_gjkIters / float32(b2_gjkCalls), b2_gjkMaxIters);
+ m_textLine += 15;
+ }
+
+ if (b2_toiCalls > 0)
+ {
+ m_debugDraw.DrawString(5, m_textLine, "toi calls = %d, ave toi iters = %3.1f, max toi iters = %d",
+ b2_toiCalls, b2_toiIters / float32(b2_toiCalls), b2_toiMaxRootIters);
+ m_textLine += 15;
+
+ m_debugDraw.DrawString(5, m_textLine, "ave toi root iters = %3.1f, max toi root iters = %d",
+ b2_toiRootIters / float32(b2_toiCalls), b2_toiMaxRootIters);
+ m_textLine += 15;
+ }
+
+ if (m_stepCount % 60 == 0)
+ {
+ Launch();
+ }
+ }
+
+ static Test* Create()
+ {
+ return new BulletTest;
+ }
+
+ b2Body* m_body;
+ b2Body* m_bullet;
+ float32 m_x;
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/Cantilever.h b/tests/box2d/Testbed/Tests/Cantilever.h new file mode 100755 index 00000000..26994d6f --- /dev/null +++ b/tests/box2d/Testbed/Tests/Cantilever.h @@ -0,0 +1,211 @@ +/*
+* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef CANTILEVER_H
+#define CANTILEVER_H
+
+// It is difficult to make a cantilever made of links completely rigid with weld joints.
+// You will have to use a high number of iterations to make them stiff.
+// So why not go ahead and use soft weld joints? They behave like a revolute
+// joint with a rotational spring.
+class Cantilever : public Test
+{
+public:
+
+ enum
+ {
+ e_count = 8
+ };
+
+ Cantilever()
+ {
+ b2Body* ground = NULL;
+ {
+ b2BodyDef bd;
+ ground = m_world->CreateBody(&bd);
+
+ b2EdgeShape shape;
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
+ ground->CreateFixture(&shape, 0.0f);
+ }
+
+ {
+ b2PolygonShape shape;
+ shape.SetAsBox(0.5f, 0.125f);
+
+ b2FixtureDef fd;
+ fd.shape = &shape;
+ fd.density = 20.0f;
+
+ b2WeldJointDef jd;
+
+ b2Body* prevBody = ground;
+ for (int32 i = 0; i < e_count; ++i)
+ {
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(-14.5f + 1.0f * i, 5.0f);
+ b2Body* body = m_world->CreateBody(&bd);
+ body->CreateFixture(&fd);
+
+ b2Vec2 anchor(-15.0f + 1.0f * i, 5.0f);
+ jd.Initialize(prevBody, body, anchor);
+ m_world->CreateJoint(&jd);
+
+ prevBody = body;
+ }
+ }
+
+ {
+ b2PolygonShape shape;
+ shape.SetAsBox(1.0f, 0.125f);
+
+ b2FixtureDef fd;
+ fd.shape = &shape;
+ fd.density = 20.0f;
+
+ b2WeldJointDef jd;
+ jd.frequencyHz = 5.0f;
+ jd.dampingRatio = 0.7f;
+
+ b2Body* prevBody = ground;
+ for (int32 i = 0; i < 3; ++i)
+ {
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(-14.0f + 2.0f * i, 15.0f);
+ b2Body* body = m_world->CreateBody(&bd);
+ body->CreateFixture(&fd);
+
+ b2Vec2 anchor(-15.0f + 2.0f * i, 15.0f);
+ jd.Initialize(prevBody, body, anchor);
+ m_world->CreateJoint(&jd);
+
+ prevBody = body;
+ }
+ }
+
+ {
+ b2PolygonShape shape;
+ shape.SetAsBox(0.5f, 0.125f);
+
+ b2FixtureDef fd;
+ fd.shape = &shape;
+ fd.density = 20.0f;
+
+ b2WeldJointDef jd;
+
+ b2Body* prevBody = ground;
+ for (int32 i = 0; i < e_count; ++i)
+ {
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(-4.5f + 1.0f * i, 5.0f);
+ b2Body* body = m_world->CreateBody(&bd);
+ body->CreateFixture(&fd);
+
+ if (i > 0)
+ {
+ b2Vec2 anchor(-5.0f + 1.0f * i, 5.0f);
+ jd.Initialize(prevBody, body, anchor);
+ m_world->CreateJoint(&jd);
+ }
+
+ prevBody = body;
+ }
+ }
+
+ {
+ b2PolygonShape shape;
+ shape.SetAsBox(0.5f, 0.125f);
+
+ b2FixtureDef fd;
+ fd.shape = &shape;
+ fd.density = 20.0f;
+
+ b2WeldJointDef jd;
+ jd.frequencyHz = 8.0f;
+ jd.dampingRatio = 0.7f;
+
+ b2Body* prevBody = ground;
+ for (int32 i = 0; i < e_count; ++i)
+ {
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(5.5f + 1.0f * i, 10.0f);
+ b2Body* body = m_world->CreateBody(&bd);
+ body->CreateFixture(&fd);
+
+ if (i > 0)
+ {
+ b2Vec2 anchor(5.0f + 1.0f * i, 10.0f);
+ jd.Initialize(prevBody, body, anchor);
+ m_world->CreateJoint(&jd);
+ }
+
+ prevBody = body;
+ }
+ }
+
+ for (int32 i = 0; i < 2; ++i)
+ {
+ b2Vec2 vertices[3];
+ vertices[0].Set(-0.5f, 0.0f);
+ vertices[1].Set(0.5f, 0.0f);
+ vertices[2].Set(0.0f, 1.5f);
+
+ b2PolygonShape shape;
+ shape.Set(vertices, 3);
+
+ b2FixtureDef fd;
+ fd.shape = &shape;
+ fd.density = 1.0f;
+
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(-8.0f + 8.0f * i, 12.0f);
+ b2Body* body = m_world->CreateBody(&bd);
+ body->CreateFixture(&fd);
+ }
+
+ for (int32 i = 0; i < 2; ++i)
+ {
+ b2CircleShape shape;
+ shape.m_radius = 0.5f;
+
+ b2FixtureDef fd;
+ fd.shape = &shape;
+ fd.density = 1.0f;
+
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(-6.0f + 6.0f * i, 10.0f);
+ b2Body* body = m_world->CreateBody(&bd);
+ body->CreateFixture(&fd);
+ }
+ }
+
+ static Test* Create()
+ {
+ return new Cantilever;
+ }
+
+ b2Body* m_middle;
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/Car.h b/tests/box2d/Testbed/Tests/Car.h new file mode 100755 index 00000000..d86201e7 --- /dev/null +++ b/tests/box2d/Testbed/Tests/Car.h @@ -0,0 +1,286 @@ +/*
+* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef CAR_H
+#define CAR_H
+
+// This is a fun demo that shows off the wheel joint
+class Car : public Test
+{
+public:
+ Car()
+ {
+ m_hz = 4.0f;
+ m_zeta = 0.7f;
+ m_speed = 50.0f;
+
+ b2Body* ground = NULL;
+ {
+ b2BodyDef bd;
+ ground = m_world->CreateBody(&bd);
+
+ b2EdgeShape shape;
+
+ b2FixtureDef fd;
+ fd.shape = &shape;
+ fd.density = 0.0f;
+ fd.friction = 0.6f;
+
+ shape.Set(b2Vec2(-20.0f, 0.0f), b2Vec2(20.0f, 0.0f));
+ ground->CreateFixture(&fd);
+
+ float32 hs[10] = {0.25f, 1.0f, 4.0f, 0.0f, 0.0f, -1.0f, -2.0f, -2.0f, -1.25f, 0.0f};
+
+ float32 x = 20.0f, y1 = 0.0f, dx = 5.0f;
+
+ for (int32 i = 0; i < 10; ++i)
+ {
+ float32 y2 = hs[i];
+ shape.Set(b2Vec2(x, y1), b2Vec2(x + dx, y2));
+ ground->CreateFixture(&fd);
+ y1 = y2;
+ x += dx;
+ }
+
+ for (int32 i = 0; i < 10; ++i)
+ {
+ float32 y2 = hs[i];
+ shape.Set(b2Vec2(x, y1), b2Vec2(x + dx, y2));
+ ground->CreateFixture(&fd);
+ y1 = y2;
+ x += dx;
+ }
+
+ shape.Set(b2Vec2(x, 0.0f), b2Vec2(x + 40.0f, 0.0f));
+ ground->CreateFixture(&fd);
+
+ x += 80.0f;
+ shape.Set(b2Vec2(x, 0.0f), b2Vec2(x + 40.0f, 0.0f));
+ ground->CreateFixture(&fd);
+
+ x += 40.0f;
+ shape.Set(b2Vec2(x, 0.0f), b2Vec2(x + 10.0f, 5.0f));
+ ground->CreateFixture(&fd);
+
+ x += 20.0f;
+ shape.Set(b2Vec2(x, 0.0f), b2Vec2(x + 40.0f, 0.0f));
+ ground->CreateFixture(&fd);
+
+ x += 40.0f;
+ shape.Set(b2Vec2(x, 0.0f), b2Vec2(x, 20.0f));
+ ground->CreateFixture(&fd);
+ }
+
+ // Teeter
+ {
+ b2BodyDef bd;
+ bd.position.Set(140.0f, 1.0f);
+ bd.type = b2_dynamicBody;
+ b2Body* body = m_world->CreateBody(&bd);
+
+ b2PolygonShape box;
+ box.SetAsBox(10.0f, 0.25f);
+ body->CreateFixture(&box, 1.0f);
+
+ b2RevoluteJointDef jd;
+ jd.Initialize(ground, body, body->GetPosition());
+ jd.lowerAngle = -8.0f * b2_pi / 180.0f;
+ jd.upperAngle = 8.0f * b2_pi / 180.0f;
+ jd.enableLimit = true;
+ m_world->CreateJoint(&jd);
+
+ body->ApplyAngularImpulse(100.0f);
+ }
+
+ // Bridge
+ {
+ int32 N = 20;
+ b2PolygonShape shape;
+ shape.SetAsBox(1.0f, 0.125f);
+
+ b2FixtureDef fd;
+ fd.shape = &shape;
+ fd.density = 1.0f;
+ fd.friction = 0.6f;
+
+ b2RevoluteJointDef jd;
+
+ b2Body* prevBody = ground;
+ for (int32 i = 0; i < N; ++i)
+ {
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(161.0f + 2.0f * i, -0.125f);
+ b2Body* body = m_world->CreateBody(&bd);
+ body->CreateFixture(&fd);
+
+ b2Vec2 anchor(160.0f + 2.0f * i, -0.125f);
+ jd.Initialize(prevBody, body, anchor);
+ m_world->CreateJoint(&jd);
+
+ prevBody = body;
+ }
+
+ b2Vec2 anchor(160.0f + 2.0f * N, -0.125f);
+ jd.Initialize(prevBody, ground, anchor);
+ m_world->CreateJoint(&jd);
+ }
+
+ // Boxes
+ {
+ b2PolygonShape box;
+ box.SetAsBox(0.5f, 0.5f);
+
+ b2Body* body = NULL;
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+
+ bd.position.Set(230.0f, 0.5f);
+ body = m_world->CreateBody(&bd);
+ body->CreateFixture(&box, 0.5f);
+
+ bd.position.Set(230.0f, 1.5f);
+ body = m_world->CreateBody(&bd);
+ body->CreateFixture(&box, 0.5f);
+
+ bd.position.Set(230.0f, 2.5f);
+ body = m_world->CreateBody(&bd);
+ body->CreateFixture(&box, 0.5f);
+
+ bd.position.Set(230.0f, 3.5f);
+ body = m_world->CreateBody(&bd);
+ body->CreateFixture(&box, 0.5f);
+
+ bd.position.Set(230.0f, 4.5f);
+ body = m_world->CreateBody(&bd);
+ body->CreateFixture(&box, 0.5f);
+ }
+
+ // Car
+ {
+ b2PolygonShape chassis;
+ b2Vec2 vertices[8];
+ vertices[0].Set(-1.5f, -0.5f);
+ vertices[1].Set(1.5f, -0.5f);
+ vertices[2].Set(1.5f, 0.0f);
+ vertices[3].Set(0.0f, 0.9f);
+ vertices[4].Set(-1.15f, 0.9f);
+ vertices[5].Set(-1.5f, 0.2f);
+ chassis.Set(vertices, 6);
+
+ b2CircleShape circle;
+ circle.m_radius = 0.4f;
+
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(0.0f, 1.0f);
+ m_car = m_world->CreateBody(&bd);
+ m_car->CreateFixture(&chassis, 1.0f);
+
+ b2FixtureDef fd;
+ fd.shape = &circle;
+ fd.density = 1.0f;
+ fd.friction = 0.9f;
+
+ bd.position.Set(-1.0f, 0.35f);
+ m_wheel1 = m_world->CreateBody(&bd);
+ m_wheel1->CreateFixture(&fd);
+
+ bd.position.Set(1.0f, 0.4f);
+ m_wheel2 = m_world->CreateBody(&bd);
+ m_wheel2->CreateFixture(&fd);
+
+ b2WheelJointDef jd;
+ b2Vec2 axis(0.0f, 1.0f);
+
+ jd.Initialize(m_car, m_wheel1, m_wheel1->GetPosition(), axis);
+ jd.motorSpeed = 0.0f;
+ jd.maxMotorTorque = 20.0f;
+ jd.enableMotor = true;
+ jd.frequencyHz = m_hz;
+ jd.dampingRatio = m_zeta;
+ m_spring1 = (b2WheelJoint*)m_world->CreateJoint(&jd);
+
+ jd.Initialize(m_car, m_wheel2, m_wheel2->GetPosition(), axis);
+ jd.motorSpeed = 0.0f;
+ jd.maxMotorTorque = 10.0f;
+ jd.enableMotor = false;
+ jd.frequencyHz = m_hz;
+ jd.dampingRatio = m_zeta;
+ m_spring2 = (b2WheelJoint*)m_world->CreateJoint(&jd);
+ }
+ }
+
+ void Keyboard(unsigned char key)
+ {
+ switch (key)
+ {
+ case 'a':
+ m_spring1->SetMotorSpeed(m_speed);
+ break;
+
+ case 's':
+ m_spring1->SetMotorSpeed(0.0f);
+ break;
+
+ case 'd':
+ m_spring1->SetMotorSpeed(-m_speed);
+ break;
+
+ case 'q':
+ m_hz = b2Max(0.0f, m_hz - 1.0f);
+ m_spring1->SetSpringFrequencyHz(m_hz);
+ m_spring2->SetSpringFrequencyHz(m_hz);
+ break;
+
+ case 'e':
+ m_hz += 1.0f;
+ m_spring1->SetSpringFrequencyHz(m_hz);
+ m_spring2->SetSpringFrequencyHz(m_hz);
+ break;
+ }
+ }
+
+ void Step(Settings* settings)
+ {
+ m_debugDraw.DrawString(5, m_textLine, "Keys: left = a, brake = s, right = d, hz down = q, hz up = e");
+ m_textLine += 15;
+ m_debugDraw.DrawString(5, m_textLine, "frequency = %g hz, damping ratio = %g", m_hz, m_zeta);
+ m_textLine += 15;
+
+ settings->viewCenter.x = m_car->GetPosition().x;
+ Test::Step(settings);
+ }
+
+ static Test* Create()
+ {
+ return new Car;
+ }
+
+ b2Body* m_car;
+ b2Body* m_wheel1;
+ b2Body* m_wheel2;
+
+ float32 m_hz;
+ float32 m_zeta;
+ float32 m_speed;
+ b2WheelJoint* m_spring1;
+ b2WheelJoint* m_spring2;
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/Chain.h b/tests/box2d/Testbed/Tests/Chain.h new file mode 100755 index 00000000..33b8de9b --- /dev/null +++ b/tests/box2d/Testbed/Tests/Chain.h @@ -0,0 +1,74 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef CHAIN_H
+#define CHAIN_H
+
+class Chain : public Test
+{
+public:
+ Chain()
+ {
+ b2Body* ground = NULL;
+ {
+ b2BodyDef bd;
+ ground = m_world->CreateBody(&bd);
+
+ b2EdgeShape shape;
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
+ ground->CreateFixture(&shape, 0.0f);
+ }
+
+ {
+ b2PolygonShape shape;
+ shape.SetAsBox(0.6f, 0.125f);
+
+ b2FixtureDef fd;
+ fd.shape = &shape;
+ fd.density = 20.0f;
+ fd.friction = 0.2f;
+
+ b2RevoluteJointDef jd;
+ jd.collideConnected = false;
+
+ const float32 y = 25.0f;
+ b2Body* prevBody = ground;
+ for (int32 i = 0; i < 30; ++i)
+ {
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(0.5f + i, y);
+ b2Body* body = m_world->CreateBody(&bd);
+ body->CreateFixture(&fd);
+
+ b2Vec2 anchor(float32(i), y);
+ jd.Initialize(prevBody, body, anchor);
+ m_world->CreateJoint(&jd);
+
+ prevBody = body;
+ }
+ }
+ }
+
+ static Test* Create()
+ {
+ return new Chain;
+ }
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/CharacterCollision.h b/tests/box2d/Testbed/Tests/CharacterCollision.h new file mode 100755 index 00000000..b000a828 --- /dev/null +++ b/tests/box2d/Testbed/Tests/CharacterCollision.h @@ -0,0 +1,253 @@ +/*
+* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef CHARACTER_COLLISION_H
+#define CHARACTER_COLLISION_H
+
+/// This is a test of typical character collision scenarios. This does not
+/// show how you should implement a character in your application.
+/// Instead this is used to test smooth collision on edge chains.
+class CharacterCollision : public Test
+{
+public:
+ CharacterCollision()
+ {
+ // Ground body
+ {
+ b2BodyDef bd;
+ b2Body* ground = m_world->CreateBody(&bd);
+
+ b2EdgeShape shape;
+ shape.Set(b2Vec2(-20.0f, 0.0f), b2Vec2(20.0f, 0.0f));
+ ground->CreateFixture(&shape, 0.0f);
+ }
+
+ // Collinear edges with no adjacency information.
+ // This shows the problematic case where a box shape can hit
+ // an internal vertex.
+ {
+ b2BodyDef bd;
+ b2Body* ground = m_world->CreateBody(&bd);
+
+ b2EdgeShape shape;
+ shape.Set(b2Vec2(-8.0f, 1.0f), b2Vec2(-6.0f, 1.0f));
+ ground->CreateFixture(&shape, 0.0f);
+ shape.Set(b2Vec2(-6.0f, 1.0f), b2Vec2(-4.0f, 1.0f));
+ ground->CreateFixture(&shape, 0.0f);
+ shape.Set(b2Vec2(-4.0f, 1.0f), b2Vec2(-2.0f, 1.0f));
+ ground->CreateFixture(&shape, 0.0f);
+ }
+
+ // Chain shape
+ {
+ b2BodyDef bd;
+ bd.angle = 0.25f * b2_pi;
+ b2Body* ground = m_world->CreateBody(&bd);
+
+ b2Vec2 vs[4];
+ vs[0].Set(5.0f, 7.0f);
+ vs[1].Set(6.0f, 8.0f);
+ vs[2].Set(7.0f, 8.0f);
+ vs[3].Set(8.0f, 7.0f);
+ b2ChainShape shape;
+ shape.CreateChain(vs, 4);
+ ground->CreateFixture(&shape, 0.0f);
+ }
+
+ // Square tiles. This shows that adjacency shapes may
+ // have non-smooth collision. There is no solution
+ // to this problem.
+ {
+ b2BodyDef bd;
+ b2Body* ground = m_world->CreateBody(&bd);
+
+ b2PolygonShape shape;
+ shape.SetAsBox(1.0f, 1.0f, b2Vec2(4.0f, 3.0f), 0.0f);
+ ground->CreateFixture(&shape, 0.0f);
+ shape.SetAsBox(1.0f, 1.0f, b2Vec2(6.0f, 3.0f), 0.0f);
+ ground->CreateFixture(&shape, 0.0f);
+ shape.SetAsBox(1.0f, 1.0f, b2Vec2(8.0f, 3.0f), 0.0f);
+ ground->CreateFixture(&shape, 0.0f);
+ }
+
+ // Square made from an edge loop. Collision should be smooth.
+ {
+ b2BodyDef bd;
+ b2Body* ground = m_world->CreateBody(&bd);
+
+ b2Vec2 vs[4];
+ vs[0].Set(-1.0f, 3.0f);
+ vs[1].Set(1.0f, 3.0f);
+ vs[2].Set(1.0f, 5.0f);
+ vs[3].Set(-1.0f, 5.0f);
+ b2ChainShape shape;
+ shape.CreateLoop(vs, 4);
+ ground->CreateFixture(&shape, 0.0f);
+ }
+
+ // Edge loop. Collision should be smooth.
+ {
+ b2BodyDef bd;
+ bd.position.Set(-10.0f, 4.0f);
+ b2Body* ground = m_world->CreateBody(&bd);
+
+ b2Vec2 vs[10];
+ vs[0].Set(0.0f, 0.0f);
+ vs[1].Set(6.0f, 0.0f);
+ vs[2].Set(6.0f, 2.0f);
+ vs[3].Set(4.0f, 1.0f);
+ vs[4].Set(2.0f, 2.0f);
+ vs[5].Set(0.0f, 2.0f);
+ vs[6].Set(-2.0f, 2.0f);
+ vs[7].Set(-4.0f, 3.0f);
+ vs[8].Set(-6.0f, 2.0f);
+ vs[9].Set(-6.0f, 0.0f);
+ b2ChainShape shape;
+ shape.CreateLoop(vs, 10);
+ ground->CreateFixture(&shape, 0.0f);
+ }
+
+ // Square character 1
+ {
+ b2BodyDef bd;
+ bd.position.Set(-3.0f, 8.0f);
+ bd.type = b2_dynamicBody;
+ bd.fixedRotation = true;
+ bd.allowSleep = false;
+
+ b2Body* body = m_world->CreateBody(&bd);
+
+ b2PolygonShape shape;
+ shape.SetAsBox(0.5f, 0.5f);
+
+ b2FixtureDef fd;
+ fd.shape = &shape;
+ fd.density = 20.0f;
+ body->CreateFixture(&fd);
+ }
+
+ // Square character 2
+ {
+ b2BodyDef bd;
+ bd.position.Set(-5.0f, 5.0f);
+ bd.type = b2_dynamicBody;
+ bd.fixedRotation = true;
+ bd.allowSleep = false;
+
+ b2Body* body = m_world->CreateBody(&bd);
+
+ b2PolygonShape shape;
+ shape.SetAsBox(0.25f, 0.25f);
+
+ b2FixtureDef fd;
+ fd.shape = &shape;
+ fd.density = 20.0f;
+ body->CreateFixture(&fd);
+ }
+
+ // Hexagon character
+ {
+ b2BodyDef bd;
+ bd.position.Set(-5.0f, 8.0f);
+ bd.type = b2_dynamicBody;
+ bd.fixedRotation = true;
+ bd.allowSleep = false;
+
+ b2Body* body = m_world->CreateBody(&bd);
+
+ float32 angle = 0.0f;
+ float32 delta = b2_pi / 3.0f;
+ b2Vec2 vertices[6];
+ for (int32 i = 0; i < 6; ++i)
+ {
+ vertices[i].Set(0.5f * cosf(angle), 0.5f * sinf(angle));
+ angle += delta;
+ }
+
+ b2PolygonShape shape;
+ shape.Set(vertices, 6);
+
+ b2FixtureDef fd;
+ fd.shape = &shape;
+ fd.density = 20.0f;
+ body->CreateFixture(&fd);
+ }
+
+ // Circle character
+ {
+ b2BodyDef bd;
+ bd.position.Set(3.0f, 5.0f);
+ bd.type = b2_dynamicBody;
+ bd.fixedRotation = true;
+ bd.allowSleep = false;
+
+ b2Body* body = m_world->CreateBody(&bd);
+
+ b2CircleShape shape;
+ shape.m_radius = 0.5f;
+
+ b2FixtureDef fd;
+ fd.shape = &shape;
+ fd.density = 20.0f;
+ body->CreateFixture(&fd);
+ }
+
+ // Circle character
+ {
+ b2BodyDef bd;
+ bd.position.Set(-7.0f, 6.0f);
+ bd.type = b2_dynamicBody;
+ bd.allowSleep = false;
+
+ m_character = m_world->CreateBody(&bd);
+
+ b2CircleShape shape;
+ shape.m_radius = 0.25f;
+
+ b2FixtureDef fd;
+ fd.shape = &shape;
+ fd.density = 20.0f;
+ fd.friction = 1.0f;
+ m_character->CreateFixture(&fd);
+ }
+ }
+
+ void Step(Settings* settings)
+ {
+ b2Vec2 v = m_character->GetLinearVelocity();
+ v.x = -5.0f;
+ m_character->SetLinearVelocity(v);
+
+ Test::Step(settings);
+ m_debugDraw.DrawString(5, m_textLine, "This tests various character collision shapes.");
+ m_textLine += 15;
+ m_debugDraw.DrawString(5, m_textLine, "Limitation: square and hexagon can snag on aligned boxes.");
+ m_textLine += 15;
+ m_debugDraw.DrawString(5, m_textLine, "Feature: edge chains have smooth collision inside and out.");
+ m_textLine += 15;
+ }
+
+ static Test* Create()
+ {
+ return new CharacterCollision;
+ }
+
+ b2Body* m_character;
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/CollisionFiltering.h b/tests/box2d/Testbed/Tests/CollisionFiltering.h new file mode 100755 index 00000000..82871759 --- /dev/null +++ b/tests/box2d/Testbed/Tests/CollisionFiltering.h @@ -0,0 +1,176 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef COLLISION_FILTERING_H
+#define COLLISION_FILTERING_H
+
+// This is a test of collision filtering.
+// There is a triangle, a box, and a circle.
+// There are 6 shapes. 3 large and 3 small.
+// The 3 small ones always collide.
+// The 3 large ones never collide.
+// The boxes don't collide with triangles (except if both are small).
+const int16 k_smallGroup = 1;
+const int16 k_largeGroup = -1;
+
+const uint16 k_defaultCategory = 0x0001;
+const uint16 k_triangleCategory = 0x0002;
+const uint16 k_boxCategory = 0x0004;
+const uint16 k_circleCategory = 0x0008;
+
+const uint16 k_triangleMask = 0xFFFF;
+const uint16 k_boxMask = 0xFFFF ^ k_triangleCategory;
+const uint16 k_circleMask = 0xFFFF;
+
+class CollisionFiltering : public Test
+{
+public:
+ CollisionFiltering()
+ {
+ // Ground body
+ {
+ b2EdgeShape shape;
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
+
+ b2FixtureDef sd;
+ sd.shape = &shape;
+ sd.friction = 0.3f;
+
+ b2BodyDef bd;
+ b2Body* ground = m_world->CreateBody(&bd);
+ ground->CreateFixture(&sd);
+ }
+
+ // Small triangle
+ b2Vec2 vertices[3];
+ vertices[0].Set(-1.0f, 0.0f);
+ vertices[1].Set(1.0f, 0.0f);
+ vertices[2].Set(0.0f, 2.0f);
+ b2PolygonShape polygon;
+ polygon.Set(vertices, 3);
+
+ b2FixtureDef triangleShapeDef;
+ triangleShapeDef.shape = &polygon;
+ triangleShapeDef.density = 1.0f;
+
+ triangleShapeDef.filter.groupIndex = k_smallGroup;
+ triangleShapeDef.filter.categoryBits = k_triangleCategory;
+ triangleShapeDef.filter.maskBits = k_triangleMask;
+
+ b2BodyDef triangleBodyDef;
+ triangleBodyDef.type = b2_dynamicBody;
+ triangleBodyDef.position.Set(-5.0f, 2.0f);
+
+ b2Body* body1 = m_world->CreateBody(&triangleBodyDef);
+ body1->CreateFixture(&triangleShapeDef);
+
+ // Large triangle (recycle definitions)
+ vertices[0] *= 2.0f;
+ vertices[1] *= 2.0f;
+ vertices[2] *= 2.0f;
+ polygon.Set(vertices, 3);
+ triangleShapeDef.filter.groupIndex = k_largeGroup;
+ triangleBodyDef.position.Set(-5.0f, 6.0f);
+ triangleBodyDef.fixedRotation = true; // look at me!
+
+ b2Body* body2 = m_world->CreateBody(&triangleBodyDef);
+ body2->CreateFixture(&triangleShapeDef);
+
+ {
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(-5.0f, 10.0f);
+ b2Body* body = m_world->CreateBody(&bd);
+
+ b2PolygonShape p;
+ p.SetAsBox(0.5f, 1.0f);
+ body->CreateFixture(&p, 1.0f);
+
+ b2PrismaticJointDef jd;
+ jd.bodyA = body2;
+ jd.bodyB = body;
+ jd.enableLimit = true;
+ jd.localAnchorA.Set(0.0f, 4.0f);
+ jd.localAnchorB.SetZero();
+ jd.localAxisA.Set(0.0f, 1.0f);
+ jd.lowerTranslation = -1.0f;
+ jd.upperTranslation = 1.0f;
+
+ m_world->CreateJoint(&jd);
+ }
+
+ // Small box
+ polygon.SetAsBox(1.0f, 0.5f);
+ b2FixtureDef boxShapeDef;
+ boxShapeDef.shape = &polygon;
+ boxShapeDef.density = 1.0f;
+ boxShapeDef.restitution = 0.1f;
+
+ boxShapeDef.filter.groupIndex = k_smallGroup;
+ boxShapeDef.filter.categoryBits = k_boxCategory;
+ boxShapeDef.filter.maskBits = k_boxMask;
+
+ b2BodyDef boxBodyDef;
+ boxBodyDef.type = b2_dynamicBody;
+ boxBodyDef.position.Set(0.0f, 2.0f);
+
+ b2Body* body3 = m_world->CreateBody(&boxBodyDef);
+ body3->CreateFixture(&boxShapeDef);
+
+ // Large box (recycle definitions)
+ polygon.SetAsBox(2.0f, 1.0f);
+ boxShapeDef.filter.groupIndex = k_largeGroup;
+ boxBodyDef.position.Set(0.0f, 6.0f);
+
+ b2Body* body4 = m_world->CreateBody(&boxBodyDef);
+ body4->CreateFixture(&boxShapeDef);
+
+ // Small circle
+ b2CircleShape circle;
+ circle.m_radius = 1.0f;
+
+ b2FixtureDef circleShapeDef;
+ circleShapeDef.shape = &circle;
+ circleShapeDef.density = 1.0f;
+
+ circleShapeDef.filter.groupIndex = k_smallGroup;
+ circleShapeDef.filter.categoryBits = k_circleCategory;
+ circleShapeDef.filter.maskBits = k_circleMask;
+
+ b2BodyDef circleBodyDef;
+ circleBodyDef.type = b2_dynamicBody;
+ circleBodyDef.position.Set(5.0f, 2.0f);
+
+ b2Body* body5 = m_world->CreateBody(&circleBodyDef);
+ body5->CreateFixture(&circleShapeDef);
+
+ // Large circle
+ circle.m_radius *= 2.0f;
+ circleShapeDef.filter.groupIndex = k_largeGroup;
+ circleBodyDef.position.Set(5.0f, 6.0f);
+
+ b2Body* body6 = m_world->CreateBody(&circleBodyDef);
+ body6->CreateFixture(&circleShapeDef);
+ }
+ static Test* Create()
+ {
+ return new CollisionFiltering;
+ }
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/CollisionProcessing.h b/tests/box2d/Testbed/Tests/CollisionProcessing.h new file mode 100755 index 00000000..c8cc3283 --- /dev/null +++ b/tests/box2d/Testbed/Tests/CollisionProcessing.h @@ -0,0 +1,188 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef COLLISION_PROCESSING_H
+#define COLLISION_PROCESSING_H
+
+#include <algorithm>
+
+// This test shows collision processing and tests
+// deferred body destruction.
+class CollisionProcessing : public Test
+{
+public:
+ CollisionProcessing()
+ {
+ // Ground body
+ {
+ b2EdgeShape shape;
+ shape.Set(b2Vec2(-50.0f, 0.0f), b2Vec2(50.0f, 0.0f));
+
+ b2FixtureDef sd;
+ sd.shape = &shape;;
+
+ b2BodyDef bd;
+ b2Body* ground = m_world->CreateBody(&bd);
+ ground->CreateFixture(&sd);
+ }
+
+ float32 xLo = -5.0f, xHi = 5.0f;
+ float32 yLo = 2.0f, yHi = 35.0f;
+
+ // Small triangle
+ b2Vec2 vertices[3];
+ vertices[0].Set(-1.0f, 0.0f);
+ vertices[1].Set(1.0f, 0.0f);
+ vertices[2].Set(0.0f, 2.0f);
+
+ b2PolygonShape polygon;
+ polygon.Set(vertices, 3);
+
+ b2FixtureDef triangleShapeDef;
+ triangleShapeDef.shape = &polygon;
+ triangleShapeDef.density = 1.0f;
+
+ b2BodyDef triangleBodyDef;
+ triangleBodyDef.type = b2_dynamicBody;
+ triangleBodyDef.position.Set(RandomFloat(xLo, xHi), RandomFloat(yLo, yHi));
+
+ b2Body* body1 = m_world->CreateBody(&triangleBodyDef);
+ body1->CreateFixture(&triangleShapeDef);
+
+ // Large triangle (recycle definitions)
+ vertices[0] *= 2.0f;
+ vertices[1] *= 2.0f;
+ vertices[2] *= 2.0f;
+ polygon.Set(vertices, 3);
+
+ triangleBodyDef.position.Set(RandomFloat(xLo, xHi), RandomFloat(yLo, yHi));
+
+ b2Body* body2 = m_world->CreateBody(&triangleBodyDef);
+ body2->CreateFixture(&triangleShapeDef);
+
+ // Small box
+ polygon.SetAsBox(1.0f, 0.5f);
+
+ b2FixtureDef boxShapeDef;
+ boxShapeDef.shape = &polygon;
+ boxShapeDef.density = 1.0f;
+
+ b2BodyDef boxBodyDef;
+ boxBodyDef.type = b2_dynamicBody;
+ boxBodyDef.position.Set(RandomFloat(xLo, xHi), RandomFloat(yLo, yHi));
+
+ b2Body* body3 = m_world->CreateBody(&boxBodyDef);
+ body3->CreateFixture(&boxShapeDef);
+
+ // Large box (recycle definitions)
+ polygon.SetAsBox(2.0f, 1.0f);
+ boxBodyDef.position.Set(RandomFloat(xLo, xHi), RandomFloat(yLo, yHi));
+
+ b2Body* body4 = m_world->CreateBody(&boxBodyDef);
+ body4->CreateFixture(&boxShapeDef);
+
+ // Small circle
+ b2CircleShape circle;
+ circle.m_radius = 1.0f;
+
+ b2FixtureDef circleShapeDef;
+ circleShapeDef.shape = &circle;
+ circleShapeDef.density = 1.0f;
+
+ b2BodyDef circleBodyDef;
+ circleBodyDef.type = b2_dynamicBody;
+ circleBodyDef.position.Set(RandomFloat(xLo, xHi), RandomFloat(yLo, yHi));
+
+ b2Body* body5 = m_world->CreateBody(&circleBodyDef);
+ body5->CreateFixture(&circleShapeDef);
+
+ // Large circle
+ circle.m_radius *= 2.0f;
+ circleBodyDef.position.Set(RandomFloat(xLo, xHi), RandomFloat(yLo, yHi));
+
+ b2Body* body6 = m_world->CreateBody(&circleBodyDef);
+ body6->CreateFixture(&circleShapeDef);
+ }
+
+ void Step(Settings* settings)
+ {
+ Test::Step(settings);
+
+ // We are going to destroy some bodies according to contact
+ // points. We must buffer the bodies that should be destroyed
+ // because they may belong to multiple contact points.
+ const int32 k_maxNuke = 6;
+ b2Body* nuke[k_maxNuke];
+ int32 nukeCount = 0;
+
+ // Traverse the contact results. Destroy bodies that
+ // are touching heavier bodies.
+ for (int32 i = 0; i < m_pointCount; ++i)
+ {
+ ContactPoint* point = m_points + i;
+
+ b2Body* body1 = point->fixtureA->GetBody();
+ b2Body* body2 = point->fixtureB->GetBody();
+ float32 mass1 = body1->GetMass();
+ float32 mass2 = body2->GetMass();
+
+ if (mass1 > 0.0f && mass2 > 0.0f)
+ {
+ if (mass2 > mass1)
+ {
+ nuke[nukeCount++] = body1;
+ }
+ else
+ {
+ nuke[nukeCount++] = body2;
+ }
+
+ if (nukeCount == k_maxNuke)
+ {
+ break;
+ }
+ }
+ }
+
+ // Sort the nuke array to group duplicates.
+ std::sort(nuke, nuke + nukeCount);
+
+ // Destroy the bodies, skipping duplicates.
+ int32 i = 0;
+ while (i < nukeCount)
+ {
+ b2Body* b = nuke[i++];
+ while (i < nukeCount && nuke[i] == b)
+ {
+ ++i;
+ }
+
+ if (b != m_bomb)
+ {
+ m_world->DestroyBody(b);
+ }
+ }
+ }
+
+ static Test* Create()
+ {
+ return new CollisionProcessing;
+ }
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/CompoundShapes.h b/tests/box2d/Testbed/Tests/CompoundShapes.h new file mode 100755 index 00000000..bc14e882 --- /dev/null +++ b/tests/box2d/Testbed/Tests/CompoundShapes.h @@ -0,0 +1,143 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef COMPOUND_SHAPES_H
+#define COMPOUND_SHAPES_H
+
+// TODO_ERIN test joints on compounds.
+class CompoundShapes : public Test
+{
+public:
+ CompoundShapes()
+ {
+ {
+ b2BodyDef bd;
+ bd.position.Set(0.0f, 0.0f);
+ b2Body* body = m_world->CreateBody(&bd);
+
+ b2EdgeShape shape;
+ shape.Set(b2Vec2(50.0f, 0.0f), b2Vec2(-50.0f, 0.0f));
+
+ body->CreateFixture(&shape, 0.0f);
+ }
+
+ {
+ b2CircleShape circle1;
+ circle1.m_radius = 0.5f;
+ circle1.m_p.Set(-0.5f, 0.5f);
+
+ b2CircleShape circle2;
+ circle2.m_radius = 0.5f;
+ circle2.m_p.Set(0.5f, 0.5f);
+
+ for (int i = 0; i < 10; ++i)
+ {
+ float32 x = RandomFloat(-0.1f, 0.1f);
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(x + 5.0f, 1.05f + 2.5f * i);
+ bd.angle = RandomFloat(-b2_pi, b2_pi);
+ b2Body* body = m_world->CreateBody(&bd);
+ body->CreateFixture(&circle1, 2.0f);
+ body->CreateFixture(&circle2, 0.0f);
+ }
+ }
+
+ {
+ b2PolygonShape polygon1;
+ polygon1.SetAsBox(0.25f, 0.5f);
+
+ b2PolygonShape polygon2;
+ polygon2.SetAsBox(0.25f, 0.5f, b2Vec2(0.0f, -0.5f), 0.5f * b2_pi);
+
+ for (int i = 0; i < 10; ++i)
+ {
+ float32 x = RandomFloat(-0.1f, 0.1f);
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(x - 5.0f, 1.05f + 2.5f * i);
+ bd.angle = RandomFloat(-b2_pi, b2_pi);
+ b2Body* body = m_world->CreateBody(&bd);
+ body->CreateFixture(&polygon1, 2.0f);
+ body->CreateFixture(&polygon2, 2.0f);
+ }
+ }
+
+ {
+ b2Transform xf1;
+ xf1.q.Set(0.3524f * b2_pi);
+ xf1.p = xf1.q.GetXAxis();
+
+ b2Vec2 vertices[3];
+
+ b2PolygonShape triangle1;
+ vertices[0] = b2Mul(xf1, b2Vec2(-1.0f, 0.0f));
+ vertices[1] = b2Mul(xf1, b2Vec2(1.0f, 0.0f));
+ vertices[2] = b2Mul(xf1, b2Vec2(0.0f, 0.5f));
+ triangle1.Set(vertices, 3);
+
+ b2Transform xf2;
+ xf2.q.Set(-0.3524f * b2_pi);
+ xf2.p = -xf2.q.GetXAxis();
+
+ b2PolygonShape triangle2;
+ vertices[0] = b2Mul(xf2, b2Vec2(-1.0f, 0.0f));
+ vertices[1] = b2Mul(xf2, b2Vec2(1.0f, 0.0f));
+ vertices[2] = b2Mul(xf2, b2Vec2(0.0f, 0.5f));
+ triangle2.Set(vertices, 3);
+
+ for (int32 i = 0; i < 10; ++i)
+ {
+ float32 x = RandomFloat(-0.1f, 0.1f);
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(x, 2.05f + 2.5f * i);
+ bd.angle = 0.0f;
+ b2Body* body = m_world->CreateBody(&bd);
+ body->CreateFixture(&triangle1, 2.0f);
+ body->CreateFixture(&triangle2, 2.0f);
+ }
+ }
+
+ {
+ b2PolygonShape bottom;
+ bottom.SetAsBox( 1.5f, 0.15f );
+
+ b2PolygonShape left;
+ left.SetAsBox(0.15f, 2.7f, b2Vec2(-1.45f, 2.35f), 0.2f);
+
+ b2PolygonShape right;
+ right.SetAsBox(0.15f, 2.7f, b2Vec2(1.45f, 2.35f), -0.2f);
+
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set( 0.0f, 2.0f );
+ b2Body* body = m_world->CreateBody(&bd);
+ body->CreateFixture(&bottom, 4.0f);
+ body->CreateFixture(&left, 4.0f);
+ body->CreateFixture(&right, 4.0f);
+ }
+ }
+
+ static Test* Create()
+ {
+ return new CompoundShapes;
+ }
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/Confined.h b/tests/box2d/Testbed/Tests/Confined.h new file mode 100755 index 00000000..f2d205eb --- /dev/null +++ b/tests/box2d/Testbed/Tests/Confined.h @@ -0,0 +1,167 @@ +/*
+* Copyright (c) 2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef CONFINED_H
+#define CONFINED_H
+
+class Confined : public Test
+{
+public:
+
+ enum
+ {
+ e_columnCount = 0,
+ e_rowCount = 0
+ };
+
+ Confined()
+ {
+ {
+ b2BodyDef bd;
+ b2Body* ground = m_world->CreateBody(&bd);
+
+ b2EdgeShape shape;
+
+ // Floor
+ shape.Set(b2Vec2(-10.0f, 0.0f), b2Vec2(10.0f, 0.0f));
+ ground->CreateFixture(&shape, 0.0f);
+
+ // Left wall
+ shape.Set(b2Vec2(-10.0f, 0.0f), b2Vec2(-10.0f, 20.0f));
+ ground->CreateFixture(&shape, 0.0f);
+
+ // Right wall
+ shape.Set(b2Vec2(10.0f, 0.0f), b2Vec2(10.0f, 20.0f));
+ ground->CreateFixture(&shape, 0.0f);
+
+ // Roof
+ shape.Set(b2Vec2(-10.0f, 20.0f), b2Vec2(10.0f, 20.0f));
+ ground->CreateFixture(&shape, 0.0f);
+ }
+
+ float32 radius = 0.5f;
+ b2CircleShape shape;
+ shape.m_p.SetZero();
+ shape.m_radius = radius;
+
+ b2FixtureDef fd;
+ fd.shape = &shape;
+ fd.density = 1.0f;
+ fd.friction = 0.1f;
+
+ for (int32 j = 0; j < e_columnCount; ++j)
+ {
+ for (int i = 0; i < e_rowCount; ++i)
+ {
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(-10.0f + (2.1f * j + 1.0f + 0.01f * i) * radius, (2.0f * i + 1.0f) * radius);
+ b2Body* body = m_world->CreateBody(&bd);
+
+ body->CreateFixture(&fd);
+ }
+ }
+
+ m_world->SetGravity(b2Vec2(0.0f, 0.0f));
+ }
+
+ void CreateCircle()
+ {
+ float32 radius = 2.0f;
+ b2CircleShape shape;
+ shape.m_p.SetZero();
+ shape.m_radius = radius;
+
+ b2FixtureDef fd;
+ fd.shape = &shape;
+ fd.density = 1.0f;
+ fd.friction = 0.0f;
+
+ b2Vec2 p(RandomFloat(), 3.0f + RandomFloat());
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position = p;
+ //bd.allowSleep = false;
+ b2Body* body = m_world->CreateBody(&bd);
+
+ body->CreateFixture(&fd);
+ }
+
+ void Keyboard(unsigned char key)
+ {
+ switch (key)
+ {
+ case 'c':
+ CreateCircle();
+ break;
+ }
+ }
+
+ void Step(Settings* settings)
+ {
+ bool sleeping = true;
+ for (b2Body* b = m_world->GetBodyList(); b; b = b->GetNext())
+ {
+ if (b->GetType() != b2_dynamicBody)
+ {
+ continue;
+ }
+
+ if (b->IsAwake())
+ {
+ sleeping = false;
+ }
+ }
+
+ if (m_stepCount == 180)
+ {
+ m_stepCount += 0;
+ }
+
+ //if (sleeping)
+ //{
+ // CreateCircle();
+ //}
+
+ Test::Step(settings);
+
+ for (b2Body* b = m_world->GetBodyList(); b; b = b->GetNext())
+ {
+ if (b->GetType() != b2_dynamicBody)
+ {
+ continue;
+ }
+
+ b2Vec2 p = b->GetPosition();
+ if (p.x <= -10.0f || 10.0f <= p.x || p.y <= 0.0f || 20.0f <= p.y)
+ {
+ p.x += 0.0;
+ }
+ }
+
+ m_debugDraw.DrawString(5, m_textLine, "Press 'c' to create a circle.");
+ m_textLine += 15;
+ }
+
+ static Test* Create()
+ {
+ return new Confined;
+ }
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/ContinuousTest.h b/tests/box2d/Testbed/Tests/ContinuousTest.h new file mode 100755 index 00000000..817103a5 --- /dev/null +++ b/tests/box2d/Testbed/Tests/ContinuousTest.h @@ -0,0 +1,137 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef CONTINUOUS_TEST_H
+#define CONTINUOUS_TEST_H
+
+class ContinuousTest : public Test
+{
+public:
+
+ ContinuousTest()
+ {
+ {
+ b2BodyDef bd;
+ bd.position.Set(0.0f, 0.0f);
+ b2Body* body = m_world->CreateBody(&bd);
+
+ b2EdgeShape edge;
+
+ edge.Set(b2Vec2(-10.0f, 0.0f), b2Vec2(10.0f, 0.0f));
+ body->CreateFixture(&edge, 0.0f);
+
+ b2PolygonShape shape;
+ shape.SetAsBox(0.2f, 1.0f, b2Vec2(0.5f, 1.0f), 0.0f);
+ body->CreateFixture(&shape, 0.0f);
+ }
+
+#if 1
+ {
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(0.0f, 20.0f);
+ //bd.angle = 0.1f;
+
+ b2PolygonShape shape;
+ shape.SetAsBox(2.0f, 0.1f);
+
+ m_body = m_world->CreateBody(&bd);
+ m_body->CreateFixture(&shape, 1.0f);
+
+ m_angularVelocity = RandomFloat(-50.0f, 50.0f);
+ //m_angularVelocity = 46.661274f;
+ m_body->SetLinearVelocity(b2Vec2(0.0f, -100.0f));
+ m_body->SetAngularVelocity(m_angularVelocity);
+ }
+#else
+ {
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(0.0f, 2.0f);
+ b2Body* body = m_world->CreateBody(&bd);
+
+ b2CircleShape shape;
+ shape.m_p.SetZero();
+ shape.m_radius = 0.5f;
+ body->CreateFixture(&shape, 1.0f);
+
+ bd.bullet = true;
+ bd.position.Set(0.0f, 10.0f);
+ body = m_world->CreateBody(&bd);
+ body->CreateFixture(&shape, 1.0f);
+ body->SetLinearVelocity(b2Vec2(0.0f, -100.0f));
+ }
+#endif
+ }
+
+ void Launch()
+ {
+ m_body->SetTransform(b2Vec2(0.0f, 20.0f), 0.0f);
+ m_angularVelocity = RandomFloat(-50.0f, 50.0f);
+ m_body->SetLinearVelocity(b2Vec2(0.0f, -100.0f));
+ m_body->SetAngularVelocity(m_angularVelocity);
+ }
+
+ void Step(Settings* settings)
+ {
+ if (m_stepCount == 12)
+ {
+ m_stepCount += 0;
+ }
+
+ Test::Step(settings);
+
+ extern int32 b2_gjkCalls, b2_gjkIters, b2_gjkMaxIters;
+
+ if (b2_gjkCalls > 0)
+ {
+ m_debugDraw.DrawString(5, m_textLine, "gjk calls = %d, ave gjk iters = %3.1f, max gjk iters = %d",
+ b2_gjkCalls, b2_gjkIters / float32(b2_gjkCalls), b2_gjkMaxIters);
+ m_textLine += 15;
+ }
+
+ extern int32 b2_toiCalls, b2_toiIters;
+ extern int32 b2_toiRootIters, b2_toiMaxRootIters;
+
+ if (b2_toiCalls > 0)
+ {
+ m_debugDraw.DrawString(5, m_textLine, "toi calls = %d, ave toi iters = %3.1f, max toi iters = %d",
+ b2_toiCalls, b2_toiIters / float32(b2_toiCalls), b2_toiMaxRootIters);
+ m_textLine += 15;
+
+ m_debugDraw.DrawString(5, m_textLine, "ave toi root iters = %3.1f, max toi root iters = %d",
+ b2_toiRootIters / float32(b2_toiCalls), b2_toiMaxRootIters);
+ m_textLine += 15;
+ }
+
+ if (m_stepCount % 60 == 0)
+ {
+ //Launch();
+ }
+ }
+
+ static Test* Create()
+ {
+ return new ContinuousTest;
+ }
+
+ b2Body* m_body;
+ float32 m_angularVelocity;
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/DistanceTest.h b/tests/box2d/Testbed/Tests/DistanceTest.h new file mode 100755 index 00000000..81e96de3 --- /dev/null +++ b/tests/box2d/Testbed/Tests/DistanceTest.h @@ -0,0 +1,135 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef DISTANCE_TEST_H +#define DISTANCE_TEST_H + +class DistanceTest : public Test +{ +public: + DistanceTest() + { + { + m_transformA.SetIdentity(); + m_transformA.p.Set(0.0f, -0.2f); + m_polygonA.SetAsBox(10.0f, 0.2f); + } + + { + m_positionB.Set(12.017401f, 0.13678508f); + m_angleB = -0.0109265f; + m_transformB.Set(m_positionB, m_angleB); + + m_polygonB.SetAsBox(2.0f, 0.1f); + } + } + + static Test* Create() + { + return new DistanceTest; + } + + void Step(Settings* settings) + { + Test::Step(settings); + + b2DistanceInput input; + input.proxyA.Set(&m_polygonA, 0); + input.proxyB.Set(&m_polygonB, 0); + input.transformA = m_transformA; + input.transformB = m_transformB; + input.useRadii = true; + b2SimplexCache cache; + cache.count = 0; + b2DistanceOutput output; + b2Distance(&output, &cache, &input); + + m_debugDraw.DrawString(5, m_textLine, "distance = %g", output.distance); + m_textLine += 15; + + m_debugDraw.DrawString(5, m_textLine, "iterations = %d", output.iterations); + m_textLine += 15; + + { + b2Color color(0.9f, 0.9f, 0.9f); + b2Vec2 v[b2_maxPolygonVertices]; + for (int32 i = 0; i < m_polygonA.m_vertexCount; ++i) + { + v[i] = b2Mul(m_transformA, m_polygonA.m_vertices[i]); + } + m_debugDraw.DrawPolygon(v, m_polygonA.m_vertexCount, color); + + for (int32 i = 0; i < m_polygonB.m_vertexCount; ++i) + { + v[i] = b2Mul(m_transformB, m_polygonB.m_vertices[i]); + } + m_debugDraw.DrawPolygon(v, m_polygonB.m_vertexCount, color); + } + + b2Vec2 x1 = output.pointA; + b2Vec2 x2 = output.pointB; + + b2Color c1(1.0f, 0.0f, 0.0f); + m_debugDraw.DrawPoint(x1, 4.0f, c1); + + b2Color c2(1.0f, 1.0f, 0.0f); + m_debugDraw.DrawPoint(x2, 4.0f, c2); + } + + void Keyboard(unsigned char key) + { + switch (key) + { + case 'a': + m_positionB.x -= 0.1f; + break; + + case 'd': + m_positionB.x += 0.1f; + break; + + case 's': + m_positionB.y -= 0.1f; + break; + + case 'w': + m_positionB.y += 0.1f; + break; + + case 'q': + m_angleB += 0.1f * b2_pi; + break; + + case 'e': + m_angleB -= 0.1f * b2_pi; + break; + } + + m_transformB.Set(m_positionB, m_angleB); + } + + b2Vec2 m_positionB; + float32 m_angleB; + + b2Transform m_transformA; + b2Transform m_transformB; + b2PolygonShape m_polygonA; + b2PolygonShape m_polygonB; +}; + +#endif diff --git a/tests/box2d/Testbed/Tests/Dominos.h b/tests/box2d/Testbed/Tests/Dominos.h new file mode 100755 index 00000000..01e8bbdb --- /dev/null +++ b/tests/box2d/Testbed/Tests/Dominos.h @@ -0,0 +1,215 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef DOMINOS_H
+#define DOMINOS_H
+
+class Dominos : public Test
+{
+public:
+
+ Dominos()
+ {
+ b2Body* b1;
+ {
+ b2EdgeShape shape;
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
+
+ b2BodyDef bd;
+ b1 = m_world->CreateBody(&bd);
+ b1->CreateFixture(&shape, 0.0f);
+ }
+
+ {
+ b2PolygonShape shape;
+ shape.SetAsBox(6.0f, 0.25f);
+
+ b2BodyDef bd;
+ bd.position.Set(-1.5f, 10.0f);
+ b2Body* ground = m_world->CreateBody(&bd);
+ ground->CreateFixture(&shape, 0.0f);
+ }
+
+ {
+ b2PolygonShape shape;
+ shape.SetAsBox(0.1f, 1.0f);
+
+ b2FixtureDef fd;
+ fd.shape = &shape;
+ fd.density = 20.0f;
+ fd.friction = 0.1f;
+
+ for (int i = 0; i < 10; ++i)
+ {
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(-6.0f + 1.0f * i, 11.25f);
+ b2Body* body = m_world->CreateBody(&bd);
+ body->CreateFixture(&fd);
+ }
+ }
+
+ {
+ b2PolygonShape shape;
+ shape.SetAsBox(7.0f, 0.25f, b2Vec2_zero, 0.3f);
+
+ b2BodyDef bd;
+ bd.position.Set(1.0f, 6.0f);
+ b2Body* ground = m_world->CreateBody(&bd);
+ ground->CreateFixture(&shape, 0.0f);
+ }
+
+ b2Body* b2;
+ {
+ b2PolygonShape shape;
+ shape.SetAsBox(0.25f, 1.5f);
+
+ b2BodyDef bd;
+ bd.position.Set(-7.0f, 4.0f);
+ b2 = m_world->CreateBody(&bd);
+ b2->CreateFixture(&shape, 0.0f);
+ }
+
+ b2Body* b3;
+ {
+ b2PolygonShape shape;
+ shape.SetAsBox(6.0f, 0.125f);
+
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(-0.9f, 1.0f);
+ bd.angle = -0.15f;
+
+ b3 = m_world->CreateBody(&bd);
+ b3->CreateFixture(&shape, 10.0f);
+ }
+
+ b2RevoluteJointDef jd;
+ b2Vec2 anchor;
+
+ anchor.Set(-2.0f, 1.0f);
+ jd.Initialize(b1, b3, anchor);
+ jd.collideConnected = true;
+ m_world->CreateJoint(&jd);
+
+ b2Body* b4;
+ {
+ b2PolygonShape shape;
+ shape.SetAsBox(0.25f, 0.25f);
+
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(-10.0f, 15.0f);
+ b4 = m_world->CreateBody(&bd);
+ b4->CreateFixture(&shape, 10.0f);
+ }
+
+ anchor.Set(-7.0f, 15.0f);
+ jd.Initialize(b2, b4, anchor);
+ m_world->CreateJoint(&jd);
+
+ b2Body* b5;
+ {
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(6.5f, 3.0f);
+ b5 = m_world->CreateBody(&bd);
+
+ b2PolygonShape shape;
+ b2FixtureDef fd;
+
+ fd.shape = &shape;
+ fd.density = 10.0f;
+ fd.friction = 0.1f;
+
+ shape.SetAsBox(1.0f, 0.1f, b2Vec2(0.0f, -0.9f), 0.0f);
+ b5->CreateFixture(&fd);
+
+ shape.SetAsBox(0.1f, 1.0f, b2Vec2(-0.9f, 0.0f), 0.0f);
+ b5->CreateFixture(&fd);
+
+ shape.SetAsBox(0.1f, 1.0f, b2Vec2(0.9f, 0.0f), 0.0f);
+ b5->CreateFixture(&fd);
+ }
+
+ anchor.Set(6.0f, 2.0f);
+ jd.Initialize(b1, b5, anchor);
+ m_world->CreateJoint(&jd);
+
+ b2Body* b6;
+ {
+ b2PolygonShape shape;
+ shape.SetAsBox(1.0f, 0.1f);
+
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(6.5f, 4.1f);
+ b6 = m_world->CreateBody(&bd);
+ b6->CreateFixture(&shape, 30.0f);
+ }
+
+ anchor.Set(7.5f, 4.0f);
+ jd.Initialize(b5, b6, anchor);
+ m_world->CreateJoint(&jd);
+
+ b2Body* b7;
+ {
+ b2PolygonShape shape;
+ shape.SetAsBox(0.1f, 1.0f);
+
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(7.4f, 1.0f);
+
+ b7 = m_world->CreateBody(&bd);
+ b7->CreateFixture(&shape, 10.0f);
+ }
+
+ b2DistanceJointDef djd;
+ djd.bodyA = b3;
+ djd.bodyB = b7;
+ djd.localAnchorA.Set(6.0f, 0.0f);
+ djd.localAnchorB.Set(0.0f, -1.0f);
+ b2Vec2 d = djd.bodyB->GetWorldPoint(djd.localAnchorB) - djd.bodyA->GetWorldPoint(djd.localAnchorA);
+ djd.length = d.Length();
+ m_world->CreateJoint(&djd);
+
+ {
+ float32 radius = 0.2f;
+
+ b2CircleShape shape;
+ shape.m_radius = radius;
+
+ for (int32 i = 0; i < 4; ++i)
+ {
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(5.9f + 2.0f * radius * i, 2.4f);
+ b2Body* body = m_world->CreateBody(&bd);
+ body->CreateFixture(&shape, 10.0f);
+ }
+ }
+ }
+
+ static Test* Create()
+ {
+ return new Dominos;
+ }
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/DumpShell.h b/tests/box2d/Testbed/Tests/DumpShell.h new file mode 100755 index 00000000..8437687d --- /dev/null +++ b/tests/box2d/Testbed/Tests/DumpShell.h @@ -0,0 +1,267 @@ +/*
+* Copyright (c) 2011 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef DUMP_SHELL_H
+#define DUMP_SHELL_H
+
+// This test holds worlds dumped using b2World::Dump.
+class DumpShell : public Test
+{
+public:
+
+ DumpShell()
+ {
+
+b2Vec2 g(0.000000000000000e+00f, 0.000000000000000e+00f);
+m_world->SetGravity(g);
+b2Body** bodies = (b2Body**)b2Alloc(3 * sizeof(b2Body*));
+b2Joint** joints = (b2Joint**)b2Alloc(2 * sizeof(b2Joint*));
+{
+ b2BodyDef bd;
+ bd.type = b2BodyType(2);
+ bd.position.Set(1.304347801208496e+01f, 2.500000000000000e+00f);
+ bd.angle = 0.000000000000000e+00f;
+ bd.linearVelocity.Set(0.000000000000000e+00f, 0.000000000000000e+00f);
+ bd.angularVelocity = 0.000000000000000e+00f;
+ bd.linearDamping = 5.000000000000000e-01f;
+ bd.angularDamping = 5.000000000000000e-01f;
+ bd.allowSleep = bool(4);
+ bd.awake = bool(2);
+ bd.fixedRotation = bool(0);
+ bd.bullet = bool(0);
+ bd.active = bool(32);
+ bd.gravityScale = 1.000000000000000e+00f;
+ bodies[0] = m_world->CreateBody(&bd);
+
+ {
+ b2FixtureDef fd;
+ fd.friction = 1.000000000000000e+00f;
+ fd.restitution = 5.000000000000000e-01f;
+ fd.density = 1.000000000000000e+01f;
+ fd.isSensor = bool(0);
+ fd.filter.categoryBits = uint16(1);
+ fd.filter.maskBits = uint16(65535);
+ fd.filter.groupIndex = int16(0);
+ b2PolygonShape shape;
+ b2Vec2 vs[8];
+ vs[0].Set(-6.900000095367432e+00f, -3.000000119209290e-01f);
+ vs[1].Set(2.000000029802322e-01f, -3.000000119209290e-01f);
+ vs[2].Set(2.000000029802322e-01f, 2.000000029802322e-01f);
+ vs[3].Set(-6.900000095367432e+00f, 2.000000029802322e-01f);
+ shape.Set(vs, 4);
+
+ fd.shape = &shape;
+
+ bodies[0]->CreateFixture(&fd);
+ }
+}
+{
+ b2BodyDef bd;
+ bd.type = b2BodyType(2);
+ bd.position.Set(8.478260636329651e-01f, 2.500000000000000e+00f);
+ bd.angle = 0.000000000000000e+00f;
+ bd.linearVelocity.Set(0.000000000000000e+00f, 0.000000000000000e+00f);
+ bd.angularVelocity = 0.000000000000000e+00f;
+ bd.linearDamping = 5.000000000000000e-01f;
+ bd.angularDamping = 5.000000000000000e-01f;
+ bd.allowSleep = bool(4);
+ bd.awake = bool(2);
+ bd.fixedRotation = bool(0);
+ bd.bullet = bool(0);
+ bd.active = bool(32);
+ bd.gravityScale = 1.000000000000000e+00f;
+ bodies[1] = m_world->CreateBody(&bd);
+
+ {
+ b2FixtureDef fd;
+ fd.friction = 1.000000000000000e+00f;
+ fd.restitution = 5.000000000000000e-01f;
+ fd.density = 1.000000000000000e+01f;
+ fd.isSensor = bool(0);
+ fd.filter.categoryBits = uint16(1);
+ fd.filter.maskBits = uint16(65535);
+ fd.filter.groupIndex = int16(0);
+ b2PolygonShape shape;
+ b2Vec2 vs[8];
+ vs[0].Set(-3.228000104427338e-01f, -2.957000136375427e-01f);
+ vs[1].Set(6.885900020599365e+00f, -3.641000092029572e-01f);
+ vs[2].Set(6.907599925994873e+00f, 3.271999955177307e-01f);
+ vs[3].Set(-3.228000104427338e-01f, 2.825999855995178e-01f);
+ shape.Set(vs, 4);
+
+ fd.shape = &shape;
+
+ bodies[1]->CreateFixture(&fd);
+ }
+}
+
+{
+ b2BodyDef bd;
+ bd.type = b2BodyType(0);
+ bd.position.Set(0.000000000000000e+00f, 0.000000000000000e+00f);
+ bd.angle = 0.000000000000000e+00f;
+ bd.linearVelocity.Set(0.000000000000000e+00f, 0.000000000000000e+00f);
+ bd.angularVelocity = 0.000000000000000e+00f;
+ bd.linearDamping = 0.000000000000000e+00f;
+ bd.angularDamping = 0.000000000000000e+00f;
+ bd.allowSleep = bool(4);
+ bd.awake = bool(2);
+ bd.fixedRotation = bool(0);
+ bd.bullet = bool(0);
+ bd.active = bool(32);
+ bd.gravityScale = 1.000000000000000e+00f;
+ bodies[2] = m_world->CreateBody(&bd);
+
+ {
+ b2FixtureDef fd;
+ fd.friction = 1.000000000000000e+01f;
+ fd.restitution = 0.000000000000000e+00f;
+ fd.density = 0.000000000000000e+00f;
+ fd.isSensor = bool(0);
+ fd.filter.categoryBits = uint16(1);
+ fd.filter.maskBits = uint16(65535);
+ fd.filter.groupIndex = int16(0);
+ b2EdgeShape shape;
+ shape.m_radius = 9.999999776482582e-03f;
+ shape.m_vertex0.Set(0.000000000000000e+00f, 0.000000000000000e+00f);
+ shape.m_vertex1.Set(4.452173995971680e+01f, 1.669565200805664e+01f);
+ shape.m_vertex2.Set(4.452173995971680e+01f, 0.000000000000000e+00f);
+ shape.m_vertex3.Set(0.000000000000000e+00f, 0.000000000000000e+00f);
+ shape.m_hasVertex0 = bool(0);
+ shape.m_hasVertex3 = bool(0);
+
+ fd.shape = &shape;
+
+ bodies[2]->CreateFixture(&fd);
+ }
+ {
+ b2FixtureDef fd;
+ fd.friction = 1.000000000000000e+01f;
+ fd.restitution = 0.000000000000000e+00f;
+ fd.density = 0.000000000000000e+00f;
+ fd.isSensor = bool(0);
+ fd.filter.categoryBits = uint16(1);
+ fd.filter.maskBits = uint16(65535);
+ fd.filter.groupIndex = int16(0);
+ b2EdgeShape shape;
+ shape.m_radius = 9.999999776482582e-03f;
+ shape.m_vertex0.Set(0.000000000000000e+00f, 0.000000000000000e+00f);
+ shape.m_vertex1.Set(0.000000000000000e+00f, 1.669565200805664e+01f);
+ shape.m_vertex2.Set(0.000000000000000e+00f, 0.000000000000000e+00f);
+ shape.m_vertex3.Set(0.000000000000000e+00f, 0.000000000000000e+00f);
+ shape.m_hasVertex0 = bool(0);
+ shape.m_hasVertex3 = bool(0);
+
+ fd.shape = &shape;
+
+ bodies[2]->CreateFixture(&fd);
+ }
+ {
+ b2FixtureDef fd;
+ fd.friction = 1.000000000000000e+01f;
+ fd.restitution = 0.000000000000000e+00f;
+ fd.density = 0.000000000000000e+00f;
+ fd.isSensor = bool(0);
+ fd.filter.categoryBits = uint16(1);
+ fd.filter.maskBits = uint16(65535);
+ fd.filter.groupIndex = int16(0);
+ b2EdgeShape shape;
+ shape.m_radius = 9.999999776482582e-03f;
+ shape.m_vertex0.Set(0.000000000000000e+00f, 0.000000000000000e+00f);
+ shape.m_vertex1.Set(0.000000000000000e+00f, 1.669565200805664e+01f);
+ shape.m_vertex2.Set(4.452173995971680e+01f, 1.669565200805664e+01f);
+ shape.m_vertex3.Set(0.000000000000000e+00f, 0.000000000000000e+00f);
+ shape.m_hasVertex0 = bool(0);
+ shape.m_hasVertex3 = bool(0);
+
+ fd.shape = &shape;
+
+ bodies[2]->CreateFixture(&fd);
+ }
+ {
+ b2FixtureDef fd;
+ fd.friction = 1.000000000000000e+01f;
+ fd.restitution = 0.000000000000000e+00f;
+ fd.density = 0.000000000000000e+00f;
+ fd.isSensor = bool(0);
+ fd.filter.categoryBits = uint16(1);
+ fd.filter.maskBits = uint16(65535);
+ fd.filter.groupIndex = int16(0);
+ b2EdgeShape shape;
+ shape.m_radius = 9.999999776482582e-03f;
+ shape.m_vertex0.Set(0.000000000000000e+00f, 0.000000000000000e+00f);
+ shape.m_vertex1.Set(0.000000000000000e+00f, 0.000000000000000e+00f);
+ shape.m_vertex2.Set(4.452173995971680e+01f, 0.000000000000000e+00f);
+ shape.m_vertex3.Set(0.000000000000000e+00f, 0.000000000000000e+00f);
+ shape.m_hasVertex0 = bool(0);
+ shape.m_hasVertex3 = bool(0);
+
+ fd.shape = &shape;
+
+ bodies[2]->CreateFixture(&fd);
+ }
+}
+
+{
+ b2PrismaticJointDef jd;
+ jd.bodyA = bodies[1];
+ jd.bodyB = bodies[0];
+ jd.collideConnected = bool(0);
+ jd.localAnchorA.Set(0.000000000000000e+00f, 0.000000000000000e+00f);
+ jd.localAnchorB.Set(-1.219565200805664e+01f, 0.000000000000000e+00f);
+ jd.localAxisA.Set(-1.219565200805664e+01f, 0.000000000000000e+00f);
+ jd.referenceAngle = 0.000000000000000e+00f;
+ jd.enableLimit = bool(1);
+ jd.lowerTranslation = -2.000000000000000e+01f;
+ jd.upperTranslation = 0.000000000000000e+00f;
+ jd.enableMotor = bool(1);
+ jd.motorSpeed = 0.000000000000000e+00f;
+ jd.maxMotorForce = 1.000000000000000e+01f;
+ joints[0] = m_world->CreateJoint(&jd);
+}
+{
+ b2RevoluteJointDef jd;
+ jd.bodyA = bodies[1];
+ jd.bodyB = bodies[2];
+ jd.collideConnected = bool(0);
+ jd.localAnchorA.Set(0.000000000000000e+00f, 0.000000000000000e+00f);
+ jd.localAnchorB.Set(8.478260636329651e-01f, 2.500000000000000e+00f);
+ jd.referenceAngle = 0.000000000000000e+00f;
+ jd.enableLimit = bool(0);
+ jd.lowerAngle = 0.000000000000000e+00f;
+ jd.upperAngle = 0.000000000000000e+00f;
+ jd.enableMotor = bool(0);
+ jd.motorSpeed = 0.000000000000000e+00f;
+ jd.maxMotorTorque = 0.000000000000000e+00f;
+ joints[1] = m_world->CreateJoint(&jd);
+}
+b2Free(joints);
+b2Free(bodies);
+joints = NULL;
+bodies = NULL;
+
+
+ }
+
+ static Test* Create()
+ {
+ return new DumpShell;
+ }
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/DynamicTreeTest.h b/tests/box2d/Testbed/Tests/DynamicTreeTest.h new file mode 100755 index 00000000..4456a396 --- /dev/null +++ b/tests/box2d/Testbed/Tests/DynamicTreeTest.h @@ -0,0 +1,357 @@ +/*
+* Copyright (c) 2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef DYNAMIC_TREE_TEST_H
+#define DYNAMIC_TREE_TEST_H
+
+class DynamicTreeTest : public Test
+{
+public:
+
+ enum
+ {
+ e_actorCount = 128
+ };
+
+ DynamicTreeTest()
+ {
+ m_worldExtent = 15.0f;
+ m_proxyExtent = 0.5f;
+
+ srand(888);
+
+ for (int32 i = 0; i < e_actorCount; ++i)
+ {
+ Actor* actor = m_actors + i;
+ GetRandomAABB(&actor->aabb);
+ actor->proxyId = m_tree.CreateProxy(actor->aabb, actor);
+ }
+
+ m_stepCount = 0;
+
+ float32 h = m_worldExtent;
+ m_queryAABB.lowerBound.Set(-3.0f, -4.0f + h);
+ m_queryAABB.upperBound.Set(5.0f, 6.0f + h);
+
+ m_rayCastInput.p1.Set(-5.0, 5.0f + h);
+ m_rayCastInput.p2.Set(7.0f, -4.0f + h);
+ //m_rayCastInput.p1.Set(0.0f, 2.0f + h);
+ //m_rayCastInput.p2.Set(0.0f, -2.0f + h);
+ m_rayCastInput.maxFraction = 1.0f;
+
+ m_automated = false;
+ }
+
+ static Test* Create()
+ {
+ return new DynamicTreeTest;
+ }
+
+ void Step(Settings* settings)
+ {
+ B2_NOT_USED(settings);
+
+ m_rayActor = NULL;
+ for (int32 i = 0; i < e_actorCount; ++i)
+ {
+ m_actors[i].fraction = 1.0f;
+ m_actors[i].overlap = false;
+ }
+
+ if (m_automated == true)
+ {
+ int32 actionCount = b2Max(1, e_actorCount >> 2);
+
+ for (int32 i = 0; i < actionCount; ++i)
+ {
+ Action();
+ }
+ }
+
+ Query();
+ RayCast();
+
+ for (int32 i = 0; i < e_actorCount; ++i)
+ {
+ Actor* actor = m_actors + i;
+ if (actor->proxyId == b2_nullNode)
+ continue;
+
+ b2Color c(0.9f, 0.9f, 0.9f);
+ if (actor == m_rayActor && actor->overlap)
+ {
+ c.Set(0.9f, 0.6f, 0.6f);
+ }
+ else if (actor == m_rayActor)
+ {
+ c.Set(0.6f, 0.9f, 0.6f);
+ }
+ else if (actor->overlap)
+ {
+ c.Set(0.6f, 0.6f, 0.9f);
+ }
+
+ m_debugDraw.DrawAABB(&actor->aabb, c);
+ }
+
+ b2Color c(0.7f, 0.7f, 0.7f);
+ m_debugDraw.DrawAABB(&m_queryAABB, c);
+
+ m_debugDraw.DrawSegment(m_rayCastInput.p1, m_rayCastInput.p2, c);
+
+ b2Color c1(0.2f, 0.9f, 0.2f);
+ b2Color c2(0.9f, 0.2f, 0.2f);
+ m_debugDraw.DrawPoint(m_rayCastInput.p1, 6.0f, c1);
+ m_debugDraw.DrawPoint(m_rayCastInput.p2, 6.0f, c2);
+
+ if (m_rayActor)
+ {
+ b2Color cr(0.2f, 0.2f, 0.9f);
+ b2Vec2 p = m_rayCastInput.p1 + m_rayActor->fraction * (m_rayCastInput.p2 - m_rayCastInput.p1);
+ m_debugDraw.DrawPoint(p, 6.0f, cr);
+ }
+
+ {
+ int32 height = m_tree.GetHeight();
+ m_debugDraw.DrawString(5, m_textLine, "dynamic tree height = %d", height);
+ m_textLine += 15;
+ }
+
+ ++m_stepCount;
+ }
+
+ void Keyboard(unsigned char key)
+ {
+ switch (key)
+ {
+ case 'a':
+ m_automated = !m_automated;
+ break;
+
+ case 'c':
+ CreateProxy();
+ break;
+
+ case 'd':
+ DestroyProxy();
+ break;
+
+ case 'm':
+ MoveProxy();
+ break;
+ }
+ }
+
+ bool QueryCallback(int32 proxyId)
+ {
+ Actor* actor = (Actor*)m_tree.GetUserData(proxyId);
+ actor->overlap = b2TestOverlap(m_queryAABB, actor->aabb);
+ return true;
+ }
+
+ float32 RayCastCallback(const b2RayCastInput& input, int32 proxyId)
+ {
+ Actor* actor = (Actor*)m_tree.GetUserData(proxyId);
+
+ b2RayCastOutput output;
+ bool hit = actor->aabb.RayCast(&output, input);
+
+ if (hit)
+ {
+ m_rayCastOutput = output;
+ m_rayActor = actor;
+ m_rayActor->fraction = output.fraction;
+ return output.fraction;
+ }
+
+ return input.maxFraction;
+ }
+
+private:
+
+ struct Actor
+ {
+ b2AABB aabb;
+ float32 fraction;
+ bool overlap;
+ int32 proxyId;
+ };
+
+ void GetRandomAABB(b2AABB* aabb)
+ {
+ b2Vec2 w; w.Set(2.0f * m_proxyExtent, 2.0f * m_proxyExtent);
+ //aabb->lowerBound.x = -m_proxyExtent;
+ //aabb->lowerBound.y = -m_proxyExtent + m_worldExtent;
+ aabb->lowerBound.x = RandomFloat(-m_worldExtent, m_worldExtent);
+ aabb->lowerBound.y = RandomFloat(0.0f, 2.0f * m_worldExtent);
+ aabb->upperBound = aabb->lowerBound + w;
+ }
+
+ void MoveAABB(b2AABB* aabb)
+ {
+ b2Vec2 d;
+ d.x = RandomFloat(-0.5f, 0.5f);
+ d.y = RandomFloat(-0.5f, 0.5f);
+ //d.x = 2.0f;
+ //d.y = 0.0f;
+ aabb->lowerBound += d;
+ aabb->upperBound += d;
+
+ b2Vec2 c0 = 0.5f * (aabb->lowerBound + aabb->upperBound);
+ b2Vec2 min; min.Set(-m_worldExtent, 0.0f);
+ b2Vec2 max; max.Set(m_worldExtent, 2.0f * m_worldExtent);
+ b2Vec2 c = b2Clamp(c0, min, max);
+
+ aabb->lowerBound += c - c0;
+ aabb->upperBound += c - c0;
+ }
+
+ void CreateProxy()
+ {
+ for (int32 i = 0; i < e_actorCount; ++i)
+ {
+ int32 j = rand() % e_actorCount;
+ Actor* actor = m_actors + j;
+ if (actor->proxyId == b2_nullNode)
+ {
+ GetRandomAABB(&actor->aabb);
+ actor->proxyId = m_tree.CreateProxy(actor->aabb, actor);
+ return;
+ }
+ }
+ }
+
+ void DestroyProxy()
+ {
+ for (int32 i = 0; i < e_actorCount; ++i)
+ {
+ int32 j = rand() % e_actorCount;
+ Actor* actor = m_actors + j;
+ if (actor->proxyId != b2_nullNode)
+ {
+ m_tree.DestroyProxy(actor->proxyId);
+ actor->proxyId = b2_nullNode;
+ return;
+ }
+ }
+ }
+
+ void MoveProxy()
+ {
+ for (int32 i = 0; i < e_actorCount; ++i)
+ {
+ int32 j = rand() % e_actorCount;
+ Actor* actor = m_actors + j;
+ if (actor->proxyId == b2_nullNode)
+ {
+ continue;
+ }
+
+ b2AABB aabb0 = actor->aabb;
+ MoveAABB(&actor->aabb);
+ b2Vec2 displacement = actor->aabb.GetCenter() - aabb0.GetCenter();
+ m_tree.MoveProxy(actor->proxyId, actor->aabb, displacement);
+ return;
+ }
+ }
+
+ void Action()
+ {
+ int32 choice = rand() % 20;
+
+ switch (choice)
+ {
+ case 0:
+ CreateProxy();
+ break;
+
+ case 1:
+ DestroyProxy();
+ break;
+
+ default:
+ MoveProxy();
+ }
+ }
+
+ void Query()
+ {
+ m_tree.Query(this, m_queryAABB);
+
+ for (int32 i = 0; i < e_actorCount; ++i)
+ {
+ if (m_actors[i].proxyId == b2_nullNode)
+ {
+ continue;
+ }
+
+ bool overlap = b2TestOverlap(m_queryAABB, m_actors[i].aabb);
+ B2_NOT_USED(overlap);
+ b2Assert(overlap == m_actors[i].overlap);
+ }
+ }
+
+ void RayCast()
+ {
+ m_rayActor = NULL;
+
+ b2RayCastInput input = m_rayCastInput;
+
+ // Ray cast against the dynamic tree.
+ m_tree.RayCast(this, input);
+
+ // Brute force ray cast.
+ Actor* bruteActor = NULL;
+ b2RayCastOutput bruteOutput;
+ for (int32 i = 0; i < e_actorCount; ++i)
+ {
+ if (m_actors[i].proxyId == b2_nullNode)
+ {
+ continue;
+ }
+
+ b2RayCastOutput output;
+ bool hit = m_actors[i].aabb.RayCast(&output, input);
+ if (hit)
+ {
+ bruteActor = m_actors + i;
+ bruteOutput = output;
+ input.maxFraction = output.fraction;
+ }
+ }
+
+ if (bruteActor != NULL)
+ {
+ b2Assert(bruteOutput.fraction == m_rayCastOutput.fraction);
+ }
+ }
+
+ float32 m_worldExtent;
+ float32 m_proxyExtent;
+
+ b2DynamicTree m_tree;
+ b2AABB m_queryAABB;
+ b2RayCastInput m_rayCastInput;
+ b2RayCastOutput m_rayCastOutput;
+ Actor* m_rayActor;
+ Actor m_actors[e_actorCount];
+ int32 m_stepCount;
+ bool m_automated;
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/EdgeShapes.h b/tests/box2d/Testbed/Tests/EdgeShapes.h new file mode 100755 index 00000000..56a6d627 --- /dev/null +++ b/tests/box2d/Testbed/Tests/EdgeShapes.h @@ -0,0 +1,249 @@ +/*
+* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef EDGE_SHAPES_H
+#define EDGE_SHAPES_H
+
+class EdgeShapesCallback : public b2RayCastCallback
+{
+public:
+ EdgeShapesCallback()
+ {
+ m_fixture = NULL;
+ }
+
+ float32 ReportFixture( b2Fixture* fixture, const b2Vec2& point,
+ const b2Vec2& normal, float32 fraction)
+ {
+ m_fixture = fixture;
+ m_point = point;
+ m_normal = normal;
+
+ return fraction;
+ }
+
+ b2Fixture* m_fixture;
+ b2Vec2 m_point;
+ b2Vec2 m_normal;
+};
+
+class EdgeShapes : public Test
+{
+public:
+
+ enum
+ {
+ e_maxBodies = 256
+ };
+
+ EdgeShapes()
+ {
+ // Ground body
+ {
+ b2BodyDef bd;
+ b2Body* ground = m_world->CreateBody(&bd);
+
+ float32 x1 = -20.0f;
+ float32 y1 = 2.0f * cosf(x1 / 10.0f * b2_pi);
+ for (int32 i = 0; i < 80; ++i)
+ {
+ float32 x2 = x1 + 0.5f;
+ float32 y2 = 2.0f * cosf(x2 / 10.0f * b2_pi);
+
+ b2EdgeShape shape;
+ shape.Set(b2Vec2(x1, y1), b2Vec2(x2, y2));
+ ground->CreateFixture(&shape, 0.0f);
+
+ x1 = x2;
+ y1 = y2;
+ }
+ }
+
+ {
+ b2Vec2 vertices[3];
+ vertices[0].Set(-0.5f, 0.0f);
+ vertices[1].Set(0.5f, 0.0f);
+ vertices[2].Set(0.0f, 1.5f);
+ m_polygons[0].Set(vertices, 3);
+ }
+
+ {
+ b2Vec2 vertices[3];
+ vertices[0].Set(-0.1f, 0.0f);
+ vertices[1].Set(0.1f, 0.0f);
+ vertices[2].Set(0.0f, 1.5f);
+ m_polygons[1].Set(vertices, 3);
+ }
+
+ {
+ float32 w = 1.0f;
+ float32 b = w / (2.0f + b2Sqrt(2.0f));
+ float32 s = b2Sqrt(2.0f) * b;
+
+ b2Vec2 vertices[8];
+ vertices[0].Set(0.5f * s, 0.0f);
+ vertices[1].Set(0.5f * w, b);
+ vertices[2].Set(0.5f * w, b + s);
+ vertices[3].Set(0.5f * s, w);
+ vertices[4].Set(-0.5f * s, w);
+ vertices[5].Set(-0.5f * w, b + s);
+ vertices[6].Set(-0.5f * w, b);
+ vertices[7].Set(-0.5f * s, 0.0f);
+
+ m_polygons[2].Set(vertices, 8);
+ }
+
+ {
+ m_polygons[3].SetAsBox(0.5f, 0.5f);
+ }
+
+ {
+ m_circle.m_radius = 0.5f;
+ }
+
+ m_bodyIndex = 0;
+ memset(m_bodies, 0, sizeof(m_bodies));
+
+ m_angle = 0.0f;
+ }
+
+ void Create(int32 index)
+ {
+ if (m_bodies[m_bodyIndex] != NULL)
+ {
+ m_world->DestroyBody(m_bodies[m_bodyIndex]);
+ m_bodies[m_bodyIndex] = NULL;
+ }
+
+ b2BodyDef bd;
+
+ float32 x = RandomFloat(-10.0f, 10.0f);
+ float32 y = RandomFloat(10.0f, 20.0f);
+ bd.position.Set(x, y);
+ bd.angle = RandomFloat(-b2_pi, b2_pi);
+ bd.type = b2_dynamicBody;
+
+ if (index == 4)
+ {
+ bd.angularDamping = 0.02f;
+ }
+
+ m_bodies[m_bodyIndex] = m_world->CreateBody(&bd);
+
+ if (index < 4)
+ {
+ b2FixtureDef fd;
+ fd.shape = m_polygons + index;
+ fd.friction = 0.3f;
+ fd.density = 20.0f;
+ m_bodies[m_bodyIndex]->CreateFixture(&fd);
+ }
+ else
+ {
+ b2FixtureDef fd;
+ fd.shape = &m_circle;
+ fd.friction = 0.3f;
+ fd.density = 20.0f;
+ m_bodies[m_bodyIndex]->CreateFixture(&fd);
+ }
+
+ m_bodyIndex = (m_bodyIndex + 1) % e_maxBodies;
+ }
+
+ void DestroyBody()
+ {
+ for (int32 i = 0; i < e_maxBodies; ++i)
+ {
+ if (m_bodies[i] != NULL)
+ {
+ m_world->DestroyBody(m_bodies[i]);
+ m_bodies[i] = NULL;
+ return;
+ }
+ }
+ }
+
+ void Keyboard(unsigned char key)
+ {
+ switch (key)
+ {
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ Create(key - '1');
+ break;
+
+ case 'd':
+ DestroyBody();
+ break;
+ }
+ }
+
+ void Step(Settings* settings)
+ {
+ bool advanceRay = settings->pause == 0 || settings->singleStep;
+
+ Test::Step(settings);
+ m_debugDraw.DrawString(5, m_textLine, "Press 1-5 to drop stuff");
+ m_textLine += 15;
+
+ float32 L = 25.0f;
+ b2Vec2 point1(0.0f, 10.0f);
+ b2Vec2 d(L * cosf(m_angle), -L * b2Abs(sinf(m_angle)));
+ b2Vec2 point2 = point1 + d;
+
+ EdgeShapesCallback callback;
+
+ m_world->RayCast(&callback, point1, point2);
+
+ if (callback.m_fixture)
+ {
+ m_debugDraw.DrawPoint(callback.m_point, 5.0f, b2Color(0.4f, 0.9f, 0.4f));
+
+ m_debugDraw.DrawSegment(point1, callback.m_point, b2Color(0.8f, 0.8f, 0.8f));
+
+ b2Vec2 head = callback.m_point + 0.5f * callback.m_normal;
+ m_debugDraw.DrawSegment(callback.m_point, head, b2Color(0.9f, 0.9f, 0.4f));
+ }
+ else
+ {
+ m_debugDraw.DrawSegment(point1, point2, b2Color(0.8f, 0.8f, 0.8f));
+ }
+
+ if (advanceRay)
+ {
+ m_angle += 0.25f * b2_pi / 180.0f;
+ }
+ }
+
+ static Test* Create()
+ {
+ return new EdgeShapes;
+ }
+
+ int32 m_bodyIndex;
+ b2Body* m_bodies[e_maxBodies];
+ b2PolygonShape m_polygons[4];
+ b2CircleShape m_circle;
+
+ float32 m_angle;
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/EdgeTest.h b/tests/box2d/Testbed/Tests/EdgeTest.h new file mode 100755 index 00000000..2cabf2e3 --- /dev/null +++ b/tests/box2d/Testbed/Tests/EdgeTest.h @@ -0,0 +1,109 @@ +/*
+* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef EDGE_TEST_H
+#define EDGE_TEST_H
+
+class EdgeTest : public Test
+{
+public:
+
+ EdgeTest()
+ {
+ {
+ b2BodyDef bd;
+ b2Body* ground = m_world->CreateBody(&bd);
+
+ b2Vec2 v1(-10.0f, 0.0f), v2(-7.0f, -2.0f), v3(-4.0f, 0.0f);
+ b2Vec2 v4(0.0f, 0.0f), v5(4.0f, 0.0f), v6(7.0f, 2.0f), v7(10.0f, 0.0f);
+
+ b2EdgeShape shape;
+
+ shape.Set(v1, v2);
+ shape.m_hasVertex3 = true;
+ shape.m_vertex3 = v3;
+ ground->CreateFixture(&shape, 0.0f);
+
+ shape.Set(v2, v3);
+ shape.m_hasVertex0 = true;
+ shape.m_hasVertex3 = true;
+ shape.m_vertex0 = v1;
+ shape.m_vertex3 = v4;
+ ground->CreateFixture(&shape, 0.0f);
+
+ shape.Set(v3, v4);
+ shape.m_hasVertex0 = true;
+ shape.m_hasVertex3 = true;
+ shape.m_vertex0 = v2;
+ shape.m_vertex3 = v5;
+ ground->CreateFixture(&shape, 0.0f);
+
+ shape.Set(v4, v5);
+ shape.m_hasVertex0 = true;
+ shape.m_hasVertex3 = true;
+ shape.m_vertex0 = v3;
+ shape.m_vertex3 = v6;
+ ground->CreateFixture(&shape, 0.0f);
+
+ shape.Set(v5, v6);
+ shape.m_hasVertex0 = true;
+ shape.m_hasVertex3 = true;
+ shape.m_vertex0 = v4;
+ shape.m_vertex3 = v7;
+ ground->CreateFixture(&shape, 0.0f);
+
+ shape.Set(v6, v7);
+ shape.m_hasVertex0 = true;
+ shape.m_vertex0 = v5;
+ ground->CreateFixture(&shape, 0.0f);
+ }
+
+ {
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(-0.5f, 0.6f);
+ bd.allowSleep = false;
+ b2Body* body = m_world->CreateBody(&bd);
+
+ b2CircleShape shape;
+ shape.m_radius = 0.5f;
+
+ body->CreateFixture(&shape, 1.0f);
+ }
+
+ {
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(1.0f, 0.6f);
+ bd.allowSleep = false;
+ b2Body* body = m_world->CreateBody(&bd);
+
+ b2PolygonShape shape;
+ shape.SetAsBox(0.5f, 0.5f);
+
+ body->CreateFixture(&shape, 1.0f);
+ }
+ }
+
+ static Test* Create()
+ {
+ return new EdgeTest;
+ }
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/Gears.h b/tests/box2d/Testbed/Tests/Gears.h new file mode 100755 index 00000000..c1bc7955 --- /dev/null +++ b/tests/box2d/Testbed/Tests/Gears.h @@ -0,0 +1,187 @@ +/*
+* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef GEARS_H
+#define GEARS_H
+
+class Gears : public Test
+{
+public:
+ Gears()
+ {
+ b2Body* ground = NULL;
+ {
+ b2BodyDef bd;
+ ground = m_world->CreateBody(&bd);
+
+ b2EdgeShape shape;
+ shape.Set(b2Vec2(50.0f, 0.0f), b2Vec2(-50.0f, 0.0f));
+ ground->CreateFixture(&shape, 0.0f);
+ }
+
+ // Gears co
+ {
+ b2CircleShape circle1;
+ circle1.m_radius = 1.0f;
+
+ b2PolygonShape box;
+ box.SetAsBox(0.5f, 5.0f);
+
+ b2CircleShape circle2;
+ circle2.m_radius = 2.0f;
+
+ b2BodyDef bd1;
+ bd1.type = b2_staticBody;
+ bd1.position.Set(10.0f, 9.0f);
+ b2Body* body1 = m_world->CreateBody(&bd1);
+ body1->CreateFixture(&circle1, 0.0f);
+
+ b2BodyDef bd2;
+ bd2.type = b2_dynamicBody;
+ bd2.position.Set(10.0f, 8.0f);
+ b2Body* body2 = m_world->CreateBody(&bd2);
+ body2->CreateFixture(&box, 5.0f);
+
+ b2BodyDef bd3;
+ bd3.type = b2_dynamicBody;
+ bd3.position.Set(10.0f, 6.0f);
+ b2Body* body3 = m_world->CreateBody(&bd3);
+ body3->CreateFixture(&circle2, 5.0f);
+
+ b2RevoluteJointDef jd1;
+ jd1.Initialize(body2, body1, bd1.position);
+ b2Joint* joint1 = m_world->CreateJoint(&jd1);
+
+ b2RevoluteJointDef jd2;
+ jd2.Initialize(body2, body3, bd3.position);
+ b2Joint* joint2 = m_world->CreateJoint(&jd2);
+
+ b2GearJointDef jd4;
+ jd4.bodyA = body1;
+ jd4.bodyB = body3;
+ jd4.joint1 = joint1;
+ jd4.joint2 = joint2;
+ jd4.ratio = circle2.m_radius / circle1.m_radius;
+ m_world->CreateJoint(&jd4);
+ }
+
+ {
+ b2CircleShape circle1;
+ circle1.m_radius = 1.0f;
+
+ b2CircleShape circle2;
+ circle2.m_radius = 2.0f;
+
+ b2PolygonShape box;
+ box.SetAsBox(0.5f, 5.0f);
+
+ b2BodyDef bd1;
+ bd1.type = b2_dynamicBody;
+ bd1.position.Set(-3.0f, 12.0f);
+ b2Body* body1 = m_world->CreateBody(&bd1);
+ body1->CreateFixture(&circle1, 5.0f);
+
+ b2RevoluteJointDef jd1;
+ jd1.bodyA = ground;
+ jd1.bodyB = body1;
+ jd1.localAnchorA = ground->GetLocalPoint(bd1.position);
+ jd1.localAnchorB = body1->GetLocalPoint(bd1.position);
+ jd1.referenceAngle = body1->GetAngle() - ground->GetAngle();
+ m_joint1 = (b2RevoluteJoint*)m_world->CreateJoint(&jd1);
+
+ b2BodyDef bd2;
+ bd2.type = b2_dynamicBody;
+ bd2.position.Set(0.0f, 12.0f);
+ b2Body* body2 = m_world->CreateBody(&bd2);
+ body2->CreateFixture(&circle2, 5.0f);
+
+ b2RevoluteJointDef jd2;
+ jd2.Initialize(ground, body2, bd2.position);
+ m_joint2 = (b2RevoluteJoint*)m_world->CreateJoint(&jd2);
+
+ b2BodyDef bd3;
+ bd3.type = b2_dynamicBody;
+ bd3.position.Set(2.5f, 12.0f);
+ b2Body* body3 = m_world->CreateBody(&bd3);
+ body3->CreateFixture(&box, 5.0f);
+
+ b2PrismaticJointDef jd3;
+ jd3.Initialize(ground, body3, bd3.position, b2Vec2(0.0f, 1.0f));
+ jd3.lowerTranslation = -5.0f;
+ jd3.upperTranslation = 5.0f;
+ jd3.enableLimit = true;
+
+ m_joint3 = (b2PrismaticJoint*)m_world->CreateJoint(&jd3);
+
+ b2GearJointDef jd4;
+ jd4.bodyA = body1;
+ jd4.bodyB = body2;
+ jd4.joint1 = m_joint1;
+ jd4.joint2 = m_joint2;
+ jd4.ratio = circle2.m_radius / circle1.m_radius;
+ m_joint4 = (b2GearJoint*)m_world->CreateJoint(&jd4);
+
+ b2GearJointDef jd5;
+ jd5.bodyA = body2;
+ jd5.bodyB = body3;
+ jd5.joint1 = m_joint2;
+ jd5.joint2 = m_joint3;
+ jd5.ratio = -1.0f / circle2.m_radius;
+ m_joint5 = (b2GearJoint*)m_world->CreateJoint(&jd5);
+ }
+ }
+
+ void Keyboard(unsigned char key)
+ {
+ switch (key)
+ {
+ case 0:
+ break;
+ }
+ }
+
+ void Step(Settings* settings)
+ {
+ Test::Step(settings);
+
+ float32 ratio, value;
+
+ ratio = m_joint4->GetRatio();
+ value = m_joint1->GetJointAngle() + ratio * m_joint2->GetJointAngle();
+ m_debugDraw.DrawString(5, m_textLine, "theta1 + %4.2f * theta2 = %4.2f", (float) ratio, (float) value);
+ m_textLine += 15;
+
+ ratio = m_joint5->GetRatio();
+ value = m_joint2->GetJointAngle() + ratio * m_joint3->GetJointTranslation();
+ m_debugDraw.DrawString(5, m_textLine, "theta2 + %4.2f * delta = %4.2f", (float) ratio, (float) value);
+ m_textLine += 15;
+ }
+
+ static Test* Create()
+ {
+ return new Gears;
+ }
+
+ b2RevoluteJoint* m_joint1;
+ b2RevoluteJoint* m_joint2;
+ b2PrismaticJoint* m_joint3;
+ b2GearJoint* m_joint4;
+ b2GearJoint* m_joint5;
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/OneSidedPlatform.h b/tests/box2d/Testbed/Tests/OneSidedPlatform.h new file mode 100755 index 00000000..9d3c84e3 --- /dev/null +++ b/tests/box2d/Testbed/Tests/OneSidedPlatform.h @@ -0,0 +1,120 @@ +/*
+* Copyright (c) 2008-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef ONE_SIDED_PLATFORM_H
+#define ONE_SIDED_PLATFORM_H
+
+class OneSidedPlatform : public Test
+{
+public:
+
+ enum State
+ {
+ e_unknown,
+ e_above,
+ e_below
+ };
+
+ OneSidedPlatform()
+ {
+ // Ground
+ {
+ b2BodyDef bd;
+ b2Body* ground = m_world->CreateBody(&bd);
+
+ b2EdgeShape shape;
+ shape.Set(b2Vec2(-20.0f, 0.0f), b2Vec2(20.0f, 0.0f));
+ ground->CreateFixture(&shape, 0.0f);
+ }
+
+ // Platform
+ {
+ b2BodyDef bd;
+ bd.position.Set(0.0f, 10.0f);
+ b2Body* body = m_world->CreateBody(&bd);
+
+ b2PolygonShape shape;
+ shape.SetAsBox(3.0f, 0.5f);
+ m_platform = body->CreateFixture(&shape, 0.0f);
+
+ m_bottom = 10.0f - 0.5f;
+ m_top = 10.0f + 0.5f;
+ }
+
+ // Actor
+ {
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(0.0f, 12.0f);
+ b2Body* body = m_world->CreateBody(&bd);
+
+ m_radius = 0.5f;
+ b2CircleShape shape;
+ shape.m_radius = m_radius;
+ m_character = body->CreateFixture(&shape, 20.0f);
+
+ body->SetLinearVelocity(b2Vec2(0.0f, -50.0f));
+
+ m_state = e_unknown;
+ }
+ }
+
+ void PreSolve(b2Contact* contact, const b2Manifold* oldManifold)
+ {
+ Test::PreSolve(contact, oldManifold);
+
+ b2Fixture* fixtureA = contact->GetFixtureA();
+ b2Fixture* fixtureB = contact->GetFixtureB();
+
+ if (fixtureA != m_platform && fixtureA != m_character)
+ {
+ return;
+ }
+
+ if (fixtureB != m_platform && fixtureB != m_character)
+ {
+ return;
+ }
+
+ b2Vec2 position = m_character->GetBody()->GetPosition();
+
+ if (position.y < m_top + m_radius - 3.0f * b2_linearSlop)
+ {
+ contact->SetEnabled(false);
+ }
+ }
+
+ void Step(Settings* settings)
+ {
+ Test::Step(settings);
+ m_debugDraw.DrawString(5, m_textLine, "Press: (c) create a shape, (d) destroy a shape.");
+ m_textLine += 15;
+ }
+
+ static Test* Create()
+ {
+ return new OneSidedPlatform;
+ }
+
+ float32 m_radius, m_top, m_bottom;
+ State m_state;
+ b2Fixture* m_platform;
+ b2Fixture* m_character;
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/Pinball.h b/tests/box2d/Testbed/Tests/Pinball.h new file mode 100755 index 00000000..640edf47 --- /dev/null +++ b/tests/box2d/Testbed/Tests/Pinball.h @@ -0,0 +1,169 @@ +/*
+* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef PINBALL_H
+#define PINBALL_H
+
+/// This tests bullet collision and provides an example of a gameplay scenario.
+/// This also uses a loop shape.
+class Pinball : public Test
+{
+public:
+ Pinball()
+ {
+ // Ground body
+ b2Body* ground = NULL;
+ {
+ b2BodyDef bd;
+ ground = m_world->CreateBody(&bd);
+
+ b2Vec2 vs[5];
+ vs[0].Set(0.0f, -2.0f);
+ vs[1].Set(8.0f, 6.0f);
+ vs[2].Set(8.0f, 20.0f);
+ vs[3].Set(-8.0f, 20.0f);
+ vs[4].Set(-8.0f, 6.0f);
+
+ b2ChainShape loop;
+ loop.CreateLoop(vs, 5);
+ b2FixtureDef fd;
+ fd.shape = &loop;
+ fd.density = 0.0f;
+ ground->CreateFixture(&fd);
+ }
+
+ // Flippers
+ {
+ b2Vec2 p1(-2.0f, 0.0f), p2(2.0f, 0.0f);
+
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+
+ bd.position = p1;
+ b2Body* leftFlipper = m_world->CreateBody(&bd);
+
+ bd.position = p2;
+ b2Body* rightFlipper = m_world->CreateBody(&bd);
+
+ b2PolygonShape box;
+ box.SetAsBox(1.75f, 0.1f);
+
+ b2FixtureDef fd;
+ fd.shape = &box;
+ fd.density = 1.0f;
+
+ leftFlipper->CreateFixture(&fd);
+ rightFlipper->CreateFixture(&fd);
+
+ b2RevoluteJointDef jd;
+ jd.bodyA = ground;
+ jd.localAnchorB.SetZero();
+ jd.enableMotor = true;
+ jd.maxMotorTorque = 1000.0f;
+ jd.enableLimit = true;
+
+ jd.motorSpeed = 0.0f;
+ jd.localAnchorA = p1;
+ jd.bodyB = leftFlipper;
+ jd.lowerAngle = -30.0f * b2_pi / 180.0f;
+ jd.upperAngle = 5.0f * b2_pi / 180.0f;
+ m_leftJoint = (b2RevoluteJoint*)m_world->CreateJoint(&jd);
+
+ jd.motorSpeed = 0.0f;
+ jd.localAnchorA = p2;
+ jd.bodyB = rightFlipper;
+ jd.lowerAngle = -5.0f * b2_pi / 180.0f;
+ jd.upperAngle = 30.0f * b2_pi / 180.0f;
+ m_rightJoint = (b2RevoluteJoint*)m_world->CreateJoint(&jd);
+ }
+
+ // Circle character
+ {
+ b2BodyDef bd;
+ bd.position.Set(1.0f, 15.0f);
+ bd.type = b2_dynamicBody;
+ bd.bullet = true;
+
+ m_ball = m_world->CreateBody(&bd);
+
+ b2CircleShape shape;
+ shape.m_radius = 0.2f;
+
+ b2FixtureDef fd;
+ fd.shape = &shape;
+ fd.density = 1.0f;
+ m_ball->CreateFixture(&fd);
+ }
+
+ m_button = false;
+ }
+
+ void Step(Settings* settings)
+ {
+ if (m_button)
+ {
+ m_leftJoint->SetMotorSpeed(20.0f);
+ m_rightJoint->SetMotorSpeed(-20.0f);
+ }
+ else
+ {
+ m_leftJoint->SetMotorSpeed(-10.0f);
+ m_rightJoint->SetMotorSpeed(10.0f);
+ }
+
+ Test::Step(settings);
+
+ m_debugDraw.DrawString(5, m_textLine, "Press 'a' to control the flippers");
+ m_textLine += 15;
+
+ }
+
+ void Keyboard(unsigned char key)
+ {
+ switch (key)
+ {
+ case 'a':
+ case 'A':
+ m_button = true;
+ break;
+ }
+ }
+
+ void KeyboardUp(unsigned char key)
+ {
+ switch (key)
+ {
+ case 'a':
+ case 'A':
+ m_button = false;
+ break;
+ }
+ }
+
+ static Test* Create()
+ {
+ return new Pinball;
+ }
+
+ b2RevoluteJoint* m_leftJoint;
+ b2RevoluteJoint* m_rightJoint;
+ b2Body* m_ball;
+ bool m_button;
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/PolyCollision.h b/tests/box2d/Testbed/Tests/PolyCollision.h new file mode 100755 index 00000000..43ede334 --- /dev/null +++ b/tests/box2d/Testbed/Tests/PolyCollision.h @@ -0,0 +1,122 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef POLYCOLLISION_H
+#define POLYCOLLISION_H
+
+class PolyCollision : public Test
+{
+public:
+ PolyCollision()
+ {
+ {
+ m_polygonA.SetAsBox(0.2f, 0.4f);
+ m_transformA.Set(b2Vec2(0.0f, 0.0f), 0.0f);
+ }
+
+ {
+ m_polygonB.SetAsBox(0.5f, 0.5f);
+ m_positionB.Set(19.345284f, 1.5632932f);
+ m_angleB = 1.9160721f;
+ m_transformB.Set(m_positionB, m_angleB);
+ }
+ }
+
+ static Test* Create()
+ {
+ return new PolyCollision;
+ }
+
+ void Step(Settings* settings)
+ {
+ B2_NOT_USED(settings);
+
+ b2Manifold manifold;
+ b2CollidePolygons(&manifold, &m_polygonA, m_transformA, &m_polygonB, m_transformB);
+
+ b2WorldManifold worldManifold;
+ worldManifold.Initialize(&manifold, m_transformA, m_polygonA.m_radius, m_transformB, m_polygonB.m_radius);
+
+ m_debugDraw.DrawString(5, m_textLine, "point count = %d", manifold.pointCount);
+ m_textLine += 15;
+
+ {
+ b2Color color(0.9f, 0.9f, 0.9f);
+ b2Vec2 v[b2_maxPolygonVertices];
+ for (int32 i = 0; i < m_polygonA.m_vertexCount; ++i)
+ {
+ v[i] = b2Mul(m_transformA, m_polygonA.m_vertices[i]);
+ }
+ m_debugDraw.DrawPolygon(v, m_polygonA.m_vertexCount, color);
+
+ for (int32 i = 0; i < m_polygonB.m_vertexCount; ++i)
+ {
+ v[i] = b2Mul(m_transformB, m_polygonB.m_vertices[i]);
+ }
+ m_debugDraw.DrawPolygon(v, m_polygonB.m_vertexCount, color);
+ }
+
+ for (int32 i = 0; i < manifold.pointCount; ++i)
+ {
+ m_debugDraw.DrawPoint(worldManifold.points[i], 4.0f, b2Color(0.9f, 0.3f, 0.3f));
+ }
+ }
+
+ void Keyboard(unsigned char key)
+ {
+ switch (key)
+ {
+ case 'a':
+ m_positionB.x -= 0.1f;
+ break;
+
+ case 'd':
+ m_positionB.x += 0.1f;
+ break;
+
+ case 's':
+ m_positionB.y -= 0.1f;
+ break;
+
+ case 'w':
+ m_positionB.y += 0.1f;
+ break;
+
+ case 'q':
+ m_angleB += 0.1f * b2_pi;
+ break;
+
+ case 'e':
+ m_angleB -= 0.1f * b2_pi;
+ break;
+ }
+
+ m_transformB.Set(m_positionB, m_angleB);
+ }
+
+ b2PolygonShape m_polygonA;
+ b2PolygonShape m_polygonB;
+
+ b2Transform m_transformA;
+ b2Transform m_transformB;
+
+ b2Vec2 m_positionB;
+ float32 m_angleB;
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/PolyShapes.h b/tests/box2d/Testbed/Tests/PolyShapes.h new file mode 100755 index 00000000..60bb7340 --- /dev/null +++ b/tests/box2d/Testbed/Tests/PolyShapes.h @@ -0,0 +1,295 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef POLY_SHAPES_H
+#define POLY_SHAPES_H
+
+/// This tests stacking. It also shows how to use b2World::Query
+/// and b2TestOverlap.
+
+const int32 k_maxBodies = 256;
+
+/// This callback is called by b2World::QueryAABB. We find all the fixtures
+/// that overlap an AABB. Of those, we use b2TestOverlap to determine which fixtures
+/// overlap a circle. Up to 4 overlapped fixtures will be highlighted with a yellow border.
+class PolyShapesCallback : public b2QueryCallback
+{
+public:
+
+ enum
+ {
+ e_maxCount = 4
+ };
+
+ PolyShapesCallback()
+ {
+ m_count = 0;
+ }
+
+ void DrawFixture(b2Fixture* fixture)
+ {
+ b2Color color(0.95f, 0.95f, 0.6f);
+ const b2Transform& xf = fixture->GetBody()->GetTransform();
+
+ switch (fixture->GetType())
+ {
+ case b2Shape::e_circle:
+ {
+ b2CircleShape* circle = (b2CircleShape*)fixture->GetShape();
+
+ b2Vec2 center = b2Mul(xf, circle->m_p);
+ float32 radius = circle->m_radius;
+
+ m_debugDraw->DrawCircle(center, radius, color);
+ }
+ break;
+
+ case b2Shape::e_polygon:
+ {
+ b2PolygonShape* poly = (b2PolygonShape*)fixture->GetShape();
+ int32 vertexCount = poly->m_vertexCount;
+ b2Assert(vertexCount <= b2_maxPolygonVertices);
+ b2Vec2 vertices[b2_maxPolygonVertices];
+
+ for (int32 i = 0; i < vertexCount; ++i)
+ {
+ vertices[i] = b2Mul(xf, poly->m_vertices[i]);
+ }
+
+ m_debugDraw->DrawPolygon(vertices, vertexCount, color);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ /// Called for each fixture found in the query AABB.
+ /// @return false to terminate the query.
+ bool ReportFixture(b2Fixture* fixture)
+ {
+ if (m_count == e_maxCount)
+ {
+ return false;
+ }
+
+ b2Body* body = fixture->GetBody();
+ b2Shape* shape = fixture->GetShape();
+
+ bool overlap = b2TestOverlap(shape, 0, &m_circle, 0, body->GetTransform(), m_transform);
+
+ if (overlap)
+ {
+ DrawFixture(fixture);
+ ++m_count;
+ }
+
+ return true;
+ }
+
+ b2CircleShape m_circle;
+ b2Transform m_transform;
+ b2Draw* m_debugDraw;
+ int32 m_count;
+};
+
+class PolyShapes : public Test
+{
+public:
+ PolyShapes()
+ {
+ // Ground body
+ {
+ b2BodyDef bd;
+ b2Body* ground = m_world->CreateBody(&bd);
+
+ b2EdgeShape shape;
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
+ ground->CreateFixture(&shape, 0.0f);
+ }
+
+ {
+ b2Vec2 vertices[3];
+ vertices[0].Set(-0.5f, 0.0f);
+ vertices[1].Set(0.5f, 0.0f);
+ vertices[2].Set(0.0f, 1.5f);
+ m_polygons[0].Set(vertices, 3);
+ }
+
+ {
+ b2Vec2 vertices[3];
+ vertices[0].Set(-0.1f, 0.0f);
+ vertices[1].Set(0.1f, 0.0f);
+ vertices[2].Set(0.0f, 1.5f);
+ m_polygons[1].Set(vertices, 3);
+ }
+
+ {
+ float32 w = 1.0f;
+ float32 b = w / (2.0f + b2Sqrt(2.0f));
+ float32 s = b2Sqrt(2.0f) * b;
+
+ b2Vec2 vertices[8];
+ vertices[0].Set(0.5f * s, 0.0f);
+ vertices[1].Set(0.5f * w, b);
+ vertices[2].Set(0.5f * w, b + s);
+ vertices[3].Set(0.5f * s, w);
+ vertices[4].Set(-0.5f * s, w);
+ vertices[5].Set(-0.5f * w, b + s);
+ vertices[6].Set(-0.5f * w, b);
+ vertices[7].Set(-0.5f * s, 0.0f);
+
+ m_polygons[2].Set(vertices, 8);
+ }
+
+ {
+ m_polygons[3].SetAsBox(0.5f, 0.5f);
+ }
+
+ {
+ m_circle.m_radius = 0.5f;
+ }
+
+ m_bodyIndex = 0;
+ memset(m_bodies, 0, sizeof(m_bodies));
+ }
+
+ void Create(int32 index)
+ {
+ if (m_bodies[m_bodyIndex] != NULL)
+ {
+ m_world->DestroyBody(m_bodies[m_bodyIndex]);
+ m_bodies[m_bodyIndex] = NULL;
+ }
+
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+
+ float32 x = RandomFloat(-2.0f, 2.0f);
+ bd.position.Set(x, 10.0f);
+ bd.angle = RandomFloat(-b2_pi, b2_pi);
+
+ if (index == 4)
+ {
+ bd.angularDamping = 0.02f;
+ }
+
+ m_bodies[m_bodyIndex] = m_world->CreateBody(&bd);
+
+ if (index < 4)
+ {
+ b2FixtureDef fd;
+ fd.shape = m_polygons + index;
+ fd.density = 1.0f;
+ fd.friction = 0.3f;
+ m_bodies[m_bodyIndex]->CreateFixture(&fd);
+ }
+ else
+ {
+ b2FixtureDef fd;
+ fd.shape = &m_circle;
+ fd.density = 1.0f;
+ fd.friction = 0.3f;
+
+ m_bodies[m_bodyIndex]->CreateFixture(&fd);
+ }
+
+ m_bodyIndex = (m_bodyIndex + 1) % k_maxBodies;
+ }
+
+ void DestroyBody()
+ {
+ for (int32 i = 0; i < k_maxBodies; ++i)
+ {
+ if (m_bodies[i] != NULL)
+ {
+ m_world->DestroyBody(m_bodies[i]);
+ m_bodies[i] = NULL;
+ return;
+ }
+ }
+ }
+
+ void Keyboard(unsigned char key)
+ {
+ switch (key)
+ {
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ Create(key - '1');
+ break;
+
+ case 'a':
+ for (int32 i = 0; i < k_maxBodies; i += 2)
+ {
+ if (m_bodies[i])
+ {
+ bool active = m_bodies[i]->IsActive();
+ m_bodies[i]->SetActive(!active);
+ }
+ }
+ break;
+
+ case 'd':
+ DestroyBody();
+ break;
+ }
+ }
+
+ void Step(Settings* settings)
+ {
+ Test::Step(settings);
+
+ PolyShapesCallback callback;
+ callback.m_circle.m_radius = 2.0f;
+ callback.m_circle.m_p.Set(0.0f, 1.1f);
+ callback.m_transform.SetIdentity();
+ callback.m_debugDraw = &m_debugDraw;
+
+ b2AABB aabb;
+ callback.m_circle.ComputeAABB(&aabb, callback.m_transform, 0);
+
+ m_world->QueryAABB(&callback, aabb);
+
+ b2Color color(0.4f, 0.7f, 0.8f);
+ m_debugDraw.DrawCircle(callback.m_circle.m_p, callback.m_circle.m_radius, color);
+
+ m_debugDraw.DrawString(5, m_textLine, "Press 1-5 to drop stuff");
+ m_textLine += 15;
+ m_debugDraw.DrawString(5, m_textLine, "Press 'a' to (de)activate some bodies");
+ m_textLine += 15;
+ m_debugDraw.DrawString(5, m_textLine, "Press 'd' to destroy a body");
+ m_textLine += 15;
+ }
+
+ static Test* Create()
+ {
+ return new PolyShapes;
+ }
+
+ int32 m_bodyIndex;
+ b2Body* m_bodies[k_maxBodies];
+ b2PolygonShape m_polygons[4];
+ b2CircleShape m_circle;
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/Prismatic.h b/tests/box2d/Testbed/Tests/Prismatic.h new file mode 100755 index 00000000..fb58cba5 --- /dev/null +++ b/tests/box2d/Testbed/Tests/Prismatic.h @@ -0,0 +1,107 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef PRISMATIC_H
+#define PRISMATIC_H
+
+// The motor in this test gets smoother with higher velocity iterations.
+class Prismatic : public Test
+{
+public:
+ Prismatic()
+ {
+ b2Body* ground = NULL;
+ {
+ b2BodyDef bd;
+ ground = m_world->CreateBody(&bd);
+
+ b2EdgeShape shape;
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
+ ground->CreateFixture(&shape, 0.0f);
+ }
+
+ {
+ b2PolygonShape shape;
+ shape.SetAsBox(2.0f, 0.5f);
+
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(-10.0f, 10.0f);
+ bd.angle = 0.5f * b2_pi;
+ bd.allowSleep = false;
+ b2Body* body = m_world->CreateBody(&bd);
+ body->CreateFixture(&shape, 5.0f);
+
+ b2PrismaticJointDef pjd;
+
+ // Bouncy limit
+ b2Vec2 axis(2.0f, 1.0f);
+ axis.Normalize();
+ pjd.Initialize(ground, body, b2Vec2(0.0f, 0.0f), axis);
+
+ // Non-bouncy limit
+ //pjd.Initialize(ground, body, b2Vec2(-10.0f, 10.0f), b2Vec2(1.0f, 0.0f));
+
+ pjd.motorSpeed = 10.0f;
+ pjd.maxMotorForce = 10000.0f;
+ pjd.enableMotor = true;
+ pjd.lowerTranslation = 0.0f;
+ pjd.upperTranslation = 20.0f;
+ pjd.enableLimit = true;
+
+ m_joint = (b2PrismaticJoint*)m_world->CreateJoint(&pjd);
+ }
+ }
+
+ void Keyboard(unsigned char key)
+ {
+ switch (key)
+ {
+ case 'l':
+ m_joint->EnableLimit(!m_joint->IsLimitEnabled());
+ break;
+
+ case 'm':
+ m_joint->EnableMotor(!m_joint->IsMotorEnabled());
+ break;
+
+ case 's':
+ m_joint->SetMotorSpeed(-m_joint->GetMotorSpeed());
+ break;
+ }
+ }
+
+ void Step(Settings* settings)
+ {
+ Test::Step(settings);
+ m_debugDraw.DrawString(5, m_textLine, "Keys: (l) limits, (m) motors, (s) speed");
+ m_textLine += 15;
+ float32 force = m_joint->GetMotorForce(settings->hz);
+ m_debugDraw.DrawString(5, m_textLine, "Motor Force = %4.0f", (float) force);
+ m_textLine += 15;
+ }
+
+ static Test* Create()
+ {
+ return new Prismatic;
+ }
+
+ b2PrismaticJoint* m_joint;
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/Pulleys.h b/tests/box2d/Testbed/Tests/Pulleys.h new file mode 100755 index 00000000..9c716267 --- /dev/null +++ b/tests/box2d/Testbed/Tests/Pulleys.h @@ -0,0 +1,106 @@ +/*
+* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef PULLEYS_H
+#define PULLEYS_H
+
+class Pulleys : public Test
+{
+public:
+ Pulleys()
+ {
+ float32 y = 16.0f;
+ float32 L = 12.0f;
+ float32 a = 1.0f;
+ float32 b = 2.0f;
+
+ b2Body* ground = NULL;
+ {
+ b2BodyDef bd;
+ ground = m_world->CreateBody(&bd);
+
+ b2EdgeShape edge;
+ edge.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
+ //ground->CreateFixture(&shape, 0.0f);
+
+ b2CircleShape circle;
+ circle.m_radius = 2.0f;
+
+ circle.m_p.Set(-10.0f, y + b + L);
+ ground->CreateFixture(&circle, 0.0f);
+
+ circle.m_p.Set(10.0f, y + b + L);
+ ground->CreateFixture(&circle, 0.0f);
+ }
+
+ {
+
+ b2PolygonShape shape;
+ shape.SetAsBox(a, b);
+
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+
+ //bd.fixedRotation = true;
+ bd.position.Set(-10.0f, y);
+ b2Body* body1 = m_world->CreateBody(&bd);
+ body1->CreateFixture(&shape, 5.0f);
+
+ bd.position.Set(10.0f, y);
+ b2Body* body2 = m_world->CreateBody(&bd);
+ body2->CreateFixture(&shape, 5.0f);
+
+ b2PulleyJointDef pulleyDef;
+ b2Vec2 anchor1(-10.0f, y + b);
+ b2Vec2 anchor2(10.0f, y + b);
+ b2Vec2 groundAnchor1(-10.0f, y + b + L);
+ b2Vec2 groundAnchor2(10.0f, y + b + L);
+ pulleyDef.Initialize(body1, body2, groundAnchor1, groundAnchor2, anchor1, anchor2, 1.5f);
+
+ m_joint1 = (b2PulleyJoint*)m_world->CreateJoint(&pulleyDef);
+ }
+ }
+
+ void Keyboard(unsigned char key)
+ {
+ switch (key)
+ {
+ case 0:
+ break;
+ }
+ }
+
+ void Step(Settings* settings)
+ {
+ Test::Step(settings);
+
+ float32 ratio = m_joint1->GetRatio();
+ float32 L = m_joint1->GetLengthA() + ratio * m_joint1->GetLengthB();
+ m_debugDraw.DrawString(5, m_textLine, "L1 + %4.2f * L2 = %4.2f", (float) ratio, (float) L);
+ m_textLine += 15;
+ }
+
+ static Test* Create()
+ {
+ return new Pulleys;
+ }
+
+ b2PulleyJoint* m_joint1;
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/Pyramid.h b/tests/box2d/Testbed/Tests/Pyramid.h new file mode 100755 index 00000000..ac3cd465 --- /dev/null +++ b/tests/box2d/Testbed/Tests/Pyramid.h @@ -0,0 +1,89 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef PYRAMID_H
+#define PYRAMID_H
+
+class Pyramid : public Test
+{
+public:
+ enum
+ {
+ e_count = 20
+ };
+
+ Pyramid()
+ {
+ {
+ b2BodyDef bd;
+ b2Body* ground = m_world->CreateBody(&bd);
+
+ b2EdgeShape shape;
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
+ ground->CreateFixture(&shape, 0.0f);
+ }
+
+ {
+ float32 a = 0.5f;
+ b2PolygonShape shape;
+ shape.SetAsBox(a, a);
+
+ b2Vec2 x(-7.0f, 0.75f);
+ b2Vec2 y;
+ b2Vec2 deltaX(0.5625f, 1.25f);
+ b2Vec2 deltaY(1.125f, 0.0f);
+
+ for (int32 i = 0; i < e_count; ++i)
+ {
+ y = x;
+
+ for (int32 j = i; j < e_count; ++j)
+ {
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position = y;
+ b2Body* body = m_world->CreateBody(&bd);
+ body->CreateFixture(&shape, 5.0f);
+
+ y += deltaY;
+ }
+
+ x += deltaX;
+ }
+ }
+ }
+
+ void Step(Settings* settings)
+ {
+ Test::Step(settings);
+
+ //b2DynamicTree* tree = &m_world->m_contactManager.m_broadPhase.m_tree;
+
+ //if (m_stepCount == 400)
+ //{
+ // tree->RebuildBottomUp();
+ //}
+ }
+
+ static Test* Create()
+ {
+ return new Pyramid;
+ }
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/RayCast.h b/tests/box2d/Testbed/Tests/RayCast.h new file mode 100755 index 00000000..5eefd9b0 --- /dev/null +++ b/tests/box2d/Testbed/Tests/RayCast.h @@ -0,0 +1,440 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef RAY_CAST_H
+#define RAY_CAST_H
+
+// This test demonstrates how to use the world ray-cast feature.
+// NOTE: we are intentionally filtering one of the polygons, therefore
+// the ray will always miss one type of polygon.
+
+// This callback finds the closest hit. Polygon 0 is filtered.
+class RayCastClosestCallback : public b2RayCastCallback
+{
+public:
+ RayCastClosestCallback()
+ {
+ m_hit = false;
+ }
+
+ float32 ReportFixture( b2Fixture* fixture, const b2Vec2& point,
+ const b2Vec2& normal, float32 fraction)
+ {
+ b2Body* body = fixture->GetBody();
+ void* userData = body->GetUserData();
+ if (userData)
+ {
+ int32 index = *(int32*)userData;
+ if (index == 0)
+ {
+ // filter
+ return -1.0f;
+ }
+ }
+
+ m_hit = true;
+ m_point = point;
+ m_normal = normal;
+ return fraction;
+ }
+
+ bool m_hit;
+ b2Vec2 m_point;
+ b2Vec2 m_normal;
+};
+
+// This callback finds any hit. Polygon 0 is filtered.
+class RayCastAnyCallback : public b2RayCastCallback
+{
+public:
+ RayCastAnyCallback()
+ {
+ m_hit = false;
+ }
+
+ float32 ReportFixture( b2Fixture* fixture, const b2Vec2& point,
+ const b2Vec2& normal, float32 fraction)
+ {
+ b2Body* body = fixture->GetBody();
+ void* userData = body->GetUserData();
+ if (userData)
+ {
+ int32 index = *(int32*)userData;
+ if (index == 0)
+ {
+ // filter
+ return -1.0f;
+ }
+ }
+
+ m_hit = true;
+ m_point = point;
+ m_normal = normal;
+ return 0.0f;
+ }
+
+ bool m_hit;
+ b2Vec2 m_point;
+ b2Vec2 m_normal;
+};
+
+// This ray cast collects multiple hits along the ray. Polygon 0 is filtered.
+class RayCastMultipleCallback : public b2RayCastCallback
+{
+public:
+ enum
+ {
+ e_maxCount = 3
+ };
+
+ RayCastMultipleCallback()
+ {
+ m_count = 0;
+ }
+
+ float32 ReportFixture( b2Fixture* fixture, const b2Vec2& point,
+ const b2Vec2& normal, float32 fraction)
+ {
+ b2Body* body = fixture->GetBody();
+ void* userData = body->GetUserData();
+ if (userData)
+ {
+ int32 index = *(int32*)userData;
+ if (index == 0)
+ {
+ // filter
+ return -1.0f;
+ }
+ }
+
+ b2Assert(m_count < e_maxCount);
+
+ m_points[m_count] = point;
+ m_normals[m_count] = normal;
+ ++m_count;
+
+ if (m_count == e_maxCount)
+ {
+ return 0.0f;
+ }
+
+ return 1.0f;
+ }
+
+ b2Vec2 m_points[e_maxCount];
+ b2Vec2 m_normals[e_maxCount];
+ int32 m_count;
+};
+
+
+class RayCast : public Test
+{
+public:
+
+ enum
+ {
+ e_maxBodies = 256
+ };
+
+ enum Mode
+ {
+ e_closest,
+ e_any,
+ e_multiple
+ };
+
+ RayCast()
+ {
+ // Ground body
+ {
+ b2BodyDef bd;
+ b2Body* ground = m_world->CreateBody(&bd);
+
+ b2EdgeShape shape;
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
+ ground->CreateFixture(&shape, 0.0f);
+ }
+
+ {
+ b2Vec2 vertices[3];
+ vertices[0].Set(-0.5f, 0.0f);
+ vertices[1].Set(0.5f, 0.0f);
+ vertices[2].Set(0.0f, 1.5f);
+ m_polygons[0].Set(vertices, 3);
+ }
+
+ {
+ b2Vec2 vertices[3];
+ vertices[0].Set(-0.1f, 0.0f);
+ vertices[1].Set(0.1f, 0.0f);
+ vertices[2].Set(0.0f, 1.5f);
+ m_polygons[1].Set(vertices, 3);
+ }
+
+ {
+ float32 w = 1.0f;
+ float32 b = w / (2.0f + b2Sqrt(2.0f));
+ float32 s = b2Sqrt(2.0f) * b;
+
+ b2Vec2 vertices[8];
+ vertices[0].Set(0.5f * s, 0.0f);
+ vertices[1].Set(0.5f * w, b);
+ vertices[2].Set(0.5f * w, b + s);
+ vertices[3].Set(0.5f * s, w);
+ vertices[4].Set(-0.5f * s, w);
+ vertices[5].Set(-0.5f * w, b + s);
+ vertices[6].Set(-0.5f * w, b);
+ vertices[7].Set(-0.5f * s, 0.0f);
+
+ m_polygons[2].Set(vertices, 8);
+ }
+
+ {
+ m_polygons[3].SetAsBox(0.5f, 0.5f);
+ }
+
+ {
+ m_circle.m_radius = 0.5f;
+ }
+
+ m_bodyIndex = 0;
+ memset(m_bodies, 0, sizeof(m_bodies));
+
+ m_angle = 0.0f;
+
+ m_mode = e_closest;
+ }
+
+ void Create(int32 index)
+ {
+ if (m_bodies[m_bodyIndex] != NULL)
+ {
+ m_world->DestroyBody(m_bodies[m_bodyIndex]);
+ m_bodies[m_bodyIndex] = NULL;
+ }
+
+ b2BodyDef bd;
+
+ float32 x = RandomFloat(-10.0f, 10.0f);
+ float32 y = RandomFloat(0.0f, 20.0f);
+ bd.position.Set(x, y);
+ bd.angle = RandomFloat(-b2_pi, b2_pi);
+
+ m_userData[m_bodyIndex] = index;
+ bd.userData = m_userData + m_bodyIndex;
+
+ if (index == 4)
+ {
+ bd.angularDamping = 0.02f;
+ }
+
+ m_bodies[m_bodyIndex] = m_world->CreateBody(&bd);
+
+ if (index < 4)
+ {
+ b2FixtureDef fd;
+ fd.shape = m_polygons + index;
+ fd.friction = 0.3f;
+ m_bodies[m_bodyIndex]->CreateFixture(&fd);
+ }
+ else
+ {
+ b2FixtureDef fd;
+ fd.shape = &m_circle;
+ fd.friction = 0.3f;
+
+ m_bodies[m_bodyIndex]->CreateFixture(&fd);
+ }
+
+ m_bodyIndex = (m_bodyIndex + 1) % e_maxBodies;
+ }
+
+ void DestroyBody()
+ {
+ for (int32 i = 0; i < e_maxBodies; ++i)
+ {
+ if (m_bodies[i] != NULL)
+ {
+ m_world->DestroyBody(m_bodies[i]);
+ m_bodies[i] = NULL;
+ return;
+ }
+ }
+ }
+
+ void Keyboard(unsigned char key)
+ {
+ switch (key)
+ {
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ Create(key - '1');
+ break;
+
+ case 'd':
+ DestroyBody();
+ break;
+
+ case 'm':
+ if (m_mode == e_closest)
+ {
+ m_mode = e_any;
+ }
+ else if (m_mode == e_any)
+ {
+ m_mode = e_multiple;
+ }
+ else if (m_mode == e_multiple)
+ {
+ m_mode = e_closest;
+ }
+ }
+ }
+
+ void Step(Settings* settings)
+ {
+ bool advanceRay = settings->pause == 0 || settings->singleStep;
+
+ Test::Step(settings);
+ m_debugDraw.DrawString(5, m_textLine, "Press 1-5 to drop stuff, m to change the mode");
+ m_textLine += 15;
+ m_debugDraw.DrawString(5, m_textLine, "Mode = %d", m_mode);
+ m_textLine += 15;
+
+ float32 L = 11.0f;
+ b2Vec2 point1(0.0f, 10.0f);
+ b2Vec2 d(L * cosf(m_angle), L * sinf(m_angle));
+ b2Vec2 point2 = point1 + d;
+
+ if (m_mode == e_closest)
+ {
+ RayCastClosestCallback callback;
+ m_world->RayCast(&callback, point1, point2);
+
+ if (callback.m_hit)
+ {
+ m_debugDraw.DrawPoint(callback.m_point, 5.0f, b2Color(0.4f, 0.9f, 0.4f));
+ m_debugDraw.DrawSegment(point1, callback.m_point, b2Color(0.8f, 0.8f, 0.8f));
+ b2Vec2 head = callback.m_point + 0.5f * callback.m_normal;
+ m_debugDraw.DrawSegment(callback.m_point, head, b2Color(0.9f, 0.9f, 0.4f));
+ }
+ else
+ {
+ m_debugDraw.DrawSegment(point1, point2, b2Color(0.8f, 0.8f, 0.8f));
+ }
+ }
+ else if (m_mode == e_any)
+ {
+ RayCastAnyCallback callback;
+ m_world->RayCast(&callback, point1, point2);
+
+ if (callback.m_hit)
+ {
+ m_debugDraw.DrawPoint(callback.m_point, 5.0f, b2Color(0.4f, 0.9f, 0.4f));
+ m_debugDraw.DrawSegment(point1, callback.m_point, b2Color(0.8f, 0.8f, 0.8f));
+ b2Vec2 head = callback.m_point + 0.5f * callback.m_normal;
+ m_debugDraw.DrawSegment(callback.m_point, head, b2Color(0.9f, 0.9f, 0.4f));
+ }
+ else
+ {
+ m_debugDraw.DrawSegment(point1, point2, b2Color(0.8f, 0.8f, 0.8f));
+ }
+ }
+ else if (m_mode == e_multiple)
+ {
+ RayCastMultipleCallback callback;
+ m_world->RayCast(&callback, point1, point2);
+ m_debugDraw.DrawSegment(point1, point2, b2Color(0.8f, 0.8f, 0.8f));
+
+ for (int32 i = 0; i < callback.m_count; ++i)
+ {
+ b2Vec2 p = callback.m_points[i];
+ b2Vec2 n = callback.m_normals[i];
+ m_debugDraw.DrawPoint(p, 5.0f, b2Color(0.4f, 0.9f, 0.4f));
+ m_debugDraw.DrawSegment(point1, p, b2Color(0.8f, 0.8f, 0.8f));
+ b2Vec2 head = p + 0.5f * n;
+ m_debugDraw.DrawSegment(p, head, b2Color(0.9f, 0.9f, 0.4f));
+ }
+ }
+
+ if (advanceRay)
+ {
+ m_angle += 0.25f * b2_pi / 180.0f;
+ }
+
+#if 0
+ // This case was failing.
+ {
+ b2Vec2 vertices[4];
+ //vertices[0].Set(-22.875f, -3.0f);
+ //vertices[1].Set(22.875f, -3.0f);
+ //vertices[2].Set(22.875f, 3.0f);
+ //vertices[3].Set(-22.875f, 3.0f);
+
+ b2PolygonShape shape;
+ //shape.Set(vertices, 4);
+ shape.SetAsBox(22.875f, 3.0f);
+
+ b2RayCastInput input;
+ input.p1.Set(10.2725f,1.71372f);
+ input.p2.Set(10.2353f,2.21807f);
+ //input.maxFraction = 0.567623f;
+ input.maxFraction = 0.56762173f;
+
+ b2Transform xf;
+ xf.SetIdentity();
+ xf.position.Set(23.0f, 5.0f);
+
+ b2RayCastOutput output;
+ bool hit;
+ hit = shape.RayCast(&output, input, xf);
+ hit = false;
+
+ b2Color color(1.0f, 1.0f, 1.0f);
+ b2Vec2 vs[4];
+ for (int32 i = 0; i < 4; ++i)
+ {
+ vs[i] = b2Mul(xf, shape.m_vertices[i]);
+ }
+
+ m_debugDraw.DrawPolygon(vs, 4, color);
+ m_debugDraw.DrawSegment(input.p1, input.p2, color);
+ }
+#endif
+ }
+
+ static Test* Create()
+ {
+ return new RayCast;
+ }
+
+ int32 m_bodyIndex;
+ b2Body* m_bodies[e_maxBodies];
+ int32 m_userData[e_maxBodies];
+ b2PolygonShape m_polygons[4];
+ b2CircleShape m_circle;
+
+ float32 m_angle;
+
+ Mode m_mode;
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/Revolute.h b/tests/box2d/Testbed/Tests/Revolute.h new file mode 100755 index 00000000..86ac28a5 --- /dev/null +++ b/tests/box2d/Testbed/Tests/Revolute.h @@ -0,0 +1,166 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef REVOLUTE_H
+#define REVOLUTE_H
+
+class Revolute : public Test
+{
+public:
+ Revolute()
+ {
+ b2Body* ground = NULL;
+ {
+ b2BodyDef bd;
+ ground = m_world->CreateBody(&bd);
+
+ b2EdgeShape shape;
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
+
+ b2FixtureDef fd;
+ fd.shape = &shape;
+ //fd.filter.categoryBits = 2;
+
+ ground->CreateFixture(&fd);
+ }
+
+ {
+ b2CircleShape shape;
+ shape.m_radius = 0.5f;
+
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+
+ b2RevoluteJointDef rjd;
+
+ bd.position.Set(-10.0f, 20.0f);
+ b2Body* body = m_world->CreateBody(&bd);
+ body->CreateFixture(&shape, 5.0f);
+
+ float32 w = 100.0f;
+ body->SetAngularVelocity(w);
+ body->SetLinearVelocity(b2Vec2(-8.0f * w, 0.0f));
+
+ rjd.Initialize(ground, body, b2Vec2(-10.0f, 12.0f));
+ rjd.motorSpeed = 1.0f * b2_pi;
+ rjd.maxMotorTorque = 10000.0f;
+ rjd.enableMotor = false;
+ rjd.lowerAngle = -0.25f * b2_pi;
+ rjd.upperAngle = 0.5f * b2_pi;
+ rjd.enableLimit = true;
+ rjd.collideConnected = true;
+
+ m_joint = (b2RevoluteJoint*)m_world->CreateJoint(&rjd);
+ }
+
+ {
+ b2CircleShape circle_shape;
+ circle_shape.m_radius = 3.0f;
+
+ b2BodyDef circle_bd;
+ circle_bd.type = b2_dynamicBody;
+ circle_bd.position.Set(5.0f, 30.0f);
+
+ b2FixtureDef fd;
+ fd.density = 5.0f;
+ fd.filter.maskBits = 1;
+ fd.shape = &circle_shape;
+
+ m_ball = m_world->CreateBody(&circle_bd);
+ m_ball->CreateFixture(&fd);
+
+ b2PolygonShape polygon_shape;
+ polygon_shape.SetAsBox(10.0f, 0.2f, b2Vec2 (-10.0f, 0.0f), 0.0f);
+
+ b2BodyDef polygon_bd;
+ polygon_bd.position.Set(20.0f, 10.0f);
+ polygon_bd.type = b2_dynamicBody;
+ polygon_bd.bullet = true;
+ b2Body* polygon_body = m_world->CreateBody(&polygon_bd);
+ polygon_body->CreateFixture(&polygon_shape, 2.0f);
+
+ b2RevoluteJointDef rjd;
+ rjd.Initialize(ground, polygon_body, b2Vec2(20.0f, 10.0f));
+ rjd.lowerAngle = -0.25f * b2_pi;
+ rjd.upperAngle = 0.0f * b2_pi;
+ rjd.enableLimit = true;
+ m_world->CreateJoint(&rjd);
+ }
+
+ // Tests mass computation of a small object far from the origin
+ {
+ b2BodyDef bodyDef;
+ bodyDef.type = b2_dynamicBody;
+ b2Body* body = m_world->CreateBody(&bodyDef);
+
+ b2PolygonShape polyShape;
+ b2Vec2 verts[3];
+ verts[0].Set( 17.63f, 36.31f );
+ verts[1].Set( 17.52f, 36.69f );
+ verts[2].Set( 17.19f, 36.36f );
+ polyShape.Set(verts, 3);
+
+ b2FixtureDef polyFixtureDef;
+ polyFixtureDef.shape = &polyShape;
+ polyFixtureDef.density = 1;
+
+ body->CreateFixture(&polyFixtureDef); //assertion hits inside here
+ }
+
+ }
+
+ void Keyboard(unsigned char key)
+ {
+ switch (key)
+ {
+ case 'l':
+ m_joint->EnableLimit(!m_joint->IsLimitEnabled());
+ break;
+
+ case 'm':
+ m_joint->EnableMotor(!m_joint->IsMotorEnabled());
+ break;
+ }
+ }
+
+ void Step(Settings* settings)
+ {
+ Test::Step(settings);
+ m_debugDraw.DrawString(5, m_textLine, "Keys: (l) limits, (m) motor");
+ m_textLine += 15;
+
+ //if (m_stepCount == 360)
+ //{
+ // m_ball->SetTransform(b2Vec2(0.0f, 0.5f), 0.0f);
+ //}
+
+ //float32 torque1 = m_joint1->GetMotorTorque();
+ //m_debugDraw.DrawString(5, m_textLine, "Motor Torque = %4.0f, %4.0f : Motor Force = %4.0f", (float) torque1, (float) torque2, (float) force3);
+ //m_textLine += 15;
+ }
+
+ static Test* Create()
+ {
+ return new Revolute;
+ }
+
+ b2Body* m_ball;
+ b2RevoluteJoint* m_joint;
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/Rope.h b/tests/box2d/Testbed/Tests/Rope.h new file mode 100755 index 00000000..38ff81d4 --- /dev/null +++ b/tests/box2d/Testbed/Tests/Rope.h @@ -0,0 +1,101 @@ +/*
+* Copyright (c) 2011 Erin Catto http://box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef ROPE_H
+#define ROPE_H
+
+///
+class Rope : public Test
+{
+public:
+ Rope()
+ {
+ const int32 N = 40;
+ b2Vec2 vertices[N];
+ float32 masses[N];
+
+ for (int32 i = 0; i < N; ++i)
+ {
+ vertices[i].Set(0.0f, 20.0f - 0.25f * i);
+ masses[i] = 1.0f;
+ }
+ masses[0] = 0.0f;
+ masses[1] = 0.0f;
+
+ b2RopeDef def;
+ def.vertices = vertices;
+ def.count = N;
+ def.gravity.Set(0.0f, -10.0f);
+ def.masses = masses;
+ def.damping = 0.1f;
+ def.k2 = 1.0f;
+ def.k3 = 0.5f;
+
+ m_rope.Initialize(&def);
+
+ m_angle = 0.0f;
+ m_rope.SetAngle(m_angle);
+ }
+
+ void Keyboard(unsigned char key)
+ {
+ switch (key)
+ {
+ case 'q':
+ m_angle = b2Max(-b2_pi, m_angle - 0.05f * b2_pi);
+ m_rope.SetAngle(m_angle);
+ break;
+
+ case 'e':
+ m_angle = b2Min(b2_pi, m_angle + 0.05f * b2_pi);
+ m_rope.SetAngle(m_angle);
+ break;
+ }
+ }
+
+ void Step(Settings* settings)
+ {
+ float32 dt = settings->hz > 0.0f ? 1.0f / settings->hz : 0.0f;
+
+ if (settings->pause == 1 && settings->singleStep == 0)
+ {
+ dt = 0.0f;
+ }
+
+ m_rope.Step(dt, 1);
+
+ Test::Step(settings);
+
+ m_rope.Draw(&m_debugDraw);
+
+ m_debugDraw.DrawString(5, m_textLine, "Press (q,e) to adjust target angle");
+ m_textLine += 15;
+ m_debugDraw.DrawString(5, m_textLine, "Target angle = %g degrees", m_angle * 180.0f / b2_pi);
+ m_textLine += 15;
+ }
+
+ static Test* Create()
+ {
+ return new Rope;
+ }
+
+ b2Rope m_rope;
+ float32 m_angle;
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/RopeJoint.h b/tests/box2d/Testbed/Tests/RopeJoint.h new file mode 100755 index 00000000..038dede0 --- /dev/null +++ b/tests/box2d/Testbed/Tests/RopeJoint.h @@ -0,0 +1,145 @@ +/*
+* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef ROPE_JOINT_H
+#define ROPE_JOINT_H
+
+/// This test shows how a rope joint can be used to stabilize a chain of
+/// bodies with a heavy payload. Notice that the rope joint just prevents
+/// excessive stretching and has no other effect.
+/// By disabling the rope joint you can see that the Box2D solver has trouble
+/// supporting heavy bodies with light bodies. Try playing around with the
+/// densities, time step, and iterations to see how they affect stability.
+/// This test also shows how to use contact filtering. Filtering is configured
+/// so that the payload does not collide with the chain.
+class RopeJoint : public Test
+{
+public:
+ RopeJoint()
+ {
+ b2Body* ground = NULL;
+ {
+ b2BodyDef bd;
+ ground = m_world->CreateBody(&bd);
+
+ b2EdgeShape shape;
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
+ ground->CreateFixture(&shape, 0.0f);
+ }
+
+ {
+ b2PolygonShape shape;
+ shape.SetAsBox(0.5f, 0.125f);
+
+ b2FixtureDef fd;
+ fd.shape = &shape;
+ fd.density = 20.0f;
+ fd.friction = 0.2f;
+ fd.filter.categoryBits = 0x0001;
+ fd.filter.maskBits = 0xFFFF & ~0x0002;
+
+ b2RevoluteJointDef jd;
+ jd.collideConnected = false;
+
+ const int32 N = 10;
+ const float32 y = 15.0f;
+ m_ropeDef.localAnchorA.Set(0.0f, y);
+
+ b2Body* prevBody = ground;
+ for (int32 i = 0; i < N; ++i)
+ {
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(0.5f + 1.0f * i, y);
+ if (i == N - 1)
+ {
+ shape.SetAsBox(1.5f, 1.5f);
+ fd.density = 100.0f;
+ fd.filter.categoryBits = 0x0002;
+ bd.position.Set(1.0f * i, y);
+ bd.angularDamping = 0.4f;
+ }
+
+ b2Body* body = m_world->CreateBody(&bd);
+
+ body->CreateFixture(&fd);
+
+ b2Vec2 anchor(float32(i), y);
+ jd.Initialize(prevBody, body, anchor);
+ m_world->CreateJoint(&jd);
+
+ prevBody = body;
+ }
+
+ m_ropeDef.localAnchorB.SetZero();
+
+ float32 extraLength = 0.01f;
+ m_ropeDef.maxLength = N - 1.0f + extraLength;
+ m_ropeDef.bodyB = prevBody;
+ }
+
+ {
+ m_ropeDef.bodyA = ground;
+ m_rope = m_world->CreateJoint(&m_ropeDef);
+ }
+ }
+
+ void Keyboard(unsigned char key)
+ {
+ switch (key)
+ {
+ case 'j':
+ if (m_rope)
+ {
+ m_world->DestroyJoint(m_rope);
+ m_rope = NULL;
+ }
+ else
+ {
+ m_rope = m_world->CreateJoint(&m_ropeDef);
+ }
+ break;
+ }
+ }
+
+ void Step(Settings* settings)
+ {
+ Test::Step(settings);
+ m_debugDraw.DrawString(5, m_textLine, "Press (j) to toggle the rope joint.");
+ m_textLine += 15;
+ if (m_rope)
+ {
+ m_debugDraw.DrawString(5, m_textLine, "Rope ON");
+ }
+ else
+ {
+ m_debugDraw.DrawString(5, m_textLine, "Rope OFF");
+ }
+ m_textLine += 15;
+ }
+
+ static Test* Create()
+ {
+ return new RopeJoint;
+ }
+
+ b2RopeJointDef m_ropeDef;
+ b2Joint* m_rope;
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/SensorTest.h b/tests/box2d/Testbed/Tests/SensorTest.h new file mode 100755 index 00000000..a2680415 --- /dev/null +++ b/tests/box2d/Testbed/Tests/SensorTest.h @@ -0,0 +1,181 @@ +/*
+* Copyright (c) 2008-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef SENSOR_TEST_H
+#define SENSOR_TEST_H
+
+// This is used to test sensor shapes.
+class SensorTest : public Test
+{
+public:
+
+ enum
+ {
+ e_count = 7
+ };
+
+ SensorTest()
+ {
+ {
+ b2BodyDef bd;
+ b2Body* ground = m_world->CreateBody(&bd);
+
+ {
+ b2EdgeShape shape;
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
+ ground->CreateFixture(&shape, 0.0f);
+ }
+
+#if 0
+ {
+ b2FixtureDef sd;
+ sd.SetAsBox(10.0f, 2.0f, b2Vec2(0.0f, 20.0f), 0.0f);
+ sd.isSensor = true;
+ m_sensor = ground->CreateFixture(&sd);
+ }
+#else
+ {
+ b2CircleShape shape;
+ shape.m_radius = 5.0f;
+ shape.m_p.Set(0.0f, 10.0f);
+
+ b2FixtureDef fd;
+ fd.shape = &shape;
+ fd.isSensor = true;
+ m_sensor = ground->CreateFixture(&fd);
+ }
+#endif
+ }
+
+ {
+ b2CircleShape shape;
+ shape.m_radius = 1.0f;
+
+ for (int32 i = 0; i < e_count; ++i)
+ {
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(-10.0f + 3.0f * i, 20.0f);
+ bd.userData = m_touching + i;
+
+ m_touching[i] = false;
+ m_bodies[i] = m_world->CreateBody(&bd);
+
+ m_bodies[i]->CreateFixture(&shape, 1.0f);
+ }
+ }
+ }
+
+ // Implement contact listener.
+ void BeginContact(b2Contact* contact)
+ {
+ b2Fixture* fixtureA = contact->GetFixtureA();
+ b2Fixture* fixtureB = contact->GetFixtureB();
+
+ if (fixtureA == m_sensor)
+ {
+ void* userData = fixtureB->GetBody()->GetUserData();
+ if (userData)
+ {
+ bool* touching = (bool*)userData;
+ *touching = true;
+ }
+ }
+
+ if (fixtureB == m_sensor)
+ {
+ void* userData = fixtureA->GetBody()->GetUserData();
+ if (userData)
+ {
+ bool* touching = (bool*)userData;
+ *touching = true;
+ }
+ }
+ }
+
+ // Implement contact listener.
+ void EndContact(b2Contact* contact)
+ {
+ b2Fixture* fixtureA = contact->GetFixtureA();
+ b2Fixture* fixtureB = contact->GetFixtureB();
+
+ if (fixtureA == m_sensor)
+ {
+ void* userData = fixtureB->GetBody()->GetUserData();
+ if (userData)
+ {
+ bool* touching = (bool*)userData;
+ *touching = false;
+ }
+ }
+
+ if (fixtureB == m_sensor)
+ {
+ void* userData = fixtureA->GetBody()->GetUserData();
+ if (userData)
+ {
+ bool* touching = (bool*)userData;
+ *touching = false;
+ }
+ }
+ }
+
+ void Step(Settings* settings)
+ {
+ Test::Step(settings);
+
+ // Traverse the contact results. Apply a force on shapes
+ // that overlap the sensor.
+ for (int32 i = 0; i < e_count; ++i)
+ {
+ if (m_touching[i] == false)
+ {
+ continue;
+ }
+
+ b2Body* body = m_bodies[i];
+ b2Body* ground = m_sensor->GetBody();
+
+ b2CircleShape* circle = (b2CircleShape*)m_sensor->GetShape();
+ b2Vec2 center = ground->GetWorldPoint(circle->m_p);
+
+ b2Vec2 position = body->GetPosition();
+
+ b2Vec2 d = center - position;
+ if (d.LengthSquared() < FLT_EPSILON * FLT_EPSILON)
+ {
+ continue;
+ }
+
+ d.Normalize();
+ b2Vec2 F = 100.0f * d;
+ body->ApplyForce(F, position);
+ }
+ }
+
+ static Test* Create()
+ {
+ return new SensorTest;
+ }
+
+ b2Fixture* m_sensor;
+ b2Body* m_bodies[e_count];
+ bool m_touching[e_count];
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/ShapeEditing.h b/tests/box2d/Testbed/Tests/ShapeEditing.h new file mode 100755 index 00000000..c900bbcb --- /dev/null +++ b/tests/box2d/Testbed/Tests/ShapeEditing.h @@ -0,0 +1,105 @@ +/*
+* Copyright (c) 2008-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef SHAPE_EDITING_H
+#define SHAPE_EDITING_H
+
+class ShapeEditing : public Test
+{
+public:
+
+ ShapeEditing()
+ {
+ {
+ b2BodyDef bd;
+ b2Body* ground = m_world->CreateBody(&bd);
+
+ b2EdgeShape shape;
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
+ ground->CreateFixture(&shape, 0.0f);
+ }
+
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(0.0f, 10.0f);
+ m_body = m_world->CreateBody(&bd);
+
+ b2PolygonShape shape;
+ shape.SetAsBox(4.0f, 4.0f, b2Vec2(0.0f, 0.0f), 0.0f);
+ m_fixture1 = m_body->CreateFixture(&shape, 10.0f);
+
+ m_fixture2 = NULL;
+
+ m_sensor = false;
+ }
+
+ void Keyboard(unsigned char key)
+ {
+ switch (key)
+ {
+ case 'c':
+ if (m_fixture2 == NULL)
+ {
+ b2CircleShape shape;
+ shape.m_radius = 3.0f;
+ shape.m_p.Set(0.5f, -4.0f);
+ m_fixture2 = m_body->CreateFixture(&shape, 10.0f);
+ m_body->SetAwake(true);
+ }
+ break;
+
+ case 'd':
+ if (m_fixture2 != NULL)
+ {
+ m_body->DestroyFixture(m_fixture2);
+ m_fixture2 = NULL;
+ m_body->SetAwake(true);
+ }
+ break;
+
+ case 's':
+ if (m_fixture2 != NULL)
+ {
+ m_sensor = !m_sensor;
+ m_fixture2->SetSensor(m_sensor);
+ }
+ break;
+ }
+ }
+
+ void Step(Settings* settings)
+ {
+ Test::Step(settings);
+ m_debugDraw.DrawString(5, m_textLine, "Press: (c) create a shape, (d) destroy a shape.");
+ m_textLine += 15;
+ m_debugDraw.DrawString(5, m_textLine, "sensor = %d", m_sensor);
+ m_textLine += 15;
+ }
+
+ static Test* Create()
+ {
+ return new ShapeEditing;
+ }
+
+ b2Body* m_body;
+ b2Fixture* m_fixture1;
+ b2Fixture* m_fixture2;
+ bool m_sensor;
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/SliderCrank.h b/tests/box2d/Testbed/Tests/SliderCrank.h new file mode 100755 index 00000000..52e6e9cf --- /dev/null +++ b/tests/box2d/Testbed/Tests/SliderCrank.h @@ -0,0 +1,156 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef SLIDER_CRANK_H
+#define SLIDER_CRANK_H
+
+// A motor driven slider crank with joint friction.
+
+class SliderCrank : public Test
+{
+public:
+ SliderCrank()
+ {
+ b2Body* ground = NULL;
+ {
+ b2BodyDef bd;
+ ground = m_world->CreateBody(&bd);
+
+ b2EdgeShape shape;
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
+ ground->CreateFixture(&shape, 0.0f);
+ }
+
+ {
+ b2Body* prevBody = ground;
+
+ // Define crank.
+ {
+ b2PolygonShape shape;
+ shape.SetAsBox(0.5f, 2.0f);
+
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(0.0f, 7.0f);
+ b2Body* body = m_world->CreateBody(&bd);
+ body->CreateFixture(&shape, 2.0f);
+
+ b2RevoluteJointDef rjd;
+ rjd.Initialize(prevBody, body, b2Vec2(0.0f, 5.0f));
+ rjd.motorSpeed = 1.0f * b2_pi;
+ rjd.maxMotorTorque = 10000.0f;
+ rjd.enableMotor = true;
+ m_joint1 = (b2RevoluteJoint*)m_world->CreateJoint(&rjd);
+
+ prevBody = body;
+ }
+
+ // Define follower.
+ {
+ b2PolygonShape shape;
+ shape.SetAsBox(0.5f, 4.0f);
+
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(0.0f, 13.0f);
+ b2Body* body = m_world->CreateBody(&bd);
+ body->CreateFixture(&shape, 2.0f);
+
+ b2RevoluteJointDef rjd;
+ rjd.Initialize(prevBody, body, b2Vec2(0.0f, 9.0f));
+ rjd.enableMotor = false;
+ m_world->CreateJoint(&rjd);
+
+ prevBody = body;
+ }
+
+ // Define piston
+ {
+ b2PolygonShape shape;
+ shape.SetAsBox(1.5f, 1.5f);
+
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.fixedRotation = true;
+ bd.position.Set(0.0f, 17.0f);
+ b2Body* body = m_world->CreateBody(&bd);
+ body->CreateFixture(&shape, 2.0f);
+
+ b2RevoluteJointDef rjd;
+ rjd.Initialize(prevBody, body, b2Vec2(0.0f, 17.0f));
+ m_world->CreateJoint(&rjd);
+
+ b2PrismaticJointDef pjd;
+ pjd.Initialize(ground, body, b2Vec2(0.0f, 17.0f), b2Vec2(0.0f, 1.0f));
+
+ pjd.maxMotorForce = 1000.0f;
+ pjd.enableMotor = true;
+
+ m_joint2 = (b2PrismaticJoint*)m_world->CreateJoint(&pjd);
+ }
+
+ // Create a payload
+ {
+ b2PolygonShape shape;
+ shape.SetAsBox(1.5f, 1.5f);
+
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(0.0f, 23.0f);
+ b2Body* body = m_world->CreateBody(&bd);
+ body->CreateFixture(&shape, 2.0f);
+ }
+ }
+ }
+
+ void Keyboard(unsigned char key)
+ {
+ switch (key)
+ {
+ case 'f':
+ m_joint2->EnableMotor(!m_joint2->IsMotorEnabled());
+ m_joint2->GetBodyB()->SetAwake(true);
+ break;
+
+ case 'm':
+ m_joint1->EnableMotor(!m_joint1->IsMotorEnabled());
+ m_joint1->GetBodyB()->SetAwake(true);
+ break;
+ }
+ }
+
+ void Step(Settings* settings)
+ {
+ Test::Step(settings);
+ m_debugDraw.DrawString(5, m_textLine, "Keys: (f) toggle friction, (m) toggle motor");
+ m_textLine += 15;
+ float32 torque = m_joint1->GetMotorTorque(settings->hz);
+ m_debugDraw.DrawString(5, m_textLine, "Motor Torque = %5.0f", (float) torque);
+ m_textLine += 15;
+ }
+
+ static Test* Create()
+ {
+ return new SliderCrank;
+ }
+
+ b2RevoluteJoint* m_joint1;
+ b2PrismaticJoint* m_joint2;
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/SphereStack.h b/tests/box2d/Testbed/Tests/SphereStack.h new file mode 100755 index 00000000..22485c6d --- /dev/null +++ b/tests/box2d/Testbed/Tests/SphereStack.h @@ -0,0 +1,86 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef SPHERE_STACK_H
+#define SPHERE_STACK_H
+
+class SphereStack : public Test
+{
+public:
+
+ enum
+ {
+ e_count = 10
+ };
+
+ SphereStack()
+ {
+ {
+ b2BodyDef bd;
+ b2Body* ground = m_world->CreateBody(&bd);
+
+ b2EdgeShape shape;
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
+ ground->CreateFixture(&shape, 0.0f);
+ }
+
+ {
+ b2CircleShape shape;
+ shape.m_radius = 1.0f;
+
+ for (int32 i = 0; i < e_count; ++i)
+ {
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(0.0, 4.0f + 3.0f * i);
+
+ m_bodies[i] = m_world->CreateBody(&bd);
+
+ m_bodies[i]->CreateFixture(&shape, 1.0f);
+
+ m_bodies[i]->SetLinearVelocity(b2Vec2(0.0f, -50.0f));
+ }
+ }
+ }
+
+ void Step(Settings* settings)
+ {
+ Test::Step(settings);
+
+ //for (int32 i = 0; i < e_count; ++i)
+ //{
+ // printf("%g ", m_bodies[i]->GetWorldCenter().y);
+ //}
+
+ //for (int32 i = 0; i < e_count; ++i)
+ //{
+ // printf("%g ", m_bodies[i]->GetLinearVelocity().y);
+ //}
+
+ //printf("\n");
+ }
+
+ static Test* Create()
+ {
+ return new SphereStack;
+ }
+
+ b2Body* m_bodies[e_count];
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/TestEntries.cpp b/tests/box2d/Testbed/Tests/TestEntries.cpp new file mode 100755 index 00000000..85db6615 --- /dev/null +++ b/tests/box2d/Testbed/Tests/TestEntries.cpp @@ -0,0 +1,125 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "../Framework/Test.h"
+#include "../Framework/Render.h"
+
+#ifdef __APPLE__
+ #include <GLUT/glut.h>
+#else
+ #include "freeglut/freeglut.h"
+#endif
+
+#include <cstring>
+using namespace std;
+
+#include "AddPair.h"
+#include "ApplyForce.h"
+#include "BodyTypes.h"
+#include "Breakable.h"
+#include "Bridge.h"
+#include "BulletTest.h"
+#include "Cantilever.h"
+#include "Car.h"
+#include "ContinuousTest.h"
+#include "Chain.h"
+#include "CharacterCollision.h"
+#include "CollisionFiltering.h"
+#include "CollisionProcessing.h"
+#include "CompoundShapes.h"
+#include "Confined.h"
+#include "DistanceTest.h"
+#include "Dominos.h"
+#include "DumpShell.h"
+#include "DynamicTreeTest.h"
+#include "EdgeShapes.h"
+#include "EdgeTest.h"
+#include "Gears.h"
+#include "OneSidedPlatform.h"
+#include "Pinball.h"
+#include "PolyCollision.h"
+#include "PolyShapes.h"
+#include "Prismatic.h"
+#include "Pulleys.h"
+#include "Pyramid.h"
+#include "RayCast.h"
+#include "Revolute.h"
+//#include "Rope.h"
+#include "RopeJoint.h"
+#include "SensorTest.h"
+#include "ShapeEditing.h"
+#include "SliderCrank.h"
+#include "SphereStack.h"
+#include "TheoJansen.h"
+#include "Tiles.h"
+#include "TimeOfImpact.h"
+#include "Tumbler.h"
+#include "VaryingFriction.h"
+#include "VaryingRestitution.h"
+#include "VerticalStack.h"
+#include "Web.h"
+
+TestEntry g_testEntries[] =
+{
+ {"Tumbler", Tumbler::Create},
+ {"Tiles", Tiles::Create},
+ {"Dump Shell", DumpShell::Create},
+ {"Gears", Gears::Create},
+ {"Cantilever", Cantilever::Create},
+ {"Varying Restitution", VaryingRestitution::Create},
+ {"Character Collision", CharacterCollision::Create},
+ {"Edge Test", EdgeTest::Create},
+ {"Body Types", BodyTypes::Create},
+ {"Shape Editing", ShapeEditing::Create},
+ {"Car", Car::Create},
+ {"Apply Force", ApplyForce::Create},
+ {"Prismatic", Prismatic::Create},
+ {"Vertical Stack", VerticalStack::Create},
+ {"SphereStack", SphereStack::Create},
+ {"Revolute", Revolute::Create},
+ {"Pulleys", Pulleys::Create},
+ {"Polygon Shapes", PolyShapes::Create},
+ //{"Rope", Rope::Create},
+ {"Web", Web::Create},
+ {"RopeJoint", RopeJoint::Create},
+ {"One-Sided Platform", OneSidedPlatform::Create},
+ {"Pinball", Pinball::Create},
+ {"Bullet Test", BulletTest::Create},
+ {"Continuous Test", ContinuousTest::Create},
+ {"Time of Impact", TimeOfImpact::Create},
+ {"Ray-Cast", RayCast::Create},
+ {"Confined", Confined::Create},
+ {"Pyramid", Pyramid::Create},
+ {"Theo Jansen's Walker", TheoJansen::Create},
+ {"Edge Shapes", EdgeShapes::Create},
+ {"PolyCollision", PolyCollision::Create},
+ {"Bridge", Bridge::Create},
+ {"Breakable", Breakable::Create},
+ {"Chain", Chain::Create},
+ {"Collision Filtering", CollisionFiltering::Create},
+ {"Collision Processing", CollisionProcessing::Create},
+ {"Compound Shapes", CompoundShapes::Create},
+ {"Distance Test", DistanceTest::Create},
+ {"Dominos", Dominos::Create},
+ {"Dynamic Tree", DynamicTreeTest::Create},
+ {"Sensor Test", SensorTest::Create},
+ {"Slider Crank", SliderCrank::Create},
+ {"Varying Friction", VaryingFriction::Create},
+ {"Add Pair Stress Test", AddPair::Create},
+ {NULL, NULL}
+};
diff --git a/tests/box2d/Testbed/Tests/TheoJansen.h b/tests/box2d/Testbed/Tests/TheoJansen.h new file mode 100755 index 00000000..6fb808b9 --- /dev/null +++ b/tests/box2d/Testbed/Tests/TheoJansen.h @@ -0,0 +1,256 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+// Inspired by a contribution by roman_m
+// Dimensions scooped from APE (http://www.cove.org/ape/index.htm)
+
+#ifndef THEO_JANSEN_H
+#define THEO_JANSEN_H
+
+class TheoJansen : public Test
+{
+public:
+
+ void CreateLeg(float32 s, const b2Vec2& wheelAnchor)
+ {
+ b2Vec2 p1(5.4f * s, -6.1f);
+ b2Vec2 p2(7.2f * s, -1.2f);
+ b2Vec2 p3(4.3f * s, -1.9f);
+ b2Vec2 p4(3.1f * s, 0.8f);
+ b2Vec2 p5(6.0f * s, 1.5f);
+ b2Vec2 p6(2.5f * s, 3.7f);
+
+ b2FixtureDef fd1, fd2;
+ fd1.filter.groupIndex = -1;
+ fd2.filter.groupIndex = -1;
+ fd1.density = 1.0f;
+ fd2.density = 1.0f;
+
+ b2PolygonShape poly1, poly2;
+
+ if (s > 0.0f)
+ {
+ b2Vec2 vertices[3];
+
+ vertices[0] = p1;
+ vertices[1] = p2;
+ vertices[2] = p3;
+ poly1.Set(vertices, 3);
+
+ vertices[0] = b2Vec2_zero;
+ vertices[1] = p5 - p4;
+ vertices[2] = p6 - p4;
+ poly2.Set(vertices, 3);
+ }
+ else
+ {
+ b2Vec2 vertices[3];
+
+ vertices[0] = p1;
+ vertices[1] = p3;
+ vertices[2] = p2;
+ poly1.Set(vertices, 3);
+
+ vertices[0] = b2Vec2_zero;
+ vertices[1] = p6 - p4;
+ vertices[2] = p5 - p4;
+ poly2.Set(vertices, 3);
+ }
+
+ fd1.shape = &poly1;
+ fd2.shape = &poly2;
+
+ b2BodyDef bd1, bd2;
+ bd1.type = b2_dynamicBody;
+ bd2.type = b2_dynamicBody;
+ bd1.position = m_offset;
+ bd2.position = p4 + m_offset;
+
+ bd1.angularDamping = 10.0f;
+ bd2.angularDamping = 10.0f;
+
+ b2Body* body1 = m_world->CreateBody(&bd1);
+ b2Body* body2 = m_world->CreateBody(&bd2);
+
+ body1->CreateFixture(&fd1);
+ body2->CreateFixture(&fd2);
+
+ b2DistanceJointDef djd;
+
+ // Using a soft distance constraint can reduce some jitter.
+ // It also makes the structure seem a bit more fluid by
+ // acting like a suspension system.
+ djd.dampingRatio = 0.5f;
+ djd.frequencyHz = 10.0f;
+
+ djd.Initialize(body1, body2, p2 + m_offset, p5 + m_offset);
+ m_world->CreateJoint(&djd);
+
+ djd.Initialize(body1, body2, p3 + m_offset, p4 + m_offset);
+ m_world->CreateJoint(&djd);
+
+ djd.Initialize(body1, m_wheel, p3 + m_offset, wheelAnchor + m_offset);
+ m_world->CreateJoint(&djd);
+
+ djd.Initialize(body2, m_wheel, p6 + m_offset, wheelAnchor + m_offset);
+ m_world->CreateJoint(&djd);
+
+ b2RevoluteJointDef rjd;
+
+ rjd.Initialize(body2, m_chassis, p4 + m_offset);
+ m_world->CreateJoint(&rjd);
+ }
+
+ TheoJansen()
+ {
+ m_offset.Set(0.0f, 8.0f);
+ m_motorSpeed = 2.0f;
+ m_motorOn = true;
+ b2Vec2 pivot(0.0f, 0.8f);
+
+ // Ground
+ {
+ b2BodyDef bd;
+ b2Body* ground = m_world->CreateBody(&bd);
+
+ b2EdgeShape shape;
+ shape.Set(b2Vec2(-50.0f, 0.0f), b2Vec2(50.0f, 0.0f));
+ ground->CreateFixture(&shape, 0.0f);
+
+ shape.Set(b2Vec2(-50.0f, 0.0f), b2Vec2(-50.0f, 10.0f));
+ ground->CreateFixture(&shape, 0.0f);
+
+ shape.Set(b2Vec2(50.0f, 0.0f), b2Vec2(50.0f, 10.0f));
+ ground->CreateFixture(&shape, 0.0f);
+ }
+
+ // Balls
+ for (int32 i = 0; i < 40; ++i)
+ {
+ b2CircleShape shape;
+ shape.m_radius = 0.25f;
+
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(-40.0f + 2.0f * i, 0.5f);
+
+ b2Body* body = m_world->CreateBody(&bd);
+ body->CreateFixture(&shape, 1.0f);
+ }
+
+ // Chassis
+ {
+ b2PolygonShape shape;
+ shape.SetAsBox(2.5f, 1.0f);
+
+ b2FixtureDef sd;
+ sd.density = 1.0f;
+ sd.shape = &shape;
+ sd.filter.groupIndex = -1;
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position = pivot + m_offset;
+ m_chassis = m_world->CreateBody(&bd);
+ m_chassis->CreateFixture(&sd);
+ }
+
+ {
+ b2CircleShape shape;
+ shape.m_radius = 1.6f;
+
+ b2FixtureDef sd;
+ sd.density = 1.0f;
+ sd.shape = &shape;
+ sd.filter.groupIndex = -1;
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position = pivot + m_offset;
+ m_wheel = m_world->CreateBody(&bd);
+ m_wheel->CreateFixture(&sd);
+ }
+
+ {
+ b2RevoluteJointDef jd;
+ jd.Initialize(m_wheel, m_chassis, pivot + m_offset);
+ jd.collideConnected = false;
+ jd.motorSpeed = m_motorSpeed;
+ jd.maxMotorTorque = 400.0f;
+ jd.enableMotor = m_motorOn;
+ m_motorJoint = (b2RevoluteJoint*)m_world->CreateJoint(&jd);
+ }
+
+ b2Vec2 wheelAnchor;
+
+ wheelAnchor = pivot + b2Vec2(0.0f, -0.8f);
+
+ CreateLeg(-1.0f, wheelAnchor);
+ CreateLeg(1.0f, wheelAnchor);
+
+ m_wheel->SetTransform(m_wheel->GetPosition(), 120.0f * b2_pi / 180.0f);
+ CreateLeg(-1.0f, wheelAnchor);
+ CreateLeg(1.0f, wheelAnchor);
+
+ m_wheel->SetTransform(m_wheel->GetPosition(), -120.0f * b2_pi / 180.0f);
+ CreateLeg(-1.0f, wheelAnchor);
+ CreateLeg(1.0f, wheelAnchor);
+ }
+
+ void Step(Settings* settings)
+ {
+ m_debugDraw.DrawString(5, m_textLine, "Keys: left = a, brake = s, right = d, toggle motor = m");
+ m_textLine += 15;
+
+ Test::Step(settings);
+ }
+
+ void Keyboard(unsigned char key)
+ {
+ switch (key)
+ {
+ case 'a':
+ m_motorJoint->SetMotorSpeed(-m_motorSpeed);
+ break;
+
+ case 's':
+ m_motorJoint->SetMotorSpeed(0.0f);
+ break;
+
+ case 'd':
+ m_motorJoint->SetMotorSpeed(m_motorSpeed);
+ break;
+
+ case 'm':
+ m_motorJoint->EnableMotor(!m_motorJoint->IsMotorEnabled());
+ break;
+ }
+ }
+
+ static Test* Create()
+ {
+ return new TheoJansen;
+ }
+
+ b2Vec2 m_offset;
+ b2Body* m_chassis;
+ b2Body* m_wheel;
+ b2RevoluteJoint* m_motorJoint;
+ bool m_motorOn;
+ float32 m_motorSpeed;
+};
+
+#endif // THEO_JANSEN_H
diff --git a/tests/box2d/Testbed/Tests/Tiles.h b/tests/box2d/Testbed/Tests/Tiles.h new file mode 100755 index 00000000..a437961c --- /dev/null +++ b/tests/box2d/Testbed/Tests/Tiles.h @@ -0,0 +1,156 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef TILES_H
+#define TILES_H
+
+/// This stress tests the dynamic tree broad-phase. This also shows that tile
+/// based collision is _not_ smooth due to Box2D not knowing about adjacency.
+class Tiles : public Test
+{
+public:
+ enum
+ {
+ e_count = 20
+ };
+
+ Tiles()
+ {
+ m_fixtureCount = 0;
+ b2Timer timer;
+
+ {
+ float32 a = 0.5f;
+ b2BodyDef bd;
+ bd.position.y = -a;
+ b2Body* ground = m_world->CreateBody(&bd);
+
+#if 1
+ int32 N = 200;
+ int32 M = 10;
+ b2Vec2 position;
+ position.y = 0.0f;
+ for (int32 j = 0; j < M; ++j)
+ {
+ position.x = -N * a;
+ for (int32 i = 0; i < N; ++i)
+ {
+ b2PolygonShape shape;
+ shape.SetAsBox(a, a, position, 0.0f);
+ ground->CreateFixture(&shape, 0.0f);
+ ++m_fixtureCount;
+ position.x += 2.0f * a;
+ }
+ position.y -= 2.0f * a;
+ }
+#else
+ int32 N = 200;
+ int32 M = 10;
+ b2Vec2 position;
+ position.x = -N * a;
+ for (int32 i = 0; i < N; ++i)
+ {
+ position.y = 0.0f;
+ for (int32 j = 0; j < M; ++j)
+ {
+ b2PolygonShape shape;
+ shape.SetAsBox(a, a, position, 0.0f);
+ ground->CreateFixture(&shape, 0.0f);
+ position.y -= 2.0f * a;
+ }
+ position.x += 2.0f * a;
+ }
+#endif
+ }
+
+ {
+ float32 a = 0.5f;
+ b2PolygonShape shape;
+ shape.SetAsBox(a, a);
+
+ b2Vec2 x(-7.0f, 0.75f);
+ b2Vec2 y;
+ b2Vec2 deltaX(0.5625f, 1.25f);
+ b2Vec2 deltaY(1.125f, 0.0f);
+
+ for (int32 i = 0; i < e_count; ++i)
+ {
+ y = x;
+
+ for (int32 j = i; j < e_count; ++j)
+ {
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position = y;
+
+ //if (i == 0 && j == 0)
+ //{
+ // bd.allowSleep = false;
+ //}
+ //else
+ //{
+ // bd.allowSleep = true;
+ //}
+
+ b2Body* body = m_world->CreateBody(&bd);
+ body->CreateFixture(&shape, 5.0f);
+ ++m_fixtureCount;
+ y += deltaY;
+ }
+
+ x += deltaX;
+ }
+ }
+
+ m_createTime = timer.GetMilliseconds();
+ }
+
+ void Step(Settings* settings)
+ {
+ const b2ContactManager& cm = m_world->GetContactManager();
+ int32 height = cm.m_broadPhase.GetTreeHeight();
+ int32 leafCount = cm.m_broadPhase.GetProxyCount();
+ int32 minimumNodeCount = 2 * leafCount - 1;
+ float32 minimumHeight = ceilf(logf(float32(minimumNodeCount)) / logf(2.0f));
+ m_debugDraw.DrawString(5, m_textLine, "dynamic tree height = %d, min = %d", height, int32(minimumHeight));
+ m_textLine += 15;
+
+ Test::Step(settings);
+
+ m_debugDraw.DrawString(5, m_textLine, "create time = %6.2f ms, fixture count = %d",
+ m_createTime, m_fixtureCount);
+ m_textLine += 15;
+
+ //b2DynamicTree* tree = &m_world->m_contactManager.m_broadPhase.m_tree;
+
+ //if (m_stepCount == 400)
+ //{
+ // tree->RebuildBottomUp();
+ //}
+ }
+
+ static Test* Create()
+ {
+ return new Tiles;
+ }
+
+ int32 m_fixtureCount;
+ float32 m_createTime;
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/TimeOfImpact.h b/tests/box2d/Testbed/Tests/TimeOfImpact.h new file mode 100755 index 00000000..f836e0e0 --- /dev/null +++ b/tests/box2d/Testbed/Tests/TimeOfImpact.h @@ -0,0 +1,131 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef TIME_OF_IMPACT_H
+#define TIME_OF_IMPACT_H
+
+class TimeOfImpact : public Test
+{
+public:
+ TimeOfImpact()
+ {
+ m_shapeA.SetAsBox(25.0f, 5.0f);
+ m_shapeB.SetAsBox(2.5f, 2.5f);
+ }
+
+ static Test* Create()
+ {
+ return new TimeOfImpact;
+ }
+
+ void Step(Settings* settings)
+ {
+ Test::Step(settings);
+
+ b2Sweep sweepA;
+ sweepA.c0.Set(24.0f, -60.0f);
+ sweepA.a0 = 2.95f;
+ sweepA.c = sweepA.c0;
+ sweepA.a = sweepA.a0;
+ sweepA.localCenter.SetZero();
+
+ b2Sweep sweepB;
+ sweepB.c0.Set(53.474274f, -50.252514f);
+ sweepB.a0 = 513.36676f; // - 162.0f * b2_pi;
+ sweepB.c.Set(54.595478f, -51.083473f);
+ sweepB.a = 513.62781f; // - 162.0f * b2_pi;
+ sweepB.localCenter.SetZero();
+
+ //sweepB.a0 -= 300.0f * b2_pi;
+ //sweepB.a -= 300.0f * b2_pi;
+
+ b2TOIInput input;
+ input.proxyA.Set(&m_shapeA, 0);
+ input.proxyB.Set(&m_shapeB, 0);
+ input.sweepA = sweepA;
+ input.sweepB = sweepB;
+ input.tMax = 1.0f;
+
+ b2TOIOutput output;
+
+ b2TimeOfImpact(&output, &input);
+
+ m_debugDraw.DrawString(5, m_textLine, "toi = %g", output.t);
+ m_textLine += 15;
+
+ extern int32 b2_toiMaxIters, b2_toiMaxRootIters;
+ m_debugDraw.DrawString(5, m_textLine, "max toi iters = %d, max root iters = %d", b2_toiMaxIters, b2_toiMaxRootIters);
+ m_textLine += 15;
+
+ b2Vec2 vertices[b2_maxPolygonVertices];
+
+ b2Transform transformA;
+ sweepA.GetTransform(&transformA, 0.0f);
+ for (int32 i = 0; i < m_shapeA.m_vertexCount; ++i)
+ {
+ vertices[i] = b2Mul(transformA, m_shapeA.m_vertices[i]);
+ }
+ m_debugDraw.DrawPolygon(vertices, m_shapeA.m_vertexCount, b2Color(0.9f, 0.9f, 0.9f));
+
+ b2Transform transformB;
+ sweepB.GetTransform(&transformB, 0.0f);
+
+ b2Vec2 localPoint(2.0f, -0.1f);
+ b2Vec2 rB = b2Mul(transformB, localPoint) - sweepB.c0;
+ float32 wB = sweepB.a - sweepB.a0;
+ b2Vec2 vB = sweepB.c - sweepB.c0;
+ b2Vec2 v = vB + b2Cross(wB, rB);
+
+ for (int32 i = 0; i < m_shapeB.m_vertexCount; ++i)
+ {
+ vertices[i] = b2Mul(transformB, m_shapeB.m_vertices[i]);
+ }
+ m_debugDraw.DrawPolygon(vertices, m_shapeB.m_vertexCount, b2Color(0.5f, 0.9f, 0.5f));
+
+ sweepB.GetTransform(&transformB, output.t);
+ for (int32 i = 0; i < m_shapeB.m_vertexCount; ++i)
+ {
+ vertices[i] = b2Mul(transformB, m_shapeB.m_vertices[i]);
+ }
+ m_debugDraw.DrawPolygon(vertices, m_shapeB.m_vertexCount, b2Color(0.5f, 0.7f, 0.9f));
+
+ sweepB.GetTransform(&transformB, 1.0f);
+ for (int32 i = 0; i < m_shapeB.m_vertexCount; ++i)
+ {
+ vertices[i] = b2Mul(transformB, m_shapeB.m_vertices[i]);
+ }
+ m_debugDraw.DrawPolygon(vertices, m_shapeB.m_vertexCount, b2Color(0.9f, 0.5f, 0.5f));
+
+#if 0
+ for (float32 t = 0.0f; t < 1.0f; t += 0.1f)
+ {
+ sweepB.GetTransform(&transformB, t);
+ for (int32 i = 0; i < m_shapeB.m_vertexCount; ++i)
+ {
+ vertices[i] = b2Mul(transformB, m_shapeB.m_vertices[i]);
+ }
+ m_debugDraw.DrawPolygon(vertices, m_shapeB.m_vertexCount, b2Color(0.9f, 0.5f, 0.5f));
+ }
+#endif
+ }
+
+ b2PolygonShape m_shapeA;
+ b2PolygonShape m_shapeB;
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/Tumbler.h b/tests/box2d/Testbed/Tests/Tumbler.h new file mode 100755 index 00000000..b654915c --- /dev/null +++ b/tests/box2d/Testbed/Tests/Tumbler.h @@ -0,0 +1,99 @@ +/*
+* Copyright (c) 2011 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef TUMBLER_H
+#define TUMBLER_H
+
+class Tumbler : public Test
+{
+public:
+
+ enum
+ {
+ e_count = 800
+ };
+
+ Tumbler()
+ {
+ b2Body* ground = NULL;
+ {
+ b2BodyDef bd;
+ ground = m_world->CreateBody(&bd);
+ }
+
+ {
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.allowSleep = false;
+ bd.position.Set(0.0f, 10.0f);
+ b2Body* body = m_world->CreateBody(&bd);
+
+ b2PolygonShape shape;
+ shape.SetAsBox(0.5f, 10.0f, b2Vec2( 10.0f, 0.0f), 0.0);
+ body->CreateFixture(&shape, 5.0f);
+ shape.SetAsBox(0.5f, 10.0f, b2Vec2(-10.0f, 0.0f), 0.0);
+ body->CreateFixture(&shape, 5.0f);
+ shape.SetAsBox(10.0f, 0.5f, b2Vec2(0.0f, 10.0f), 0.0);
+ body->CreateFixture(&shape, 5.0f);
+ shape.SetAsBox(10.0f, 0.5f, b2Vec2(0.0f, -10.0f), 0.0);
+ body->CreateFixture(&shape, 5.0f);
+
+ b2RevoluteJointDef jd;
+ jd.bodyA = ground;
+ jd.bodyB = body;
+ jd.localAnchorA.Set(0.0f, 10.0f);
+ jd.localAnchorB.Set(0.0f, 0.0f);
+ jd.referenceAngle = 0.0f;
+ jd.motorSpeed = 0.05f * b2_pi;
+ jd.maxMotorTorque = 1e8f;
+ jd.enableMotor = true;
+ m_joint = (b2RevoluteJoint*)m_world->CreateJoint(&jd);
+ }
+
+ m_count = 0;
+ }
+
+ void Step(Settings* settings)
+ {
+ Test::Step(settings);
+
+ if (m_count < e_count)
+ {
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(0.0f, 10.0f);
+ b2Body* body = m_world->CreateBody(&bd);
+
+ b2PolygonShape shape;
+ shape.SetAsBox(0.125f, 0.125f);
+ body->CreateFixture(&shape, 1.0f);
+
+ ++m_count;
+ }
+ }
+
+ static Test* Create()
+ {
+ return new Tumbler;
+ }
+
+ b2RevoluteJoint* m_joint;
+ int32 m_count;
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/VaryingFriction.h b/tests/box2d/Testbed/Tests/VaryingFriction.h new file mode 100755 index 00000000..a28354a9 --- /dev/null +++ b/tests/box2d/Testbed/Tests/VaryingFriction.h @@ -0,0 +1,124 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef VARYING_FRICTION_H
+#define VARYING_FRICTION_H
+
+class VaryingFriction : public Test
+{
+public:
+
+ VaryingFriction()
+ {
+ {
+ b2BodyDef bd;
+ b2Body* ground = m_world->CreateBody(&bd);
+
+ b2EdgeShape shape;
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
+ ground->CreateFixture(&shape, 0.0f);
+ }
+
+ {
+ b2PolygonShape shape;
+ shape.SetAsBox(13.0f, 0.25f);
+
+ b2BodyDef bd;
+ bd.position.Set(-4.0f, 22.0f);
+ bd.angle = -0.25f;
+
+ b2Body* ground = m_world->CreateBody(&bd);
+ ground->CreateFixture(&shape, 0.0f);
+ }
+
+ {
+ b2PolygonShape shape;
+ shape.SetAsBox(0.25f, 1.0f);
+
+ b2BodyDef bd;
+ bd.position.Set(10.5f, 19.0f);
+
+ b2Body* ground = m_world->CreateBody(&bd);
+ ground->CreateFixture(&shape, 0.0f);
+ }
+
+ {
+ b2PolygonShape shape;
+ shape.SetAsBox(13.0f, 0.25f);
+
+ b2BodyDef bd;
+ bd.position.Set(4.0f, 14.0f);
+ bd.angle = 0.25f;
+
+ b2Body* ground = m_world->CreateBody(&bd);
+ ground->CreateFixture(&shape, 0.0f);
+ }
+
+ {
+ b2PolygonShape shape;
+ shape.SetAsBox(0.25f, 1.0f);
+
+ b2BodyDef bd;
+ bd.position.Set(-10.5f, 11.0f);
+
+ b2Body* ground = m_world->CreateBody(&bd);
+ ground->CreateFixture(&shape, 0.0f);
+ }
+
+ {
+ b2PolygonShape shape;
+ shape.SetAsBox(13.0f, 0.25f);
+
+ b2BodyDef bd;
+ bd.position.Set(-4.0f, 6.0f);
+ bd.angle = -0.25f;
+
+ b2Body* ground = m_world->CreateBody(&bd);
+ ground->CreateFixture(&shape, 0.0f);
+ }
+
+ {
+ b2PolygonShape shape;
+ shape.SetAsBox(0.5f, 0.5f);
+
+ b2FixtureDef fd;
+ fd.shape = &shape;
+ fd.density = 25.0f;
+
+ float friction[5] = {0.75f, 0.5f, 0.35f, 0.1f, 0.0f};
+
+ for (int i = 0; i < 5; ++i)
+ {
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(-15.0f + 4.0f * i, 28.0f);
+ b2Body* body = m_world->CreateBody(&bd);
+
+ fd.friction = friction[i];
+ body->CreateFixture(&fd);
+ }
+ }
+ }
+
+ static Test* Create()
+ {
+ return new VaryingFriction;
+ }
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/VaryingRestitution.h b/tests/box2d/Testbed/Tests/VaryingRestitution.h new file mode 100755 index 00000000..8a1bed69 --- /dev/null +++ b/tests/box2d/Testbed/Tests/VaryingRestitution.h @@ -0,0 +1,69 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef VARYING_RESTITUTION_H
+#define VARYING_RESTITUTION_H
+
+// Note: even with a restitution of 1.0, there is some energy change
+// due to position correction.
+class VaryingRestitution : public Test
+{
+public:
+
+ VaryingRestitution()
+ {
+ {
+ b2BodyDef bd;
+ b2Body* ground = m_world->CreateBody(&bd);
+
+ b2EdgeShape shape;
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
+ ground->CreateFixture(&shape, 0.0f);
+ }
+
+ {
+ b2CircleShape shape;
+ shape.m_radius = 1.0f;
+
+ b2FixtureDef fd;
+ fd.shape = &shape;
+ fd.density = 1.0f;
+
+ float32 restitution[7] = {0.0f, 0.1f, 0.3f, 0.5f, 0.75f, 0.9f, 1.0f};
+
+ for (int32 i = 0; i < 7; ++i)
+ {
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.position.Set(-10.0f + 3.0f * i, 20.0f);
+
+ b2Body* body = m_world->CreateBody(&bd);
+
+ fd.restitution = restitution[i];
+ body->CreateFixture(&fd);
+ }
+ }
+ }
+
+ static Test* Create()
+ {
+ return new VaryingRestitution;
+ }
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/VerticalStack.h b/tests/box2d/Testbed/Tests/VerticalStack.h new file mode 100755 index 00000000..7d545e23 --- /dev/null +++ b/tests/box2d/Testbed/Tests/VerticalStack.h @@ -0,0 +1,165 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef VERTICAL_STACK_H
+#define VERTICAL_STACK_H
+
+class VerticalStack : public Test
+{
+public:
+
+ enum
+ {
+ e_columnCount = 5,
+ e_rowCount = 16
+ //e_columnCount = 1,
+ //e_rowCount = 1
+ };
+
+ VerticalStack()
+ {
+ {
+ b2BodyDef bd;
+ b2Body* ground = m_world->CreateBody(&bd);
+
+ b2EdgeShape shape;
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
+ ground->CreateFixture(&shape, 0.0f);
+
+ shape.Set(b2Vec2(20.0f, 0.0f), b2Vec2(20.0f, 20.0f));
+ ground->CreateFixture(&shape, 0.0f);
+ }
+
+ float32 xs[5] = {0.0f, -10.0f, -5.0f, 5.0f, 10.0f};
+
+ for (int32 j = 0; j < e_columnCount; ++j)
+ {
+ b2PolygonShape shape;
+ shape.SetAsBox(0.5f, 0.5f);
+
+ b2FixtureDef fd;
+ fd.shape = &shape;
+ fd.density = 1.0f;
+ fd.friction = 0.3f;
+
+ for (int i = 0; i < e_rowCount; ++i)
+ {
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+
+ int32 n = j * e_rowCount + i;
+ b2Assert(n < e_rowCount * e_columnCount);
+ m_indices[n] = n;
+ bd.userData = m_indices + n;
+
+ float32 x = 0.0f;
+ //float32 x = RandomFloat(-0.02f, 0.02f);
+ //float32 x = i % 2 == 0 ? -0.025f : 0.025f;
+ bd.position.Set(xs[j] + x, 0.752f + 1.54f * i);
+ b2Body* body = m_world->CreateBody(&bd);
+
+ m_bodies[n] = body;
+
+ body->CreateFixture(&fd);
+ }
+ }
+
+ m_bullet = NULL;
+ }
+
+ void Keyboard(unsigned char key)
+ {
+ switch (key)
+ {
+ case ',':
+ if (m_bullet != NULL)
+ {
+ m_world->DestroyBody(m_bullet);
+ m_bullet = NULL;
+ }
+
+ {
+ b2CircleShape shape;
+ shape.m_radius = 0.25f;
+
+ b2FixtureDef fd;
+ fd.shape = &shape;
+ fd.density = 20.0f;
+ fd.restitution = 0.05f;
+
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+ bd.bullet = true;
+ bd.position.Set(-31.0f, 5.0f);
+
+ m_bullet = m_world->CreateBody(&bd);
+ m_bullet->CreateFixture(&fd);
+
+ m_bullet->SetLinearVelocity(b2Vec2(400.0f, 0.0f));
+ }
+ break;
+ }
+ }
+
+ void Step(Settings* settings)
+ {
+ Test::Step(settings);
+ m_debugDraw.DrawString(5, m_textLine, "Press: (,) to launch a bullet.");
+ m_textLine += 15;
+
+ //if (m_stepCount == 300)
+ //{
+ // if (m_bullet != NULL)
+ // {
+ // m_world->DestroyBody(m_bullet);
+ // m_bullet = NULL;
+ // }
+
+ // {
+ // b2CircleShape shape;
+ // shape.m_radius = 0.25f;
+
+ // b2FixtureDef fd;
+ // fd.shape = &shape;
+ // fd.density = 20.0f;
+ // fd.restitution = 0.05f;
+
+ // b2BodyDef bd;
+ // bd.type = b2_dynamicBody;
+ // bd.bullet = true;
+ // bd.position.Set(-31.0f, 5.0f);
+
+ // m_bullet = m_world->CreateBody(&bd);
+ // m_bullet->CreateFixture(&fd);
+
+ // m_bullet->SetLinearVelocity(b2Vec2(400.0f, 0.0f));
+ // }
+ //}
+ }
+
+ static Test* Create()
+ {
+ return new VerticalStack;
+ }
+
+ b2Body* m_bullet;
+ b2Body* m_bodies[e_rowCount * e_columnCount];
+ int32 m_indices[e_rowCount * e_columnCount];
+};
+
+#endif
diff --git a/tests/box2d/Testbed/Tests/Web.h b/tests/box2d/Testbed/Tests/Web.h new file mode 100755 index 00000000..9ed279ec --- /dev/null +++ b/tests/box2d/Testbed/Tests/Web.h @@ -0,0 +1,209 @@ +/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef WEB_H
+#define WEB_H
+
+// This tests distance joints, body destruction, and joint destruction.
+class Web : public Test
+{
+public:
+ Web()
+ {
+ b2Body* ground = NULL;
+ {
+ b2BodyDef bd;
+ ground = m_world->CreateBody(&bd);
+
+ b2EdgeShape shape;
+ shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
+ ground->CreateFixture(&shape, 0.0f);
+ }
+
+ {
+ b2PolygonShape shape;
+ shape.SetAsBox(0.5f, 0.5f);
+
+ b2BodyDef bd;
+ bd.type = b2_dynamicBody;
+
+ bd.position.Set(-5.0f, 5.0f);
+ m_bodies[0] = m_world->CreateBody(&bd);
+ m_bodies[0]->CreateFixture(&shape, 5.0f);
+
+ bd.position.Set(5.0f, 5.0f);
+ m_bodies[1] = m_world->CreateBody(&bd);
+ m_bodies[1]->CreateFixture(&shape, 5.0f);
+
+ bd.position.Set(5.0f, 15.0f);
+ m_bodies[2] = m_world->CreateBody(&bd);
+ m_bodies[2]->CreateFixture(&shape, 5.0f);
+
+ bd.position.Set(-5.0f, 15.0f);
+ m_bodies[3] = m_world->CreateBody(&bd);
+ m_bodies[3]->CreateFixture(&shape, 5.0f);
+
+ b2DistanceJointDef jd;
+ b2Vec2 p1, p2, d;
+
+ jd.frequencyHz = 2.0f;
+ jd.dampingRatio = 0.0f;
+
+ jd.bodyA = ground;
+ jd.bodyB = m_bodies[0];
+ jd.localAnchorA.Set(-10.0f, 0.0f);
+ jd.localAnchorB.Set(-0.5f, -0.5f);
+ p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA);
+ p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB);
+ d = p2 - p1;
+ jd.length = d.Length();
+ m_joints[0] = m_world->CreateJoint(&jd);
+
+ jd.bodyA = ground;
+ jd.bodyB = m_bodies[1];
+ jd.localAnchorA.Set(10.0f, 0.0f);
+ jd.localAnchorB.Set(0.5f, -0.5f);
+ p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA);
+ p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB);
+ d = p2 - p1;
+ jd.length = d.Length();
+ m_joints[1] = m_world->CreateJoint(&jd);
+
+ jd.bodyA = ground;
+ jd.bodyB = m_bodies[2];
+ jd.localAnchorA.Set(10.0f, 20.0f);
+ jd.localAnchorB.Set(0.5f, 0.5f);
+ p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA);
+ p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB);
+ d = p2 - p1;
+ jd.length = d.Length();
+ m_joints[2] = m_world->CreateJoint(&jd);
+
+ jd.bodyA = ground;
+ jd.bodyB = m_bodies[3];
+ jd.localAnchorA.Set(-10.0f, 20.0f);
+ jd.localAnchorB.Set(-0.5f, 0.5f);
+ p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA);
+ p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB);
+ d = p2 - p1;
+ jd.length = d.Length();
+ m_joints[3] = m_world->CreateJoint(&jd);
+
+ jd.bodyA = m_bodies[0];
+ jd.bodyB = m_bodies[1];
+ jd.localAnchorA.Set(0.5f, 0.0f);
+ jd.localAnchorB.Set(-0.5f, 0.0f);;
+ p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA);
+ p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB);
+ d = p2 - p1;
+ jd.length = d.Length();
+ m_joints[4] = m_world->CreateJoint(&jd);
+
+ jd.bodyA = m_bodies[1];
+ jd.bodyB = m_bodies[2];
+ jd.localAnchorA.Set(0.0f, 0.5f);
+ jd.localAnchorB.Set(0.0f, -0.5f);
+ p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA);
+ p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB);
+ d = p2 - p1;
+ jd.length = d.Length();
+ m_joints[5] = m_world->CreateJoint(&jd);
+
+ jd.bodyA = m_bodies[2];
+ jd.bodyB = m_bodies[3];
+ jd.localAnchorA.Set(-0.5f, 0.0f);
+ jd.localAnchorB.Set(0.5f, 0.0f);
+ p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA);
+ p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB);
+ d = p2 - p1;
+ jd.length = d.Length();
+ m_joints[6] = m_world->CreateJoint(&jd);
+
+ jd.bodyA = m_bodies[3];
+ jd.bodyB = m_bodies[0];
+ jd.localAnchorA.Set(0.0f, -0.5f);
+ jd.localAnchorB.Set(0.0f, 0.5f);
+ p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA);
+ p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB);
+ d = p2 - p1;
+ jd.length = d.Length();
+ m_joints[7] = m_world->CreateJoint(&jd);
+ }
+ }
+
+ void Keyboard(unsigned char key)
+ {
+ switch (key)
+ {
+ case 'b':
+ for (int32 i = 0; i < 4; ++i)
+ {
+ if (m_bodies[i])
+ {
+ m_world->DestroyBody(m_bodies[i]);
+ m_bodies[i] = NULL;
+ break;
+ }
+ }
+ break;
+
+ case 'j':
+ for (int32 i = 0; i < 8; ++i)
+ {
+ if (m_joints[i])
+ {
+ m_world->DestroyJoint(m_joints[i]);
+ m_joints[i] = NULL;
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ void Step(Settings* settings)
+ {
+ Test::Step(settings);
+ m_debugDraw.DrawString(5, m_textLine, "This demonstrates a soft distance joint.");
+ m_textLine += 15;
+ m_debugDraw.DrawString(5, m_textLine, "Press: (b) to delete a body, (j) to delete a joint");
+ m_textLine += 15;
+ }
+
+ void JointDestroyed(b2Joint* joint)
+ {
+ for (int32 i = 0; i < 8; ++i)
+ {
+ if (m_joints[i] == joint)
+ {
+ m_joints[i] = NULL;
+ break;
+ }
+ }
+ }
+
+ static Test* Create()
+ {
+ return new Web;
+ }
+
+ b2Body* m_bodies[4];
+ b2Joint* m_joints[8];
+};
+
+#endif
diff --git a/tests/box2d/freeglut/CMakeLists.txt b/tests/box2d/freeglut/CMakeLists.txt new file mode 100755 index 00000000..8c97446d --- /dev/null +++ b/tests/box2d/freeglut/CMakeLists.txt @@ -0,0 +1,51 @@ +add_definitions( -DFREEGLUT_EXPORTS -DFREEGLUT_STATIC -D_CRT_SECURE_NO_WARNINGS )
+
+if(APPLE)
+ include_directories( /usr/X11/include )
+endif(APPLE)
+
+if(UNIX)
+ add_definitions( -D__unix__ -DHAVE_FCNTL_H -DHAVE_GETTIMEOFDAY )
+endif(UNIX)
+
+set(freeglut_SRCS
+ freeglut_callbacks.c
+ freeglut_callbacks.c
+ freeglut_cursor.c
+ freeglut_display.c
+ freeglut_ext.c
+ freeglut_font_data.c
+ freeglut_font.c
+ freeglut_gamemode.c
+ freeglut_geometry.c
+ freeglut_glutfont_definitions.c
+ freeglut_init.c
+ freeglut_input_devices.c
+ freeglut_internal.h
+ freeglut_joystick.c
+ freeglut_main.c
+ freeglut_menu.c
+ freeglut_misc.c
+ freeglut_overlay.c
+ freeglut_spaceball.c
+ freeglut_state.c
+ freeglut_stroke_mono_roman.c
+ freeglut_stroke_roman.c
+ freeglut_structure.c
+ freeglut_teapot_data.h
+ freeglut_teapot.c
+ freeglut_videoresize.c
+ freeglut_window.c
+ freeglut.h
+ freeglut_ext.h
+ freeglut_std.h
+)
+
+include_directories (
+ ${OPENGL_INCLUDE_DIR}
+ .
+)
+
+add_library(freeglut_static
+ ${freeglut_SRCS}
+)
diff --git a/tests/box2d/freeglut/COPYING b/tests/box2d/freeglut/COPYING new file mode 100755 index 00000000..fc36ad99 --- /dev/null +++ b/tests/box2d/freeglut/COPYING @@ -0,0 +1,27 @@ + + Freeglut Copyright + ------------------ + + Freeglut code without an explicit copyright is covered by the following + copyright: + + Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies or substantial portions of the Software. + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Pawel W. Olszta shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Pawel W. Olszta. diff --git a/tests/box2d/freeglut/freeglut.h b/tests/box2d/freeglut/freeglut.h new file mode 100755 index 00000000..0e6f8c6a --- /dev/null +++ b/tests/box2d/freeglut/freeglut.h @@ -0,0 +1,22 @@ +#ifndef __FREEGLUT_H__ +#define __FREEGLUT_H__ + +/* + * freeglut.h + * + * The freeglut library include file + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "freeglut_std.h" +#include "freeglut_ext.h" + +/*** END OF FILE ***/ + +#endif /* __FREEGLUT_H__ */ diff --git a/tests/box2d/freeglut/freeglut_callbacks.c b/tests/box2d/freeglut/freeglut_callbacks.c new file mode 100755 index 00000000..b6b25b37 --- /dev/null +++ b/tests/box2d/freeglut/freeglut_callbacks.c @@ -0,0 +1,367 @@ +/* + * freeglut_callbacks.c + * + * The callbacks setting methods. + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, <olszta@sourceforge.net> + * Creation date: Fri Dec 3 1999 + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "freeglut.h" +#include "freeglut_internal.h" + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +/* + * All of the callbacks setting methods can be generalized to this: + */ +#define SET_CALLBACK(a) \ +do \ +{ \ + if( fgStructure.CurrentWindow == NULL ) \ + return; \ + SET_WCB( ( *( fgStructure.CurrentWindow ) ), a, callback ); \ +} while( 0 ) + +/* + * Sets the Display callback for the current window + */ +void FGAPIENTRY glutDisplayFunc( void (* callback)( void ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDisplayFunc" ); + if( !callback ) + fgError( "Fatal error in program. NULL display callback not " + "permitted in GLUT 3.0+ or freeglut 2.0.1+" ); + SET_CALLBACK( Display ); +} + +/* + * Sets the Reshape callback for the current window + */ +void FGAPIENTRY glutReshapeFunc( void (* callback)( int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutReshapeFunc" ); + SET_CALLBACK( Reshape ); +} + +/* + * Sets the Keyboard callback for the current window + */ +void FGAPIENTRY glutKeyboardFunc( void (* callback) + ( unsigned char, int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutKeyboardFunc" ); + SET_CALLBACK( Keyboard ); +} + +/* + * Sets the Special callback for the current window + */ +void FGAPIENTRY glutSpecialFunc( void (* callback)( int, int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpecialFunc" ); + SET_CALLBACK( Special ); +} + +/* + * Sets the global idle callback + */ +void FGAPIENTRY glutIdleFunc( void (* callback)( void ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutIdleFunc" ); + fgState.IdleCallback = callback; +} + +/* + * Sets the Timer callback for the current window + */ +void FGAPIENTRY glutTimerFunc( unsigned int timeOut, void (* callback)( int ), + int timerID ) +{ + SFG_Timer *timer, *node; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutTimerFunc" ); + + if( (timer = fgState.FreeTimers.Last) ) + { + fgListRemove( &fgState.FreeTimers, &timer->Node ); + } + else + { + if( ! (timer = malloc(sizeof(SFG_Timer))) ) + fgError( "Fatal error: " + "Memory allocation failure in glutTimerFunc()" ); + } + + timer->Callback = callback; + timer->ID = timerID; + timer->TriggerTime = fgElapsedTime() + timeOut; + + for( node = fgState.Timers.First; node; node = node->Node.Next ) + { + if( node->TriggerTime > timer->TriggerTime ) + break; + } + + fgListInsert( &fgState.Timers, &node->Node, &timer->Node ); +} + +/* + * Sets the Visibility callback for the current window. + */ +static void fghVisibility( int status ) +{ + int glut_status = GLUT_VISIBLE; + + FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Visibility Callback" ); + freeglut_return_if_fail( fgStructure.CurrentWindow ); + + if( ( GLUT_HIDDEN == status ) || ( GLUT_FULLY_COVERED == status ) ) + glut_status = GLUT_NOT_VISIBLE; + INVOKE_WCB( *( fgStructure.CurrentWindow ), Visibility, ( glut_status ) ); +} + +void FGAPIENTRY glutVisibilityFunc( void (* callback)( int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutVisibilityFunc" ); + SET_CALLBACK( Visibility ); + + if( callback ) + glutWindowStatusFunc( fghVisibility ); + else + glutWindowStatusFunc( NULL ); +} + +/* + * Sets the keyboard key release callback for the current window + */ +void FGAPIENTRY glutKeyboardUpFunc( void (* callback) + ( unsigned char, int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutKeyboardUpFunc" ); + SET_CALLBACK( KeyboardUp ); +} + +/* + * Sets the special key release callback for the current window + */ +void FGAPIENTRY glutSpecialUpFunc( void (* callback)( int, int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpecialUpFunc" ); + SET_CALLBACK( SpecialUp ); +} + +/* + * Sets the joystick callback and polling rate for the current window + */ +void FGAPIENTRY glutJoystickFunc( void (* callback) + ( unsigned int, int, int, int ), + int pollInterval ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickFunc" ); + fgInitialiseJoysticks (); + + SET_CALLBACK( Joystick ); + fgStructure.CurrentWindow->State.JoystickPollRate = pollInterval; + + fgStructure.CurrentWindow->State.JoystickLastPoll = + fgElapsedTime() - fgStructure.CurrentWindow->State.JoystickPollRate; + + if( fgStructure.CurrentWindow->State.JoystickLastPoll < 0 ) + fgStructure.CurrentWindow->State.JoystickLastPoll = 0; +} + +/* + * Sets the mouse callback for the current window + */ +void FGAPIENTRY glutMouseFunc( void (* callback)( int, int, int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMouseFunc" ); + SET_CALLBACK( Mouse ); +} + +/* + * Sets the mouse wheel callback for the current window + */ +void FGAPIENTRY glutMouseWheelFunc( void (* callback)( int, int, int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMouseWheelFunc" ); + SET_CALLBACK( MouseWheel ); +} + +/* + * Sets the mouse motion callback for the current window (one or more buttons + * are pressed) + */ +void FGAPIENTRY glutMotionFunc( void (* callback)( int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMotionFunc" ); + SET_CALLBACK( Motion ); +} + +/* + * Sets the passive mouse motion callback for the current window (no mouse + * buttons are pressed) + */ +void FGAPIENTRY glutPassiveMotionFunc( void (* callback)( int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPassiveMotionFunc" ); + SET_CALLBACK( Passive ); +} + +/* + * Window mouse entry/leave callback + */ +void FGAPIENTRY glutEntryFunc( void (* callback)( int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutEntryFunc" ); + SET_CALLBACK( Entry ); +} + +/* + * Window destruction callbacks + */ +void FGAPIENTRY glutCloseFunc( void (* callback)( void ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCloseFunc" ); + SET_CALLBACK( Destroy ); +} + +void FGAPIENTRY glutWMCloseFunc( void (* callback)( void ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWMCloseFunc" ); + glutCloseFunc( callback ); +} + +/* A. Donev: Destruction callback for menus */ +void FGAPIENTRY glutMenuDestroyFunc( void (* callback)( void ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMenuDestroyFunc" ); + if( fgStructure.CurrentMenu ) + fgStructure.CurrentMenu->Destroy = callback; +} + +/* + * Deprecated version of glutMenuStatusFunc callback setting method + */ +void FGAPIENTRY glutMenuStateFunc( void (* callback)( int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMenuStateFunc" ); + fgState.MenuStateCallback = callback; +} + +/* + * Sets the global menu status callback for the current window + */ +void FGAPIENTRY glutMenuStatusFunc( void (* callback)( int, int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMenuStatusFunc" ); + fgState.MenuStatusCallback = callback; +} + +/* + * Sets the overlay display callback for the current window + */ +void FGAPIENTRY glutOverlayDisplayFunc( void (* callback)( void ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutOverlayDisplayFunc" ); + SET_CALLBACK( OverlayDisplay ); +} + +/* + * Sets the window status callback for the current window + */ +void FGAPIENTRY glutWindowStatusFunc( void (* callback)( int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWindowStatusFunc" ); + SET_CALLBACK( WindowStatus ); +} + +/* + * Sets the spaceball motion callback for the current window + */ +void FGAPIENTRY glutSpaceballMotionFunc( void (* callback)( int, int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballMotionFunc" ); + fgInitialiseSpaceball(); + + SET_CALLBACK( SpaceMotion ); +} + +/* + * Sets the spaceball rotate callback for the current window + */ +void FGAPIENTRY glutSpaceballRotateFunc( void (* callback)( int, int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballRotateFunc" ); + fgInitialiseSpaceball(); + + SET_CALLBACK( SpaceRotation ); +} + +/* + * Sets the spaceball button callback for the current window + */ +void FGAPIENTRY glutSpaceballButtonFunc( void (* callback)( int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballButtonFunc" ); + fgInitialiseSpaceball(); + + SET_CALLBACK( SpaceButton ); +} + +/* + * Sets the button box callback for the current window + */ +void FGAPIENTRY glutButtonBoxFunc( void (* callback)( int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutButtonBoxFunc" ); + SET_CALLBACK( ButtonBox ); +} + +/* + * Sets the dials box callback for the current window + */ +void FGAPIENTRY glutDialsFunc( void (* callback)( int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDialsFunc" ); + SET_CALLBACK( Dials ); +} + +/* + * Sets the tablet motion callback for the current window + */ +void FGAPIENTRY glutTabletMotionFunc( void (* callback)( int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutTabletMotionFunc" ); + SET_CALLBACK( TabletMotion ); +} + +/* + * Sets the tablet buttons callback for the current window + */ +void FGAPIENTRY glutTabletButtonFunc( void (* callback)( int, int, int, int ) ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutTabletButtonFunc" ); + SET_CALLBACK( TabletButton ); +} + +/*** END OF FILE ***/ diff --git a/tests/box2d/freeglut/freeglut_cursor.c b/tests/box2d/freeglut/freeglut_cursor.c new file mode 100755 index 00000000..f0ba136a --- /dev/null +++ b/tests/box2d/freeglut/freeglut_cursor.c @@ -0,0 +1,280 @@ +/* + * freeglut_cursor.c + * + * The mouse cursor related stuff. + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, <olszta@sourceforge.net> + * Creation date: Thu Dec 16 1999 + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "freeglut.h" +#include "freeglut_internal.h" + +#if TARGET_HOST_POSIX_X11 + #include <X11/cursorfont.h> +#endif + +/* + * TODO BEFORE THE STABLE RELEASE: + * glutSetCursor() -- Win32 mappings are incomplete. + * + * It would be good to use custom mouse cursor shapes, and introduce + * an option to display them using glBitmap() and/or texture mapping, + * apart from the windowing system version. + */ + +/* -- PRIVATE FUNCTIONS --------------------------------------------------- */ + +#if TARGET_HOST_POSIX_X11 +/* + * A factory method for an empty cursor + */ +static Cursor getEmptyCursor( void ) +{ + static Cursor cursorNone = None; + if( cursorNone == None ) { + char cursorNoneBits[ 32 ]; + XColor dontCare; + Pixmap cursorNonePixmap; + memset( cursorNoneBits, 0, sizeof( cursorNoneBits ) ); + memset( &dontCare, 0, sizeof( dontCare ) ); + cursorNonePixmap = XCreateBitmapFromData ( fgDisplay.Display, + fgDisplay.RootWindow, + cursorNoneBits, 16, 16 ); + if( cursorNonePixmap != None ) { + cursorNone = XCreatePixmapCursor( fgDisplay.Display, + cursorNonePixmap, cursorNonePixmap, + &dontCare, &dontCare, 0, 0 ); + XFreePixmap( fgDisplay.Display, cursorNonePixmap ); + } + } + return cursorNone; +} + +typedef struct tag_cursorCacheEntry cursorCacheEntry; +struct tag_cursorCacheEntry { + unsigned int cursorShape; /* an XC_foo value */ + Cursor cachedCursor; /* None if the corresponding cursor has + not been created yet */ +}; + +/* + * Note: The arrangement of the table below depends on the fact that + * the "normal" GLUT_CURSOR_* values start a 0 and are consecutive. + */ +static cursorCacheEntry cursorCache[] = { + { XC_arrow, None }, /* GLUT_CURSOR_RIGHT_ARROW */ + { XC_top_left_arrow, None }, /* GLUT_CURSOR_LEFT_ARROW */ + { XC_hand1, None }, /* GLUT_CURSOR_INFO */ + { XC_pirate, None }, /* GLUT_CURSOR_DESTROY */ + { XC_question_arrow, None }, /* GLUT_CURSOR_HELP */ + { XC_exchange, None }, /* GLUT_CURSOR_CYCLE */ + { XC_spraycan, None }, /* GLUT_CURSOR_SPRAY */ + { XC_watch, None }, /* GLUT_CURSOR_WAIT */ + { XC_xterm, None }, /* GLUT_CURSOR_TEXT */ + { XC_crosshair, None }, /* GLUT_CURSOR_CROSSHAIR */ + { XC_sb_v_double_arrow, None }, /* GLUT_CURSOR_UP_DOWN */ + { XC_sb_h_double_arrow, None }, /* GLUT_CURSOR_LEFT_RIGHT */ + { XC_top_side, None }, /* GLUT_CURSOR_TOP_SIDE */ + { XC_bottom_side, None }, /* GLUT_CURSOR_BOTTOM_SIDE */ + { XC_left_side, None }, /* GLUT_CURSOR_LEFT_SIDE */ + { XC_right_side, None }, /* GLUT_CURSOR_RIGHT_SIDE */ + { XC_top_left_corner, None }, /* GLUT_CURSOR_TOP_LEFT_CORNER */ + { XC_top_right_corner, None }, /* GLUT_CURSOR_TOP_RIGHT_CORNER */ + { XC_bottom_right_corner, None }, /* GLUT_CURSOR_BOTTOM_RIGHT_CORNER */ + { XC_bottom_left_corner, None } /* GLUT_CURSOR_BOTTOM_LEFT_CORNER */ +}; +#endif + +/* -- INTERNAL FUNCTIONS ---------------------------------------------------- */ + +/* + * Set the cursor image to be used for the current window + */ +void fgSetCursor ( SFG_Window *window, int cursorID ) +{ +#if TARGET_HOST_POSIX_X11 + { + Cursor cursor; + /* + * XXX FULL_CROSSHAIR demotes to plain CROSSHAIR. Old GLUT allows + * for this, but if there is a system that easily supports a full- + * window (or full-screen) crosshair, we might consider it. + */ + int cursorIDToUse = + ( cursorID == GLUT_CURSOR_FULL_CROSSHAIR ) ? GLUT_CURSOR_CROSSHAIR : cursorID; + + if( ( cursorIDToUse >= 0 ) && + ( cursorIDToUse < sizeof( cursorCache ) / sizeof( cursorCache[0] ) ) ) { + cursorCacheEntry *entry = &cursorCache[ cursorIDToUse ]; + if( entry->cachedCursor == None ) { + entry->cachedCursor = + XCreateFontCursor( fgDisplay.Display, entry->cursorShape ); + } + cursor = entry->cachedCursor; + } else { + switch( cursorIDToUse ) + { + case GLUT_CURSOR_NONE: + cursor = getEmptyCursor( ); + break; + + case GLUT_CURSOR_INHERIT: + cursor = None; + break; + + default: + fgError( "Unknown cursor type: %d", cursorIDToUse ); + return; + } + } + + if ( cursorIDToUse == GLUT_CURSOR_INHERIT ) { + XUndefineCursor( fgDisplay.Display, window->Window.Handle ); + } else if ( cursor != None ) { + XDefineCursor( fgDisplay.Display, window->Window.Handle, cursor ); + } else if ( cursorIDToUse != GLUT_CURSOR_NONE ) { + fgError( "Failed to create cursor" ); + } + } + +#elif TARGET_HOST_MS_WINDOWS + + /* + * Joe Krahn is re-writing the following code. + */ + /* Set the cursor AND change it for this window class. */ +#if !defined(__MINGW64__) && _MSC_VER <= 1200 +# define MAP_CURSOR(a,b) \ + case a: \ + SetCursor( LoadCursor( NULL, b ) ); \ + SetClassLong( window->Window.Handle, \ + GCL_HCURSOR, \ + ( LONG )LoadCursor( NULL, b ) ); \ + break; + /* Nuke the cursor AND change it for this window class. */ +# define ZAP_CURSOR(a,b) \ + case a: \ + SetCursor( NULL ); \ + SetClassLong( window->Window.Handle, \ + GCL_HCURSOR, ( LONG )NULL ); \ + break; +#else +# define MAP_CURSOR(a,b) \ + case a: \ + SetCursor( LoadCursor( NULL, b ) ); \ + SetClassLongPtr( window->Window.Handle, \ + GCLP_HCURSOR, \ + ( LONG )( LONG_PTR )LoadCursor( NULL, b ) ); \ + break; + /* Nuke the cursor AND change it for this window class. */ +# define ZAP_CURSOR(a,b) \ + case a: \ + SetCursor( NULL ); \ + SetClassLongPtr( window->Window.Handle, \ + GCLP_HCURSOR, ( LONG )( LONG_PTR )NULL ); \ + break; +#endif + + switch( cursorID ) + { + MAP_CURSOR( GLUT_CURSOR_RIGHT_ARROW, IDC_ARROW ); + MAP_CURSOR( GLUT_CURSOR_LEFT_ARROW, IDC_ARROW ); + MAP_CURSOR( GLUT_CURSOR_INFO, IDC_HELP ); + MAP_CURSOR( GLUT_CURSOR_DESTROY, IDC_CROSS ); + MAP_CURSOR( GLUT_CURSOR_HELP, IDC_HELP ); + MAP_CURSOR( GLUT_CURSOR_CYCLE, IDC_SIZEALL ); + MAP_CURSOR( GLUT_CURSOR_SPRAY, IDC_CROSS ); + MAP_CURSOR( GLUT_CURSOR_WAIT, IDC_WAIT ); + MAP_CURSOR( GLUT_CURSOR_TEXT, IDC_IBEAM ); + MAP_CURSOR( GLUT_CURSOR_CROSSHAIR, IDC_CROSS ); + MAP_CURSOR( GLUT_CURSOR_UP_DOWN, IDC_SIZENS ); + MAP_CURSOR( GLUT_CURSOR_LEFT_RIGHT, IDC_SIZEWE ); + MAP_CURSOR( GLUT_CURSOR_TOP_SIDE, IDC_ARROW ); /* XXX ToDo */ + MAP_CURSOR( GLUT_CURSOR_BOTTOM_SIDE, IDC_ARROW ); /* XXX ToDo */ + MAP_CURSOR( GLUT_CURSOR_LEFT_SIDE, IDC_ARROW ); /* XXX ToDo */ + MAP_CURSOR( GLUT_CURSOR_RIGHT_SIDE, IDC_ARROW ); /* XXX ToDo */ + MAP_CURSOR( GLUT_CURSOR_TOP_LEFT_CORNER, IDC_SIZENWSE ); + MAP_CURSOR( GLUT_CURSOR_TOP_RIGHT_CORNER, IDC_SIZENESW ); + MAP_CURSOR( GLUT_CURSOR_BOTTOM_RIGHT_CORNER, IDC_SIZENWSE ); + MAP_CURSOR( GLUT_CURSOR_BOTTOM_LEFT_CORNER, IDC_SIZENESW ); + MAP_CURSOR( GLUT_CURSOR_INHERIT, IDC_ARROW ); /* XXX ToDo */ + ZAP_CURSOR( GLUT_CURSOR_NONE, NULL ); + MAP_CURSOR( GLUT_CURSOR_FULL_CROSSHAIR, IDC_CROSS ); /* XXX ToDo */ + + default: + fgError( "Unknown cursor type: %d", cursorID ); + break; + } +#endif + + window->State.Cursor = cursorID; +} + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +/* + * Set the cursor image to be used for the current window + */ +void FGAPIENTRY glutSetCursor( int cursorID ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetCursor" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetCursor" ); + + fgSetCursor ( fgStructure.CurrentWindow, cursorID ); +} + +/* + * Moves the mouse pointer to given window coordinates + */ +void FGAPIENTRY glutWarpPointer( int x, int y ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWarpPointer" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutWarpPointer" ); + +#if TARGET_HOST_POSIX_X11 + + XWarpPointer( + fgDisplay.Display, + None, + fgStructure.CurrentWindow->Window.Handle, + 0, 0, 0, 0, + x, y + ); + /* Make the warp visible immediately. */ + XFlush( fgDisplay.Display ); + +#elif TARGET_HOST_MS_WINDOWS + + { + POINT coords; + coords.x = x; + coords.y = y; + + /* ClientToScreen() translates {coords} for us. */ + ClientToScreen( fgStructure.CurrentWindow->Window.Handle, &coords ); + SetCursorPos( coords.x, coords.y ); + } + +#endif +} + +/*** END OF FILE ***/ diff --git a/tests/box2d/freeglut/freeglut_display.c b/tests/box2d/freeglut/freeglut_display.c new file mode 100755 index 00000000..2f2c5752 --- /dev/null +++ b/tests/box2d/freeglut/freeglut_display.c @@ -0,0 +1,98 @@ +/* + * freeglut_display.c + * + * Display message posting, context buffer swapping. + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, <olszta@sourceforge.net> + * Creation date: Fri Dec 3 1999 + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "freeglut.h" +#include "freeglut_internal.h" + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +/* + * Marks the current window to have the redisplay performed when possible... + */ +void FGAPIENTRY glutPostRedisplay( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPostRedisplay" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPostRedisplay" ); + fgStructure.CurrentWindow->State.Redisplay = GL_TRUE; +} + +/* + * Swaps the buffers for the current window (if any) + */ +void FGAPIENTRY glutSwapBuffers( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSwapBuffers" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSwapBuffers" ); + + /* + * "glXSwapBuffers" already performs an implicit call to "glFlush". What + * about "SwapBuffers"? + */ + glFlush( ); + if( ! fgStructure.CurrentWindow->Window.DoubleBuffered ) + return; + +#if TARGET_HOST_POSIX_X11 + glXSwapBuffers( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle ); +#elif TARGET_HOST_MS_WINDOWS + SwapBuffers( fgStructure.CurrentWindow->Window.Device ); +#endif + + /* GLUT_FPS env var support */ + if( fgState.FPSInterval ) + { + GLint t = glutGet( GLUT_ELAPSED_TIME ); + fgState.SwapCount++; + if( fgState.SwapTime == 0 ) + fgState.SwapTime = t; + else if( t - fgState.SwapTime > fgState.FPSInterval ) + { + float time = 0.001f * ( t - fgState.SwapTime ); + float fps = ( float )fgState.SwapCount / time; + fprintf( stderr, + "freeglut: %d frames in %.2f seconds = %.2f FPS\n", + fgState.SwapCount, time, fps ); + fgState.SwapTime = t; + fgState.SwapCount = 0; + } + } +} + +/* + * Mark appropriate window to be displayed + */ +void FGAPIENTRY glutPostWindowRedisplay( int windowID ) +{ + SFG_Window* window; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPostWindowRedisplay" ); + window = fgWindowByID( windowID ); + freeglut_return_if_fail( window ); + window->State.Redisplay = GL_TRUE; +} + +/*** END OF FILE ***/ diff --git a/tests/box2d/freeglut/freeglut_ext.c b/tests/box2d/freeglut/freeglut_ext.c new file mode 100755 index 00000000..cf854341 --- /dev/null +++ b/tests/box2d/freeglut/freeglut_ext.c @@ -0,0 +1,226 @@ +/* + * freeglut_ext.c + * + * Functions related to OpenGL extensions. + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, <olszta@sourceforge.net> + * Creation date: Thu Dec 9 1999 + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#define GLX_GLXEXT_PROTOTYPES +#include "freeglut.h" +#include "freeglut_internal.h" + +static GLUTproc fghGetGLUTProcAddress( const char* procName ) +{ + /* optimization: quick initial check */ + if( strncmp( procName, "glut", 4 ) != 0 ) + return NULL; + +#define CHECK_NAME(x) if( strcmp( procName, #x ) == 0) return (GLUTproc)x; + CHECK_NAME(glutInit); + CHECK_NAME(glutInitDisplayMode); + CHECK_NAME(glutInitDisplayString); + CHECK_NAME(glutInitWindowPosition); + CHECK_NAME(glutInitWindowSize); + CHECK_NAME(glutMainLoop); + CHECK_NAME(glutExit); + CHECK_NAME(glutCreateWindow); + CHECK_NAME(glutCreateSubWindow); + CHECK_NAME(glutDestroyWindow); + CHECK_NAME(glutPostRedisplay); + CHECK_NAME(glutPostWindowRedisplay); + CHECK_NAME(glutSwapBuffers); + CHECK_NAME(glutGetWindow); + CHECK_NAME(glutSetWindow); + CHECK_NAME(glutSetWindowTitle); + CHECK_NAME(glutSetIconTitle); + CHECK_NAME(glutPositionWindow); + CHECK_NAME(glutReshapeWindow); + CHECK_NAME(glutPopWindow); + CHECK_NAME(glutPushWindow); + CHECK_NAME(glutIconifyWindow); + CHECK_NAME(glutShowWindow); + CHECK_NAME(glutHideWindow); + CHECK_NAME(glutFullScreen); + CHECK_NAME(glutSetCursor); + CHECK_NAME(glutWarpPointer); + CHECK_NAME(glutEstablishOverlay); + CHECK_NAME(glutRemoveOverlay); + CHECK_NAME(glutUseLayer); + CHECK_NAME(glutPostOverlayRedisplay); + CHECK_NAME(glutPostWindowOverlayRedisplay); + CHECK_NAME(glutShowOverlay); + CHECK_NAME(glutHideOverlay); + CHECK_NAME(glutCreateMenu); + CHECK_NAME(glutDestroyMenu); + CHECK_NAME(glutGetMenu); + CHECK_NAME(glutSetMenu); + CHECK_NAME(glutAddMenuEntry); + CHECK_NAME(glutAddSubMenu); + CHECK_NAME(glutChangeToMenuEntry); + CHECK_NAME(glutChangeToSubMenu); + CHECK_NAME(glutRemoveMenuItem); + CHECK_NAME(glutAttachMenu); + CHECK_NAME(glutDetachMenu); + CHECK_NAME(glutDisplayFunc); + CHECK_NAME(glutReshapeFunc); + CHECK_NAME(glutKeyboardFunc); + CHECK_NAME(glutMouseFunc); + CHECK_NAME(glutMotionFunc); + CHECK_NAME(glutPassiveMotionFunc); + CHECK_NAME(glutEntryFunc); + CHECK_NAME(glutVisibilityFunc); + CHECK_NAME(glutIdleFunc); + CHECK_NAME(glutTimerFunc); + CHECK_NAME(glutMenuStateFunc); + CHECK_NAME(glutSpecialFunc); + CHECK_NAME(glutSpaceballMotionFunc); + CHECK_NAME(glutSpaceballRotateFunc); + CHECK_NAME(glutSpaceballButtonFunc); + CHECK_NAME(glutButtonBoxFunc); + CHECK_NAME(glutDialsFunc); + CHECK_NAME(glutTabletMotionFunc); + CHECK_NAME(glutTabletButtonFunc); + CHECK_NAME(glutMenuStatusFunc); + CHECK_NAME(glutOverlayDisplayFunc); + CHECK_NAME(glutWindowStatusFunc); + CHECK_NAME(glutKeyboardUpFunc); + CHECK_NAME(glutSpecialUpFunc); +#if !defined(_WIN32_WCE) + CHECK_NAME(glutJoystickFunc); +#endif /* !defined(_WIN32_WCE) */ + CHECK_NAME(glutSetColor); + CHECK_NAME(glutGetColor); + CHECK_NAME(glutCopyColormap); + CHECK_NAME(glutGet); + CHECK_NAME(glutDeviceGet); + CHECK_NAME(glutExtensionSupported); + CHECK_NAME(glutGetModifiers); + CHECK_NAME(glutLayerGet); + CHECK_NAME(glutBitmapCharacter); + CHECK_NAME(glutBitmapWidth); + CHECK_NAME(glutStrokeCharacter); + CHECK_NAME(glutStrokeWidth); + CHECK_NAME(glutBitmapLength); + CHECK_NAME(glutStrokeLength); + CHECK_NAME(glutWireSphere); + CHECK_NAME(glutSolidSphere); + CHECK_NAME(glutWireCone); + CHECK_NAME(glutSolidCone); + CHECK_NAME(glutWireCube); + CHECK_NAME(glutSolidCube); + CHECK_NAME(glutWireTorus); + CHECK_NAME(glutSolidTorus); + CHECK_NAME(glutWireDodecahedron); + CHECK_NAME(glutSolidDodecahedron); + CHECK_NAME(glutWireTeapot); + CHECK_NAME(glutSolidTeapot); + CHECK_NAME(glutWireOctahedron); + CHECK_NAME(glutSolidOctahedron); + CHECK_NAME(glutWireTetrahedron); + CHECK_NAME(glutSolidTetrahedron); + CHECK_NAME(glutWireIcosahedron); + CHECK_NAME(glutSolidIcosahedron); + CHECK_NAME(glutVideoResizeGet); + CHECK_NAME(glutSetupVideoResizing); + CHECK_NAME(glutStopVideoResizing); + CHECK_NAME(glutVideoResize); + CHECK_NAME(glutVideoPan); + CHECK_NAME(glutReportErrors); + CHECK_NAME(glutIgnoreKeyRepeat); + CHECK_NAME(glutSetKeyRepeat); +#if !defined(_WIN32_WCE) + CHECK_NAME(glutForceJoystickFunc); + CHECK_NAME(glutGameModeString); + CHECK_NAME(glutEnterGameMode); + CHECK_NAME(glutLeaveGameMode); + CHECK_NAME(glutGameModeGet); +#endif /* !defined(_WIN32_WCE) */ + /* freeglut extensions */ + CHECK_NAME(glutMainLoopEvent); + CHECK_NAME(glutLeaveMainLoop); + CHECK_NAME(glutCloseFunc); + CHECK_NAME(glutWMCloseFunc); + CHECK_NAME(glutMenuDestroyFunc); + CHECK_NAME(glutFullScreenToggle); + CHECK_NAME(glutSetOption); + CHECK_NAME(glutGetModeValues); + CHECK_NAME(glutSetWindowData); + CHECK_NAME(glutGetWindowData); + CHECK_NAME(glutSetMenuData); + CHECK_NAME(glutGetMenuData); + CHECK_NAME(glutBitmapHeight); + CHECK_NAME(glutStrokeHeight); + CHECK_NAME(glutBitmapString); + CHECK_NAME(glutStrokeString); + CHECK_NAME(glutWireRhombicDodecahedron); + CHECK_NAME(glutSolidRhombicDodecahedron); + CHECK_NAME(glutWireSierpinskiSponge); + CHECK_NAME(glutSolidSierpinskiSponge); + CHECK_NAME(glutWireCylinder); + CHECK_NAME(glutSolidCylinder); + CHECK_NAME(glutGetProcAddress); + CHECK_NAME(glutMouseWheelFunc); + CHECK_NAME(glutJoystickGetNumAxes); + CHECK_NAME(glutJoystickGetNumButtons); + CHECK_NAME(glutJoystickNotWorking); + CHECK_NAME(glutJoystickGetDeadBand); + CHECK_NAME(glutJoystickSetDeadBand); + CHECK_NAME(glutJoystickGetSaturation); + CHECK_NAME(glutJoystickSetSaturation); + CHECK_NAME(glutJoystickSetMinRange); + CHECK_NAME(glutJoystickSetMaxRange); + CHECK_NAME(glutJoystickSetCenter); + CHECK_NAME(glutJoystickGetMinRange); + CHECK_NAME(glutJoystickGetMaxRange); + CHECK_NAME(glutJoystickGetCenter); + CHECK_NAME(glutInitContextVersion); + CHECK_NAME(glutInitContextFlags); + CHECK_NAME(glutInitContextProfile); +#undef CHECK_NAME + + return NULL; +} + + +SFG_Proc fghGetProcAddress( const char *procName ) +{ +#if TARGET_HOST_MS_WINDOWS + return (SFG_Proc)wglGetProcAddress( ( LPCSTR )procName ); +#elif TARGET_HOST_POSIX_X11 && defined( GLX_ARB_get_proc_address ) + return (SFG_Proc)glXGetProcAddressARB( ( const GLubyte * )procName ); +#else + return NULL; +#endif +} + + +GLUTproc FGAPIENTRY +glutGetProcAddress( const char *procName ) +{ + GLUTproc p; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGetProcAddress" ); + + /* Try GLUT functions first, then core GL functions */ + p = fghGetGLUTProcAddress( procName ); + return ( p != NULL ) ? p : fghGetProcAddress( procName ); +} diff --git a/tests/box2d/freeglut/freeglut_ext.h b/tests/box2d/freeglut/freeglut_ext.h new file mode 100755 index 00000000..aca85e7b --- /dev/null +++ b/tests/box2d/freeglut/freeglut_ext.h @@ -0,0 +1,212 @@ +#ifndef __FREEGLUT_EXT_H__ +#define __FREEGLUT_EXT_H__ + +/* + * freeglut_ext.h + * + * The non-GLUT-compatible extensions to the freeglut library include file + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, <olszta@sourceforge.net> + * Creation date: Thu Dec 2 1999 + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifdef __cplusplus + extern "C" { +#endif + +/* + * Additional GLUT Key definitions for the Special key function + */ +#define GLUT_KEY_NUM_LOCK 0x006D +#define GLUT_KEY_BEGIN 0x006E +#define GLUT_KEY_DELETE 0x006F + +/* + * GLUT API Extension macro definitions -- behaviour when the user clicks on an "x" to close a window + */ +#define GLUT_ACTION_EXIT 0 +#define GLUT_ACTION_GLUTMAINLOOP_RETURNS 1 +#define GLUT_ACTION_CONTINUE_EXECUTION 2 + +/* + * Create a new rendering context when the user opens a new window? + */ +#define GLUT_CREATE_NEW_CONTEXT 0 +#define GLUT_USE_CURRENT_CONTEXT 1 + +/* + * Direct/Indirect rendering context options (has meaning only in Unix/X11) + */ +#define GLUT_FORCE_INDIRECT_CONTEXT 0 +#define GLUT_ALLOW_DIRECT_CONTEXT 1 +#define GLUT_TRY_DIRECT_CONTEXT 2 +#define GLUT_FORCE_DIRECT_CONTEXT 3 + +/* + * GLUT API Extension macro definitions -- the glutGet parameters + */ +#define GLUT_INIT_STATE 0x007C + +#define GLUT_ACTION_ON_WINDOW_CLOSE 0x01F9 + +#define GLUT_WINDOW_BORDER_WIDTH 0x01FA +#define GLUT_WINDOW_HEADER_HEIGHT 0x01FB + +#define GLUT_VERSION 0x01FC + +#define GLUT_RENDERING_CONTEXT 0x01FD +#define GLUT_DIRECT_RENDERING 0x01FE + +#define GLUT_FULL_SCREEN 0x01FF + +/* + * New tokens for glutInitDisplayMode. + * Only one GLUT_AUXn bit may be used at a time. + * Value 0x0400 is defined in OpenGLUT. + */ +#define GLUT_AUX 0x1000 + +#define GLUT_AUX1 0x1000 +#define GLUT_AUX2 0x2000 +#define GLUT_AUX3 0x4000 +#define GLUT_AUX4 0x8000 + +/* + * Context-related flags, see freeglut_state.c + */ +#define GLUT_INIT_MAJOR_VERSION 0x0200 +#define GLUT_INIT_MINOR_VERSION 0x0201 +#define GLUT_INIT_FLAGS 0x0202 +#define GLUT_INIT_PROFILE 0x0203 + +/* + * Flags for glutInitContextFlags, see freeglut_init.c + */ +#define GLUT_DEBUG 0x0001 +#define GLUT_FORWARD_COMPATIBLE 0x0002 + + +/* + * Flags for glutInitContextProfile, see freeglut_init.c + */ +#define GLUT_CORE_PROFILE 0x0001 +#define GLUT_COMPATIBILITY_PROFILE 0x0002 + +/* + * Process loop function, see freeglut_main.c + */ +FGAPI void FGAPIENTRY glutMainLoopEvent( void ); +FGAPI void FGAPIENTRY glutLeaveMainLoop( void ); +FGAPI void FGAPIENTRY glutExit ( void ); + +/* + * Window management functions, see freeglut_window.c + */ +FGAPI void FGAPIENTRY glutFullScreenToggle( void ); + +/* + * Window-specific callback functions, see freeglut_callbacks.c + */ +FGAPI void FGAPIENTRY glutMouseWheelFunc( void (* callback)( int, int, int, int ) ); +FGAPI void FGAPIENTRY glutCloseFunc( void (* callback)( void ) ); +FGAPI void FGAPIENTRY glutWMCloseFunc( void (* callback)( void ) ); +/* A. Donev: Also a destruction callback for menus */ +FGAPI void FGAPIENTRY glutMenuDestroyFunc( void (* callback)( void ) ); + +/* + * State setting and retrieval functions, see freeglut_state.c + */ +FGAPI void FGAPIENTRY glutSetOption ( GLenum option_flag, int value ); +FGAPI int * FGAPIENTRY glutGetModeValues(GLenum mode, int * size); +/* A.Donev: User-data manipulation */ +FGAPI void* FGAPIENTRY glutGetWindowData( void ); +FGAPI void FGAPIENTRY glutSetWindowData(void* data); +FGAPI void* FGAPIENTRY glutGetMenuData( void ); +FGAPI void FGAPIENTRY glutSetMenuData(void* data); + +/* + * Font stuff, see freeglut_font.c + */ +FGAPI int FGAPIENTRY glutBitmapHeight( void* font ); +FGAPI GLfloat FGAPIENTRY glutStrokeHeight( void* font ); +FGAPI void FGAPIENTRY glutBitmapString( void* font, const unsigned char *string ); +FGAPI void FGAPIENTRY glutStrokeString( void* font, const unsigned char *string ); + +/* + * Geometry functions, see freeglut_geometry.c + */ +FGAPI void FGAPIENTRY glutWireRhombicDodecahedron( void ); +FGAPI void FGAPIENTRY glutSolidRhombicDodecahedron( void ); +FGAPI void FGAPIENTRY glutWireSierpinskiSponge ( int num_levels, GLdouble offset[3], GLdouble scale ); +FGAPI void FGAPIENTRY glutSolidSierpinskiSponge ( int num_levels, GLdouble offset[3], GLdouble scale ); +FGAPI void FGAPIENTRY glutWireCylinder( GLdouble radius, GLdouble height, GLint slices, GLint stacks); +FGAPI void FGAPIENTRY glutSolidCylinder( GLdouble radius, GLdouble height, GLint slices, GLint stacks); + +/* + * Extension functions, see freeglut_ext.c + */ +typedef void (*GLUTproc)(); +FGAPI GLUTproc FGAPIENTRY glutGetProcAddress( const char *procName ); + +/* + * Joystick functions, see freeglut_joystick.c + */ +/* USE OF THESE FUNCTIONS IS DEPRECATED !!!!! */ +/* If you have a serious need for these functions in your application, please either + * contact the "freeglut" developer community at freeglut-developer@lists.sourceforge.net, + * switch to the OpenGLUT library, or else port your joystick functionality over to PLIB's + * "js" library. + */ +int glutJoystickGetNumAxes( int ident ); +int glutJoystickGetNumButtons( int ident ); +int glutJoystickNotWorking( int ident ); +float glutJoystickGetDeadBand( int ident, int axis ); +void glutJoystickSetDeadBand( int ident, int axis, float db ); +float glutJoystickGetSaturation( int ident, int axis ); +void glutJoystickSetSaturation( int ident, int axis, float st ); +void glutJoystickSetMinRange( int ident, float *axes ); +void glutJoystickSetMaxRange( int ident, float *axes ); +void glutJoystickSetCenter( int ident, float *axes ); +void glutJoystickGetMinRange( int ident, float *axes ); +void glutJoystickGetMaxRange( int ident, float *axes ); +void glutJoystickGetCenter( int ident, float *axes ); + +/* + * Initialization functions, see freeglut_init.c + */ +FGAPI void FGAPIENTRY glutInitContextVersion( int majorVersion, int minorVersion ); +FGAPI void FGAPIENTRY glutInitContextFlags( int flags ); +FGAPI void FGAPIENTRY glutInitContextProfile( int profile ); + +/* + * GLUT API macro definitions -- the display mode definitions + */ +#define GLUT_CAPTIONLESS 0x0400 +#define GLUT_BORDERLESS 0x0800 +#define GLUT_SRGB 0x1000 + +#ifdef __cplusplus + } +#endif + +/*** END OF FILE ***/ + +#endif /* __FREEGLUT_EXT_H__ */ diff --git a/tests/box2d/freeglut/freeglut_font.c b/tests/box2d/freeglut/freeglut_font.c new file mode 100755 index 00000000..6e37b95d --- /dev/null +++ b/tests/box2d/freeglut/freeglut_font.c @@ -0,0 +1,384 @@ +/* + * freeglut_font.c + * + * Bitmap and stroke fonts displaying. + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, <olszta@sourceforge.net> + * Creation date: Thu Dec 16 1999 + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "freeglut.h" +#include "freeglut_internal.h" + +/* + * TODO BEFORE THE STABLE RELEASE: + * + * Test things out ... + */ + +/* -- IMPORT DECLARATIONS -------------------------------------------------- */ + +/* + * These are the font faces defined in freeglut_font_data.c file: + */ +extern SFG_Font fgFontFixed8x13; +extern SFG_Font fgFontFixed9x15; +extern SFG_Font fgFontHelvetica10; +extern SFG_Font fgFontHelvetica12; +extern SFG_Font fgFontHelvetica18; +extern SFG_Font fgFontTimesRoman10; +extern SFG_Font fgFontTimesRoman24; +extern SFG_StrokeFont fgStrokeRoman; +extern SFG_StrokeFont fgStrokeMonoRoman; + + +/* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ + +/* + * Matches a font ID with a SFG_Font structure pointer. + * This was changed to match the GLUT header style. + */ +static SFG_Font* fghFontByID( void* font ) +{ + if( font == GLUT_BITMAP_8_BY_13 ) + return &fgFontFixed8x13; + if( font == GLUT_BITMAP_9_BY_15 ) + return &fgFontFixed9x15; + if( font == GLUT_BITMAP_HELVETICA_10 ) + return &fgFontHelvetica10; + if( font == GLUT_BITMAP_HELVETICA_12 ) + return &fgFontHelvetica12; + if( font == GLUT_BITMAP_HELVETICA_18 ) + return &fgFontHelvetica18; + if( font == GLUT_BITMAP_TIMES_ROMAN_10 ) + return &fgFontTimesRoman10; + if( font == GLUT_BITMAP_TIMES_ROMAN_24 ) + return &fgFontTimesRoman24; + + fgWarning( "font 0x%08x not found", font ); + return 0; +} + +/* + * Matches a font ID with a SFG_StrokeFont structure pointer. + * This was changed to match the GLUT header style. + */ +static SFG_StrokeFont* fghStrokeByID( void* font ) +{ + if( font == GLUT_STROKE_ROMAN ) + return &fgStrokeRoman; + if( font == GLUT_STROKE_MONO_ROMAN ) + return &fgStrokeMonoRoman; + + fgWarning( "stroke font 0x%08x not found", font ); + return 0; +} + + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +/* + * Draw a bitmap character + */ +void FGAPIENTRY glutBitmapCharacter( void* fontID, int character ) +{ + const GLubyte* face; + SFG_Font* font; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutBitmapCharacter" ); + font = fghFontByID( fontID ); + freeglut_return_if_fail( ( character >= 1 )&&( character < 256 ) ); + freeglut_return_if_fail( font ); + + /* + * Find the character we want to draw (???) + */ + face = font->Characters[ character ]; + + glPushClientAttrib( GL_CLIENT_PIXEL_STORE_BIT ); + glPixelStorei( GL_UNPACK_SWAP_BYTES, GL_FALSE ); + glPixelStorei( GL_UNPACK_LSB_FIRST, GL_FALSE ); + glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 ); + glPixelStorei( GL_UNPACK_SKIP_ROWS, 0 ); + glPixelStorei( GL_UNPACK_SKIP_PIXELS, 0 ); + glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + glBitmap( + face[ 0 ], font->Height, /* The bitmap's width and height */ + font->xorig, font->yorig, /* The origin in the font glyph */ + ( float )( face[ 0 ] ), 0.0, /* The raster advance -- inc. x,y */ + ( face + 1 ) /* The packed bitmap data... */ + ); + glPopClientAttrib( ); +} + +void FGAPIENTRY glutBitmapString( void* fontID, const unsigned char *string ) +{ + unsigned char c; + float x = 0.0f ; + SFG_Font* font; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutBitmapString" ); + font = fghFontByID( fontID ); + freeglut_return_if_fail( font ); + if ( !string || ! *string ) + return; + + glPushClientAttrib( GL_CLIENT_PIXEL_STORE_BIT ); + glPixelStorei( GL_UNPACK_SWAP_BYTES, GL_FALSE ); + glPixelStorei( GL_UNPACK_LSB_FIRST, GL_FALSE ); + glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 ); + glPixelStorei( GL_UNPACK_SKIP_ROWS, 0 ); + glPixelStorei( GL_UNPACK_SKIP_PIXELS, 0 ); + glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + + /* + * Step through the string, drawing each character. + * A newline will simply translate the next character's insertion + * point back to the start of the line and down one line. + */ + while( ( c = *string++) ) + if( c == '\n' ) + { + glBitmap ( 0, 0, 0, 0, -x, (float) -font->Height, NULL ); + x = 0.0f; + } + else /* Not an EOL, draw the bitmap character */ + { + const GLubyte* face = font->Characters[ c ]; + + glBitmap( + face[ 0 ], font->Height, /* Bitmap's width and height */ + font->xorig, font->yorig, /* The origin in the font glyph */ + ( float )( face[ 0 ] ), 0.0, /* The raster advance; inc. x,y */ + ( face + 1 ) /* The packed bitmap data... */ + ); + + x += ( float )( face[ 0 ] ); + } + + glPopClientAttrib( ); +} + +/* + * Returns the width in pixels of a font's character + */ +int FGAPIENTRY glutBitmapWidth( void* fontID, int character ) +{ + SFG_Font* font; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutBitmapWidth" ); + font = fghFontByID( fontID ); + freeglut_return_val_if_fail( character > 0 && character < 256, 0 ); + freeglut_return_val_if_fail( font, 0 ); + return *( font->Characters[ character ] ); +} + +/* + * Return the width of a string drawn using a bitmap font + */ +int FGAPIENTRY glutBitmapLength( void* fontID, const unsigned char* string ) +{ + unsigned char c; + int length = 0, this_line_length = 0; + SFG_Font* font; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutBitmapLength" ); + font = fghFontByID( fontID ); + freeglut_return_val_if_fail( font, 0 ); + if ( !string || ! *string ) + return 0; + + while( ( c = *string++) ) + { + if( c != '\n' )/* Not an EOL, increment length of line */ + this_line_length += *( font->Characters[ c ]); + else /* EOL; reset the length of this line */ + { + if( length < this_line_length ) + length = this_line_length; + this_line_length = 0; + } + } + if ( length < this_line_length ) + length = this_line_length; + + return length; +} + +/* + * Returns the height of a bitmap font + */ +int FGAPIENTRY glutBitmapHeight( void* fontID ) +{ + SFG_Font* font; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutBitmapHeight" ); + font = fghFontByID( fontID ); + freeglut_return_val_if_fail( font, 0 ); + return font->Height; +} + +/* + * Draw a stroke character + */ +void FGAPIENTRY glutStrokeCharacter( void* fontID, int character ) +{ + const SFG_StrokeChar *schar; + const SFG_StrokeStrip *strip; + int i, j; + SFG_StrokeFont* font; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutStrokeCharacter" ); + font = fghStrokeByID( fontID ); + freeglut_return_if_fail( character >= 0 ); + freeglut_return_if_fail( character < font->Quantity ); + freeglut_return_if_fail( font ); + + schar = font->Characters[ character ]; + freeglut_return_if_fail( schar ); + strip = schar->Strips; + + for( i = 0; i < schar->Number; i++, strip++ ) + { + glBegin( GL_LINE_STRIP ); + for( j = 0; j < strip->Number; j++ ) + glVertex2f( strip->Vertices[ j ].X, strip->Vertices[ j ].Y ); + glEnd( ); + glBegin( GL_POINTS ); + for( j = 0; j < strip->Number; j++ ) + glVertex2f( strip->Vertices[ j ].X, strip->Vertices[ j ].Y ); + glEnd( ); + } + glTranslatef( schar->Right, 0.0, 0.0 ); +} + +void FGAPIENTRY glutStrokeString( void* fontID, const unsigned char *string ) +{ + unsigned char c; + int i, j; + float length = 0.0; + SFG_StrokeFont* font; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutStrokeString" ); + font = fghStrokeByID( fontID ); + freeglut_return_if_fail( font ); + if ( !string || ! *string ) + return; + + /* + * Step through the string, drawing each character. + * A newline will simply translate the next character's insertion + * point back to the start of the line and down one line. + */ + while( ( c = *string++) ) + if( c < font->Quantity ) + { + if( c == '\n' ) + { + glTranslatef ( -length, -( float )( font->Height ), 0.0 ); + length = 0.0; + } + else /* Not an EOL, draw the bitmap character */ + { + const SFG_StrokeChar *schar = font->Characters[ c ]; + if( schar ) + { + const SFG_StrokeStrip *strip = schar->Strips; + + for( i = 0; i < schar->Number; i++, strip++ ) + { + glBegin( GL_LINE_STRIP ); + for( j = 0; j < strip->Number; j++ ) + glVertex2f( strip->Vertices[ j ].X, + strip->Vertices[ j ].Y); + + glEnd( ); + } + + length += schar->Right; + glTranslatef( schar->Right, 0.0, 0.0 ); + } + } + } +} + +/* + * Return the width in pixels of a stroke character + */ +int FGAPIENTRY glutStrokeWidth( void* fontID, int character ) +{ + const SFG_StrokeChar *schar; + SFG_StrokeFont* font; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutStrokeWidth" ); + font = fghStrokeByID( fontID ); + freeglut_return_val_if_fail( ( character >= 0 ) && + ( character < font->Quantity ), + 0 + ); + freeglut_return_val_if_fail( font, 0 ); + schar = font->Characters[ character ]; + freeglut_return_val_if_fail( schar, 0 ); + + return ( int )( schar->Right + 0.5 ); +} + +/* + * Return the width of a string drawn using a stroke font + */ +int FGAPIENTRY glutStrokeLength( void* fontID, const unsigned char* string ) +{ + unsigned char c; + float length = 0.0; + float this_line_length = 0.0; + SFG_StrokeFont* font; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutStrokeLength" ); + font = fghStrokeByID( fontID ); + freeglut_return_val_if_fail( font, 0 ); + if ( !string || ! *string ) + return 0; + + while( ( c = *string++) ) + if( c < font->Quantity ) + { + if( c == '\n' ) /* EOL; reset the length of this line */ + { + if( length < this_line_length ) + length = this_line_length; + this_line_length = 0.0; + } + else /* Not an EOL, increment the length of this line */ + { + const SFG_StrokeChar *schar = font->Characters[ c ]; + if( schar ) + this_line_length += schar->Right; + } + } + if( length < this_line_length ) + length = this_line_length; + return( int )( length + 0.5 ); +} + +/* + * Returns the height of a stroke font + */ +GLfloat FGAPIENTRY glutStrokeHeight( void* fontID ) +{ + SFG_StrokeFont* font; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutStrokeHeight" ); + font = fghStrokeByID( fontID ); + freeglut_return_val_if_fail( font, 0.0 ); + return font->Height; +} + +/*** END OF FILE ***/ diff --git a/tests/box2d/freeglut/freeglut_font_data.c b/tests/box2d/freeglut/freeglut_font_data.c new file mode 100755 index 00000000..5ffef5a0 --- /dev/null +++ b/tests/box2d/freeglut/freeglut_font_data.c @@ -0,0 +1,2020 @@ +/* + \file og_font_data.c + \brief Bitmapped font data for OpenGLUT fonts. +*/ + +/* + * This file has been automatically generated by the + * genfonts utility. + * + * The legal status of this file is a bit vague. The font glyphs + * themselves come from XFree86 v4.3.0 (as of this writing), and as + * part of the X server may be subject to the XFree86 copyrights. + * The original freeglut fonts were extracted by a utility written + * by Pawel W. Olszta (see below) and the generated fonts contained + * his copyright exclusively. Steve Baker asserts that Pawel + * assigned intellectual property rights to Steve Baker. Steve + * Baker also asserts that fonts cannot be copyrighted. He has + * neither stripped the copyright from the freeglut fonts nor + * formally retitled anything in his name. Since that time, the + * OpenGLUT project has branched from freeglut, and has made + * necessary modifications to Pawel's ``genfonts'' utility. + * To that extent, OpenGLUT may have some title to this file. + * What is fairly clear is that the font data is licensed under + * the XFree86 license (which is variously termed ``XFree'' and + * ``MIT'' by the freeglut project). It is believed that all + * title holders wish this file to be as useful as possible, and + * that either the ``XFree'' or ``MIT'' license works. + * + * Portions copyright (c) 2004, the OpenGLUT project contributors. + * OpenGLUT branched from freeglut in February, 2004. + * + * Copyright (c) 1999-2000 by Pawel W. Olszta + * Written by Pawel W. Olszta, <olszta@sourceforge.net> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Sotware. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "freeglut.h" +#include "freeglut_internal.h" + +/* + * The following bitmapped fonts are defined in this file: + * + * 1. fgFontFixed8x13 + * -misc-fixed-medium-r-normal--13-120-75-75-C-80-iso8859-1 + * 2. fgFontFixed9x15 + * -misc-fixed-medium-r-normal--15-140-75-75-C-90-iso8859-1 + * 3. fgFontHelvetica10 + * -adobe-helvetica-medium-r-normal--10-100-75-75-p-56-iso8859-1 + * 4. fgFontHelvetica12 + * -adobe-helvetica-medium-r-normal--12-120-75-75-p-67-iso8859-1 + * 5. fgFontHelvetica18 + * -adobe-helvetica-medium-r-normal--18-180-75-75-p-98-iso8859-1 + * 6. fgFontTimesRoman10 + * -adobe-times-medium-r-normal--10-100-75-75-p-54-iso8859-1 + * 7. fgFontTimesRoman24 + * -adobe-times-medium-r-normal--24-240-75-75-p-124-iso8859-1 + */ + +static const GLubyte Fixed8x13_Character_000[] = { 8, 0, 0, 0,170, 0,130, 0,130, 0,130, 0,170, 0, 0}; +static const GLubyte Fixed8x13_Character_001[] = { 8, 0, 0, 0, 0, 16, 56,124,254,124, 56, 16, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_002[] = { 8, 0,170, 85,170, 85,170, 85,170, 85,170, 85,170, 85,170}; +static const GLubyte Fixed8x13_Character_003[] = { 8, 0, 0, 0, 4, 4, 4, 4,174,160,224,160,160, 0, 0}; +static const GLubyte Fixed8x13_Character_004[] = { 8, 0, 0, 0, 8, 8, 12, 8,142,128,192,128,224, 0, 0}; +static const GLubyte Fixed8x13_Character_005[] = { 8, 0, 0, 0, 10, 10, 12, 10,108,128,128,128, 96, 0, 0}; +static const GLubyte Fixed8x13_Character_006[] = { 8, 0, 0, 0, 8, 8, 12, 8,238,128,128,128,128, 0, 0}; +static const GLubyte Fixed8x13_Character_007[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 24, 36, 36, 24, 0, 0}; +static const GLubyte Fixed8x13_Character_008[] = { 8, 0, 0, 0, 0,124, 0, 16, 16,124, 16, 16, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_009[] = { 8, 0, 0, 0, 14, 8, 8, 8,168,160,160,160,192, 0, 0}; +static const GLubyte Fixed8x13_Character_010[] = { 8, 0, 0, 0, 4, 4, 4, 4, 46, 80, 80,136,136, 0, 0}; +static const GLubyte Fixed8x13_Character_011[] = { 8, 0, 0, 0, 0, 0, 0, 0,240, 16, 16, 16, 16, 16, 16}; +static const GLubyte Fixed8x13_Character_012[] = { 8, 0, 16, 16, 16, 16, 16, 16,240, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_013[] = { 8, 0, 16, 16, 16, 16, 16, 16, 31, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_014[] = { 8, 0, 0, 0, 0, 0, 0, 0, 31, 16, 16, 16, 16, 16, 16}; +static const GLubyte Fixed8x13_Character_015[] = { 8, 0, 16, 16, 16, 16, 16, 16,255, 16, 16, 16, 16, 16, 16}; +static const GLubyte Fixed8x13_Character_016[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255}; +static const GLubyte Fixed8x13_Character_017[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_018[] = { 8, 0, 0, 0, 0, 0, 0, 0,255, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_019[] = { 8, 0, 0, 0, 0,255, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_020[] = { 8, 0,255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_021[] = { 8, 0, 16, 16, 16, 16, 16, 16, 31, 16, 16, 16, 16, 16, 16}; +static const GLubyte Fixed8x13_Character_022[] = { 8, 0, 16, 16, 16, 16, 16, 16,240, 16, 16, 16, 16, 16, 16}; +static const GLubyte Fixed8x13_Character_023[] = { 8, 0, 0, 0, 0, 0, 0, 0,255, 16, 16, 16, 16, 16, 16}; +static const GLubyte Fixed8x13_Character_024[] = { 8, 0, 16, 16, 16, 16, 16, 16,255, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_025[] = { 8, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}; +static const GLubyte Fixed8x13_Character_026[] = { 8, 0, 0, 0,254, 0, 14, 48,192, 48, 14, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_027[] = { 8, 0, 0, 0,254, 0,224, 24, 6, 24,224, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_028[] = { 8, 0, 0, 0, 68, 68, 68, 68, 68,254, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_029[] = { 8, 0, 0, 0, 32, 32,126, 16, 8,126, 4, 4, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_030[] = { 8, 0, 0, 0,220, 98, 32, 32, 32,112, 32, 34, 28, 0, 0}; +static const GLubyte Fixed8x13_Character_031[] = { 8, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_032[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_033[] = { 8, 0, 0, 0, 16, 0, 16, 16, 16, 16, 16, 16, 16, 0, 0}; +static const GLubyte Fixed8x13_Character_034[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 36, 36, 0, 0}; +static const GLubyte Fixed8x13_Character_035[] = { 8, 0, 0, 0, 0, 36, 36,126, 36,126, 36, 36, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_036[] = { 8, 0, 0, 0, 16,120, 20, 20, 56, 80, 80, 60, 16, 0, 0}; +static const GLubyte Fixed8x13_Character_037[] = { 8, 0, 0, 0, 68, 42, 36, 16, 8, 8, 36, 82, 34, 0, 0}; +static const GLubyte Fixed8x13_Character_038[] = { 8, 0, 0, 0, 58, 68, 74, 48, 72, 72, 48, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_039[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 48, 56, 0, 0}; +static const GLubyte Fixed8x13_Character_040[] = { 8, 0, 0, 0, 4, 8, 8, 16, 16, 16, 8, 8, 4, 0, 0}; +static const GLubyte Fixed8x13_Character_041[] = { 8, 0, 0, 0, 32, 16, 16, 8, 8, 8, 16, 16, 32, 0, 0}; +static const GLubyte Fixed8x13_Character_042[] = { 8, 0, 0, 0, 0, 0, 36, 24,126, 24, 36, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_043[] = { 8, 0, 0, 0, 0, 0, 16, 16,124, 16, 16, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_044[] = { 8, 0, 0, 64, 48, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_045[] = { 8, 0, 0, 0, 0, 0, 0, 0,126, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_046[] = { 8, 0, 0, 16, 56, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_047[] = { 8, 0, 0, 0,128,128, 64, 32, 16, 8, 4, 2, 2, 0, 0}; +static const GLubyte Fixed8x13_Character_048[] = { 8, 0, 0, 0, 24, 36, 66, 66, 66, 66, 66, 36, 24, 0, 0}; +static const GLubyte Fixed8x13_Character_049[] = { 8, 0, 0, 0,124, 16, 16, 16, 16, 16, 80, 48, 16, 0, 0}; +static const GLubyte Fixed8x13_Character_050[] = { 8, 0, 0, 0,126, 64, 32, 24, 4, 2, 66, 66, 60, 0, 0}; +static const GLubyte Fixed8x13_Character_051[] = { 8, 0, 0, 0, 60, 66, 2, 2, 28, 8, 4, 2,126, 0, 0}; +static const GLubyte Fixed8x13_Character_052[] = { 8, 0, 0, 0, 4, 4,126, 68, 68, 36, 20, 12, 4, 0, 0}; +static const GLubyte Fixed8x13_Character_053[] = { 8, 0, 0, 0, 60, 66, 2, 2, 98, 92, 64, 64,126, 0, 0}; +static const GLubyte Fixed8x13_Character_054[] = { 8, 0, 0, 0, 60, 66, 66, 98, 92, 64, 64, 32, 28, 0, 0}; +static const GLubyte Fixed8x13_Character_055[] = { 8, 0, 0, 0, 32, 32, 16, 16, 8, 8, 4, 2,126, 0, 0}; +static const GLubyte Fixed8x13_Character_056[] = { 8, 0, 0, 0, 60, 66, 66, 66, 60, 66, 66, 66, 60, 0, 0}; +static const GLubyte Fixed8x13_Character_057[] = { 8, 0, 0, 0, 56, 4, 2, 2, 58, 70, 66, 66, 60, 0, 0}; +static const GLubyte Fixed8x13_Character_058[] = { 8, 0, 0, 16, 56, 16, 0, 0, 16, 56, 16, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_059[] = { 8, 0, 0, 64, 48, 56, 0, 0, 16, 56, 16, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_060[] = { 8, 0, 0, 0, 2, 4, 8, 16, 32, 16, 8, 4, 2, 0, 0}; +static const GLubyte Fixed8x13_Character_061[] = { 8, 0, 0, 0, 0, 0,126, 0, 0,126, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_062[] = { 8, 0, 0, 0, 64, 32, 16, 8, 4, 8, 16, 32, 64, 0, 0}; +static const GLubyte Fixed8x13_Character_063[] = { 8, 0, 0, 0, 8, 0, 8, 8, 4, 2, 66, 66, 60, 0, 0}; +static const GLubyte Fixed8x13_Character_064[] = { 8, 0, 0, 0, 60, 64, 74, 86, 82, 78, 66, 66, 60, 0, 0}; +static const GLubyte Fixed8x13_Character_065[] = { 8, 0, 0, 0, 66, 66, 66,126, 66, 66, 66, 36, 24, 0, 0}; +static const GLubyte Fixed8x13_Character_066[] = { 8, 0, 0, 0,252, 66, 66, 66,124, 66, 66, 66,252, 0, 0}; +static const GLubyte Fixed8x13_Character_067[] = { 8, 0, 0, 0, 60, 66, 64, 64, 64, 64, 64, 66, 60, 0, 0}; +static const GLubyte Fixed8x13_Character_068[] = { 8, 0, 0, 0,252, 66, 66, 66, 66, 66, 66, 66,252, 0, 0}; +static const GLubyte Fixed8x13_Character_069[] = { 8, 0, 0, 0,126, 64, 64, 64,120, 64, 64, 64,126, 0, 0}; +static const GLubyte Fixed8x13_Character_070[] = { 8, 0, 0, 0, 64, 64, 64, 64,120, 64, 64, 64,126, 0, 0}; +static const GLubyte Fixed8x13_Character_071[] = { 8, 0, 0, 0, 58, 70, 66, 78, 64, 64, 64, 66, 60, 0, 0}; +static const GLubyte Fixed8x13_Character_072[] = { 8, 0, 0, 0, 66, 66, 66, 66,126, 66, 66, 66, 66, 0, 0}; +static const GLubyte Fixed8x13_Character_073[] = { 8, 0, 0, 0,124, 16, 16, 16, 16, 16, 16, 16,124, 0, 0}; +static const GLubyte Fixed8x13_Character_074[] = { 8, 0, 0, 0, 56, 68, 4, 4, 4, 4, 4, 4, 31, 0, 0}; +static const GLubyte Fixed8x13_Character_075[] = { 8, 0, 0, 0, 66, 68, 72, 80, 96, 80, 72, 68, 66, 0, 0}; +static const GLubyte Fixed8x13_Character_076[] = { 8, 0, 0, 0,126, 64, 64, 64, 64, 64, 64, 64, 64, 0, 0}; +static const GLubyte Fixed8x13_Character_077[] = { 8, 0, 0, 0,130,130,130,146,146,170,198,130,130, 0, 0}; +static const GLubyte Fixed8x13_Character_078[] = { 8, 0, 0, 0, 66, 66, 66, 70, 74, 82, 98, 66, 66, 0, 0}; +static const GLubyte Fixed8x13_Character_079[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 66, 60, 0, 0}; +static const GLubyte Fixed8x13_Character_080[] = { 8, 0, 0, 0, 64, 64, 64, 64,124, 66, 66, 66,124, 0, 0}; +static const GLubyte Fixed8x13_Character_081[] = { 8, 0, 0, 2, 60, 74, 82, 66, 66, 66, 66, 66, 60, 0, 0}; +static const GLubyte Fixed8x13_Character_082[] = { 8, 0, 0, 0, 66, 68, 72, 80,124, 66, 66, 66,124, 0, 0}; +static const GLubyte Fixed8x13_Character_083[] = { 8, 0, 0, 0, 60, 66, 2, 2, 60, 64, 64, 66, 60, 0, 0}; +static const GLubyte Fixed8x13_Character_084[] = { 8, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16,254, 0, 0}; +static const GLubyte Fixed8x13_Character_085[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 66, 66, 0, 0}; +static const GLubyte Fixed8x13_Character_086[] = { 8, 0, 0, 0, 16, 40, 40, 40, 68, 68, 68,130,130, 0, 0}; +static const GLubyte Fixed8x13_Character_087[] = { 8, 0, 0, 0, 68,170,146,146,146,130,130,130,130, 0, 0}; +static const GLubyte Fixed8x13_Character_088[] = { 8, 0, 0, 0,130,130, 68, 40, 16, 40, 68,130,130, 0, 0}; +static const GLubyte Fixed8x13_Character_089[] = { 8, 0, 0, 0, 16, 16, 16, 16, 16, 40, 68,130,130, 0, 0}; +static const GLubyte Fixed8x13_Character_090[] = { 8, 0, 0, 0,126, 64, 64, 32, 16, 8, 4, 2,126, 0, 0}; +static const GLubyte Fixed8x13_Character_091[] = { 8, 0, 0, 0, 60, 32, 32, 32, 32, 32, 32, 32, 60, 0, 0}; +static const GLubyte Fixed8x13_Character_092[] = { 8, 0, 0, 0, 2, 2, 4, 8, 16, 32, 64,128,128, 0, 0}; +static const GLubyte Fixed8x13_Character_093[] = { 8, 0, 0, 0,120, 8, 8, 8, 8, 8, 8, 8,120, 0, 0}; +static const GLubyte Fixed8x13_Character_094[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 40, 16, 0, 0}; +static const GLubyte Fixed8x13_Character_095[] = { 8, 0, 0,254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_096[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 24, 56, 0, 0}; +static const GLubyte Fixed8x13_Character_097[] = { 8, 0, 0, 0, 58, 70, 66, 62, 2, 60, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_098[] = { 8, 0, 0, 0, 92, 98, 66, 66, 98, 92, 64, 64, 64, 0, 0}; +static const GLubyte Fixed8x13_Character_099[] = { 8, 0, 0, 0, 60, 66, 64, 64, 66, 60, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_100[] = { 8, 0, 0, 0, 58, 70, 66, 66, 70, 58, 2, 2, 2, 0, 0}; +static const GLubyte Fixed8x13_Character_101[] = { 8, 0, 0, 0, 60, 66, 64,126, 66, 60, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_102[] = { 8, 0, 0, 0, 32, 32, 32, 32,124, 32, 32, 34, 28, 0, 0}; +static const GLubyte Fixed8x13_Character_103[] = { 8, 0, 60, 66, 60, 64, 56, 68, 68, 58, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_104[] = { 8, 0, 0, 0, 66, 66, 66, 66, 98, 92, 64, 64, 64, 0, 0}; +static const GLubyte Fixed8x13_Character_105[] = { 8, 0, 0, 0,124, 16, 16, 16, 16, 48, 0, 16, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_106[] = { 8, 0, 56, 68, 68, 4, 4, 4, 4, 12, 0, 4, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_107[] = { 8, 0, 0, 0, 66, 68, 72,112, 72, 68, 64, 64, 64, 0, 0}; +static const GLubyte Fixed8x13_Character_108[] = { 8, 0, 0, 0,124, 16, 16, 16, 16, 16, 16, 16, 48, 0, 0}; +static const GLubyte Fixed8x13_Character_109[] = { 8, 0, 0, 0,130,146,146,146,146,236, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_110[] = { 8, 0, 0, 0, 66, 66, 66, 66, 98, 92, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_111[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 60, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_112[] = { 8, 0, 64, 64, 64, 92, 98, 66, 98, 92, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_113[] = { 8, 0, 2, 2, 2, 58, 70, 66, 70, 58, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_114[] = { 8, 0, 0, 0, 32, 32, 32, 32, 34, 92, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_115[] = { 8, 0, 0, 0, 60, 66, 12, 48, 66, 60, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_116[] = { 8, 0, 0, 0, 28, 34, 32, 32, 32,124, 32, 32, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_117[] = { 8, 0, 0, 0, 58, 68, 68, 68, 68, 68, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_118[] = { 8, 0, 0, 0, 16, 40, 40, 68, 68, 68, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_119[] = { 8, 0, 0, 0, 68,170,146,146,130,130, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_120[] = { 8, 0, 0, 0, 66, 36, 24, 24, 36, 66, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_121[] = { 8, 0, 60, 66, 2, 58, 70, 66, 66, 66, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_122[] = { 8, 0, 0, 0,126, 32, 16, 8, 4,126, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_123[] = { 8, 0, 0, 0, 14, 16, 16, 8, 48, 8, 16, 16, 14, 0, 0}; +static const GLubyte Fixed8x13_Character_124[] = { 8, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0}; +static const GLubyte Fixed8x13_Character_125[] = { 8, 0, 0, 0,112, 8, 8, 16, 12, 16, 8, 8,112, 0, 0}; +static const GLubyte Fixed8x13_Character_126[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 84, 36, 0, 0}; +static const GLubyte Fixed8x13_Character_127[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_128[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_129[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_130[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_131[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_132[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_133[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_134[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_135[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_136[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_137[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_138[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_139[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_140[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_141[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_142[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_143[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_144[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_145[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_146[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_147[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_148[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_149[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_150[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_151[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_152[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_153[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_154[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_155[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_156[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_157[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_158[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_159[] = { 9, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_160[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_161[] = { 8, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 0, 16, 0, 0}; +static const GLubyte Fixed8x13_Character_162[] = { 8, 0, 0, 0, 0, 16, 56, 84, 80, 80, 84, 56, 16, 0, 0}; +static const GLubyte Fixed8x13_Character_163[] = { 8, 0, 0, 0,220, 98, 32, 32, 32,112, 32, 34, 28, 0, 0}; +static const GLubyte Fixed8x13_Character_164[] = { 8, 0, 0, 0, 0, 66, 60, 36, 36, 60, 66, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_165[] = { 8, 0, 0, 0, 16, 16,124, 16,124, 40, 68,130,130, 0, 0}; +static const GLubyte Fixed8x13_Character_166[] = { 8, 0, 0, 0, 16, 16, 16, 16, 0, 16, 16, 16, 16, 0, 0}; +static const GLubyte Fixed8x13_Character_167[] = { 8, 0, 0, 0, 24, 36, 4, 24, 36, 36, 24, 32, 36, 24, 0}; +static const GLubyte Fixed8x13_Character_168[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,108, 0, 0}; +static const GLubyte Fixed8x13_Character_169[] = { 8, 0, 0, 0, 0, 56, 68,146,170,162,170,146, 68, 56, 0}; +static const GLubyte Fixed8x13_Character_170[] = { 8, 0, 0, 0, 0, 0,124, 0, 60, 68, 60, 4, 56, 0, 0}; +static const GLubyte Fixed8x13_Character_171[] = { 8, 0, 0, 0, 0, 18, 36, 72,144, 72, 36, 18, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_172[] = { 8, 0, 0, 0, 0, 2, 2, 2,126, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_173[] = { 8, 0, 0, 0, 0, 0, 0, 0, 60, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_174[] = { 8, 0, 0, 0, 0, 56, 68,170,178,170,170,146, 68, 56, 0}; +static const GLubyte Fixed8x13_Character_175[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,126, 0, 0}; +static const GLubyte Fixed8x13_Character_176[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 24, 36, 36, 24, 0, 0}; +static const GLubyte Fixed8x13_Character_177[] = { 8, 0, 0, 0, 0,124, 0, 16, 16,124, 16, 16, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_178[] = { 8, 0, 0, 0, 0, 0, 0, 0,120, 64, 48, 8, 72, 48, 0}; +static const GLubyte Fixed8x13_Character_179[] = { 8, 0, 0, 0, 0, 0, 0, 0, 48, 72, 8, 16, 72, 48, 0}; +static const GLubyte Fixed8x13_Character_180[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 8, 0}; +static const GLubyte Fixed8x13_Character_181[] = { 8, 0, 0, 64, 90,102, 66, 66, 66, 66, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_182[] = { 8, 0, 0, 0, 20, 20, 20, 20, 52,116,116,116, 62, 0, 0}; +static const GLubyte Fixed8x13_Character_183[] = { 8, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_184[] = { 8, 0, 24, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_185[] = { 8, 0, 0, 0, 0, 0, 0, 0,112, 32, 32, 32, 96, 32, 0}; +static const GLubyte Fixed8x13_Character_186[] = { 8, 0, 0, 0, 0, 0, 0,120, 0, 48, 72, 72, 48, 0, 0}; +static const GLubyte Fixed8x13_Character_187[] = { 8, 0, 0, 0, 0,144, 72, 36, 18, 36, 72,144, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_188[] = { 8, 0, 0, 0, 6, 26, 18, 10,230, 66, 64, 64,192, 64, 0}; +static const GLubyte Fixed8x13_Character_189[] = { 8, 0, 0, 0, 30, 16, 12, 2,242, 76, 64, 64,192, 64, 0}; +static const GLubyte Fixed8x13_Character_190[] = { 8, 0, 0, 0, 6, 26, 18, 10,102,146, 16, 32,144, 96, 0}; +static const GLubyte Fixed8x13_Character_191[] = { 8, 0, 0, 0, 60, 66, 66, 64, 32, 16, 16, 0, 16, 0, 0}; +static const GLubyte Fixed8x13_Character_192[] = { 8, 0, 0, 0, 66, 66,126, 66, 66, 36, 24, 0, 8, 16, 0}; +static const GLubyte Fixed8x13_Character_193[] = { 8, 0, 0, 0, 66, 66,126, 66, 66, 36, 24, 0, 16, 8, 0}; +static const GLubyte Fixed8x13_Character_194[] = { 8, 0, 0, 0, 66, 66,126, 66, 66, 36, 24, 0, 36, 24, 0}; +static const GLubyte Fixed8x13_Character_195[] = { 8, 0, 0, 0, 66, 66,126, 66, 66, 36, 24, 0, 76, 50, 0}; +static const GLubyte Fixed8x13_Character_196[] = { 8, 0, 0, 0, 66, 66,126, 66, 66, 36, 24, 0, 36, 36, 0}; +static const GLubyte Fixed8x13_Character_197[] = { 8, 0, 0, 0, 66, 66,126, 66, 66, 36, 24, 24, 36, 24, 0}; +static const GLubyte Fixed8x13_Character_198[] = { 8, 0, 0, 0,158,144,144,240,156,144,144,144,110, 0, 0}; +static const GLubyte Fixed8x13_Character_199[] = { 8, 0, 16, 8, 60, 66, 64, 64, 64, 64, 64, 66, 60, 0, 0}; +static const GLubyte Fixed8x13_Character_200[] = { 8, 0, 0, 0,126, 64, 64,120, 64, 64,126, 0, 8, 16, 0}; +static const GLubyte Fixed8x13_Character_201[] = { 8, 0, 0, 0,126, 64, 64,120, 64, 64,126, 0, 16, 8, 0}; +static const GLubyte Fixed8x13_Character_202[] = { 8, 0, 0, 0,126, 64, 64,120, 64, 64,126, 0, 36, 24, 0}; +static const GLubyte Fixed8x13_Character_203[] = { 8, 0, 0, 0,126, 64, 64,120, 64, 64,126, 0, 36, 36, 0}; +static const GLubyte Fixed8x13_Character_204[] = { 8, 0, 0, 0,124, 16, 16, 16, 16, 16,124, 0, 16, 32, 0}; +static const GLubyte Fixed8x13_Character_205[] = { 8, 0, 0, 0,124, 16, 16, 16, 16, 16,124, 0, 16, 8, 0}; +static const GLubyte Fixed8x13_Character_206[] = { 8, 0, 0, 0,124, 16, 16, 16, 16, 16,124, 0, 36, 24, 0}; +static const GLubyte Fixed8x13_Character_207[] = { 8, 0, 0, 0,124, 16, 16, 16, 16, 16,124, 0, 40, 40, 0}; +static const GLubyte Fixed8x13_Character_208[] = { 8, 0, 0, 0,120, 68, 66, 66,226, 66, 66, 68,120, 0, 0}; +static const GLubyte Fixed8x13_Character_209[] = { 8, 0, 0, 0,130,134,138,146,162,194,130, 0,152,100, 0}; +static const GLubyte Fixed8x13_Character_210[] = { 8, 0, 0, 0,124,130,130,130,130,130,124, 0, 16, 32, 0}; +static const GLubyte Fixed8x13_Character_211[] = { 8, 0, 0, 0,124,130,130,130,130,130,124, 0, 16, 8, 0}; +static const GLubyte Fixed8x13_Character_212[] = { 8, 0, 0, 0,124,130,130,130,130,130,124, 0, 36, 24, 0}; +static const GLubyte Fixed8x13_Character_213[] = { 8, 0, 0, 0,124,130,130,130,130,130,124, 0,152,100, 0}; +static const GLubyte Fixed8x13_Character_214[] = { 8, 0, 0, 0,124,130,130,130,130,130,124, 0, 40, 40, 0}; +static const GLubyte Fixed8x13_Character_215[] = { 8, 0, 0, 0, 0, 66, 36, 24, 24, 36, 66, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_216[] = { 8, 0, 0, 64, 60, 98, 82, 82, 82, 74, 74, 70, 60, 2, 0}; +static const GLubyte Fixed8x13_Character_217[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 0, 8, 16, 0}; +static const GLubyte Fixed8x13_Character_218[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 0, 16, 8, 0}; +static const GLubyte Fixed8x13_Character_219[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 0, 36, 24, 0}; +static const GLubyte Fixed8x13_Character_220[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 0, 36, 36, 0}; +static const GLubyte Fixed8x13_Character_221[] = { 8, 0, 0, 0, 16, 16, 16, 16, 40, 68, 68, 0, 16, 8, 0}; +static const GLubyte Fixed8x13_Character_222[] = { 8, 0, 0, 0, 64, 64, 64,124, 66, 66, 66,124, 64, 0, 0}; +static const GLubyte Fixed8x13_Character_223[] = { 8, 0, 0, 0, 92, 66, 66, 76, 80, 72, 68, 68, 56, 0, 0}; +static const GLubyte Fixed8x13_Character_224[] = { 8, 0, 0, 0, 58, 70, 66, 62, 2, 60, 0, 0, 8, 16, 0}; +static const GLubyte Fixed8x13_Character_225[] = { 8, 0, 0, 0, 58, 70, 66, 62, 2, 60, 0, 0, 8, 4, 0}; +static const GLubyte Fixed8x13_Character_226[] = { 8, 0, 0, 0, 58, 70, 66, 62, 2, 60, 0, 0, 36, 24, 0}; +static const GLubyte Fixed8x13_Character_227[] = { 8, 0, 0, 0, 58, 70, 66, 62, 2, 60, 0, 0, 76, 50, 0}; +static const GLubyte Fixed8x13_Character_228[] = { 8, 0, 0, 0, 58, 70, 66, 62, 2, 60, 0, 0, 36, 36, 0}; +static const GLubyte Fixed8x13_Character_229[] = { 8, 0, 0, 0, 58, 70, 66, 62, 2, 60, 0, 24, 36, 24, 0}; +static const GLubyte Fixed8x13_Character_230[] = { 8, 0, 0, 0,108,146,144,124, 18,108, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_231[] = { 8, 0, 16, 8, 60, 66, 64, 64, 66, 60, 0, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_232[] = { 8, 0, 0, 0, 60, 66, 64,126, 66, 60, 0, 0, 8, 16, 0}; +static const GLubyte Fixed8x13_Character_233[] = { 8, 0, 0, 0, 60, 66, 64,126, 66, 60, 0, 0, 16, 8, 0}; +static const GLubyte Fixed8x13_Character_234[] = { 8, 0, 0, 0, 60, 66, 64,126, 66, 60, 0, 0, 36, 24, 0}; +static const GLubyte Fixed8x13_Character_235[] = { 8, 0, 0, 0, 60, 66, 64,126, 66, 60, 0, 0, 36, 36, 0}; +static const GLubyte Fixed8x13_Character_236[] = { 8, 0, 0, 0,124, 16, 16, 16, 16, 48, 0, 0, 16, 32, 0}; +static const GLubyte Fixed8x13_Character_237[] = { 8, 0, 0, 0,124, 16, 16, 16, 16, 48, 0, 0, 32, 16, 0}; +static const GLubyte Fixed8x13_Character_238[] = { 8, 0, 0, 0,124, 16, 16, 16, 16, 48, 0, 0, 72, 48, 0}; +static const GLubyte Fixed8x13_Character_239[] = { 8, 0, 0, 0,124, 16, 16, 16, 16, 48, 0, 0, 40, 40, 0}; +static const GLubyte Fixed8x13_Character_240[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 60, 4, 40, 24, 36, 0}; +static const GLubyte Fixed8x13_Character_241[] = { 8, 0, 0, 0, 66, 66, 66, 66, 98, 92, 0, 0, 76, 50, 0}; +static const GLubyte Fixed8x13_Character_242[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 60, 0, 0, 16, 32, 0}; +static const GLubyte Fixed8x13_Character_243[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 60, 0, 0, 16, 8, 0}; +static const GLubyte Fixed8x13_Character_244[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 60, 0, 0, 36, 24, 0}; +static const GLubyte Fixed8x13_Character_245[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 60, 0, 0, 76, 50, 0}; +static const GLubyte Fixed8x13_Character_246[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 60, 0, 0, 36, 36, 0}; +static const GLubyte Fixed8x13_Character_247[] = { 8, 0, 0, 0, 0, 16, 16, 0,124, 0, 16, 16, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_248[] = { 8, 0, 0, 64, 60, 98, 82, 74, 70, 60, 2, 0, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_249[] = { 8, 0, 0, 0, 58, 68, 68, 68, 68, 68, 0, 0, 16, 32, 0}; +static const GLubyte Fixed8x13_Character_250[] = { 8, 0, 0, 0, 58, 68, 68, 68, 68, 68, 0, 0, 16, 8, 0}; +static const GLubyte Fixed8x13_Character_251[] = { 8, 0, 0, 0, 58, 68, 68, 68, 68, 68, 0, 0, 36, 24, 0}; +static const GLubyte Fixed8x13_Character_252[] = { 8, 0, 0, 0, 58, 68, 68, 68, 68, 68, 0, 0, 40, 40, 0}; +static const GLubyte Fixed8x13_Character_253[] = { 8, 0, 60, 66, 2, 58, 70, 66, 66, 66, 0, 0, 16, 8, 0}; +static const GLubyte Fixed8x13_Character_254[] = { 8, 0, 64, 64, 92, 98, 66, 66, 98, 92, 64, 64, 0, 0, 0}; +static const GLubyte Fixed8x13_Character_255[] = { 8, 0, 60, 66, 2, 58, 70, 66, 66, 66, 0, 0, 36, 36, 0}; + +/* The font characters mapping: */ +static const GLubyte* Fixed8x13_Character_Map[] = {Fixed8x13_Character_000,Fixed8x13_Character_001,Fixed8x13_Character_002,Fixed8x13_Character_003,Fixed8x13_Character_004,Fixed8x13_Character_005,Fixed8x13_Character_006,Fixed8x13_Character_007,Fixed8x13_Character_008,Fixed8x13_Character_009,Fixed8x13_Character_010,Fixed8x13_Character_011,Fixed8x13_Character_012,Fixed8x13_Character_013,Fixed8x13_Character_014,Fixed8x13_Character_015, + Fixed8x13_Character_016,Fixed8x13_Character_017,Fixed8x13_Character_018,Fixed8x13_Character_019,Fixed8x13_Character_020,Fixed8x13_Character_021,Fixed8x13_Character_022,Fixed8x13_Character_023,Fixed8x13_Character_024,Fixed8x13_Character_025,Fixed8x13_Character_026,Fixed8x13_Character_027,Fixed8x13_Character_028,Fixed8x13_Character_029,Fixed8x13_Character_030,Fixed8x13_Character_031, + Fixed8x13_Character_032,Fixed8x13_Character_033,Fixed8x13_Character_034,Fixed8x13_Character_035,Fixed8x13_Character_036,Fixed8x13_Character_037,Fixed8x13_Character_038,Fixed8x13_Character_039,Fixed8x13_Character_040,Fixed8x13_Character_041,Fixed8x13_Character_042,Fixed8x13_Character_043,Fixed8x13_Character_044,Fixed8x13_Character_045,Fixed8x13_Character_046,Fixed8x13_Character_047, + Fixed8x13_Character_048,Fixed8x13_Character_049,Fixed8x13_Character_050,Fixed8x13_Character_051,Fixed8x13_Character_052,Fixed8x13_Character_053,Fixed8x13_Character_054,Fixed8x13_Character_055,Fixed8x13_Character_056,Fixed8x13_Character_057,Fixed8x13_Character_058,Fixed8x13_Character_059,Fixed8x13_Character_060,Fixed8x13_Character_061,Fixed8x13_Character_062,Fixed8x13_Character_063, + Fixed8x13_Character_064,Fixed8x13_Character_065,Fixed8x13_Character_066,Fixed8x13_Character_067,Fixed8x13_Character_068,Fixed8x13_Character_069,Fixed8x13_Character_070,Fixed8x13_Character_071,Fixed8x13_Character_072,Fixed8x13_Character_073,Fixed8x13_Character_074,Fixed8x13_Character_075,Fixed8x13_Character_076,Fixed8x13_Character_077,Fixed8x13_Character_078,Fixed8x13_Character_079, + Fixed8x13_Character_080,Fixed8x13_Character_081,Fixed8x13_Character_082,Fixed8x13_Character_083,Fixed8x13_Character_084,Fixed8x13_Character_085,Fixed8x13_Character_086,Fixed8x13_Character_087,Fixed8x13_Character_088,Fixed8x13_Character_089,Fixed8x13_Character_090,Fixed8x13_Character_091,Fixed8x13_Character_092,Fixed8x13_Character_093,Fixed8x13_Character_094,Fixed8x13_Character_095, + Fixed8x13_Character_096,Fixed8x13_Character_097,Fixed8x13_Character_098,Fixed8x13_Character_099,Fixed8x13_Character_100,Fixed8x13_Character_101,Fixed8x13_Character_102,Fixed8x13_Character_103,Fixed8x13_Character_104,Fixed8x13_Character_105,Fixed8x13_Character_106,Fixed8x13_Character_107,Fixed8x13_Character_108,Fixed8x13_Character_109,Fixed8x13_Character_110,Fixed8x13_Character_111, + Fixed8x13_Character_112,Fixed8x13_Character_113,Fixed8x13_Character_114,Fixed8x13_Character_115,Fixed8x13_Character_116,Fixed8x13_Character_117,Fixed8x13_Character_118,Fixed8x13_Character_119,Fixed8x13_Character_120,Fixed8x13_Character_121,Fixed8x13_Character_122,Fixed8x13_Character_123,Fixed8x13_Character_124,Fixed8x13_Character_125,Fixed8x13_Character_126,Fixed8x13_Character_032, + Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032, + Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032,Fixed8x13_Character_032, + Fixed8x13_Character_160,Fixed8x13_Character_161,Fixed8x13_Character_162,Fixed8x13_Character_163,Fixed8x13_Character_164,Fixed8x13_Character_165,Fixed8x13_Character_166,Fixed8x13_Character_167,Fixed8x13_Character_168,Fixed8x13_Character_169,Fixed8x13_Character_170,Fixed8x13_Character_171,Fixed8x13_Character_172,Fixed8x13_Character_173,Fixed8x13_Character_174,Fixed8x13_Character_175, + Fixed8x13_Character_176,Fixed8x13_Character_177,Fixed8x13_Character_178,Fixed8x13_Character_179,Fixed8x13_Character_180,Fixed8x13_Character_181,Fixed8x13_Character_182,Fixed8x13_Character_183,Fixed8x13_Character_184,Fixed8x13_Character_185,Fixed8x13_Character_186,Fixed8x13_Character_187,Fixed8x13_Character_188,Fixed8x13_Character_189,Fixed8x13_Character_190,Fixed8x13_Character_191, + Fixed8x13_Character_192,Fixed8x13_Character_193,Fixed8x13_Character_194,Fixed8x13_Character_195,Fixed8x13_Character_196,Fixed8x13_Character_197,Fixed8x13_Character_198,Fixed8x13_Character_199,Fixed8x13_Character_200,Fixed8x13_Character_201,Fixed8x13_Character_202,Fixed8x13_Character_203,Fixed8x13_Character_204,Fixed8x13_Character_205,Fixed8x13_Character_206,Fixed8x13_Character_207, + Fixed8x13_Character_208,Fixed8x13_Character_209,Fixed8x13_Character_210,Fixed8x13_Character_211,Fixed8x13_Character_212,Fixed8x13_Character_213,Fixed8x13_Character_214,Fixed8x13_Character_215,Fixed8x13_Character_216,Fixed8x13_Character_217,Fixed8x13_Character_218,Fixed8x13_Character_219,Fixed8x13_Character_220,Fixed8x13_Character_221,Fixed8x13_Character_222,Fixed8x13_Character_223, + Fixed8x13_Character_224,Fixed8x13_Character_225,Fixed8x13_Character_226,Fixed8x13_Character_227,Fixed8x13_Character_228,Fixed8x13_Character_229,Fixed8x13_Character_230,Fixed8x13_Character_231,Fixed8x13_Character_232,Fixed8x13_Character_233,Fixed8x13_Character_234,Fixed8x13_Character_235,Fixed8x13_Character_236,Fixed8x13_Character_237,Fixed8x13_Character_238,Fixed8x13_Character_239, + Fixed8x13_Character_240,Fixed8x13_Character_241,Fixed8x13_Character_242,Fixed8x13_Character_243,Fixed8x13_Character_244,Fixed8x13_Character_245,Fixed8x13_Character_246,Fixed8x13_Character_247,Fixed8x13_Character_248,Fixed8x13_Character_249,Fixed8x13_Character_250,Fixed8x13_Character_251,Fixed8x13_Character_252,Fixed8x13_Character_253,Fixed8x13_Character_254,Fixed8x13_Character_255,NULL}; + +/* The font structure: */ +const SFG_Font fgFontFixed8x13 = { "-misc-fixed-medium-r-normal--13-120-75-75-C-80-iso8859-1", 256, 14, Fixed8x13_Character_Map, 0, 3 }; + +static const GLubyte Fixed9x15_Character_000[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_001[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 28, 0, 62, 0,127, 0,255,128,127, 0, 62, 0, 28, 0, 8, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_002[] = { 9, 0, 0,170,128, 85, 0,170,128, 85, 0,170,128, 85, 0,170,128, 85, 0,170,128, 85, 0,170,128, 85, 0,170,128, 85, 0,170,128}; +static const GLubyte Fixed9x15_Character_003[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4, 0, 4, 0, 4, 0, 31, 0, 0, 0, 72, 0, 72, 0,120, 0, 72, 0, 72, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_004[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 8, 0, 8, 0, 14, 0, 72, 0, 79, 0, 64, 0,112, 0, 64, 0,120, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_005[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 9, 0, 14, 0, 9, 0, 14, 0, 0, 0, 56, 0, 64, 0, 64, 0, 64, 0, 56, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_006[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 8, 0, 14, 0, 8, 0, 15, 0, 0, 0,120, 0, 64, 0, 64, 0, 64, 0, 64, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_007[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 18, 0, 18, 0, 12, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_008[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127, 0, 0, 0, 8, 0, 8, 0, 8, 0,127, 0, 8, 0, 8, 0, 8, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_009[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 8, 0, 8, 0, 8, 0, 8, 0, 0, 0, 68, 0, 76, 0, 84, 0,100, 0, 68, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_010[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4, 0, 4, 0, 4, 0, 31, 0, 0, 0, 16, 0, 40, 0, 40, 0, 68, 0, 68, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_011[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,248, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0}; +static const GLubyte Fixed9x15_Character_012[] = { 9, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0,248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_013[] = { 9, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 15,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_014[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15,128, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0}; +static const GLubyte Fixed9x15_Character_015[] = { 9, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0,255,128, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0}; +static const GLubyte Fixed9x15_Character_016[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,128}; +static const GLubyte Fixed9x15_Character_017[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,128, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_018[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_019[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0,255,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_020[] = { 9, 0, 0,255,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_021[] = { 9, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 15,128, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0}; +static const GLubyte Fixed9x15_Character_022[] = { 9, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0,248, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0}; +static const GLubyte Fixed9x15_Character_023[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,128, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0}; +static const GLubyte Fixed9x15_Character_024[] = { 9, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0,255,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_025[] = { 9, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0}; +static const GLubyte Fixed9x15_Character_026[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127, 0, 0, 0, 3, 0, 28, 0, 96, 0, 28, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_027[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127, 0, 0, 0, 96, 0, 28, 0, 3, 0, 28, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_028[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 34, 0, 34, 0, 34, 0, 34, 0, 34, 0, 34, 0,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_029[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 16, 0,127, 0, 8, 0,127, 0, 4, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_030[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 46, 0, 81, 0, 48, 0, 16, 0, 16, 0,124, 0, 16, 0, 16, 0, 17, 0, 14, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_031[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_032[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_033[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 8, 0, 0, 0, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_034[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_035[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 36, 0,126, 0, 36, 0, 36, 0,126, 0, 36, 0, 36, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_036[] = { 9, 0, 0, 0, 0, 0, 0, 8, 0, 62, 0, 73, 0, 9, 0, 9, 0, 10, 0, 28, 0, 40, 0, 72, 0, 73, 0, 62, 0, 8, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_037[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 66, 0, 37, 0, 37, 0, 18, 0, 8, 0, 8, 0, 36, 0, 82, 0, 82, 0, 33, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_038[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0, 74, 0, 68, 0, 74, 0, 49, 0, 48, 0, 72, 0, 72, 0, 72, 0, 48, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_039[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 8, 0, 4, 0, 6, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_040[] = { 9, 0, 0, 0, 0, 0, 0, 4, 0, 8, 0, 8, 0, 16, 0, 16, 0, 16, 0, 16, 0, 16, 0, 16, 0, 8, 0, 8, 0, 4, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_041[] = { 9, 0, 0, 0, 0, 0, 0, 16, 0, 8, 0, 8, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 8, 0, 8, 0, 16, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_042[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 73, 0, 42, 0, 28, 0, 42, 0, 73, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_043[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 8, 0, 8, 0,127, 0, 8, 0, 8, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_044[] = { 9, 0, 0, 8, 0, 4, 0, 4, 0, 12, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_045[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_046[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_047[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 32, 0, 32, 0, 16, 0, 8, 0, 8, 0, 4, 0, 2, 0, 2, 0, 1, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_048[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 34, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 34, 0, 28, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_049[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0,127, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 72, 0, 40, 0, 24, 0, 8, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_050[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0,127, 0, 64, 0, 32, 0, 16, 0, 8, 0, 4, 0, 2, 0, 65, 0, 65, 0, 62, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_051[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 1, 0, 1, 0, 1, 0, 14, 0, 4, 0, 2, 0, 1, 0,127, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_052[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 2, 0,127, 0, 66, 0, 34, 0, 18, 0, 10, 0, 6, 0, 2, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_053[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 1, 0, 1, 0, 1, 0, 97, 0, 94, 0, 64, 0, 64, 0,127, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_054[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 97, 0, 94, 0, 64, 0, 64, 0, 32, 0, 30, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_055[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 32, 0, 16, 0, 16, 0, 8, 0, 4, 0, 2, 0, 1, 0, 1, 0,127, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_056[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 34, 0, 65, 0, 65, 0, 34, 0, 28, 0, 34, 0, 65, 0, 34, 0, 28, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_057[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 60, 0, 2, 0, 1, 0, 1, 0, 61, 0, 67, 0, 65, 0, 65, 0, 65, 0, 62, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_058[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 12, 0, 0, 0, 0, 0, 0, 0, 12, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_059[] = { 9, 0, 0, 8, 0, 4, 0, 4, 0, 12, 0, 12, 0, 0, 0, 0, 0, 0, 0, 12, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_060[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 4, 0, 8, 0, 16, 0, 32, 0, 32, 0, 16, 0, 8, 0, 4, 0, 2, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_061[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127, 0, 0, 0, 0, 0,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_062[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 16, 0, 8, 0, 4, 0, 2, 0, 2, 0, 4, 0, 8, 0, 16, 0, 32, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_063[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 8, 0, 4, 0, 2, 0, 1, 0, 65, 0, 65, 0, 62, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_064[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 64, 0, 64, 0, 77, 0, 83, 0, 81, 0, 79, 0, 65, 0, 65, 0, 62, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_065[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0,127, 0, 65, 0, 65, 0, 65, 0, 34, 0, 20, 0, 8, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_066[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0,126, 0, 33, 0, 33, 0, 33, 0, 33, 0,126, 0, 33, 0, 33, 0, 33, 0,126, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_067[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 64, 0, 64, 0, 64, 0, 64, 0, 64, 0, 64, 0, 65, 0, 62, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_068[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0,126, 0, 33, 0, 33, 0, 33, 0, 33, 0, 33, 0, 33, 0, 33, 0, 33, 0,126, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_069[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0,127, 0, 32, 0, 32, 0, 32, 0, 32, 0, 60, 0, 32, 0, 32, 0, 32, 0,127, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_070[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 60, 0, 32, 0, 32, 0, 32, 0,127, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_071[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 71, 0, 64, 0, 64, 0, 64, 0, 65, 0, 62, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_072[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0,127, 0, 65, 0, 65, 0, 65, 0, 65, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_073[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 62, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_074[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 60, 0, 66, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 15,128, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_075[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 66, 0, 68, 0, 72, 0, 80, 0,112, 0, 72, 0, 68, 0, 66, 0, 65, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_076[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0,127, 0, 64, 0, 64, 0, 64, 0, 64, 0, 64, 0, 64, 0, 64, 0, 64, 0, 64, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_077[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0, 73, 0, 73, 0, 85, 0, 85, 0, 99, 0, 65, 0, 65, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_078[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0, 67, 0, 69, 0, 73, 0, 81, 0, 97, 0, 65, 0, 65, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_079[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 62, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_080[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 64, 0, 64, 0, 64, 0, 64, 0,126, 0, 65, 0, 65, 0, 65, 0,126, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_081[] = { 9, 0, 0, 0, 0, 3, 0, 4, 0, 62, 0, 73, 0, 81, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 62, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_082[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 66, 0, 68, 0, 72, 0,126, 0, 65, 0, 65, 0, 65, 0,126, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_083[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 1, 0, 6, 0, 56, 0, 64, 0, 65, 0, 65, 0, 62, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_084[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0,127, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_085[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_086[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 20, 0, 20, 0, 20, 0, 34, 0, 34, 0, 34, 0, 65, 0, 65, 0, 65, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_087[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 34, 0, 85, 0, 73, 0, 73, 0, 73, 0, 73, 0, 65, 0, 65, 0, 65, 0, 65, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_088[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 34, 0, 20, 0, 8, 0, 8, 0, 20, 0, 34, 0, 65, 0, 65, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_089[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 20, 0, 34, 0, 65, 0, 65, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_090[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0,127, 0, 64, 0, 64, 0, 32, 0, 16, 0, 8, 0, 4, 0, 2, 0, 1, 0,127, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_091[] = { 9, 0, 0, 0, 0, 0, 0, 30, 0, 16, 0, 16, 0, 16, 0, 16, 0, 16, 0, 16, 0, 16, 0, 16, 0, 16, 0, 16, 0, 30, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_092[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 2, 0, 4, 0, 8, 0, 8, 0, 16, 0, 32, 0, 32, 0, 64, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_093[] = { 9, 0, 0, 0, 0, 0, 0, 60, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 60, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_094[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 34, 0, 20, 0, 8, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_095[] = { 9, 0, 0, 0, 0, 0, 0,255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_096[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 8, 0, 16, 0, 48, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_097[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 67, 0, 65, 0, 63, 0, 1, 0, 1, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_098[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 94, 0, 97, 0, 65, 0, 65, 0, 65, 0, 97, 0, 94, 0, 64, 0, 64, 0, 64, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_099[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 64, 0, 64, 0, 64, 0, 65, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_100[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 67, 0, 65, 0, 65, 0, 65, 0, 67, 0, 61, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_101[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 64, 0, 64, 0,127, 0, 65, 0, 65, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_102[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 16, 0, 16, 0, 16, 0,124, 0, 16, 0, 16, 0, 17, 0, 17, 0, 14, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_103[] = { 9, 0, 0, 62, 0, 65, 0, 65, 0, 62, 0, 64, 0, 60, 0, 66, 0, 66, 0, 66, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_104[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 97, 0, 94, 0, 64, 0, 64, 0, 64, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_105[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 56, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_106[] = { 9, 0, 0, 60, 0, 66, 0, 66, 0, 66, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 14, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_107[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 70, 0, 88, 0, 96, 0, 88, 0, 70, 0, 65, 0, 64, 0, 64, 0, 64, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_108[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 56, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_109[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 73, 0, 73, 0, 73, 0, 73, 0, 73, 0,118, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_110[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 97, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_111[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_112[] = { 9, 0, 0, 64, 0, 64, 0, 64, 0, 94, 0, 97, 0, 65, 0, 65, 0, 65, 0, 97, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_113[] = { 9, 0, 0, 1, 0, 1, 0, 1, 0, 61, 0, 67, 0, 65, 0, 65, 0, 65, 0, 67, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_114[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 32, 0, 32, 0, 32, 0, 33, 0, 49, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_115[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 1, 0, 62, 0, 64, 0, 65, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_116[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 17, 0, 16, 0, 16, 0, 16, 0, 16, 0,126, 0, 16, 0, 16, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_117[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 66, 0, 66, 0, 66, 0, 66, 0, 66, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_118[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 20, 0, 20, 0, 34, 0, 34, 0, 65, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_119[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 34, 0, 85, 0, 73, 0, 73, 0, 73, 0, 65, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_120[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 34, 0, 20, 0, 8, 0, 20, 0, 34, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_121[] = { 9, 0, 0, 60, 0, 66, 0, 2, 0, 58, 0, 70, 0, 66, 0, 66, 0, 66, 0, 66, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_122[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0,127, 0, 32, 0, 16, 0, 8, 0, 4, 0, 2, 0,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_123[] = { 9, 0, 0, 0, 0, 0, 0, 7, 0, 8, 0, 8, 0, 8, 0, 4, 0, 24, 0, 24, 0, 4, 0, 8, 0, 8, 0, 8, 0, 7, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_124[] = { 9, 0, 0, 0, 0, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_125[] = { 9, 0, 0, 0, 0, 0, 0,112, 0, 8, 0, 8, 0, 8, 0, 16, 0, 12, 0, 12, 0, 16, 0, 8, 0, 8, 0, 8, 0,112, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_126[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70, 0, 73, 0, 49, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_127[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_128[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_129[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_130[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_131[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_132[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_133[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_134[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_135[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_136[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_137[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_138[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_139[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_140[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_141[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_142[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_143[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_144[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_145[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_146[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_147[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_148[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_149[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_150[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_151[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_152[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_153[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_154[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_155[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_156[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_157[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_158[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_159[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0, 65, 0, 64, 0, 1, 0,109, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_160[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_161[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 0, 0, 0, 0, 8, 0, 8, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_162[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 60, 0, 82, 0, 80, 0, 72, 0, 74, 0, 60, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_163[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 46, 0, 81, 0, 48, 0, 16, 0, 16, 0,124, 0, 16, 0, 16, 0, 17, 0, 14, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_164[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 62, 0, 34, 0, 34, 0, 62, 0, 65, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_165[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 8, 0, 8, 0, 62, 0, 8, 0, 62, 0, 20, 0, 34, 0, 65, 0, 65, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_166[] = { 9, 0, 0, 0, 0, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_167[] = { 9, 0, 0, 0, 0, 0, 0, 24, 0, 36, 0, 4, 0, 24, 0, 36, 0, 36, 0, 36, 0, 24, 0, 32, 0, 36, 0, 24, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_168[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 0, 34, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_169[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 0, 66, 0,153, 0,165, 0,161, 0,165, 0,153, 0, 66, 0, 60, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_170[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,124, 0, 0, 0, 60, 0, 72, 0, 56, 0, 72, 0, 48, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_171[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 18, 0, 36, 0, 72, 0, 72, 0, 36, 0, 18, 0, 9, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_172[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 2, 0,126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_173[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_174[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 0, 66, 0,165, 0,169, 0,185, 0,165, 0,185, 0, 66, 0, 60, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_175[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,126, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_176[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 18, 0, 18, 0, 12, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_177[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127, 0, 0, 0, 8, 0, 8, 0, 8, 0,127, 0, 8, 0, 8, 0, 8, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_178[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,120, 0, 64, 0, 48, 0, 8, 0, 72, 0, 48, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_179[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 72, 0, 8, 0, 16, 0, 72, 0, 48, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_180[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 8, 0, 4, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_181[] = { 9, 0, 0, 0, 0, 64, 0, 64, 0, 93, 0, 99, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_182[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 61, 0, 69, 0, 69, 0, 69, 0, 63, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_183[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_184[] = { 9, 0, 0, 24, 0, 36, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_185[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,112, 0, 32, 0, 32, 0, 32, 0, 96, 0, 32, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_186[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,124, 0, 0, 0, 56, 0, 68, 0, 68, 0, 56, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_187[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 0, 36, 0, 18, 0, 9, 0, 9, 0, 18, 0, 36, 0, 72, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_188[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 13, 0, 9, 0, 5, 0,115, 0, 33, 0, 32, 0, 32, 0, 96, 0, 32, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_189[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 8, 0, 6, 0, 1, 0,121, 0, 38, 0, 32, 0, 32, 0, 96, 0, 32, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_190[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 13, 0, 9, 0, 5, 0, 51, 0, 73, 0, 8, 0, 16, 0, 72, 0, 48, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_191[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 64, 0, 32, 0, 16, 0, 8, 0, 8, 0, 0, 0, 8, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_192[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0,127, 0, 65, 0, 65, 0, 34, 0, 28, 0, 0, 0, 8, 0, 16, 0, 32, 0}; +static const GLubyte Fixed9x15_Character_193[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0,127, 0, 65, 0, 65, 0, 34, 0, 28, 0, 0, 0, 8, 0, 4, 0, 2, 0}; +static const GLubyte Fixed9x15_Character_194[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0,127, 0, 65, 0, 65, 0, 34, 0, 28, 0, 0, 0, 34, 0, 20, 0, 8, 0}; +static const GLubyte Fixed9x15_Character_195[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0,127, 0, 65, 0, 65, 0, 34, 0, 28, 0, 0, 0, 78, 0, 49, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_196[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0,127, 0, 65, 0, 65, 0, 34, 0, 28, 0, 0, 0, 34, 0, 34, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_197[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0,127, 0, 65, 0, 65, 0, 34, 0, 20, 0, 28, 0, 34, 0, 28, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_198[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 79, 0, 72, 0, 72, 0, 72, 0,126, 0, 72, 0, 72, 0, 72, 0, 72, 0, 55, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_199[] = { 9, 0, 0, 24, 0, 36, 0, 12, 0, 62, 0, 65, 0, 64, 0, 64, 0, 64, 0, 64, 0, 64, 0, 64, 0, 65, 0, 62, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_200[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0,127, 0, 32, 0, 32, 0, 32, 0, 60, 0, 32, 0, 32, 0,127, 0, 0, 0, 8, 0, 16, 0, 32, 0}; +static const GLubyte Fixed9x15_Character_201[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0,127, 0, 32, 0, 32, 0, 32, 0, 60, 0, 32, 0, 32, 0,127, 0, 0, 0, 8, 0, 4, 0, 2, 0}; +static const GLubyte Fixed9x15_Character_202[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0,127, 0, 32, 0, 32, 0, 32, 0, 60, 0, 32, 0, 32, 0,127, 0, 0, 0, 34, 0, 20, 0, 8, 0}; +static const GLubyte Fixed9x15_Character_203[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0,127, 0, 32, 0, 32, 0, 32, 0, 60, 0, 32, 0, 32, 0,127, 0, 0, 0, 34, 0, 34, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_204[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 62, 0, 0, 0, 8, 0, 16, 0, 32, 0}; +static const GLubyte Fixed9x15_Character_205[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 62, 0, 0, 0, 8, 0, 4, 0, 2, 0}; +static const GLubyte Fixed9x15_Character_206[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 62, 0, 0, 0, 34, 0, 20, 0, 8, 0}; +static const GLubyte Fixed9x15_Character_207[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 62, 0, 0, 0, 34, 0, 34, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_208[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0,124, 0, 33, 0, 33, 0, 33, 0, 33, 0,225, 0, 33, 0, 33, 0, 33, 0,124, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_209[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 67, 0, 69, 0, 73, 0, 73, 0, 81, 0, 97, 0, 65, 0, 0, 0, 78, 0, 49, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_210[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 62, 0, 0, 0, 8, 0, 16, 0, 32, 0}; +static const GLubyte Fixed9x15_Character_211[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 62, 0, 0, 0, 8, 0, 4, 0, 2, 0}; +static const GLubyte Fixed9x15_Character_212[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 62, 0, 0, 0, 34, 0, 20, 0, 8, 0}; +static const GLubyte Fixed9x15_Character_213[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 62, 0, 0, 0, 78, 0, 49, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_214[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 62, 0, 0, 0, 34, 0, 34, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_215[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 34, 0, 20, 0, 8, 0, 20, 0, 34, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_216[] = { 9, 0, 0, 0, 0, 0, 0, 64, 0, 62, 0, 97, 0, 81, 0, 81, 0, 73, 0, 73, 0, 69, 0, 69, 0, 67, 0, 62, 0, 1, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_217[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 0, 0, 8, 0, 16, 0, 32, 0}; +static const GLubyte Fixed9x15_Character_218[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 0, 0, 8, 0, 4, 0, 2, 0}; +static const GLubyte Fixed9x15_Character_219[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 0, 0, 34, 0, 20, 0, 8, 0}; +static const GLubyte Fixed9x15_Character_220[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 0, 0, 34, 0, 34, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_221[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 20, 0, 34, 0, 65, 0, 65, 0, 0, 0, 8, 0, 4, 0, 2, 0}; +static const GLubyte Fixed9x15_Character_222[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 64, 0, 64, 0,126, 0, 65, 0, 65, 0, 65, 0,126, 0, 64, 0, 64, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_223[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 34, 0, 34, 0, 34, 0, 36, 0,104, 0, 36, 0, 34, 0, 34, 0, 28, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_224[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 67, 0, 65, 0, 63, 0, 1, 0, 1, 0, 62, 0, 0, 0, 4, 0, 8, 0, 16, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_225[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 67, 0, 65, 0, 63, 0, 1, 0, 1, 0, 62, 0, 0, 0, 8, 0, 4, 0, 2, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_226[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 67, 0, 65, 0, 63, 0, 1, 0, 1, 0, 62, 0, 0, 0, 34, 0, 20, 0, 8, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_227[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 67, 0, 65, 0, 63, 0, 1, 0, 1, 0, 62, 0, 0, 0, 38, 0, 25, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_228[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 67, 0, 65, 0, 63, 0, 1, 0, 1, 0, 62, 0, 0, 0, 34, 0, 34, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_229[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 67, 0, 65, 0, 63, 0, 1, 0, 1, 0, 62, 0, 0, 0, 12, 0, 18, 0, 12, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_230[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 55, 0, 73, 0, 72, 0, 62, 0, 9, 0, 73, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_231[] = { 9, 0, 0, 24, 0, 36, 0, 12, 0, 62, 0, 65, 0, 64, 0, 64, 0, 64, 0, 65, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_232[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 64, 0, 64, 0,127, 0, 65, 0, 65, 0, 62, 0, 0, 0, 8, 0, 16, 0, 32, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_233[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 64, 0, 64, 0,127, 0, 65, 0, 65, 0, 62, 0, 0, 0, 8, 0, 4, 0, 2, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_234[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 64, 0, 64, 0,127, 0, 65, 0, 65, 0, 62, 0, 0, 0, 34, 0, 20, 0, 8, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_235[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 64, 0, 64, 0,127, 0, 65, 0, 65, 0, 62, 0, 0, 0, 34, 0, 34, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_236[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 56, 0, 0, 0, 8, 0, 16, 0, 32, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_237[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 56, 0, 0, 0, 16, 0, 8, 0, 4, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_238[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 56, 0, 0, 0, 68, 0, 40, 0, 16, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_239[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 56, 0, 0, 0, 36, 0, 36, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_240[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 62, 0, 4, 0, 40, 0, 24, 0, 36, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_241[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 97, 0, 94, 0, 0, 0, 78, 0, 49, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_242[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 62, 0, 0, 0, 8, 0, 16, 0, 32, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_243[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 62, 0, 0, 0, 8, 0, 4, 0, 2, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_244[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 62, 0, 0, 0, 34, 0, 20, 0, 8, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_245[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 62, 0, 0, 0, 78, 0, 49, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_246[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 62, 0, 0, 0, 34, 0, 34, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_247[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 28, 0, 8, 0, 0, 0,127, 0, 0, 0, 8, 0, 28, 0, 8, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_248[] = { 9, 0, 0, 0, 0, 0, 0, 64, 0, 62, 0, 81, 0, 81, 0, 73, 0, 69, 0, 69, 0, 62, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_249[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 66, 0, 66, 0, 66, 0, 66, 0, 66, 0, 66, 0, 0, 0, 8, 0, 16, 0, 32, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_250[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 66, 0, 66, 0, 66, 0, 66, 0, 66, 0, 66, 0, 0, 0, 8, 0, 4, 0, 2, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_251[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 66, 0, 66, 0, 66, 0, 66, 0, 66, 0, 66, 0, 0, 0, 34, 0, 20, 0, 8, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_252[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 66, 0, 66, 0, 66, 0, 66, 0, 66, 0, 66, 0, 0, 0, 36, 0, 36, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_253[] = { 9, 0, 0, 60, 0, 66, 0, 2, 0, 58, 0, 70, 0, 66, 0, 66, 0, 66, 0, 66, 0, 66, 0, 0, 0, 16, 0, 8, 0, 4, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_254[] = { 9, 0, 0, 64, 0, 64, 0, 64, 0, 94, 0, 97, 0, 65, 0, 65, 0, 97, 0, 94, 0, 64, 0, 64, 0, 64, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Fixed9x15_Character_255[] = { 9, 0, 0, 60, 0, 66, 0, 2, 0, 58, 0, 70, 0, 66, 0, 66, 0, 66, 0, 66, 0, 66, 0, 0, 0, 36, 0, 36, 0, 0, 0, 0, 0}; + +/* The font characters mapping: */ +static const GLubyte* Fixed9x15_Character_Map[] = {Fixed9x15_Character_000,Fixed9x15_Character_001,Fixed9x15_Character_002,Fixed9x15_Character_003,Fixed9x15_Character_004,Fixed9x15_Character_005,Fixed9x15_Character_006,Fixed9x15_Character_007,Fixed9x15_Character_008,Fixed9x15_Character_009,Fixed9x15_Character_010,Fixed9x15_Character_011,Fixed9x15_Character_012,Fixed9x15_Character_013,Fixed9x15_Character_014,Fixed9x15_Character_015, + Fixed9x15_Character_016,Fixed9x15_Character_017,Fixed9x15_Character_018,Fixed9x15_Character_019,Fixed9x15_Character_020,Fixed9x15_Character_021,Fixed9x15_Character_022,Fixed9x15_Character_023,Fixed9x15_Character_024,Fixed9x15_Character_025,Fixed9x15_Character_026,Fixed9x15_Character_027,Fixed9x15_Character_028,Fixed9x15_Character_029,Fixed9x15_Character_030,Fixed9x15_Character_031, + Fixed9x15_Character_032,Fixed9x15_Character_033,Fixed9x15_Character_034,Fixed9x15_Character_035,Fixed9x15_Character_036,Fixed9x15_Character_037,Fixed9x15_Character_038,Fixed9x15_Character_039,Fixed9x15_Character_040,Fixed9x15_Character_041,Fixed9x15_Character_042,Fixed9x15_Character_043,Fixed9x15_Character_044,Fixed9x15_Character_045,Fixed9x15_Character_046,Fixed9x15_Character_047, + Fixed9x15_Character_048,Fixed9x15_Character_049,Fixed9x15_Character_050,Fixed9x15_Character_051,Fixed9x15_Character_052,Fixed9x15_Character_053,Fixed9x15_Character_054,Fixed9x15_Character_055,Fixed9x15_Character_056,Fixed9x15_Character_057,Fixed9x15_Character_058,Fixed9x15_Character_059,Fixed9x15_Character_060,Fixed9x15_Character_061,Fixed9x15_Character_062,Fixed9x15_Character_063, + Fixed9x15_Character_064,Fixed9x15_Character_065,Fixed9x15_Character_066,Fixed9x15_Character_067,Fixed9x15_Character_068,Fixed9x15_Character_069,Fixed9x15_Character_070,Fixed9x15_Character_071,Fixed9x15_Character_072,Fixed9x15_Character_073,Fixed9x15_Character_074,Fixed9x15_Character_075,Fixed9x15_Character_076,Fixed9x15_Character_077,Fixed9x15_Character_078,Fixed9x15_Character_079, + Fixed9x15_Character_080,Fixed9x15_Character_081,Fixed9x15_Character_082,Fixed9x15_Character_083,Fixed9x15_Character_084,Fixed9x15_Character_085,Fixed9x15_Character_086,Fixed9x15_Character_087,Fixed9x15_Character_088,Fixed9x15_Character_089,Fixed9x15_Character_090,Fixed9x15_Character_091,Fixed9x15_Character_092,Fixed9x15_Character_093,Fixed9x15_Character_094,Fixed9x15_Character_095, + Fixed9x15_Character_096,Fixed9x15_Character_097,Fixed9x15_Character_098,Fixed9x15_Character_099,Fixed9x15_Character_100,Fixed9x15_Character_101,Fixed9x15_Character_102,Fixed9x15_Character_103,Fixed9x15_Character_104,Fixed9x15_Character_105,Fixed9x15_Character_106,Fixed9x15_Character_107,Fixed9x15_Character_108,Fixed9x15_Character_109,Fixed9x15_Character_110,Fixed9x15_Character_111, + Fixed9x15_Character_112,Fixed9x15_Character_113,Fixed9x15_Character_114,Fixed9x15_Character_115,Fixed9x15_Character_116,Fixed9x15_Character_117,Fixed9x15_Character_118,Fixed9x15_Character_119,Fixed9x15_Character_120,Fixed9x15_Character_121,Fixed9x15_Character_122,Fixed9x15_Character_123,Fixed9x15_Character_124,Fixed9x15_Character_125,Fixed9x15_Character_126,Fixed9x15_Character_032, + Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032, + Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032,Fixed9x15_Character_032, + Fixed9x15_Character_160,Fixed9x15_Character_161,Fixed9x15_Character_162,Fixed9x15_Character_163,Fixed9x15_Character_164,Fixed9x15_Character_165,Fixed9x15_Character_166,Fixed9x15_Character_167,Fixed9x15_Character_168,Fixed9x15_Character_169,Fixed9x15_Character_170,Fixed9x15_Character_171,Fixed9x15_Character_172,Fixed9x15_Character_173,Fixed9x15_Character_174,Fixed9x15_Character_175, + Fixed9x15_Character_176,Fixed9x15_Character_177,Fixed9x15_Character_178,Fixed9x15_Character_179,Fixed9x15_Character_180,Fixed9x15_Character_181,Fixed9x15_Character_182,Fixed9x15_Character_183,Fixed9x15_Character_184,Fixed9x15_Character_185,Fixed9x15_Character_186,Fixed9x15_Character_187,Fixed9x15_Character_188,Fixed9x15_Character_189,Fixed9x15_Character_190,Fixed9x15_Character_191, + Fixed9x15_Character_192,Fixed9x15_Character_193,Fixed9x15_Character_194,Fixed9x15_Character_195,Fixed9x15_Character_196,Fixed9x15_Character_197,Fixed9x15_Character_198,Fixed9x15_Character_199,Fixed9x15_Character_200,Fixed9x15_Character_201,Fixed9x15_Character_202,Fixed9x15_Character_203,Fixed9x15_Character_204,Fixed9x15_Character_205,Fixed9x15_Character_206,Fixed9x15_Character_207, + Fixed9x15_Character_208,Fixed9x15_Character_209,Fixed9x15_Character_210,Fixed9x15_Character_211,Fixed9x15_Character_212,Fixed9x15_Character_213,Fixed9x15_Character_214,Fixed9x15_Character_215,Fixed9x15_Character_216,Fixed9x15_Character_217,Fixed9x15_Character_218,Fixed9x15_Character_219,Fixed9x15_Character_220,Fixed9x15_Character_221,Fixed9x15_Character_222,Fixed9x15_Character_223, + Fixed9x15_Character_224,Fixed9x15_Character_225,Fixed9x15_Character_226,Fixed9x15_Character_227,Fixed9x15_Character_228,Fixed9x15_Character_229,Fixed9x15_Character_230,Fixed9x15_Character_231,Fixed9x15_Character_232,Fixed9x15_Character_233,Fixed9x15_Character_234,Fixed9x15_Character_235,Fixed9x15_Character_236,Fixed9x15_Character_237,Fixed9x15_Character_238,Fixed9x15_Character_239, + Fixed9x15_Character_240,Fixed9x15_Character_241,Fixed9x15_Character_242,Fixed9x15_Character_243,Fixed9x15_Character_244,Fixed9x15_Character_245,Fixed9x15_Character_246,Fixed9x15_Character_247,Fixed9x15_Character_248,Fixed9x15_Character_249,Fixed9x15_Character_250,Fixed9x15_Character_251,Fixed9x15_Character_252,Fixed9x15_Character_253,Fixed9x15_Character_254,Fixed9x15_Character_255,NULL}; + +/* The font structure: */ +const SFG_Font fgFontFixed9x15 = { "-misc-fixed-medium-r-normal--15-140-75-75-C-90-iso8859-1", 256, 16, Fixed9x15_Character_Map, 0, 4 }; + +static const GLubyte Helvetica10_Character_000[] = { 8, 0, 0, 0, 84, 0, 68, 0, 68, 0, 84, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_001[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_002[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_003[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_004[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_005[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_006[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_007[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_008[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_009[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_010[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_011[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_012[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_013[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_014[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_015[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_016[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_017[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_018[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_019[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_020[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_021[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_022[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_023[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_024[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_025[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_026[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_027[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_028[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_029[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_030[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_031[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_032[] = { 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_033[] = { 3, 0, 0, 0, 64, 0, 64, 64, 64, 64, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica10_Character_034[] = { 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 80, 0, 0, 0}; +static const GLubyte Helvetica10_Character_035[] = { 6, 0, 0, 0, 80, 80,248, 40,124, 40, 40, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_036[] = { 6, 0, 0, 32,112,168, 40,112,160,168,112, 32, 0, 0, 0}; +static const GLubyte Helvetica10_Character_037[] = { 9, 0, 0, 0, 0, 0, 0, 38, 0, 41, 0, 22, 0, 16, 0, 8, 0,104, 0,148, 0,100, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_038[] = { 8, 0, 0, 0, 50, 76, 76, 82, 48, 40, 40, 16, 0, 0, 0}; +static const GLubyte Helvetica10_Character_039[] = { 3, 0, 0, 0, 0, 0, 0, 0, 0, 64, 32, 32, 0, 0, 0}; +static const GLubyte Helvetica10_Character_040[] = { 4, 0, 32, 64, 64,128,128,128,128, 64, 64, 32, 0, 0, 0}; +static const GLubyte Helvetica10_Character_041[] = { 4, 0, 64, 32, 32, 16, 16, 16, 16, 32, 32, 64, 0, 0, 0}; +static const GLubyte Helvetica10_Character_042[] = { 4, 0, 0, 0, 0, 0, 0, 0, 0,160, 64,160, 0, 0, 0}; +static const GLubyte Helvetica10_Character_043[] = { 6, 0, 0, 0, 0, 32, 32,248, 32, 32, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_044[] = { 3, 0,128, 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_045[] = { 7, 0, 0, 0, 0, 0, 0,124, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_046[] = { 3, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_047[] = { 3, 0, 0, 0,128,128, 64, 64, 64, 64, 32, 32, 0, 0, 0}; +static const GLubyte Helvetica10_Character_048[] = { 6, 0, 0, 0,112,136,136,136,136,136,136,112, 0, 0, 0}; +static const GLubyte Helvetica10_Character_049[] = { 6, 0, 0, 0, 32, 32, 32, 32, 32, 32, 96, 32, 0, 0, 0}; +static const GLubyte Helvetica10_Character_050[] = { 6, 0, 0, 0,248,128, 64, 48, 8, 8,136,112, 0, 0, 0}; +static const GLubyte Helvetica10_Character_051[] = { 6, 0, 0, 0,112,136, 8, 8, 48, 8,136,112, 0, 0, 0}; +static const GLubyte Helvetica10_Character_052[] = { 6, 0, 0, 0, 16, 16,248,144, 80, 80, 48, 16, 0, 0, 0}; +static const GLubyte Helvetica10_Character_053[] = { 6, 0, 0, 0,112,136, 8, 8,240,128,128,248, 0, 0, 0}; +static const GLubyte Helvetica10_Character_054[] = { 6, 0, 0, 0,112,136,136,200,176,128,136,112, 0, 0, 0}; +static const GLubyte Helvetica10_Character_055[] = { 6, 0, 0, 0, 64, 64, 32, 32, 16, 16, 8,248, 0, 0, 0}; +static const GLubyte Helvetica10_Character_056[] = { 6, 0, 0, 0,112,136,136,136,112,136,136,112, 0, 0, 0}; +static const GLubyte Helvetica10_Character_057[] = { 6, 0, 0, 0,112,136, 8,104,152,136,136,112, 0, 0, 0}; +static const GLubyte Helvetica10_Character_058[] = { 3, 0, 0, 0, 64, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_059[] = { 3, 0,128, 64, 64, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_060[] = { 6, 0, 0, 0, 0, 16, 32, 64, 32, 16, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_061[] = { 5, 0, 0, 0, 0, 0,240, 0,240, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_062[] = { 6, 0, 0, 0, 0, 64, 32, 16, 32, 64, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_063[] = { 6, 0, 0, 0, 32, 0, 32, 32, 16, 8, 72, 48, 0, 0, 0}; +static const GLubyte Helvetica10_Character_064[] = { 11, 0, 0, 62, 0, 64, 0,155, 0,164,128,164,128,162, 64,146, 64, 77, 64, 32,128, 31, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_065[] = { 7, 0, 0, 0,130,130,124, 68, 40, 40, 16, 16, 0, 0, 0}; +static const GLubyte Helvetica10_Character_066[] = { 7, 0, 0, 0,120, 68, 68, 68,120, 68, 68,120, 0, 0, 0}; +static const GLubyte Helvetica10_Character_067[] = { 8, 0, 0, 0, 60, 66, 64, 64, 64, 64, 66, 60, 0, 0, 0}; +static const GLubyte Helvetica10_Character_068[] = { 8, 0, 0, 0,120, 68, 66, 66, 66, 66, 68,120, 0, 0, 0}; +static const GLubyte Helvetica10_Character_069[] = { 7, 0, 0, 0,124, 64, 64, 64,124, 64, 64,124, 0, 0, 0}; +static const GLubyte Helvetica10_Character_070[] = { 6, 0, 0, 0, 64, 64, 64, 64,120, 64, 64,124, 0, 0, 0}; +static const GLubyte Helvetica10_Character_071[] = { 8, 0, 0, 0, 58, 70, 66, 70, 64, 64, 66, 60, 0, 0, 0}; +static const GLubyte Helvetica10_Character_072[] = { 8, 0, 0, 0, 66, 66, 66, 66,126, 66, 66, 66, 0, 0, 0}; +static const GLubyte Helvetica10_Character_073[] = { 3, 0, 0, 0, 64, 64, 64, 64, 64, 64, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica10_Character_074[] = { 5, 0, 0, 0, 96,144, 16, 16, 16, 16, 16, 16, 0, 0, 0}; +static const GLubyte Helvetica10_Character_075[] = { 7, 0, 0, 0, 68, 68, 72, 72,112, 80, 72, 68, 0, 0, 0}; +static const GLubyte Helvetica10_Character_076[] = { 6, 0, 0, 0,120, 64, 64, 64, 64, 64, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica10_Character_077[] = { 9, 0, 0, 0, 0, 0, 0, 73, 0, 73, 0, 73, 0, 85, 0, 85, 0, 99, 0, 99, 0, 65, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_078[] = { 8, 0, 0, 0, 70, 70, 74, 74, 82, 82, 98, 98, 0, 0, 0}; +static const GLubyte Helvetica10_Character_079[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 60, 0, 0, 0}; +static const GLubyte Helvetica10_Character_080[] = { 7, 0, 0, 0, 64, 64, 64, 64,120, 68, 68,120, 0, 0, 0}; +static const GLubyte Helvetica10_Character_081[] = { 8, 0, 0, 1, 62, 70, 74, 66, 66, 66, 66, 60, 0, 0, 0}; +static const GLubyte Helvetica10_Character_082[] = { 7, 0, 0, 0, 68, 68, 68, 68,120, 68, 68,120, 0, 0, 0}; +static const GLubyte Helvetica10_Character_083[] = { 7, 0, 0, 0, 56, 68, 68, 4, 56, 64, 68, 56, 0, 0, 0}; +static const GLubyte Helvetica10_Character_084[] = { 5, 0, 0, 0, 32, 32, 32, 32, 32, 32, 32,248, 0, 0, 0}; +static const GLubyte Helvetica10_Character_085[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 66, 0, 0, 0}; +static const GLubyte Helvetica10_Character_086[] = { 7, 0, 0, 0, 16, 40, 40, 68, 68, 68,130,130, 0, 0, 0}; +static const GLubyte Helvetica10_Character_087[] = { 9, 0, 0, 0, 0, 0, 0, 34, 0, 34, 0, 34, 0, 85, 0, 73, 0, 73, 0,136,128,136,128, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_088[] = { 7, 0, 0, 0, 68, 68, 40, 40, 16, 40, 68, 68, 0, 0, 0}; +static const GLubyte Helvetica10_Character_089[] = { 7, 0, 0, 0, 16, 16, 16, 40, 40, 68, 68,130, 0, 0, 0}; +static const GLubyte Helvetica10_Character_090[] = { 7, 0, 0, 0,124, 64, 32, 16, 16, 8, 4,124, 0, 0, 0}; +static const GLubyte Helvetica10_Character_091[] = { 3, 0, 96, 64, 64, 64, 64, 64, 64, 64, 64, 96, 0, 0, 0}; +static const GLubyte Helvetica10_Character_092[] = { 3, 0, 0, 0, 32, 32, 64, 64, 64, 64,128,128, 0, 0, 0}; +static const GLubyte Helvetica10_Character_093[] = { 3, 0,192, 64, 64, 64, 64, 64, 64, 64, 64,192, 0, 0, 0}; +static const GLubyte Helvetica10_Character_094[] = { 6, 0, 0, 0, 0, 0, 0,136, 80, 80, 32, 32, 0, 0, 0}; +static const GLubyte Helvetica10_Character_095[] = { 6, 0,252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_096[] = { 3, 0, 0, 0, 0, 0, 0, 0, 0, 63, 64, 32, 0, 0, 0}; +static const GLubyte Helvetica10_Character_097[] = { 5, 0, 0, 0,104,144,144,112, 16,224, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_098[] = { 6, 0, 0, 0,176,200,136,136,200,176,128,128, 0, 0, 0}; +static const GLubyte Helvetica10_Character_099[] = { 5, 0, 0, 0, 96,144,128,128,144, 96, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_100[] = { 6, 0, 0, 0,104,152,136,136,152,104, 8, 8, 0, 0, 0}; +static const GLubyte Helvetica10_Character_101[] = { 5, 0, 0, 0, 96,144,128,240,144, 96, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_102[] = { 4, 0, 0, 0, 64, 64, 64, 64, 64,224, 64, 48, 0, 0, 0}; +static const GLubyte Helvetica10_Character_103[] = { 6, 0,112, 8,104,152,136,136,152,104, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_104[] = { 6, 0, 0, 0,136,136,136,136,200,176,128,128, 0, 0, 0}; +static const GLubyte Helvetica10_Character_105[] = { 2, 0, 0, 0,128,128,128,128,128,128, 0,128, 0, 0, 0}; +static const GLubyte Helvetica10_Character_106[] = { 2, 0, 0,128,128,128,128,128,128,128, 0,128, 0, 0, 0}; +static const GLubyte Helvetica10_Character_107[] = { 5, 0, 0, 0,144,144,160,192,160,144,128,128, 0, 0, 0}; +static const GLubyte Helvetica10_Character_108[] = { 2, 0, 0, 0,128,128,128,128,128,128,128,128, 0, 0, 0}; +static const GLubyte Helvetica10_Character_109[] = { 8, 0, 0, 0,146,146,146,146,146,236, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_110[] = { 6, 0, 0, 0,136,136,136,136,200,176, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_111[] = { 6, 0, 0, 0,112,136,136,136,136,112, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_112[] = { 6, 0,128,128,176,200,136,136,200,176, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_113[] = { 6, 0, 8, 8,104,152,136,136,152,104, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_114[] = { 4, 0, 0, 0,128,128,128,128,192,160, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_115[] = { 5, 0, 0, 0, 96,144, 16, 96,144, 96, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_116[] = { 4, 0, 0, 0, 96, 64, 64, 64, 64,224, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica10_Character_117[] = { 5, 0, 0, 0,112,144,144,144,144,144, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_118[] = { 6, 0, 0, 0, 32, 32, 80, 80,136,136, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_119[] = { 8, 0, 0, 0, 40, 40, 84, 84,146,146, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_120[] = { 6, 0, 0, 0,136,136, 80, 32, 80,136, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_121[] = { 5, 0,128, 64, 64, 96,160,160,144,144, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_122[] = { 5, 0, 0, 0,240,128, 64, 32, 16,240, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_123[] = { 3, 0, 32, 64, 64, 64, 64,128, 64, 64, 64, 32, 0, 0, 0}; +static const GLubyte Helvetica10_Character_124[] = { 3, 0, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica10_Character_125[] = { 3, 0,128, 64, 64, 64, 64, 32, 64, 64, 64,128, 0, 0, 0}; +static const GLubyte Helvetica10_Character_126[] = { 7, 0, 0, 0, 0, 0, 0,152,100, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_127[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_128[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_129[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_130[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_131[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_132[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_133[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_134[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_135[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_136[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_137[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_138[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_139[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_140[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_141[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_142[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_143[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_144[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_145[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_146[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_147[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_148[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_149[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_150[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_151[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_152[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_153[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_154[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_155[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_156[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_157[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_158[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_159[] = { 13, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_160[] = { 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_161[] = { 3, 0, 64, 64, 64, 64, 64, 64, 0, 64, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_162[] = { 6, 0, 0, 64,112,168,160,160,168,112, 16, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_163[] = { 6, 0, 0, 0,176, 72, 64, 64,224, 64, 72, 48, 0, 0, 0}; +static const GLubyte Helvetica10_Character_164[] = { 5, 0, 0, 0, 0,144, 96,144,144, 96,144, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_165[] = { 6, 0, 0, 0, 32,248, 32,248, 80, 80,136,136, 0, 0, 0}; +static const GLubyte Helvetica10_Character_166[] = { 3, 0, 64, 64, 64, 64, 0, 0, 64, 64, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica10_Character_167[] = { 6, 0,112,136, 24,112,200,152,112,192,136,112, 0, 0, 0}; +static const GLubyte Helvetica10_Character_168[] = { 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,160, 0, 0, 0}; +static const GLubyte Helvetica10_Character_169[] = { 9, 0, 0, 0, 0, 0, 0, 28, 0, 34, 0, 77, 0, 81, 0, 77, 0, 34, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_170[] = { 4, 0, 0, 0, 0, 0, 0,224, 0,160, 32,224, 0, 0, 0}; +static const GLubyte Helvetica10_Character_171[] = { 6, 0, 0, 0, 40, 80,160, 80, 40, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_172[] = { 7, 0, 0, 0, 0, 0, 4, 4,124, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_173[] = { 4, 0, 0, 0, 0, 0, 0,224, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_174[] = { 9, 0, 0, 0, 0, 0, 0, 28, 0, 34, 0, 85, 0, 89, 0, 93, 0, 34, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_175[] = { 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,224, 0, 0, 0}; +static const GLubyte Helvetica10_Character_176[] = { 4, 0, 0, 0, 0, 0, 0, 96,144,144, 96, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_177[] = { 6, 0, 0, 0,248, 0, 32, 32,248, 32, 32, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_178[] = { 3, 0, 0, 0, 0, 0, 0,224, 64,160, 96, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_179[] = { 3, 0, 0, 0, 0, 0, 0,192, 32, 64,224, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_180[] = { 3, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 64, 0, 0, 0}; +static const GLubyte Helvetica10_Character_181[] = { 5, 0,128,128,240,144,144,144,144,144, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_182[] = { 6, 0, 40, 40, 40, 40, 40,104,232,232,232,124, 0, 0, 0}; +static const GLubyte Helvetica10_Character_183[] = { 3, 0, 0, 0, 0, 0, 0,192, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_184[] = { 3, 0,192, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_185[] = { 3, 0, 0, 0, 0, 0, 0, 64, 64,192, 64, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_186[] = { 4, 0, 0, 0, 0, 0, 0,224, 0,224,160,224, 0, 0, 0}; +static const GLubyte Helvetica10_Character_187[] = { 6, 0, 0, 0,160, 80, 40, 80,160, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_188[] = { 9, 0, 0, 0, 0, 0, 0, 33, 0, 23,128, 19, 0, 9, 0, 72, 0, 68, 0,196, 0, 66, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_189[] = { 9, 0, 0, 0, 0, 0, 0, 39, 0, 18, 0, 21, 0, 11, 0, 72, 0, 68, 0,196, 0, 66, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_190[] = { 9, 0, 0, 0, 0, 0, 0, 33, 0, 23,128, 19, 0, 9, 0,200, 0, 36, 0, 68, 0,226, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_191[] = { 6, 0, 48, 72, 64, 32, 16, 16, 0, 16, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_192[] = { 7, 0, 0, 0,130,130,124, 68, 40, 40, 16, 16, 0, 16, 32}; +static const GLubyte Helvetica10_Character_193[] = { 7, 0, 0, 0,130,130,124, 68, 40, 40, 16, 16, 0, 16, 8}; +static const GLubyte Helvetica10_Character_194[] = { 7, 0, 0, 0,130,130,124, 68, 40, 40, 16, 16, 0, 40, 16}; +static const GLubyte Helvetica10_Character_195[] = { 7, 0, 0, 0,130,130,124, 68, 40, 40, 16, 16, 0, 40, 20}; +static const GLubyte Helvetica10_Character_196[] = { 7, 0, 0, 0,130,130,124, 68, 40, 40, 16, 16, 0, 40, 0}; +static const GLubyte Helvetica10_Character_197[] = { 7, 0, 0, 0,130,130,124, 68, 40, 40, 16, 16, 16, 40, 16}; +static const GLubyte Helvetica10_Character_198[] = { 10, 0, 0, 0, 0, 0, 0,143,128,136, 0,120, 0, 72, 0, 47,128, 40, 0, 24, 0, 31,128, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_199[] = { 8, 0, 24, 8, 60, 66, 64, 64, 64, 64, 66, 60, 0, 0, 0}; +static const GLubyte Helvetica10_Character_200[] = { 7, 0, 0, 0,124, 64, 64, 64,124, 64, 64,124, 0, 16, 32}; +static const GLubyte Helvetica10_Character_201[] = { 7, 0, 0, 0,124, 64, 64, 64,124, 64, 64,124, 0, 16, 8}; +static const GLubyte Helvetica10_Character_202[] = { 7, 0, 0, 0,124, 64, 64,124, 64, 64, 64,124, 0, 40, 16}; +static const GLubyte Helvetica10_Character_203[] = { 7, 0, 0, 0,124, 64, 64, 64,124, 64, 64,124, 0, 40, 0}; +static const GLubyte Helvetica10_Character_204[] = { 3, 0, 0, 0, 64, 64, 64, 64, 64, 64, 64, 64, 0, 64,128}; +static const GLubyte Helvetica10_Character_205[] = { 3, 0, 0, 0, 64, 64, 64, 64, 64, 64, 64, 64, 0, 64, 32}; +static const GLubyte Helvetica10_Character_206[] = { 3, 0, 0, 0, 64, 64, 64, 64, 64, 64, 64, 64, 0,160, 64}; +static const GLubyte Helvetica10_Character_207[] = { 3, 0, 0, 0, 64, 64, 64, 64, 64, 64, 64, 64, 0,160, 0}; +static const GLubyte Helvetica10_Character_208[] = { 8, 0, 0, 0,120, 68, 66, 66,242, 66, 68,120, 0, 0, 0}; +static const GLubyte Helvetica10_Character_209[] = { 8, 0, 0, 0, 70, 70, 74, 74, 82, 82, 98, 98, 0, 40, 20}; +static const GLubyte Helvetica10_Character_210[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 60, 0, 8, 16}; +static const GLubyte Helvetica10_Character_211[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 60, 0, 8, 4}; +static const GLubyte Helvetica10_Character_212[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 60, 0, 20, 8}; +static const GLubyte Helvetica10_Character_213[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 60, 0, 40, 20}; +static const GLubyte Helvetica10_Character_214[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 60, 0, 36, 0}; +static const GLubyte Helvetica10_Character_215[] = { 6, 0, 0, 0, 0,136, 80, 32, 80,136, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_216[] = { 8, 0, 0, 64, 60, 98, 82, 82, 74, 74, 70, 60, 2, 0, 0}; +static const GLubyte Helvetica10_Character_217[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 66, 0, 8, 16}; +static const GLubyte Helvetica10_Character_218[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 66, 0, 16, 8}; +static const GLubyte Helvetica10_Character_219[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 66, 0, 20, 8}; +static const GLubyte Helvetica10_Character_220[] = { 8, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 66, 0, 36, 0}; +static const GLubyte Helvetica10_Character_221[] = { 7, 0, 0, 0, 16, 16, 16, 40, 40, 68, 68,130, 0, 16, 8}; +static const GLubyte Helvetica10_Character_222[] = { 7, 0, 0, 0, 64, 64,120, 68, 68,120, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica10_Character_223[] = { 5, 0, 0, 0,160,144,144,144,160,144,144, 96, 0, 0, 0}; +static const GLubyte Helvetica10_Character_224[] = { 5, 0, 0, 0,104,144,144,112, 16,224, 0, 32, 64, 0, 0}; +static const GLubyte Helvetica10_Character_225[] = { 5, 0, 0, 0,104,144,144,112, 16,224, 0, 32, 16, 0, 0}; +static const GLubyte Helvetica10_Character_226[] = { 5, 0, 0, 0,104,144,144,112, 16,224, 0, 80, 32, 0, 0}; +static const GLubyte Helvetica10_Character_227[] = { 5, 0, 0, 0,104,144,144,112, 16,224, 0,160, 80, 0, 0}; +static const GLubyte Helvetica10_Character_228[] = { 5, 0, 0, 0,104,144,144,112, 16,224, 0, 80, 0, 0, 0}; +static const GLubyte Helvetica10_Character_229[] = { 5, 0, 0, 0,104,144,144,112, 16,224, 32, 80, 32, 0, 0}; +static const GLubyte Helvetica10_Character_230[] = { 8, 0, 0, 0,108,146,144,126, 18,236, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_231[] = { 5, 0, 96, 32, 96,144,128,128,144, 96, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_232[] = { 5, 0, 0, 0, 96,144,128,240,144, 96, 0, 32, 64, 0, 0}; +static const GLubyte Helvetica10_Character_233[] = { 5, 0, 0, 0, 96,144,128,240,144, 96, 0, 64, 32, 0, 0}; +static const GLubyte Helvetica10_Character_234[] = { 5, 0, 0, 0, 96,144,128,240,144, 96, 0, 80, 32, 0, 0}; +static const GLubyte Helvetica10_Character_235[] = { 5, 0, 0, 0, 96,144,128,240,144, 96, 0, 80, 0, 0, 0}; +static const GLubyte Helvetica10_Character_236[] = { 2, 0, 0, 0,128,128,128,128,128,128, 0,128, 0, 0, 0}; +static const GLubyte Helvetica10_Character_237[] = { 2, 0, 0, 0,128,128,128,128,128,128, 0,128, 64, 0, 0}; +static const GLubyte Helvetica10_Character_238[] = { 2, 0, 0, 0,128,128,128,128,128,128, 0, 64,128, 0, 0}; +static const GLubyte Helvetica10_Character_239[] = { 2, 0, 0, 0, 64, 64, 64, 64, 64, 64, 0,160, 0, 0, 0}; +static const GLubyte Helvetica10_Character_240[] = { 6, 0, 0, 0,112,136,136,136,136,120,144, 96, 80, 0, 0}; +static const GLubyte Helvetica10_Character_241[] = { 5, 0, 0, 0,144,144,144,144,144,224, 0,160, 80, 0, 0}; +static const GLubyte Helvetica10_Character_242[] = { 6, 0, 0, 0,112,136,136,136,136,112, 0, 32, 64, 0, 0}; +static const GLubyte Helvetica10_Character_243[] = { 6, 0, 0, 0,112,136,136,136,136,112, 0, 32, 16, 0, 0}; +static const GLubyte Helvetica10_Character_244[] = { 6, 0, 0, 0,112,136,136,136,136,112, 0, 80, 32, 0, 0}; +static const GLubyte Helvetica10_Character_245[] = { 6, 0, 0, 0,112,136,136,136,136,112, 0, 80, 40, 0, 0}; +static const GLubyte Helvetica10_Character_246[] = { 6, 0, 0, 0,112,136,136,136,136,112, 0, 80, 0, 0, 0}; +static const GLubyte Helvetica10_Character_247[] = { 6, 0, 0, 0, 0, 32, 0,248, 0, 32, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_248[] = { 6, 0, 0, 0,112,136,200,168,152,116, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica10_Character_249[] = { 5, 0, 0, 0,112,144,144,144,144,144, 0, 32, 64, 0, 0}; +static const GLubyte Helvetica10_Character_250[] = { 5, 0, 0, 0,112,144,144,144,144,144, 0, 64, 32, 0, 0}; +static const GLubyte Helvetica10_Character_251[] = { 5, 0, 0, 0,112,144,144,144,144,144, 0, 80, 32, 0, 0}; +static const GLubyte Helvetica10_Character_252[] = { 5, 0, 0, 0,112,144,144,144,144,144, 0, 80, 0, 0, 0}; +static const GLubyte Helvetica10_Character_253[] = { 5, 0,128, 64, 64, 96,160,160,144,144, 0, 32, 16, 0, 0}; +static const GLubyte Helvetica10_Character_254[] = { 6, 0,128,128,176,200,136,136,200,176,128,128, 0, 0, 0}; +static const GLubyte Helvetica10_Character_255[] = { 5, 0,128, 64, 64, 96,160,160,144,144, 0, 80, 0, 0, 0}; + +/* The font characters mapping: */ +static const GLubyte* Helvetica10_Character_Map[] = {Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032, + Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032, + Helvetica10_Character_032,Helvetica10_Character_033,Helvetica10_Character_034,Helvetica10_Character_035,Helvetica10_Character_036,Helvetica10_Character_037,Helvetica10_Character_038,Helvetica10_Character_039,Helvetica10_Character_040,Helvetica10_Character_041,Helvetica10_Character_042,Helvetica10_Character_043,Helvetica10_Character_044,Helvetica10_Character_045,Helvetica10_Character_046,Helvetica10_Character_047, + Helvetica10_Character_048,Helvetica10_Character_049,Helvetica10_Character_050,Helvetica10_Character_051,Helvetica10_Character_052,Helvetica10_Character_053,Helvetica10_Character_054,Helvetica10_Character_055,Helvetica10_Character_056,Helvetica10_Character_057,Helvetica10_Character_058,Helvetica10_Character_059,Helvetica10_Character_060,Helvetica10_Character_061,Helvetica10_Character_062,Helvetica10_Character_063, + Helvetica10_Character_064,Helvetica10_Character_065,Helvetica10_Character_066,Helvetica10_Character_067,Helvetica10_Character_068,Helvetica10_Character_069,Helvetica10_Character_070,Helvetica10_Character_071,Helvetica10_Character_072,Helvetica10_Character_073,Helvetica10_Character_074,Helvetica10_Character_075,Helvetica10_Character_076,Helvetica10_Character_077,Helvetica10_Character_078,Helvetica10_Character_079, + Helvetica10_Character_080,Helvetica10_Character_081,Helvetica10_Character_082,Helvetica10_Character_083,Helvetica10_Character_084,Helvetica10_Character_085,Helvetica10_Character_086,Helvetica10_Character_087,Helvetica10_Character_088,Helvetica10_Character_089,Helvetica10_Character_090,Helvetica10_Character_091,Helvetica10_Character_092,Helvetica10_Character_093,Helvetica10_Character_094,Helvetica10_Character_095, + Helvetica10_Character_096,Helvetica10_Character_097,Helvetica10_Character_098,Helvetica10_Character_099,Helvetica10_Character_100,Helvetica10_Character_101,Helvetica10_Character_102,Helvetica10_Character_103,Helvetica10_Character_104,Helvetica10_Character_105,Helvetica10_Character_106,Helvetica10_Character_107,Helvetica10_Character_108,Helvetica10_Character_109,Helvetica10_Character_110,Helvetica10_Character_111, + Helvetica10_Character_112,Helvetica10_Character_113,Helvetica10_Character_114,Helvetica10_Character_115,Helvetica10_Character_116,Helvetica10_Character_117,Helvetica10_Character_118,Helvetica10_Character_119,Helvetica10_Character_120,Helvetica10_Character_121,Helvetica10_Character_122,Helvetica10_Character_123,Helvetica10_Character_124,Helvetica10_Character_125,Helvetica10_Character_126,Helvetica10_Character_032, + Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032, + Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032,Helvetica10_Character_032, + Helvetica10_Character_160,Helvetica10_Character_161,Helvetica10_Character_162,Helvetica10_Character_163,Helvetica10_Character_164,Helvetica10_Character_165,Helvetica10_Character_166,Helvetica10_Character_167,Helvetica10_Character_168,Helvetica10_Character_169,Helvetica10_Character_170,Helvetica10_Character_171,Helvetica10_Character_172,Helvetica10_Character_173,Helvetica10_Character_174,Helvetica10_Character_175, + Helvetica10_Character_176,Helvetica10_Character_177,Helvetica10_Character_178,Helvetica10_Character_179,Helvetica10_Character_180,Helvetica10_Character_181,Helvetica10_Character_182,Helvetica10_Character_183,Helvetica10_Character_184,Helvetica10_Character_185,Helvetica10_Character_186,Helvetica10_Character_187,Helvetica10_Character_188,Helvetica10_Character_189,Helvetica10_Character_190,Helvetica10_Character_191, + Helvetica10_Character_192,Helvetica10_Character_193,Helvetica10_Character_194,Helvetica10_Character_195,Helvetica10_Character_196,Helvetica10_Character_197,Helvetica10_Character_198,Helvetica10_Character_199,Helvetica10_Character_200,Helvetica10_Character_201,Helvetica10_Character_202,Helvetica10_Character_203,Helvetica10_Character_204,Helvetica10_Character_205,Helvetica10_Character_206,Helvetica10_Character_207, + Helvetica10_Character_208,Helvetica10_Character_209,Helvetica10_Character_210,Helvetica10_Character_211,Helvetica10_Character_212,Helvetica10_Character_213,Helvetica10_Character_214,Helvetica10_Character_215,Helvetica10_Character_216,Helvetica10_Character_217,Helvetica10_Character_218,Helvetica10_Character_219,Helvetica10_Character_220,Helvetica10_Character_221,Helvetica10_Character_222,Helvetica10_Character_223, + Helvetica10_Character_224,Helvetica10_Character_225,Helvetica10_Character_226,Helvetica10_Character_227,Helvetica10_Character_228,Helvetica10_Character_229,Helvetica10_Character_230,Helvetica10_Character_231,Helvetica10_Character_232,Helvetica10_Character_233,Helvetica10_Character_234,Helvetica10_Character_235,Helvetica10_Character_236,Helvetica10_Character_237,Helvetica10_Character_238,Helvetica10_Character_239, + Helvetica10_Character_240,Helvetica10_Character_241,Helvetica10_Character_242,Helvetica10_Character_243,Helvetica10_Character_244,Helvetica10_Character_245,Helvetica10_Character_246,Helvetica10_Character_247,Helvetica10_Character_248,Helvetica10_Character_249,Helvetica10_Character_250,Helvetica10_Character_251,Helvetica10_Character_252,Helvetica10_Character_253,Helvetica10_Character_254,Helvetica10_Character_255,NULL}; + +/* The font structure: */ +const SFG_Font fgFontHelvetica10 = { "-adobe-helvetica-medium-r-normal--10-100-75-75-p-56-iso8859-1", 256, 14, Helvetica10_Character_Map, 0, 3 }; + +static const GLubyte Helvetica12_Character_000[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_001[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_002[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_003[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_004[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_005[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_006[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_007[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_008[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_009[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_010[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_011[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_012[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_013[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_014[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_015[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_016[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_017[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_018[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_019[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_020[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_021[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_022[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_023[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_024[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_025[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_026[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_027[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_028[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_029[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_030[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_031[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_032[] = { 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_033[] = { 3, 0, 0, 0, 0, 64, 0, 64, 64, 64, 64, 64, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica12_Character_034[] = { 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 80, 80, 0, 0, 0}; +static const GLubyte Helvetica12_Character_035[] = { 7, 0, 0, 0, 0, 80, 80, 80,252, 40,252, 40, 40, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_036[] = { 7, 0, 0, 0, 16, 56, 84, 84, 20, 56, 80, 84, 56, 16, 0, 0, 0}; +static const GLubyte Helvetica12_Character_037[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 17,128, 10, 64, 10, 64, 9,128, 4, 0, 52, 0, 74, 0, 74, 0, 49, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_038[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 57, 0, 70, 0, 66, 0, 69, 0, 40, 0, 24, 0, 36, 0, 36, 0, 24, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_039[] = { 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 32, 96, 0, 0, 0}; +static const GLubyte Helvetica12_Character_040[] = { 4, 0, 16, 32, 32, 64, 64, 64, 64, 64, 64, 32, 32, 16, 0, 0, 0}; +static const GLubyte Helvetica12_Character_041[] = { 4, 0,128, 64, 64, 32, 32, 32, 32, 32, 32, 64, 64,128, 0, 0, 0}; +static const GLubyte Helvetica12_Character_042[] = { 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 32, 80, 0, 0, 0}; +static const GLubyte Helvetica12_Character_043[] = { 7, 0, 0, 0, 0, 0, 16, 16,124, 16, 16, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_044[] = { 4, 0, 0, 64, 32, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_045[] = { 8, 0, 0, 0, 0, 0, 0, 0,124, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_046[] = { 3, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_047[] = { 4, 0, 0, 0, 0,128,128, 64, 64, 64, 32, 32, 16, 16, 0, 0, 0}; +static const GLubyte Helvetica12_Character_048[] = { 7, 0, 0, 0, 0, 56, 68, 68, 68, 68, 68, 68, 68, 56, 0, 0, 0}; +static const GLubyte Helvetica12_Character_049[] = { 7, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16,112, 16, 0, 0, 0}; +static const GLubyte Helvetica12_Character_050[] = { 7, 0, 0, 0, 0,124, 64, 64, 32, 16, 8, 4, 68, 56, 0, 0, 0}; +static const GLubyte Helvetica12_Character_051[] = { 7, 0, 0, 0, 0, 56, 68, 68, 4, 4, 24, 4, 68, 56, 0, 0, 0}; +static const GLubyte Helvetica12_Character_052[] = { 7, 0, 0, 0, 0, 8, 8,252,136, 72, 40, 40, 24, 8, 0, 0, 0}; +static const GLubyte Helvetica12_Character_053[] = { 7, 0, 0, 0, 0, 56, 68, 68, 4, 4,120, 64, 64,124, 0, 0, 0}; +static const GLubyte Helvetica12_Character_054[] = { 7, 0, 0, 0, 0, 56, 68, 68, 68,100, 88, 64, 68, 56, 0, 0, 0}; +static const GLubyte Helvetica12_Character_055[] = { 7, 0, 0, 0, 0, 32, 32, 16, 16, 16, 8, 8, 4,124, 0, 0, 0}; +static const GLubyte Helvetica12_Character_056[] = { 7, 0, 0, 0, 0, 56, 68, 68, 68, 68, 56, 68, 68, 56, 0, 0, 0}; +static const GLubyte Helvetica12_Character_057[] = { 7, 0, 0, 0, 0, 56, 68, 4, 4, 60, 68, 68, 68, 56, 0, 0, 0}; +static const GLubyte Helvetica12_Character_058[] = { 3, 0, 0, 0, 0, 64, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_059[] = { 3, 0, 0,128, 64, 64, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_060[] = { 7, 0, 0, 0, 0, 0, 12, 48,192, 48, 12, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_061[] = { 7, 0, 0, 0, 0, 0, 0,124, 0,124, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_062[] = { 7, 0, 0, 0, 0, 0, 96, 24, 6, 24, 96, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_063[] = { 7, 0, 0, 0, 0, 16, 0, 16, 16, 8, 8, 68, 68, 56, 0, 0, 0}; +static const GLubyte Helvetica12_Character_064[] = { 12, 0, 0, 0, 0, 0, 0, 31, 0, 32, 0, 77,128, 83, 64, 81, 32, 81, 32, 73, 32, 38,160, 48, 64, 15,128, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_065[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0, 62, 0, 34, 0, 34, 0, 20, 0, 20, 0, 8, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_066[] = { 8, 0, 0, 0, 0,124, 66, 66, 66,124, 66, 66, 66,124, 0, 0, 0}; +static const GLubyte Helvetica12_Character_067[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 33, 0, 64, 0, 64, 0, 64, 0, 64, 0, 64, 0, 33, 0, 30, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_068[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0,124, 0, 66, 0, 65, 0, 65, 0, 65, 0, 65, 0, 65, 0, 66, 0,124, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_069[] = { 8, 0, 0, 0, 0,126, 64, 64, 64,126, 64, 64, 64,126, 0, 0, 0}; +static const GLubyte Helvetica12_Character_070[] = { 8, 0, 0, 0, 0, 64, 64, 64, 64,124, 64, 64, 64,126, 0, 0, 0}; +static const GLubyte Helvetica12_Character_071[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 35, 0, 65, 0, 65, 0, 71, 0, 64, 0, 64, 0, 33, 0, 30, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_072[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0, 65, 0,127, 0, 65, 0, 65, 0, 65, 0, 65, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_073[] = { 3, 0, 0, 0, 0, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica12_Character_074[] = { 7, 0, 0, 0, 0, 56, 68, 68, 4, 4, 4, 4, 4, 4, 0, 0, 0}; +static const GLubyte Helvetica12_Character_075[] = { 8, 0, 0, 0, 0, 65, 66, 68, 72,112, 80, 72, 68, 66, 0, 0, 0}; +static const GLubyte Helvetica12_Character_076[] = { 7, 0, 0, 0, 0,124, 64, 64, 64, 64, 64, 64, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica12_Character_077[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 68, 64, 68, 64, 74, 64, 74, 64, 81, 64, 81, 64, 96,192, 96,192, 64, 64, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_078[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 67, 0, 69, 0, 69, 0, 73, 0, 81, 0, 81, 0, 97, 0, 65, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_079[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 33, 0, 64,128, 64,128, 64,128, 64,128, 64,128, 33, 0, 30, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_080[] = { 8, 0, 0, 0, 0, 64, 64, 64, 64,124, 66, 66, 66,124, 0, 0, 0}; +static const GLubyte Helvetica12_Character_081[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 30,128, 33, 0, 66,128, 68,128, 64,128, 64,128, 64,128, 33, 0, 30, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_082[] = { 8, 0, 0, 0, 0, 66, 66, 66, 68,124, 66, 66, 66,124, 0, 0, 0}; +static const GLubyte Helvetica12_Character_083[] = { 8, 0, 0, 0, 0, 60, 66, 66, 2, 12, 48, 64, 66, 60, 0, 0, 0}; +static const GLubyte Helvetica12_Character_084[] = { 7, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16,254, 0, 0, 0}; +static const GLubyte Helvetica12_Character_085[] = { 8, 0, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 66, 66, 0, 0, 0}; +static const GLubyte Helvetica12_Character_086[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 8, 0, 20, 0, 20, 0, 34, 0, 34, 0, 34, 0, 65, 0, 65, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_087[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 42,128, 42,128, 36,128, 68, 64, 68, 64, 68, 64, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_088[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 34, 0, 34, 0, 20, 0, 8, 0, 20, 0, 34, 0, 34, 0, 65, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_089[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 20, 0, 34, 0, 34, 0, 65, 0, 65, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_090[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0,127, 0, 64, 0, 32, 0, 16, 0, 8, 0, 4, 0, 2, 0, 1, 0,127, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_091[] = { 3, 0, 96, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 96, 0, 0, 0}; +static const GLubyte Helvetica12_Character_092[] = { 4, 0, 0, 0, 0, 16, 16, 32, 32, 32, 64, 64,128,128, 0, 0, 0}; +static const GLubyte Helvetica12_Character_093[] = { 3, 0,192, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,192, 0, 0, 0}; +static const GLubyte Helvetica12_Character_094[] = { 6, 0, 0, 0, 0, 0, 0, 0, 0, 0,136, 80, 32, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_095[] = { 7, 0, 0,254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_096[] = { 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,192,128, 64, 0, 0, 0}; +static const GLubyte Helvetica12_Character_097[] = { 7, 0, 0, 0, 0, 58, 68, 68, 60, 4, 68, 56, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_098[] = { 7, 0, 0, 0, 0, 88,100, 68, 68, 68,100, 88, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica12_Character_099[] = { 7, 0, 0, 0, 0, 56, 68, 64, 64, 64, 68, 56, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_100[] = { 7, 0, 0, 0, 0, 52, 76, 68, 68, 68, 76, 52, 4, 4, 0, 0, 0}; +static const GLubyte Helvetica12_Character_101[] = { 7, 0, 0, 0, 0, 56, 68, 64,124, 68, 68, 56, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_102[] = { 3, 0, 0, 0, 0, 64, 64, 64, 64, 64, 64,224, 64, 48, 0, 0, 0}; +static const GLubyte Helvetica12_Character_103[] = { 7, 0, 56, 68, 4, 52, 76, 68, 68, 68, 76, 52, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_104[] = { 7, 0, 0, 0, 0, 68, 68, 68, 68, 68,100, 88, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica12_Character_105[] = { 3, 0, 0, 0, 0, 64, 64, 64, 64, 64, 64, 64, 0, 64, 0, 0, 0}; +static const GLubyte Helvetica12_Character_106[] = { 3, 0,128, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 64, 0, 0, 0}; +static const GLubyte Helvetica12_Character_107[] = { 6, 0, 0, 0, 0, 68, 72, 80, 96, 96, 80, 72, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica12_Character_108[] = { 3, 0, 0, 0, 0, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica12_Character_109[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 73, 0, 73, 0, 73, 0, 73, 0, 73, 0,109, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_110[] = { 7, 0, 0, 0, 0, 68, 68, 68, 68, 68,100, 88, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_111[] = { 7, 0, 0, 0, 0, 56, 68, 68, 68, 68, 68, 56, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_112[] = { 7, 0, 64, 64, 64, 88,100, 68, 68, 68,100, 88, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_113[] = { 7, 0, 4, 4, 4, 52, 76, 68, 68, 68, 76, 52, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_114[] = { 4, 0, 0, 0, 0, 64, 64, 64, 64, 64, 96, 80, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_115[] = { 6, 0, 0, 0, 0, 48, 72, 8, 48, 64, 72, 48, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_116[] = { 3, 0, 0, 0, 0, 96, 64, 64, 64, 64, 64,224, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica12_Character_117[] = { 7, 0, 0, 0, 0, 52, 76, 68, 68, 68, 68, 68, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_118[] = { 7, 0, 0, 0, 0, 16, 16, 40, 40, 68, 68, 68, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_119[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 34, 0, 34, 0, 85, 0, 73, 0, 73, 0,136,128,136,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_120[] = { 6, 0, 0, 0, 0,132,132, 72, 48, 48, 72,132, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_121[] = { 7, 0, 64, 32, 16, 16, 40, 40, 72, 68, 68, 68, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_122[] = { 6, 0, 0, 0, 0,120, 64, 32, 32, 16, 8,120, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_123[] = { 4, 0, 48, 64, 64, 64, 64, 64,128, 64, 64, 64, 64, 48, 0, 0, 0}; +static const GLubyte Helvetica12_Character_124[] = { 3, 0, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica12_Character_125[] = { 4, 0,192, 32, 32, 32, 32, 32, 16, 32, 32, 32, 32,192, 0, 0, 0}; +static const GLubyte Helvetica12_Character_126[] = { 7, 0, 0, 0, 0, 0, 0, 0,152,100, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_127[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_128[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_129[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_130[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_131[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_132[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_133[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_134[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_135[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_136[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_137[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_138[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_139[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_140[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_141[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_142[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_143[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_144[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_145[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_146[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_147[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_148[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_149[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_150[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_151[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_152[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_153[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_154[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_155[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_156[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_157[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_158[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_159[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 65, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_160[] = { 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_161[] = { 3, 0, 64, 64, 64, 64, 64, 64, 64, 64, 0, 64, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_162[] = { 7, 0, 0, 0, 32, 56,100, 80, 80, 80, 84, 56, 8, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_163[] = { 7, 0, 0, 0, 0, 88, 36, 16, 16,120, 32, 32, 36, 24, 0, 0, 0}; +static const GLubyte Helvetica12_Character_164[] = { 7, 0, 0, 0, 0, 0,132,120, 72, 72,120,132, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_165[] = { 7, 0, 0, 0, 0, 16, 16,124, 16,124, 16, 40, 68, 68, 0, 0, 0}; +static const GLubyte Helvetica12_Character_166[] = { 3, 0, 0, 64, 64, 64, 64, 0, 0, 0, 64, 64, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica12_Character_167[] = { 6, 0,112,136, 8, 48, 72,136,136,144, 96,128,136,112, 0, 0, 0}; +static const GLubyte Helvetica12_Character_168[] = { 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,160, 0, 0, 0}; +static const GLubyte Helvetica12_Character_169[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 32,128, 78, 64, 81, 64, 80, 64, 81, 64, 78, 64, 32,128, 31, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_170[] = { 5, 0, 0, 0, 0, 0, 0, 0, 0,112, 0, 80, 16,112, 0, 0, 0}; +static const GLubyte Helvetica12_Character_171[] = { 7, 0, 0, 0, 0, 0, 20, 40, 80, 40, 20, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_172[] = { 8, 0, 0, 0, 0, 0, 0, 2, 2, 2,126, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_173[] = { 5, 0, 0, 0, 0, 0, 0, 0,240, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_174[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 32,128, 74, 64, 74, 64, 76, 64, 74, 64, 78, 64, 32,128, 31, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_175[] = { 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,240, 0, 0, 0}; +static const GLubyte Helvetica12_Character_176[] = { 5, 0, 0, 0, 0, 0, 0, 0, 0, 96,144,144, 96, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_177[] = { 7, 0, 0, 0, 0,124, 0, 16, 16,124, 16, 16, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_178[] = { 4, 0, 0, 0, 0, 0, 0, 0,240, 64, 32,144, 96, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_179[] = { 4, 0, 0, 0, 0, 0, 0, 0,192, 32, 64, 32,224, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_180[] = { 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 64, 0, 0}; +static const GLubyte Helvetica12_Character_181[] = { 7, 0, 64, 64, 64,116, 76, 68, 68, 68, 68, 68, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_182[] = { 7, 0, 40, 40, 40, 40, 40, 40,104,232,232,232,104, 60, 0, 0, 0}; +static const GLubyte Helvetica12_Character_183[] = { 3, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_184[] = { 3, 0,192, 32, 32, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_185[] = { 4, 0, 0, 0, 0, 0, 0, 0, 32, 32, 32, 96, 32, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_186[] = { 5, 0, 0, 0, 0, 0, 0, 0, 0,112, 0,112, 80,112, 0, 0, 0}; +static const GLubyte Helvetica12_Character_187[] = { 7, 0, 0, 0, 0, 0, 80, 40, 20, 40, 80, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_188[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 39,128, 21, 0, 19, 0, 73, 0, 68, 0, 68, 0,194, 0, 65, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_189[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 71,128, 34, 0, 17, 0, 20,128, 75, 0, 72, 0, 68, 0,194, 0, 65, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_190[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 23,128, 21, 0, 11, 0,201, 0, 36, 0, 68, 0, 34, 0,225, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_191[] = { 7, 0, 56, 68, 68, 32, 32, 16, 16, 0, 16, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_192[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0, 62, 0, 34, 0, 34, 0, 20, 0, 8, 0, 8, 0, 0, 0, 8, 0, 16, 0}; +static const GLubyte Helvetica12_Character_193[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0, 62, 0, 34, 0, 34, 0, 20, 0, 8, 0, 8, 0, 0, 0, 8, 0, 4, 0}; +static const GLubyte Helvetica12_Character_194[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0, 62, 0, 34, 0, 34, 0, 20, 0, 8, 0, 8, 0, 0, 0, 20, 0, 8, 0}; +static const GLubyte Helvetica12_Character_195[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0, 62, 0, 34, 0, 34, 0, 20, 0, 8, 0, 8, 0, 0, 0, 20, 0, 10, 0}; +static const GLubyte Helvetica12_Character_196[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0, 62, 0, 34, 0, 34, 0, 20, 0, 8, 0, 8, 0, 0, 0, 20, 0, 0, 0}; +static const GLubyte Helvetica12_Character_197[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 65, 0, 65, 0, 62, 0, 34, 0, 34, 0, 20, 0, 8, 0, 8, 0, 8, 0, 20, 0, 8, 0}; +static const GLubyte Helvetica12_Character_198[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 71,192, 68, 0, 68, 0, 60, 0, 39,192, 36, 0, 20, 0, 20, 0, 15,192, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_199[] = { 9, 0, 0, 24, 0, 4, 0, 4, 0, 30, 0, 33, 0, 64, 0, 64, 0, 64, 0, 64, 0, 64, 0, 33, 0, 30, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_200[] = { 8, 0, 0, 0, 0,126, 64, 64, 64,126, 64, 64, 64,126, 0, 8, 16}; +static const GLubyte Helvetica12_Character_201[] = { 8, 0, 0, 0, 0,126, 64, 64, 64,126, 64, 64, 64,126, 0, 8, 4}; +static const GLubyte Helvetica12_Character_202[] = { 8, 0, 0, 0, 0,126, 64, 64, 64,126, 64, 64, 64,126, 0, 20, 8}; +static const GLubyte Helvetica12_Character_203[] = { 8, 0, 0, 0, 0,126, 64, 64, 64,126, 64, 64, 64,126, 0, 20, 0}; +static const GLubyte Helvetica12_Character_204[] = { 3, 0, 0, 0, 0, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 64,128}; +static const GLubyte Helvetica12_Character_205[] = { 3, 0, 0, 0, 0, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 64, 32}; +static const GLubyte Helvetica12_Character_206[] = { 3, 0, 0, 0, 0, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0,160, 64}; +static const GLubyte Helvetica12_Character_207[] = { 3, 0, 0, 0, 0, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0,160, 0}; +static const GLubyte Helvetica12_Character_208[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0,124, 0, 66, 0, 65, 0, 65, 0,241, 0, 65, 0, 65, 0, 66, 0,124, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_209[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 67, 0, 69, 0, 69, 0, 73, 0, 81, 0, 81, 0, 97, 0, 65, 0, 0, 0, 20, 0, 10, 0}; +static const GLubyte Helvetica12_Character_210[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 33, 0, 64,128, 64,128, 64,128, 64,128, 64,128, 33, 0, 30, 0, 0, 0, 4, 0, 8, 0}; +static const GLubyte Helvetica12_Character_211[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 33, 0, 64,128, 64,128, 64,128, 64,128, 64,128, 33, 0, 30, 0, 0, 0, 4, 0, 2, 0}; +static const GLubyte Helvetica12_Character_212[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 33, 0, 64,128, 64,128, 64,128, 64,128, 64,128, 33, 0, 30, 0, 0, 0, 10, 0, 4, 0}; +static const GLubyte Helvetica12_Character_213[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 33, 0, 64,128, 64,128, 64,128, 64,128, 64,128, 33, 0, 30, 0, 0, 0, 20, 0, 10, 0}; +static const GLubyte Helvetica12_Character_214[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 33, 0, 64,128, 64,128, 64,128, 64,128, 64,128, 33, 0, 30, 0, 0, 0, 18, 0, 0, 0}; +static const GLubyte Helvetica12_Character_215[] = { 7, 0, 0, 0, 0, 0, 68, 40, 16, 40, 68, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_216[] = { 10, 0, 0, 0, 0, 0, 0,128, 0, 94, 0, 33, 0, 80,128, 72,128, 68,128, 68,128, 66,128, 33, 0, 30,128, 0, 64, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_217[] = { 8, 0, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 66, 66, 0, 8, 16}; +static const GLubyte Helvetica12_Character_218[] = { 8, 0, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 66, 66, 0, 8, 4}; +static const GLubyte Helvetica12_Character_219[] = { 8, 0, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 66, 66, 0, 20, 8}; +static const GLubyte Helvetica12_Character_220[] = { 8, 0, 0, 0, 0, 60, 66, 66, 66, 66, 66, 66, 66, 66, 0, 36, 0}; +static const GLubyte Helvetica12_Character_221[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 20, 0, 34, 0, 34, 0, 65, 0, 65, 0, 0, 0, 8, 0, 4, 0}; +static const GLubyte Helvetica12_Character_222[] = { 8, 0, 0, 0, 0, 64, 64,124, 66, 66, 66,124, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica12_Character_223[] = { 7, 0, 0, 0, 0, 88, 68, 68, 68, 88, 68, 68, 68, 56, 0, 0, 0}; +static const GLubyte Helvetica12_Character_224[] = { 7, 0, 0, 0, 0, 58, 68, 68, 60, 4, 68, 56, 0, 8, 16, 0, 0}; +static const GLubyte Helvetica12_Character_225[] = { 7, 0, 0, 0, 0, 58, 68, 68, 60, 4, 68, 56, 0, 16, 8, 0, 0}; +static const GLubyte Helvetica12_Character_226[] = { 7, 0, 0, 0, 0, 58, 68, 68, 60, 4, 68, 56, 0, 40, 16, 0, 0}; +static const GLubyte Helvetica12_Character_227[] = { 7, 0, 0, 0, 0, 58, 68, 68, 60, 4, 68, 56, 0, 40, 20, 0, 0}; +static const GLubyte Helvetica12_Character_228[] = { 7, 0, 0, 0, 0, 58, 68, 68, 60, 4, 68, 56, 0, 40, 0, 0, 0}; +static const GLubyte Helvetica12_Character_229[] = { 7, 0, 0, 0, 0, 58, 68, 68, 60, 4, 68, 56, 24, 36, 24, 0, 0}; +static const GLubyte Helvetica12_Character_230[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 59,128, 68, 64, 68, 0, 63,192, 4, 64, 68, 64, 59,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_231[] = { 7, 0, 48, 8, 16, 56, 68, 64, 64, 64, 68, 56, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_232[] = { 7, 0, 0, 0, 0, 56, 68, 64,124, 68, 68, 56, 0, 16, 32, 0, 0}; +static const GLubyte Helvetica12_Character_233[] = { 7, 0, 0, 0, 0, 56, 68, 64,124, 68, 68, 56, 0, 16, 8, 0, 0}; +static const GLubyte Helvetica12_Character_234[] = { 7, 0, 0, 0, 0, 56, 68, 64,124, 68, 68, 56, 0, 40, 16, 0, 0}; +static const GLubyte Helvetica12_Character_235[] = { 7, 0, 0, 0, 0, 56, 68, 64,124, 68, 68, 56, 0, 40, 0, 0, 0}; +static const GLubyte Helvetica12_Character_236[] = { 3, 0, 0, 0, 0, 64, 64, 64, 64, 64, 64, 64, 0, 64,128, 0, 0}; +static const GLubyte Helvetica12_Character_237[] = { 3, 0, 0, 0, 0, 64, 64, 64, 64, 64, 64, 64, 0, 64, 32, 0, 0}; +static const GLubyte Helvetica12_Character_238[] = { 3, 0, 0, 0, 0, 64, 64, 64, 64, 64, 64, 64, 0,160, 64, 0, 0}; +static const GLubyte Helvetica12_Character_239[] = { 3, 0, 0, 0, 0, 64, 64, 64, 64, 64, 64, 64, 0,160, 0, 0, 0}; +static const GLubyte Helvetica12_Character_240[] = { 7, 0, 0, 0, 0, 56, 68, 68, 68, 68, 60, 4, 40, 24, 52, 0, 0}; +static const GLubyte Helvetica12_Character_241[] = { 7, 0, 0, 0, 0, 68, 68, 68, 68, 68,100, 88, 0, 40, 20, 0, 0}; +static const GLubyte Helvetica12_Character_242[] = { 7, 0, 0, 0, 0, 56, 68, 68, 68, 68, 68, 56, 0, 16, 32, 0, 0}; +static const GLubyte Helvetica12_Character_243[] = { 7, 0, 0, 0, 0, 56, 68, 68, 68, 68, 68, 56, 0, 16, 8, 0, 0}; +static const GLubyte Helvetica12_Character_244[] = { 7, 0, 0, 0, 0, 56, 68, 68, 68, 68, 68, 56, 0, 40, 16, 0, 0}; +static const GLubyte Helvetica12_Character_245[] = { 7, 0, 0, 0, 0, 56, 68, 68, 68, 68, 68, 56, 0, 40, 20, 0, 0}; +static const GLubyte Helvetica12_Character_246[] = { 7, 0, 0, 0, 0, 56, 68, 68, 68, 68, 68, 56, 0, 40, 0, 0, 0}; +static const GLubyte Helvetica12_Character_247[] = { 7, 0, 0, 0, 0, 0, 16, 0,124, 0, 16, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_248[] = { 7, 0, 0, 0, 0,184, 68,100, 84, 76, 68, 58, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica12_Character_249[] = { 7, 0, 0, 0, 0, 52, 76, 68, 68, 68, 68, 68, 0, 16, 32, 0, 0}; +static const GLubyte Helvetica12_Character_250[] = { 7, 0, 0, 0, 0, 52, 76, 68, 68, 68, 68, 68, 0, 16, 8, 0, 0}; +static const GLubyte Helvetica12_Character_251[] = { 7, 0, 0, 0, 0, 52, 76, 68, 68, 68, 68, 68, 0, 40, 16, 0, 0}; +static const GLubyte Helvetica12_Character_252[] = { 7, 0, 0, 0, 0, 52, 76, 68, 68, 68, 68, 68, 0, 40, 0, 0, 0}; +static const GLubyte Helvetica12_Character_253[] = { 7, 0, 64, 32, 16, 16, 40, 40, 72, 68, 68, 68, 0, 16, 8, 0, 0}; +static const GLubyte Helvetica12_Character_254[] = { 7, 0, 64, 64, 64, 88,100, 68, 68, 68,100, 88, 64, 64, 0, 0, 0}; +static const GLubyte Helvetica12_Character_255[] = { 7, 0, 96, 16, 16, 16, 24, 40, 40, 36, 68, 68, 0, 40, 0, 0, 0}; + +/* The font characters mapping: */ +static const GLubyte* Helvetica12_Character_Map[] = {Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032, + Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032, + Helvetica12_Character_032,Helvetica12_Character_033,Helvetica12_Character_034,Helvetica12_Character_035,Helvetica12_Character_036,Helvetica12_Character_037,Helvetica12_Character_038,Helvetica12_Character_039,Helvetica12_Character_040,Helvetica12_Character_041,Helvetica12_Character_042,Helvetica12_Character_043,Helvetica12_Character_044,Helvetica12_Character_045,Helvetica12_Character_046,Helvetica12_Character_047, + Helvetica12_Character_048,Helvetica12_Character_049,Helvetica12_Character_050,Helvetica12_Character_051,Helvetica12_Character_052,Helvetica12_Character_053,Helvetica12_Character_054,Helvetica12_Character_055,Helvetica12_Character_056,Helvetica12_Character_057,Helvetica12_Character_058,Helvetica12_Character_059,Helvetica12_Character_060,Helvetica12_Character_061,Helvetica12_Character_062,Helvetica12_Character_063, + Helvetica12_Character_064,Helvetica12_Character_065,Helvetica12_Character_066,Helvetica12_Character_067,Helvetica12_Character_068,Helvetica12_Character_069,Helvetica12_Character_070,Helvetica12_Character_071,Helvetica12_Character_072,Helvetica12_Character_073,Helvetica12_Character_074,Helvetica12_Character_075,Helvetica12_Character_076,Helvetica12_Character_077,Helvetica12_Character_078,Helvetica12_Character_079, + Helvetica12_Character_080,Helvetica12_Character_081,Helvetica12_Character_082,Helvetica12_Character_083,Helvetica12_Character_084,Helvetica12_Character_085,Helvetica12_Character_086,Helvetica12_Character_087,Helvetica12_Character_088,Helvetica12_Character_089,Helvetica12_Character_090,Helvetica12_Character_091,Helvetica12_Character_092,Helvetica12_Character_093,Helvetica12_Character_094,Helvetica12_Character_095, + Helvetica12_Character_096,Helvetica12_Character_097,Helvetica12_Character_098,Helvetica12_Character_099,Helvetica12_Character_100,Helvetica12_Character_101,Helvetica12_Character_102,Helvetica12_Character_103,Helvetica12_Character_104,Helvetica12_Character_105,Helvetica12_Character_106,Helvetica12_Character_107,Helvetica12_Character_108,Helvetica12_Character_109,Helvetica12_Character_110,Helvetica12_Character_111, + Helvetica12_Character_112,Helvetica12_Character_113,Helvetica12_Character_114,Helvetica12_Character_115,Helvetica12_Character_116,Helvetica12_Character_117,Helvetica12_Character_118,Helvetica12_Character_119,Helvetica12_Character_120,Helvetica12_Character_121,Helvetica12_Character_122,Helvetica12_Character_123,Helvetica12_Character_124,Helvetica12_Character_125,Helvetica12_Character_126,Helvetica12_Character_032, + Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032, + Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032,Helvetica12_Character_032, + Helvetica12_Character_160,Helvetica12_Character_161,Helvetica12_Character_162,Helvetica12_Character_163,Helvetica12_Character_164,Helvetica12_Character_165,Helvetica12_Character_166,Helvetica12_Character_167,Helvetica12_Character_168,Helvetica12_Character_169,Helvetica12_Character_170,Helvetica12_Character_171,Helvetica12_Character_172,Helvetica12_Character_173,Helvetica12_Character_174,Helvetica12_Character_175, + Helvetica12_Character_176,Helvetica12_Character_177,Helvetica12_Character_178,Helvetica12_Character_179,Helvetica12_Character_180,Helvetica12_Character_181,Helvetica12_Character_182,Helvetica12_Character_183,Helvetica12_Character_184,Helvetica12_Character_185,Helvetica12_Character_186,Helvetica12_Character_187,Helvetica12_Character_188,Helvetica12_Character_189,Helvetica12_Character_190,Helvetica12_Character_191, + Helvetica12_Character_192,Helvetica12_Character_193,Helvetica12_Character_194,Helvetica12_Character_195,Helvetica12_Character_196,Helvetica12_Character_197,Helvetica12_Character_198,Helvetica12_Character_199,Helvetica12_Character_200,Helvetica12_Character_201,Helvetica12_Character_202,Helvetica12_Character_203,Helvetica12_Character_204,Helvetica12_Character_205,Helvetica12_Character_206,Helvetica12_Character_207, + Helvetica12_Character_208,Helvetica12_Character_209,Helvetica12_Character_210,Helvetica12_Character_211,Helvetica12_Character_212,Helvetica12_Character_213,Helvetica12_Character_214,Helvetica12_Character_215,Helvetica12_Character_216,Helvetica12_Character_217,Helvetica12_Character_218,Helvetica12_Character_219,Helvetica12_Character_220,Helvetica12_Character_221,Helvetica12_Character_222,Helvetica12_Character_223, + Helvetica12_Character_224,Helvetica12_Character_225,Helvetica12_Character_226,Helvetica12_Character_227,Helvetica12_Character_228,Helvetica12_Character_229,Helvetica12_Character_230,Helvetica12_Character_231,Helvetica12_Character_232,Helvetica12_Character_233,Helvetica12_Character_234,Helvetica12_Character_235,Helvetica12_Character_236,Helvetica12_Character_237,Helvetica12_Character_238,Helvetica12_Character_239, + Helvetica12_Character_240,Helvetica12_Character_241,Helvetica12_Character_242,Helvetica12_Character_243,Helvetica12_Character_244,Helvetica12_Character_245,Helvetica12_Character_246,Helvetica12_Character_247,Helvetica12_Character_248,Helvetica12_Character_249,Helvetica12_Character_250,Helvetica12_Character_251,Helvetica12_Character_252,Helvetica12_Character_253,Helvetica12_Character_254,Helvetica12_Character_255,NULL}; + +/* The font structure: */ +const SFG_Font fgFontHelvetica12 = { "-adobe-helvetica-medium-r-normal--12-120-75-75-p-67-iso8859-1", 256, 16, Helvetica12_Character_Map, 0, 4 }; + +static const GLubyte Helvetica18_Character_000[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 64, 16, 0, 0, 64, 16, 0, 0, 64, 16, 0, 0, 64, 16, 0, 0, 64, 16, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_001[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_002[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_003[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_004[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_005[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_006[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_007[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_008[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_009[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_010[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_011[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_012[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_013[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_014[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_015[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_016[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_017[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_018[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_019[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_020[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_021[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_022[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_023[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_024[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_025[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_026[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_027[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_028[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_029[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_030[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_031[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_032[] = { 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_033[] = { 6, 0, 0, 0, 0, 0, 48, 48, 0, 0, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_034[] = { 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,144,144,216,216,216, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_035[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 36, 0, 36, 0,255,128,255,128, 18, 0, 18, 0, 18, 0,127,192,127,192, 9, 0, 9, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_036[] = { 10, 0, 0, 0, 0, 0, 0, 4, 0, 4, 0, 31, 0, 63,128,117,192,100,192, 4,192, 7,128, 31, 0, 60, 0,116, 0,100, 0,101,128, 63,128, 31, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_037[] = { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 60, 12,126, 6,102, 6,102, 3,126, 3, 60, 1,128, 61,128,126,192,102,192,102, 96,126, 96, 60, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_038[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 56, 63,112,115,224, 97,192, 97,224, 99, 96,119, 96, 62, 0, 30, 0, 51, 0, 51, 0, 63, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_039[] = { 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 32, 32, 96, 96, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_040[] = { 6, 0, 8, 24, 48, 48, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 48, 48, 24, 8, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_041[] = { 6, 0, 64, 96, 48, 48, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 48, 48, 96, 64, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_042[] = { 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 56, 56,124, 16, 16, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_043[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 12, 0, 12, 0, 12, 0,127,128,127,128, 12, 0, 12, 0, 12, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_044[] = { 5, 0, 0, 64, 32, 32, 96, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_045[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,128,127,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_046[] = { 5, 0, 0, 0, 0, 0, 96, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_047[] = { 5, 0, 0, 0, 0, 0,192,192, 64, 64, 96, 96, 32, 32, 48, 48, 16, 16, 24, 24, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_048[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 63, 0, 51, 0, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128, 51, 0, 63, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_049[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 62, 0, 62, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_050[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,128,127,128, 96, 0,112, 0, 56, 0, 28, 0, 14, 0, 7, 0, 3,128, 1,128, 97,128,127, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_051[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 63, 0, 99,128, 97,128, 1,128, 3,128, 15, 0, 14, 0, 3, 0, 97,128, 97,128, 63, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_052[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,128, 1,128, 1,128,127,192,127,192, 97,128, 49,128, 25,128, 25,128, 13,128, 7,128, 3,128, 1,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_053[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0,127, 0, 99,128, 97,128, 1,128, 1,128, 99,128,127, 0,126, 0, 96, 0, 96, 0,127, 0,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_054[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 63, 0,113,128, 97,128, 97,128, 97,128,127, 0,110, 0, 96, 0, 96, 0, 49,128, 63,128, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_055[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 48, 0, 24, 0, 24, 0, 24, 0, 12, 0, 12, 0, 6, 0, 6, 0, 3, 0, 1,128,127,128,127,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_056[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 63, 0,115,128, 97,128, 97,128, 51, 0, 63, 0, 51, 0, 97,128, 97,128,115,128, 63, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_057[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0,127, 0, 99, 0, 1,128, 1,128, 29,128, 63,128, 97,128, 97,128, 97,128, 99,128, 63, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_058[] = { 5, 0, 0, 0, 0, 0, 96, 96, 0, 0, 0, 0, 0, 0, 96, 96, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_059[] = { 5, 0, 0, 64, 32, 32, 96, 96, 0, 0, 0, 0, 0, 0, 96, 96, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_060[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,128, 7,128, 30, 0, 56, 0, 96, 0, 56, 0, 30, 0, 7,128, 1,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_061[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 63,128, 0, 0, 0, 0, 63,128, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_062[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0,120, 0, 30, 0, 7, 0, 1,128, 7, 0, 30, 0,120, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_063[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 24, 0, 0, 0, 0, 0, 24, 0, 24, 0, 24, 0, 28, 0, 14, 0, 7, 0, 99, 0, 99, 0,127, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_064[] = { 18, 0, 0, 0, 0, 0, 0, 3,240, 0, 15,248, 0, 28, 0, 0, 56, 0, 0, 51,184, 0,103,252, 0,102,102, 0,102, 51, 0,102, 51, 0,102, 49,128, 99, 25,128, 51,185,128, 49,217,128, 24, 3, 0, 14, 7, 0, 7,254, 0, 1,248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_065[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,192, 48,192, 48, 96, 96, 96, 96,127,224, 63,192, 48,192, 48,192, 25,128, 25,128, 15, 0, 15, 0, 6, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_066[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,192,127,224, 96,112, 96, 48, 96, 48, 96,112,127,224,127,192, 96,192, 96, 96, 96, 96, 96,224,127,192,127,128, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_067[] = { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,192, 31,240, 56, 56, 48, 24,112, 0, 96, 0, 96, 0, 96, 0, 96, 0,112, 0, 48, 24, 56, 56, 31,240, 7,192, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_068[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,128,127,192, 96,224, 96, 96, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 96, 96,224,127,192,127,128, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_069[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,192,127,192, 96, 0, 96, 0, 96, 0, 96, 0,127,128,127,128, 96, 0, 96, 0, 96, 0, 96, 0,127,192,127,192, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_070[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0,127,128,127,128, 96, 0, 96, 0, 96, 0, 96, 0,127,192,127,192, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_071[] = { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,216, 31,248, 56, 56, 48, 24,112, 24, 96,248, 96,248, 96, 0, 96, 0,112, 24, 48, 24, 56, 56, 31,240, 7,192, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_072[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48,127,240,127,240, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_073[] = { 6, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_074[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 63, 0,115,128, 97,128, 97,128, 1,128, 1,128, 1,128, 1,128, 1,128, 1,128, 1,128, 1,128, 1,128, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_075[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 56, 96,112, 96,224, 97,192, 99,128,103, 0,126, 0,124, 0,110, 0,103, 0, 99,128, 97,192, 96,224, 96,112, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_076[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,128,127,128, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_077[] = { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97,134, 97,134, 99,198, 98, 70,102,102,102,102,108, 54,108, 54,120, 30,120, 30,112, 14,112, 14, 96, 6, 96, 6, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_078[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 48, 96,112, 96,240, 96,240, 97,176, 99, 48, 99, 48,102, 48,102, 48,108, 48,120, 48,120, 48,112, 48, 96, 48, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_079[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,192, 31,240, 56, 56, 48, 24,112, 28, 96, 12, 96, 12, 96, 12, 96, 12,112, 28, 48, 24, 56, 56, 31,240, 7,192, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_080[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0,127,128,127,192, 96,224, 96, 96, 96, 96, 96,224,127,192,127,128, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_081[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 7,216, 31,240, 56,120, 48,216,112,220, 96, 12, 96, 12, 96, 12, 96, 12,112, 28, 48, 24, 56, 56, 31,240, 7,192, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_082[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 96, 96, 96, 96, 96, 96, 96, 96,192, 96,192,127,128,127,192, 96,224, 96, 96, 96, 96, 96,224,127,192,127,128, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_083[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31,128, 63,224,112,112, 96, 48, 0, 48, 0,112, 1,224, 15,128, 62, 0,112, 0, 96, 48,112,112, 63,224, 15,128, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_084[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0,127,224,127,224, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_085[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15,128, 63,224, 48, 96, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_086[] = { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 7,128, 7,128, 12,192, 12,192, 12,192, 24, 96, 24, 96, 24, 96, 48, 48, 48, 48, 48, 48, 96, 24, 96, 24, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_087[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 0, 12, 12, 0, 14, 28, 0, 26, 22, 0, 27, 54, 0, 27, 54, 0, 51, 51, 0, 51, 51, 0, 49, 35, 0, 49,227, 0, 97,225,128, 96,193,128, 96,193,128, 96,193,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_088[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 48,112,112, 48, 96, 56,224, 24,192, 13,128, 7, 0, 7, 0, 13,128, 24,192, 56,224, 48, 96,112,112, 96, 48, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_089[] = { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 7,128, 12,192, 24, 96, 24, 96, 48, 48, 48, 48, 96, 24, 96, 24, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_090[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,224,127,224, 96, 0, 48, 0, 24, 0, 12, 0, 14, 0, 6, 0, 3, 0, 1,128, 0,192, 0, 96,127,224,127,224, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_091[] = { 5, 0,120,120, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,120,120, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_092[] = { 5, 0, 0, 0, 0, 0, 24, 24, 16, 16, 48, 48, 32, 32, 96, 96, 64, 64,192,192, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_093[] = { 5, 0,240,240, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,240,240, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_094[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 99, 0, 54, 0, 28, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_095[] = { 10, 0, 0,255,192,255,192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_096[] = { 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 96, 64, 64, 32, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_097[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0,119, 0, 99, 0, 99, 0,115, 0, 63, 0, 7, 0, 99, 0,119, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_098[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,111, 0,127,128,113,128, 96,192, 96,192, 96,192, 96,192,113,128,127,128,111, 0, 96, 0, 96, 0, 96, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_099[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 63,128, 49,128, 96, 0, 96, 0, 96, 0, 96, 0, 49,128, 63,128, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_100[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30,192, 63,192, 49,192, 96,192, 96,192, 96,192, 96,192, 49,192, 63,192, 30,192, 0,192, 0,192, 0,192, 0,192, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_101[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 63,128,113,128, 96, 0, 96, 0,127,128, 97,128, 97,128, 63, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_102[] = { 6, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48,252,252, 48, 48, 60, 28, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_103[] = { 11, 0, 0, 14, 0, 63,128, 49,128, 0,192, 30,192, 63,192, 49,192, 96,192, 96,192, 96,192, 96,192, 48,192, 63,192, 30,192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_104[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128,113,128,111,128,103, 0, 96, 0, 96, 0, 96, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_105[] = { 4, 0, 0, 0, 0, 0, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 0, 0, 96, 96, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_106[] = { 4, 0,192,224, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 0, 0, 96, 96, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_107[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99,128, 99, 0,103, 0,102, 0,108, 0,124, 0,120, 0,108, 0,102, 0, 99, 0, 96, 0, 96, 0, 96, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_108[] = { 4, 0, 0, 0, 0, 0, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_109[] = { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99, 24, 99, 24, 99, 24, 99, 24, 99, 24, 99, 24, 99, 24,115,152,111,120,102, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_110[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128,113,128,111,128,103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_111[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 63,128, 49,128, 96,192, 96,192, 96,192, 96,192, 49,128, 63,128, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_112[] = { 11, 0, 0, 96, 0, 96, 0, 96, 0, 96, 0,111, 0,127,128,113,128, 96,192, 96,192, 96,192, 96,192,113,128,127,128,111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_113[] = { 11, 0, 0, 0,192, 0,192, 0,192, 0,192, 30,192, 63,192, 49,192, 96,192, 96,192, 96,192, 96,192, 49,192, 63,192, 30,192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_114[] = { 6, 0, 0, 0, 0, 0, 96, 96, 96, 96, 96, 96, 96,112,108,108, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_115[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 0,126, 0, 99, 0, 3, 0, 31, 0,126, 0, 96, 0, 99, 0, 63, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_116[] = { 6, 0, 0, 0, 0, 0, 24, 56, 48, 48, 48, 48, 48, 48,252,252, 48, 48, 48, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_117[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57,128,125,128, 99,128, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_118[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 12, 0, 30, 0, 18, 0, 51, 0, 51, 0, 51, 0, 97,128, 97,128, 97,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_119[] = { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12,192, 12,192, 28,224, 20,160, 52,176, 51, 48, 51, 48, 99, 24, 99, 24, 99, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_120[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97,128,115,128, 51, 0, 30, 0, 12, 0, 12, 0, 30, 0, 51, 0,115,128, 97,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_121[] = { 10, 0, 0, 56, 0, 56, 0, 12, 0, 12, 0, 12, 0, 12, 0, 30, 0, 18, 0, 51, 0, 51, 0, 51, 0, 97,128, 97,128, 97,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_122[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127, 0,127, 0, 96, 0, 48, 0, 24, 0, 12, 0, 6, 0, 3, 0,127, 0,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_123[] = { 6, 0, 12, 24, 48, 48, 48, 48, 48, 48, 96,192, 96, 48, 48, 48, 48, 48, 24, 12, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_124[] = { 4, 0, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_125[] = { 6, 0,192, 96, 48, 48, 48, 48, 48, 48, 24, 12, 24, 48, 48, 48, 48, 48, 96,192, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_126[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,102, 0, 63, 0, 25,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_127[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_128[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_129[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_130[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_131[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_132[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_133[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_134[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_135[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_136[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_137[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_138[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_139[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_140[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_141[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_142[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_143[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_144[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_145[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_146[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_147[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_148[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_149[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_150[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_151[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_152[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_153[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_154[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_155[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_156[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_157[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_158[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_159[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 85, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_160[] = { 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_161[] = { 6, 0, 48, 48, 48, 48, 48, 48, 48, 48, 16, 16, 0, 0, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_162[] = { 10, 0, 0, 0, 0, 0, 0, 8, 0, 8, 0, 31, 0, 63,128, 53,128,100, 0,100, 0,100, 0,100, 0, 53,128, 63,128, 31, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_163[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,223, 0,255,128, 96,128, 48, 0, 24, 0, 24, 0,126, 0, 48, 0, 96, 0, 97,128, 97,128, 63, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_164[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97,128,127,128, 51, 0, 51, 0, 51, 0,127,128, 97,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_165[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 12, 0, 12, 0, 12, 0,127,128, 12, 0,127,128, 30, 0, 51, 0, 51, 0, 51, 0, 97,128, 97,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_166[] = { 4, 0, 0, 96, 96, 96, 96, 96, 96, 0, 0, 0, 0, 96, 96, 96, 96, 96, 96, 96, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_167[] = { 10, 0, 0, 30, 0, 63, 0, 97,128, 97,128, 3,128, 7, 0, 31, 0, 57,128,113,128, 97,128, 99,128, 55, 0, 62, 0,120, 0, 97,128, 97,128, 63, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_168[] = { 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,216,216, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_169[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,192, 24, 48, 32, 8, 35,136, 68, 68, 72, 4, 72, 4, 72, 4, 68, 68, 35,136, 32, 8, 24, 48, 7,192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_170[] = { 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,124, 0, 52,108, 36, 28,100, 56, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_171[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 27, 0, 54, 0,108, 0,108, 0, 54, 0, 27, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_172[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,192, 0,192, 0,192,127,192,127,192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_173[] = { 7, 0, 0, 0, 0, 0, 0, 0, 0, 0,124,124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_174[] = { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,192, 24, 48, 32, 8, 36, 40, 68, 68, 68,132, 71,196, 68, 36, 68, 36, 39,200, 32, 8, 24, 48, 7,192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_175[] = { 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,248, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_176[] = { 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56,108, 68,108, 56, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_177[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,128,127,128, 0, 0, 12, 0, 12, 0, 12, 0,127,128,127,128, 12, 0, 12, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_178[] = { 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,248,248, 96, 48, 24,152,248,112, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_179[] = { 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,112,248,152, 48, 48,152,248,112, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_180[] = { 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,192, 96, 48, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_181[] = { 10, 0, 0, 96, 0, 96, 0, 96, 0, 96, 0,109,128,127,128,115,128, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_182[] = { 10, 0, 0, 9, 0, 9, 0, 9, 0, 9, 0, 9, 0, 9, 0, 9, 0, 9, 0, 9, 0, 9, 0, 25, 0, 57, 0,121, 0,121, 0,121, 0,121, 0, 57, 0, 31,128, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_183[] = { 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_184[] = { 5, 0,240,216, 24,112, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_185[] = { 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48,112,112, 48, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_186[] = { 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,124, 0, 56,108, 68, 68,108, 56, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_187[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 0,108, 0, 54, 0, 27, 0, 27, 0, 54, 0,108, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_188[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 24, 24, 24, 12,252, 6,216, 6,120, 51, 56, 49, 24, 49,136, 48,192, 48,192,112, 96,112, 48, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_189[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24,124, 24,124, 12, 48, 6, 24, 6, 12, 51, 76, 49,124, 49,184, 48,192, 48,192,112, 96,112, 48, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_190[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 24, 24, 24, 12,252, 6,216, 6,120,115, 56,249, 24,153,136, 48,192, 48,192,152, 96,248, 48,112, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_191[] = { 10, 0, 0, 62, 0,127, 0, 99, 0, 99, 0,112, 0, 56, 0, 28, 0, 12, 0, 12, 0, 12, 0, 0, 0, 0, 0, 12, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_192[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,192, 48,192, 48, 96, 96, 96, 96,127,224, 63,192, 48,192, 48,192, 25,128, 25,128, 15, 0, 15, 0, 6, 0, 6, 0, 0, 0, 6, 0, 12, 0, 24, 0}; +static const GLubyte Helvetica18_Character_193[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,192, 48,192, 48, 96, 96, 96, 96,127,224, 63,192, 48,192, 48,192, 25,128, 25,128, 15, 0, 15, 0, 6, 0, 6, 0, 0, 0, 6, 0, 3, 0, 1,128}; +static const GLubyte Helvetica18_Character_194[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,192, 48,192, 48, 96, 96, 96, 96,127,224, 63,192, 48,192, 48,192, 25,128, 25,128, 15, 0, 15, 0, 6, 0, 6, 0, 0, 0, 25,128, 15, 0, 6, 0}; +static const GLubyte Helvetica18_Character_195[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,192, 48,192, 48, 96, 96, 96, 96,127,224, 63,192, 48,192, 48,192, 25,128, 25,128, 15, 0, 15, 0, 6, 0, 6, 0, 0, 0, 19, 0, 22,128, 12,128}; +static const GLubyte Helvetica18_Character_196[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,192, 48,192, 48, 96, 96, 96, 96,127,224, 63,192, 48,192, 48,192, 25,128, 25,128, 15, 0, 15, 0, 6, 0, 6, 0, 0, 0, 25,128, 25,128, 0, 0}; +static const GLubyte Helvetica18_Character_197[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,192, 48,192, 48, 96, 96, 96, 96,127,224, 63,192, 48,192, 48,192, 25,128, 25,128, 15, 0, 15, 0, 6, 0, 6, 0, 15, 0, 25,128, 25,128, 15, 0}; +static const GLubyte Helvetica18_Character_198[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96,255,128, 96,255,128, 48,192, 0, 48,192, 0, 63,192, 0, 31,192, 0, 24,255, 0, 24,255, 0, 12,192, 0, 12,192, 0, 6,192, 0, 6,192, 0, 3,255,128, 3,255,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_199[] = { 14, 0, 0, 15, 0, 13,128, 1,128, 7, 0, 7,192, 31,240, 56, 56, 48, 24,112, 0, 96, 0, 96, 0, 96, 0, 96, 0,112, 0, 48, 24, 56, 56, 31,240, 7,192, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_200[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,192,127,192, 96, 0, 96, 0, 96, 0, 96, 0,127,128,127,128, 96, 0, 96, 0, 96, 0, 96, 0,127,192,127,192, 0, 0, 6, 0, 12, 0, 24, 0}; +static const GLubyte Helvetica18_Character_201[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,192,127,192, 96, 0, 96, 0, 96, 0, 96, 0,127,128,127,128, 96, 0, 96, 0, 96, 0, 96, 0,127,192,127,192, 0, 0, 6, 0, 3, 0, 1,128}; +static const GLubyte Helvetica18_Character_202[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,192,127,192, 96, 0, 96, 0, 96, 0, 96, 0,127,128,127,128, 96, 0, 96, 0, 96, 0, 96, 0,127,192,127,192, 0, 0, 25,128, 15, 0, 6, 0}; +static const GLubyte Helvetica18_Character_203[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,192,127,192, 96, 0, 96, 0, 96, 0, 96, 0,127,128,127,128, 96, 0, 96, 0, 96, 0, 96, 0,127,192,127,192, 0, 0, 25,128, 25,128, 0, 0}; +static const GLubyte Helvetica18_Character_204[] = { 6, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 48, 96,192}; +static const GLubyte Helvetica18_Character_205[] = { 6, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 48, 24, 12}; +static const GLubyte Helvetica18_Character_206[] = { 6, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0,204,120, 48}; +static const GLubyte Helvetica18_Character_207[] = { 6, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0,204,204, 0}; +static const GLubyte Helvetica18_Character_208[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,128,127,192, 96,224, 96, 96, 96, 48, 96, 48,252, 48,252, 48, 96, 48, 96, 48, 96, 96, 96,224,127,192,127,128, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_209[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 48, 96,112, 96,240, 96,240, 97,176, 99, 48, 99, 48,102, 48,102, 48,108, 48,108, 48,120, 48,112, 48,112, 48, 0, 0, 9,128, 11, 64, 6, 64}; +static const GLubyte Helvetica18_Character_210[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,192, 31,240, 56, 56, 48, 24,112, 28, 96, 12, 96, 12, 96, 12, 96, 12,112, 28, 48, 24, 56, 56, 31,240, 7,192, 0, 0, 1,128, 3, 0, 6, 0}; +static const GLubyte Helvetica18_Character_211[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,192, 31,240, 56, 56, 48, 24,112, 28, 96, 12, 96, 12, 96, 12, 96, 12,112, 28, 48, 24, 56, 56, 31,240, 7,192, 0, 0, 1,128, 0,192, 0, 96}; +static const GLubyte Helvetica18_Character_212[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,192, 31,240, 56, 56, 48, 24,112, 28, 96, 12, 96, 12, 96, 12, 96, 12,112, 28, 48, 24, 56, 56, 31,240, 7,192, 0, 0, 6, 96, 3,192, 1,128}; +static const GLubyte Helvetica18_Character_213[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,192, 31,240, 56, 56, 48, 24,112, 28, 96, 12, 96, 12, 96, 12, 96, 12,112, 28, 48, 24, 56, 56, 31,240, 7,192, 0, 0, 4,192, 5,160, 3, 32}; +static const GLubyte Helvetica18_Character_214[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,192, 31,240, 56, 56, 48, 24,112, 28, 96, 12, 96, 12, 96, 12, 96, 12,112, 28, 48, 24, 56, 56, 31,240, 7,192, 0, 0, 6,192, 6,192, 0, 0}; +static const GLubyte Helvetica18_Character_215[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,192,192, 97,128, 51, 0, 30, 0, 12, 0, 30, 0, 51, 0, 97,128,192,192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_216[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,199,192,255,240,120, 56, 56, 24,108, 28,110, 12,103, 12, 99,140, 97,204,112,220, 48,120, 56, 56, 31,252, 7,204, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_217[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15,128, 63,224, 48, 96, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 0, 0, 3, 0, 6, 0, 12, 0}; +static const GLubyte Helvetica18_Character_218[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15,128, 63,224, 48, 96, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 0, 0, 6, 0, 3, 0, 1,128}; +static const GLubyte Helvetica18_Character_219[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15,128, 63,224, 48, 96, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 0, 0, 12,192, 7,128, 3, 0}; +static const GLubyte Helvetica18_Character_220[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15,128, 63,224, 48, 96, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 0, 0, 12,192, 12,192, 0, 0}; +static const GLubyte Helvetica18_Character_221[] = { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 7,128, 12,192, 24, 96, 24, 96, 48, 48, 48, 48, 96, 24, 96, 24, 0, 0, 3, 0, 1,128, 0,192}; +static const GLubyte Helvetica18_Character_222[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, 96, 0, 96, 0,127,128,127,192, 96,224, 96, 96, 96, 96, 96,224,127,192,127,128, 96, 0, 96, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_223[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,110, 0,111, 0, 99, 0, 99, 0, 99, 0, 99, 0,110, 0,110, 0, 99, 0, 99, 0, 99, 0, 99, 0, 62, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_224[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0,119, 0, 99, 0, 99, 0,115, 0, 63, 0, 7, 0, 99, 0,119, 0, 62, 0, 0, 0, 12, 0, 24, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_225[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0,119, 0, 99, 0, 99, 0,115, 0, 63, 0, 7, 0, 99, 0,119, 0, 62, 0, 0, 0, 24, 0, 12, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_226[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0,119, 0, 99, 0, 99, 0,115, 0, 63, 0, 7, 0, 99, 0,119, 0, 62, 0, 0, 0, 51, 0, 30, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_227[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0,119, 0, 99, 0, 99, 0,115, 0, 63, 0, 7, 0, 99, 0,119, 0, 62, 0, 0, 0, 38, 0, 45, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_228[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0,119, 0, 99, 0, 99, 0,115, 0, 63, 0, 7, 0, 99, 0,119, 0, 62, 0, 0, 0, 54, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_229[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0,119, 0, 99, 0, 99, 0,115, 0, 63, 0, 7, 0, 99, 0,119, 0, 62, 0, 28, 0, 54, 0, 54, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_230[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58,240,119,252, 99,140, 99, 0,115, 0, 63,252, 7, 12, 99, 12,119,248, 62,240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_231[] = { 10, 0, 0, 60, 0, 54, 0, 6, 0, 28, 0, 31, 0, 63,128, 49,128, 96, 0, 96, 0, 96, 0, 96, 0, 49,128, 63,128, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_232[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 63,128,113,128, 96, 0, 96, 0,127,128, 97,128, 97,128, 63, 0, 30, 0, 0, 0, 12, 0, 24, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_233[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 63,128,113,128, 96, 0, 96, 0,127,128, 97,128, 97,128, 63, 0, 30, 0, 0, 0, 12, 0, 6, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_234[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 63,128,113,128, 96, 0, 96, 0,127,128, 97,128, 97,128, 63, 0, 30, 0, 0, 0, 51, 0, 30, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_235[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 63,128,113,128, 96, 0, 96, 0,127,128, 97,128, 97,128, 63, 0, 30, 0, 0, 0, 27, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_236[] = { 4, 0, 0, 0, 0, 0, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 0, 48, 96,192, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_237[] = { 4, 0, 0, 0, 0, 0, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 0,192, 96, 48, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_238[] = { 4, 0, 0, 0, 0, 0, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 0,144,240, 96, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_239[] = { 4, 0, 0, 0, 0, 0, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 0,216,216, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_240[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 63,128, 49,128, 96,192, 96,192, 96,192, 96,192, 49,128, 63,128, 31, 0, 38, 0, 28, 0, 27, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_241[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128,113,128,111,128,103, 0, 0, 0, 38, 0, 45, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_242[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 63,128, 49,128, 96,192, 96,192, 96,192, 96,192, 49,128, 63,128, 31, 0, 0, 0, 6, 0, 12, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_243[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 63,128, 49,128, 96,192, 96,192, 96,192, 96,192, 49,128, 63,128, 31, 0, 0, 0, 12, 0, 6, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_244[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 63,128, 49,128, 96,192, 96,192, 96,192, 96,192, 49,128, 63,128, 31, 0, 0, 0, 25,128, 15, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_245[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 63,128, 49,128, 96,192, 96,192, 96,192, 96,192, 49,128, 63,128, 31, 0, 0, 0, 19, 0, 22,128, 12,128, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_246[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 63,128, 49,128, 96,192, 96,192, 96,192, 96,192, 49,128, 63,128, 31, 0, 0, 0, 27, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_247[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 12, 0, 0, 0,127,128,127,128, 0, 0, 12, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_248[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,206, 0,127,128, 49,128,120,192,108,192,102,192, 99,192, 49,128, 63,192, 14, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_249[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57,128,125,128, 99,128, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128, 0, 0, 6, 0, 12, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_250[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57,128,125,128, 99,128, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128, 0, 0, 12, 0, 6, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_251[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57,128,125,128, 99,128, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128, 0, 0, 51, 0, 30, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_252[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57,128,125,128, 99,128, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128, 97,128, 0, 0, 51, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_253[] = { 10, 0, 0, 56, 0, 56, 0, 12, 0, 12, 0, 12, 0, 12, 0, 30, 0, 18, 0, 51, 0, 51, 0, 51, 0, 97,128, 97,128, 97,128, 0, 0, 12, 0, 6, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_254[] = { 11, 0, 0, 96, 0, 96, 0, 96, 0, 96, 0,111, 0,127,128,113,128, 96,192, 96,192, 96,192, 96,192,113,128,127,128,111, 0, 96, 0, 96, 0, 96, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte Helvetica18_Character_255[] = { 10, 0, 0, 56, 0, 56, 0, 12, 0, 12, 0, 12, 0, 12, 0, 30, 0, 18, 0, 51, 0, 51, 0, 51, 0, 97,128, 97,128, 97,128, 0, 0, 51, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +/* The font characters mapping: */ +static const GLubyte* Helvetica18_Character_Map[] = {Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032, + Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032, + Helvetica18_Character_032,Helvetica18_Character_033,Helvetica18_Character_034,Helvetica18_Character_035,Helvetica18_Character_036,Helvetica18_Character_037,Helvetica18_Character_038,Helvetica18_Character_039,Helvetica18_Character_040,Helvetica18_Character_041,Helvetica18_Character_042,Helvetica18_Character_043,Helvetica18_Character_044,Helvetica18_Character_045,Helvetica18_Character_046,Helvetica18_Character_047, + Helvetica18_Character_048,Helvetica18_Character_049,Helvetica18_Character_050,Helvetica18_Character_051,Helvetica18_Character_052,Helvetica18_Character_053,Helvetica18_Character_054,Helvetica18_Character_055,Helvetica18_Character_056,Helvetica18_Character_057,Helvetica18_Character_058,Helvetica18_Character_059,Helvetica18_Character_060,Helvetica18_Character_061,Helvetica18_Character_062,Helvetica18_Character_063, + Helvetica18_Character_064,Helvetica18_Character_065,Helvetica18_Character_066,Helvetica18_Character_067,Helvetica18_Character_068,Helvetica18_Character_069,Helvetica18_Character_070,Helvetica18_Character_071,Helvetica18_Character_072,Helvetica18_Character_073,Helvetica18_Character_074,Helvetica18_Character_075,Helvetica18_Character_076,Helvetica18_Character_077,Helvetica18_Character_078,Helvetica18_Character_079, + Helvetica18_Character_080,Helvetica18_Character_081,Helvetica18_Character_082,Helvetica18_Character_083,Helvetica18_Character_084,Helvetica18_Character_085,Helvetica18_Character_086,Helvetica18_Character_087,Helvetica18_Character_088,Helvetica18_Character_089,Helvetica18_Character_090,Helvetica18_Character_091,Helvetica18_Character_092,Helvetica18_Character_093,Helvetica18_Character_094,Helvetica18_Character_095, + Helvetica18_Character_096,Helvetica18_Character_097,Helvetica18_Character_098,Helvetica18_Character_099,Helvetica18_Character_100,Helvetica18_Character_101,Helvetica18_Character_102,Helvetica18_Character_103,Helvetica18_Character_104,Helvetica18_Character_105,Helvetica18_Character_106,Helvetica18_Character_107,Helvetica18_Character_108,Helvetica18_Character_109,Helvetica18_Character_110,Helvetica18_Character_111, + Helvetica18_Character_112,Helvetica18_Character_113,Helvetica18_Character_114,Helvetica18_Character_115,Helvetica18_Character_116,Helvetica18_Character_117,Helvetica18_Character_118,Helvetica18_Character_119,Helvetica18_Character_120,Helvetica18_Character_121,Helvetica18_Character_122,Helvetica18_Character_123,Helvetica18_Character_124,Helvetica18_Character_125,Helvetica18_Character_126,Helvetica18_Character_032, + Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032, + Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032,Helvetica18_Character_032, + Helvetica18_Character_160,Helvetica18_Character_161,Helvetica18_Character_162,Helvetica18_Character_163,Helvetica18_Character_164,Helvetica18_Character_165,Helvetica18_Character_166,Helvetica18_Character_167,Helvetica18_Character_168,Helvetica18_Character_169,Helvetica18_Character_170,Helvetica18_Character_171,Helvetica18_Character_172,Helvetica18_Character_173,Helvetica18_Character_174,Helvetica18_Character_175, + Helvetica18_Character_176,Helvetica18_Character_177,Helvetica18_Character_178,Helvetica18_Character_179,Helvetica18_Character_180,Helvetica18_Character_181,Helvetica18_Character_182,Helvetica18_Character_183,Helvetica18_Character_184,Helvetica18_Character_185,Helvetica18_Character_186,Helvetica18_Character_187,Helvetica18_Character_188,Helvetica18_Character_189,Helvetica18_Character_190,Helvetica18_Character_191, + Helvetica18_Character_192,Helvetica18_Character_193,Helvetica18_Character_194,Helvetica18_Character_195,Helvetica18_Character_196,Helvetica18_Character_197,Helvetica18_Character_198,Helvetica18_Character_199,Helvetica18_Character_200,Helvetica18_Character_201,Helvetica18_Character_202,Helvetica18_Character_203,Helvetica18_Character_204,Helvetica18_Character_205,Helvetica18_Character_206,Helvetica18_Character_207, + Helvetica18_Character_208,Helvetica18_Character_209,Helvetica18_Character_210,Helvetica18_Character_211,Helvetica18_Character_212,Helvetica18_Character_213,Helvetica18_Character_214,Helvetica18_Character_215,Helvetica18_Character_216,Helvetica18_Character_217,Helvetica18_Character_218,Helvetica18_Character_219,Helvetica18_Character_220,Helvetica18_Character_221,Helvetica18_Character_222,Helvetica18_Character_223, + Helvetica18_Character_224,Helvetica18_Character_225,Helvetica18_Character_226,Helvetica18_Character_227,Helvetica18_Character_228,Helvetica18_Character_229,Helvetica18_Character_230,Helvetica18_Character_231,Helvetica18_Character_232,Helvetica18_Character_233,Helvetica18_Character_234,Helvetica18_Character_235,Helvetica18_Character_236,Helvetica18_Character_237,Helvetica18_Character_238,Helvetica18_Character_239, + Helvetica18_Character_240,Helvetica18_Character_241,Helvetica18_Character_242,Helvetica18_Character_243,Helvetica18_Character_244,Helvetica18_Character_245,Helvetica18_Character_246,Helvetica18_Character_247,Helvetica18_Character_248,Helvetica18_Character_249,Helvetica18_Character_250,Helvetica18_Character_251,Helvetica18_Character_252,Helvetica18_Character_253,Helvetica18_Character_254,Helvetica18_Character_255,NULL}; + +/* The font structure: */ +const SFG_Font fgFontHelvetica18 = { "-adobe-helvetica-medium-r-normal--18-180-75-75-p-98-iso8859-1", 256, 23, Helvetica18_Character_Map, 0, 5 }; + +static const GLubyte TimesRoman10_Character_000[] = { 8, 0, 0, 0, 0,170, 0,130, 0,130, 0,170, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_001[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_002[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_003[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_004[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_005[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_006[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_007[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_008[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_009[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_010[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_011[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_012[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_013[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_014[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_015[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_016[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_017[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_018[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_019[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_020[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_021[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_022[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_023[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_024[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_025[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_026[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_027[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_028[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_029[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_030[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_031[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_032[] = { 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_033[] = { 3, 0, 0, 0, 0, 64, 0, 64, 64, 64, 64, 64, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_034[] = { 4, 0, 0, 0, 0, 0, 0, 0, 0, 0,160,160, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_035[] = { 5, 0, 0, 0, 0, 80, 80,248, 80,248, 80, 80, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_036[] = { 5, 0, 0, 0, 32,224,144, 16, 96,128,144,112, 32, 0, 0}; +static const GLubyte TimesRoman10_Character_037[] = { 8, 0, 0, 0, 0, 68, 42, 42, 86,168,164,126, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_038[] = { 8, 0, 0, 0, 0,118,141,152,116,110, 80, 48, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_039[] = { 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64,192, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_040[] = { 4, 0, 0, 32, 64, 64,128,128,128, 64, 64, 32, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_041[] = { 4, 0, 0,128, 64, 64, 32, 32, 32, 64, 64,128, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_042[] = { 5, 0, 0, 0, 0, 0, 0, 0, 0,160, 64,160, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_043[] = { 6, 0, 0, 0, 0, 32, 32,248, 32, 32, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_044[] = { 3, 0, 0, 64, 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_045[] = { 7, 0, 0, 0, 0, 0, 0,120, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_046[] = { 3, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_047[] = { 3, 0, 0, 0, 0,128,128, 64, 64, 64, 32, 32, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_048[] = { 5, 0, 0, 0, 0, 96,144,144,144,144,144, 96, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_049[] = { 5, 0, 0, 0, 0,112, 32, 32, 32, 32, 96, 32, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_050[] = { 5, 0, 0, 0, 0,240, 64, 32, 32, 16,144, 96, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_051[] = { 5, 0, 0, 0, 0,224, 16, 16, 96, 16,144, 96, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_052[] = { 5, 0, 0, 0, 0, 16, 16,248,144, 80, 48, 16, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_053[] = { 5, 0, 0, 0, 0,224,144, 16, 16,224, 64,112, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_054[] = { 5, 0, 0, 0, 0, 96,144,144,144,224, 64, 48, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_055[] = { 5, 0, 0, 0, 0, 64, 64, 64, 32, 32,144,240, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_056[] = { 5, 0, 0, 0, 0, 96,144,144, 96,144,144, 96, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_057[] = { 5, 0, 0, 0, 0,192, 32,112,144,144,144, 96, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_058[] = { 3, 0, 0, 0, 0, 64, 0, 0, 0, 64, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_059[] = { 3, 0, 0, 64, 64, 64, 0, 0, 0, 64, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_060[] = { 5, 0, 0, 0, 0, 16, 32, 64, 32, 16, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_061[] = { 6, 0, 0, 0, 0, 0,248, 0,248, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_062[] = { 5, 0, 0, 0, 0,128, 64, 32, 64,128, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_063[] = { 4, 0, 0, 0, 0, 64, 0, 64, 64, 32,160,224, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_064[] = { 9, 0, 0, 0, 0, 62, 0, 64, 0,146, 0,173, 0,165, 0,165, 0,157, 0, 66, 0, 60, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_065[] = { 8, 0, 0, 0, 0,238, 68,124, 40, 40, 56, 16, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_066[] = { 6, 0, 0, 0, 0,240, 72, 72,112, 72, 72,240, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_067[] = { 7, 0, 0, 0, 0,120,196,128,128,128,196,124, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_068[] = { 7, 0, 0, 0, 0,248, 76, 68, 68, 68, 76,248, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_069[] = { 6, 0, 0, 0, 0,248, 72, 64,112, 64, 72,248, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_070[] = { 6, 0, 0, 0, 0,224, 64, 64,112, 64, 72,248, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_071[] = { 7, 0, 0, 0, 0,120,196,132,156,128,196,124, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_072[] = { 8, 0, 0, 0, 0,238, 68, 68,124, 68, 68,238, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_073[] = { 4, 0, 0, 0, 0,224, 64, 64, 64, 64, 64,224, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_074[] = { 4, 0, 0, 0, 0,192,160, 32, 32, 32, 32,112, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_075[] = { 7, 0, 0, 0, 0,236, 72, 80, 96, 80, 72,236, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_076[] = { 6, 0, 0, 0, 0,248, 72, 64, 64, 64, 64,224, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_077[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0,235,128, 73, 0, 85, 0, 85, 0, 99, 0, 99, 0,227,128, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_078[] = { 8, 0, 0, 0, 0,228, 76, 76, 84, 84,100,238, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_079[] = { 7, 0, 0, 0, 0,120,204,132,132,132,204,120, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_080[] = { 6, 0, 0, 0, 0,224, 64, 64,112, 72, 72,240, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_081[] = { 7, 0, 0, 12, 24,112,204,132,132,132,204,120, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_082[] = { 7, 0, 0, 0, 0,236, 72, 80,112, 72, 72,240, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_083[] = { 5, 0, 0, 0, 0,224,144, 16, 96,192,144,112, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_084[] = { 6, 0, 0, 0, 0,112, 32, 32, 32, 32,168,248, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_085[] = { 8, 0, 0, 0, 0, 56,108, 68, 68, 68, 68,238, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_086[] = { 8, 0, 0, 0, 0, 16, 16, 40, 40,108, 68,238, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_087[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 34, 0, 34, 0, 85, 0, 85, 0,201,128,136,128,221,192, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_088[] = { 8, 0, 0, 0, 0,238, 68, 40, 16, 40, 68,238, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_089[] = { 8, 0, 0, 0, 0, 56, 16, 16, 40, 40, 68,238, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_090[] = { 6, 0, 0, 0, 0,248,136, 64, 32, 16,136,248, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_091[] = { 3, 0, 0,192,128,128,128,128,128,128,128,192, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_092[] = { 3, 0, 0, 0, 0, 32, 32, 64, 64, 64,128,128, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_093[] = { 3, 0, 0,192, 64, 64, 64, 64, 64, 64, 64,192, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_094[] = { 5, 0, 0, 0, 0, 0, 0, 0, 0, 80, 80, 32, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_095[] = { 5, 0,248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_096[] = { 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,192,128, 0, 0}; +static const GLubyte TimesRoman10_Character_097[] = { 4, 0, 0, 0, 0,224,160, 96, 32,192, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_098[] = { 5, 0, 0, 0, 0,224,144,144,144,224,128,128, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_099[] = { 4, 0, 0, 0, 0, 96,128,128,128, 96, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_100[] = { 5, 0, 0, 0, 0,104,144,144,144,112, 16, 48, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_101[] = { 4, 0, 0, 0, 0, 96,128,192,160, 96, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_102[] = { 4, 0, 0, 0, 0,224, 64, 64, 64,224, 64, 48, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_103[] = { 5, 0, 0,224,144, 96, 64,160,160,112, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_104[] = { 5, 0, 0, 0, 0,216,144,144,144,224,128,128, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_105[] = { 3, 0, 0, 0, 0, 64, 64, 64, 64,192, 0, 64, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_106[] = { 3, 0, 0,128, 64, 64, 64, 64, 64,192, 0, 64, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_107[] = { 5, 0, 0, 0, 0,152,144,224,160,144,128,128, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_108[] = { 4, 0, 0, 0, 0,224, 64, 64, 64, 64, 64,192, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_109[] = { 8, 0, 0, 0, 0,219,146,146,146,236, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_110[] = { 5, 0, 0, 0, 0,216,144,144,144,224, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_111[] = { 5, 0, 0, 0, 0, 96,144,144,144, 96, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_112[] = { 5, 0, 0,192,128,224,144,144,144,224, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_113[] = { 5, 0, 0, 56, 16,112,144,144,144,112, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_114[] = { 4, 0, 0, 0, 0,224, 64, 64, 96,160, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_115[] = { 4, 0, 0, 0, 0,224, 32, 96,128,224, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_116[] = { 4, 0, 0, 0, 0, 48, 64, 64, 64,224, 64, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_117[] = { 5, 0, 0, 0, 0,104,144,144,144,144, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_118[] = { 5, 0, 0, 0, 0, 32, 96, 80,144,216, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_119[] = { 8, 0, 0, 0, 0, 40,108, 84,146,219, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_120[] = { 6, 0, 0, 0, 0,216, 80, 32, 80,216, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_121[] = { 5, 0, 0,128,128, 64, 96,160,144,184, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_122[] = { 5, 0, 0, 0, 0,240,144, 64, 32,240, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_123[] = { 4, 0, 0, 32, 64, 64, 64,128, 64, 64, 64, 32, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_124[] = { 2, 0, 0,128,128,128,128,128,128,128,128,128, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_125[] = { 4, 0, 0,128, 64, 64, 64, 32, 64, 64, 64,128, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_126[] = { 7, 0, 0, 0, 0, 0, 0,152,100, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_127[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_128[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_129[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_130[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_131[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_132[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_133[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_134[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_135[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_136[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_137[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_138[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_139[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_140[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_141[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_142[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_143[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_144[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_145[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_146[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_147[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_148[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_149[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_150[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_151[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_152[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_153[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_154[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_155[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_156[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_157[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_158[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_159[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0,170, 0, 0, 0,130, 0, 0, 0,130, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_160[] = { 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_161[] = { 3, 0, 0, 64, 64, 64, 64, 64, 0, 64, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_162[] = { 5, 0, 0, 0,128,224,144,128,144,112, 16, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_163[] = { 5, 0, 0, 0, 0,240,200, 64,224, 64, 80, 48, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_164[] = { 5, 0, 0, 0, 0, 0,136,112, 80, 80,112,136, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_165[] = { 5, 0, 0, 0, 0,112, 32,248, 32,216, 80,136, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_166[] = { 2, 0, 0, 0, 0,128,128,128, 0,128,128,128, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_167[] = { 5, 0, 0, 0,224,144, 32, 80,144,160, 64,144,112, 0, 0}; +static const GLubyte TimesRoman10_Character_168[] = { 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_169[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 34, 0, 77, 0, 81, 0, 77, 0, 34, 0, 28, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_170[] = { 4, 0, 0, 0, 0, 0, 0,224, 0,160, 32,192, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_171[] = { 5, 0, 0, 0, 0, 0, 80,160,160, 80, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_172[] = { 7, 0, 0, 0, 0, 0, 4, 4,124, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_173[] = { 4, 0, 0, 0, 0, 0, 0,224, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_174[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 34, 0, 85, 0, 89, 0, 93, 0, 34, 0, 28, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_175[] = { 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,224, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_176[] = { 4, 0, 0, 0, 0, 0, 0, 0, 96,144,144, 96, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_177[] = { 6, 0, 0, 0, 0,248, 0, 32, 32,248, 32, 32, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_178[] = { 3, 0, 0, 0, 0, 0, 0, 0,224, 64,160, 96, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_179[] = { 3, 0, 0, 0, 0, 0, 0, 0,192, 32, 64,224, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_180[] = { 3, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 64, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_181[] = { 5, 0, 0,128,128,232,144,144,144,144, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_182[] = { 6, 0, 0, 40, 40, 40, 40,104,232,232,232,124, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_183[] = { 2, 0, 0, 0, 0, 0, 0,128, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_184[] = { 4, 0,192, 32, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_185[] = { 3, 0, 0, 0, 0, 0, 0, 0,224, 64,192, 64, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_186[] = { 4, 0, 0, 0, 0, 0, 0,224, 0, 64,160, 64, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_187[] = { 5, 0, 0, 0, 0, 0,160, 80, 80,160, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_188[] = { 8, 0, 0, 0, 0, 68, 62, 44,244, 72,200, 68, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_189[] = { 8, 0, 0, 0, 0, 78, 36, 42,246, 72,200, 68, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_190[] = { 8, 0, 0, 0, 0, 68, 62, 44,212, 40, 72,228, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_191[] = { 4, 0, 0,224,160,128, 64, 64, 0, 64, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_192[] = { 8, 0, 0, 0, 0,238, 68,124, 40, 40, 56, 16, 0, 16, 32}; +static const GLubyte TimesRoman10_Character_193[] = { 8, 0, 0, 0, 0,238, 68,124, 40, 40, 56, 16, 0, 16, 8}; +static const GLubyte TimesRoman10_Character_194[] = { 8, 0, 0, 0, 0,238, 68,124, 40, 40, 56, 16, 0, 40, 16}; +static const GLubyte TimesRoman10_Character_195[] = { 8, 0, 0, 0, 0,238, 68,124, 40, 40, 56, 16, 0, 40, 20}; +static const GLubyte TimesRoman10_Character_196[] = { 8, 0, 0, 0, 0,238, 68,124, 40, 40, 56, 16, 0, 40, 0}; +static const GLubyte TimesRoman10_Character_197[] = { 8, 0, 0, 0, 0,238, 68,124, 40, 40, 56, 16, 16, 40, 16}; +static const GLubyte TimesRoman10_Character_198[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0,239, 0, 73, 0,120, 0, 46, 0, 40, 0, 57, 0, 31, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_199[] = { 7, 0, 96, 16, 32,120,196,128,128,128,196,124, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_200[] = { 6, 0, 0, 0, 0,248, 72, 64,112, 64, 72,248, 0, 32, 64}; +static const GLubyte TimesRoman10_Character_201[] = { 6, 0, 0, 0, 0,248, 72, 64,112, 64, 72,248, 0, 32, 16}; +static const GLubyte TimesRoman10_Character_202[] = { 6, 0, 0, 0, 0,248, 72, 64,112, 64, 72,248, 0, 80, 32}; +static const GLubyte TimesRoman10_Character_203[] = { 6, 0, 0, 0, 0,248, 72, 64,112, 64, 72,248, 0, 80, 0}; +static const GLubyte TimesRoman10_Character_204[] = { 4, 0, 0, 0, 0,224, 64, 64, 64, 64, 64,224, 0, 64,128}; +static const GLubyte TimesRoman10_Character_205[] = { 4, 0, 0, 0, 0,224, 64, 64, 64, 64, 64,224, 0, 64, 32}; +static const GLubyte TimesRoman10_Character_206[] = { 4, 0, 0, 0, 0,224, 64, 64, 64, 64, 64,224, 0,160, 64}; +static const GLubyte TimesRoman10_Character_207[] = { 4, 0, 0, 0, 0,224, 64, 64, 64, 64, 64,224, 0,160, 0}; +static const GLubyte TimesRoman10_Character_208[] = { 7, 0, 0, 0, 0,248, 76, 68,228, 68, 76,248, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_209[] = { 8, 0, 0, 0, 0,228, 76, 76, 84, 84,100,238, 0, 80, 40}; +static const GLubyte TimesRoman10_Character_210[] = { 7, 0, 0, 0, 0,120,204,132,132,132,204,120, 0, 32, 64}; +static const GLubyte TimesRoman10_Character_211[] = { 7, 0, 0, 0, 0,120,204,132,132,132,204,120, 0, 16, 8}; +static const GLubyte TimesRoman10_Character_212[] = { 7, 0, 0, 0, 0,120,204,132,132,132,204,120, 0, 80, 32}; +static const GLubyte TimesRoman10_Character_213[] = { 7, 0, 0, 0, 0,120,204,132,132,132,204,120, 0, 80, 40}; +static const GLubyte TimesRoman10_Character_214[] = { 7, 0, 0, 0, 0,120,204,132,132,132,204,120, 0, 80, 0}; +static const GLubyte TimesRoman10_Character_215[] = { 6, 0, 0, 0, 0,136, 80, 32, 80,136, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_216[] = { 8, 0, 0, 0,128,124,102, 82, 82, 74,102, 62, 1, 0, 0}; +static const GLubyte TimesRoman10_Character_217[] = { 8, 0, 0, 0, 0, 56,108, 68, 68, 68, 68,238, 0, 16, 32}; +static const GLubyte TimesRoman10_Character_218[] = { 8, 0, 0, 0, 0, 56,108, 68, 68, 68, 68,238, 0, 16, 8}; +static const GLubyte TimesRoman10_Character_219[] = { 8, 0, 0, 0, 0, 56,108, 68, 68, 68, 68,238, 0, 40, 16}; +static const GLubyte TimesRoman10_Character_220[] = { 8, 0, 0, 0, 0, 56,108, 68, 68, 68, 68,238, 0, 40, 0}; +static const GLubyte TimesRoman10_Character_221[] = { 8, 0, 0, 0, 0, 56, 16, 16, 40, 40, 68,238, 0, 16, 8}; +static const GLubyte TimesRoman10_Character_222[] = { 6, 0, 0, 0, 0,224, 64,112, 72,112, 64,224, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_223[] = { 5, 0, 0, 0, 0,224, 80, 80, 96, 80, 80, 32, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_224[] = { 4, 0, 0, 0, 0,224,160, 96, 32,192, 0, 64,128, 0, 0}; +static const GLubyte TimesRoman10_Character_225[] = { 4, 0, 0, 0, 0,224,160, 96, 32,192, 0, 64, 32, 0, 0}; +static const GLubyte TimesRoman10_Character_226[] = { 4, 0, 0, 0, 0,224,160, 96, 32,192, 0,160, 64, 0, 0}; +static const GLubyte TimesRoman10_Character_227[] = { 4, 0, 0, 0, 0,224,160, 96, 32,192, 0,160, 80, 0, 0}; +static const GLubyte TimesRoman10_Character_228[] = { 4, 0, 0, 0, 0,224,160, 96, 32,192, 0,160, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_229[] = { 4, 0, 0, 0, 0,224,160, 96, 32,192, 64,160, 64, 0, 0}; +static const GLubyte TimesRoman10_Character_230[] = { 6, 0, 0, 0, 0,216,160,112, 40,216, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_231[] = { 4, 0,192, 32, 64, 96,128,128,128, 96, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_232[] = { 4, 0, 0, 0, 0, 96,128,192,160, 96, 0, 64,128, 0, 0}; +static const GLubyte TimesRoman10_Character_233[] = { 4, 0, 0, 0, 0, 96,128,192,160, 96, 0, 64, 32, 0, 0}; +static const GLubyte TimesRoman10_Character_234[] = { 4, 0, 0, 0, 0, 96,128,192,160, 96, 0,160, 64, 0, 0}; +static const GLubyte TimesRoman10_Character_235[] = { 4, 0, 0, 0, 0, 96,128,192,160, 96, 0,160, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_236[] = { 4, 0, 0, 0, 0,224, 64, 64, 64,192, 0, 64,128, 0, 0}; +static const GLubyte TimesRoman10_Character_237[] = { 4, 0, 0, 0, 0,224, 64, 64, 64,192, 0, 64, 32, 0, 0}; +static const GLubyte TimesRoman10_Character_238[] = { 4, 0, 0, 0, 0,224, 64, 64, 64,192, 0,160, 64, 0, 0}; +static const GLubyte TimesRoman10_Character_239[] = { 4, 0, 0, 0, 0,224, 64, 64, 64,192, 0,160, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_240[] = { 5, 0, 0, 0, 0, 96,144,144,144,112,160,112, 64, 0, 0}; +static const GLubyte TimesRoman10_Character_241[] = { 5, 0, 0, 0, 0,216,144,144,144,224, 0,160, 80, 0, 0}; +static const GLubyte TimesRoman10_Character_242[] = { 5, 0, 0, 0, 0, 96,144,144,144, 96, 0, 32, 64, 0, 0}; +static const GLubyte TimesRoman10_Character_243[] = { 5, 0, 0, 0, 0, 96,144,144,144, 96, 0, 64, 32, 0, 0}; +static const GLubyte TimesRoman10_Character_244[] = { 5, 0, 0, 0, 0, 96,144,144,144, 96, 0,160, 64, 0, 0}; +static const GLubyte TimesRoman10_Character_245[] = { 5, 0, 0, 0, 0, 96,144,144,144, 96, 0,160, 80, 0, 0}; +static const GLubyte TimesRoman10_Character_246[] = { 5, 0, 0, 0, 0, 96,144,144,144, 96, 0,160, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_247[] = { 6, 0, 0, 0, 0, 32, 0,248, 0, 32, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_248[] = { 5, 0, 0, 0, 0,224,144,144,144,112, 8, 0, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_249[] = { 5, 0, 0, 0, 0,104,144,144,144,144, 0, 32, 64, 0, 0}; +static const GLubyte TimesRoman10_Character_250[] = { 5, 0, 0, 0, 0,104,144,144,144,144, 0, 64, 32, 0, 0}; +static const GLubyte TimesRoman10_Character_251[] = { 5, 0, 0, 0, 0,104,144,144,144,144, 0, 80, 32, 0, 0}; +static const GLubyte TimesRoman10_Character_252[] = { 5, 0, 0, 0, 0,104,144,144,144,144, 0, 80, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_253[] = { 5, 0, 0,128,192, 64, 96,160,144,184, 0, 32, 16, 0, 0}; +static const GLubyte TimesRoman10_Character_254[] = { 5, 0, 0,192,128,224,144,144,144,224,128,128, 0, 0, 0}; +static const GLubyte TimesRoman10_Character_255[] = { 5, 0, 0,128,192, 64, 96,160,144,184, 0,160, 0, 0, 0}; + +/* The font characters mapping: */ +static const GLubyte* TimesRoman10_Character_Map[] = {TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032, + TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032, + TimesRoman10_Character_032,TimesRoman10_Character_033,TimesRoman10_Character_034,TimesRoman10_Character_035,TimesRoman10_Character_036,TimesRoman10_Character_037,TimesRoman10_Character_038,TimesRoman10_Character_039,TimesRoman10_Character_040,TimesRoman10_Character_041,TimesRoman10_Character_042,TimesRoman10_Character_043,TimesRoman10_Character_044,TimesRoman10_Character_045,TimesRoman10_Character_046,TimesRoman10_Character_047, + TimesRoman10_Character_048,TimesRoman10_Character_049,TimesRoman10_Character_050,TimesRoman10_Character_051,TimesRoman10_Character_052,TimesRoman10_Character_053,TimesRoman10_Character_054,TimesRoman10_Character_055,TimesRoman10_Character_056,TimesRoman10_Character_057,TimesRoman10_Character_058,TimesRoman10_Character_059,TimesRoman10_Character_060,TimesRoman10_Character_061,TimesRoman10_Character_062,TimesRoman10_Character_063, + TimesRoman10_Character_064,TimesRoman10_Character_065,TimesRoman10_Character_066,TimesRoman10_Character_067,TimesRoman10_Character_068,TimesRoman10_Character_069,TimesRoman10_Character_070,TimesRoman10_Character_071,TimesRoman10_Character_072,TimesRoman10_Character_073,TimesRoman10_Character_074,TimesRoman10_Character_075,TimesRoman10_Character_076,TimesRoman10_Character_077,TimesRoman10_Character_078,TimesRoman10_Character_079, + TimesRoman10_Character_080,TimesRoman10_Character_081,TimesRoman10_Character_082,TimesRoman10_Character_083,TimesRoman10_Character_084,TimesRoman10_Character_085,TimesRoman10_Character_086,TimesRoman10_Character_087,TimesRoman10_Character_088,TimesRoman10_Character_089,TimesRoman10_Character_090,TimesRoman10_Character_091,TimesRoman10_Character_092,TimesRoman10_Character_093,TimesRoman10_Character_094,TimesRoman10_Character_095, + TimesRoman10_Character_096,TimesRoman10_Character_097,TimesRoman10_Character_098,TimesRoman10_Character_099,TimesRoman10_Character_100,TimesRoman10_Character_101,TimesRoman10_Character_102,TimesRoman10_Character_103,TimesRoman10_Character_104,TimesRoman10_Character_105,TimesRoman10_Character_106,TimesRoman10_Character_107,TimesRoman10_Character_108,TimesRoman10_Character_109,TimesRoman10_Character_110,TimesRoman10_Character_111, + TimesRoman10_Character_112,TimesRoman10_Character_113,TimesRoman10_Character_114,TimesRoman10_Character_115,TimesRoman10_Character_116,TimesRoman10_Character_117,TimesRoman10_Character_118,TimesRoman10_Character_119,TimesRoman10_Character_120,TimesRoman10_Character_121,TimesRoman10_Character_122,TimesRoman10_Character_123,TimesRoman10_Character_124,TimesRoman10_Character_125,TimesRoman10_Character_126,TimesRoman10_Character_032, + TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032, + TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032,TimesRoman10_Character_032, + TimesRoman10_Character_160,TimesRoman10_Character_161,TimesRoman10_Character_162,TimesRoman10_Character_163,TimesRoman10_Character_164,TimesRoman10_Character_165,TimesRoman10_Character_166,TimesRoman10_Character_167,TimesRoman10_Character_168,TimesRoman10_Character_169,TimesRoman10_Character_170,TimesRoman10_Character_171,TimesRoman10_Character_172,TimesRoman10_Character_173,TimesRoman10_Character_174,TimesRoman10_Character_175, + TimesRoman10_Character_176,TimesRoman10_Character_177,TimesRoman10_Character_178,TimesRoman10_Character_179,TimesRoman10_Character_180,TimesRoman10_Character_181,TimesRoman10_Character_182,TimesRoman10_Character_183,TimesRoman10_Character_184,TimesRoman10_Character_185,TimesRoman10_Character_186,TimesRoman10_Character_187,TimesRoman10_Character_188,TimesRoman10_Character_189,TimesRoman10_Character_190,TimesRoman10_Character_191, + TimesRoman10_Character_192,TimesRoman10_Character_193,TimesRoman10_Character_194,TimesRoman10_Character_195,TimesRoman10_Character_196,TimesRoman10_Character_197,TimesRoman10_Character_198,TimesRoman10_Character_199,TimesRoman10_Character_200,TimesRoman10_Character_201,TimesRoman10_Character_202,TimesRoman10_Character_203,TimesRoman10_Character_204,TimesRoman10_Character_205,TimesRoman10_Character_206,TimesRoman10_Character_207, + TimesRoman10_Character_208,TimesRoman10_Character_209,TimesRoman10_Character_210,TimesRoman10_Character_211,TimesRoman10_Character_212,TimesRoman10_Character_213,TimesRoman10_Character_214,TimesRoman10_Character_215,TimesRoman10_Character_216,TimesRoman10_Character_217,TimesRoman10_Character_218,TimesRoman10_Character_219,TimesRoman10_Character_220,TimesRoman10_Character_221,TimesRoman10_Character_222,TimesRoman10_Character_223, + TimesRoman10_Character_224,TimesRoman10_Character_225,TimesRoman10_Character_226,TimesRoman10_Character_227,TimesRoman10_Character_228,TimesRoman10_Character_229,TimesRoman10_Character_230,TimesRoman10_Character_231,TimesRoman10_Character_232,TimesRoman10_Character_233,TimesRoman10_Character_234,TimesRoman10_Character_235,TimesRoman10_Character_236,TimesRoman10_Character_237,TimesRoman10_Character_238,TimesRoman10_Character_239, + TimesRoman10_Character_240,TimesRoman10_Character_241,TimesRoman10_Character_242,TimesRoman10_Character_243,TimesRoman10_Character_244,TimesRoman10_Character_245,TimesRoman10_Character_246,TimesRoman10_Character_247,TimesRoman10_Character_248,TimesRoman10_Character_249,TimesRoman10_Character_250,TimesRoman10_Character_251,TimesRoman10_Character_252,TimesRoman10_Character_253,TimesRoman10_Character_254,TimesRoman10_Character_255,NULL}; + +/* The font structure: */ +const SFG_Font fgFontTimesRoman10 = { "-adobe-times-medium-r-normal--10-100-75-75-p-54-iso8859-1", 256, 14, TimesRoman10_Character_Map, 0, 4 }; + +static const GLubyte TimesRoman24_Character_000[] = { 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 64, 0, 64, 0, 0, 0, 64, 0, 64, 0, 0, 0, 64, 0, 64, 0, 0, 0, 64, 0, 64, 0, 0, 0, 64, 0, 64, 0, 0, 0, 64, 0, 64, 0, 0, 0, 64, 0, 64, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_001[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_002[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_003[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_004[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_005[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_006[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_007[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_008[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_009[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_010[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_011[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_012[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_013[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_014[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_015[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_016[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_017[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_018[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_019[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_020[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_021[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_022[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_023[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_024[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_025[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_026[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_027[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_028[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_029[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_030[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_031[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_032[] = { 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_033[] = { 8, 0, 0, 0, 0, 0, 0, 0, 24, 24, 0, 0, 0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_034[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 0,102, 0,102, 0,102, 0,102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_035[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 0, 17, 0,127,224,127,224, 8,128, 8,128, 8,128, 63,240, 63,240, 4, 64, 4, 64, 4, 64, 4, 64, 4, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_036[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4, 0, 63, 0,229,192,196,192,132, 96,132, 96, 4, 96, 4,224, 7,192, 7,128, 30, 0, 60, 0,116, 0,100, 0,100, 32,100, 96, 52,224, 31,128, 4, 0, 4, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_037[] = { 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 30, 0, 12, 57, 0, 6, 48,128, 2, 48, 64, 3, 48, 64, 1,152, 64, 0,140,192, 0,199,128, 60, 96, 0,114, 32, 0, 97, 48, 0, 96,152, 0, 96,136, 0, 48,140, 0, 25,254, 0, 15, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_038[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 0, 63,191, 0,112,240,128, 96, 96, 0, 96,224, 0, 96,208, 0, 49,144, 0, 27,136, 0, 15, 12, 0, 7, 31, 0, 7,128, 0, 14,192, 0, 12, 96, 0, 12, 32, 0, 12, 32, 0, 6, 96, 0, 3,192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_039[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 12, 4, 28, 24, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_040[] = { 8, 0, 0, 2, 4, 8, 24, 16, 48, 48, 96, 96, 96, 96, 96, 96, 96, 96, 48, 48, 16, 24, 8, 4, 2, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_041[] = { 8, 0, 0, 64, 32, 16, 24, 8, 12, 12, 6, 6, 6, 6, 6, 6, 6, 6, 12, 12, 8, 24, 16, 32, 64, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_042[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 7, 0, 50, 96, 58,224, 7, 0, 58,224, 50, 96, 7, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_043[] = { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0,127,248,127,248, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_044[] = { 7, 0, 0, 0, 0, 48, 24, 8, 56, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_045[] = { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,248,127,248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_046[] = { 6, 0, 0, 0, 0, 0, 0, 0, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_047[] = { 7, 0, 0, 0, 0,192,192,192, 64, 96, 96, 32, 48, 48, 16, 24, 24, 8, 12, 12, 4, 6, 6, 6, 6, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_048[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 25,128, 48,192, 48,192,112,224, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 48,192, 48,192, 25,128, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_049[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,192, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 30, 0, 6, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_050[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,192,127,224, 48, 32, 24, 0, 12, 0, 6, 0, 2, 0, 3, 0, 1,128, 1,128, 0,192, 0,192, 64,192, 64,192, 33,192, 63,128, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_051[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 0,115, 0, 97,128, 0,128, 0,192, 0,192, 0,192, 1,192, 3,128, 15, 0, 6, 0, 3, 0, 65,128, 65,128, 35,128, 63, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_052[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,128, 1,128, 1,128, 1,128,127,224,127,224, 97,128, 33,128, 49,128, 17,128, 25,128, 9,128, 13,128, 5,128, 3,128, 3,128, 1,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_053[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0,113,192, 96,192, 0, 96, 0, 96, 0, 96, 0, 96, 0,224, 1,192, 7,192, 63, 0, 60, 0, 48, 0, 16, 0, 16, 0, 15,192, 15,224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_054[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 61,192, 48,192,112, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,192,121,192,119, 0, 48, 0, 56, 0, 24, 0, 12, 0, 7, 0, 1,224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_055[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 12, 0, 6, 0, 6, 0, 6, 0, 2, 0, 3, 0, 3, 0, 1, 0, 1,128, 1,128, 0,128, 0,192, 64,192, 96, 96,127,224, 63,224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_056[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 57,192,112,192, 96, 96, 96, 96, 96, 96, 32,224, 48,192, 27,128, 15, 0, 15, 0, 25,128, 48,192, 48,192, 48,192, 25,128, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_057[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,120, 0, 14, 0, 3, 0, 1,128, 1,192, 0,192, 14,192, 57,224, 48,224, 96, 96, 96, 96, 96, 96, 96, 96, 96,224, 48,192, 59,192, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_058[] = { 6, 0, 0, 0, 0, 0, 0, 0, 48, 48, 0, 0, 0, 0, 0, 0, 0, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_059[] = { 7, 0, 0, 0, 0, 48, 24, 8, 56, 48, 0, 0, 0, 0, 0, 0, 0, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_060[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0,224, 3,128, 14, 0, 56, 0, 96, 0, 56, 0, 14, 0, 3,128, 0,224, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_061[] = { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,248,127,248, 0, 0, 0, 0,127,248,127,248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_062[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, 56, 0, 14, 0, 3,128, 0,224, 0, 48, 0,224, 3,128, 14, 0, 56, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_063[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 12, 0, 0, 0, 0, 0, 4, 0, 4, 0, 4, 0, 6, 0, 6, 0, 3, 0, 3,128, 1,192, 48,192, 48,192, 32,192, 49,128, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_064[] = { 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,252, 0, 3,131, 0, 6, 0, 0, 12, 0, 0, 24,119,128, 24,222,192, 49,142, 96, 49,134, 32, 49,134, 48, 49,134, 16, 49,131, 16, 48,195, 16, 48,227, 16, 56,127, 16, 24, 59, 48, 28, 0, 32, 14, 0, 96, 7, 0,192, 3,195,128, 0,254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_065[] = { 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,252, 31,128, 48, 6, 0, 16, 6, 0, 16, 12, 0, 24, 12, 0, 8, 12, 0, 15,248, 0, 12, 24, 0, 4, 24, 0, 4, 48, 0, 6, 48, 0, 2, 48, 0, 2, 96, 0, 1, 96, 0, 1,192, 0, 1,192, 0, 0,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_066[] = { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,240, 24, 60, 24, 12, 24, 6, 24, 6, 24, 6, 24, 12, 24, 28, 31,240, 24, 32, 24, 24, 24, 12, 24, 12, 24, 12, 24, 24, 24, 56,127,224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_067[] = { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,240, 15, 28, 28, 4, 48, 2, 48, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0, 48, 2, 48, 2, 28, 6, 14, 30, 3,242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_068[] = { 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,224, 0, 24, 56, 0, 24, 28, 0, 24, 6, 0, 24, 6, 0, 24, 3, 0, 24, 3, 0, 24, 3, 0, 24, 3, 0, 24, 3, 0, 24, 3, 0, 24, 3, 0, 24, 6, 0, 24, 6, 0, 24, 28, 0, 24, 56, 0,127,224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_069[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,252, 24, 12, 24, 4, 24, 4, 24, 0, 24, 0, 24, 32, 24, 32, 31,224, 24, 32, 24, 32, 24, 0, 24, 0, 24, 8, 24, 8, 24, 24,127,248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_070[] = { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,126, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 16, 24, 16, 31,240, 24, 16, 24, 16, 24, 0, 24, 0, 24, 8, 24, 8, 24, 24,127,248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_071[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,240, 0, 15, 28, 0, 28, 14, 0, 48, 6, 0, 48, 6, 0, 96, 6, 0, 96, 6, 0, 96, 31,128, 96, 0, 0, 96, 0, 0, 96, 0, 0, 96, 0, 0, 48, 2, 0, 48, 2, 0, 28, 6, 0, 14, 30, 0, 3,242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_072[] = { 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,126, 15,192, 24, 3, 0, 24, 3, 0, 24, 3, 0, 24, 3, 0, 24, 3, 0, 24, 3, 0, 24, 3, 0, 31,255, 0, 24, 3, 0, 24, 3, 0, 24, 3, 0, 24, 3, 0, 24, 3, 0, 24, 3, 0, 24, 3, 0,126, 15,192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_073[] = { 8, 0, 0, 0, 0, 0, 0, 0,126, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,126, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_074[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 0,102, 0, 99, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 15,192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_075[] = { 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,126, 15,128, 24, 7, 0, 24, 14, 0, 24, 28, 0, 24, 56, 0, 24,112, 0, 24,224, 0, 25,192, 0, 31,128, 0, 31, 0, 0, 25,128, 0, 24,192, 0, 24, 96, 0, 24, 48, 0, 24, 24, 0, 24, 12, 0,126, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_076[] = { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,252, 24, 12, 24, 4, 24, 4, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0,126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_077[] = { 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,124, 16,252, 16, 48, 48, 16, 48, 48, 16,104, 48, 16,104, 48, 16,196, 48, 16,196, 48, 17,132, 48, 17,130, 48, 19, 2, 48, 19, 1, 48, 22, 1, 48, 22, 1, 48, 28, 0,176, 28, 0,176, 24, 0,112,120, 0,124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_078[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,124, 6, 0, 16, 14, 0, 16, 14, 0, 16, 26, 0, 16, 50, 0, 16, 50, 0, 16, 98, 0, 16,194, 0, 16,194, 0, 17,130, 0, 19, 2, 0, 19, 2, 0, 22, 2, 0, 28, 2, 0, 28, 2, 0, 24, 2, 0,120, 15,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_079[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,240, 0, 14, 28, 0, 28, 14, 0, 48, 3, 0, 48, 3, 0, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 48, 3, 0, 48, 3, 0, 28, 14, 0, 14, 28, 0, 3,240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_080[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,126, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, 31,224, 24, 56, 24, 24, 24, 12, 24, 12, 24, 12, 24, 24, 24, 56,127,224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_081[] = { 18, 0, 0, 0, 0, 0, 0, 0, 7,128, 0, 28, 0, 0, 56, 0, 0,112, 0, 0,224, 0, 3,240, 0, 14, 28, 0, 28, 14, 0, 48, 3, 0, 48, 3, 0, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 48, 3, 0, 48, 3, 0, 28, 14, 0, 14, 28, 0, 3,240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_082[] = { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,126, 15, 24, 14, 24, 28, 24, 56, 24, 48, 24, 96, 24,224, 25,192, 31,224, 24, 56, 24, 24, 24, 28, 24, 12, 24, 28, 24, 24, 24, 56,127,224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_083[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, 0,120,192, 96, 96, 64, 48, 64, 48, 0, 48, 0,112, 1,224, 7,192, 15, 0, 60, 0,112, 0, 96, 32, 96, 32, 96, 96, 49,224, 15, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_084[] = { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,224, 1,128, 1,128, 1,128, 1,128, 1,128, 1,128, 1,128, 1,128, 1,128, 1,128, 1,128, 1,128, 65,130, 65,130, 97,134,127,254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_085[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,240, 0, 14, 24, 0, 12, 4, 0, 24, 4, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0,126, 15,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_086[] = { 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,128, 0, 1,128, 0, 1,128, 0, 3,192, 0, 3, 64, 0, 3, 96, 0, 6, 32, 0, 6, 32, 0, 6, 48, 0, 12, 16, 0, 12, 24, 0, 24, 8, 0, 24, 8, 0, 24, 12, 0, 48, 4, 0, 48, 6, 0,252, 31,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_087[] = { 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,131, 0, 1,131, 0, 1,131,128, 3,135,128, 3, 70,128, 3, 70,192, 6, 70, 64, 6, 76, 64, 6, 76, 96, 12, 44, 96, 12, 44, 32, 24, 44, 32, 24, 24, 48, 24, 24, 16, 48, 24, 16, 48, 24, 24,252,126,126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_088[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,252, 15,192, 48, 3,128, 24, 7, 0, 8, 14, 0, 4, 12, 0, 6, 24, 0, 2, 56, 0, 1,112, 0, 0,224, 0, 0,192, 0, 1,192, 0, 3,160, 0, 3, 16, 0, 6, 8, 0, 14, 12, 0, 28, 6, 0,126, 15,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_089[] = { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,224, 1,128, 1,128, 1,128, 1,128, 1,128, 1,128, 3,192, 3, 64, 6, 96, 6, 32, 12, 48, 28, 16, 24, 24, 56, 8, 48, 12,252, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_090[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,252,112, 12, 56, 4, 24, 4, 28, 0, 12, 0, 14, 0, 7, 0, 3, 0, 3,128, 1,128, 1,192, 0,224, 64, 96, 64,112, 96, 56,127,248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_091[] = { 8, 0, 0, 0, 62, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 62, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_092[] = { 7, 0, 0, 0, 0, 0, 0, 0, 6, 6, 4, 12, 12, 8, 24, 24, 16, 48, 48, 32, 96, 96, 64,192,192, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_093[] = { 8, 0, 0, 0,124, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,124, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_094[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 64, 96,192, 32,128, 49,128, 17, 0, 27, 0, 10, 0, 14, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_095[] = { 13, 0, 0, 0, 0,255,248,255,248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_096[] = { 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48,112, 64, 96, 48, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_097[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56,192,125,128, 99,128, 97,128, 97,128, 49,128, 29,128, 7,128, 1,128, 49,128, 51,128, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_098[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 0, 57,192, 48,192, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48,192, 57,192, 55, 0, 48, 0, 48, 0, 48, 0, 48, 0,112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_099[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 63,128, 56, 64,112, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0, 32,192, 49,192, 15,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_100[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 96, 57,192, 48,192, 96,192, 96,192, 96,192, 96,192, 96,192, 96,192, 48,192, 57,192, 14,192, 0,192, 0,192, 0,192, 0,192, 1,192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_101[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 63,128, 56, 64,112, 0, 96, 0, 96, 0, 96, 0,127,192, 96,192, 32,192, 49,128, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_102[] = { 7, 0, 0, 0, 0, 0, 0, 0,120, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,254, 48, 48, 48, 22, 14, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_103[] = { 12, 0, 0, 0, 0, 31,128,120,224, 96, 48, 96, 16, 48, 48, 31,224, 63,128, 48, 0, 24, 0, 31, 0, 25,128, 48,192, 48,192, 48,192, 48,192, 25,128, 15,224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_104[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,120,240, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 56,224, 55,192, 51,128, 48, 0, 48, 0, 48, 0, 48, 0,112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_105[] = { 6, 0, 0, 0, 0, 0, 0, 0,120, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,112, 0, 0, 0, 48, 48, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_106[] = { 6, 0, 0,192,224, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,112, 0, 0, 0, 48, 48, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_107[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,121,240, 48,224, 49,192, 51,128, 55, 0, 54, 0, 60, 0, 52, 0, 50, 0, 51, 0, 49,128, 51,224, 48, 0, 48, 0, 48, 0, 48, 0,112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_108[] = { 6, 0, 0, 0, 0, 0, 0, 0,120, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,112, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_109[] = { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,120,241,224, 48, 96,192, 48, 96,192, 48, 96,192, 48, 96,192, 48, 96,192, 48, 96,192, 48, 96,192, 48, 96,192, 56,241,192, 55,207,128,115,135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_110[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,120,240, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 56,224, 55,192,115,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_111[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 57,192, 48,192, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 48,192, 57,192, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_112[] = { 12, 0, 0, 0, 0,120, 0, 48, 0, 48, 0, 48, 0, 48, 0, 55, 0, 57,192, 48,192, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48,192, 57,192,119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_113[] = { 12, 0, 0, 0, 0, 1,224, 0,192, 0,192, 0,192, 0,192, 14,192, 57,192, 48,192, 96,192, 96,192, 96,192, 96,192, 96,192, 96,192, 48,192, 57,192, 14,192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_114[] = { 8, 0, 0, 0, 0, 0, 0, 0,120, 48, 48, 48, 48, 48, 48, 48, 48, 59, 55,115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_115[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,124, 0, 99, 0, 65,128, 1,128, 3,128, 15, 0, 62, 0, 56, 0,112, 0, 97, 0, 51, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_116[] = { 7, 0, 0, 0, 0, 0, 0, 0, 28, 50, 48, 48, 48, 48, 48, 48, 48, 48, 48,254,112, 48, 16, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_117[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14,112, 31, 96, 56,224, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96,112,224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_118[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 14, 0, 14, 0, 26, 0, 25, 0, 25, 0, 49, 0, 48,128, 48,128, 96,128, 96,192,241,224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_119[] = { 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 16, 0, 14, 56, 0, 14, 56, 0, 26, 40, 0, 26,100, 0, 25,100, 0, 49,100, 0, 48,194, 0, 48,194, 0, 96,194, 0, 96,195, 0,241,231,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_120[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,120,240, 48, 96, 16,192, 25,192, 13,128, 7, 0, 6, 0, 13, 0, 28,128, 24,192, 48, 96,120,240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_121[] = { 11, 0, 0, 0, 0,224, 0,240, 0, 24, 0, 8, 0, 12, 0, 4, 0, 14, 0, 14, 0, 26, 0, 25, 0, 25, 0, 49, 0, 48,128, 48,128, 96,128, 96,192,241,224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_122[] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,128, 97,128, 48,128, 56, 0, 24, 0, 28, 0, 12, 0, 14, 0, 7, 0, 67, 0, 97,128,127,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_123[] = { 10, 0, 0, 0, 0, 3,128, 6, 0, 12, 0, 12, 0, 12, 0, 12, 0, 12, 0, 12, 0, 8, 0, 24, 0, 16, 0, 96, 0, 16, 0, 24, 0, 8, 0, 12, 0, 12, 0, 12, 0, 12, 0, 12, 0, 6, 0, 3,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_124[] = { 6, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_125[] = { 10, 0, 0, 0, 0,112, 0, 24, 0, 12, 0, 12, 0, 12, 0, 12, 0, 12, 0, 12, 0, 4, 0, 6, 0, 2, 0, 1,128, 2, 0, 6, 0, 4, 0, 12, 0, 12, 0, 12, 0, 12, 0, 12, 0, 24, 0,112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_126[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65,192, 99,224, 62, 48, 28, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_127[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_128[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_129[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_130[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_131[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_132[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_133[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_134[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_135[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_136[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_137[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_138[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_139[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_140[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_141[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_142[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_143[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_144[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_145[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_146[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_147[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_148[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_149[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_150[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_151[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_152[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_153[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_154[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_155[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_156[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_157[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_158[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_159[] = { 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 64, 0, 64, 0, 0, 0, 0, 0, 85, 85, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_160[] = { 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_161[] = { 8, 0, 0, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 0, 0, 0, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_162[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 32, 0, 31, 0, 63,128, 56, 64,104, 0,100, 0,100, 0,100, 0, 98, 0, 98, 0, 33,192, 49,192, 15,128, 0,128, 0,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_163[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,115,192, 95, 96, 60, 32, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0,126, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24,192, 12,192, 7,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_164[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 48,119,112, 63,224, 24,192, 48, 96, 48, 96, 48, 96, 48, 96, 24,192, 63,224,119,112, 96, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_165[] = { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15,192, 3, 0, 3, 0, 3, 0, 3, 0, 31,224, 3, 0, 31,224, 3, 0, 7,128, 12,128, 12,192, 24, 64, 24, 96, 48, 32,112, 48,248,124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_166[] = { 6, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_167[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 25, 0, 24,128, 1,128, 3,128, 7, 0, 14, 0, 29, 0, 56,128, 48,192, 32,192, 33,192, 19,128, 15, 0, 14, 0, 28, 0, 24, 0, 17,128, 9,128, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_168[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,102,102, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_169[] = { 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,248, 0, 14, 14, 0, 24, 3, 0, 48,225,128, 35,184,128, 98, 12,192, 70, 0, 64, 68, 0, 64, 68, 0, 64, 68, 0, 64, 70, 0, 64, 98, 12,192, 35,152,128, 48,241,128, 24, 3, 0, 14, 14, 0, 3,248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_170[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,126, 0,118,204,204,124, 12,204,120, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_171[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 32, 6, 96, 12,192, 25,128, 51, 0, 51, 0, 25,128, 12,192, 6, 96, 2, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_172[] = { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24,127,248,127,248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_173[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127, 0,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_174[] = { 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,248, 0, 14, 14, 0, 24, 3, 0, 48, 1,128, 35,140,128, 97, 24,192, 65, 16, 64, 65, 32, 64, 65,240, 64, 65, 24, 64, 65, 8, 64, 97, 8,192, 33, 24,128, 51,241,128, 24, 3, 0, 14, 14, 0, 3,248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_175[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,126,126, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_176[] = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 34, 0, 65, 0, 65, 0, 65, 0, 34, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_177[] = { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,248,127,248, 0, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0,127,248,127,248, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_178[] = { 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,252, 68, 32, 48, 16, 8, 12,140, 76, 56, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_179[] = { 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,112,136,140, 12, 8, 48, 8,140, 76, 56, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_180[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 24, 14, 6, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_181[] = { 13, 0, 0, 0, 0, 32, 0,112, 0, 96, 0, 32, 0, 32, 0, 46,112, 63, 96, 56,224, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96,112,224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_182[] = { 11, 0, 0, 0, 0, 4,128, 4,128, 4,128, 4,128, 4,128, 4,128, 4,128, 4,128, 4,128, 4,128, 4,128, 12,128, 28,128, 60,128, 60,128,124,128,124,128,124,128, 60,128, 60,128, 28,128, 15,192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_183[] = { 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_184[] = { 8, 0, 60,102, 6, 30, 24, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_185[] = { 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,124, 16, 16, 16, 16, 16, 16, 80, 48, 16, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_186[] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,126, 0, 60,102,102,102,102,102, 60, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_187[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 0, 51, 0, 25,128, 12,192, 6, 96, 6, 96, 12,192, 25,128, 51, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_188[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 2, 0, 8, 2, 0, 12,127,128, 4, 34, 0, 6, 50, 0, 3, 18, 0, 1, 10, 0,125,142, 0, 16,134, 0, 16,194, 0, 16, 96, 0, 16, 32, 0, 16, 48, 0, 16, 16, 0, 80, 24, 0, 48, 12, 0, 16, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_189[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 63, 0, 8, 17, 0, 12, 8, 0, 4, 12, 0, 6, 4, 0, 3, 2, 0, 1, 3, 0,125,163, 0, 16,147, 0, 16,206, 0, 16, 96, 0, 16, 32, 0, 16, 48, 0, 16, 16, 0, 80, 24, 0, 48, 12, 0, 16, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_190[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 2, 0, 8, 2, 0, 12,127,128, 4, 34, 0, 6, 50, 0, 3, 18, 0, 1, 10, 0,113,142, 0,136,134, 0,140,194, 0, 12, 96, 0, 8, 32, 0, 48, 48, 0, 8, 16, 0,140, 24, 0, 76, 12, 0, 56, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_191[] = { 11, 0, 0, 0, 0, 31, 0, 49,128, 96,128, 97,128, 97,128,112, 0, 56, 0, 24, 0, 28, 0, 12, 0, 12, 0, 4, 0, 4, 0, 0, 0, 0, 0, 6, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_192[] = { 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,252, 31,128, 48, 6, 0, 16, 6, 0, 16, 12, 0, 24, 12, 0, 8, 12, 0, 15,248, 0, 12, 24, 0, 4, 24, 0, 4, 48, 0, 6, 48, 0, 2, 48, 0, 2, 96, 0, 1, 96, 0, 1,192, 0, 1,192, 0, 0,128, 0, 0, 0, 0, 0, 32, 0, 0,192, 0, 3,128, 0, 3, 0, 0}; +static const GLubyte TimesRoman24_Character_193[] = { 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,252, 31,128, 48, 6, 0, 16, 6, 0, 16, 12, 0, 24, 12, 0, 8, 12, 0, 15,248, 0, 12, 24, 0, 4, 24, 0, 4, 48, 0, 6, 48, 0, 2, 48, 0, 2, 96, 0, 1, 96, 0, 1,192, 0, 1,192, 0, 0,128, 0, 0, 0, 0, 1, 0, 0, 0,192, 0, 0,112, 0, 0, 48, 0}; +static const GLubyte TimesRoman24_Character_194[] = { 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,252, 31,128, 48, 6, 0, 16, 6, 0, 16, 12, 0, 24, 12, 0, 8, 12, 0, 15,248, 0, 12, 24, 0, 4, 24, 0, 4, 48, 0, 6, 48, 0, 2, 48, 0, 2, 96, 0, 1, 96, 0, 1,192, 0, 1,192, 0, 0,128, 0, 0, 0, 0, 8, 16, 0, 6, 96, 0, 3,192, 0, 1,128, 0}; +static const GLubyte TimesRoman24_Character_195[] = { 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,252, 31,128, 48, 7, 0, 16, 6, 0, 16, 12, 0, 24, 12, 0, 8, 12, 0, 15,248, 0, 12, 24, 0, 4, 24, 0, 4, 48, 0, 6, 48, 0, 2, 48, 0, 2, 96, 0, 1, 96, 0, 1,192, 0, 1,192, 0, 0,128, 0, 0, 0, 0, 0, 0, 0, 4,224, 0, 3,144, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_196[] = { 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,252, 31,128, 48, 6, 0, 16, 6, 0, 16, 12, 0, 24, 12, 0, 8, 12, 0, 15,248, 0, 12, 24, 0, 4, 24, 0, 4, 48, 0, 6, 48, 0, 2, 48, 0, 2, 96, 0, 1, 96, 0, 1,192, 0, 1,192, 0, 0,128, 0, 0, 0, 0, 0, 0, 0, 6, 48, 0, 6, 48, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_197[] = { 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,252, 31,128, 48, 6, 0, 16, 6, 0, 16, 12, 0, 24, 12, 0, 8, 12, 0, 15,248, 0, 12, 24, 0, 4, 24, 0, 4, 48, 0, 6, 48, 0, 2, 48, 0, 2, 96, 0, 1, 96, 0, 1,192, 0, 1,192, 0, 0,128, 0, 1,192, 0, 2, 32, 0, 2, 32, 0, 1,192, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_198[] = { 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,249,255,240, 48, 96, 48, 16, 96, 16, 16, 96, 16, 24, 96, 0, 8, 96, 0, 15,224,128, 12, 96,128, 4,127,128, 4, 96,128, 6, 96,128, 2, 96, 0, 2, 96, 0, 1, 96, 32, 1, 96, 32, 1,224, 96, 3,255,224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_199[] = { 16, 0, 0, 3,192, 6, 96, 0, 96, 1,224, 1,128, 0,128, 3,240, 15, 28, 28, 4, 48, 2, 48, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0, 48, 2, 48, 2, 28, 6, 14, 30, 3,242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_200[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,252, 24, 12, 24, 4, 24, 4, 24, 0, 24, 0, 24, 32, 24, 32, 31,224, 24, 32, 24, 32, 24, 0, 24, 0, 24, 8, 24, 8, 24, 24,127,248, 0, 0, 0,128, 3, 0, 14, 0, 12, 0}; +static const GLubyte TimesRoman24_Character_201[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,252, 24, 12, 24, 4, 24, 4, 24, 0, 24, 0, 24, 32, 24, 32, 31,224, 24, 32, 24, 32, 24, 0, 24, 0, 24, 8, 24, 8, 24, 24,127,248, 0, 0, 2, 0, 1,128, 0,224, 0, 96}; +static const GLubyte TimesRoman24_Character_202[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,252, 24, 12, 24, 4, 24, 4, 24, 0, 24, 0, 24, 32, 24, 32, 31,224, 24, 32, 24, 32, 24, 0, 24, 0, 24, 8, 24, 8, 24, 24,127,248, 0, 0, 8, 16, 6, 96, 3,192, 1,128}; +static const GLubyte TimesRoman24_Character_203[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,252, 24, 12, 24, 4, 24, 4, 24, 0, 24, 0, 24, 32, 24, 32, 31,224, 24, 32, 24, 32, 24, 0, 24, 0, 24, 8, 24, 8, 24, 24,127,248, 0, 0, 0, 0, 12,192, 12,192, 0, 0}; +static const GLubyte TimesRoman24_Character_204[] = { 8, 0, 0, 0, 0, 0, 0, 0,126, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,126, 0, 4, 24,112, 96}; +static const GLubyte TimesRoman24_Character_205[] = { 8, 0, 0, 0, 0, 0, 0, 0,126, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,126, 0, 32, 24, 14, 6}; +static const GLubyte TimesRoman24_Character_206[] = { 8, 0, 0, 0, 0, 0, 0, 0, 63, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 63, 0, 64, 51, 30, 12}; +static const GLubyte TimesRoman24_Character_207[] = { 8, 0, 0, 0, 0, 0, 0, 0,126, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,126, 0, 0,102,102, 0}; +static const GLubyte TimesRoman24_Character_208[] = { 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,224, 0, 24, 56, 0, 24, 28, 0, 24, 6, 0, 24, 6, 0, 24, 3, 0, 24, 3, 0, 24, 3, 0,255, 3, 0, 24, 3, 0, 24, 3, 0, 24, 3, 0, 24, 6, 0, 24, 6, 0, 24, 28, 0, 24, 56, 0,127,224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_209[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,124, 6, 0, 16, 14, 0, 16, 14, 0, 16, 26, 0, 16, 50, 0, 16, 50, 0, 16, 98, 0, 16,194, 0, 16,194, 0, 17,130, 0, 19, 2, 0, 19, 2, 0, 22, 2, 0, 28, 2, 0, 28, 2, 0, 24, 2, 0,120, 15,128, 0, 0, 0, 0, 0, 0, 2,112, 0, 1,200, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_210[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,240, 0, 14, 28, 0, 28, 14, 0, 48, 3, 0, 48, 3, 0, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 48, 3, 0, 48, 3, 0, 28, 14, 0, 14, 28, 0, 3,240, 0, 0, 0, 0, 0, 32, 0, 0,192, 0, 3,128, 0, 3, 0, 0}; +static const GLubyte TimesRoman24_Character_211[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,240, 0, 14, 28, 0, 28, 14, 0, 48, 3, 0, 48, 3, 0, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 48, 3, 0, 48, 3, 0, 28, 14, 0, 14, 28, 0, 3,240, 0, 0, 0, 0, 0,128, 0, 0, 96, 0, 0, 56, 0, 0, 24, 0}; +static const GLubyte TimesRoman24_Character_212[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,240, 0, 14, 28, 0, 28, 14, 0, 48, 3, 0, 48, 3, 0, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 48, 3, 0, 48, 3, 0, 28, 14, 0, 14, 28, 0, 3,240, 0, 0, 0, 0, 4, 8, 0, 3, 48, 0, 1,224, 0, 0,192, 0}; +static const GLubyte TimesRoman24_Character_213[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,240, 0, 14, 28, 0, 28, 14, 0, 48, 3, 0, 48, 3, 0, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 48, 3, 0, 48, 3, 0, 28, 14, 0, 14, 28, 0, 3,240, 0, 0, 0, 0, 0, 0, 0, 2,112, 0, 1,200, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_214[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,240, 0, 14, 28, 0, 28, 14, 0, 48, 3, 0, 48, 3, 0, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 96, 1,128, 48, 3, 0, 48, 3, 0, 28, 14, 0, 14, 28, 0, 3,240, 0, 0, 0, 0, 0, 0, 0, 3, 48, 0, 3, 48, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_215[] = { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 16, 48, 48, 24, 96, 12,192, 7,128, 3, 0, 7,128, 12,192, 24, 96, 48, 48, 32, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_216[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 19,240, 0, 14, 28, 0, 28, 14, 0, 52, 3, 0, 50, 3, 0, 97, 1,128, 97, 1,128, 96,129,128, 96,129,128, 96, 65,128, 96, 65,128, 96, 33,128, 48, 35, 0, 48, 19, 0, 28, 14, 0, 14, 28, 0, 3,242, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_217[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,240, 0, 14, 24, 0, 12, 4, 0, 24, 4, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0,126, 15,128, 0, 0, 0, 0, 32, 0, 0,192, 0, 3,128, 0, 3, 0, 0}; +static const GLubyte TimesRoman24_Character_218[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,240, 0, 14, 24, 0, 12, 4, 0, 24, 4, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0,126, 15,128, 0, 0, 0, 0,128, 0, 0, 96, 0, 0, 56, 0, 0, 24, 0}; +static const GLubyte TimesRoman24_Character_219[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,240, 0, 14, 24, 0, 12, 4, 0, 24, 4, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0,126, 15,128, 0, 0, 0, 4, 8, 0, 3, 48, 0, 1,224, 0, 0,192, 0}; +static const GLubyte TimesRoman24_Character_220[] = { 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,240, 0, 14, 24, 0, 12, 4, 0, 24, 4, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0, 24, 2, 0,126, 15,128, 0, 0, 0, 0, 0, 0, 3, 24, 0, 3, 24, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_221[] = { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,224, 1,128, 1,128, 1,128, 1,128, 1,128, 1,128, 3,192, 3, 64, 6, 96, 6, 32, 12, 48, 28, 16, 24, 24, 56, 8, 48, 12,252, 63, 0, 0, 1, 0, 0,192, 0,112, 0, 48}; +static const GLubyte TimesRoman24_Character_222[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,126, 0, 24, 0, 24, 0, 24, 0, 31,224, 24, 56, 24, 24, 24, 12, 24, 12, 24, 12, 24, 24, 24, 56, 31,224, 24, 0, 24, 0, 24, 0,126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_223[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,115,128, 54, 64, 54, 96, 48, 96, 48, 96, 48,224, 48,192, 49,192, 51,128, 54, 0, 49,128, 48,192, 48,192, 48,192, 48,192, 25,128, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_224[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56,192,125,128, 99,128, 97,128, 97,128, 49,128, 29,128, 7,128, 1,128, 49,128, 51,128, 31, 0, 0, 0, 2, 0, 12, 0, 56, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_225[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56,192,125,128, 99,128, 97,128, 97,128, 49,128, 29,128, 7,128, 1,128, 49,128, 51,128, 31, 0, 0, 0, 8, 0, 6, 0, 3,128, 1,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_226[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56,192,125,128, 99,128, 97,128, 97,128, 49,128, 29,128, 7,128, 1,128, 49,128, 51,128, 31, 0, 0, 0, 33, 0, 18, 0, 30, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_227[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56,192,125,128, 99,128, 97,128, 97,128, 49,128, 29,128, 7,128, 1,128, 49,128, 51,128, 31, 0, 0, 0, 0, 0, 46, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_228[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56,192,125,128, 99,128, 97,128, 97,128, 49,128, 29,128, 7,128, 1,128, 49,128, 51,128, 31, 0, 0, 0, 0, 0, 51, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_229[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56,192,125,128, 99,128, 97,128, 97,128, 49,128, 29,128, 7,128, 1,128, 49,128, 51,128, 31, 0, 0, 0, 14, 0, 17, 0, 17, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_230[] = { 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56,120,125,252, 99,194, 97,128, 97,128, 49,128, 29,128, 7,254, 1,134, 49,134, 51,204, 30,120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_231[] = { 11, 0, 0, 30, 0, 51, 0, 3, 0, 15, 0, 12, 0, 4, 0, 15, 0, 63,128, 56, 64,112, 0, 96, 0, 96, 0, 96, 0, 96, 0, 96, 0, 32,192, 49,192, 15,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_232[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 63,128, 56, 64,112, 0, 96, 0, 96, 0, 96, 0,127,192, 96,192, 32,192, 49,128, 15, 0, 0, 0, 2, 0, 12, 0, 56, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_233[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 63,128, 56, 64,112, 0, 96, 0, 96, 0, 96, 0,127,192, 96,192, 32,192, 49,128, 15, 0, 0, 0, 8, 0, 6, 0, 3,128, 1,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_234[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 63,128, 56, 64,112, 0, 96, 0, 96, 0, 96, 0,127,192, 96,192, 32,192, 49,128, 15, 0, 0, 0, 16,128, 9, 0, 15, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_235[] = { 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 63,128, 56, 64,112, 0, 96, 0, 96, 0, 96, 0,127,192, 96,192, 32,192, 49,128, 15, 0, 0, 0, 0, 0, 25,128, 25,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_236[] = { 6, 0, 0, 0, 0, 0, 0, 0,120, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,112, 0, 8, 48,224,192, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_237[] = { 6, 0, 0, 0, 0, 0, 0, 0,120, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,112, 0, 64, 48, 28, 12, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_238[] = { 6, 0, 0, 0, 0, 0, 0, 0,120, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,112, 0,132, 72,120, 48, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_239[] = { 6, 0, 0, 0, 0, 0, 0, 0,120, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,112, 0, 0,204,204, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_240[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 57,192, 48,192, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 48,192, 57,192, 15,128, 99, 0, 30, 0, 15, 0, 56,192, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_241[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,120,240, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 56,224, 55,192,115,128, 0, 0, 0, 0, 19,128, 14, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_242[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 57,192, 48,192, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 48,192, 57,192, 15, 0, 0, 0, 1, 0, 6, 0, 28, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_243[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 57,192, 48,192, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 48,192, 57,192, 15, 0, 0, 0, 4, 0, 3, 0, 1,192, 0,192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_244[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 57,192, 48,192, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 48,192, 57,192, 15, 0, 0, 0, 16,128, 9, 0, 15, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_245[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 57,192, 48,192, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 48,192, 57,192, 15, 0, 0, 0, 0, 0, 19,128, 14, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_246[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 57,192, 48,192, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 48,192, 57,192, 15, 0, 0, 0, 0, 0, 25,128, 25,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_247[] = { 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3, 0, 0, 0, 0, 0,127,248,127,248, 0, 0, 0, 0, 3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_248[] = { 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0,111, 0, 57,192, 56,192,104, 96,108, 96,100, 96,102, 96, 98, 96, 99, 96, 49,192, 57,192, 15, 96, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_249[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14,112, 31, 96, 56,224, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96,112,224, 0, 0, 1, 0, 6, 0, 28, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_250[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14,112, 31, 96, 56,224, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96,112,224, 0, 0, 4, 0, 3, 0, 1,192, 0,192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_251[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14,112, 31, 96, 56,224, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96,112,224, 0, 0, 16,128, 9, 0, 15, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_252[] = { 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14,112, 31, 96, 56,224, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96,112,224, 0, 0, 0, 0, 25,128, 25,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_253[] = { 11, 0, 0, 0, 0,224, 0,240, 0, 24, 0, 8, 0, 12, 0, 4, 0, 14, 0, 14, 0, 26, 0, 25, 0, 25, 0, 49, 0, 48,128, 48,128, 96,128, 96,192,241,224, 0, 0, 8, 0, 6, 0, 3,128, 1,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_254[] = { 12, 0, 0, 0, 0,120, 0, 48, 0, 48, 0, 48, 0, 48, 0, 55, 0, 57,192, 48,192, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48, 96, 48,192, 57,192, 55, 0, 48, 0, 48, 0, 48, 0, 48, 0,112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const GLubyte TimesRoman24_Character_255[] = { 11, 0, 0, 0, 0,224, 0,240, 0, 24, 0, 8, 0, 12, 0, 4, 0, 14, 0, 14, 0, 26, 0, 25, 0, 25, 0, 49, 0, 48,128, 48,128, 96,128, 96,192,241,224, 0, 0, 0, 0, 51, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +/* The font characters mapping: */ +static const GLubyte* TimesRoman24_Character_Map[] = {TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032, + TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032, + TimesRoman24_Character_032,TimesRoman24_Character_033,TimesRoman24_Character_034,TimesRoman24_Character_035,TimesRoman24_Character_036,TimesRoman24_Character_037,TimesRoman24_Character_038,TimesRoman24_Character_039,TimesRoman24_Character_040,TimesRoman24_Character_041,TimesRoman24_Character_042,TimesRoman24_Character_043,TimesRoman24_Character_044,TimesRoman24_Character_045,TimesRoman24_Character_046,TimesRoman24_Character_047, + TimesRoman24_Character_048,TimesRoman24_Character_049,TimesRoman24_Character_050,TimesRoman24_Character_051,TimesRoman24_Character_052,TimesRoman24_Character_053,TimesRoman24_Character_054,TimesRoman24_Character_055,TimesRoman24_Character_056,TimesRoman24_Character_057,TimesRoman24_Character_058,TimesRoman24_Character_059,TimesRoman24_Character_060,TimesRoman24_Character_061,TimesRoman24_Character_062,TimesRoman24_Character_063, + TimesRoman24_Character_064,TimesRoman24_Character_065,TimesRoman24_Character_066,TimesRoman24_Character_067,TimesRoman24_Character_068,TimesRoman24_Character_069,TimesRoman24_Character_070,TimesRoman24_Character_071,TimesRoman24_Character_072,TimesRoman24_Character_073,TimesRoman24_Character_074,TimesRoman24_Character_075,TimesRoman24_Character_076,TimesRoman24_Character_077,TimesRoman24_Character_078,TimesRoman24_Character_079, + TimesRoman24_Character_080,TimesRoman24_Character_081,TimesRoman24_Character_082,TimesRoman24_Character_083,TimesRoman24_Character_084,TimesRoman24_Character_085,TimesRoman24_Character_086,TimesRoman24_Character_087,TimesRoman24_Character_088,TimesRoman24_Character_089,TimesRoman24_Character_090,TimesRoman24_Character_091,TimesRoman24_Character_092,TimesRoman24_Character_093,TimesRoman24_Character_094,TimesRoman24_Character_095, + TimesRoman24_Character_096,TimesRoman24_Character_097,TimesRoman24_Character_098,TimesRoman24_Character_099,TimesRoman24_Character_100,TimesRoman24_Character_101,TimesRoman24_Character_102,TimesRoman24_Character_103,TimesRoman24_Character_104,TimesRoman24_Character_105,TimesRoman24_Character_106,TimesRoman24_Character_107,TimesRoman24_Character_108,TimesRoman24_Character_109,TimesRoman24_Character_110,TimesRoman24_Character_111, + TimesRoman24_Character_112,TimesRoman24_Character_113,TimesRoman24_Character_114,TimesRoman24_Character_115,TimesRoman24_Character_116,TimesRoman24_Character_117,TimesRoman24_Character_118,TimesRoman24_Character_119,TimesRoman24_Character_120,TimesRoman24_Character_121,TimesRoman24_Character_122,TimesRoman24_Character_123,TimesRoman24_Character_124,TimesRoman24_Character_125,TimesRoman24_Character_126,TimesRoman24_Character_032, + TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032, + TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032,TimesRoman24_Character_032, + TimesRoman24_Character_160,TimesRoman24_Character_161,TimesRoman24_Character_162,TimesRoman24_Character_163,TimesRoman24_Character_164,TimesRoman24_Character_165,TimesRoman24_Character_166,TimesRoman24_Character_167,TimesRoman24_Character_168,TimesRoman24_Character_169,TimesRoman24_Character_170,TimesRoman24_Character_171,TimesRoman24_Character_172,TimesRoman24_Character_173,TimesRoman24_Character_174,TimesRoman24_Character_175, + TimesRoman24_Character_176,TimesRoman24_Character_177,TimesRoman24_Character_178,TimesRoman24_Character_179,TimesRoman24_Character_180,TimesRoman24_Character_181,TimesRoman24_Character_182,TimesRoman24_Character_183,TimesRoman24_Character_184,TimesRoman24_Character_185,TimesRoman24_Character_186,TimesRoman24_Character_187,TimesRoman24_Character_188,TimesRoman24_Character_189,TimesRoman24_Character_190,TimesRoman24_Character_191, + TimesRoman24_Character_192,TimesRoman24_Character_193,TimesRoman24_Character_194,TimesRoman24_Character_195,TimesRoman24_Character_196,TimesRoman24_Character_197,TimesRoman24_Character_198,TimesRoman24_Character_199,TimesRoman24_Character_200,TimesRoman24_Character_201,TimesRoman24_Character_202,TimesRoman24_Character_203,TimesRoman24_Character_204,TimesRoman24_Character_205,TimesRoman24_Character_206,TimesRoman24_Character_207, + TimesRoman24_Character_208,TimesRoman24_Character_209,TimesRoman24_Character_210,TimesRoman24_Character_211,TimesRoman24_Character_212,TimesRoman24_Character_213,TimesRoman24_Character_214,TimesRoman24_Character_215,TimesRoman24_Character_216,TimesRoman24_Character_217,TimesRoman24_Character_218,TimesRoman24_Character_219,TimesRoman24_Character_220,TimesRoman24_Character_221,TimesRoman24_Character_222,TimesRoman24_Character_223, + TimesRoman24_Character_224,TimesRoman24_Character_225,TimesRoman24_Character_226,TimesRoman24_Character_227,TimesRoman24_Character_228,TimesRoman24_Character_229,TimesRoman24_Character_230,TimesRoman24_Character_231,TimesRoman24_Character_232,TimesRoman24_Character_233,TimesRoman24_Character_234,TimesRoman24_Character_235,TimesRoman24_Character_236,TimesRoman24_Character_237,TimesRoman24_Character_238,TimesRoman24_Character_239, + TimesRoman24_Character_240,TimesRoman24_Character_241,TimesRoman24_Character_242,TimesRoman24_Character_243,TimesRoman24_Character_244,TimesRoman24_Character_245,TimesRoman24_Character_246,TimesRoman24_Character_247,TimesRoman24_Character_248,TimesRoman24_Character_249,TimesRoman24_Character_250,TimesRoman24_Character_251,TimesRoman24_Character_252,TimesRoman24_Character_253,TimesRoman24_Character_254,TimesRoman24_Character_255,NULL}; + +/* The font structure: */ +const SFG_Font fgFontTimesRoman24 = { "-adobe-times-medium-r-normal--24-240-75-75-p-124-iso8859-1", 256, 29, TimesRoman24_Character_Map, 0, 7 }; + diff --git a/tests/box2d/freeglut/freeglut_gamemode.c b/tests/box2d/freeglut/freeglut_gamemode.c new file mode 100755 index 00000000..db776b51 --- /dev/null +++ b/tests/box2d/freeglut/freeglut_gamemode.c @@ -0,0 +1,594 @@ +/* + * freeglut_gamemode.c + * + * The game mode handling code. + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, <olszta@sourceforge.net> + * Creation date: Thu Dec 16 1999 + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "freeglut.h" +#include "freeglut_internal.h" + +/* + * TODO BEFORE THE STABLE RELEASE: + * + * glutGameModeString() -- missing + * glutEnterGameMode() -- X11 version + * glutLeaveGameMode() -- is that correct? + * glutGameModeGet() -- is that correct? + */ + + +/* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ + +/* + * Remembers the current visual settings, so that + * we can change them and restore later... + */ +static void fghRememberState( void ) +{ +#if TARGET_HOST_POSIX_X11 + + /* + * This highly depends on the XFree86 extensions, + * not approved as X Consortium standards + */ +# ifdef X_XF86VidModeGetModeLine + + + /* + * Remember the current ViewPort location of the screen to be able to + * restore the ViewPort on LeaveGameMode(): + */ + if( !XF86VidModeGetViewPort( + fgDisplay.Display, + fgDisplay.Screen, + &fgDisplay.DisplayViewPortX, + &fgDisplay.DisplayViewPortY ) ) + fgWarning( "XF86VidModeGetViewPort failed" ); + + /* + * Remember the current pointer location before going fullscreen + * for restoring it later: + */ + { + Window junk_window; + unsigned int mask; + + XQueryPointer( + fgDisplay.Display, fgDisplay.RootWindow, + &junk_window, &junk_window, + &fgDisplay.DisplayPointerX, &fgDisplay.DisplayPointerY, + &fgDisplay.DisplayPointerX, &fgDisplay.DisplayPointerY, &mask + ); + } + + /* Query the current display settings: */ + fgDisplay.DisplayModeValid = + XF86VidModeGetModeLine( + fgDisplay.Display, + fgDisplay.Screen, + &fgDisplay.DisplayModeClock, + &fgDisplay.DisplayMode + ); + + if( !fgDisplay.DisplayModeValid ) + fgWarning( "XF86VidModeGetModeLine failed" ); + +# else + /* + * XXX warning fghRememberState: missing XFree86 video mode extensions, + * XXX game mode will not change screen resolution when activated + */ +# endif + +#elif TARGET_HOST_MS_WINDOWS + +/* DEVMODE devMode; */ + + /* Grab the current desktop settings... */ + +/* hack to get around my stupid cross-gcc headers */ +#define FREEGLUT_ENUM_CURRENT_SETTINGS -1 + + EnumDisplaySettings( NULL, FREEGLUT_ENUM_CURRENT_SETTINGS, + &fgDisplay.DisplayMode ); + + /* Make sure we will be restoring all settings needed */ + fgDisplay.DisplayMode.dmFields |= + DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY; + +#endif +} + +/* + * Restores the previously remembered visual settings + */ +static void fghRestoreState( void ) +{ +#if TARGET_HOST_POSIX_X11 + +# ifdef X_XF86VidModeGetAllModeLines + /* Restore the remembered pointer position: */ + XWarpPointer( + fgDisplay.Display, None, fgDisplay.RootWindow, 0, 0, 0, 0, + fgDisplay.DisplayPointerX, fgDisplay.DisplayPointerY + ); + + /* + * This highly depends on the XFree86 extensions, + * not approved as X Consortium standards + */ + + if( fgDisplay.DisplayModeValid ) + { + XF86VidModeModeInfo** displayModes; + int i, displayModesCount; + + if( !XF86VidModeGetAllModeLines( + fgDisplay.Display, + fgDisplay.Screen, + &displayModesCount, + &displayModes ) ) + { + fgWarning( "XF86VidModeGetAllModeLines failed" ); + return; + } + + + /* + * Check every of the modes looking for one that matches our demands. + * If we find one, switch to it and restore the remembered viewport. + */ + for( i = 0; i < displayModesCount; i++ ) + { + if(displayModes[ i ]->hdisplay == fgDisplay.DisplayMode.hdisplay && + displayModes[ i ]->vdisplay == fgDisplay.DisplayMode.vdisplay && + displayModes[ i ]->dotclock == fgDisplay.DisplayModeClock ) + { + if( !XF86VidModeSwitchToMode( + fgDisplay.Display, + fgDisplay.Screen, + displayModes[ i ] ) ) + { + fgWarning( "XF86VidModeSwitchToMode failed" ); + break; + } + + if( !XF86VidModeSetViewPort( + fgDisplay.Display, + fgDisplay.Screen, + fgDisplay.DisplayViewPortX, + fgDisplay.DisplayViewPortY ) ) + fgWarning( "XF86VidModeSetViewPort failed" ); + + + /* + * For the case this would be the last X11 call the application + * calls exit() we've to flush the X11 output queue to have the + * commands sent to the X server before the application exits. + */ + XFlush( fgDisplay.Display ); + + break; + } + } + XFree( displayModes ); + } + +# else + /* + * XXX warning fghRestoreState: missing XFree86 video mode extensions, + * XXX game mode will not change screen resolution when activated + */ +# endif + +#elif TARGET_HOST_MS_WINDOWS + + /* Restore the previously rememebered desktop display settings */ + ChangeDisplaySettings( &fgDisplay.DisplayMode, 0 ); + +#endif +} + +#if TARGET_HOST_POSIX_X11 +#ifdef X_XF86VidModeGetAllModeLines + +/* + * Checks a single display mode settings against user's preferences. + */ +static GLboolean fghCheckDisplayMode( int width, int height, int depth, int refresh ) +{ + /* The desired values should be stored in fgState structure... */ + return ( width == fgState.GameModeSize.X ) && + ( height == fgState.GameModeSize.Y ) && + ( depth == fgState.GameModeDepth ) && + ( refresh == fgState.GameModeRefresh ); +} + +/* + * Checks all display modes settings against user's preferences. + * Returns the mode number found or -1 if none could be found. + */ +static int fghCheckDisplayModes( GLboolean exactMatch, int displayModesCount, XF86VidModeModeInfo** displayModes ) +{ + int i; + for( i = 0; i < displayModesCount; i++ ) + { + /* Compute the displays refresh rate, dotclock comes in kHz. */ + int refresh = ( displayModes[ i ]->dotclock * 1000 ) / + ( displayModes[ i ]->htotal * displayModes[ i ]->vtotal ); + + if( fghCheckDisplayMode( displayModes[ i ]->hdisplay, + displayModes[ i ]->vdisplay, + fgState.GameModeDepth, + ( exactMatch ? refresh : fgState.GameModeRefresh ) ) ) { + return i; + } + } + return -1; +} + +#endif +#endif + +/* + * Changes the current display mode to match user's settings + */ +static GLboolean fghChangeDisplayMode( GLboolean haveToTest ) +{ + GLboolean success = GL_FALSE; +#if TARGET_HOST_POSIX_X11 + + /* + * This highly depends on the XFree86 extensions, + * not approved as X Consortium standards + */ +# ifdef X_XF86VidModeGetAllModeLines + + /* + * This is also used by applcations which check modes by calling + * glutGameModeGet(GLUT_GAME_MODE_POSSIBLE), so allow the check: + */ + if( haveToTest || fgDisplay.DisplayModeValid ) + { + XF86VidModeModeInfo** displayModes; + int i, displayModesCount; + + if( !XF86VidModeGetAllModeLines( + fgDisplay.Display, + fgDisplay.Screen, + &displayModesCount, + &displayModes ) ) + { + fgWarning( "XF86VidModeGetAllModeLines failed" ); + return success; + } + + + /* + * Check every of the modes looking for one that matches our demands, + * ignoring the refresh rate if no exact match could be found. + */ + i = fghCheckDisplayModes( GL_TRUE, displayModesCount, displayModes ); + if( i < 0 ) { + i = fghCheckDisplayModes( GL_FALSE, displayModesCount, displayModes ); + } + success = ( i < 0 ) ? GL_FALSE : GL_TRUE; + + if( !haveToTest && success ) { + if( !XF86VidModeSwitchToMode( + fgDisplay.Display, + fgDisplay.Screen, + displayModes[ i ] ) ) + fgWarning( "XF86VidModeSwitchToMode failed" ); + } + + XFree( displayModes ); + } + +# else + + /* + * XXX warning fghChangeDisplayMode: missing XFree86 video mode extensions, + * XXX game mode will not change screen resolution when activated + */ + success = GL_TRUE; + +# endif + +#elif TARGET_HOST_MS_WINDOWS + + DEVMODE devMode; + char *fggmstr = NULL; + + success = GL_FALSE; + + EnumDisplaySettings( NULL, -1, &devMode ); + devMode.dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY; + + devMode.dmPelsWidth = fgState.GameModeSize.X; + devMode.dmPelsHeight = fgState.GameModeSize.Y; + devMode.dmBitsPerPel = fgState.GameModeDepth; + devMode.dmDisplayFrequency = fgState.GameModeRefresh; + devMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY; + + switch ( ChangeDisplaySettingsEx(NULL, &devMode, NULL, haveToTest ? CDS_TEST : CDS_FULLSCREEN , NULL) ) + { + case DISP_CHANGE_SUCCESSFUL: + success = GL_TRUE; + + /* update vars in case if windows switched to proper mode */ + EnumDisplaySettings( NULL, FREEGLUT_ENUM_CURRENT_SETTINGS, &devMode ); + fgState.GameModeSize.X = devMode.dmPelsWidth; + fgState.GameModeSize.Y = devMode.dmPelsHeight; + fgState.GameModeDepth = devMode.dmBitsPerPel; + fgState.GameModeRefresh = devMode.dmDisplayFrequency; + break; + case DISP_CHANGE_RESTART: + fggmstr = "The computer must be restarted for the graphics mode to work."; + break; + case DISP_CHANGE_BADFLAGS: + fggmstr = "An invalid set of flags was passed in."; + break; + case DISP_CHANGE_BADPARAM: + fggmstr = "An invalid parameter was passed in. This can include an invalid flag or combination of flags."; + break; + case DISP_CHANGE_FAILED: + fggmstr = "The display driver failed the specified graphics mode."; + break; + case DISP_CHANGE_BADMODE: + fggmstr = "The graphics mode is not supported."; + break; + default: + fggmstr = "Unknown error in graphics mode???"; /* dunno if it is possible,MSDN does not mention any other error */ + break; + } + + if ( !success ) + fgWarning(fggmstr); /* I'd rather get info whats going on in my program than wonder about */ + /* magic happenings behind my back, its lib for devels at last ;) */ +#endif + + return success; +} + + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +/* + * Sets the game mode display string + */ +void FGAPIENTRY glutGameModeString( const char* string ) +{ + int width = 640, height = 480, depth = 16, refresh = 72; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGameModeString" ); + + /* + * This one seems a bit easier than glutInitDisplayString. The bad thing + * about it that I was unable to find the game mode string definition, so + * that I assumed it is: "[width]x[height]:[depth]@[refresh rate]", which + * appears in all GLUT game mode programs I have seen to date. + */ + if( sscanf( string, "%ix%i:%i@%i", &width, &height, &depth, &refresh ) != + 4 ) + if( sscanf( string, "%ix%i:%i", &width, &height, &depth ) != 3 ) + if( sscanf( string, "%ix%i@%i", &width, &height, &refresh ) != 3 ) + if( sscanf( string, "%ix%i", &width, &height ) != 2 ) + if( sscanf( string, ":%i@%i", &depth, &refresh ) != 2 ) + if( sscanf( string, ":%i", &depth ) != 1 ) + if( sscanf( string, "@%i", &refresh ) != 1 ) + fgWarning( + "unable to parse game mode string `%s'", + string + ); + + /* Hopefully it worked, and if not, we still have the default values */ + fgState.GameModeSize.X = width; + fgState.GameModeSize.Y = height; + fgState.GameModeDepth = depth; + fgState.GameModeRefresh = refresh; +} + +/* + * Enters the game mode + */ +int FGAPIENTRY glutEnterGameMode( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutEnterGameMode" ); + + if( fgStructure.GameModeWindow ) + fgAddToWindowDestroyList( fgStructure.GameModeWindow ); + else + fghRememberState( ); + + if( ! fghChangeDisplayMode( GL_FALSE ) ) + { + fgWarning( "failed to change screen settings" ); + return 0; + } + + fgStructure.GameModeWindow = fgCreateWindow( + NULL, "FREEGLUT", GL_TRUE, 0, 0, + GL_TRUE, fgState.GameModeSize.X, fgState.GameModeSize.Y, + GL_TRUE, GL_FALSE + ); + + fgStructure.GameModeWindow->State.Width = fgState.GameModeSize.X; + fgStructure.GameModeWindow->State.Height = fgState.GameModeSize.Y; + fgStructure.GameModeWindow->State.NeedToResize = GL_TRUE; + +#if TARGET_HOST_POSIX_X11 + + /* + * Sync needed to avoid a real race, the Xserver must have really created + * the window before we can grab the pointer into it: + */ + XSync( fgDisplay.Display, False ); + + /* + * Grab the pointer to confine it into the window after the calls to + * XWrapPointer() which ensure that the pointer really enters the window. + * + * We also need to wait here until XGrabPointer() returns GrabSuccess, + * otherwise the new window is not viewable yet and if the next function + * (XSetInputFocus) is called with a not yet viewable window, it will exit + * the application which we have to aviod, so wait until it's viewable: + */ + while( GrabSuccess != XGrabPointer( + fgDisplay.Display, fgStructure.GameModeWindow->Window.Handle, + TRUE, + ButtonPressMask | ButtonReleaseMask | ButtonMotionMask + | PointerMotionMask, + GrabModeAsync, GrabModeAsync, + fgStructure.GameModeWindow->Window.Handle, None, CurrentTime) ) + usleep( 100 ); + + /* + * Change input focus to the new window. This will exit the application + * if the new window is not viewable yet, see the XGrabPointer loop above. + */ + XSetInputFocus( + fgDisplay.Display, + fgStructure.GameModeWindow->Window.Handle, + RevertToNone, + CurrentTime + ); + + /* Move the Pointer to the middle of the fullscreen window */ + XWarpPointer( + fgDisplay.Display, + None, + fgDisplay.RootWindow, + 0, 0, 0, 0, + fgState.GameModeSize.X/2, fgState.GameModeSize.Y/2 + ); + +# ifdef X_XF86VidModeSetViewPort + + if( fgDisplay.DisplayModeValid ) + { + int x, y; + Window child; + + /* Change to viewport to the window topleft edge: */ + if( !XF86VidModeSetViewPort( fgDisplay.Display, fgDisplay.Screen, 0, 0 ) ) + fgWarning( "XF86VidModeSetViewPort failed" ); + + /* + * Final window repositioning: It could be avoided using an undecorated + * window using override_redirect, but this * would possily require + * more changes and investigation. + */ + + /* Get the current postion of the drawable area on screen */ + XTranslateCoordinates( + fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle, + fgDisplay.RootWindow, + 0, 0, &x, &y, + &child + ); + + /* Move the decorataions out of the topleft corner of the display */ + XMoveWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle, + -x, -y); + } + +#endif + + /* Grab the keyboard, too */ + XGrabKeyboard( + fgDisplay.Display, + fgStructure.GameModeWindow->Window.Handle, + FALSE, + GrabModeAsync, GrabModeAsync, + CurrentTime + ); + +#endif + + return fgStructure.GameModeWindow->ID; +} + +/* + * Leaves the game mode + */ +void FGAPIENTRY glutLeaveGameMode( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutLeaveGameMode" ); + + freeglut_return_if_fail( fgStructure.GameModeWindow ); + + fgAddToWindowDestroyList( fgStructure.GameModeWindow ); + fgStructure.GameModeWindow = NULL; + +#if TARGET_HOST_POSIX_X11 + + XUngrabPointer( fgDisplay.Display, CurrentTime ); + XUngrabKeyboard( fgDisplay.Display, CurrentTime ); + +#endif + + fghRestoreState(); +} + +/* + * Returns information concerning the freeglut game mode + */ +int FGAPIENTRY glutGameModeGet( GLenum eWhat ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGameModeGet" ); + + switch( eWhat ) + { + case GLUT_GAME_MODE_ACTIVE: + return !!fgStructure.GameModeWindow; + + case GLUT_GAME_MODE_POSSIBLE: + return fghChangeDisplayMode( GL_TRUE ); + + case GLUT_GAME_MODE_WIDTH: + return fgState.GameModeSize.X; + + case GLUT_GAME_MODE_HEIGHT: + return fgState.GameModeSize.Y; + + case GLUT_GAME_MODE_PIXEL_DEPTH: + return fgState.GameModeDepth; + + case GLUT_GAME_MODE_REFRESH_RATE: + return fgState.GameModeRefresh; + + case GLUT_GAME_MODE_DISPLAY_CHANGED: + /* + * This is true if the game mode has been activated successfully.. + */ + return !!fgStructure.GameModeWindow; + } + + fgWarning( "Unknown gamemode get: %d", eWhat ); + return -1; +} + +/*** END OF FILE ***/ diff --git a/tests/box2d/freeglut/freeglut_geometry.c b/tests/box2d/freeglut/freeglut_geometry.c new file mode 100755 index 00000000..1b6cb7d8 --- /dev/null +++ b/tests/box2d/freeglut/freeglut_geometry.c @@ -0,0 +1,1215 @@ +/* + * freeglut_geometry.c + * + * Freeglut geometry rendering methods. + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, <olszta@sourceforge.net> + * Creation date: Fri Dec 3 1999 + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "freeglut.h" +#include "freeglut_internal.h" + +/* + * TODO BEFORE THE STABLE RELEASE: + * + * Following functions have been contributed by Andreas Umbach. + * + * glutWireCube() -- looks OK + * glutSolidCube() -- OK + * + * Those functions have been implemented by John Fay. + * + * glutWireTorus() -- looks OK + * glutSolidTorus() -- looks OK + * glutWireDodecahedron() -- looks OK + * glutSolidDodecahedron() -- looks OK + * glutWireOctahedron() -- looks OK + * glutSolidOctahedron() -- looks OK + * glutWireTetrahedron() -- looks OK + * glutSolidTetrahedron() -- looks OK + * glutWireIcosahedron() -- looks OK + * glutSolidIcosahedron() -- looks OK + * + * The Following functions have been updated by Nigel Stewart, based + * on FreeGLUT 2.0.0 implementations: + * + * glutWireSphere() -- looks OK + * glutSolidSphere() -- looks OK + * glutWireCone() -- looks OK + * glutSolidCone() -- looks OK + */ + + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +/* + * Draws a wireframed cube. Code contributed by Andreas Umbach <marvin@dataway.ch> + */ +void FGAPIENTRY glutWireCube( GLdouble dSize ) +{ + double size = dSize * 0.5; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCube" ); + +# define V(a,b,c) glVertex3d( a size, b size, c size ); +# define N(a,b,c) glNormal3d( a, b, c ); + + /* PWO: I dared to convert the code to use macros... */ + glBegin( GL_LINE_LOOP ); N( 1.0, 0.0, 0.0); V(+,-,+); V(+,-,-); V(+,+,-); V(+,+,+); glEnd(); + glBegin( GL_LINE_LOOP ); N( 0.0, 1.0, 0.0); V(+,+,+); V(+,+,-); V(-,+,-); V(-,+,+); glEnd(); + glBegin( GL_LINE_LOOP ); N( 0.0, 0.0, 1.0); V(+,+,+); V(-,+,+); V(-,-,+); V(+,-,+); glEnd(); + glBegin( GL_LINE_LOOP ); N(-1.0, 0.0, 0.0); V(-,-,+); V(-,+,+); V(-,+,-); V(-,-,-); glEnd(); + glBegin( GL_LINE_LOOP ); N( 0.0,-1.0, 0.0); V(-,-,+); V(-,-,-); V(+,-,-); V(+,-,+); glEnd(); + glBegin( GL_LINE_LOOP ); N( 0.0, 0.0,-1.0); V(-,-,-); V(-,+,-); V(+,+,-); V(+,-,-); glEnd(); + +# undef V +# undef N +} + +/* + * Draws a solid cube. Code contributed by Andreas Umbach <marvin@dataway.ch> + */ +void FGAPIENTRY glutSolidCube( GLdouble dSize ) +{ + double size = dSize * 0.5; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCube" ); + +# define V(a,b,c) glVertex3d( a size, b size, c size ); +# define N(a,b,c) glNormal3d( a, b, c ); + + /* PWO: Again, I dared to convert the code to use macros... */ + glBegin( GL_QUADS ); + N( 1.0, 0.0, 0.0); V(+,-,+); V(+,-,-); V(+,+,-); V(+,+,+); + N( 0.0, 1.0, 0.0); V(+,+,+); V(+,+,-); V(-,+,-); V(-,+,+); + N( 0.0, 0.0, 1.0); V(+,+,+); V(-,+,+); V(-,-,+); V(+,-,+); + N(-1.0, 0.0, 0.0); V(-,-,+); V(-,+,+); V(-,+,-); V(-,-,-); + N( 0.0,-1.0, 0.0); V(-,-,+); V(-,-,-); V(+,-,-); V(+,-,+); + N( 0.0, 0.0,-1.0); V(-,-,-); V(-,+,-); V(+,+,-); V(+,-,-); + glEnd(); + +# undef V +# undef N +} + +/* + * Compute lookup table of cos and sin values forming a cirle + * + * Notes: + * It is the responsibility of the caller to free these tables + * The size of the table is (n+1) to form a connected loop + * The last entry is exactly the same as the first + * The sign of n can be flipped to get the reverse loop + */ + +static void fghCircleTable(double **sint,double **cost,const int n) +{ + int i; + + /* Table size, the sign of n flips the circle direction */ + + const int size = abs(n); + + /* Determine the angle between samples */ + + const double angle = 2*M_PI/(double)( ( n == 0 ) ? 1 : n ); + + /* Allocate memory for n samples, plus duplicate of first entry at the end */ + + *sint = (double *) calloc(sizeof(double), size+1); + *cost = (double *) calloc(sizeof(double), size+1); + + /* Bail out if memory allocation fails, fgError never returns */ + + if (!(*sint) || !(*cost)) + { + free(*sint); + free(*cost); + fgError("Failed to allocate memory in fghCircleTable"); + } + + /* Compute cos and sin around the circle */ + + (*sint)[0] = 0.0; + (*cost)[0] = 1.0; + + for (i=1; i<size; i++) + { + (*sint)[i] = sin(angle*i); + (*cost)[i] = cos(angle*i); + } + + /* Last sample is duplicate of the first */ + + (*sint)[size] = (*sint)[0]; + (*cost)[size] = (*cost)[0]; +} + +/* + * Draws a solid sphere + */ +void FGAPIENTRY glutSolidSphere(GLdouble radius, GLint slices, GLint stacks) +{ + int i,j; + + /* Adjust z and radius as stacks are drawn. */ + + double z0,z1; + double r0,r1; + + /* Pre-computed circle */ + + double *sint1,*cost1; + double *sint2,*cost2; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidSphere" ); + + fghCircleTable(&sint1,&cost1,-slices); + fghCircleTable(&sint2,&cost2,stacks*2); + + /* The top stack is covered with a triangle fan */ + + z0 = 1.0; + z1 = cost2[(stacks>0)?1:0]; + r0 = 0.0; + r1 = sint2[(stacks>0)?1:0]; + + glBegin(GL_TRIANGLE_FAN); + + glNormal3d(0,0,1); + glVertex3d(0,0,radius); + + for (j=slices; j>=0; j--) + { + glNormal3d(cost1[j]*r1, sint1[j]*r1, z1 ); + glVertex3d(cost1[j]*r1*radius, sint1[j]*r1*radius, z1*radius); + } + + glEnd(); + + /* Cover each stack with a quad strip, except the top and bottom stacks */ + + for( i=1; i<stacks-1; i++ ) + { + z0 = z1; z1 = cost2[i+1]; + r0 = r1; r1 = sint2[i+1]; + + glBegin(GL_QUAD_STRIP); + + for(j=0; j<=slices; j++) + { + glNormal3d(cost1[j]*r1, sint1[j]*r1, z1 ); + glVertex3d(cost1[j]*r1*radius, sint1[j]*r1*radius, z1*radius); + glNormal3d(cost1[j]*r0, sint1[j]*r0, z0 ); + glVertex3d(cost1[j]*r0*radius, sint1[j]*r0*radius, z0*radius); + } + + glEnd(); + } + + /* The bottom stack is covered with a triangle fan */ + + z0 = z1; + r0 = r1; + + glBegin(GL_TRIANGLE_FAN); + + glNormal3d(0,0,-1); + glVertex3d(0,0,-radius); + + for (j=0; j<=slices; j++) + { + glNormal3d(cost1[j]*r0, sint1[j]*r0, z0 ); + glVertex3d(cost1[j]*r0*radius, sint1[j]*r0*radius, z0*radius); + } + + glEnd(); + + /* Release sin and cos tables */ + + free(sint1); + free(cost1); + free(sint2); + free(cost2); +} + +/* + * Draws a wire sphere + */ +void FGAPIENTRY glutWireSphere(GLdouble radius, GLint slices, GLint stacks) +{ + int i,j; + + /* Adjust z and radius as stacks and slices are drawn. */ + + double r; + double x,y,z; + + /* Pre-computed circle */ + + double *sint1,*cost1; + double *sint2,*cost2; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireSphere" ); + + fghCircleTable(&sint1,&cost1,-slices ); + fghCircleTable(&sint2,&cost2, stacks*2); + + /* Draw a line loop for each stack */ + + for (i=1; i<stacks; i++) + { + z = cost2[i]; + r = sint2[i]; + + glBegin(GL_LINE_LOOP); + + for(j=0; j<=slices; j++) + { + x = cost1[j]; + y = sint1[j]; + + glNormal3d(x,y,z); + glVertex3d(x*r*radius,y*r*radius,z*radius); + } + + glEnd(); + } + + /* Draw a line loop for each slice */ + + for (i=0; i<slices; i++) + { + glBegin(GL_LINE_STRIP); + + for(j=0; j<=stacks; j++) + { + x = cost1[i]*sint2[j]; + y = sint1[i]*sint2[j]; + z = cost2[j]; + + glNormal3d(x,y,z); + glVertex3d(x*radius,y*radius,z*radius); + } + + glEnd(); + } + + /* Release sin and cos tables */ + + free(sint1); + free(cost1); + free(sint2); + free(cost2); +} + +/* + * Draws a solid cone + */ +void FGAPIENTRY glutSolidCone( GLdouble base, GLdouble height, GLint slices, GLint stacks ) +{ + int i,j; + + /* Step in z and radius as stacks are drawn. */ + + double z0,z1; + double r0,r1; + + const double zStep = height / ( ( stacks > 0 ) ? stacks : 1 ); + const double rStep = base / ( ( stacks > 0 ) ? stacks : 1 ); + + /* Scaling factors for vertex normals */ + + const double cosn = ( height / sqrt ( height * height + base * base )); + const double sinn = ( base / sqrt ( height * height + base * base )); + + /* Pre-computed circle */ + + double *sint,*cost; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCone" ); + + fghCircleTable(&sint,&cost,-slices); + + /* Cover the circular base with a triangle fan... */ + + z0 = 0.0; + z1 = zStep; + + r0 = base; + r1 = r0 - rStep; + + glBegin(GL_TRIANGLE_FAN); + + glNormal3d(0.0,0.0,-1.0); + glVertex3d(0.0,0.0, z0 ); + + for (j=0; j<=slices; j++) + glVertex3d(cost[j]*r0, sint[j]*r0, z0); + + glEnd(); + + /* Cover each stack with a quad strip, except the top stack */ + + for( i=0; i<stacks-1; i++ ) + { + glBegin(GL_QUAD_STRIP); + + for(j=0; j<=slices; j++) + { + glNormal3d(cost[j]*sinn, sint[j]*sinn, cosn); + glVertex3d(cost[j]*r0, sint[j]*r0, z0 ); + glVertex3d(cost[j]*r1, sint[j]*r1, z1 ); + } + + z0 = z1; z1 += zStep; + r0 = r1; r1 -= rStep; + + glEnd(); + } + + /* The top stack is covered with individual triangles */ + + glBegin(GL_TRIANGLES); + + glNormal3d(cost[0]*sinn, sint[0]*sinn, cosn); + + for (j=0; j<slices; j++) + { + glVertex3d(cost[j+0]*r0, sint[j+0]*r0, z0 ); + glVertex3d(0, 0, height); + glNormal3d(cost[j+1]*sinn, sint[j+1]*sinn, cosn ); + glVertex3d(cost[j+1]*r0, sint[j+1]*r0, z0 ); + } + + glEnd(); + + /* Release sin and cos tables */ + + free(sint); + free(cost); +} + +/* + * Draws a wire cone + */ +void FGAPIENTRY glutWireCone( GLdouble base, GLdouble height, GLint slices, GLint stacks) +{ + int i,j; + + /* Step in z and radius as stacks are drawn. */ + + double z = 0.0; + double r = base; + + const double zStep = height / ( ( stacks > 0 ) ? stacks : 1 ); + const double rStep = base / ( ( stacks > 0 ) ? stacks : 1 ); + + /* Scaling factors for vertex normals */ + + const double cosn = ( height / sqrt ( height * height + base * base )); + const double sinn = ( base / sqrt ( height * height + base * base )); + + /* Pre-computed circle */ + + double *sint,*cost; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCone" ); + + fghCircleTable(&sint,&cost,-slices); + + /* Draw the stacks... */ + + for (i=0; i<stacks; i++) + { + glBegin(GL_LINE_LOOP); + + for( j=0; j<slices; j++ ) + { + glNormal3d(cost[j]*sinn, sint[j]*sinn, cosn); + glVertex3d(cost[j]*r, sint[j]*r, z ); + } + + glEnd(); + + z += zStep; + r -= rStep; + } + + /* Draw the slices */ + + r = base; + + glBegin(GL_LINES); + + for (j=0; j<slices; j++) + { + glNormal3d(cost[j]*sinn, sint[j]*sinn, cosn ); + glVertex3d(cost[j]*r, sint[j]*r, 0.0 ); + glVertex3d(0.0, 0.0, height); + } + + glEnd(); + + /* Release sin and cos tables */ + + free(sint); + free(cost); +} + + +/* + * Draws a solid cylinder + */ +void FGAPIENTRY glutSolidCylinder(GLdouble radius, GLdouble height, GLint slices, GLint stacks) +{ + int i,j; + + /* Step in z and radius as stacks are drawn. */ + + double z0,z1; + const double zStep = height / ( ( stacks > 0 ) ? stacks : 1 ); + + /* Pre-computed circle */ + + double *sint,*cost; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCylinder" ); + + fghCircleTable(&sint,&cost,-slices); + + /* Cover the base and top */ + + glBegin(GL_TRIANGLE_FAN); + glNormal3d(0.0, 0.0, -1.0 ); + glVertex3d(0.0, 0.0, 0.0 ); + for (j=0; j<=slices; j++) + glVertex3d(cost[j]*radius, sint[j]*radius, 0.0); + glEnd(); + + glBegin(GL_TRIANGLE_FAN); + glNormal3d(0.0, 0.0, 1.0 ); + glVertex3d(0.0, 0.0, height); + for (j=slices; j>=0; j--) + glVertex3d(cost[j]*radius, sint[j]*radius, height); + glEnd(); + + /* Do the stacks */ + + z0 = 0.0; + z1 = zStep; + + for (i=1; i<=stacks; i++) + { + if (i==stacks) + z1 = height; + + glBegin(GL_QUAD_STRIP); + for (j=0; j<=slices; j++ ) + { + glNormal3d(cost[j], sint[j], 0.0 ); + glVertex3d(cost[j]*radius, sint[j]*radius, z0 ); + glVertex3d(cost[j]*radius, sint[j]*radius, z1 ); + } + glEnd(); + + z0 = z1; z1 += zStep; + } + + /* Release sin and cos tables */ + + free(sint); + free(cost); +} + +/* + * Draws a wire cylinder + */ +void FGAPIENTRY glutWireCylinder(GLdouble radius, GLdouble height, GLint slices, GLint stacks) +{ + int i,j; + + /* Step in z and radius as stacks are drawn. */ + + double z = 0.0; + const double zStep = height / ( ( stacks > 0 ) ? stacks : 1 ); + + /* Pre-computed circle */ + + double *sint,*cost; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCylinder" ); + + fghCircleTable(&sint,&cost,-slices); + + /* Draw the stacks... */ + + for (i=0; i<=stacks; i++) + { + if (i==stacks) + z = height; + + glBegin(GL_LINE_LOOP); + + for( j=0; j<slices; j++ ) + { + glNormal3d(cost[j], sint[j], 0.0); + glVertex3d(cost[j]*radius, sint[j]*radius, z ); + } + + glEnd(); + + z += zStep; + } + + /* Draw the slices */ + + glBegin(GL_LINES); + + for (j=0; j<slices; j++) + { + glNormal3d(cost[j], sint[j], 0.0 ); + glVertex3d(cost[j]*radius, sint[j]*radius, 0.0 ); + glVertex3d(cost[j]*radius, sint[j]*radius, height); + } + + glEnd(); + + /* Release sin and cos tables */ + + free(sint); + free(cost); +} + +/* + * Draws a wire torus + */ +void FGAPIENTRY glutWireTorus( GLdouble dInnerRadius, GLdouble dOuterRadius, GLint nSides, GLint nRings ) +{ + double iradius = dInnerRadius, oradius = dOuterRadius, phi, psi, dpsi, dphi; + double *vertex, *normal; + int i, j; + double spsi, cpsi, sphi, cphi ; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireTorus" ); + + if ( nSides < 1 ) nSides = 1; + if ( nRings < 1 ) nRings = 1; + + /* Allocate the vertices array */ + vertex = (double *)calloc( sizeof(double), 3 * nSides * nRings ); + normal = (double *)calloc( sizeof(double), 3 * nSides * nRings ); + + glPushMatrix(); + + dpsi = 2.0 * M_PI / (double)nRings ; + dphi = -2.0 * M_PI / (double)nSides ; + psi = 0.0; + + for( j=0; j<nRings; j++ ) + { + cpsi = cos ( psi ) ; + spsi = sin ( psi ) ; + phi = 0.0; + + for( i=0; i<nSides; i++ ) + { + int offset = 3 * ( j * nSides + i ) ; + cphi = cos ( phi ) ; + sphi = sin ( phi ) ; + *(vertex + offset + 0) = cpsi * ( oradius + cphi * iradius ) ; + *(vertex + offset + 1) = spsi * ( oradius + cphi * iradius ) ; + *(vertex + offset + 2) = sphi * iradius ; + *(normal + offset + 0) = cpsi * cphi ; + *(normal + offset + 1) = spsi * cphi ; + *(normal + offset + 2) = sphi ; + phi += dphi; + } + + psi += dpsi; + } + + for( i=0; i<nSides; i++ ) + { + glBegin( GL_LINE_LOOP ); + + for( j=0; j<nRings; j++ ) + { + int offset = 3 * ( j * nSides + i ) ; + glNormal3dv( normal + offset ); + glVertex3dv( vertex + offset ); + } + + glEnd(); + } + + for( j=0; j<nRings; j++ ) + { + glBegin(GL_LINE_LOOP); + + for( i=0; i<nSides; i++ ) + { + int offset = 3 * ( j * nSides + i ) ; + glNormal3dv( normal + offset ); + glVertex3dv( vertex + offset ); + } + + glEnd(); + } + + free ( vertex ) ; + free ( normal ) ; + glPopMatrix(); +} + +/* + * Draws a solid torus + */ +void FGAPIENTRY glutSolidTorus( GLdouble dInnerRadius, GLdouble dOuterRadius, GLint nSides, GLint nRings ) +{ + double iradius = dInnerRadius, oradius = dOuterRadius, phi, psi, dpsi, dphi; + double *vertex, *normal; + int i, j; + double spsi, cpsi, sphi, cphi ; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidTorus" ); + + if ( nSides < 1 ) nSides = 1; + if ( nRings < 1 ) nRings = 1; + + /* Increment the number of sides and rings to allow for one more point than surface */ + nSides ++ ; + nRings ++ ; + + /* Allocate the vertices array */ + vertex = (double *)calloc( sizeof(double), 3 * nSides * nRings ); + normal = (double *)calloc( sizeof(double), 3 * nSides * nRings ); + + glPushMatrix(); + + dpsi = 2.0 * M_PI / (double)(nRings - 1) ; + dphi = -2.0 * M_PI / (double)(nSides - 1) ; + psi = 0.0; + + for( j=0; j<nRings; j++ ) + { + cpsi = cos ( psi ) ; + spsi = sin ( psi ) ; + phi = 0.0; + + for( i=0; i<nSides; i++ ) + { + int offset = 3 * ( j * nSides + i ) ; + cphi = cos ( phi ) ; + sphi = sin ( phi ) ; + *(vertex + offset + 0) = cpsi * ( oradius + cphi * iradius ) ; + *(vertex + offset + 1) = spsi * ( oradius + cphi * iradius ) ; + *(vertex + offset + 2) = sphi * iradius ; + *(normal + offset + 0) = cpsi * cphi ; + *(normal + offset + 1) = spsi * cphi ; + *(normal + offset + 2) = sphi ; + phi += dphi; + } + + psi += dpsi; + } + + glBegin( GL_QUADS ); + for( i=0; i<nSides-1; i++ ) + { + for( j=0; j<nRings-1; j++ ) + { + int offset = 3 * ( j * nSides + i ) ; + glNormal3dv( normal + offset ); + glVertex3dv( vertex + offset ); + glNormal3dv( normal + offset + 3 ); + glVertex3dv( vertex + offset + 3 ); + glNormal3dv( normal + offset + 3 * nSides + 3 ); + glVertex3dv( vertex + offset + 3 * nSides + 3 ); + glNormal3dv( normal + offset + 3 * nSides ); + glVertex3dv( vertex + offset + 3 * nSides ); + } + } + + glEnd(); + + free ( vertex ) ; + free ( normal ) ; + glPopMatrix(); +} + +/* + * + */ +void FGAPIENTRY glutWireDodecahedron( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireDodecahedron" ); + + /* Magic Numbers: It is possible to create a dodecahedron by attaching two pentagons to each face of + * of a cube. The coordinates of the points are: + * (+-x,0, z); (+-1, 1, 1); (0, z, x ) + * where x = (-1 + sqrt(5))/2, z = (1 + sqrt(5))/2 or + * x = 0.61803398875 and z = 1.61803398875. + */ + glBegin ( GL_LINE_LOOP ) ; + glNormal3d ( 0.0, 0.525731112119, 0.850650808354 ) ; glVertex3d ( 0.0, 1.61803398875, 0.61803398875 ) ; glVertex3d ( -1.0, 1.0, 1.0 ) ; glVertex3d ( -0.61803398875, 0.0, 1.61803398875 ) ; glVertex3d ( 0.61803398875, 0.0, 1.61803398875 ) ; glVertex3d ( 1.0, 1.0, 1.0 ) ; + glEnd () ; + glBegin ( GL_LINE_LOOP ) ; + glNormal3d ( 0.0, 0.525731112119, -0.850650808354 ) ; glVertex3d ( 0.0, 1.61803398875, -0.61803398875 ) ; glVertex3d ( 1.0, 1.0, -1.0 ) ; glVertex3d ( 0.61803398875, 0.0, -1.61803398875 ) ; glVertex3d ( -0.61803398875, 0.0, -1.61803398875 ) ; glVertex3d ( -1.0, 1.0, -1.0 ) ; + glEnd () ; + glBegin ( GL_LINE_LOOP ) ; + glNormal3d ( 0.0, -0.525731112119, 0.850650808354 ) ; glVertex3d ( 0.0, -1.61803398875, 0.61803398875 ) ; glVertex3d ( 1.0, -1.0, 1.0 ) ; glVertex3d ( 0.61803398875, 0.0, 1.61803398875 ) ; glVertex3d ( -0.61803398875, 0.0, 1.61803398875 ) ; glVertex3d ( -1.0, -1.0, 1.0 ) ; + glEnd () ; + glBegin ( GL_LINE_LOOP ) ; + glNormal3d ( 0.0, -0.525731112119, -0.850650808354 ) ; glVertex3d ( 0.0, -1.61803398875, -0.61803398875 ) ; glVertex3d ( -1.0, -1.0, -1.0 ) ; glVertex3d ( -0.61803398875, 0.0, -1.61803398875 ) ; glVertex3d ( 0.61803398875, 0.0, -1.61803398875 ) ; glVertex3d ( 1.0, -1.0, -1.0 ) ; + glEnd () ; + + glBegin ( GL_LINE_LOOP ) ; + glNormal3d ( 0.850650808354, 0.0, 0.525731112119 ) ; glVertex3d ( 0.61803398875, 0.0, 1.61803398875 ) ; glVertex3d ( 1.0, -1.0, 1.0 ) ; glVertex3d ( 1.61803398875, -0.61803398875, 0.0 ) ; glVertex3d ( 1.61803398875, 0.61803398875, 0.0 ) ; glVertex3d ( 1.0, 1.0, 1.0 ) ; + glEnd () ; + glBegin ( GL_LINE_LOOP ) ; + glNormal3d ( -0.850650808354, 0.0, 0.525731112119 ) ; glVertex3d ( -0.61803398875, 0.0, 1.61803398875 ) ; glVertex3d ( -1.0, 1.0, 1.0 ) ; glVertex3d ( -1.61803398875, 0.61803398875, 0.0 ) ; glVertex3d ( -1.61803398875, -0.61803398875, 0.0 ) ; glVertex3d ( -1.0, -1.0, 1.0 ) ; + glEnd () ; + glBegin ( GL_LINE_LOOP ) ; + glNormal3d ( 0.850650808354, 0.0, -0.525731112119 ) ; glVertex3d ( 0.61803398875, 0.0, -1.61803398875 ) ; glVertex3d ( 1.0, 1.0, -1.0 ) ; glVertex3d ( 1.61803398875, 0.61803398875, 0.0 ) ; glVertex3d ( 1.61803398875, -0.61803398875, 0.0 ) ; glVertex3d ( 1.0, -1.0, -1.0 ) ; + glEnd () ; + glBegin ( GL_LINE_LOOP ) ; + glNormal3d ( -0.850650808354, 0.0, -0.525731112119 ) ; glVertex3d ( -0.61803398875, 0.0, -1.61803398875 ) ; glVertex3d ( -1.0, -1.0, -1.0 ) ; glVertex3d ( -1.61803398875, -0.61803398875, 0.0 ) ; glVertex3d ( -1.61803398875, 0.61803398875, 0.0 ) ; glVertex3d ( -1.0, 1.0, -1.0 ) ; + glEnd () ; + + glBegin ( GL_LINE_LOOP ) ; + glNormal3d ( 0.525731112119, 0.850650808354, 0.0 ) ; glVertex3d ( 1.61803398875, 0.61803398875, 0.0 ) ; glVertex3d ( 1.0, 1.0, -1.0 ) ; glVertex3d ( 0.0, 1.61803398875, -0.61803398875 ) ; glVertex3d ( 0.0, 1.61803398875, 0.61803398875 ) ; glVertex3d ( 1.0, 1.0, 1.0 ) ; + glEnd () ; + glBegin ( GL_LINE_LOOP ) ; + glNormal3d ( 0.525731112119, -0.850650808354, 0.0 ) ; glVertex3d ( 1.61803398875, -0.61803398875, 0.0 ) ; glVertex3d ( 1.0, -1.0, 1.0 ) ; glVertex3d ( 0.0, -1.61803398875, 0.61803398875 ) ; glVertex3d ( 0.0, -1.61803398875, -0.61803398875 ) ; glVertex3d ( 1.0, -1.0, -1.0 ) ; + glEnd () ; + glBegin ( GL_LINE_LOOP ) ; + glNormal3d ( -0.525731112119, 0.850650808354, 0.0 ) ; glVertex3d ( -1.61803398875, 0.61803398875, 0.0 ) ; glVertex3d ( -1.0, 1.0, 1.0 ) ; glVertex3d ( 0.0, 1.61803398875, 0.61803398875 ) ; glVertex3d ( 0.0, 1.61803398875, -0.61803398875 ) ; glVertex3d ( -1.0, 1.0, -1.0 ) ; + glEnd () ; + glBegin ( GL_LINE_LOOP ) ; + glNormal3d ( -0.525731112119, -0.850650808354, 0.0 ) ; glVertex3d ( -1.61803398875, -0.61803398875, 0.0 ) ; glVertex3d ( -1.0, -1.0, -1.0 ) ; glVertex3d ( 0.0, -1.61803398875, -0.61803398875 ) ; glVertex3d ( 0.0, -1.61803398875, 0.61803398875 ) ; glVertex3d ( -1.0, -1.0, 1.0 ) ; + glEnd () ; +} + +/* + * + */ +void FGAPIENTRY glutSolidDodecahedron( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidDodecahedron" ); + + /* Magic Numbers: It is possible to create a dodecahedron by attaching two pentagons to each face of + * of a cube. The coordinates of the points are: + * (+-x,0, z); (+-1, 1, 1); (0, z, x ) + * where x = (-1 + sqrt(5))/2, z = (1 + sqrt(5))/2 or + * x = 0.61803398875 and z = 1.61803398875. + */ + glBegin ( GL_POLYGON ) ; + glNormal3d ( 0.0, 0.525731112119, 0.850650808354 ) ; glVertex3d ( 0.0, 1.61803398875, 0.61803398875 ) ; glVertex3d ( -1.0, 1.0, 1.0 ) ; glVertex3d ( -0.61803398875, 0.0, 1.61803398875 ) ; glVertex3d ( 0.61803398875, 0.0, 1.61803398875 ) ; glVertex3d ( 1.0, 1.0, 1.0 ) ; + glEnd () ; + glBegin ( GL_POLYGON ) ; + glNormal3d ( 0.0, 0.525731112119, -0.850650808354 ) ; glVertex3d ( 0.0, 1.61803398875, -0.61803398875 ) ; glVertex3d ( 1.0, 1.0, -1.0 ) ; glVertex3d ( 0.61803398875, 0.0, -1.61803398875 ) ; glVertex3d ( -0.61803398875, 0.0, -1.61803398875 ) ; glVertex3d ( -1.0, 1.0, -1.0 ) ; + glEnd () ; + glBegin ( GL_POLYGON ) ; + glNormal3d ( 0.0, -0.525731112119, 0.850650808354 ) ; glVertex3d ( 0.0, -1.61803398875, 0.61803398875 ) ; glVertex3d ( 1.0, -1.0, 1.0 ) ; glVertex3d ( 0.61803398875, 0.0, 1.61803398875 ) ; glVertex3d ( -0.61803398875, 0.0, 1.61803398875 ) ; glVertex3d ( -1.0, -1.0, 1.0 ) ; + glEnd () ; + glBegin ( GL_POLYGON ) ; + glNormal3d ( 0.0, -0.525731112119, -0.850650808354 ) ; glVertex3d ( 0.0, -1.61803398875, -0.61803398875 ) ; glVertex3d ( -1.0, -1.0, -1.0 ) ; glVertex3d ( -0.61803398875, 0.0, -1.61803398875 ) ; glVertex3d ( 0.61803398875, 0.0, -1.61803398875 ) ; glVertex3d ( 1.0, -1.0, -1.0 ) ; + glEnd () ; + + glBegin ( GL_POLYGON ) ; + glNormal3d ( 0.850650808354, 0.0, 0.525731112119 ) ; glVertex3d ( 0.61803398875, 0.0, 1.61803398875 ) ; glVertex3d ( 1.0, -1.0, 1.0 ) ; glVertex3d ( 1.61803398875, -0.61803398875, 0.0 ) ; glVertex3d ( 1.61803398875, 0.61803398875, 0.0 ) ; glVertex3d ( 1.0, 1.0, 1.0 ) ; + glEnd () ; + glBegin ( GL_POLYGON ) ; + glNormal3d ( -0.850650808354, 0.0, 0.525731112119 ) ; glVertex3d ( -0.61803398875, 0.0, 1.61803398875 ) ; glVertex3d ( -1.0, 1.0, 1.0 ) ; glVertex3d ( -1.61803398875, 0.61803398875, 0.0 ) ; glVertex3d ( -1.61803398875, -0.61803398875, 0.0 ) ; glVertex3d ( -1.0, -1.0, 1.0 ) ; + glEnd () ; + glBegin ( GL_POLYGON ) ; + glNormal3d ( 0.850650808354, 0.0, -0.525731112119 ) ; glVertex3d ( 0.61803398875, 0.0, -1.61803398875 ) ; glVertex3d ( 1.0, 1.0, -1.0 ) ; glVertex3d ( 1.61803398875, 0.61803398875, 0.0 ) ; glVertex3d ( 1.61803398875, -0.61803398875, 0.0 ) ; glVertex3d ( 1.0, -1.0, -1.0 ) ; + glEnd () ; + glBegin ( GL_POLYGON ) ; + glNormal3d ( -0.850650808354, 0.0, -0.525731112119 ) ; glVertex3d ( -0.61803398875, 0.0, -1.61803398875 ) ; glVertex3d ( -1.0, -1.0, -1.0 ) ; glVertex3d ( -1.61803398875, -0.61803398875, 0.0 ) ; glVertex3d ( -1.61803398875, 0.61803398875, 0.0 ) ; glVertex3d ( -1.0, 1.0, -1.0 ) ; + glEnd () ; + + glBegin ( GL_POLYGON ) ; + glNormal3d ( 0.525731112119, 0.850650808354, 0.0 ) ; glVertex3d ( 1.61803398875, 0.61803398875, 0.0 ) ; glVertex3d ( 1.0, 1.0, -1.0 ) ; glVertex3d ( 0.0, 1.61803398875, -0.61803398875 ) ; glVertex3d ( 0.0, 1.61803398875, 0.61803398875 ) ; glVertex3d ( 1.0, 1.0, 1.0 ) ; + glEnd () ; + glBegin ( GL_POLYGON ) ; + glNormal3d ( 0.525731112119, -0.850650808354, 0.0 ) ; glVertex3d ( 1.61803398875, -0.61803398875, 0.0 ) ; glVertex3d ( 1.0, -1.0, 1.0 ) ; glVertex3d ( 0.0, -1.61803398875, 0.61803398875 ) ; glVertex3d ( 0.0, -1.61803398875, -0.61803398875 ) ; glVertex3d ( 1.0, -1.0, -1.0 ) ; + glEnd () ; + glBegin ( GL_POLYGON ) ; + glNormal3d ( -0.525731112119, 0.850650808354, 0.0 ) ; glVertex3d ( -1.61803398875, 0.61803398875, 0.0 ) ; glVertex3d ( -1.0, 1.0, 1.0 ) ; glVertex3d ( 0.0, 1.61803398875, 0.61803398875 ) ; glVertex3d ( 0.0, 1.61803398875, -0.61803398875 ) ; glVertex3d ( -1.0, 1.0, -1.0 ) ; + glEnd () ; + glBegin ( GL_POLYGON ) ; + glNormal3d ( -0.525731112119, -0.850650808354, 0.0 ) ; glVertex3d ( -1.61803398875, -0.61803398875, 0.0 ) ; glVertex3d ( -1.0, -1.0, -1.0 ) ; glVertex3d ( 0.0, -1.61803398875, -0.61803398875 ) ; glVertex3d ( 0.0, -1.61803398875, 0.61803398875 ) ; glVertex3d ( -1.0, -1.0, 1.0 ) ; + glEnd () ; +} + +/* + * + */ +void FGAPIENTRY glutWireOctahedron( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireOctahedron" ); + +#define RADIUS 1.0f + glBegin( GL_LINE_LOOP ); + glNormal3d( 0.577350269189, 0.577350269189, 0.577350269189); glVertex3d( RADIUS, 0.0, 0.0 ); glVertex3d( 0.0, RADIUS, 0.0 ); glVertex3d( 0.0, 0.0, RADIUS ); + glNormal3d( 0.577350269189, 0.577350269189,-0.577350269189); glVertex3d( RADIUS, 0.0, 0.0 ); glVertex3d( 0.0, 0.0,-RADIUS ); glVertex3d( 0.0, RADIUS, 0.0 ); + glNormal3d( 0.577350269189,-0.577350269189, 0.577350269189); glVertex3d( RADIUS, 0.0, 0.0 ); glVertex3d( 0.0, 0.0, RADIUS ); glVertex3d( 0.0,-RADIUS, 0.0 ); + glNormal3d( 0.577350269189,-0.577350269189,-0.577350269189); glVertex3d( RADIUS, 0.0, 0.0 ); glVertex3d( 0.0,-RADIUS, 0.0 ); glVertex3d( 0.0, 0.0,-RADIUS ); + glNormal3d(-0.577350269189, 0.577350269189, 0.577350269189); glVertex3d(-RADIUS, 0.0, 0.0 ); glVertex3d( 0.0, 0.0, RADIUS ); glVertex3d( 0.0, RADIUS, 0.0 ); + glNormal3d(-0.577350269189, 0.577350269189,-0.577350269189); glVertex3d(-RADIUS, 0.0, 0.0 ); glVertex3d( 0.0, RADIUS, 0.0 ); glVertex3d( 0.0, 0.0,-RADIUS ); + glNormal3d(-0.577350269189,-0.577350269189, 0.577350269189); glVertex3d(-RADIUS, 0.0, 0.0 ); glVertex3d( 0.0,-RADIUS, 0.0 ); glVertex3d( 0.0, 0.0, RADIUS ); + glNormal3d(-0.577350269189,-0.577350269189,-0.577350269189); glVertex3d(-RADIUS, 0.0, 0.0 ); glVertex3d( 0.0, 0.0,-RADIUS ); glVertex3d( 0.0,-RADIUS, 0.0 ); + glEnd(); +#undef RADIUS +} + +/* + * + */ +void FGAPIENTRY glutSolidOctahedron( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidOctahedron" ); + +#define RADIUS 1.0f + glBegin( GL_TRIANGLES ); + glNormal3d( 0.577350269189, 0.577350269189, 0.577350269189); glVertex3d( RADIUS, 0.0, 0.0 ); glVertex3d( 0.0, RADIUS, 0.0 ); glVertex3d( 0.0, 0.0, RADIUS ); + glNormal3d( 0.577350269189, 0.577350269189,-0.577350269189); glVertex3d( RADIUS, 0.0, 0.0 ); glVertex3d( 0.0, 0.0,-RADIUS ); glVertex3d( 0.0, RADIUS, 0.0 ); + glNormal3d( 0.577350269189,-0.577350269189, 0.577350269189); glVertex3d( RADIUS, 0.0, 0.0 ); glVertex3d( 0.0, 0.0, RADIUS ); glVertex3d( 0.0,-RADIUS, 0.0 ); + glNormal3d( 0.577350269189,-0.577350269189,-0.577350269189); glVertex3d( RADIUS, 0.0, 0.0 ); glVertex3d( 0.0,-RADIUS, 0.0 ); glVertex3d( 0.0, 0.0,-RADIUS ); + glNormal3d(-0.577350269189, 0.577350269189, 0.577350269189); glVertex3d(-RADIUS, 0.0, 0.0 ); glVertex3d( 0.0, 0.0, RADIUS ); glVertex3d( 0.0, RADIUS, 0.0 ); + glNormal3d(-0.577350269189, 0.577350269189,-0.577350269189); glVertex3d(-RADIUS, 0.0, 0.0 ); glVertex3d( 0.0, RADIUS, 0.0 ); glVertex3d( 0.0, 0.0,-RADIUS ); + glNormal3d(-0.577350269189,-0.577350269189, 0.577350269189); glVertex3d(-RADIUS, 0.0, 0.0 ); glVertex3d( 0.0,-RADIUS, 0.0 ); glVertex3d( 0.0, 0.0, RADIUS ); + glNormal3d(-0.577350269189,-0.577350269189,-0.577350269189); glVertex3d(-RADIUS, 0.0, 0.0 ); glVertex3d( 0.0, 0.0,-RADIUS ); glVertex3d( 0.0,-RADIUS, 0.0 ); + glEnd(); +#undef RADIUS +} + +/* Magic Numbers: r0 = ( 1, 0, 0 ) + * r1 = ( -1/3, 2 sqrt(2) / 3, 0 ) + * r2 = ( -1/3, -sqrt(2) / 3, sqrt(6) / 3 ) + * r3 = ( -1/3, -sqrt(2) / 3, -sqrt(6) / 3 ) + * |r0| = |r1| = |r2| = |r3| = 1 + * Distance between any two points is 2 sqrt(6) / 3 + * + * Normals: The unit normals are simply the negative of the coordinates of the point not on the surface. + */ + +#define NUM_TETR_FACES 4 + +static GLdouble tet_r[4][3] = { { 1.0, 0.0, 0.0 }, + { -0.333333333333, 0.942809041582, 0.0 }, + { -0.333333333333, -0.471404520791, 0.816496580928 }, + { -0.333333333333, -0.471404520791, -0.816496580928 } } ; + +static GLint tet_i[4][3] = /* Vertex indices */ +{ + { 1, 3, 2 }, { 0, 2, 3 }, { 0, 3, 1 }, { 0, 1, 2 } +} ; + +/* + * + */ +void FGAPIENTRY glutWireTetrahedron( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireTetrahedron" ); + + glBegin( GL_LINE_LOOP ) ; + glNormal3d ( -tet_r[0][0], -tet_r[0][1], -tet_r[0][2] ) ; glVertex3dv ( tet_r[1] ) ; glVertex3dv ( tet_r[3] ) ; glVertex3dv ( tet_r[2] ) ; + glNormal3d ( -tet_r[1][0], -tet_r[1][1], -tet_r[1][2] ) ; glVertex3dv ( tet_r[0] ) ; glVertex3dv ( tet_r[2] ) ; glVertex3dv ( tet_r[3] ) ; + glNormal3d ( -tet_r[2][0], -tet_r[2][1], -tet_r[2][2] ) ; glVertex3dv ( tet_r[0] ) ; glVertex3dv ( tet_r[3] ) ; glVertex3dv ( tet_r[1] ) ; + glNormal3d ( -tet_r[3][0], -tet_r[3][1], -tet_r[3][2] ) ; glVertex3dv ( tet_r[0] ) ; glVertex3dv ( tet_r[1] ) ; glVertex3dv ( tet_r[2] ) ; + glEnd() ; +} + +/* + * + */ +void FGAPIENTRY glutSolidTetrahedron( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidTetrahedron" ); + + glBegin( GL_TRIANGLES ) ; + glNormal3d ( -tet_r[0][0], -tet_r[0][1], -tet_r[0][2] ) ; glVertex3dv ( tet_r[1] ) ; glVertex3dv ( tet_r[3] ) ; glVertex3dv ( tet_r[2] ) ; + glNormal3d ( -tet_r[1][0], -tet_r[1][1], -tet_r[1][2] ) ; glVertex3dv ( tet_r[0] ) ; glVertex3dv ( tet_r[2] ) ; glVertex3dv ( tet_r[3] ) ; + glNormal3d ( -tet_r[2][0], -tet_r[2][1], -tet_r[2][2] ) ; glVertex3dv ( tet_r[0] ) ; glVertex3dv ( tet_r[3] ) ; glVertex3dv ( tet_r[1] ) ; + glNormal3d ( -tet_r[3][0], -tet_r[3][1], -tet_r[3][2] ) ; glVertex3dv ( tet_r[0] ) ; glVertex3dv ( tet_r[1] ) ; glVertex3dv ( tet_r[2] ) ; + glEnd() ; +} + +/* + * + */ +static double icos_r[12][3] = { + { 1.0, 0.0, 0.0 }, + { 0.447213595500, 0.894427191000, 0.0 }, + { 0.447213595500, 0.276393202252, 0.850650808354 }, + { 0.447213595500, -0.723606797748, 0.525731112119 }, + { 0.447213595500, -0.723606797748, -0.525731112119 }, + { 0.447213595500, 0.276393202252, -0.850650808354 }, + { -0.447213595500, -0.894427191000, 0.0 }, + { -0.447213595500, -0.276393202252, 0.850650808354 }, + { -0.447213595500, 0.723606797748, 0.525731112119 }, + { -0.447213595500, 0.723606797748, -0.525731112119 }, + { -0.447213595500, -0.276393202252, -0.850650808354 }, + { -1.0, 0.0, 0.0 } +}; + +static int icos_v [20][3] = { + { 0, 1, 2 }, + { 0, 2, 3 }, + { 0, 3, 4 }, + { 0, 4, 5 }, + { 0, 5, 1 }, + { 1, 8, 2 }, + { 2, 7, 3 }, + { 3, 6, 4 }, + { 4, 10, 5 }, + { 5, 9, 1 }, + { 1, 9, 8 }, + { 2, 8, 7 }, + { 3, 7, 6 }, + { 4, 6, 10 }, + { 5, 10, 9 }, + { 11, 9, 10 }, + { 11, 8, 9 }, + { 11, 7, 8 }, + { 11, 6, 7 }, + { 11, 10, 6 } +}; + +void FGAPIENTRY glutWireIcosahedron( void ) +{ + int i ; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireIcosahedron" ); + + for ( i = 0; i < 20; i++ ) + { + double normal[3] ; + normal[0] = ( icos_r[icos_v[i][1]][1] - icos_r[icos_v[i][0]][1] ) * ( icos_r[icos_v[i][2]][2] - icos_r[icos_v[i][0]][2] ) - ( icos_r[icos_v[i][1]][2] - icos_r[icos_v[i][0]][2] ) * ( icos_r[icos_v[i][2]][1] - icos_r[icos_v[i][0]][1] ) ; + normal[1] = ( icos_r[icos_v[i][1]][2] - icos_r[icos_v[i][0]][2] ) * ( icos_r[icos_v[i][2]][0] - icos_r[icos_v[i][0]][0] ) - ( icos_r[icos_v[i][1]][0] - icos_r[icos_v[i][0]][0] ) * ( icos_r[icos_v[i][2]][2] - icos_r[icos_v[i][0]][2] ) ; + normal[2] = ( icos_r[icos_v[i][1]][0] - icos_r[icos_v[i][0]][0] ) * ( icos_r[icos_v[i][2]][1] - icos_r[icos_v[i][0]][1] ) - ( icos_r[icos_v[i][1]][1] - icos_r[icos_v[i][0]][1] ) * ( icos_r[icos_v[i][2]][0] - icos_r[icos_v[i][0]][0] ) ; + glBegin ( GL_LINE_LOOP ) ; + glNormal3dv ( normal ) ; + glVertex3dv ( icos_r[icos_v[i][0]] ) ; + glVertex3dv ( icos_r[icos_v[i][1]] ) ; + glVertex3dv ( icos_r[icos_v[i][2]] ) ; + glEnd () ; + } +} + +/* + * + */ +void FGAPIENTRY glutSolidIcosahedron( void ) +{ + int i ; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidIcosahedron" ); + + glBegin ( GL_TRIANGLES ) ; + for ( i = 0; i < 20; i++ ) + { + double normal[3] ; + normal[0] = ( icos_r[icos_v[i][1]][1] - icos_r[icos_v[i][0]][1] ) * ( icos_r[icos_v[i][2]][2] - icos_r[icos_v[i][0]][2] ) - ( icos_r[icos_v[i][1]][2] - icos_r[icos_v[i][0]][2] ) * ( icos_r[icos_v[i][2]][1] - icos_r[icos_v[i][0]][1] ) ; + normal[1] = ( icos_r[icos_v[i][1]][2] - icos_r[icos_v[i][0]][2] ) * ( icos_r[icos_v[i][2]][0] - icos_r[icos_v[i][0]][0] ) - ( icos_r[icos_v[i][1]][0] - icos_r[icos_v[i][0]][0] ) * ( icos_r[icos_v[i][2]][2] - icos_r[icos_v[i][0]][2] ) ; + normal[2] = ( icos_r[icos_v[i][1]][0] - icos_r[icos_v[i][0]][0] ) * ( icos_r[icos_v[i][2]][1] - icos_r[icos_v[i][0]][1] ) - ( icos_r[icos_v[i][1]][1] - icos_r[icos_v[i][0]][1] ) * ( icos_r[icos_v[i][2]][0] - icos_r[icos_v[i][0]][0] ) ; + glNormal3dv ( normal ) ; + glVertex3dv ( icos_r[icos_v[i][0]] ) ; + glVertex3dv ( icos_r[icos_v[i][1]] ) ; + glVertex3dv ( icos_r[icos_v[i][2]] ) ; + } + + glEnd () ; +} + +/* + * + */ +static double rdod_r[14][3] = { + { 0.0, 0.0, 1.0 }, + { 0.707106781187, 0.000000000000, 0.5 }, + { 0.000000000000, 0.707106781187, 0.5 }, + { -0.707106781187, 0.000000000000, 0.5 }, + { 0.000000000000, -0.707106781187, 0.5 }, + { 0.707106781187, 0.707106781187, 0.0 }, + { -0.707106781187, 0.707106781187, 0.0 }, + { -0.707106781187, -0.707106781187, 0.0 }, + { 0.707106781187, -0.707106781187, 0.0 }, + { 0.707106781187, 0.000000000000, -0.5 }, + { 0.000000000000, 0.707106781187, -0.5 }, + { -0.707106781187, 0.000000000000, -0.5 }, + { 0.000000000000, -0.707106781187, -0.5 }, + { 0.0, 0.0, -1.0 } +} ; + +static int rdod_v [12][4] = { + { 0, 1, 5, 2 }, + { 0, 2, 6, 3 }, + { 0, 3, 7, 4 }, + { 0, 4, 8, 1 }, + { 5, 10, 6, 2 }, + { 6, 11, 7, 3 }, + { 7, 12, 8, 4 }, + { 8, 9, 5, 1 }, + { 5, 9, 13, 10 }, + { 6, 10, 13, 11 }, + { 7, 11, 13, 12 }, + { 8, 12, 13, 9 } +}; + +static double rdod_n[12][3] = { + { 0.353553390594, 0.353553390594, 0.5 }, + { -0.353553390594, 0.353553390594, 0.5 }, + { -0.353553390594, -0.353553390594, 0.5 }, + { 0.353553390594, -0.353553390594, 0.5 }, + { 0.000000000000, 1.000000000000, 0.0 }, + { -1.000000000000, 0.000000000000, 0.0 }, + { 0.000000000000, -1.000000000000, 0.0 }, + { 1.000000000000, 0.000000000000, 0.0 }, + { 0.353553390594, 0.353553390594, -0.5 }, + { -0.353553390594, 0.353553390594, -0.5 }, + { -0.353553390594, -0.353553390594, -0.5 }, + { 0.353553390594, -0.353553390594, -0.5 } +}; + +void FGAPIENTRY glutWireRhombicDodecahedron( void ) +{ + int i ; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireRhombicDodecahedron" ); + + for ( i = 0; i < 12; i++ ) + { + glBegin ( GL_LINE_LOOP ) ; + glNormal3dv ( rdod_n[i] ) ; + glVertex3dv ( rdod_r[rdod_v[i][0]] ) ; + glVertex3dv ( rdod_r[rdod_v[i][1]] ) ; + glVertex3dv ( rdod_r[rdod_v[i][2]] ) ; + glVertex3dv ( rdod_r[rdod_v[i][3]] ) ; + glEnd () ; + } +} + +/* + * + */ +void FGAPIENTRY glutSolidRhombicDodecahedron( void ) +{ + int i ; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidRhombicDodecahedron" ); + + glBegin ( GL_QUADS ) ; + for ( i = 0; i < 12; i++ ) + { + glNormal3dv ( rdod_n[i] ) ; + glVertex3dv ( rdod_r[rdod_v[i][0]] ) ; + glVertex3dv ( rdod_r[rdod_v[i][1]] ) ; + glVertex3dv ( rdod_r[rdod_v[i][2]] ) ; + glVertex3dv ( rdod_r[rdod_v[i][3]] ) ; + } + + glEnd () ; +} + +void FGAPIENTRY glutWireSierpinskiSponge ( int num_levels, GLdouble offset[3], GLdouble scale ) +{ + int i, j ; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireSierpinskiSponge" ); + + if ( num_levels == 0 ) + { + + for ( i = 0 ; i < NUM_TETR_FACES ; i++ ) + { + glBegin ( GL_LINE_LOOP ) ; + glNormal3d ( -tet_r[i][0], -tet_r[i][1], -tet_r[i][2] ) ; + for ( j = 0; j < 3; j++ ) + { + double x = offset[0] + scale * tet_r[tet_i[i][j]][0] ; + double y = offset[1] + scale * tet_r[tet_i[i][j]][1] ; + double z = offset[2] + scale * tet_r[tet_i[i][j]][2] ; + glVertex3d ( x, y, z ) ; + } + + glEnd () ; + } + } + else if ( num_levels > 0 ) + { + GLdouble local_offset[3] ; /* Use a local variable to avoid buildup of roundoff errors */ + num_levels -- ; + scale /= 2.0 ; + for ( i = 0 ; i < NUM_TETR_FACES ; i++ ) + { + local_offset[0] = offset[0] + scale * tet_r[i][0] ; + local_offset[1] = offset[1] + scale * tet_r[i][1] ; + local_offset[2] = offset[2] + scale * tet_r[i][2] ; + glutWireSierpinskiSponge ( num_levels, local_offset, scale ) ; + } + } +} + +void FGAPIENTRY glutSolidSierpinskiSponge ( int num_levels, GLdouble offset[3], GLdouble scale ) +{ + int i, j ; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidSierpinskiSponge" ); + + if ( num_levels == 0 ) + { + glBegin ( GL_TRIANGLES ) ; + + for ( i = 0 ; i < NUM_TETR_FACES ; i++ ) + { + glNormal3d ( -tet_r[i][0], -tet_r[i][1], -tet_r[i][2] ) ; + for ( j = 0; j < 3; j++ ) + { + double x = offset[0] + scale * tet_r[tet_i[i][j]][0] ; + double y = offset[1] + scale * tet_r[tet_i[i][j]][1] ; + double z = offset[2] + scale * tet_r[tet_i[i][j]][2] ; + glVertex3d ( x, y, z ) ; + } + } + + glEnd () ; + } + else if ( num_levels > 0 ) + { + GLdouble local_offset[3] ; /* Use a local variable to avoid buildup of roundoff errors */ + num_levels -- ; + scale /= 2.0 ; + for ( i = 0 ; i < NUM_TETR_FACES ; i++ ) + { + local_offset[0] = offset[0] + scale * tet_r[i][0] ; + local_offset[1] = offset[1] + scale * tet_r[i][1] ; + local_offset[2] = offset[2] + scale * tet_r[i][2] ; + glutSolidSierpinskiSponge ( num_levels, local_offset, scale ) ; + } + } +} + +/*** END OF FILE ***/ diff --git a/tests/box2d/freeglut/freeglut_glutfont_definitions.c b/tests/box2d/freeglut/freeglut_glutfont_definitions.c new file mode 100755 index 00000000..0a24cce7 --- /dev/null +++ b/tests/box2d/freeglut/freeglut_glutfont_definitions.c @@ -0,0 +1,108 @@ +/* + * freeglut_glutfont_definitions.c + * + * Bitmap and stroke fonts displaying. + * + * Copyright (c) 2003 Stephen J. Baker (whether he wants it or not). + * All Rights Reserved. + * Written by John F. Fay <fayjf@sourceforge.net>, who releases the + * copyright over to the "freeglut" project lead. + * Creation date: Mon July 21 2003 + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * This file is necessary for the *nix version of "freeglut" because the + * original GLUT defined its font variables in rather an unusual way. + * Publicly, in "glut.h", they were defined as "void *". Privately, + * in one of the source code files, they were defined as pointers to a + * structure. Most compilers and linkers are satisfied with the "void *" + * and don't go any farther, but some of them balked. In particular, + * when compiling with "freeglut" and then trying to run using the GLUT + * ".so" library, some of them would give an error. So we are having to + * create this file to define the variables as pointers to an unusual + * structure to match GLUT. + */ + +/* + * freeglut_internal.h uses some GL types, but including the GL header portably + * is a bit tricky, so we include freeglut_std.h here, which contains the + * necessary machinery. But this poses another problem, caused by the ugly + * original defintion of the font constants in "classic" GLUT: They are defined + * as void* externally, so we move them temporarily out of the way by AN EXTREME + * CPP HACK. + */ + +#define glutStrokeRoman glutStrokeRomanIGNOREME +#define glutStrokeMonoRoman glutStrokeMonoRomanIGNOREME +#define glutBitmap9By15 glutBitmap9By15IGNOREME +#define glutBitmap8By13 glutBitmap8By13IGNOREME +#define glutBitmapTimesRoman10 glutBitmapTimesRoman10IGNOREME +#define glutBitmapTimesRoman24 glutBitmapTimesRoman24IGNOREME +#define glutBitmapHelvetica10 glutBitmapHelvetica10IGNOREME +#define glutBitmapHelvetica12 glutBitmapHelvetica12IGNOREME +#define glutBitmapHelvetica18 glutBitmapHelvetica18IGNOREME + +#include "freeglut_std.h" + +#undef glutStrokeRoman +#undef glutStrokeMonoRoman +#undef glutBitmap9By15 +#undef glutBitmap8By13 +#undef glutBitmapTimesRoman10 +#undef glutBitmapTimesRoman24 +#undef glutBitmapHelvetica10 +#undef glutBitmapHelvetica12 +#undef glutBitmapHelvetica18 + +#include "freeglut_internal.h" + +#if TARGET_HOST_POSIX_X11 + +struct freeglutStrokeFont +{ + const char *name ; + int num_chars ; + void *ch ; + float top ; + float bottom ; +}; + +struct freeglutBitmapFont +{ + const char *name ; + const int num_chars ; + const int first ; + const void *ch ; +}; + + +struct freeglutStrokeFont glutStrokeRoman ; +struct freeglutStrokeFont glutStrokeMonoRoman ; + +struct freeglutBitmapFont glutBitmap9By15 ; +struct freeglutBitmapFont glutBitmap8By13 ; +struct freeglutBitmapFont glutBitmapTimesRoman10 ; +struct freeglutBitmapFont glutBitmapTimesRoman24 ; +struct freeglutBitmapFont glutBitmapHelvetica10 ; +struct freeglutBitmapFont glutBitmapHelvetica12 ; +struct freeglutBitmapFont glutBitmapHelvetica18 ; + +#endif + diff --git a/tests/box2d/freeglut/freeglut_init.c b/tests/box2d/freeglut/freeglut_init.c new file mode 100755 index 00000000..73310eaa --- /dev/null +++ b/tests/box2d/freeglut/freeglut_init.c @@ -0,0 +1,1166 @@ +/* + * freeglut_init.c + * + * Various freeglut initialization functions. + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, <olszta@sourceforge.net> + * Creation date: Thu Dec 2 1999 + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#define FREEGLUT_BUILDING_LIB +#include "freeglut.h" +#include "freeglut_internal.h" + +#if TARGET_HOST_POSIX_X11 +#include <limits.h> /* LONG_MAX */ +#endif + +/* + * TODO BEFORE THE STABLE RELEASE: + * + * fgDeinitialize() -- Win32's OK, X11 needs the OS-specific + * deinitialization done + * glutInitDisplayString() -- display mode string parsing + * + * Wouldn't it be cool to use gettext() for error messages? I just love + * bash saying "nie znaleziono pliku" instead of "file not found" :) + * Is gettext easily portable? + */ + +/* -- GLOBAL VARIABLES ----------------------------------------------------- */ + +/* + * A structure pointed by g_pDisplay holds all information + * regarding the display, screen, root window etc. + */ +SFG_Display fgDisplay; + +/* + * The settings for the current freeglut session + */ +SFG_State fgState = { { -1, -1, GL_FALSE }, /* Position */ + { 300, 300, GL_TRUE }, /* Size */ + GLUT_RGBA | GLUT_SINGLE | GLUT_DEPTH, /* DisplayMode */ + GL_FALSE, /* Initialised */ + GLUT_TRY_DIRECT_CONTEXT, /* DirectContext */ + GL_FALSE, /* ForceIconic */ + GL_FALSE, /* UseCurrentContext */ + GL_FALSE, /* GLDebugSwitch */ + GL_FALSE, /* XSyncSwitch */ + GLUT_KEY_REPEAT_ON, /* KeyRepeat */ + INVALID_MODIFIERS, /* Modifiers */ + 0, /* FPSInterval */ + 0, /* SwapCount */ + 0, /* SwapTime */ + 0, /* Time */ + { NULL, NULL }, /* Timers */ + { NULL, NULL }, /* FreeTimers */ + NULL, /* IdleCallback */ + 0, /* ActiveMenus */ + NULL, /* MenuStateCallback */ + NULL, /* MenuStatusCallback */ + { 640, 480, GL_TRUE }, /* GameModeSize */ + 16, /* GameModeDepth */ + 72, /* GameModeRefresh */ + GLUT_ACTION_EXIT, /* ActionOnWindowClose */ + GLUT_EXEC_STATE_INIT, /* ExecState */ + NULL, /* ProgramName */ + GL_FALSE, /* JoysticksInitialised */ + GL_FALSE, /* InputDevsInitialised */ + 1, /* AuxiliaryBufferNumber */ + 4, /* SampleNumber */ + 1, /* MajorVersion */ + 0, /* MajorVersion */ + 0, /* ContextFlags */ + 0 /* ContextProfile */ +}; + + +/* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ + +#if TARGET_HOST_POSIX_X11 + +/* Return the atom associated with "name". */ +static Atom fghGetAtom(const char * name) +{ + return XInternAtom(fgDisplay.Display, name, False); +} + +/* + * Check if "property" is set on "window". The property's values are returned + * through "data". If the property is set and is of type "type", return the + * number of elements in "data". Return zero otherwise. In both cases, use + * "Xfree()" to free "data". + */ +static int fghGetWindowProperty(Window window, + Atom property, + Atom type, + unsigned char ** data) +{ + /* + * Caller always has to use "Xfree()" to free "data", since + * "XGetWindowProperty() always allocates one extra byte in prop_return + * [i.e. "data"] (even if the property is zero length) [..]". + */ + + int status; /* Returned by "XGetWindowProperty". */ + + Atom type_returned; + int temp_format; /* Not used. */ + unsigned long number_of_elements; + unsigned long temp_bytes_after; /* Not used. */ + + + status = XGetWindowProperty(fgDisplay.Display, + window, + property, + 0, + LONG_MAX, + False, + type, + &type_returned, + &temp_format, + &number_of_elements, + &temp_bytes_after, + data); + + FREEGLUT_INTERNAL_ERROR_EXIT(status == Success, + "XGetWindowProperty failled", + "fghGetWindowProperty"); + + if (type_returned != type) + { + number_of_elements = 0; + } + + return number_of_elements; +} + +/* Check if the window manager is NET WM compliant. */ +static int fghNetWMSupported(void) +{ + Atom wm_check; + Window ** window_ptr_1; + + int number_of_windows; + int net_wm_supported; + + + net_wm_supported = 0; + + wm_check = fghGetAtom("_NET_SUPPORTING_WM_CHECK"); + window_ptr_1 = malloc(sizeof(Window *)); + + /* + * Check that the window manager has set this property on the root window. + * The property must be the ID of a child window. + */ + number_of_windows = fghGetWindowProperty(fgDisplay.RootWindow, + wm_check, + XA_WINDOW, + (unsigned char **) window_ptr_1); + if (number_of_windows == 1) + { + Window ** window_ptr_2; + + window_ptr_2 = malloc(sizeof(Window *)); + + /* Check that the window has the same property set to the same value. */ + number_of_windows = fghGetWindowProperty(**window_ptr_1, + wm_check, + XA_WINDOW, + (unsigned char **) window_ptr_2); + if ((number_of_windows == 1) && (**window_ptr_1 == **window_ptr_2)) + { + /* NET WM compliant */ + net_wm_supported = 1; + } + + XFree(*window_ptr_2); + free(window_ptr_2); + } + + XFree(*window_ptr_1); + free(window_ptr_1); + + return net_wm_supported; +} + +/* Check if "hint" is present in "property" for "window". */ +int fgHintPresent(Window window, Atom property, Atom hint) +{ + Atom ** atoms_ptr; + int number_of_atoms; + int supported; + int i; + + supported = 0; + + atoms_ptr = malloc(sizeof(Atom *)); + number_of_atoms = fghGetWindowProperty(window, + property, + XA_ATOM, + (unsigned char **) atoms_ptr); + for (i = 0; i < number_of_atoms; i++) + { + if ((*atoms_ptr)[i] == hint) + { + supported = 1; + break; + } + } + + return supported; +} + +#endif /* TARGET_HOST_POSIX_X11 */ + + +/* + * A call to this function should initialize all the display stuff... + */ +static void fghInitialize( const char* displayName ) +{ +#if TARGET_HOST_POSIX_X11 + fgDisplay.Display = XOpenDisplay( displayName ); + + if( fgDisplay.Display == NULL ) + fgError( "failed to open display '%s'", XDisplayName( displayName ) ); + + if( !glXQueryExtension( fgDisplay.Display, NULL, NULL ) ) + fgError( "OpenGL GLX extension not supported by display '%s'", + XDisplayName( displayName ) ); + + fgDisplay.Screen = DefaultScreen( fgDisplay.Display ); + fgDisplay.RootWindow = RootWindow( + fgDisplay.Display, + fgDisplay.Screen + ); + + fgDisplay.ScreenWidth = DisplayWidth( + fgDisplay.Display, + fgDisplay.Screen + ); + fgDisplay.ScreenHeight = DisplayHeight( + fgDisplay.Display, + fgDisplay.Screen + ); + + fgDisplay.ScreenWidthMM = DisplayWidthMM( + fgDisplay.Display, + fgDisplay.Screen + ); + fgDisplay.ScreenHeightMM = DisplayHeightMM( + fgDisplay.Display, + fgDisplay.Screen + ); + + fgDisplay.Connection = ConnectionNumber( fgDisplay.Display ); + + /* Create the window deletion atom */ + fgDisplay.DeleteWindow = fghGetAtom("WM_DELETE_WINDOW"); + + /* Create the state and full screen atoms */ + fgDisplay.State = None; + fgDisplay.StateFullScreen = None; + + if (fghNetWMSupported()) + { + const Atom supported = fghGetAtom("_NET_SUPPORTED"); + const Atom state = fghGetAtom("_NET_WM_STATE"); + + /* Check if the state hint is supported. */ + if (fgHintPresent(fgDisplay.RootWindow, supported, state)) + { + const Atom full_screen = fghGetAtom("_NET_WM_STATE_FULLSCREEN"); + + fgDisplay.State = state; + + /* Check if the window manager supports full screen. */ + /** Check "_NET_WM_ALLOWED_ACTIONS" on our window instead? **/ + if (fgHintPresent(fgDisplay.RootWindow, supported, full_screen)) + { + fgDisplay.StateFullScreen = full_screen; + } + } + } + +#elif TARGET_HOST_MS_WINDOWS + + WNDCLASS wc; + ATOM atom; + + /* What we need to do is to initialize the fgDisplay global structure here. */ + fgDisplay.Instance = GetModuleHandle( NULL ); + + atom = GetClassInfo( fgDisplay.Instance, _T("FREEGLUT"), &wc ); + + if( atom == 0 ) + { + ZeroMemory( &wc, sizeof(WNDCLASS) ); + + /* + * Each of the windows should have its own device context, and we + * want redraw events during Vertical and Horizontal Resizes by + * the user. + * + * XXX Old code had "| CS_DBCLCKS" commented out. Plans for the + * XXX future? Dead-end idea? + */ + wc.lpfnWndProc = fgWindowProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = fgDisplay.Instance; + wc.hIcon = LoadIcon( fgDisplay.Instance, _T("GLUT_ICON") ); + +#if defined(_WIN32_WCE) + wc.style = CS_HREDRAW | CS_VREDRAW; +#else + wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; + if (!wc.hIcon) + wc.hIcon = LoadIcon( NULL, IDI_WINLOGO ); +#endif + + wc.hCursor = LoadCursor( NULL, IDC_ARROW ); + wc.hbrBackground = NULL; + wc.lpszMenuName = NULL; + wc.lpszClassName = _T("FREEGLUT"); + + /* Register the window class */ + atom = RegisterClass( &wc ); + FREEGLUT_INTERNAL_ERROR_EXIT ( atom, "Window Class Not Registered", "fghInitialize" ); + } + + /* The screen dimensions can be obtained via GetSystemMetrics() calls */ + fgDisplay.ScreenWidth = GetSystemMetrics( SM_CXSCREEN ); + fgDisplay.ScreenHeight = GetSystemMetrics( SM_CYSCREEN ); + + { + HWND desktop = GetDesktopWindow( ); + HDC context = GetDC( desktop ); + + fgDisplay.ScreenWidthMM = GetDeviceCaps( context, HORZSIZE ); + fgDisplay.ScreenHeightMM = GetDeviceCaps( context, VERTSIZE ); + + ReleaseDC( desktop, context ); + } + + /* Set the timer granularity to 1 ms */ + timeBeginPeriod ( 1 ); + +#endif + + fgState.Initialised = GL_TRUE; + + /* InputDevice uses GlutTimerFunc(), so fgState.Initialised must be TRUE */ + fgInitialiseInputDevices(); +} + +/* + * Perform the freeglut deinitialization... + */ +void fgDeinitialize( void ) +{ + SFG_Timer *timer; + + if( !fgState.Initialised ) + { + fgWarning( "fgDeinitialize(): " + "no valid initialization has been performed" ); + return; + } + + /* If there was a menu created, destroy the rendering context */ + if( fgStructure.MenuContext ) + { +#if TARGET_HOST_POSIX_X11 + /* Note that the MVisualInfo is not owned by the MenuContext! */ + glXDestroyContext( fgDisplay.Display, fgStructure.MenuContext->MContext ); +#endif + free( fgStructure.MenuContext ); + fgStructure.MenuContext = NULL; + } + + fgDestroyStructure( ); + + while( ( timer = fgState.Timers.First) ) + { + fgListRemove( &fgState.Timers, &timer->Node ); + free( timer ); + } + + while( ( timer = fgState.FreeTimers.First) ) + { + fgListRemove( &fgState.FreeTimers, &timer->Node ); + free( timer ); + } + +#if !defined(_WIN32_WCE) + if ( fgState.JoysticksInitialised ) + fgJoystickClose( ); + + if ( fgState.InputDevsInitialised ) + fgInputDeviceClose( ); +#endif /* !defined(_WIN32_WCE) */ + fgState.JoysticksInitialised = GL_FALSE; + fgState.InputDevsInitialised = GL_FALSE; + + fgState.MajorVersion = 1; + fgState.MinorVersion = 0; + fgState.ContextFlags = 0; + fgState.ContextProfile = 0; + + fgState.Initialised = GL_FALSE; + + fgState.Position.X = -1; + fgState.Position.Y = -1; + fgState.Position.Use = GL_FALSE; + + fgState.Size.X = 300; + fgState.Size.Y = 300; + fgState.Size.Use = GL_TRUE; + + fgState.DisplayMode = GLUT_RGBA | GLUT_SINGLE | GLUT_DEPTH; + + fgState.DirectContext = GLUT_TRY_DIRECT_CONTEXT; + fgState.ForceIconic = GL_FALSE; + fgState.UseCurrentContext = GL_FALSE; + fgState.GLDebugSwitch = GL_FALSE; + fgState.XSyncSwitch = GL_FALSE; + fgState.ActionOnWindowClose = GLUT_ACTION_EXIT; + fgState.ExecState = GLUT_EXEC_STATE_INIT; + + fgState.KeyRepeat = GLUT_KEY_REPEAT_ON; + fgState.Modifiers = INVALID_MODIFIERS; + + fgState.GameModeSize.X = 640; + fgState.GameModeSize.Y = 480; + fgState.GameModeDepth = 16; + fgState.GameModeRefresh = 72; + + fgListInit( &fgState.Timers ); + fgListInit( &fgState.FreeTimers ); + + fgState.IdleCallback = NULL; + fgState.MenuStateCallback = ( FGCBMenuState )NULL; + fgState.MenuStatusCallback = ( FGCBMenuStatus )NULL; + + fgState.SwapCount = 0; + fgState.SwapTime = 0; + fgState.FPSInterval = 0; + + if( fgState.ProgramName ) + { + free( fgState.ProgramName ); + fgState.ProgramName = NULL; + } + +#if TARGET_HOST_POSIX_X11 + + /* + * Make sure all X-client data we have created will be destroyed on + * display closing + */ + XSetCloseDownMode( fgDisplay.Display, DestroyAll ); + + /* + * Close the display connection, destroying all windows we have + * created so far + */ + XCloseDisplay( fgDisplay.Display ); + +#elif TARGET_HOST_MS_WINDOWS + + /* Reset the timer granularity */ + timeEndPeriod ( 1 ); + +#endif + + fgState.Initialised = GL_FALSE; +} + +/* + * Everything inside the following #ifndef is copied from the X sources. + */ + +#if TARGET_HOST_MS_WINDOWS + +/* + +Copyright 1985, 1986, 1987,1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +#define NoValue 0x0000 +#define XValue 0x0001 +#define YValue 0x0002 +#define WidthValue 0x0004 +#define HeightValue 0x0008 +#define AllValues 0x000F +#define XNegative 0x0010 +#define YNegative 0x0020 + +/* + * XParseGeometry parses strings of the form + * "=<width>x<height>{+-}<xoffset>{+-}<yoffset>", where + * width, height, xoffset, and yoffset are unsigned integers. + * Example: "=80x24+300-49" + * The equal sign is optional. + * It returns a bitmask that indicates which of the four values + * were actually found in the string. For each value found, + * the corresponding argument is updated; for each value + * not found, the corresponding argument is left unchanged. + */ + +static int +ReadInteger(char *string, char **NextString) +{ + register int Result = 0; + int Sign = 1; + + if (*string == '+') + string++; + else if (*string == '-') + { + string++; + Sign = -1; + } + for (; (*string >= '0') && (*string <= '9'); string++) + { + Result = (Result * 10) + (*string - '0'); + } + *NextString = string; + if (Sign >= 0) + return Result; + else + return -Result; +} + +static int XParseGeometry ( + const char *string, + int *x, + int *y, + unsigned int *width, /* RETURN */ + unsigned int *height) /* RETURN */ +{ + int mask = NoValue; + register char *strind; + unsigned int tempWidth = 0, tempHeight = 0; + int tempX = 0, tempY = 0; + char *nextCharacter; + + if ( (string == NULL) || (*string == '\0')) + return mask; + if (*string == '=') + string++; /* ignore possible '=' at beg of geometry spec */ + + strind = (char *)string; + if (*strind != '+' && *strind != '-' && *strind != 'x') { + tempWidth = ReadInteger(strind, &nextCharacter); + if (strind == nextCharacter) + return 0; + strind = nextCharacter; + mask |= WidthValue; + } + + if (*strind == 'x' || *strind == 'X') { + strind++; + tempHeight = ReadInteger(strind, &nextCharacter); + if (strind == nextCharacter) + return 0; + strind = nextCharacter; + mask |= HeightValue; + } + + if ((*strind == '+') || (*strind == '-')) { + if (*strind == '-') { + strind++; + tempX = -ReadInteger(strind, &nextCharacter); + if (strind == nextCharacter) + return 0; + strind = nextCharacter; + mask |= XNegative; + } + else + { + strind++; + tempX = ReadInteger(strind, &nextCharacter); + if (strind == nextCharacter) + return 0; + strind = nextCharacter; + } + mask |= XValue; + if ((*strind == '+') || (*strind == '-')) { + if (*strind == '-') { + strind++; + tempY = -ReadInteger(strind, &nextCharacter); + if (strind == nextCharacter) + return 0; + strind = nextCharacter; + mask |= YNegative; + } + else + { + strind++; + tempY = ReadInteger(strind, &nextCharacter); + if (strind == nextCharacter) + return 0; + strind = nextCharacter; + } + mask |= YValue; + } + } + + /* If strind isn't at the end of the string the it's an invalid + geometry specification. */ + + if (*strind != '\0') return 0; + + if (mask & XValue) + *x = tempX; + if (mask & YValue) + *y = tempY; + if (mask & WidthValue) + *width = tempWidth; + if (mask & HeightValue) + *height = tempHeight; + return mask; +} +#endif + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +/* + * Perform initialization. This usually happens on the program startup + * and restarting after glutMainLoop termination... + */ +void FGAPIENTRY glutInit( int* pargc, char** argv ) +{ + char* displayName = NULL; + char* geometry = NULL; + int i, j, argc = *pargc; + + /* will return true for VC8 (VC2005) and higher */ +#if TARGET_HOST_MS_WINDOWS && ( _MSC_VER >= 1400 ) +#if HAVE_ERRNO + size_t sLen; + errno_t err; +#endif +#endif + + if( fgState.Initialised ) + fgError( "illegal glutInit() reinitialization attempt" ); + + if (pargc && *pargc && argv && *argv && **argv) + { + fgState.ProgramName = strdup (*argv); + + if( !fgState.ProgramName ) + fgError ("Could not allocate space for the program's name."); + } + + fgCreateStructure( ); + + /* Get start time */ + fgState.Time = fgSystemTime(); + + /* check if GLUT_FPS env var is set */ +#ifndef _WIN32_WCE + { + /* will return true for VC8 (VC2005) and higher */ +#if TARGET_HOST_MS_WINDOWS && ( _MSC_VER >= 1400 ) && HAVE_ERRNO + char* fps = NULL; + err = _dupenv_s( &fps, &sLen, "GLUT_FPS" ); + if (err) + fgError("Error getting GLUT_FPS environment variable"); +#else + const char *fps = getenv( "GLUT_FPS" ); +#endif + if( fps ) + { + int interval; + sscanf( fps, "%d", &interval ); + + if( interval <= 0 ) + fgState.FPSInterval = 5000; /* 5000 millisecond default */ + else + fgState.FPSInterval = interval; + } + /* will return true for VC8 (VC2005) and higher */ +#if TARGET_HOST_MS_WINDOWS && ( _MSC_VER >= 1400 ) && HAVE_ERRNO + free ( fps ); fps = NULL; /* dupenv_s allocates a string that we must free */ +#endif + } + + /* will return true for VC8 (VC2005) and higher */ +#if TARGET_HOST_MS_WINDOWS && ( _MSC_VER >= 1400 ) && HAVE_ERRNO + err = _dupenv_s( &displayName, &sLen, "DISPLAY" ); + if (err) + fgError("Error getting DISPLAY environment variable"); +#else + displayName = getenv( "DISPLAY" ); +#endif + + for( i = 1; i < argc; i++ ) + { + if( strcmp( argv[ i ], "-display" ) == 0 ) + { + if( ++i >= argc ) + fgError( "-display parameter must be followed by display name" ); + + displayName = argv[ i ]; + + argv[ i - 1 ] = NULL; + argv[ i ] = NULL; + ( *pargc ) -= 2; + } + else if( strcmp( argv[ i ], "-geometry" ) == 0 ) + { + if( ++i >= argc ) + fgError( "-geometry parameter must be followed by window " + "geometry settings" ); + + geometry = argv[ i ]; + + argv[ i - 1 ] = NULL; + argv[ i ] = NULL; + ( *pargc ) -= 2; + } + else if( strcmp( argv[ i ], "-direct" ) == 0) + { + if( fgState.DirectContext == GLUT_FORCE_INDIRECT_CONTEXT ) + fgError( "parameters ambiguity, -direct and -indirect " + "cannot be both specified" ); + + fgState.DirectContext = GLUT_FORCE_DIRECT_CONTEXT; + argv[ i ] = NULL; + ( *pargc )--; + } + else if( strcmp( argv[ i ], "-indirect" ) == 0 ) + { + if( fgState.DirectContext == GLUT_FORCE_DIRECT_CONTEXT ) + fgError( "parameters ambiguity, -direct and -indirect " + "cannot be both specified" ); + + fgState.DirectContext = GLUT_FORCE_INDIRECT_CONTEXT; + argv[ i ] = NULL; + (*pargc)--; + } + else if( strcmp( argv[ i ], "-iconic" ) == 0 ) + { + fgState.ForceIconic = GL_TRUE; + argv[ i ] = NULL; + ( *pargc )--; + } + else if( strcmp( argv[ i ], "-gldebug" ) == 0 ) + { + fgState.GLDebugSwitch = GL_TRUE; + argv[ i ] = NULL; + ( *pargc )--; + } + else if( strcmp( argv[ i ], "-sync" ) == 0 ) + { + fgState.XSyncSwitch = GL_TRUE; + argv[ i ] = NULL; + ( *pargc )--; + } + } + + /* Compact {argv}. */ + for( i = j = 1; i < *pargc; i++, j++ ) + { + /* Guaranteed to end because there are "*pargc" arguments left */ + while ( argv[ j ] == NULL ) + j++; + if ( i != j ) + argv[ i ] = argv[ j ]; + } + +#endif /* _WIN32_WCE */ + + /* + * Have the display created now. If there wasn't a "-display" + * in the program arguments, we will use the DISPLAY environment + * variable for opening the X display (see code above): + */ + fghInitialize( displayName ); + /* will return true for VC8 (VC2005) and higher */ +#if TARGET_HOST_MS_WINDOWS && ( _MSC_VER >= 1400 ) && HAVE_ERRNO + free ( displayName ); displayName = NULL; /* dupenv_s allocates a string that we must free */ +#endif + + /* + * Geometry parsing deffered until here because we may need the screen + * size. + */ + + if (geometry ) + { + unsigned int parsedWidth, parsedHeight; + int mask = XParseGeometry( geometry, + &fgState.Position.X, &fgState.Position.Y, + &parsedWidth, &parsedHeight ); + /* TODO: Check for overflow? */ + fgState.Size.X = parsedWidth; + fgState.Size.Y = parsedHeight; + + if( (mask & (WidthValue|HeightValue)) == (WidthValue|HeightValue) ) + fgState.Size.Use = GL_TRUE; + + if( mask & XNegative ) + fgState.Position.X += fgDisplay.ScreenWidth - fgState.Size.X; + + if( mask & YNegative ) + fgState.Position.Y += fgDisplay.ScreenHeight - fgState.Size.Y; + + if( (mask & (XValue|YValue)) == (XValue|YValue) ) + fgState.Position.Use = GL_TRUE; + } +} + +#if TARGET_HOST_MS_WINDOWS +void (__cdecl *__glutExitFunc)( int return_value ) = NULL; + +void FGAPIENTRY __glutInitWithExit( int *pargc, char **argv, void (__cdecl *exit_function)(int) ) +{ + __glutExitFunc = exit_function; + glutInit(pargc, argv); +} +#endif + +/* + * Undoes all the "glutInit" stuff + */ +void FGAPIENTRY glutExit ( void ) +{ + fgDeinitialize (); +} + +/* + * Sets the default initial window position for new windows + */ +void FGAPIENTRY glutInitWindowPosition( int x, int y ) +{ + fgState.Position.X = x; + fgState.Position.Y = y; + + if( ( x >= 0 ) && ( y >= 0 ) ) + fgState.Position.Use = GL_TRUE; + else + fgState.Position.Use = GL_FALSE; +} + +/* + * Sets the default initial window size for new windows + */ +void FGAPIENTRY glutInitWindowSize( int width, int height ) +{ + fgState.Size.X = width; + fgState.Size.Y = height; + + if( ( width > 0 ) && ( height > 0 ) ) + fgState.Size.Use = GL_TRUE; + else + fgState.Size.Use = GL_FALSE; +} + +/* + * Sets the default display mode for all new windows + */ +void FGAPIENTRY glutInitDisplayMode( unsigned int displayMode ) +{ + /* We will make use of this value when creating a new OpenGL context... */ + fgState.DisplayMode = displayMode; +} + + +/* -- INIT DISPLAY STRING PARSING ------------------------------------------ */ + +static char* Tokens[] = +{ + "alpha", "acca", "acc", "blue", "buffer", "conformant", "depth", "double", + "green", "index", "num", "red", "rgba", "rgb", "luminance", "stencil", + "single", "stereo", "samples", "slow", "win32pdf", "win32pfd", "xvisual", + "xstaticgray", "xgrayscale", "xstaticcolor", "xpseudocolor", + "xtruecolor", "xdirectcolor", + "xstaticgrey", "xgreyscale", "xstaticcolour", "xpseudocolour", + "xtruecolour", "xdirectcolour", "borderless", "aux" +}; +#define NUM_TOKENS (sizeof(Tokens) / sizeof(*Tokens)) + +void FGAPIENTRY glutInitDisplayString( const char* displayMode ) +{ + int glut_state_flag = 0 ; + /* + * Unpack a lot of options from a character string. The options are + * delimited by blanks or tabs. + */ + char *token ; + /* will return true for VC8 (VC2005) and higher */ +#if TARGET_HOST_MS_WINDOWS && ( _MSC_VER >= 1400 ) + char *next_token = NULL; +#endif + size_t len = strlen ( displayMode ); + char *buffer = (char *)malloc ( (len+1) * sizeof(char) ); + memcpy ( buffer, displayMode, len ); + buffer[len] = '\0'; + + /* will return true for VC8 (VC2005) and higher */ +#if TARGET_HOST_MS_WINDOWS && ( _MSC_VER >= 1400 ) + token = strtok_s ( buffer, " \t", &next_token ); +#else + token = strtok ( buffer, " \t" ); +#endif + while ( token ) + { + /* Process this token */ + int i ; + + /* Temporary fix: Ignore any length specifications and at least + * process the basic token + * TODO: Fix this permanently + */ + size_t cleanlength = strcspn ( token, "=<>~!" ); + + for ( i = 0; i < NUM_TOKENS; i++ ) + { + if ( strncmp ( token, Tokens[i], cleanlength ) == 0 ) break ; + } + + switch ( i ) + { + case 0 : /* "alpha": Alpha color buffer precision in bits */ + glut_state_flag |= GLUT_ALPHA ; /* Somebody fix this for me! */ + break ; + + case 1 : /* "acca": Red, green, blue, and alpha accumulation buffer + precision in bits */ + break ; + + case 2 : /* "acc": Red, green, and blue accumulation buffer precision + in bits with zero bits alpha */ + glut_state_flag |= GLUT_ACCUM ; /* Somebody fix this for me! */ + break ; + + case 3 : /* "blue": Blue color buffer precision in bits */ + break ; + + case 4 : /* "buffer": Number of bits in the color index color buffer + */ + break ; + + case 5 : /* "conformant": Boolean indicating if the frame buffer + configuration is conformant or not */ + break ; + + case 6 : /* "depth": Number of bits of precsion in the depth buffer */ + glut_state_flag |= GLUT_DEPTH ; /* Somebody fix this for me! */ + break ; + + case 7 : /* "double": Boolean indicating if the color buffer is + double buffered */ + glut_state_flag |= GLUT_DOUBLE ; + break ; + + case 8 : /* "green": Green color buffer precision in bits */ + break ; + + case 9 : /* "index": Boolean if the color model is color index or not + */ + glut_state_flag |= GLUT_INDEX ; + break ; + + case 10 : /* "num": A special capability name indicating where the + value represents the Nth frame buffer configuration + matching the description string */ + break ; + + case 11 : /* "red": Red color buffer precision in bits */ + break ; + + case 12 : /* "rgba": Number of bits of red, green, blue, and alpha in + the RGBA color buffer */ + glut_state_flag |= GLUT_RGBA ; /* Somebody fix this for me! */ + break ; + + case 13 : /* "rgb": Number of bits of red, green, and blue in the + RGBA color buffer with zero bits alpha */ + glut_state_flag |= GLUT_RGB ; /* Somebody fix this for me! */ + break ; + + case 14 : /* "luminance": Number of bits of red in the RGBA and zero + bits of green, blue (alpha not specified) of color buffer + precision */ + glut_state_flag |= GLUT_LUMINANCE ; /* Somebody fix this for me! */ + break ; + + case 15 : /* "stencil": Number of bits in the stencil buffer */ + glut_state_flag |= GLUT_STENCIL; /* Somebody fix this for me! */ + break ; + + case 16 : /* "single": Boolean indicate the color buffer is single + buffered */ + glut_state_flag |= GLUT_SINGLE ; + break ; + + case 17 : /* "stereo": Boolean indicating the color buffer supports + OpenGL-style stereo */ + glut_state_flag |= GLUT_STEREO ; + break ; + + case 18 : /* "samples": Indicates the number of multisamples to use + based on GLX's SGIS_multisample extension (for + antialiasing) */ + glut_state_flag |= GLUT_MULTISAMPLE ; /*Somebody fix this for me!*/ + break ; + + case 19 : /* "slow": Boolean indicating if the frame buffer + configuration is slow or not */ + break ; + + case 20 : /* "win32pdf": (incorrect spelling but was there before */ + case 21 : /* "win32pfd": matches the Win32 Pixel Format Descriptor by + number */ +#if TARGET_HOST_MS_WINDOWS +#endif + break ; + + case 22 : /* "xvisual": matches the X visual ID by number */ +#if TARGET_HOST_POSIX_X11 +#endif + break ; + + case 23 : /* "xstaticgray": */ + case 29 : /* "xstaticgrey": boolean indicating if the frame buffer + configuration's X visual is of type StaticGray */ +#if TARGET_HOST_POSIX_X11 +#endif + break ; + + case 24 : /* "xgrayscale": */ + case 30 : /* "xgreyscale": boolean indicating if the frame buffer + configuration's X visual is of type GrayScale */ +#if TARGET_HOST_POSIX_X11 +#endif + break ; + + case 25 : /* "xstaticcolor": */ + case 31 : /* "xstaticcolour": boolean indicating if the frame buffer + configuration's X visual is of type StaticColor */ +#if TARGET_HOST_POSIX_X11 +#endif + break ; + + case 26 : /* "xpseudocolor": */ + case 32 : /* "xpseudocolour": boolean indicating if the frame buffer + configuration's X visual is of type PseudoColor */ +#if TARGET_HOST_POSIX_X11 +#endif + break ; + + case 27 : /* "xtruecolor": */ + case 33 : /* "xtruecolour": boolean indicating if the frame buffer + configuration's X visual is of type TrueColor */ +#if TARGET_HOST_POSIX_X11 +#endif + break ; + + case 28 : /* "xdirectcolor": */ + case 34 : /* "xdirectcolour": boolean indicating if the frame buffer + configuration's X visual is of type DirectColor */ +#if TARGET_HOST_POSIX_X11 +#endif + break ; + + case 35 : /* "borderless": windows should not have borders */ +#if TARGET_HOST_POSIX_X11 +#endif + break ; + + case 36 : /* "aux": some number of aux buffers */ + glut_state_flag |= GLUT_AUX; + break ; + + case 37 : /* Unrecognized */ + fgWarning ( "WARNING - Display string token not recognized: %s", + token ); + break ; + } + + /* will return true for VC8 (VC2005) and higher */ +#if TARGET_HOST_MS_WINDOWS && ( _MSC_VER >= 1400 ) + token = strtok_s ( NULL, " \t", &next_token ); +#else + token = strtok ( NULL, " \t" ); +#endif + } + + free ( buffer ); + + /* We will make use of this value when creating a new OpenGL context... */ + fgState.DisplayMode = glut_state_flag; +} + +/* -- SETTING OPENGL 3.0 CONTEXT CREATION PARAMETERS ---------------------- */ + +void FGAPIENTRY glutInitContextVersion( int majorVersion, int minorVersion ) +{ + /* We will make use of these valuse when creating a new OpenGL context... */ + fgState.MajorVersion = majorVersion; + fgState.MinorVersion = minorVersion; +} + + +void FGAPIENTRY glutInitContextFlags( int flags ) +{ + /* We will make use of this value when creating a new OpenGL context... */ + fgState.ContextFlags = flags; +} + +void FGAPIENTRY glutInitContextProfile( int profile ) +{ + /* We will make use of this value when creating a new OpenGL context... */ + fgState.ContextProfile = profile; +} + +/*** END OF FILE ***/ diff --git a/tests/box2d/freeglut/freeglut_input_devices.c b/tests/box2d/freeglut/freeglut_input_devices.c new file mode 100755 index 00000000..b500e830 --- /dev/null +++ b/tests/box2d/freeglut/freeglut_input_devices.c @@ -0,0 +1,395 @@ +/* + * freeglut_input_devices.c + * + * Handles miscellaneous input devices via direct serial-port access. + * Proper X11 XInput device support is not yet supported. + * Also lacks Mac support. + * + * Written by Joe Krahn <krahn@niehs.nih.gov> 2005 + * + * Copyright (c) 2005 Stephen J. Baker. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA OR STEPHEN J. BAKER BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "freeglut.h" +#include "freeglut_internal.h" + +#if TARGET_HOST_POSIX_X11 +#if HAVE_ERRNO +#include <errno.h> +#endif +#include <sys/ioctl.h> +#include <sys/time.h> +#include <time.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <termios.h> +#include <fcntl.h> +#include <sys/types.h> + +typedef struct { + int fd; + struct termios termio, termio_save; +} SERIALPORT; + +#elif TARGET_HOST_MS_WINDOWS +#include <sys/types.h> +#include <winbase.h> +typedef struct { + HANDLE fh; + COMMTIMEOUTS timeouts_save; + DCB dcb_save; +} SERIALPORT; + +#endif + +/********************* Dialbox definitions ***********************/ + +#define DIAL_NUM_VALUATORS 8 + +/* dial parser state machine states */ +#define DIAL_NEW (-1) +#define DIAL_WHICH_DEVICE 0 +#define DIAL_VALUE_HIGH 1 +#define DIAL_VALUE_LOW 2 + +/* dial/button box commands */ +#define DIAL_INITIALIZE 0x20 +#define DIAL_SET_LEDS 0x75 +#define DIAL_SET_TEXT 0x61 +#define DIAL_SET_AUTO_DIALS 0x50 +#define DIAL_SET_AUTO_DELTA_DIALS 0x51 +#define DIAL_SET_FILTER 0x53 +#define DIAL_SET_BUTTONS_MOM_TYPE 0x71 +#define DIAL_SET_AUTO_MOM_BUTTONS 0x73 +#define DIAL_SET_ALL_LEDS 0x4b +#define DIAL_CLEAR_ALL_LEDS 0x4c + +/* dial/button box replies and events */ +#define DIAL_INITIALIZED 0x20 +#define DIAL_BASE 0x30 +#define DIAL_DELTA_BASE 0x40 +#define DIAL_PRESS_BASE 0xc0 +#define DIAL_RELEASE_BASE 0xe0 + +/* macros to determine reply type */ +#define IS_DIAL_EVENT(ch) (((ch)>=DIAL_BASE)&&((ch)<DIAL_BASE+DIAL_NUM_VALUATORS)) +#define IS_KEY_PRESS(ch) (((ch)>=DIAL_PRESS_BASE)&&((ch)<DIAL_PRESS_BASE+DIAL_NUM_BUTTONS)) +#define IS_KEY_RELEASE(ch) (((ch)>=DIAL_RELEASE_BASE)&&((ch)<DIAL_RELEASE_BASE+DIAL_NUM_BUTTONS)) +#define IS_INIT_EVENT(ch) ((ch)==DIAL_INITIALIZED) + +/*****************************************************************/ + +static SERIALPORT *serial_open ( const char *device ); +static void serial_close ( SERIALPORT *port ); +static int serial_getchar ( SERIALPORT *port ); +static int serial_putchar ( SERIALPORT *port, unsigned char ch ); +static void serial_flush ( SERIALPORT *port ); + +static void send_dial_event(int dial, int value); +static void poll_dials(int id); + +/* local variables */ +static SERIALPORT *dialbox_port=NULL; + +/*****************************************************************/ + +/* + * Implementation for glutDeviceGet(GLUT_HAS_DIAL_AND_BUTTON_BOX) + */ +int fgInputDeviceDetect( void ) +{ + fgInitialiseInputDevices (); + + if ( !dialbox_port ) + return 0; + + if ( !fgState.InputDevsInitialised ) + return 0; + + return 1; +} + +/* + * Try initializing the input device(s) + */ +void fgInitialiseInputDevices ( void ) +{ + if( !fgState.InputDevsInitialised ) + { + /* will return true for VC8 (VC2005) and higher */ +#if TARGET_HOST_MS_WINDOWS && ( _MSC_VER >= 1400 ) && HAVE_ERRNO + char *dial_device=NULL; + size_t sLen; + errno_t err = _dupenv_s( &dial_device, &sLen, "GLUT_DIALS_SERIAL" ); + if (err) + fgError("Error getting GLUT_DIALS_SERIAL environment variable"); +#else + const char *dial_device=NULL; + dial_device = getenv ( "GLUT_DIALS_SERIAL" ); +#endif +#if TARGET_HOST_MS_WINDOWS + if (!dial_device){ + static char devname[256]; + DWORD size=sizeof(devname); + DWORD type = REG_SZ; + HKEY key; + if (RegOpenKeyA(HKEY_LOCAL_MACHINE,"SOFTWARE\\FreeGLUT",&key)==ERROR_SUCCESS) { + if (RegQueryValueExA(key,"DialboxSerialPort",NULL,&type,(LPBYTE)devname,&size)==ERROR_SUCCESS){ + dial_device=devname; + } + RegCloseKey(key); + } + } +#endif + if ( !dial_device ) return; + if ( !( dialbox_port = serial_open ( dial_device ) ) ) return; + /* will return true for VC8 (VC2005) and higher */ +#if TARGET_HOST_MS_WINDOWS && ( _MSC_VER >= 1400 ) && HAVE_ERRNO + free ( dial_device ); dial_device = NULL; /* dupenv_s allocates a string that we must free */ +#endif + serial_putchar(dialbox_port,DIAL_INITIALIZE); + glutTimerFunc ( 10, poll_dials, 0 ); + fgState.InputDevsInitialised = GL_TRUE; + } +} + +/* + * + */ +void fgInputDeviceClose( void ) +{ + if ( fgState.InputDevsInitialised ) + { + serial_close ( dialbox_port ); + dialbox_port = NULL; + fgState.InputDevsInitialised = GL_FALSE; + } +} + +/********************************************************************/ + +/* Check all windows for dialbox callbacks */ +static void fghcbEnumDialCallbacks ( SFG_Window *window, SFG_Enumerator *enumerator ) +{ + /* Built-in to INVOKE_WCB(): if window->Callbacks[CB_Dials] */ + INVOKE_WCB ( *window,Dials, ( ((int*)enumerator->data)[0], ((int*)enumerator->data)[1]) ); + fgEnumSubWindows ( window, fghcbEnumDialCallbacks, enumerator ); +} + +static void send_dial_event ( int num, int value ) +{ + SFG_Enumerator enumerator; + int data[2]; + data[0] = num; + data[1] = value; + enumerator.found = GL_FALSE; + enumerator.data = data; + fgEnumWindows ( fghcbEnumDialCallbacks, &enumerator ); +} + +/********************************************************************/ +static void poll_dials ( int id ) +{ + int data; + static int dial_state = DIAL_NEW; + static int dial_which; + static int dial_value; + static int dials[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + + if ( !dialbox_port ) return; + + while ( (data=serial_getchar(dialbox_port)) != EOF ) + { + if ( ( dial_state > DIAL_WHICH_DEVICE ) || IS_DIAL_EVENT ( data ) ) + { + switch ( dial_state ) + { + case DIAL_WHICH_DEVICE: + dial_which = data - DIAL_BASE; + dial_state++; + break; + case DIAL_VALUE_HIGH: + dial_value = ( data << 8 ); + dial_state++; + break; + case DIAL_VALUE_LOW: + dial_value |= data; + if ( dial_value & 0x8000 ) dial_value -= 0x10000; + dials[dial_which] = dial_value; + send_dial_event ( dial_which + 1, dial_value * 360 / 256 ); + dial_state = DIAL_WHICH_DEVICE; + break; + default: + /* error: Impossible state value! */ + break; + } + } + else if ( data == DIAL_INITIALIZED ) + { + fgState.InputDevsInitialised = GL_TRUE; + dial_state = DIAL_WHICH_DEVICE; + serial_putchar(dialbox_port,DIAL_SET_AUTO_DIALS); + serial_putchar(dialbox_port,0xff); + serial_putchar(dialbox_port,0xff); + } + else /* Unknown data; try flushing. */ + serial_flush(dialbox_port); + } + + glutTimerFunc ( 2, poll_dials, 0 ); +} + + +/******** OS Specific Serial I/O routines *******/ +#if TARGET_HOST_POSIX_X11 /* ==> Linux/BSD/UNIX POSIX serial I/O */ +static SERIALPORT *serial_open ( const char *device ) +{ + int fd; + struct termios termio; + SERIALPORT *port; + + fd = open(device, O_RDWR | O_NONBLOCK ); + if (fd <0) { + perror(device); + return NULL; + } + + port = malloc(sizeof(SERIALPORT)); + memset(port, 0, sizeof(SERIALPORT)); + port->fd = fd; + + /* save current port settings */ + tcgetattr(fd,&port->termio_save); + + memset(&termio, 0, sizeof(termio)); + termio.c_cflag = CS8 | CREAD | HUPCL ; + termio.c_iflag = IGNPAR | IGNBRK ; + termio.c_cc[VTIME] = 0; /* inter-character timer */ + termio.c_cc[VMIN] = 1; /* block read until 1 chars received, when blocking I/O */ + + cfsetispeed(&termio, B9600); + cfsetospeed(&termio, B9600); + tcsetattr(fd,TCSANOW,&termio); + + serial_flush(port); + return port; +} + +static void serial_close(SERIALPORT *port) +{ + if (port) + { + /* restore old port settings */ + tcsetattr(port->fd,TCSANOW,&port->termio_save); + close(port->fd); + free(port); + } +} + +static int serial_getchar(SERIALPORT *port) +{ + unsigned char ch; + if (!port) return EOF; + if (read(port->fd,&ch,1)) return ch; + return EOF; +} + +static int serial_putchar(SERIALPORT *port, unsigned char ch){ + if (!port) return 0; + return write(port->fd,&ch,1); +} + +static void serial_flush ( SERIALPORT *port ) +{ + tcflush ( port->fd, TCIOFLUSH ); +} + +#elif TARGET_HOST_MS_WINDOWS + +static SERIALPORT *serial_open(const char *device){ + HANDLE fh; + DCB dcb={sizeof(DCB)}; + COMMTIMEOUTS timeouts; + SERIALPORT *port; + + fh = CreateFile(device,GENERIC_READ|GENERIC_WRITE,0,NULL, + OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); + if (!fh) return NULL; + + port = malloc(sizeof(SERIALPORT)); + ZeroMemory(port, sizeof(SERIALPORT)); + port->fh = fh; + + /* save current port settings */ + GetCommState(fh,&port->dcb_save); + GetCommTimeouts(fh,&port->timeouts_save); + + dcb.DCBlength=sizeof(DCB); + BuildCommDCB("96,n,8,1",&dcb); + SetCommState(fh,&dcb); + + ZeroMemory(&timeouts,sizeof(timeouts)); + timeouts.ReadTotalTimeoutConstant=1; + timeouts.WriteTotalTimeoutConstant=1; + SetCommTimeouts(fh,&timeouts); + + serial_flush(port); + + return port; +} + +static void serial_close(SERIALPORT *port){ + if (port){ + /* restore old port settings */ + SetCommState(port->fh,&port->dcb_save); + SetCommTimeouts(port->fh,&port->timeouts_save); + CloseHandle(port->fh); + free(port); + } +} + +static int serial_getchar(SERIALPORT *port){ + DWORD n; + unsigned char ch; + if (!port) return EOF; + if (!ReadFile(port->fh,&ch,1,&n,NULL)) return EOF; + if (n==1) return ch; + return EOF; +} + +static int serial_putchar(SERIALPORT *port, unsigned char ch){ + DWORD n; + if (!port) return 0; + return WriteFile(port->fh,&ch,1,&n,NULL); +} + +static void serial_flush ( SERIALPORT *port ) +{ + FlushFileBuffers(port->fh); +} + +#endif diff --git a/tests/box2d/freeglut/freeglut_internal.h b/tests/box2d/freeglut/freeglut_internal.h new file mode 100755 index 00000000..2d77ab01 --- /dev/null +++ b/tests/box2d/freeglut/freeglut_internal.h @@ -0,0 +1,960 @@ +/* + * freeglut_internal.h + * + * The freeglut library private include file. + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, <olszta@sourceforge.net> + * Creation date: Thu Dec 2 1999 + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef FREEGLUT_INTERNAL_H +#define FREEGLUT_INTERNAL_H + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +/* XXX Update these for each release! */ +#define VERSION_MAJOR 2 +#define VERSION_MINOR 6 +#define VERSION_PATCH 0 + +/* Freeglut is intended to function under all Unix/X11 and Win32 platforms. */ +/* XXX: Don't all MS-Windows compilers (except Cygwin) have _WIN32 defined? + * XXX: If so, remove the first set of defined()'s below. + */ +#if defined(_MSC_VER) || defined(__WATCOMC__) || defined(__MINGW32__) \ + || defined(_WIN32) || defined(_WIN32_WCE) \ + || ( defined(__CYGWIN__) && defined(X_DISPLAY_MISSING) ) +# define TARGET_HOST_MS_WINDOWS 1 + +#elif defined(__posix__) || defined(__unix__) || defined(__linux__) +# define TARGET_HOST_POSIX_X11 1 + +#elif defined(__APPLE__) +/* This is a placeholder until we get native OSX support ironed out -- JFF 11/18/09 */ +# define TARGET_HOST_POSIX_X11 1 +/* # define TARGET_HOST_MAC_OSX 1 */ + +#else +# error "Unrecognized target host!" +*/ +#endif + +/* Detect both SunPro and gcc compilers on Sun Solaris */ +#if defined (__SVR4) && defined (__sun) +# define TARGET_HOST_SOLARIS 1 +#endif + +#ifndef TARGET_HOST_MS_WINDOWS +# define TARGET_HOST_MS_WINDOWS 0 +#endif + +#ifndef TARGET_HOST_POSIX_X11 +# define TARGET_HOST_POSIX_X11 0 +#endif + +#ifndef TARGET_HOST_MAC_OSX +# define TARGET_HOST_MAC_OSX 0 +#endif + +#ifndef TARGET_HOST_SOLARIS +# define TARGET_HOST_SOLARIS 0 +#endif + +/* -- FIXED CONFIGURATION LIMITS ------------------------------------------- */ + +#define FREEGLUT_MAX_MENUS 3 + +/* -- PLATFORM-SPECIFIC INCLUDES ------------------------------------------- */ + +/* All Win32 headers depend on the huge Windows.h recursive include. + * Note: Let's use proper case for MS-Win headers. Even though it's + * not required due to case insensitivity, it's a good habit to keep + * because the cross-platform includes are case sensitive. + */ +#if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) +# include <Windows.h> +# include <WindowsX.h> +# include <MMSystem.h> +/* CYGWIN does not have tchar.h, but has TEXT(x), defined in winnt.h. */ +# ifndef __CYGWIN__ +# include <tchar.h> +# else +# define _TEXT(x) TEXT(x) +# define _T(x) TEXT(x) +# endif + +#elif TARGET_HOST_POSIX_X11 +# include <GL/glx.h> +# include <X11/Xlib.h> +# include <X11/Xatom.h> +# include <X11/keysym.h> +# include <X11/extensions/XInput.h> +# ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H +# include <X11/extensions/xf86vmode.h> +# endif +/* If GLX is too old, we will fail during runtime when multisampling + is requested, but at least freeglut compiles. */ +# ifndef GLX_SAMPLE_BUFFERS +# define GLX_SAMPLE_BUFFERS 0x80A8 +# endif +# ifndef GLX_SAMPLES +# define GLX_SAMPLES 0x80A9 +# endif + +#endif + +/* These files should be available on every platform. */ +#include <stdio.h> +#include <string.h> +#include <math.h> +#include <stdlib.h> + +/* These are included based on autoconf directives. */ +#if HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif +#if HAVE_UNISTD_H +# include <unistd.h> +#endif +#if TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#elif HAVE_SYS_TIME_H +# include <sys/time.h> +#else +# include <time.h> +#endif + +/* -- AUTOCONF HACKS --------------------------------------------------------*/ + +/* XXX: Update autoconf to avoid these. + * XXX: Are non-POSIX platforms intended not to use autoconf? + * If so, perhaps there should be a config_guess.h for them. Alternatively, + * config guesses could be placed above, just after the config.h exclusion. + */ +#if defined(__FreeBSD__) || defined(__NetBSD__) +# define HAVE_USB_JS 1 +# if defined(__NetBSD__) || ( defined(__FreeBSD__) && __FreeBSD_version >= 500000) +# define HAVE_USBHID_H 1 +# endif +#endif + +#if TARGET_HOST_MS_WINDOWS +# define HAVE_VPRINTF 1 +#endif + +#if !defined(HAVE_VPRINTF) && !defined(HAVE_DOPRNT) +/* XXX warning directive here? */ +# define HAVE_VPRINTF 1 +#endif + +/* MinGW may lack a prototype for ChangeDisplaySettingsEx() (depending on the version?) */ +#if TARGET_HOST_MS_WINDOWS && !defined(ChangeDisplaySettingsEx) +LONG WINAPI ChangeDisplaySettingsExA(LPCSTR,LPDEVMODEA,HWND,DWORD,LPVOID); +LONG WINAPI ChangeDisplaySettingsExW(LPCWSTR,LPDEVMODEW,HWND,DWORD,LPVOID); +# ifdef UNICODE +# define ChangeDisplaySettingsEx ChangeDisplaySettingsExW +# else +# define ChangeDisplaySettingsEx ChangeDisplaySettingsExA +# endif +#endif + +#if defined(_MSC_VER) || defined(__WATCOMC__) +/* strdup() is non-standard, for all but POSIX-2001 */ +#define strdup _strdup +#endif + +/* M_PI is non-standard (defined by BSD, not ISO-C) */ +#ifndef M_PI +# define M_PI 3.14159265358979323846 +#endif + +#ifndef TRUE +# define TRUE 1 +#endif + +#ifndef FALSE +# define FALSE 0 +#endif + +/* General defines */ + +#define INVALID_MODIFIERS 0xffffffff + +/* -- GLOBAL TYPE DEFINITIONS ---------------------------------------------- */ + +/* Freeglut callbacks type definitions */ +typedef void (* FGCBDisplay )( void ); +typedef void (* FGCBReshape )( int, int ); +typedef void (* FGCBVisibility )( int ); +typedef void (* FGCBKeyboard )( unsigned char, int, int ); +typedef void (* FGCBSpecial )( int, int, int ); +typedef void (* FGCBMouse )( int, int, int, int ); +typedef void (* FGCBMouseWheel )( int, int, int, int ); +typedef void (* FGCBMotion )( int, int ); +typedef void (* FGCBPassive )( int, int ); +typedef void (* FGCBEntry )( int ); +typedef void (* FGCBWindowStatus )( int ); +typedef void (* FGCBSelect )( int, int, int ); +typedef void (* FGCBJoystick )( unsigned int, int, int, int ); +typedef void (* FGCBKeyboardUp )( unsigned char, int, int ); +typedef void (* FGCBSpecialUp )( int, int, int ); +typedef void (* FGCBOverlayDisplay)( void ); +typedef void (* FGCBSpaceMotion )( int, int, int ); +typedef void (* FGCBSpaceRotation )( int, int, int ); +typedef void (* FGCBSpaceButton )( int, int ); +typedef void (* FGCBDials )( int, int ); +typedef void (* FGCBButtonBox )( int, int ); +typedef void (* FGCBTabletMotion )( int, int ); +typedef void (* FGCBTabletButton )( int, int, int, int ); +typedef void (* FGCBDestroy )( void ); + +/* The global callbacks type definitions */ +typedef void (* FGCBIdle )( void ); +typedef void (* FGCBTimer )( int ); +typedef void (* FGCBMenuState )( int ); +typedef void (* FGCBMenuStatus )( int, int, int ); + +/* The callback used when creating/using menus */ +typedef void (* FGCBMenu )( int ); + + +/* A list structure */ +typedef struct tagSFG_List SFG_List; +struct tagSFG_List +{ + void *First; + void *Last; +}; + +/* A list node structure */ +typedef struct tagSFG_Node SFG_Node; +struct tagSFG_Node +{ + void *Next; + void *Prev; +}; + +/* A helper structure holding two ints and a boolean */ +typedef struct tagSFG_XYUse SFG_XYUse; +struct tagSFG_XYUse +{ + GLint X, Y; /* The two integers... */ + GLboolean Use; /* ...and a single boolean. */ +}; + +/* + * An enumeration containing the state of the GLUT execution: + * initializing, running, or stopping + */ +typedef enum +{ + GLUT_EXEC_STATE_INIT, + GLUT_EXEC_STATE_RUNNING, + GLUT_EXEC_STATE_STOP +} fgExecutionState ; + +/* This structure holds different freeglut settings */ +typedef struct tagSFG_State SFG_State; +struct tagSFG_State +{ + SFG_XYUse Position; /* The default windows' position */ + SFG_XYUse Size; /* The default windows' size */ + unsigned int DisplayMode; /* Display mode for new windows */ + + GLboolean Initialised; /* freeglut has been initialised */ + + int DirectContext; /* Direct rendering state */ + + GLboolean ForceIconic; /* New top windows are iconified */ + GLboolean UseCurrentContext; /* New windows share with current */ + + GLboolean GLDebugSwitch; /* OpenGL state debugging switch */ + GLboolean XSyncSwitch; /* X11 sync protocol switch */ + + int KeyRepeat; /* Global key repeat mode. */ + int Modifiers; /* Current ALT/SHIFT/CTRL state */ + + GLuint FPSInterval; /* Interval between FPS printfs */ + GLuint SwapCount; /* Count of glutSwapBuffer calls */ + GLuint SwapTime; /* Time of last SwapBuffers */ + + unsigned long Time; /* Time that glutInit was called */ + SFG_List Timers; /* The freeglut timer hooks */ + SFG_List FreeTimers; /* The unused timer hooks */ + + FGCBIdle IdleCallback; /* The global idle callback */ + + int ActiveMenus; /* Num. of currently active menus */ + FGCBMenuState MenuStateCallback; /* Menu callbacks are global */ + FGCBMenuStatus MenuStatusCallback; + + SFG_XYUse GameModeSize; /* Game mode screen's dimensions */ + int GameModeDepth; /* The pixel depth for game mode */ + int GameModeRefresh; /* The refresh rate for game mode */ + + int ActionOnWindowClose; /* Action when user closes window */ + + fgExecutionState ExecState; /* Used for GLUT termination */ + char *ProgramName; /* Name of the invoking program */ + GLboolean JoysticksInitialised; /* Only initialize if application calls for them */ + GLboolean InputDevsInitialised; /* Only initialize if application calls for them */ + + int AuxiliaryBufferNumber; /* Number of auxiliary buffers */ + int SampleNumber; /* Number of samples per pixel */ + + int MajorVersion; /* Major OpenGL context version */ + int MinorVersion; /* Minor OpenGL context version */ + int ContextFlags; /* OpenGL context flags */ + int ContextProfile; /* OpenGL context profile */ +}; + +/* The structure used by display initialization in freeglut_init.c */ +typedef struct tagSFG_Display SFG_Display; +struct tagSFG_Display +{ +#if TARGET_HOST_POSIX_X11 + Display* Display; /* The display we are being run in. */ + int Screen; /* The screen we are about to use. */ + Window RootWindow; /* The screen's root window. */ + int Connection; /* The display's connection number */ + Atom DeleteWindow; /* The window deletion atom */ + Atom State; /* The state atom */ + Atom StateFullScreen; /* The full screen atom */ + +#ifdef X_XF86VidModeGetModeLine + /* + * XF86VidMode may be compilable even if it fails at runtime. Therefore, + * the validity of the VidMode has to be tracked + */ + int DisplayModeValid; /* Flag that indicates runtime status*/ + XF86VidModeModeLine DisplayMode; /* Current screen's display settings */ + int DisplayModeClock; /* The display mode's refresh rate */ + int DisplayViewPortX; /* saved X location of the viewport */ + int DisplayViewPortY; /* saved Y location of the viewport */ + int DisplayPointerX; /* saved X location of the pointer */ + int DisplayPointerY; /* saved Y location of the pointer */ + +#endif /* X_XF86VidModeGetModeLine */ + +#elif TARGET_HOST_MS_WINDOWS + HINSTANCE Instance; /* The application's instance */ + DEVMODE DisplayMode; /* Desktop's display settings */ + +#endif + + int ScreenWidth; /* The screen's width in pixels */ + int ScreenHeight; /* The screen's height in pixels */ + int ScreenWidthMM; /* The screen's width in milimeters */ + int ScreenHeightMM; /* The screen's height in milimeters */ +}; + + +/* The user can create any number of timer hooks */ +typedef struct tagSFG_Timer SFG_Timer; +struct tagSFG_Timer +{ + SFG_Node Node; + int ID; /* The timer ID integer */ + FGCBTimer Callback; /* The timer callback */ + long TriggerTime; /* The timer trigger time */ +}; + +/* + * Make "freeglut" window handle and context types so that we don't need so + * much conditionally-compiled code later in the library. + */ +#if TARGET_HOST_POSIX_X11 + +typedef Window SFG_WindowHandleType ; +typedef GLXContext SFG_WindowContextType ; + +#elif TARGET_HOST_MS_WINDOWS + +typedef HWND SFG_WindowHandleType ; +typedef HGLRC SFG_WindowContextType ; + +#endif + +/* + * A window and its OpenGL context. The contents of this structure + * are highly dependant on the target operating system we aim at... + */ +typedef struct tagSFG_Context SFG_Context; +struct tagSFG_Context +{ + SFG_WindowHandleType Handle; /* The window's handle */ + SFG_WindowContextType Context; /* The window's OpenGL/WGL context */ + +#if TARGET_HOST_POSIX_X11 + GLXFBConfig* FBConfig; /* The window's FBConfig */ +#elif TARGET_HOST_MS_WINDOWS + HDC Device; /* The window's device context */ +#endif + + int DoubleBuffered; /* Treat the window as double-buffered */ +}; + +/* Window's state description. This structure should be kept portable. */ +typedef struct tagSFG_WindowState SFG_WindowState; +struct tagSFG_WindowState +{ + int Width; /* Window's width in pixels */ + int Height; /* The same about the height */ + int OldWidth; /* Window width from before a resize */ + int OldHeight; /* " height " " " " */ + + GLboolean Redisplay; /* Do we have to redisplay? */ + GLboolean Visible; /* Is the window visible now */ + + int Cursor; /* The currently selected cursor */ + + long JoystickPollRate; /* The joystick polling rate */ + long JoystickLastPoll; /* When the last poll happened */ + + int MouseX, MouseY; /* The most recent mouse position */ + + GLboolean IgnoreKeyRepeat; /* Whether to ignore key repeat. */ + GLboolean KeyRepeating; /* Currently in repeat mode */ + + GLboolean NeedToResize; /* Do we need to resize the window? */ + + GLboolean IsFullscreen; /* is the window fullscreen? */ +}; + + +/* + * A generic function pointer. We should really use the GLUTproc type + * defined in freeglut_ext.h, but if we include that header in this file + * a bunch of other stuff (font-related) blows up! + */ +typedef void (*SFG_Proc)(); + + +/* + * SET_WCB() is used as: + * + * SET_WCB( window, cbname, func ); + * + * ...where {window} is the freeglut window to set the callback, + * {cbname} is the window-specific callback to set, + * {func} is a function-pointer. + * + * Originally, {FETCH_WCB( ... ) = func} was rather sloppily used, + * but this can cause warnings because the FETCH_WCB() macro type- + * casts its result, and a type-cast value shouldn't be an lvalue. + * + * The {if( FETCH_WCB( ... ) != func )} test is to do type-checking + * and for no other reason. Since it's hidden in the macro, the + * ugliness is felt to be rather benign. + */ +#define SET_WCB(window,cbname,func) \ +do \ +{ \ + if( FETCH_WCB( window, cbname ) != (SFG_Proc)(func) ) \ + (((window).CallBacks[CB_ ## cbname]) = (SFG_Proc)(func)); \ +} while( 0 ) + +/* + * FETCH_WCB() is used as: + * + * FETCH_WCB( window, cbname ); + * + * ...where {window} is the freeglut window to fetch the callback from, + * {cbname} is the window-specific callback to fetch. + * + * The result is correctly type-cast to the callback function pointer + * type. + */ +#define FETCH_WCB(window,cbname) \ + ((window).CallBacks[CB_ ## cbname]) + +/* + * INVOKE_WCB() is used as: + * + * INVOKE_WCB( window, cbname, ( arg_list ) ); + * + * ...where {window} is the freeglut window, + * {cbname} is the window-specific callback to be invoked, + * {(arg_list)} is the parameter list. + * + * The callback is invoked as: + * + * callback( arg_list ); + * + * ...so the parentheses are REQUIRED in the {arg_list}. + * + * NOTE that it does a sanity-check and also sets the + * current window. + * + */ +#if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) /* FIXME: also WinCE? */ +#define INVOKE_WCB(window,cbname,arg_list) \ +do \ +{ \ + if( FETCH_WCB( window, cbname ) ) \ + { \ + FGCB ## cbname func = (FGCB ## cbname)(FETCH_WCB( window, cbname )); \ + fgSetWindow( &window ); \ + func arg_list; \ + } \ +} while( 0 ) +#else +#define INVOKE_WCB(window,cbname,arg_list) \ +do \ +{ \ + if( FETCH_WCB( window, cbname ) ) \ + { \ + fgSetWindow( &window ); \ + ((FGCB ## cbname)FETCH_WCB( window, cbname )) arg_list; \ + } \ +} while( 0 ) +#endif + +/* + * The window callbacks the user can supply us with. Should be kept portable. + * + * This enumeration provides the freeglut CallBack numbers. + * The symbolic constants are indices into a window's array of + * function callbacks. The names are formed by splicing a common + * prefix onto the callback's base name. (This was originally + * done so that an early stage of development could live side-by- + * side with the old callback code. The old callback code used + * the bare callback's name as a structure member, so I used a + * prefix for the array index name.) + * + * XXX For consistancy, perhaps the prefix should match the + * XXX FETCH* and INVOKE* macro suffices. I.e., WCB_, rather than + * XXX CB_. + */ +enum +{ + CB_Display, + CB_Reshape, + CB_Keyboard, + CB_KeyboardUp, + CB_Special, + CB_SpecialUp, + CB_Mouse, + CB_MouseWheel, + CB_Motion, + CB_Passive, + CB_Entry, + CB_Visibility, + CB_WindowStatus, + CB_Joystick, + CB_Destroy, + + /* Presently ignored */ + CB_Select, + CB_OverlayDisplay, + CB_SpaceMotion, /* presently implemented only on UNIX/X11 */ + CB_SpaceRotation, /* presently implemented only on UNIX/X11 */ + CB_SpaceButton, /* presently implemented only on UNIX/X11 */ + CB_Dials, + CB_ButtonBox, + CB_TabletMotion, + CB_TabletButton, + + /* Always make this the LAST one */ + TOTAL_CALLBACKS +}; + + +/* This structure holds the OpenGL rendering context for all the menu windows */ +typedef struct tagSFG_MenuContext SFG_MenuContext; +struct tagSFG_MenuContext +{ + SFG_WindowContextType MContext; /* The menu window's WGL context */ +}; + +/* This structure describes a menu */ +typedef struct tagSFG_Window SFG_Window; +typedef struct tagSFG_MenuEntry SFG_MenuEntry; +typedef struct tagSFG_Menu SFG_Menu; +struct tagSFG_Menu +{ + SFG_Node Node; + void *UserData; /* User data passed back at callback */ + int ID; /* The global menu ID */ + SFG_List Entries; /* The menu entries list */ + FGCBMenu Callback; /* The menu callback */ + FGCBDestroy Destroy; /* Destruction callback */ + GLboolean IsActive; /* Is the menu selected? */ + int Width; /* Menu box width in pixels */ + int Height; /* Menu box height in pixels */ + int X, Y; /* Menu box raster position */ + + SFG_MenuEntry *ActiveEntry; /* Currently active entry in the menu */ + SFG_Window *Window; /* Window for menu */ + SFG_Window *ParentWindow; /* Window in which the menu is invoked */ +}; + +/* This is a menu entry */ +struct tagSFG_MenuEntry +{ + SFG_Node Node; + int ID; /* The menu entry ID (local) */ + int Ordinal; /* The menu's ordinal number */ + char* Text; /* The text to be displayed */ + SFG_Menu* SubMenu; /* Optional sub-menu tree */ + GLboolean IsActive; /* Is the entry highlighted? */ + int Width; /* Label's width in pixels */ +}; + +/* + * A window, making part of freeglut windows hierarchy. + * Should be kept portable. + * + * NOTE that ActiveMenu is set to menu itself if the window is a menu. + */ +struct tagSFG_Window +{ + SFG_Node Node; + int ID; /* Window's ID number */ + + SFG_Context Window; /* Window and OpenGL context */ + SFG_WindowState State; /* The window state */ + SFG_Proc CallBacks[ TOTAL_CALLBACKS ]; /* Array of window callbacks */ + void *UserData ; /* For use by user */ + + SFG_Menu* Menu[ FREEGLUT_MAX_MENUS ]; /* Menus appended to window */ + SFG_Menu* ActiveMenu; /* The window's active menu */ + + SFG_Window* Parent; /* The parent to this window */ + SFG_List Children; /* The subwindows d.l. list */ + + GLboolean IsMenu; /* Set to 1 if we are a menu */ +}; + + +/* A linked list structure of windows */ +typedef struct tagSFG_WindowList SFG_WindowList ; +struct tagSFG_WindowList +{ + SFG_Node node; + SFG_Window *window ; +}; + +/* This holds information about all the windows, menus etc. */ +typedef struct tagSFG_Structure SFG_Structure; +struct tagSFG_Structure +{ + SFG_List Windows; /* The global windows list */ + SFG_List Menus; /* The global menus list */ + SFG_List WindowsToDestroy; + + SFG_Window* CurrentWindow; /* The currently set window */ + SFG_Menu* CurrentMenu; /* Same, but menu... */ + + SFG_MenuContext* MenuContext; /* OpenGL rendering context for menus */ + + SFG_Window* GameModeWindow; /* The game mode window */ + + int WindowID; /* The new current window ID */ + int MenuID; /* The new current menu ID */ +}; + +/* + * This structure is used for the enumeration purposes. + * You can easily extend its functionalities by declaring + * a structure containing enumerator's contents and custom + * data, then casting its pointer to (SFG_Enumerator *). + */ +typedef struct tagSFG_Enumerator SFG_Enumerator; +struct tagSFG_Enumerator +{ + GLboolean found; /* Used to terminate search */ + void* data; /* Custom data pointer */ +}; +typedef void (* FGCBenumerator )( SFG_Window *, SFG_Enumerator * ); + +/* The bitmap font structure */ +typedef struct tagSFG_Font SFG_Font; +struct tagSFG_Font +{ + char* Name; /* The source font name */ + int Quantity; /* Number of chars in font */ + int Height; /* Height of the characters */ + const GLubyte** Characters; /* The characters mapping */ + + float xorig, yorig; /* Relative origin of the character */ +}; + +/* The stroke font structures */ + +typedef struct tagSFG_StrokeVertex SFG_StrokeVertex; +struct tagSFG_StrokeVertex +{ + GLfloat X, Y; +}; + +typedef struct tagSFG_StrokeStrip SFG_StrokeStrip; +struct tagSFG_StrokeStrip +{ + int Number; + const SFG_StrokeVertex* Vertices; +}; + +typedef struct tagSFG_StrokeChar SFG_StrokeChar; +struct tagSFG_StrokeChar +{ + GLfloat Right; + int Number; + const SFG_StrokeStrip* Strips; +}; + +typedef struct tagSFG_StrokeFont SFG_StrokeFont; +struct tagSFG_StrokeFont +{ + char* Name; /* The source font name */ + int Quantity; /* Number of chars in font */ + GLfloat Height; /* Height of the characters */ + const SFG_StrokeChar** Characters; /* The characters mapping */ +}; + +/* -- GLOBAL VARIABLES EXPORTS --------------------------------------------- */ + +/* Freeglut display related stuff (initialized once per session) */ +extern SFG_Display fgDisplay; + +/* Freeglut internal structure */ +extern SFG_Structure fgStructure; + +/* The current freeglut settings */ +extern SFG_State fgState; + + +/* -- PRIVATE FUNCTION DECLARATIONS ---------------------------------------- */ + +/* + * A call to this function makes us sure that the Display and Structure + * subsystems have been properly initialized and are ready to be used + */ +#define FREEGLUT_EXIT_IF_NOT_INITIALISED( string ) \ + if ( ! fgState.Initialised ) \ + { \ + fgError ( " ERROR: Function <%s> called" \ + " without first calling 'glutInit'.", (string) ) ; \ + } + +#define FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED( string ) \ + if ( ! fgState.Initialised ) \ + { \ + fgError ( " ERROR: Internal <%s> function called" \ + " without first calling 'glutInit'.", (string) ) ; \ + } + +#define FREEGLUT_INTERNAL_ERROR_EXIT( cond, string, function ) \ + if ( ! ( cond ) ) \ + { \ + fgError ( " ERROR: Internal error <%s> in function %s", \ + (string), (function) ) ; \ + } + +/* + * Following definitions are somewhat similiar to GLib's, + * but do not generate any log messages: + */ +#define freeglut_return_if_fail( expr ) \ + if( !(expr) ) \ + return; +#define freeglut_return_val_if_fail( expr, val ) \ + if( !(expr) ) \ + return val ; + +/* + * A call to those macros assures us that there is a current + * window set, respectively: + */ +#define FREEGLUT_EXIT_IF_NO_WINDOW( string ) \ + if ( ! fgStructure.CurrentWindow ) \ + { \ + fgError ( " ERROR: Function <%s> called" \ + " with no current window defined.", (string) ) ; \ + } + +/* + * The deinitialize function gets called on glutMainLoop() end. It should clean up + * everything inside of the freeglut + */ +void fgDeinitialize( void ); + +/* + * Those two functions are used to create/destroy the freeglut internal + * structures. This actually happens when calling glutInit() and when + * quitting the glutMainLoop() (which actually happens, when all windows + * have been closed). + */ +void fgCreateStructure( void ); +void fgDestroyStructure( void ); + +/* A helper function to check if a display mode is possible to use */ +#if TARGET_HOST_POSIX_X11 +GLXFBConfig* fgChooseFBConfig( void ); +#endif + +/* The window procedure for Win32 events handling */ +#if TARGET_HOST_MS_WINDOWS +LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, + WPARAM wParam, LPARAM lParam ); +void fgNewWGLCreateContext( SFG_Window* window ); +GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly, + unsigned char layer_type ); +#endif + +/* + * Window creation, opening, closing and destruction. + * Also CallBack clearing/initialization. + * Defined in freeglut_structure.c, freeglut_window.c. + */ +SFG_Window* fgCreateWindow( SFG_Window* parent, const char* title, + GLboolean positionUse, int x, int y, + GLboolean sizeUse, int w, int h, + GLboolean gameMode, GLboolean isMenu ); +void fgSetWindow ( SFG_Window *window ); +void fgOpenWindow( SFG_Window* window, const char* title, + GLboolean positionUse, int x, int y, + GLboolean sizeUse, int w, int h, + GLboolean gameMode, GLboolean isSubWindow ); +void fgCloseWindow( SFG_Window* window ); +void fgAddToWindowDestroyList ( SFG_Window* window ); +void fgCloseWindows (); +void fgDestroyWindow( SFG_Window* window ); + +/* Menu creation and destruction. Defined in freeglut_structure.c */ +SFG_Menu* fgCreateMenu( FGCBMenu menuCallback ); +void fgDestroyMenu( SFG_Menu* menu ); + +/* Joystick device management functions, defined in freeglut_joystick.c */ +int fgJoystickDetect( void ); +void fgInitialiseJoysticks( void ); +void fgJoystickClose( void ); +void fgJoystickPollWindow( SFG_Window* window ); + +/* InputDevice Initialisation and Closure */ +int fgInputDeviceDetect( void ); +void fgInitialiseInputDevices( void ); +void fgInputDeviceClose( void ); + +/* spaceball device functions, defined in freeglut_spaceball.c */ +void fgInitialiseSpaceball( void ); +void fgSpaceballClose( void ); +void fgSpaceballSetWindow( SFG_Window *window ); + +int fgHasSpaceball( void ); +int fgSpaceballNumButtons( void ); + +#if TARGET_HOST_POSIX_X11 +int fgIsSpaceballXEvent( const XEvent *ev ); +void fgSpaceballHandleXEvent( const XEvent *ev ); +#endif + +/* Setting the cursor for a given window */ +void fgSetCursor ( SFG_Window *window, int cursorID ); + +/* + * Helper function to enumerate through all registered windows + * and one to enumerate all of a window's subwindows... + * + * The GFunc callback for those functions will be defined as: + * + * void enumCallback( gpointer window, gpointer enumerator ); + * + * where window is the enumerated (sub)window pointer (SFG_Window *), + * and userData is the a custom user-supplied pointer. Functions + * are defined and exported from freeglut_structure.c file. + */ +void fgEnumWindows( FGCBenumerator enumCallback, SFG_Enumerator* enumerator ); +void fgEnumSubWindows( SFG_Window* window, FGCBenumerator enumCallback, + SFG_Enumerator* enumerator ); + +/* + * fgWindowByHandle returns a (SFG_Window *) value pointing to the + * first window in the queue matching the specified window handle. + * The function is defined in freeglut_structure.c file. + */ +SFG_Window* fgWindowByHandle( SFG_WindowHandleType hWindow ); + +/* + * This function is similiar to the previous one, except it is + * looking for a specified (sub)window identifier. The function + * is defined in freeglut_structure.c file. + */ +SFG_Window* fgWindowByID( int windowID ); + +/* + * Looks up a menu given its ID. This is easier than fgWindowByXXX + * as all menus are placed in a single doubly linked list... + */ +SFG_Menu* fgMenuByID( int menuID ); + +/* + * The menu activation and deactivation the code. This is the meat + * of the menu user interface handling code... + */ +void fgUpdateMenuHighlight ( SFG_Menu *menu ); +GLboolean fgCheckActiveMenu ( SFG_Window *window, int button, GLboolean pressed, + int mouse_x, int mouse_y ); +void fgDeactivateMenu( SFG_Window *window ); + +/* + * This function gets called just before the buffers swap, so that + * freeglut can display the pull-down menus via OpenGL. The function + * is defined in freeglut_menu.c file. + */ +void fgDisplayMenu( void ); + +/* Elapsed time as per glutGet(GLUT_ELAPSED_TIME). */ +long fgElapsedTime( void ); + +/* System time in milliseconds */ +long unsigned fgSystemTime(void); + +/* List functions */ +void fgListInit(SFG_List *list); +void fgListAppend(SFG_List *list, SFG_Node *node); +void fgListRemove(SFG_List *list, SFG_Node *node); +int fgListLength(SFG_List *list); +void fgListInsert(SFG_List *list, SFG_Node *next, SFG_Node *node); + +/* Error Message functions */ +void fgError( const char *fmt, ... ); +void fgWarning( const char *fmt, ... ); + +/* + * Check if "hint" is present in "property" for "window". See freeglut_init.c + */ +#if TARGET_HOST_POSIX_X11 +int fgHintPresent(Window window, Atom property, Atom hint); +#endif + +SFG_Proc fghGetProcAddress( const char *procName ); + +#if TARGET_HOST_MS_WINDOWS +extern void (__cdecl *__glutExitFunc)( int return_value ); +#endif + +#endif /* FREEGLUT_INTERNAL_H */ + +/*** END OF FILE ***/ diff --git a/tests/box2d/freeglut/freeglut_joystick.c b/tests/box2d/freeglut/freeglut_joystick.c new file mode 100755 index 00000000..47127f54 --- /dev/null +++ b/tests/box2d/freeglut/freeglut_joystick.c @@ -0,0 +1,1801 @@ +/* + * freeglut_joystick.c + * + * Joystick handling code + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Steve Baker, <sjbaker1@airmail.net> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * FreeBSD port by Stephen Montgomery-Smith <stephen@math.missouri.edu> + * + * Redone by John Fay 2/4/04 with another look from the PLIB "js" library. + * Many thanks for Steve Baker for permission to pull from that library. + */ + +#include "freeglut.h" +#include "freeglut_internal.h" +#if HAVE_SYS_PARAM_H +# include <sys/param.h> +#endif + +/* + * Initial defines from "js.h" starting around line 33 with the existing "freeglut_joystick.c" + * interspersed + */ + +/* XXX It might be better to poll the operating system for the numbers of buttons and + * XXX axes and then dynamically allocate the arrays. + */ +#define _JS_MAX_BUTTONS 32 + +#if TARGET_HOST_MACINTOSH +# define _JS_MAX_AXES 9 +# include <InputSprocket.h> +#endif + +#if TARGET_HOST_MAC_OSX +# define _JS_MAX_AXES 16 +# include <mach/mach.h> +# include <IOKit/IOkitLib.h> +# include <IOKit/hid/IOHIDLib.h> +#endif + +#if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) +# define _JS_MAX_AXES 8 +# include <windows.h> +# include <mmsystem.h> +# include <regstr.h> + +#endif + +#if TARGET_HOST_POSIX_X11 +# define _JS_MAX_AXES 16 +# if HAVE_SYS_IOCTL_H +# include <sys/ioctl.h> +# endif +# if HAVE_FCNTL_H +# include <fcntl.h> +# endif +# if HAVE_ERRNO +# include <errno.h> +# endif +# if defined(__FreeBSD__) || defined(__NetBSD__) +/* XXX The below hack is done until freeglut's autoconf is updated. */ +# define HAVE_USB_JS 1 + +# if defined(__FreeBSD__) +# include <sys/joystick.h> +# else +/* + * XXX NetBSD/amd64 systems may find that they have to steal the + * XXX /usr/include/machine/joystick.h from a NetBSD/i386 system. + * XXX I cannot comment whether that works for the interface, but + * XXX it lets you compile...(^& I do not think that we can do away + * XXX with this header. + */ +# include <machine/joystick.h> /* For analog joysticks */ +# endif +# define JS_DATA_TYPE joystick +# define JS_RETURN (sizeof(struct JS_DATA_TYPE)) +# endif + +# if defined(__linux__) +# include <linux/joystick.h> + +/* check the joystick driver version */ +# if defined(JS_VERSION) && JS_VERSION >= 0x010000 +# define JS_NEW +# endif +# else /* Not BSD or Linux */ +# ifndef JS_RETURN + + /* + * We'll put these values in and that should + * allow the code to at least compile when there is + * no support. The JS open routine should error out + * and shut off all the code downstream anyway and if + * the application doesn't use a joystick we'll be fine. + */ + + struct JS_DATA_TYPE + { + int buttons; + int x; + int y; + }; + +# define JS_RETURN (sizeof(struct JS_DATA_TYPE)) +# endif +# endif +#endif + +#define JS_TRUE 1 +#define JS_FALSE 0 + +/* BSD defines from "jsBSD.cxx" around lines 42-270 */ + +#if defined(__NetBSD__) || defined(__FreeBSD__) + +# ifdef HAVE_USB_JS +# if defined(__NetBSD__) +/* XXX The below hack is done until freeglut's autoconf is updated. */ +# define HAVE_USBHID_H 1 +# ifdef HAVE_USBHID_H +# include <usbhid.h> +# else +# include <usb.h> +# endif +# elif defined(__FreeBSD__) +# if __FreeBSD_version < 500000 +# include <libusbhid.h> +# else +/* XXX The below hack is done until freeglut's autoconf is updated. */ +# define HAVE_USBHID_H 1 +# include <usbhid.h> +# endif +# endif +# include <dev/usb/usb.h> +# include <dev/usb/usbhid.h> + +/* Compatibility with older usb.h revisions */ +# if !defined(USB_MAX_DEVNAMES) && defined(MAXDEVNAMES) +# define USB_MAX_DEVNAMES MAXDEVNAMES +# endif +# endif + +static int hatmap_x[9] = { 0, 0, 1, 1, 1, 0, -1, -1, -1 }; +static int hatmap_y[9] = { 0, 1, 1, 0, -1, -1, -1, 0, 1 }; +struct os_specific_s { + char fname [128 ]; + int fd; + int is_analog; + /* The following structure members are specific to analog joysticks */ + struct joystick ajs; +# ifdef HAVE_USB_JS + /* The following structure members are specific to USB joysticks */ + struct hid_item *hids; + int hid_dlen; + int hid_offset; + char *hid_data_buf; + int axes_usage [ _JS_MAX_AXES ]; +# endif + /* We keep button and axes state ourselves, as they might not be updated + * on every read of a USB device + */ + int cache_buttons; + float cache_axes [ _JS_MAX_AXES ]; +}; + +/* Idents lower than USB_IDENT_OFFSET are for analog joysticks. */ +# define USB_IDENT_OFFSET 2 + +# define USBDEV "/dev/usb" +# define UHIDDEV "/dev/uhid" +# define AJSDEV "/dev/joy" + +# ifdef HAVE_USB_JS +/* + * fghJoystickFindUSBdev (and its helper, fghJoystickWalkUSBdev) try to locate + * the full name of a USB device. If /dev/usbN isn't readable, we punt and + * return the uhidN device name. We warn the user of this situation once. + */ +static char *fghJoystickWalkUSBdev(int f, char *dev, char *out, int outlen) +{ + struct usb_device_info di; + int i, a; + char *cp; + + for (a = 1; a < USB_MAX_DEVICES; a++) { + di.udi_addr = a; + if (ioctl(f, USB_DEVICEINFO, &di) != 0) + return NULL; + for (i = 0; i < USB_MAX_DEVNAMES; i++) + if (di.udi_devnames[i][0] && + strcmp(di.udi_devnames[i], dev) == 0) { + cp = calloc( 1, strlen(di.udi_vendor) + strlen(di.udi_product) + 2); + strcpy(cp, di.udi_vendor); + strcat(cp, " "); + strcat(cp, di.udi_product); + strncpy(out, cp, outlen - 1); + out[outlen - 1] = 0; + free( cp ); + return out; + } + } + return NULL; +} + +static int fghJoystickFindUSBdev(char *name, char *out, int outlen) +{ + int i, f; + char buf[50]; + char *cp; + static int protection_warned = 0; + + for (i = 0; i < 16; i++) { + snprintf(buf, sizeof(buf), "%s%d", USBDEV, i); + f = open(buf, O_RDONLY); + if (f >= 0) { + cp = fghJoystickWalkUSBdev(f, name, out, outlen); + close(f); + if (cp) + return 1; + } +#if HAVE_ERRNO + else if (errno == EACCES) { + if (!protection_warned) { + fgWarning ( "Can't open %s for read!", buf ); + protection_warned = 1; + } + } +#endif + } + return 0; +} + +static int fghJoystickInitializeHID(struct os_specific_s *os, + int *num_axes, int *num_buttons) +{ + int size, is_joystick; +# ifdef HAVE_USBHID_H + int report_id = 0; +# endif + struct hid_data *d; + struct hid_item h; + report_desc_t rd; + + if ( ( rd = hid_get_report_desc( os->fd ) ) == 0 ) + { +#if HAVE_ERRNO + fgWarning ( "error: %s: %s", os->fname, strerror( errno ) ); +#else + fgWarning ( "error: %s", os->fname ); +#endif + return FALSE; + } + + os->hids = NULL; + +# ifdef HAVE_USBHID_H + if( ioctl( os->fd, USB_GET_REPORT_ID, &report_id ) < 0) + { + /*** XXX {report_id} may not be the right variable? ***/ +#if HAVE_ERRNO + fgWarning ( "error: %s%d: %s", UHIDDEV, report_id, strerror( errno ) ); +#else + fgWarning ( "error: %s%d", UHIDDEV, report_id ); +#endif + return FALSE; + } + + size = hid_report_size( rd, hid_input, report_id ); +# else + size = hid_report_size( rd, 0, hid_input ); +# endif + os->hid_data_buf = calloc( 1, size ); + os->hid_dlen = size; + + is_joystick = 0; +# ifdef HAVE_USBHID_H + d = hid_start_parse( rd, 1 << hid_input, report_id ); +# else + d = hid_start_parse( rd, 1 << hid_input ); +# endif + while( hid_get_item( d, &h ) ) + { + int usage, page, interesting_hid; + + page = HID_PAGE( h.usage ); + usage = HID_USAGE( h.usage ); + + /* This test is somewhat too simplistic, but this is how MicroSoft + * does, so I guess it works for all joysticks/game pads. */ + is_joystick = is_joystick || + ( h.kind == hid_collection && + page == HUP_GENERIC_DESKTOP && + ( usage == HUG_JOYSTICK || usage == HUG_GAME_PAD ) ); + + if( h.kind != hid_input ) + continue; + + if( !is_joystick ) + continue; + + interesting_hid = TRUE; + if( page == HUP_GENERIC_DESKTOP ) + { + switch( usage ) + { + case HUG_X: + case HUG_RX: + case HUG_Y: + case HUG_RY: + case HUG_Z: + case HUG_RZ: + case HUG_SLIDER: + if( *num_axes < _JS_MAX_AXES ) + { + os->axes_usage[ *num_axes ] = usage; + ( *num_axes )++; + } + break; + case HUG_HAT_SWITCH: + /* Allocate two axes for a hat */ + if( *num_axes + 1 < _JS_MAX_AXES ) + { + os->axes_usage[ *num_axes ] = usage; + (*num_axes)++; + os->axes_usage[ *num_axes ] = usage; + (*num_axes)++; + } + break; + default: + interesting_hid = FALSE; + break; + } + } + else if( page == HUP_BUTTON ) + { + interesting_hid = ( usage > 0 ) && + ( usage <= _JS_MAX_BUTTONS ); + + if( interesting_hid && usage - 1 > *num_buttons ) + *num_buttons = usage - 1; + } + + if( interesting_hid ) + { + h.next = os->hids; + os->hids = calloc( 1, sizeof ( struct hid_item ) ); + *os->hids = h; + } + } + hid_end_parse( d ); + + return os->hids != NULL; +} +# endif +#endif + +/* + * Definition of "SFG_Joystick" structure -- based on JS's "jsJoystick" object class. + * See "js.h" lines 80-178. + */ +typedef struct tagSFG_Joystick SFG_Joystick; +struct tagSFG_Joystick +{ +#if TARGET_HOST_MACINTOSH +#define ISP_NUM_AXIS 9 +#define ISP_NUM_NEEDS 41 + ISpElementReference isp_elem [ ISP_NUM_NEEDS ]; + ISpNeed isp_needs [ ISP_NUM_NEEDS ]; +#endif + +#if TARGET_HOST_MAC_OSX + IOHIDDeviceInterface ** hidDev; + IOHIDElementCookie buttonCookies[41]; + IOHIDElementCookie axisCookies[_JS_MAX_AXES]; + long minReport[_JS_MAX_AXES], + maxReport[_JS_MAX_AXES]; +#endif + +#if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) + JOYCAPS jsCaps; + JOYINFOEX js; + UINT js_id; +#endif + + +#if TARGET_HOST_POSIX_X11 +# if defined(__FreeBSD__) || defined(__NetBSD__) + struct os_specific_s *os; +# endif + +# ifdef JS_NEW + struct js_event js; + int tmp_buttons; + float tmp_axes [ _JS_MAX_AXES ]; +# else + struct JS_DATA_TYPE js; +# endif + + char fname [ 128 ]; + int fd; +#endif + + int id; + GLboolean error; + char name [ 128 ]; + int num_axes; + int num_buttons; + + float dead_band[ _JS_MAX_AXES ]; + float saturate [ _JS_MAX_AXES ]; + float center [ _JS_MAX_AXES ]; + float max [ _JS_MAX_AXES ]; + float min [ _JS_MAX_AXES ]; +}; + +/* + * Functions associated with the "jsJoystick" class in PLIB + */ +#if TARGET_HOST_MAC_OSX +#define K_NUM_DEVICES 32 +int numDevices; +io_object_t ioDevices[K_NUM_DEVICES]; + +static void fghJoystickFindDevices ( SFG_Joystick* joy, mach_port_t ); +static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick* joy, io_object_t ); + +static void fghJoystickEnumerateElements ( SFG_Joystick* joy, CFTypeRef element ); +/* callback for CFArrayApply */ +static void fghJoystickElementEnumerator ( SFG_Joystick* joy, void *element, void* vjs ); + +static void fghJoystickAddAxisElement ( SFG_Joystick* joy, CFDictionaryRef axis ); +static void fghJoystickAddButtonElement ( SFG_Joystick* joy, CFDictionaryRef button ); +static void fghJoystickAddHatElement ( SFG_Joystick* joy, CFDictionaryRef hat ); +#endif + + +/* + * The static joystick structure pointer + */ +#define MAX_NUM_JOYSTICKS 2 +static SFG_Joystick *fgJoystick [ MAX_NUM_JOYSTICKS ]; + + +/* + * Read the raw joystick data + */ +static void fghJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes ) +{ +#if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) + MMRESULT status; +#else + int status; +#endif + +#if defined(__FreeBSD__) || defined(__NetBSD__) + int len; +#endif + + int i; + + /* Defaults */ + if( buttons ) + *buttons = 0; + + if( axes ) + for( i = 0; i < joy->num_axes; i++ ) + axes[ i ] = 1500.0f; + + if( joy->error ) + return; + +#if TARGET_HOST_MACINTOSH + if ( buttons ) + { + *buttons = 0; + + for ( i = 0; i < joy->num_buttons; i++ ) + { + UInt32 state; + int err = ISpElement_GetSimpleState ( isp_elem [ i + isp_num_axis ], &state); + ISP_CHECK_ERR(err) + + *buttons |= state << i; + } + } + + if ( axes ) + { + for ( i = 0; i < joy->num_axes; i++ ) + { + UInt32 state; + int err = ISpElement_GetSimpleState ( isp_elem [ i ], &state ); + ISP_CHECK_ERR(err) + + axes [i] = (float) state; + } + } +#endif + +#if TARGET_HOST_MAC_OSX + if ( buttons != NULL ) + { + *buttons = 0; + + for ( i = 0; i < joy->num_buttons; i++ ) + { + IOHIDEventStruct hidEvent; + (*(joy->hidDev))->getElementValue ( joy->hidDev, buttonCookies[i], &hidEvent ); + if ( hidEvent.value ) + *buttons |= 1 << i; + } + } + + if ( axes != NULL ) + { + for ( i = 0; i < joy->num_axes; i++ ) + { + IOHIDEventStruct hidEvent; + (*(joy->hidDev))->getElementValue ( joy->hidDev, axisCookies[i], &hidEvent ); + axes[i] = hidEvent.value; + } + } +#endif + +#if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) + status = joyGetPosEx( joy->js_id, &joy->js ); + + if ( status != JOYERR_NOERROR ) + { + joy->error = GL_TRUE; + return; + } + + if ( buttons ) + *buttons = joy->js.dwButtons; + + if ( axes ) + { + /* + * WARNING - Fall through case clauses!! + */ + switch ( joy->num_axes ) + { + case 8: + /* Generate two POV axes from the POV hat angle. + * Low 16 bits of js.dwPOV gives heading (clockwise from ahead) in + * hundredths of a degree, or 0xFFFF when idle. + */ + if ( ( joy->js.dwPOV & 0xFFFF ) == 0xFFFF ) + { + axes [ 6 ] = 0.0; + axes [ 7 ] = 0.0; + } + else + { + /* This is the contentious bit: how to convert angle to X/Y. + * wk: I know of no define for PI that we could use here: + * SG_PI would pull in sg, M_PI is undefined for MSVC + * But the accuracy of the value of PI is very unimportant at + * this point. + */ + float s = (float) sin ( ( joy->js.dwPOV & 0xFFFF ) * ( 0.01 * 3.1415926535f / 180.0f ) ); + float c = (float) cos ( ( joy->js.dwPOV & 0xFFFF ) * ( 0.01 * 3.1415926535f / 180.0f ) ); + + /* Convert to coordinates on a square so that North-East + * is (1,1) not (.7,.7), etc. + * s and c cannot both be zero so we won't divide by zero. + */ + if ( fabs ( s ) < fabs ( c ) ) + { + axes [ 6 ] = ( c < 0.0 ) ? -s/c : s/c ; + axes [ 7 ] = ( c < 0.0 ) ? -1.0f : 1.0f; + } + else + { + axes [ 6 ] = ( s < 0.0 ) ? -1.0f : 1.0f; + axes [ 7 ] = ( s < 0.0 ) ? -c/s : c/s ; + } + } + + case 6: axes[5] = (float) joy->js.dwVpos; + case 5: axes[4] = (float) joy->js.dwUpos; + case 4: axes[3] = (float) joy->js.dwRpos; + case 3: axes[2] = (float) joy->js.dwZpos; + case 2: axes[1] = (float) joy->js.dwYpos; + case 1: axes[0] = (float) joy->js.dwXpos; + } + } +#endif + +#if TARGET_HOST_POSIX_X11 +# if defined(__FreeBSD__) || defined(__NetBSD__) + if ( joy->os->is_analog ) + { + int status = read ( joy->os->fd, &joy->os->ajs, sizeof(joy->os->ajs) ); + if ( status != sizeof(joy->os->ajs) ) { + perror ( joy->os->fname ); + joy->error = GL_TRUE; + return; + } + if ( buttons != NULL ) + *buttons = ( joy->os->ajs.b1 ? 1 : 0 ) | ( joy->os->ajs.b2 ? 2 : 0 ); + + if ( axes != NULL ) + { + axes[0] = (float) joy->os->ajs.x; + axes[1] = (float) joy->os->ajs.y; + } + + return; + } + +# ifdef HAVE_USB_JS + while ( ( len = read ( joy->os->fd, joy->os->hid_data_buf, joy->os->hid_dlen ) ) == joy->os->hid_dlen ) + { + struct hid_item *h; + + for ( h = joy->os->hids; h; h = h->next ) + { + int d = hid_get_data ( joy->os->hid_data_buf, h ); + + int page = HID_PAGE ( h->usage ); + int usage = HID_USAGE ( h->usage ); + + if ( page == HUP_GENERIC_DESKTOP ) + { + int i; + for ( i = 0; i < joy->num_axes; i++ ) + if (joy->os->axes_usage[i] == usage) + { + if (usage == HUG_HAT_SWITCH) + { + if (d < 0 || d > 8) + d = 0; /* safety */ + joy->os->cache_axes[i] = (float)hatmap_x[d]; + joy->os->cache_axes[i + 1] = (float)hatmap_y[d]; + } + else + { + joy->os->cache_axes[i] = (float)d; + } + break; + } + } + else if (page == HUP_BUTTON) + { + if (usage > 0 && usage < _JS_MAX_BUTTONS + 1) + { + if (d) + joy->os->cache_buttons |= (1 << ( usage - 1 )); + else + joy->os->cache_buttons &= ~(1 << ( usage - 1 )); + } + } + } + } +#if HAVE_ERRNO + if ( len < 0 && errno != EAGAIN ) +#else + if ( len < 0 ) +#endif + { + perror( joy->os->fname ); + joy->error = 1; + } + if ( buttons != NULL ) *buttons = joy->os->cache_buttons; + if ( axes != NULL ) + memcpy ( axes, joy->os->cache_axes, sizeof(float) * joy->num_axes ); +# endif +# endif + +# ifdef JS_NEW + + while ( 1 ) + { + status = read ( joy->fd, &joy->js, sizeof(struct js_event) ); + + if ( status != sizeof( struct js_event ) ) + { +#if HAVE_ERRNO + if ( errno == EAGAIN ) + { + /* Use the old values */ + if ( buttons ) + *buttons = joy->tmp_buttons; + if ( axes ) + memcpy( axes, joy->tmp_axes, + sizeof( float ) * joy->num_axes ); + return; + } +#endif + + fgWarning ( "%s", joy->fname ); + joy->error = GL_TRUE; + return; + } + + switch ( joy->js.type & ~JS_EVENT_INIT ) + { + case JS_EVENT_BUTTON: + if( joy->js.value == 0 ) /* clear the flag */ + joy->tmp_buttons &= ~( 1 << joy->js.number ); + else + joy->tmp_buttons |= ( 1 << joy->js.number ); + break; + + case JS_EVENT_AXIS: + if ( joy->js.number < joy->num_axes ) + { + joy->tmp_axes[ joy->js.number ] = ( float )joy->js.value; + + if( axes ) + memcpy( axes, joy->tmp_axes, sizeof(float) * joy->num_axes ); + } + break; + + default: + fgWarning ( "PLIB_JS: Unrecognised /dev/js return!?!" ); + + /* use the old values */ + + if ( buttons != NULL ) *buttons = joy->tmp_buttons; + if ( axes != NULL ) + memcpy ( axes, joy->tmp_axes, sizeof(float) * joy->num_axes ); + + return; + } + + if( buttons ) + *buttons = joy->tmp_buttons; + } +# else + + status = read( joy->fd, &joy->js, JS_RETURN ); + + if ( status != JS_RETURN ) + { + fgWarning( "%s", joy->fname ); + joy->error = GL_TRUE; + return; + } + + if ( buttons ) +# if defined( __FreeBSD__ ) || defined( __NetBSD__ ) + *buttons = ( joy->js.b1 ? 1 : 0 ) | ( joy->js.b2 ? 2 : 0 ); /* XXX Should not be here -- BSD is handled earlier */ +# else + *buttons = joy->js.buttons; +# endif + + if ( axes ) + { + axes[ 0 ] = (float) joy->js.x; + axes[ 1 ] = (float) joy->js.y; + } +# endif +#endif +} + +/* + * Correct the joystick axis data + */ +static float fghJoystickFudgeAxis( SFG_Joystick* joy, float value, int axis ) +{ + if( value < joy->center[ axis ] ) + { + float xx = ( value - joy->center[ axis ] ) / ( joy->center[ axis ] - + joy->min[ axis ] ); + + if( xx < -joy->saturate[ axis ] ) + return -1.0f; + + if( xx > -joy->dead_band [ axis ] ) + return 0.0f; + + xx = ( xx + joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] - + joy->dead_band[ axis ] ); + + return ( xx < -1.0f ) ? -1.0f : xx; + } + else + { + float xx = ( value - joy->center [ axis ] ) / ( joy->max[ axis ] - + joy->center[ axis ] ); + + if( xx > joy->saturate[ axis ] ) + return 1.0f; + + if( xx < joy->dead_band[ axis ] ) + return 0.0f; + + xx = ( xx - joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] - + joy->dead_band[ axis ] ); + + return ( xx > 1.0f ) ? 1.0f : xx; + } +} + +/* + * Read the corrected joystick data + */ +static void fghJoystickRead( SFG_Joystick* joy, int* buttons, float* axes ) +{ + float raw_axes[ _JS_MAX_AXES ]; + int i; + + if( joy->error ) + { + if( buttons ) + *buttons = 0; + + if( axes ) + for ( i=0; i<joy->num_axes; i++ ) + axes[ i ] = 0.0f; + } + + fghJoystickRawRead( joy, buttons, raw_axes ); + + if( axes ) + for( i=0; i<joy->num_axes; i++ ) + axes[ i ] = fghJoystickFudgeAxis( joy, raw_axes[ i ], i ); +} + +/* + * Happy happy happy joy joy joy (happy new year toudi :D) + */ + + +#if TARGET_HOST_MAC_OSX +/** open the IOKit connection, enumerate all the HID devices, add their +interface references to the static array. We then use the array index +as the device number when we come to open() the joystick. */ +static int fghJoystickFindDevices ( SFG_Joystick *joy, mach_port_t masterPort ) +{ + CFMutableDictionaryRef hidMatch = NULL; + IOReturn rv = kIOReturnSuccess; + + io_iterator_t hidIterator; + io_object_t ioDev; + + /* build a dictionary matching HID devices */ + hidMatch = IOServiceMatching(kIOHIDDeviceKey); + + rv = IOServiceGetMatchingServices(masterPort, hidMatch, &hidIterator); + if (rv != kIOReturnSuccess || !hidIterator) { + fgWarning( "no joystick (HID) devices found" ); + return; + } + + /* iterate */ + while ((ioDev = IOIteratorNext(hidIterator))) { + /* filter out keyboard and mouse devices */ + CFDictionaryRef properties = getCFProperties(ioDev); + long usage, page; + + CFTypeRef refPage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsagePageKey)); + CFTypeRef refUsage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsageKey)); + CFNumberGetValue((CFNumberRef) refUsage, kCFNumberLongType, &usage); + CFNumberGetValue((CFNumberRef) refPage, kCFNumberLongType, &page); + + /* keep only joystick devices */ + if ( ( page == kHIDPage_GenericDesktop ) && ( + (usage == kHIDUsage_GD_Joystick) + || (usage == kHIDUsage_GD_GamePad) + || (usage == kHIDUsage_GD_MultiAxisController) + || (usage == kHIDUsage_GD_Hatswitch) /* last two necessary ? */ + /* add it to the array */ + ioDevices[numDevices++] = ioDev; + } + + IOObjectRelease(hidIterator); +} + +static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick *joy, io_object_t ioDev ) +{ + IOReturn rv; + CFMutableDictionaryRef cfProperties; + +#if 0 + /* comment copied from darwin/SDL_sysjoystick.c */ + /* Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also + * get dictionary for usb properties: step up two levels and get CF dictionary for USB properties + */ + + io_registry_entry_t parent1, parent2; + + rv = IORegistryEntryGetParentEntry (ioDev, kIOServicePlane, &parent1); + if (rv != kIOReturnSuccess) { + fgWarning ( "error getting device entry parent"); + return NULL; + } + + rv = IORegistryEntryGetParentEntry (parent1, kIOServicePlane, &parent2); + if (rv != kIOReturnSuccess) { + fgWarning ( "error getting device entry parent 2"); + return NULL; + } +#endif + + rv = IORegistryEntryCreateCFProperties( ioDev /*parent2*/, + &cfProperties, kCFAllocatorDefault, kNilOptions); + if (rv != kIOReturnSuccess || !cfProperties) { + fgWarning ( "error getting device properties"); + return NULL; + } + + return cfProperties; +} + +static void fghJoystickElementEnumerator ( SFG_Joystick *joy, void *element, void* vjs ) +{ + if (CFGetTypeID((CFTypeRef) element) != CFDictionaryGetTypeID()) { + fgError ( "%s", "element enumerator passed non-dictionary value"); + return; + } + + static_cast<jsJoystick*>(vjs)->parseElement ( (CFDictionaryRef) element ); +} + +/** element enumerator function : pass NULL for top-level*/ +static void fghJoystickEnumerateElements ( SFG_Joystick *joy, CFTypeRef element ) +{ + FREEGLUT_INTERNAL_ERROR_EXIT( (CFGetTypeID(element) == CFArrayGetTypeID(), + "Joystick element type mismatch", + "fghJoystickEnumerateElements" ); + + CFRange range = {0, CFArrayGetCount ((CFArrayRef)element)}; + CFArrayApplyFunction((CFArrayRef) element, range, + &fghJoystickElementEnumerator, joy ); +} + +static void fghJoystickAddAxisElement ( SFG_Joystick *joy, CFDictionaryRef axis ) +{ + long cookie, lmin, lmax; + int index = joy->num_axes++; + + CFNumberGetValue ((CFNumberRef) + CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementCookieKey) ), + kCFNumberLongType, &cookie); + + axisCookies[index] = (IOHIDElementCookie) cookie; + + CFNumberGetValue ((CFNumberRef) + CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMinKey) ), + kCFNumberLongType, &lmin); + + CFNumberGetValue ((CFNumberRef) + CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMaxKey) ), + kCFNumberLongType, &lmax); + + joy->min[index] = lmin; + joy->max[index] = lmax; + joy->dead_band[index] = 0.0; + joy->saturate[index] = 1.0; + joy->center[index] = (lmax + lmin) * 0.5; +} + +static void fghJoystickAddButtonElement ( SFG_Joystick *joy, CFDictionaryRef button ) +{ + long cookie; + CFNumberGetValue ((CFNumberRef) + CFDictionaryGetValue ( button, CFSTR(kIOHIDElementCookieKey) ), + kCFNumberLongType, &cookie); + + joy->buttonCookies[num_buttons++] = (IOHIDElementCookie) cookie; + /* anything else for buttons? */ +} + +static void fghJoystickAddHatElement ( SFG_Joystick *joy, CFDictionaryRef button ) +{ + /* hatCookies[num_hats++] = (IOHIDElementCookie) cookie; */ + /* do we map hats to axes or buttons? */ +} +#endif + +#if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) +/* Inspired by + http://msdn.microsoft.com/archive/en-us/dnargame/html/msdn_sidewind3d.asp + */ +# if FREEGLUT_LIB_PRAGMAS +# pragma comment (lib, "advapi32.lib") +# endif + +static int fghJoystickGetOEMProductName ( SFG_Joystick* joy, char *buf, int buf_sz ) +{ + char buffer [ 256 ]; + + char OEMKey [ 256 ]; + + HKEY hKey; + DWORD dwcb; + LONG lr; + + if ( joy->error ) + return 0; + + /* Open .. MediaResources\CurrentJoystickSettings */ + _snprintf ( buffer, sizeof(buffer), "%s\\%s\\%s", + REGSTR_PATH_JOYCONFIG, joy->jsCaps.szRegKey, + REGSTR_KEY_JOYCURR ); + + lr = RegOpenKeyEx ( HKEY_LOCAL_MACHINE, buffer, 0, KEY_QUERY_VALUE, &hKey); + + if ( lr != ERROR_SUCCESS ) return 0; + + /* Get OEM Key name */ + dwcb = sizeof(OEMKey); + + /* JOYSTICKID1-16 is zero-based; registry entries for VJOYD are 1-based. */ + _snprintf ( buffer, sizeof(buffer), "Joystick%d%s", joy->js_id + 1, REGSTR_VAL_JOYOEMNAME ); + + lr = RegQueryValueEx ( hKey, buffer, 0, 0, (LPBYTE) OEMKey, &dwcb); + RegCloseKey ( hKey ); + + if ( lr != ERROR_SUCCESS ) return 0; + + /* Open OEM Key from ...MediaProperties */ + _snprintf ( buffer, sizeof(buffer), "%s\\%s", REGSTR_PATH_JOYOEM, OEMKey ); + + lr = RegOpenKeyEx ( HKEY_LOCAL_MACHINE, buffer, 0, KEY_QUERY_VALUE, &hKey ); + + if ( lr != ERROR_SUCCESS ) return 0; + + /* Get OEM Name */ + dwcb = buf_sz; + + lr = RegQueryValueEx ( hKey, REGSTR_VAL_JOYOEMNAME, 0, 0, (LPBYTE) buf, + &dwcb ); + RegCloseKey ( hKey ); + + if ( lr != ERROR_SUCCESS ) return 0; + + return 1; +} +#endif + + +static void fghJoystickOpen( SFG_Joystick* joy ) +{ + int i = 0; +#if TARGET_HOST_MACINTOSH + OSStatus err; +#endif +#if TARGET_HOST_MAC_OSX + IOReturn rv; + SInt32 score; + IOCFPlugInInterface **plugin; + + HRESULT pluginResult; + + CFDictionaryRef props; + CFTypeRef topLevelElement; +#endif +#if TARGET_HOST_POSIX_X11 +# if defined( __FreeBSD__ ) || defined( __NetBSD__ ) + char *cp; +# endif +# ifdef JS_NEW + unsigned char u; +# else +# if defined( __linux__ ) || TARGET_HOST_SOLARIS + int counter = 0; +# endif +# endif +#endif + + /* Silence gcc, the correct #ifdefs would be too fragile... */ + (void)i; + + /* + * Default values (for no joystick -- each conditional will reset the + * error flag) + */ + joy->error = TRUE; + joy->num_axes = joy->num_buttons = 0; + joy->name[ 0 ] = '\0'; + +#if TARGET_HOST_MACINTOSH + /* XXX FIXME: get joystick name in Mac */ + + err = ISpStartup( ); + + if( err == noErr ) + { +#define ISP_CHECK_ERR(x) if( x != noErr ) { joy->error = GL_TRUE; return; } + + joy->error = GL_TRUE; + + /* initialize the needs structure */ + ISpNeed temp_isp_needs[ isp_num_needs ] = + { + { "\pX-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 }, + { "\pY-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 }, + { "\pZ-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 }, + { "\pR-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 }, + { "\pAxis 4", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 }, + { "\pAxis 5", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 }, + { "\pAxis 6", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 }, + { "\pAxis 7", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 }, + { "\pAxis 8", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 }, + + { "\pButton 0", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 1", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 2", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 3", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 4", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 5", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 6", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 7", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 8", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 9", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 10", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 11", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 12", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 13", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 14", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 15", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 16", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 17", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 18", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 19", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 20", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 21", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 22", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 23", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 24", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 25", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 26", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 27", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 28", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 29", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 30", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + { "\pButton 31", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 }, + }; + + memcpy( joy->isp_needs, temp_isp_needs, sizeof (temp_isp_needs ) ); + + + /* next two calls allow keyboard and mouse to emulate other input + * devices (gamepads, joysticks, etc) + */ + /* + err = ISpDevices_ActivateClass ( kISpDeviceClass_Keyboard ); + ISP_CHECK_ERR(err) + + + err = ISpDevices_ActivateClass ( kISpDeviceClass_Mouse ); + ISP_CHECK_ERR(err) + */ + + err = ISpElement_NewVirtualFromNeeds( joy->isp_num_needs, + joy->isp_needs, joy->isp_elem, + 0 ); + ISP_CHECK_ERR( err ) + + err = ISpInit( joy->isp_num_needs, joy->isp_needs, joy->isp_elem, + 'freeglut', nil, 0, 128, 0 ); + ISP_CHECK_ERR( err ) + + joy->num_buttons = joy->isp_num_needs - joy->isp_num_axis; + joy->num_axes = joy->isp_num_axis; + + for( i = 0; i < joy->num_axes; i++ ) + { + joy->dead_band[ i ] = 0; + joy->saturate [ i ] = 1; + joy->center [ i ] = kISpAxisMiddle; + joy->max [ i ] = kISpAxisMaximum; + joy->min [ i ] = kISpAxisMinimum; + } + + joy->error = GL_FALSE; + } + else + joy->num_buttons = joy->num_axes = 0; +#endif + +#if TARGET_HOST_MAC_OSX + if( joy->id >= numDevices ) + { + fgWarning( "device index out of range in fgJoystickOpen()" ); + return; + } + + /* create device interface */ + rv = IOCreatePlugInInterfaceForService( ioDevices[ joy->id ], + kIOHIDDeviceUserClientTypeID, + kIOCFPlugInInterfaceID, + &plugin, &score ); + + if( rv != kIOReturnSuccess ) + { + fgWarning( "error creating plugin for io device" ); + return; + } + + pluginResult = ( *plugin )->QueryInterface( + plugin, + CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID), + &( LPVOID )joy->hidDev + ); + + if( pluginResult != S_OK ) + fgWarning ( "QI-ing IO plugin to HID Device interface failed" ); + + ( *plugin )->Release( plugin ); /* don't leak a ref */ + if( joy->hidDev == NULL ) + return; + + /* store the interface in this instance */ + rv = ( *( joy->hidDev ) )->open( joy->hidDev, 0 ); + if( rv != kIOReturnSuccess ) + { + fgWarning( "error opening device interface"); + return; + } + + props = getCFProperties( ioDevices[ joy->id ] ); + + /* recursively enumerate all the bits */ + CFTypeRef topLevelElement = + CFDictionaryGetValue( props, CFSTR( kIOHIDElementKey ) ); + enumerateElements( topLevelElement ); + + CFRelease( props ); +#endif + +#if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) + joy->js.dwFlags = JOY_RETURNALL; + joy->js.dwSize = sizeof( joy->js ); + + memset( &joy->jsCaps, 0, sizeof( joy->jsCaps ) ); + + joy->error = + ( joyGetDevCaps( joy->js_id, &joy->jsCaps, sizeof( joy->jsCaps ) ) != + JOYERR_NOERROR ); + + if( joy->jsCaps.wNumAxes == 0 ) + { + joy->num_axes = 0; + joy->error = GL_TRUE; + } + else + { + /* Device name from jsCaps is often "Microsoft PC-joystick driver", + * at least for USB. Try to get the real name from the registry. + */ + if ( ! fghJoystickGetOEMProductName( joy, joy->name, + sizeof( joy->name ) ) ) + { + fgWarning( "JS: Failed to read joystick name from registry" ); + strncpy( joy->name, joy->jsCaps.szPname, sizeof( joy->name ) ); + } + + /* Windows joystick drivers may provide any combination of + * X,Y,Z,R,U,V,POV - not necessarily the first n of these. + */ + if( joy->jsCaps.wCaps & JOYCAPS_HASPOV ) + { + joy->num_axes = _JS_MAX_AXES; + joy->min[ 7 ] = -1.0; joy->max[ 7 ] = 1.0; /* POV Y */ + joy->min[ 6 ] = -1.0; joy->max[ 6 ] = 1.0; /* POV X */ + } + else + joy->num_axes = 6; + + joy->min[ 5 ] = ( float )joy->jsCaps.wVmin; + joy->max[ 5 ] = ( float )joy->jsCaps.wVmax; + joy->min[ 4 ] = ( float )joy->jsCaps.wUmin; + joy->max[ 4 ] = ( float )joy->jsCaps.wUmax; + joy->min[ 3 ] = ( float )joy->jsCaps.wRmin; + joy->max[ 3 ] = ( float )joy->jsCaps.wRmax; + joy->min[ 2 ] = ( float )joy->jsCaps.wZmin; + joy->max[ 2 ] = ( float )joy->jsCaps.wZmax; + joy->min[ 1 ] = ( float )joy->jsCaps.wYmin; + joy->max[ 1 ] = ( float )joy->jsCaps.wYmax; + joy->min[ 0 ] = ( float )joy->jsCaps.wXmin; + joy->max[ 0 ] = ( float )joy->jsCaps.wXmax; + } + + /* Guess all the rest judging on the axes extremals */ + for( i = 0; i < joy->num_axes; i++ ) + { + joy->center [ i ] = ( joy->max[ i ] + joy->min[ i ] ) * 0.5f; + joy->dead_band[ i ] = 0.0f; + joy->saturate [ i ] = 1.0f; + } +#endif + +#if TARGET_HOST_POSIX_X11 +#if defined( __FreeBSD__ ) || defined( __NetBSD__ ) + for( i = 0; i < _JS_MAX_AXES; i++ ) + joy->os->cache_axes[ i ] = 0.0f; + + joy->os->cache_buttons = 0; + + joy->os->fd = open( joy->os->fname, O_RDONLY | O_NONBLOCK); + +#if HAVE_ERRNO + if( joy->os->fd < 0 && errno == EACCES ) + fgWarning ( "%s exists but is not readable by you", joy->os->fname ); +#endif + + joy->error =( joy->os->fd < 0 ); + + if( joy->error ) + return; + + joy->num_axes = 0; + joy->num_buttons = 0; + if( joy->os->is_analog ) + { + FILE *joyfile; + char joyfname[ 1024 ]; + int noargs, in_no_axes; + + float axes [ _JS_MAX_AXES ]; + int buttons[ _JS_MAX_AXES ]; + + joy->num_axes = 2; + joy->num_buttons = 32; + + fghJoystickRawRead( joy, buttons, axes ); + joy->error = axes[ 0 ] < -1000000000.0f; + if( joy->error ) + return; + + snprintf( joyfname, sizeof(joyfname), "%s/.joy%drc", getenv( "HOME" ), joy->id ); + + joyfile = fopen( joyfname, "r" ); + joy->error =( joyfile == NULL ); + if( joy->error ) + return; + + noargs = fscanf( joyfile, "%d%f%f%f%f%f%f", &in_no_axes, + &joy->min[ 0 ], &joy->center[ 0 ], &joy->max[ 0 ], + &joy->min[ 1 ], &joy->center[ 1 ], &joy->max[ 1 ] ); + joy->error = noargs != 7 || in_no_axes != _JS_MAX_AXES; + fclose( joyfile ); + if( joy->error ) + return; + + for( i = 0; i < _JS_MAX_AXES; i++ ) + { + joy->dead_band[ i ] = 0.0f; + joy->saturate [ i ] = 1.0f; + } + + return; /* End of analog code */ + } + +# ifdef HAVE_USB_JS + if( ! fghJoystickInitializeHID( joy->os, &joy->num_axes, + &joy->num_buttons ) ) + { + close( joy->os->fd ); + joy->error = GL_TRUE; + return; + } + + cp = strrchr( joy->os->fname, '/' ); + if( cp ) + { + if( fghJoystickFindUSBdev( &cp[1], joy->name, sizeof( joy->name ) ) == + 0 ) + strcpy( joy->name, &cp[1] ); + } + + if( joy->num_axes > _JS_MAX_AXES ) + joy->num_axes = _JS_MAX_AXES; + + for( i = 0; i < _JS_MAX_AXES; i++ ) + { + /* We really should get this from the HID, but that data seems + * to be quite unreliable for analog-to-USB converters. Punt for + * now. + */ + if( joy->os->axes_usage[ i ] == HUG_HAT_SWITCH ) + { + joy->max [ i ] = 1.0f; + joy->center[ i ] = 0.0f; + joy->min [ i ] = -1.0f; + } + else + { + joy->max [ i ] = 255.0f; + joy->center[ i ] = 127.0f; + joy->min [ i ] = 0.0f; + } + + joy->dead_band[ i ] = 0.0f; + joy->saturate[ i ] = 1.0f; + } +# endif +#endif + +#if defined( __linux__ ) || TARGET_HOST_SOLARIS + /* Default for older Linux systems. */ + joy->num_axes = 2; + joy->num_buttons = 32; + +# ifdef JS_NEW + for( i = 0; i < _JS_MAX_AXES; i++ ) + joy->tmp_axes[ i ] = 0.0f; + + joy->tmp_buttons = 0; +# endif + + joy->fd = open( joy->fname, O_RDONLY ); + + joy->error =( joy->fd < 0 ); + + if( joy->error ) + return; + + /* Set the correct number of axes for the linux driver */ +# ifdef JS_NEW + /* Melchior Franz's fixes for big-endian Linuxes since writing + * to the upper byte of an uninitialized word doesn't work. + * 9 April 2003 + */ + ioctl( joy->fd, JSIOCGAXES, &u ); + joy->num_axes = u; + ioctl( joy->fd, JSIOCGBUTTONS, &u ); + joy->num_buttons = u; + ioctl( joy->fd, JSIOCGNAME( sizeof( joy->name ) ), joy->name ); + fcntl( joy->fd, F_SETFL, O_NONBLOCK ); +# endif + + /* + * The Linux driver seems to return 512 for all axes + * when no stick is present - but there is a chance + * that could happen by accident - so it's gotta happen + * on both axes for at least 100 attempts. + * + * PWO: shouldn't be that done somehow wiser on the kernel level? + */ +# ifndef JS_NEW + counter = 0; + + do + { + fghJoystickRawRead( joy, NULL, joy->center ); + counter++; + } while( !joy->error && + counter < 100 && + joy->center[ 0 ] == 512.0f && + joy->center[ 1 ] == 512.0f ); + + if ( counter >= 100 ) + joy->error = GL_TRUE; +# endif + + for( i = 0; i < _JS_MAX_AXES; i++ ) + { +# ifdef JS_NEW + joy->max [ i ] = 32767.0f; + joy->center[ i ] = 0.0f; + joy->min [ i ] = -32767.0f; +# else + joy->max[ i ] = joy->center[ i ] * 2.0f; + joy->min[ i ] = 0.0f; +# endif + joy->dead_band[ i ] = 0.0f; + joy->saturate [ i ] = 1.0f; + } +#endif +#endif +} + +/* + * This function replaces the constructor method in the JS library. + */ +static void fghJoystickInit( int ident ) +{ + if( ident >= MAX_NUM_JOYSTICKS ) + fgError( "Too large a joystick number: %d", ident ); + + if( fgJoystick[ ident ] ) + fgError( "illegal attempt to initialize joystick device again" ); + + fgJoystick[ ident ] = + ( SFG_Joystick * )calloc( sizeof( SFG_Joystick ), 1 ); + + /* Set defaults */ + fgJoystick[ ident ]->num_axes = fgJoystick[ ident ]->num_buttons = 0; + fgJoystick[ ident ]->error = GL_TRUE; + +#if TARGET_HOST_MACINTOSH + fgJoystick[ ident ]->id = ident; + snprintf( fgJoystick[ ident ]->fname, sizeof(fgJoystick[ ident ]->fname), "/dev/js%d", ident ); /* FIXME */ + fgJoystick[ ident ]->error = GL_FALSE; +#endif + +#if TARGET_HOST_MAC_OSX + fgJoystick[ ident ]->id = ident; + fgJoystick[ ident ]->error = GL_FALSE; + fgJoystick[ ident ]->num_axes = 0; + fgJoystick[ ident ]->num_buttons = 0; + + if( numDevices < 0 ) + { + /* do first-time init (since we can't over-ride jsInit, hmm */ + numDevices = 0; + + mach_port_t masterPort; + IOReturn rv = IOMasterPort( bootstrap_port, &masterPort ); + if( rv != kIOReturnSuccess ) + { + fgWarning( "error getting master Mach port" ); + return; + } + fghJoystickFindDevices( masterPort ); + } + + if ( ident >= numDevices ) + { + fgJoystick[ ident ]->error = GL_TRUE; + return; + } + + /* get the name now too */ + CFDictionaryRef properties = getCFProperties( ioDevices[ ident ] ); + CFTypeRef ref = CFDictionaryGetValue( properties, + CFSTR( kIOHIDProductKey ) ); + if (!ref) + ref = CFDictionaryGetValue(properties, CFSTR( "USB Product Name" ) ); + + if( !ref || + !CFStringGetCString( ( CFStringRef )ref, name, 128, + CFStringGetSystemEncoding( ) ) ) + { + fgWarning( "error getting device name" ); + name[ 0 ] = '\0'; + } +#endif + +#if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) + switch( ident ) + { + case 0: + fgJoystick[ ident ]->js_id = JOYSTICKID1; + fgJoystick[ ident ]->error = GL_FALSE; + break; + case 1: + fgJoystick[ ident ]->js_id = JOYSTICKID2; + fgJoystick[ ident ]->error = GL_FALSE; + break; + default: + fgJoystick[ ident ]->num_axes = 0; + fgJoystick[ ident ]->error = GL_TRUE; + return; + } +#endif + +#if TARGET_HOST_POSIX_X11 +# if defined( __FreeBSD__ ) || defined( __NetBSD__ ) + fgJoystick[ ident ]->id = ident; + fgJoystick[ ident ]->error = GL_FALSE; + + fgJoystick[ ident ]->os = calloc( 1, sizeof( struct os_specific_s ) ); + memset( fgJoystick[ ident ]->os, 0, sizeof( struct os_specific_s ) ); + if( ident < USB_IDENT_OFFSET ) + fgJoystick[ ident ]->os->is_analog = 1; + if( fgJoystick[ ident ]->os->is_analog ) + snprintf( fgJoystick[ ident ]->os->fname, sizeof(fgJoystick[ ident ]->os->fname), "%s%d", AJSDEV, ident ); + else + snprintf( fgJoystick[ ident ]->os->fname, sizeof(fgJoystick[ ident ]->os->fname), "%s%d", UHIDDEV, + ident - USB_IDENT_OFFSET ); +# elif defined( __linux__ ) + fgJoystick[ ident ]->id = ident; + fgJoystick[ ident ]->error = GL_FALSE; + + snprintf( fgJoystick[ident]->fname, sizeof(fgJoystick[ident]->fname), "/dev/input/js%d", ident ); + + if( access( fgJoystick[ ident ]->fname, F_OK ) != 0 ) + snprintf( fgJoystick[ ident ]->fname, sizeof(fgJoystick[ ident ]->fname), "/dev/js%d", ident ); +# endif +#endif + + fghJoystickOpen( fgJoystick[ ident ] ); +} + +/* + * Try initializing all the joysticks (well, both of them) + */ +void fgInitialiseJoysticks ( void ) +{ + if( !fgState.JoysticksInitialised ) + { + int ident ; + for ( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ ) + fghJoystickInit( ident ); + + fgState.JoysticksInitialised = GL_TRUE; + } +} + +/* + * + */ +void fgJoystickClose( void ) +{ + int ident ; + for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ ) + { + if( fgJoystick[ ident ] ) + { + +#if TARGET_HOST_MACINTOSH + ISpSuspend( ); + ISpStop( ); + ISpShutdown( ); +#endif + +#if TARGET_HOST_MAC_OSX + ( *( fgJoystick[ ident ]->hidDev ) )-> + close( fgJoystick[ ident ]->hidDev ); +#endif + +#if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) + /* Do nothing special */ +#endif + +#if TARGET_HOST_POSIX_X11 +#if defined( __FreeBSD__ ) || defined( __NetBSD__ ) + if( fgJoystick[ident]->os ) + { + if( ! fgJoystick[ ident ]->error ) + close( fgJoystick[ ident ]->os->fd ); +#ifdef HAVE_USB_JS + if( fgJoystick[ ident ]->os->hids ) + free (fgJoystick[ ident ]->os->hids); + if( fgJoystick[ ident ]->os->hid_data_buf ) + free( fgJoystick[ ident ]->os->hid_data_buf ); +#endif + free( fgJoystick[ident]->os ); + } +#endif + + if( ! fgJoystick[ident]->error ) + close( fgJoystick[ ident ]->fd ); +#endif + + free( fgJoystick[ ident ] ); + fgJoystick[ ident ] = NULL; + /* show joystick has been deinitialized */ + } + } +} + +/* + * Polls the joystick and executes the joystick callback hooked to the + * window specified in the function's parameter: + */ +void fgJoystickPollWindow( SFG_Window* window ) +{ + float axes[ _JS_MAX_AXES ]; + int buttons; + int ident; + + freeglut_return_if_fail( window ); + freeglut_return_if_fail( FETCH_WCB( *window, Joystick ) ); + + for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ ) + { + if( fgJoystick[ident] ) + { + fghJoystickRead( fgJoystick[ident], &buttons, axes ); + + if( !fgJoystick[ident]->error ) + INVOKE_WCB( *window, Joystick, + ( buttons, + (int) ( axes[ 0 ] * 1000.0f ), + (int) ( axes[ 1 ] * 1000.0f ), + (int) ( axes[ 2 ] * 1000.0f ) ) + ); + } + } +} + +/* + * Implementation for glutDeviceGet(GLUT_HAS_JOYSTICK) + */ +int fgJoystickDetect( void ) +{ + int ident; + + fgInitialiseJoysticks (); + + if ( !fgState.JoysticksInitialised ) + return 0; + + for( ident=0; ident<MAX_NUM_JOYSTICKS; ident++ ) + if( fgJoystick[ident] && !fgJoystick[ident]->error ) + return 1; + + return 0; +} + +/* + * Joystick information functions + */ +int glutJoystickGetNumAxes( int ident ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetNumAxes" ); + return fgJoystick[ ident ]->num_axes; +} +int glutJoystickGetNumButtons( int ident ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetNumButtons" ); + return fgJoystick[ ident ]->num_buttons; +} +int glutJoystickNotWorking( int ident ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickNotWorking" ); + return fgJoystick[ ident ]->error; +} + +float glutJoystickGetDeadBand( int ident, int axis ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetDeadBand" ); + return fgJoystick[ ident ]->dead_band [ axis ]; +} +void glutJoystickSetDeadBand( int ident, int axis, float db ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetDeadBand" ); + fgJoystick[ ident ]->dead_band[ axis ] = db; +} + +float glutJoystickGetSaturation( int ident, int axis ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetSaturation" ); + return fgJoystick[ ident ]->saturate[ axis ]; +} +void glutJoystickSetSaturation( int ident, int axis, float st ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetSaturation" ); + fgJoystick[ ident ]->saturate [ axis ] = st; +} + +void glutJoystickSetMinRange( int ident, float *axes ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetMinRange" ); + memcpy( fgJoystick[ ident ]->min, axes, + fgJoystick[ ident ]->num_axes * sizeof( float ) ); +} +void glutJoystickSetMaxRange( int ident, float *axes ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetMaxRange" ); + memcpy( fgJoystick[ ident ]->max, axes, + fgJoystick[ ident ]->num_axes * sizeof( float ) ); +} +void glutJoystickSetCenter( int ident, float *axes ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetCenter" ); + memcpy( fgJoystick[ ident ]->center, axes, + fgJoystick[ ident ]->num_axes * sizeof( float ) ); +} + +void glutJoystickGetMinRange( int ident, float *axes ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetMinRange" ); + memcpy( axes, fgJoystick[ ident ]->min, + fgJoystick[ ident ]->num_axes * sizeof( float ) ); +} +void glutJoystickGetMaxRange( int ident, float *axes ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetMaxRange" ); + memcpy( axes, fgJoystick[ ident ]->max, + fgJoystick[ ident ]->num_axes * sizeof( float ) ); +} +void glutJoystickGetCenter( int ident, float *axes ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetCenter" ); + memcpy( axes, fgJoystick[ ident ]->center, + fgJoystick[ ident ]->num_axes * sizeof( float ) ); +} + +/*** END OF FILE ***/ diff --git a/tests/box2d/freeglut/freeglut_main.c b/tests/box2d/freeglut/freeglut_main.c new file mode 100755 index 00000000..47043a03 --- /dev/null +++ b/tests/box2d/freeglut/freeglut_main.c @@ -0,0 +1,2296 @@ +/* + * freeglut_main.c + * + * The windows message processing methods. + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, <olszta@sourceforge.net> + * Creation date: Fri Dec 3 1999 + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "freeglut.h" +#include "freeglut_internal.h" +#if HAVE_ERRNO +# include <errno.h> +#endif +#include <stdarg.h> +#if HAVE_VPRINTF +# define VFPRINTF(s,f,a) vfprintf((s),(f),(a)) +#elif HAVE_DOPRNT +# define VFPRINTF(s,f,a) _doprnt((f),(a),(s)) +#else +# define VFPRINTF(s,f,a) +#endif + +#ifdef _WIN32_WCE + +typedef struct GXDisplayProperties GXDisplayProperties; +typedef struct GXKeyList GXKeyList; +#include <gx.h> + +typedef struct GXKeyList (*GXGETDEFAULTKEYS)(int); +typedef int (*GXOPENINPUT)(); + +GXGETDEFAULTKEYS GXGetDefaultKeys_ = NULL; +GXOPENINPUT GXOpenInput_ = NULL; + +struct GXKeyList gxKeyList; + +#endif /* _WIN32_WCE */ + +/* + * Try to get the maximum value allowed for ints, falling back to the minimum + * guaranteed by ISO C99 if there is no suitable header. + */ +#if HAVE_LIMITS_H +# include <limits.h> +#endif +#ifndef INT_MAX +# define INT_MAX 32767 +#endif + +#ifndef MIN +# define MIN(a,b) (((a)<(b)) ? (a) : (b)) +#endif + + +/* + * TODO BEFORE THE STABLE RELEASE: + * + * There are some issues concerning window redrawing under X11, and maybe + * some events are not handled. The Win32 version lacks some more features, + * but seems acceptable for not demanding purposes. + * + * Need to investigate why the X11 version breaks out with an error when + * closing a window (using the window manager, not glutDestroyWindow)... + */ + +/* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ + +/* + * Handle a window configuration change. When no reshape + * callback is hooked, the viewport size is updated to + * match the new window size. + */ +static void fghReshapeWindow ( SFG_Window *window, int width, int height ) +{ + SFG_Window *current_window = fgStructure.CurrentWindow; + + freeglut_return_if_fail( window != NULL ); + + +#if TARGET_HOST_POSIX_X11 + + XResizeWindow( fgDisplay.Display, window->Window.Handle, + width, height ); + XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ + +#elif TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) + { + RECT winRect; + int x, y, w, h; + + /* + * For windowed mode, get the current position of the + * window and resize taking the size of the frame + * decorations into account. + */ + + /* "GetWindowRect" returns the pixel coordinates of the outside of the window */ + GetWindowRect( window->Window.Handle, &winRect ); + x = winRect.left; + y = winRect.top; + w = width; + h = height; + + if ( window->Parent == NULL ) + { + if ( ! window->IsMenu && (window != fgStructure.GameModeWindow) ) + { + w += GetSystemMetrics( SM_CXSIZEFRAME ) * 2; + h += GetSystemMetrics( SM_CYSIZEFRAME ) * 2 + + GetSystemMetrics( SM_CYCAPTION ); + } + } + else + { + RECT parentRect; + GetWindowRect( window->Parent->Window.Handle, &parentRect ); + x -= parentRect.left + GetSystemMetrics( SM_CXSIZEFRAME ) * 2; + y -= parentRect.top + GetSystemMetrics( SM_CYSIZEFRAME ) * 2 + + GetSystemMetrics( SM_CYCAPTION ); + } + + /* + * SWP_NOACTIVATE Do not activate the window + * SWP_NOOWNERZORDER Do not change position in z-order + * SWP_NOSENDCHANGING Supress WM_WINDOWPOSCHANGING message + * SWP_NOZORDER Retains the current Z order (ignore 2nd param) + */ + + SetWindowPos( window->Window.Handle, + HWND_TOP, + x, y, w, h, + SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | + SWP_NOZORDER + ); + } +#endif + + /* + * XXX Should update {window->State.OldWidth, window->State.OldHeight} + * XXX to keep in lockstep with POSIX_X11 code. + */ + if( FETCH_WCB( *window, Reshape ) ) + INVOKE_WCB( *window, Reshape, ( width, height ) ); + else + { + fgSetWindow( window ); + glViewport( 0, 0, width, height ); + } + + /* + * Force a window redraw. In Windows at least this is only a partial + * solution: if the window is increasing in size in either dimension, + * the already-drawn part does not get drawn again and things look funny. + * But without this we get this bad behaviour whenever we resize the + * window. + */ + window->State.Redisplay = GL_TRUE; + + if( window->IsMenu ) + fgSetWindow( current_window ); +} + +/* + * Calls a window's redraw method. This is used when + * a redraw is forced by the incoming window messages. + */ +static void fghRedrawWindow ( SFG_Window *window ) +{ + SFG_Window *current_window = fgStructure.CurrentWindow; + + freeglut_return_if_fail( window ); + freeglut_return_if_fail( FETCH_WCB ( *window, Display ) ); + + window->State.Redisplay = GL_FALSE; + + freeglut_return_if_fail( window->State.Visible ); + + fgSetWindow( window ); + + if( window->State.NeedToResize ) + { + fghReshapeWindow( + window, + window->State.Width, + window->State.Height + ); + + window->State.NeedToResize = GL_FALSE; + } + + INVOKE_WCB( *window, Display, ( ) ); + + fgSetWindow( current_window ); +} + +/* + * A static helper function to execute display callback for a window + */ +static void fghcbDisplayWindow( SFG_Window *window, + SFG_Enumerator *enumerator ) +{ + if( window->State.Redisplay && + window->State.Visible ) + { + window->State.Redisplay = GL_FALSE; + +#if TARGET_HOST_POSIX_X11 + fghRedrawWindow ( window ) ; +#elif TARGET_HOST_MS_WINDOWS + RedrawWindow( + window->Window.Handle, NULL, NULL, + RDW_NOERASE | RDW_INTERNALPAINT | RDW_INVALIDATE | RDW_UPDATENOW + ); +#endif + } + + fgEnumSubWindows( window, fghcbDisplayWindow, enumerator ); +} + +/* + * Make all windows perform a display call + */ +static void fghDisplayAll( void ) +{ + SFG_Enumerator enumerator; + + enumerator.found = GL_FALSE; + enumerator.data = NULL; + + fgEnumWindows( fghcbDisplayWindow, &enumerator ); +} + +/* + * Window enumerator callback to check for the joystick polling code + */ +static void fghcbCheckJoystickPolls( SFG_Window *window, + SFG_Enumerator *enumerator ) +{ + long int checkTime = fgElapsedTime( ); + + if( window->State.JoystickLastPoll + window->State.JoystickPollRate <= + checkTime ) + { +#if !defined(_WIN32_WCE) + fgJoystickPollWindow( window ); +#endif /* !defined(_WIN32_WCE) */ + window->State.JoystickLastPoll = checkTime; + } + + fgEnumSubWindows( window, fghcbCheckJoystickPolls, enumerator ); +} + +/* + * Check all windows for joystick polling + */ +static void fghCheckJoystickPolls( void ) +{ + SFG_Enumerator enumerator; + + enumerator.found = GL_FALSE; + enumerator.data = NULL; + + fgEnumWindows( fghcbCheckJoystickPolls, &enumerator ); +} + +/* + * Check the global timers + */ +static void fghCheckTimers( void ) +{ + long checkTime = fgElapsedTime( ); + + while( fgState.Timers.First ) + { + SFG_Timer *timer = fgState.Timers.First; + + if( timer->TriggerTime > checkTime ) + break; + + fgListRemove( &fgState.Timers, &timer->Node ); + fgListAppend( &fgState.FreeTimers, &timer->Node ); + + timer->Callback( timer->ID ); + } +} + + +/* Platform-dependent time in milliseconds, as an unsigned 32-bit integer. + * This value wraps every 49.7 days, but integer overflows cancel + * when subtracting an initial start time, unless the total time exceeds + * 32-bit, where the GLUT API return value is also overflowed. + */ +unsigned long fgSystemTime(void) { +#if TARGET_HOST_SOLARIS || HAVE_GETTIMEOFDAY + struct timeval now; + gettimeofday( &now, NULL ); + return now.tv_usec/1000 + now.tv_sec*1000; +#elif TARGET_HOST_MS_WINDOWS +# if defined(_WIN32_WCE) + return GetTickCount(); +# else + return timeGetTime(); +# endif +#endif +} + +/* + * Elapsed Time + */ +long fgElapsedTime( void ) +{ + return (long) (fgSystemTime() - fgState.Time); +} + +/* + * Error Messages. + */ +void fgError( const char *fmt, ... ) +{ + va_list ap; + + va_start( ap, fmt ); + + fprintf( stderr, "freeglut "); + if( fgState.ProgramName ) + fprintf( stderr, "(%s): ", fgState.ProgramName ); + VFPRINTF( stderr, fmt, ap ); + fprintf( stderr, "\n" ); + + va_end( ap ); + + if ( fgState.Initialised ) + fgDeinitialize (); + + exit( 1 ); +} + +void fgWarning( const char *fmt, ... ) +{ + va_list ap; + + va_start( ap, fmt ); + + fprintf( stderr, "freeglut "); + if( fgState.ProgramName ) + fprintf( stderr, "(%s): ", fgState.ProgramName ); + VFPRINTF( stderr, fmt, ap ); + fprintf( stderr, "\n" ); + + va_end( ap ); +} + +/* + * Indicates whether Joystick events are being used by ANY window. + * + * The current mechanism is to walk all of the windows and ask if + * there is a joystick callback. We have a short-circuit early + * return if we find any joystick handler registered. + * + * The real way to do this is to make use of the glutTimer() API + * to more cleanly re-implement the joystick API. Then, this code + * and all other "joystick timer" code can be yanked. + * + */ +static void fghCheckJoystickCallback( SFG_Window* w, SFG_Enumerator* e) +{ + if( FETCH_WCB( *w, Joystick ) ) + { + e->found = GL_TRUE; + e->data = w; + } + fgEnumSubWindows( w, fghCheckJoystickCallback, e ); +} +static int fghHaveJoystick( void ) +{ + SFG_Enumerator enumerator; + + enumerator.found = GL_FALSE; + enumerator.data = NULL; + fgEnumWindows( fghCheckJoystickCallback, &enumerator ); + return !!enumerator.data; +} +static void fghHavePendingRedisplaysCallback( SFG_Window* w, SFG_Enumerator* e) +{ + if( w->State.Redisplay && w->State.Visible ) + { + e->found = GL_TRUE; + e->data = w; + } + fgEnumSubWindows( w, fghHavePendingRedisplaysCallback, e ); +} +static int fghHavePendingRedisplays (void) +{ + SFG_Enumerator enumerator; + + enumerator.found = GL_FALSE; + enumerator.data = NULL; + fgEnumWindows( fghHavePendingRedisplaysCallback, &enumerator ); + return !!enumerator.data; +} +/* + * Returns the number of GLUT ticks (milliseconds) till the next timer event. + */ +static long fghNextTimer( void ) +{ + long ret = INT_MAX; + SFG_Timer *timer = fgState.Timers.First; + + if( timer ) + ret = timer->TriggerTime - fgElapsedTime(); + if( ret < 0 ) + ret = 0; + + return ret; +} +/* + * Does the magic required to relinquish the CPU until something interesting + * happens. + */ +static void fghSleepForEvents( void ) +{ + long msec; + + if( fgState.IdleCallback || fghHavePendingRedisplays( ) ) + return; + + msec = fghNextTimer( ); + /* XXX Use GLUT timers for joysticks... */ + /* XXX Dumb; forces granularity to .01sec */ + if( fghHaveJoystick( ) && ( msec > 10 ) ) + msec = 10; + +#if TARGET_HOST_POSIX_X11 + /* + * Possibly due to aggressive use of XFlush() and friends, + * it is possible to have our socket drained but still have + * unprocessed events. (Or, this may just be normal with + * X, anyway?) We do non-trivial processing of X events + * after the event-reading loop, in any case, so we + * need to allow that we may have an empty socket but non- + * empty event queue. + */ + if( ! XPending( fgDisplay.Display ) ) + { + fd_set fdset; + int err; + int socket; + struct timeval wait; + + socket = ConnectionNumber( fgDisplay.Display ); + FD_ZERO( &fdset ); + FD_SET( socket, &fdset ); + wait.tv_sec = msec / 1000; + wait.tv_usec = (msec % 1000) * 1000; + err = select( socket+1, &fdset, NULL, NULL, &wait ); + +#if HAVE_ERRNO + if( ( -1 == err ) && ( errno != EINTR ) ) + fgWarning ( "freeglut select() error: %d", errno ); +#endif + } +#elif TARGET_HOST_MS_WINDOWS + MsgWaitForMultipleObjects( 0, NULL, FALSE, msec, QS_ALLINPUT ); +#endif +} + +#if TARGET_HOST_POSIX_X11 +/* + * Returns GLUT modifier mask for the state field of an X11 event. + */ +static int fghGetXModifiers( int state ) +{ + int ret = 0; + + if( state & ( ShiftMask | LockMask ) ) + ret |= GLUT_ACTIVE_SHIFT; + if( state & ControlMask ) + ret |= GLUT_ACTIVE_CTRL; + if( state & Mod1Mask ) + ret |= GLUT_ACTIVE_ALT; + + return ret; +} +#endif + + +#if TARGET_HOST_POSIX_X11 && _DEBUG + +static const char* fghTypeToString( int type ) +{ + switch( type ) { + case KeyPress: return "KeyPress"; + case KeyRelease: return "KeyRelease"; + case ButtonPress: return "ButtonPress"; + case ButtonRelease: return "ButtonRelease"; + case MotionNotify: return "MotionNotify"; + case EnterNotify: return "EnterNotify"; + case LeaveNotify: return "LeaveNotify"; + case FocusIn: return "FocusIn"; + case FocusOut: return "FocusOut"; + case KeymapNotify: return "KeymapNotify"; + case Expose: return "Expose"; + case GraphicsExpose: return "GraphicsExpose"; + case NoExpose: return "NoExpose"; + case VisibilityNotify: return "VisibilityNotify"; + case CreateNotify: return "CreateNotify"; + case DestroyNotify: return "DestroyNotify"; + case UnmapNotify: return "UnmapNotify"; + case MapNotify: return "MapNotify"; + case MapRequest: return "MapRequest"; + case ReparentNotify: return "ReparentNotify"; + case ConfigureNotify: return "ConfigureNotify"; + case ConfigureRequest: return "ConfigureRequest"; + case GravityNotify: return "GravityNotify"; + case ResizeRequest: return "ResizeRequest"; + case CirculateNotify: return "CirculateNotify"; + case CirculateRequest: return "CirculateRequest"; + case PropertyNotify: return "PropertyNotify"; + case SelectionClear: return "SelectionClear"; + case SelectionRequest: return "SelectionRequest"; + case SelectionNotify: return "SelectionNotify"; + case ColormapNotify: return "ColormapNotify"; + case ClientMessage: return "ClientMessage"; + case MappingNotify: return "MappingNotify"; + default: return "UNKNOWN"; + } +} + +static const char* fghBoolToString( Bool b ) +{ + return b == False ? "False" : "True"; +} + +static const char* fghNotifyHintToString( char is_hint ) +{ + switch( is_hint ) { + case NotifyNormal: return "NotifyNormal"; + case NotifyHint: return "NotifyHint"; + default: return "UNKNOWN"; + } +} + +static const char* fghNotifyModeToString( int mode ) +{ + switch( mode ) { + case NotifyNormal: return "NotifyNormal"; + case NotifyGrab: return "NotifyGrab"; + case NotifyUngrab: return "NotifyUngrab"; + case NotifyWhileGrabbed: return "NotifyWhileGrabbed"; + default: return "UNKNOWN"; + } +} + +static const char* fghNotifyDetailToString( int detail ) +{ + switch( detail ) { + case NotifyAncestor: return "NotifyAncestor"; + case NotifyVirtual: return "NotifyVirtual"; + case NotifyInferior: return "NotifyInferior"; + case NotifyNonlinear: return "NotifyNonlinear"; + case NotifyNonlinearVirtual: return "NotifyNonlinearVirtual"; + case NotifyPointer: return "NotifyPointer"; + case NotifyPointerRoot: return "NotifyPointerRoot"; + case NotifyDetailNone: return "NotifyDetailNone"; + default: return "UNKNOWN"; + } +} + +static const char* fghVisibilityToString( int state ) { + switch( state ) { + case VisibilityUnobscured: return "VisibilityUnobscured"; + case VisibilityPartiallyObscured: return "VisibilityPartiallyObscured"; + case VisibilityFullyObscured: return "VisibilityFullyObscured"; + default: return "UNKNOWN"; + } +} + +static const char* fghConfigureDetailToString( int detail ) +{ + switch( detail ) { + case Above: return "Above"; + case Below: return "Below"; + case TopIf: return "TopIf"; + case BottomIf: return "BottomIf"; + case Opposite: return "Opposite"; + default: return "UNKNOWN"; + } +} + +static const char* fghPlaceToString( int place ) +{ + switch( place ) { + case PlaceOnTop: return "PlaceOnTop"; + case PlaceOnBottom: return "PlaceOnBottom"; + default: return "UNKNOWN"; + } +} + +static const char* fghMappingRequestToString( int request ) +{ + switch( request ) { + case MappingModifier: return "MappingModifier"; + case MappingKeyboard: return "MappingKeyboard"; + case MappingPointer: return "MappingPointer"; + default: return "UNKNOWN"; + } +} + +static const char* fghPropertyStateToString( int state ) +{ + switch( state ) { + case PropertyNewValue: return "PropertyNewValue"; + case PropertyDelete: return "PropertyDelete"; + default: return "UNKNOWN"; + } +} + +static const char* fghColormapStateToString( int state ) +{ + switch( state ) { + case ColormapUninstalled: return "ColormapUninstalled"; + case ColormapInstalled: return "ColormapInstalled"; + default: return "UNKNOWN"; + } +} + +static void fghPrintEvent( XEvent *event ) +{ + switch( event->type ) { + + case KeyPress: + case KeyRelease: { + XKeyEvent *e = &event->xkey; + fgWarning( "%s: window=0x%x, root=0x%x, subwindow=0x%x, time=%lu, " + "(x,y)=(%d,%d), (x_root,y_root)=(%d,%d), state=0x%x, " + "keycode=%u, same_screen=%s", fghTypeToString( e->type ), + e->window, e->root, e->subwindow, (unsigned long)e->time, + e->x, e->y, e->x_root, e->y_root, e->state, e->keycode, + fghBoolToString( e->same_screen ) ); + break; + } + + case ButtonPress: + case ButtonRelease: { + XButtonEvent *e = &event->xbutton; + fgWarning( "%s: window=0x%x, root=0x%x, subwindow=0x%x, time=%lu, " + "(x,y)=(%d,%d), (x_root,y_root)=(%d,%d), state=0x%x, " + "button=%u, same_screen=%d", fghTypeToString( e->type ), + e->window, e->root, e->subwindow, (unsigned long)e->time, + e->x, e->y, e->x_root, e->y_root, e->state, e->button, + fghBoolToString( e->same_screen ) ); + break; + } + + case MotionNotify: { + XMotionEvent *e = &event->xmotion; + fgWarning( "%s: window=0x%x, root=0x%x, subwindow=0x%x, time=%lu, " + "(x,y)=(%d,%d), (x_root,y_root)=(%d,%d), state=0x%x, " + "is_hint=%s, same_screen=%d", fghTypeToString( e->type ), + e->window, e->root, e->subwindow, (unsigned long)e->time, + e->x, e->y, e->x_root, e->y_root, e->state, + fghNotifyHintToString( e->is_hint ), + fghBoolToString( e->same_screen ) ); + break; + } + + case EnterNotify: + case LeaveNotify: { + XCrossingEvent *e = &event->xcrossing; + fgWarning( "%s: window=0x%x, root=0x%x, subwindow=0x%x, time=%lu, " + "(x,y)=(%d,%d), mode=%s, detail=%s, same_screen=%d, " + "focus=%d, state=0x%x", fghTypeToString( e->type ), + e->window, e->root, e->subwindow, (unsigned long)e->time, + e->x, e->y, fghNotifyModeToString( e->mode ), + fghNotifyDetailToString( e->detail ), (int)e->same_screen, + (int)e->focus, e->state ); + break; + } + + case FocusIn: + case FocusOut: { + XFocusChangeEvent *e = &event->xfocus; + fgWarning( "%s: window=0x%x, mode=%s, detail=%s", + fghTypeToString( e->type ), e->window, + fghNotifyModeToString( e->mode ), + fghNotifyDetailToString( e->detail ) ); + break; + } + + case KeymapNotify: { + XKeymapEvent *e = &event->xkeymap; + char buf[32 * 2 + 1]; + int i; + for ( i = 0; i < 32; i++ ) { + snprintf( &buf[ i * 2 ], sizeof( buf ) - i * 2, + "%02x", e->key_vector[ i ] ); + } + buf[ i ] = '\0'; + fgWarning( "%s: window=0x%x, %s", fghTypeToString( e->type ), e->window, + buf ); + break; + } + + case Expose: { + XExposeEvent *e = &event->xexpose; + fgWarning( "%s: window=0x%x, (x,y)=(%d,%d), (width,height)=(%d,%d), " + "count=%d", fghTypeToString( e->type ), e->window, e->x, + e->y, e->width, e->height, e->count ); + break; + } + + case GraphicsExpose: { + XGraphicsExposeEvent *e = &event->xgraphicsexpose; + fgWarning( "%s: drawable=0x%x, (x,y)=(%d,%d), (width,height)=(%d,%d), " + "count=%d, (major_code,minor_code)=(%d,%d)", + fghTypeToString( e->type ), e->drawable, e->x, e->y, + e->width, e->height, e->count, e->major_code, + e->minor_code ); + break; + } + + case NoExpose: { + XNoExposeEvent *e = &event->xnoexpose; + fgWarning( "%s: drawable=0x%x, (major_code,minor_code)=(%d,%d)", + fghTypeToString( e->type ), e->drawable, e->major_code, + e->minor_code ); + break; + } + + case VisibilityNotify: { + XVisibilityEvent *e = &event->xvisibility; + fgWarning( "%s: window=0x%x, state=%s", fghTypeToString( e->type ), + e->window, fghVisibilityToString( e->state) ); + break; + } + + case CreateNotify: { + XCreateWindowEvent *e = &event->xcreatewindow; + fgWarning( "%s: (x,y)=(%d,%d), (width,height)=(%d,%d), border_width=%d, " + "window=0x%x, override_redirect=%s", + fghTypeToString( e->type ), e->x, e->y, e->width, e->height, + e->border_width, e->window, + fghBoolToString( e->override_redirect ) ); + break; + } + + case DestroyNotify: { + XDestroyWindowEvent *e = &event->xdestroywindow; + fgWarning( "%s: event=0x%x, window=0x%x", + fghTypeToString( e->type ), e->event, e->window ); + break; + } + + case UnmapNotify: { + XUnmapEvent *e = &event->xunmap; + fgWarning( "%s: event=0x%x, window=0x%x, from_configure=%s", + fghTypeToString( e->type ), e->event, e->window, + fghBoolToString( e->from_configure ) ); + break; + } + + case MapNotify: { + XMapEvent *e = &event->xmap; + fgWarning( "%s: event=0x%x, window=0x%x, override_redirect=%s", + fghTypeToString( e->type ), e->event, e->window, + fghBoolToString( e->override_redirect ) ); + break; + } + + case MapRequest: { + XMapRequestEvent *e = &event->xmaprequest; + fgWarning( "%s: parent=0x%x, window=0x%x", + fghTypeToString( event->type ), e->parent, e->window ); + break; + } + + case ReparentNotify: { + XReparentEvent *e = &event->xreparent; + fgWarning( "%s: event=0x%x, window=0x%x, parent=0x%x, (x,y)=(%d,%d), " + "override_redirect=%s", fghTypeToString( e->type ), + e->event, e->window, e->parent, e->x, e->y, + fghBoolToString( e->override_redirect ) ); + break; + } + + case ConfigureNotify: { + XConfigureEvent *e = &event->xconfigure; + fgWarning( "%s: event=0x%x, window=0x%x, (x,y)=(%d,%d), " + "(width,height)=(%d,%d), border_width=%d, above=0x%x, " + "override_redirect=%s", fghTypeToString( e->type ), e->event, + e->window, e->x, e->y, e->width, e->height, e->border_width, + e->above, fghBoolToString( e->override_redirect ) ); + break; + } + + case ConfigureRequest: { + XConfigureRequestEvent *e = &event->xconfigurerequest; + fgWarning( "%s: parent=0x%x, window=0x%x, (x,y)=(%d,%d), " + "(width,height)=(%d,%d), border_width=%d, above=0x%x, " + "detail=%s, value_mask=%lx", fghTypeToString( e->type ), + e->parent, e->window, e->x, e->y, e->width, e->height, + e->border_width, e->above, + fghConfigureDetailToString( e->detail ), e->value_mask ); + break; + } + + case GravityNotify: { + XGravityEvent *e = &event->xgravity; + fgWarning( "%s: event=0x%x, window=0x%x, (x,y)=(%d,%d)", + fghTypeToString( e->type ), e->event, e->window, e->x, e->y ); + break; + } + + case ResizeRequest: { + XResizeRequestEvent *e = &event->xresizerequest; + fgWarning( "%s: window=0x%x, (width,height)=(%d,%d)", + fghTypeToString( e->type ), e->window, e->width, e->height ); + break; + } + + case CirculateNotify: { + XCirculateEvent *e = &event->xcirculate; + fgWarning( "%s: event=0x%x, window=0x%x, place=%s", + fghTypeToString( e->type ), e->event, e->window, + fghPlaceToString( e->place ) ); + break; + } + + case CirculateRequest: { + XCirculateRequestEvent *e = &event->xcirculaterequest; + fgWarning( "%s: parent=0x%x, window=0x%x, place=%s", + fghTypeToString( e->type ), e->parent, e->window, + fghPlaceToString( e->place ) ); + break; + } + + case PropertyNotify: { + XPropertyEvent *e = &event->xproperty; + fgWarning( "%s: window=0x%x, atom=%lu, time=%lu, state=%s", + fghTypeToString( e->type ), e->window, + (unsigned long)e->atom, (unsigned long)e->time, + fghPropertyStateToString( e->state ) ); + break; + } + + case SelectionClear: { + XSelectionClearEvent *e = &event->xselectionclear; + fgWarning( "%s: window=0x%x, selection=%lu, time=%lu", + fghTypeToString( e->type ), e->window, + (unsigned long)e->selection, (unsigned long)e->time ); + break; + } + + case SelectionRequest: { + XSelectionRequestEvent *e = &event->xselectionrequest; + fgWarning( "%s: owner=0x%x, requestor=0x%x, selection=0x%x, " + "target=0x%x, property=%lu, time=%lu", + fghTypeToString( e->type ), e->owner, e->requestor, + (unsigned long)e->selection, (unsigned long)e->target, + (unsigned long)e->property, (unsigned long)e->time ); + break; + } + + case SelectionNotify: { + XSelectionEvent *e = &event->xselection; + fgWarning( "%s: requestor=0x%x, selection=0x%x, target=0x%x, " + "property=%lu, time=%lu", fghTypeToString( e->type ), + e->requestor, (unsigned long)e->selection, + (unsigned long)e->target, (unsigned long)e->property, + (unsigned long)e->time ); + break; + } + + case ColormapNotify: { + XColormapEvent *e = &event->xcolormap; + fgWarning( "%s: window=0x%x, colormap=%lu, new=%s, state=%s", + fghTypeToString( e->type ), e->window, + (unsigned long)e->colormap, fghBoolToString( e->new ), + fghColormapStateToString( e->state ) ); + break; + } + + case ClientMessage: { + XClientMessageEvent *e = &event->xclient; + char buf[ 61 ]; + char* p = buf; + char* end = buf + sizeof( buf ); + int i; + switch( e->format ) { + case 8: + for ( i = 0; i < 20; i++, p += 3 ) { + snprintf( p, end - p, " %02x", e->data.b[ i ] ); + } + break; + case 16: + for ( i = 0; i < 10; i++, p += 5 ) { + snprintf( p, end - p, " %04x", e->data.s[ i ] ); + } + break; + case 32: + for ( i = 0; i < 5; i++, p += 9 ) { + snprintf( p, end - p, " %08lx", e->data.l[ i ] ); + } + break; + } + *p = '\0'; + fgWarning( "%s: window=0x%x, message_type=%lu, format=%d, data=(%s )", + fghTypeToString( e->type ), e->window, + (unsigned long)e->message_type, e->format, buf ); + break; + } + + case MappingNotify: { + XMappingEvent *e = &event->xmapping; + fgWarning( "%s: window=0x%x, request=%s, first_keycode=%d, count=%d", + fghTypeToString( e->type ), e->window, + fghMappingRequestToString( e->request ), e->first_keycode, + e->count ); + break; + } + + default: { + fgWarning( "%s", fghTypeToString( event->type ) ); + break; + } + } +} + +#endif + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +/* + * Executes a single iteration in the freeglut processing loop. + */ +void FGAPIENTRY glutMainLoopEvent( void ) +{ +#if TARGET_HOST_POSIX_X11 + SFG_Window* window; + XEvent event; + + /* This code was repeated constantly, so here it goes into a definition: */ +#define GETWINDOW(a) \ + window = fgWindowByHandle( event.a.window ); \ + if( window == NULL ) \ + break; + +#define GETMOUSE(a) \ + window->State.MouseX = event.a.x; \ + window->State.MouseY = event.a.y; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoopEvent" ); + + while( XPending( fgDisplay.Display ) ) + { + XNextEvent( fgDisplay.Display, &event ); +#if _DEBUG + fghPrintEvent( &event ); +#endif + + switch( event.type ) + { + case ClientMessage: + if(fgIsSpaceballXEvent(&event)) { + fgSpaceballHandleXEvent(&event); + break; + } + /* Destroy the window when the WM_DELETE_WINDOW message arrives */ + if( (Atom) event.xclient.data.l[ 0 ] == fgDisplay.DeleteWindow ) + { + GETWINDOW( xclient ); + + fgDestroyWindow ( window ); + + if( fgState.ActionOnWindowClose == GLUT_ACTION_EXIT ) + { + fgDeinitialize( ); + exit( 0 ); + } + else if( fgState.ActionOnWindowClose == GLUT_ACTION_GLUTMAINLOOP_RETURNS ) + fgState.ExecState = GLUT_EXEC_STATE_STOP; + + return; + } + break; + + /* + * CreateNotify causes a configure-event so that sub-windows are + * handled compatibly with GLUT. Otherwise, your sub-windows + * (in freeglut only) will not get an initial reshape event, + * which can break things. + * + * GLUT presumably does this because it generally tries to treat + * sub-windows the same as windows. + */ + case CreateNotify: + case ConfigureNotify: + { + int width, height; + if( event.type == CreateNotify ) { + GETWINDOW( xcreatewindow ); + width = event.xcreatewindow.width; + height = event.xcreatewindow.height; + } else { + GETWINDOW( xconfigure ); + width = event.xconfigure.width; + height = event.xconfigure.height; + } + + if( ( width != window->State.OldWidth ) || + ( height != window->State.OldHeight ) ) + { + SFG_Window *current_window = fgStructure.CurrentWindow; + + window->State.OldWidth = width; + window->State.OldHeight = height; + if( FETCH_WCB( *window, Reshape ) ) + INVOKE_WCB( *window, Reshape, ( width, height ) ); + else + { + fgSetWindow( window ); + glViewport( 0, 0, width, height ); + } + glutPostRedisplay( ); + if( window->IsMenu ) + fgSetWindow( current_window ); + } + } + break; + + case DestroyNotify: + /* + * This is sent to confirm the XDestroyWindow call. + * + * XXX WHY is this commented out? Should we re-enable it? + */ + /* fgAddToWindowDestroyList ( window ); */ + break; + + case Expose: + /* + * We are too dumb to process partial exposes... + * + * XXX Well, we could do it. However, it seems to only + * XXX be potentially useful for single-buffered (since + * XXX double-buffered does not respect viewport when we + * XXX do a buffer-swap). + * + */ + if( event.xexpose.count == 0 ) + { + GETWINDOW( xexpose ); + window->State.Redisplay = GL_TRUE; + } + break; + + case MapNotify: + break; + + case UnmapNotify: + /* We get this when iconifying a window. */ + GETWINDOW( xunmap ); + INVOKE_WCB( *window, WindowStatus, ( GLUT_HIDDEN ) ); + window->State.Visible = GL_FALSE; + break; + + case MappingNotify: + /* + * Have the client's keyboard knowledge updated (xlib.ps, + * page 206, says that's a good thing to do) + */ + XRefreshKeyboardMapping( (XMappingEvent *) &event ); + break; + + case VisibilityNotify: + { + /* + * Sending this event, the X server can notify us that the window + * has just acquired one of the three possible visibility states: + * VisibilityUnobscured, VisibilityPartiallyObscured or + * VisibilityFullyObscured. Note that we DO NOT receive a + * VisibilityNotify event when iconifying a window, we only get an + * UnmapNotify then. + */ + GETWINDOW( xvisibility ); + switch( event.xvisibility.state ) + { + case VisibilityUnobscured: + INVOKE_WCB( *window, WindowStatus, ( GLUT_FULLY_RETAINED ) ); + window->State.Visible = GL_TRUE; + break; + + case VisibilityPartiallyObscured: + INVOKE_WCB( *window, WindowStatus, + ( GLUT_PARTIALLY_RETAINED ) ); + window->State.Visible = GL_TRUE; + break; + + case VisibilityFullyObscured: + INVOKE_WCB( *window, WindowStatus, ( GLUT_FULLY_COVERED ) ); + window->State.Visible = GL_FALSE; + break; + + default: + fgWarning( "Unknown X visibility state: %d", + event.xvisibility.state ); + break; + } + } + break; + + case EnterNotify: + case LeaveNotify: + GETWINDOW( xcrossing ); + GETMOUSE( xcrossing ); + if( ( event.type == LeaveNotify ) && window->IsMenu && + window->ActiveMenu && window->ActiveMenu->IsActive ) + fgUpdateMenuHighlight( window->ActiveMenu ); + + INVOKE_WCB( *window, Entry, ( ( EnterNotify == event.type ) ? + GLUT_ENTERED : + GLUT_LEFT ) ); + break; + + case MotionNotify: + { + GETWINDOW( xmotion ); + GETMOUSE( xmotion ); + + if( window->ActiveMenu ) + { + if( window == window->ActiveMenu->ParentWindow ) + { + window->ActiveMenu->Window->State.MouseX = + event.xmotion.x_root - window->ActiveMenu->X; + window->ActiveMenu->Window->State.MouseY = + event.xmotion.y_root - window->ActiveMenu->Y; + } + + fgUpdateMenuHighlight( window->ActiveMenu ); + + break; + } + + /* + * XXX For more than 5 buttons, just check {event.xmotion.state}, + * XXX rather than a host of bit-masks? Or maybe we need to + * XXX track ButtonPress/ButtonRelease events in our own + * XXX bit-mask? + */ + fgState.Modifiers = fghGetXModifiers( event.xmotion.state ); + if ( event.xmotion.state & ( Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask ) ) { + INVOKE_WCB( *window, Motion, ( event.xmotion.x, + event.xmotion.y ) ); + } else { + INVOKE_WCB( *window, Passive, ( event.xmotion.x, + event.xmotion.y ) ); + } + fgState.Modifiers = INVALID_MODIFIERS; + } + break; + + case ButtonRelease: + case ButtonPress: + { + GLboolean pressed = GL_TRUE; + int button; + + if( event.type == ButtonRelease ) + pressed = GL_FALSE ; + + /* + * A mouse button has been pressed or released. Traditionally, + * break if the window was found within the freeglut structures. + */ + GETWINDOW( xbutton ); + GETMOUSE( xbutton ); + + /* + * An X button (at least in XFree86) is numbered from 1. + * A GLUT button is numbered from 0. + * Old GLUT passed through buttons other than just the first + * three, though it only gave symbolic names and official + * support to the first three. + */ + button = event.xbutton.button - 1; + + /* + * Do not execute the application's mouse callback if a menu + * is hooked to this button. In that case an appropriate + * private call should be generated. + */ + if( fgCheckActiveMenu( window, button, pressed, + event.xbutton.x_root, event.xbutton.y_root ) ) + break; + + /* + * Check if there is a mouse or mouse wheel callback hooked to the + * window + */ + if( ! FETCH_WCB( *window, Mouse ) && + ! FETCH_WCB( *window, MouseWheel ) ) + break; + + fgState.Modifiers = fghGetXModifiers( event.xbutton.state ); + + /* Finally execute the mouse or mouse wheel callback */ + if( ( button < glutDeviceGet ( GLUT_NUM_MOUSE_BUTTONS ) ) || ( ! FETCH_WCB( *window, MouseWheel ) ) ) + INVOKE_WCB( *window, Mouse, ( button, + pressed ? GLUT_DOWN : GLUT_UP, + event.xbutton.x, + event.xbutton.y ) + ); + else + { + /* + * Map 4 and 5 to wheel zero; EVEN to +1, ODD to -1 + * " 6 and 7 " " one; ... + * + * XXX This *should* be behind some variables/macros, + * XXX since the order and numbering isn't certain + * XXX See XFree86 configuration docs (even back in the + * XXX 3.x days, and especially with 4.x). + * + * XXX Note that {button} has already been decremeted + * XXX in mapping from X button numbering to GLUT. + */ + int wheel_number = (button - glutDeviceGet ( GLUT_NUM_MOUSE_BUTTONS )) / 2; + int direction = -1; + if( button % 2 ) + direction = 1; + + if( pressed ) + INVOKE_WCB( *window, MouseWheel, ( wheel_number, + direction, + event.xbutton.x, + event.xbutton.y ) + ); + } + fgState.Modifiers = INVALID_MODIFIERS; + } + break; + + case KeyRelease: + case KeyPress: + { + FGCBKeyboard keyboard_cb; + FGCBSpecial special_cb; + + GETWINDOW( xkey ); + GETMOUSE( xkey ); + + /* Detect auto repeated keys, if configured globally or per-window */ + + if ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) + { + if (event.type==KeyRelease) + { + /* + * Look at X11 keystate to detect repeat mode. + * While X11 says the key is actually held down, we'll ignore KeyRelease/KeyPress pairs. + */ + + char keys[32]; + XQueryKeymap( fgDisplay.Display, keys ); /* Look at X11 keystate to detect repeat mode */ + + if ( event.xkey.keycode<256 ) /* XQueryKeymap is limited to 256 keycodes */ + { + if ( keys[event.xkey.keycode>>3] & (1<<(event.xkey.keycode%8)) ) + window->State.KeyRepeating = GL_TRUE; + else + window->State.KeyRepeating = GL_FALSE; + } + } + } + else + window->State.KeyRepeating = GL_FALSE; + + /* Cease processing this event if it is auto repeated */ + + if (window->State.KeyRepeating) + { + if (event.type == KeyPress) window->State.KeyRepeating = GL_FALSE; + break; + } + + if( event.type == KeyPress ) + { + keyboard_cb = (FGCBKeyboard)( FETCH_WCB( *window, Keyboard )); + special_cb = (FGCBSpecial) ( FETCH_WCB( *window, Special )); + } + else + { + keyboard_cb = (FGCBKeyboard)( FETCH_WCB( *window, KeyboardUp )); + special_cb = (FGCBSpecial) ( FETCH_WCB( *window, SpecialUp )); + } + + /* Is there a keyboard/special callback hooked for this window? */ + if( keyboard_cb || special_cb ) + { + XComposeStatus composeStatus; + char asciiCode[ 32 ]; + KeySym keySym; + int len; + + /* Check for the ASCII/KeySym codes associated with the event: */ + len = XLookupString( &event.xkey, asciiCode, sizeof(asciiCode), + &keySym, &composeStatus + ); + + /* GLUT API tells us to have two separate callbacks... */ + if( len > 0 ) + { + /* ...one for the ASCII translateable keypresses... */ + if( keyboard_cb ) + { + fgSetWindow( window ); + fgState.Modifiers = fghGetXModifiers( event.xkey.state ); + keyboard_cb( asciiCode[ 0 ], + event.xkey.x, event.xkey.y + ); + fgState.Modifiers = INVALID_MODIFIERS; + } + } + else + { + int special = -1; + + /* + * ...and one for all the others, which need to be + * translated to GLUT_KEY_Xs... + */ + switch( keySym ) + { + case XK_F1: special = GLUT_KEY_F1; break; + case XK_F2: special = GLUT_KEY_F2; break; + case XK_F3: special = GLUT_KEY_F3; break; + case XK_F4: special = GLUT_KEY_F4; break; + case XK_F5: special = GLUT_KEY_F5; break; + case XK_F6: special = GLUT_KEY_F6; break; + case XK_F7: special = GLUT_KEY_F7; break; + case XK_F8: special = GLUT_KEY_F8; break; + case XK_F9: special = GLUT_KEY_F9; break; + case XK_F10: special = GLUT_KEY_F10; break; + case XK_F11: special = GLUT_KEY_F11; break; + case XK_F12: special = GLUT_KEY_F12; break; + + case XK_KP_Left: + case XK_Left: special = GLUT_KEY_LEFT; break; + case XK_KP_Right: + case XK_Right: special = GLUT_KEY_RIGHT; break; + case XK_KP_Up: + case XK_Up: special = GLUT_KEY_UP; break; + case XK_KP_Down: + case XK_Down: special = GLUT_KEY_DOWN; break; + + case XK_KP_Prior: + case XK_Prior: special = GLUT_KEY_PAGE_UP; break; + case XK_KP_Next: + case XK_Next: special = GLUT_KEY_PAGE_DOWN; break; + case XK_KP_Home: + case XK_Home: special = GLUT_KEY_HOME; break; + case XK_KP_End: + case XK_End: special = GLUT_KEY_END; break; + case XK_KP_Insert: + case XK_Insert: special = GLUT_KEY_INSERT; break; + + case XK_Num_Lock : special = GLUT_KEY_NUM_LOCK; break; + case XK_KP_Begin : special = GLUT_KEY_BEGIN; break; + case XK_KP_Delete: special = GLUT_KEY_DELETE; break; + } + + /* + * Execute the callback (if one has been specified), + * given that the special code seems to be valid... + */ + if( special_cb && (special != -1) ) + { + fgSetWindow( window ); + fgState.Modifiers = fghGetXModifiers( event.xkey.state ); + special_cb( special, event.xkey.x, event.xkey.y ); + fgState.Modifiers = INVALID_MODIFIERS; + } + } + } + } + break; + + case ReparentNotify: + break; /* XXX Should disable this event */ + + /* Not handled */ + case GravityNotify: + break; + + default: + fgWarning ("Unknown X event type: %d\n", event.type); + break; + } + } + +#elif TARGET_HOST_MS_WINDOWS + + MSG stMsg; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoopEvent" ); + + while( PeekMessage( &stMsg, NULL, 0, 0, PM_NOREMOVE ) ) + { + if( GetMessage( &stMsg, NULL, 0, 0 ) == 0 ) + { + if( fgState.ActionOnWindowClose == GLUT_ACTION_EXIT ) + { + fgDeinitialize( ); + exit( 0 ); + } + else if( fgState.ActionOnWindowClose == GLUT_ACTION_GLUTMAINLOOP_RETURNS ) + fgState.ExecState = GLUT_EXEC_STATE_STOP; + + return; + } + + TranslateMessage( &stMsg ); + DispatchMessage( &stMsg ); + } +#endif + + if( fgState.Timers.First ) + fghCheckTimers( ); + fghCheckJoystickPolls( ); + fghDisplayAll( ); + + fgCloseWindows( ); +} + +/* + * Enters the freeglut processing loop. + * Stays until the "ExecState" changes to "GLUT_EXEC_STATE_STOP". + */ +void FGAPIENTRY glutMainLoop( void ) +{ + int action; + +#if TARGET_HOST_MS_WINDOWS + SFG_Window *window = (SFG_Window *)fgStructure.Windows.First ; +#endif + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoop" ); + +#if TARGET_HOST_MS_WINDOWS + /* + * Processing before the main loop: If there is a window which is open and + * which has a visibility callback, call it. I know this is an ugly hack, + * but I'm not sure what else to do about it. Ideally we should leave + * something uninitialized in the create window code and initialize it in + * the main loop, and have that initialization create a "WM_ACTIVATE" + * message. Then we would put the visibility callback code in the + * "case WM_ACTIVATE" block below. - John Fay -- 10/24/02 + */ + while( window ) + { + if ( FETCH_WCB( *window, Visibility ) ) + { + SFG_Window *current_window = fgStructure.CurrentWindow ; + + INVOKE_WCB( *window, Visibility, ( window->State.Visible ) ); + fgSetWindow( current_window ); + } + + window = (SFG_Window *)window->Node.Next ; + } +#endif + + fgState.ExecState = GLUT_EXEC_STATE_RUNNING ; + while( fgState.ExecState == GLUT_EXEC_STATE_RUNNING ) + { + SFG_Window *window; + + glutMainLoopEvent( ); + /* + * Step through the list of windows, seeing if there are any + * that are not menus + */ + for( window = ( SFG_Window * )fgStructure.Windows.First; + window; + window = ( SFG_Window * )window->Node.Next ) + if ( ! ( window->IsMenu ) ) + break; + + if( ! window ) + fgState.ExecState = GLUT_EXEC_STATE_STOP; + else + { + if( fgState.IdleCallback ) + { + if( fgStructure.CurrentWindow && + fgStructure.CurrentWindow->IsMenu ) + /* fail safe */ + fgSetWindow( window ); + fgState.IdleCallback( ); + } + + fghSleepForEvents( ); + } + } + + /* + * When this loop terminates, destroy the display, state and structure + * of a freeglut session, so that another glutInit() call can happen + * + * Save the "ActionOnWindowClose" because "fgDeinitialize" resets it. + */ + action = fgState.ActionOnWindowClose; + fgDeinitialize( ); + if( action == GLUT_ACTION_EXIT ) + exit( 0 ); +} + +/* + * Leaves the freeglut processing loop. + */ +void FGAPIENTRY glutLeaveMainLoop( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutLeaveMainLoop" ); + fgState.ExecState = GLUT_EXEC_STATE_STOP ; +} + + +#if TARGET_HOST_MS_WINDOWS +/* + * Determine a GLUT modifer mask based on MS-WINDOWS system info. + */ +static int fghGetWin32Modifiers (void) +{ + return + ( ( ( GetKeyState( VK_LSHIFT ) < 0 ) || + ( GetKeyState( VK_RSHIFT ) < 0 )) ? GLUT_ACTIVE_SHIFT : 0 ) | + ( ( ( GetKeyState( VK_LCONTROL ) < 0 ) || + ( GetKeyState( VK_RCONTROL ) < 0 )) ? GLUT_ACTIVE_CTRL : 0 ) | + ( ( ( GetKeyState( VK_LMENU ) < 0 ) || + ( GetKeyState( VK_RMENU ) < 0 )) ? GLUT_ACTIVE_ALT : 0 ); +} + +/* + * The window procedure for handling Win32 events + */ +LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, + LPARAM lParam ) +{ + SFG_Window* window; + PAINTSTRUCT ps; + LRESULT lRet = 1; + + FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Event Handler" ) ; + + window = fgWindowByHandle( hWnd ); + + if ( ( window == NULL ) && ( uMsg != WM_CREATE ) ) + return DefWindowProc( hWnd, uMsg, wParam, lParam ); + + /* printf ( "Window %3d message <%04x> %12d %12d\n", window?window->ID:0, + uMsg, wParam, lParam ); */ + switch( uMsg ) + { + case WM_CREATE: + /* The window structure is passed as the creation structure paramter... */ + window = (SFG_Window *) (((LPCREATESTRUCT) lParam)->lpCreateParams); + FREEGLUT_INTERNAL_ERROR_EXIT ( ( window != NULL ), "Cannot create window", + "fgWindowProc" ); + + window->Window.Handle = hWnd; + window->Window.Device = GetDC( hWnd ); + if( window->IsMenu ) + { + unsigned int current_DisplayMode = fgState.DisplayMode; + fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH; +#if !defined(_WIN32_WCE) + fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE ); +#endif + fgState.DisplayMode = current_DisplayMode; + + if( fgStructure.MenuContext ) + wglMakeCurrent( window->Window.Device, + fgStructure.MenuContext->MContext + ); + else + { + fgStructure.MenuContext = + (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) ); + fgStructure.MenuContext->MContext = + wglCreateContext( window->Window.Device ); + } + + /* window->Window.Context = wglGetCurrentContext (); */ + window->Window.Context = wglCreateContext( window->Window.Device ); + } + else + { +#if !defined(_WIN32_WCE) + fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE ); +#endif + + if( ! fgState.UseCurrentContext ) + window->Window.Context = + wglCreateContext( window->Window.Device ); + else + { + window->Window.Context = wglGetCurrentContext( ); + if( ! window->Window.Context ) + window->Window.Context = + wglCreateContext( window->Window.Device ); + } + +#if !defined(_WIN32_WCE) + fgNewWGLCreateContext( window ); +#endif + } + + window->State.NeedToResize = GL_TRUE; + if( ( window->State.Width < 0 ) || ( window->State.Height < 0 ) ) + { + SFG_Window *current_window = fgStructure.CurrentWindow; + + fgSetWindow( window ); + window->State.Width = glutGet( GLUT_WINDOW_WIDTH ); + window->State.Height = glutGet( GLUT_WINDOW_HEIGHT ); + fgSetWindow( current_window ); + } + + ReleaseDC( window->Window.Handle, window->Window.Device ); + +#if defined(_WIN32_WCE) + /* Take over button handling */ + { + HINSTANCE dxDllLib=LoadLibrary(_T("gx.dll")); + if (dxDllLib) + { + GXGetDefaultKeys_=(GXGETDEFAULTKEYS)GetProcAddress(dxDllLib, _T("?GXGetDefaultKeys@@YA?AUGXKeyList@@H@Z")); + GXOpenInput_=(GXOPENINPUT)GetProcAddress(dxDllLib, _T("?GXOpenInput@@YAHXZ")); + } + + if(GXOpenInput_) + (*GXOpenInput_)(); + if(GXGetDefaultKeys_) + gxKeyList = (*GXGetDefaultKeys_)(GX_LANDSCAPEKEYS); + } + +#endif /* defined(_WIN32_WCE) */ + break; + + case WM_SIZE: + /* + * If the window is visible, then it is the user manually resizing it. + * If it is not, then it is the system sending us a dummy resize with + * zero dimensions on a "glutIconifyWindow" call. + */ + if( window->State.Visible ) + { + window->State.NeedToResize = GL_TRUE; +#if defined(_WIN32_WCE) + window->State.Width = HIWORD(lParam); + window->State.Height = LOWORD(lParam); +#else + window->State.Width = LOWORD(lParam); + window->State.Height = HIWORD(lParam); +#endif /* defined(_WIN32_WCE) */ + } + + break; + + case WM_SETFOCUS: +/* printf("WM_SETFOCUS: %p\n", window ); */ + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) ); + break; + + case WM_KILLFOCUS: +/* printf("WM_KILLFOCUS: %p\n", window ); */ + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) ); + + if( window->IsMenu && + window->ActiveMenu && window->ActiveMenu->IsActive ) + fgUpdateMenuHighlight( window->ActiveMenu ); + + break; + +#if 0 + case WM_ACTIVATE: + if (LOWORD(wParam) != WA_INACTIVE) + { +/* printf("WM_ACTIVATE: fgSetCursor( %p, %d)\n", window, + window->State.Cursor ); */ + fgSetCursor( window, window->State.Cursor ); + } + + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + break; +#endif + + case WM_SETCURSOR: +/* printf ( "Cursor event %x %x %x %x\n", window, window->State.Cursor, lParam, wParam ) ; */ + if( LOWORD( lParam ) == HTCLIENT ) + fgSetCursor ( window, window->State.Cursor ) ; + else + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + break; + + case WM_SHOWWINDOW: + window->State.Visible = GL_TRUE; + window->State.Redisplay = GL_TRUE; + break; + + case WM_PAINT: + /* Turn on the visibility in case it was turned off somehow */ + window->State.Visible = GL_TRUE; + BeginPaint( hWnd, &ps ); + fghRedrawWindow( window ); + EndPaint( hWnd, &ps ); + break; + + case WM_CLOSE: + fgDestroyWindow ( window ); + if ( fgState.ActionOnWindowClose != GLUT_ACTION_CONTINUE_EXECUTION ) + PostQuitMessage(0); + break; + + case WM_DESTROY: + /* + * The window already got destroyed, so don't bother with it. + */ + return 0; + + case WM_MOUSEMOVE: + { +#if defined(_WIN32_WCE) + window->State.MouseX = 320-HIWORD( lParam ); + window->State.MouseY = LOWORD( lParam ); +#else + window->State.MouseX = LOWORD( lParam ); + window->State.MouseY = HIWORD( lParam ); +#endif /* defined(_WIN32_WCE) */ + /* Restrict to [-32768, 32767] to match X11 behaviour */ + /* See comment in "freeglut_developer" mailing list 10/4/04 */ + if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536; + if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536; + + if ( window->ActiveMenu ) + { + fgUpdateMenuHighlight( window->ActiveMenu ); + break; + } + + fgState.Modifiers = fghGetWin32Modifiers( ); + + if( ( wParam & MK_LBUTTON ) || + ( wParam & MK_MBUTTON ) || + ( wParam & MK_RBUTTON ) ) + INVOKE_WCB( *window, Motion, ( window->State.MouseX, + window->State.MouseY ) ); + else + INVOKE_WCB( *window, Passive, ( window->State.MouseX, + window->State.MouseY ) ); + + fgState.Modifiers = INVALID_MODIFIERS; + } + break; + + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + { + GLboolean pressed = GL_TRUE; + int button; + +#if defined(_WIN32_WCE) + window->State.MouseX = 320-HIWORD( lParam ); + window->State.MouseY = LOWORD( lParam ); +#else + window->State.MouseX = LOWORD( lParam ); + window->State.MouseY = HIWORD( lParam ); +#endif /* defined(_WIN32_WCE) */ + + /* Restrict to [-32768, 32767] to match X11 behaviour */ + /* See comment in "freeglut_developer" mailing list 10/4/04 */ + if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536; + if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536; + + switch( uMsg ) + { + case WM_LBUTTONDOWN: + pressed = GL_TRUE; + button = GLUT_LEFT_BUTTON; + break; + case WM_MBUTTONDOWN: + pressed = GL_TRUE; + button = GLUT_MIDDLE_BUTTON; + break; + case WM_RBUTTONDOWN: + pressed = GL_TRUE; + button = GLUT_RIGHT_BUTTON; + break; + case WM_LBUTTONUP: + pressed = GL_FALSE; + button = GLUT_LEFT_BUTTON; + break; + case WM_MBUTTONUP: + pressed = GL_FALSE; + button = GLUT_MIDDLE_BUTTON; + break; + case WM_RBUTTONUP: + pressed = GL_FALSE; + button = GLUT_RIGHT_BUTTON; + break; + default: + pressed = GL_FALSE; + button = -1; + break; + } + +#if !defined(_WIN32_WCE) + if( GetSystemMetrics( SM_SWAPBUTTON ) ) + { + if( button == GLUT_LEFT_BUTTON ) + button = GLUT_RIGHT_BUTTON; + else + if( button == GLUT_RIGHT_BUTTON ) + button = GLUT_LEFT_BUTTON; + } +#endif /* !defined(_WIN32_WCE) */ + + if( button == -1 ) + return DefWindowProc( hWnd, uMsg, lParam, wParam ); + + /* + * Do not execute the application's mouse callback if a menu + * is hooked to this button. In that case an appropriate + * private call should be generated. + */ + if( fgCheckActiveMenu( window, button, pressed, + window->State.MouseX, window->State.MouseY ) ) + break; + + /* Set capture so that the window captures all the mouse messages */ + /* + * XXX - Multiple button support: Under X11, the mouse is not released + * XXX - from the window until all buttons have been released, even if the + * XXX - user presses a button in another window. This will take more + * XXX - code changes than I am up to at the moment (10/5/04). The present + * XXX - is a 90 percent solution. + */ + if ( pressed == GL_TRUE ) + SetCapture ( window->Window.Handle ) ; + else + ReleaseCapture () ; + + if( ! FETCH_WCB( *window, Mouse ) ) + break; + + fgSetWindow( window ); + fgState.Modifiers = fghGetWin32Modifiers( ); + + INVOKE_WCB( + *window, Mouse, + ( button, + pressed ? GLUT_DOWN : GLUT_UP, + window->State.MouseX, + window->State.MouseY + ) + ); + + fgState.Modifiers = INVALID_MODIFIERS; + } + break; + + case 0x020a: + /* Should be WM_MOUSEWHEEL but my compiler doesn't recognize it */ + { + /* + * XXX THIS IS SPECULATIVE -- John Fay, 10/2/03 + * XXX Should use WHEEL_DELTA instead of 120 + */ + int wheel_number = LOWORD( wParam ); + short ticks = ( short )HIWORD( wParam ) / 120; + int direction = 1; + + if( ticks < 0 ) + { + direction = -1; + ticks = -ticks; + } + + /* + * The mouse cursor has moved. Remember the new mouse cursor's position + */ + /* window->State.MouseX = LOWORD( lParam ); */ + /* Need to adjust by window position, */ + /* window->State.MouseY = HIWORD( lParam ); */ + /* change "lParam" to other parameter */ + + if( ! FETCH_WCB( *window, MouseWheel ) && + ! FETCH_WCB( *window, Mouse ) ) + break; + + fgSetWindow( window ); + fgState.Modifiers = fghGetWin32Modifiers( ); + + while( ticks-- ) + if( FETCH_WCB( *window, MouseWheel ) ) + INVOKE_WCB( *window, MouseWheel, + ( wheel_number, + direction, + window->State.MouseX, + window->State.MouseY + ) + ); + else /* No mouse wheel, call the mouse button callback twice */ + { + /* + * Map wheel zero to button 3 and 4; +1 to 3, -1 to 4 + * " " one +1 to 5, -1 to 6, ... + * + * XXX The below assumes that you have no more than 3 mouse + * XXX buttons. Sorry. + */ + int button = wheel_number * 2 + 3; + if( direction < 0 ) + ++button; + INVOKE_WCB( *window, Mouse, + ( button, GLUT_DOWN, + window->State.MouseX, window->State.MouseY ) + ); + INVOKE_WCB( *window, Mouse, + ( button, GLUT_UP, + window->State.MouseX, window->State.MouseY ) + ); + } + + fgState.Modifiers = INVALID_MODIFIERS; + } + break ; + + case WM_SYSKEYDOWN: + case WM_KEYDOWN: + { + int keypress = -1; + POINT mouse_pos ; + + if( ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) && (HIWORD(lParam) & KF_REPEAT) ) + break; + + /* + * Remember the current modifiers state. This is done here in order + * to make sure the VK_DELETE keyboard callback is executed properly. + */ + fgState.Modifiers = fghGetWin32Modifiers( ); + + GetCursorPos( &mouse_pos ); + ScreenToClient( window->Window.Handle, &mouse_pos ); + + window->State.MouseX = mouse_pos.x; + window->State.MouseY = mouse_pos.y; + + /* Convert the Win32 keystroke codes to GLUTtish way */ +# define KEY(a,b) case a: keypress = b; break; + + switch( wParam ) + { + KEY( VK_F1, GLUT_KEY_F1 ); + KEY( VK_F2, GLUT_KEY_F2 ); + KEY( VK_F3, GLUT_KEY_F3 ); + KEY( VK_F4, GLUT_KEY_F4 ); + KEY( VK_F5, GLUT_KEY_F5 ); + KEY( VK_F6, GLUT_KEY_F6 ); + KEY( VK_F7, GLUT_KEY_F7 ); + KEY( VK_F8, GLUT_KEY_F8 ); + KEY( VK_F9, GLUT_KEY_F9 ); + KEY( VK_F10, GLUT_KEY_F10 ); + KEY( VK_F11, GLUT_KEY_F11 ); + KEY( VK_F12, GLUT_KEY_F12 ); + KEY( VK_PRIOR, GLUT_KEY_PAGE_UP ); + KEY( VK_NEXT, GLUT_KEY_PAGE_DOWN ); + KEY( VK_HOME, GLUT_KEY_HOME ); + KEY( VK_END, GLUT_KEY_END ); + KEY( VK_LEFT, GLUT_KEY_LEFT ); + KEY( VK_UP, GLUT_KEY_UP ); + KEY( VK_RIGHT, GLUT_KEY_RIGHT ); + KEY( VK_DOWN, GLUT_KEY_DOWN ); + KEY( VK_INSERT, GLUT_KEY_INSERT ); + + case VK_DELETE: + /* The delete key should be treated as an ASCII keypress: */ + INVOKE_WCB( *window, Keyboard, + ( 127, window->State.MouseX, window->State.MouseY ) + ); + } + +#if defined(_WIN32_WCE) + if(!(lParam & 0x40000000)) /* Prevent auto-repeat */ + { + if(wParam==(unsigned)gxKeyList.vkRight) + keypress = GLUT_KEY_RIGHT; + else if(wParam==(unsigned)gxKeyList.vkLeft) + keypress = GLUT_KEY_LEFT; + else if(wParam==(unsigned)gxKeyList.vkUp) + keypress = GLUT_KEY_UP; + else if(wParam==(unsigned)gxKeyList.vkDown) + keypress = GLUT_KEY_DOWN; + else if(wParam==(unsigned)gxKeyList.vkA) + keypress = GLUT_KEY_F1; + else if(wParam==(unsigned)gxKeyList.vkB) + keypress = GLUT_KEY_F2; + else if(wParam==(unsigned)gxKeyList.vkC) + keypress = GLUT_KEY_F3; + else if(wParam==(unsigned)gxKeyList.vkStart) + keypress = GLUT_KEY_F4; + } +#endif + + if( keypress != -1 ) + INVOKE_WCB( *window, Special, + ( keypress, + window->State.MouseX, window->State.MouseY ) + ); + + fgState.Modifiers = INVALID_MODIFIERS; + } + break; + + case WM_SYSKEYUP: + case WM_KEYUP: + { + int keypress = -1; + POINT mouse_pos; + + /* + * Remember the current modifiers state. This is done here in order + * to make sure the VK_DELETE keyboard callback is executed properly. + */ + fgState.Modifiers = fghGetWin32Modifiers( ); + + GetCursorPos( &mouse_pos ); + ScreenToClient( window->Window.Handle, &mouse_pos ); + + window->State.MouseX = mouse_pos.x; + window->State.MouseY = mouse_pos.y; + + /* + * Convert the Win32 keystroke codes to GLUTtish way. + * "KEY(a,b)" was defined under "WM_KEYDOWN" + */ + + switch( wParam ) + { + KEY( VK_F1, GLUT_KEY_F1 ); + KEY( VK_F2, GLUT_KEY_F2 ); + KEY( VK_F3, GLUT_KEY_F3 ); + KEY( VK_F4, GLUT_KEY_F4 ); + KEY( VK_F5, GLUT_KEY_F5 ); + KEY( VK_F6, GLUT_KEY_F6 ); + KEY( VK_F7, GLUT_KEY_F7 ); + KEY( VK_F8, GLUT_KEY_F8 ); + KEY( VK_F9, GLUT_KEY_F9 ); + KEY( VK_F10, GLUT_KEY_F10 ); + KEY( VK_F11, GLUT_KEY_F11 ); + KEY( VK_F12, GLUT_KEY_F12 ); + KEY( VK_PRIOR, GLUT_KEY_PAGE_UP ); + KEY( VK_NEXT, GLUT_KEY_PAGE_DOWN ); + KEY( VK_HOME, GLUT_KEY_HOME ); + KEY( VK_END, GLUT_KEY_END ); + KEY( VK_LEFT, GLUT_KEY_LEFT ); + KEY( VK_UP, GLUT_KEY_UP ); + KEY( VK_RIGHT, GLUT_KEY_RIGHT ); + KEY( VK_DOWN, GLUT_KEY_DOWN ); + KEY( VK_INSERT, GLUT_KEY_INSERT ); + + case VK_DELETE: + /* The delete key should be treated as an ASCII keypress: */ + INVOKE_WCB( *window, KeyboardUp, + ( 127, window->State.MouseX, window->State.MouseY ) + ); + break; + + default: + { +#if !defined(_WIN32_WCE) + BYTE state[ 256 ]; + WORD code[ 2 ]; + + GetKeyboardState( state ); + + if( ToAscii( (UINT)wParam, 0, state, code, 0 ) == 1 ) + wParam=code[ 0 ]; + + INVOKE_WCB( *window, KeyboardUp, + ( (char)wParam, + window->State.MouseX, window->State.MouseY ) + ); +#endif /* !defined(_WIN32_WCE) */ + } + } + + if( keypress != -1 ) + INVOKE_WCB( *window, SpecialUp, + ( keypress, + window->State.MouseX, window->State.MouseY ) + ); + + fgState.Modifiers = INVALID_MODIFIERS; + } + break; + + case WM_SYSCHAR: + case WM_CHAR: + { + if( (fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE) && (HIWORD(lParam) & KF_REPEAT) ) + break; + + fgState.Modifiers = fghGetWin32Modifiers( ); + INVOKE_WCB( *window, Keyboard, + ( (char)wParam, + window->State.MouseX, window->State.MouseY ) + ); + fgState.Modifiers = INVALID_MODIFIERS; + } + break; + + case WM_CAPTURECHANGED: + /* User has finished resizing the window, force a redraw */ + INVOKE_WCB( *window, Display, ( ) ); + + /*lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); */ + break; + + /* Other messages that I have seen and which are not handled already */ + case WM_SETTEXT: /* 0x000c */ + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + /* Pass it on to "DefWindowProc" to set the window text */ + break; + + case WM_GETTEXT: /* 0x000d */ + /* Ideally we would copy the title of the window into "lParam" */ + /* strncpy ( (char *)lParam, "Window Title", wParam ); + lRet = ( wParam > 12 ) ? 12 : wParam; */ + /* the number of characters copied */ + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + break; + + case WM_GETTEXTLENGTH: /* 0x000e */ + /* Ideally we would get the length of the title of the window */ + lRet = 12; + /* the number of characters in "Window Title\0" (see above) */ + break; + + case WM_ERASEBKGND: /* 0x0014 */ + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + break; + +#if !defined(_WIN32_WCE) + case WM_SYNCPAINT: /* 0x0088 */ + /* Another window has moved, need to update this one */ + window->State.Redisplay = GL_TRUE; + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + /* Help screen says this message must be passed to "DefWindowProc" */ + break; + + case WM_NCPAINT: /* 0x0085 */ + /* Need to update the border of this window */ + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + /* Pass it on to "DefWindowProc" to repaint a standard border */ + break; + + case WM_SYSCOMMAND : /* 0x0112 */ + { + /* + * We have received a system command message. Try to act on it. + * The commands are passed in through the "wParam" parameter: + * The least significant digit seems to be which edge of the window + * is being used for a resize event: + * 4 3 5 + * 1 2 + * 7 6 8 + * Congratulations and thanks to Richard Rauch for figuring this out.. + */ + switch ( wParam & 0xfff0 ) + { + case SC_SIZE : + break ; + + case SC_MOVE : + break ; + + case SC_MINIMIZE : + /* User has clicked on the "-" to minimize the window */ + /* Turn off the visibility */ + window->State.Visible = GL_FALSE ; + + break ; + + case SC_MAXIMIZE : + break ; + + case SC_NEXTWINDOW : + break ; + + case SC_PREVWINDOW : + break ; + + case SC_CLOSE : + /* Followed very closely by a WM_CLOSE message */ + break ; + + case SC_VSCROLL : + break ; + + case SC_HSCROLL : + break ; + + case SC_MOUSEMENU : + break ; + + case SC_KEYMENU : + break ; + + case SC_ARRANGE : + break ; + + case SC_RESTORE : + break ; + + case SC_TASKLIST : + break ; + + case SC_SCREENSAVE : + break ; + + case SC_HOTKEY : + break ; + +#if(WINVER >= 0x0400) + case SC_DEFAULT : + break ; + + case SC_MONITORPOWER : + break ; + + case SC_CONTEXTHELP : + break ; +#endif /* WINVER >= 0x0400 */ + + default: +#if _DEBUG + fgWarning( "Unknown wParam type 0x%x", wParam ); +#endif + break; + } + } +#endif /* !defined(_WIN32_WCE) */ + + /* We need to pass the message on to the operating system as well */ + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + break; + + default: + /* Handle unhandled messages */ + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + break; + } + + return lRet; +} +#endif + +/*** END OF FILE ***/ diff --git a/tests/box2d/freeglut/freeglut_menu.c b/tests/box2d/freeglut/freeglut_menu.c new file mode 100755 index 00000000..9bdf8895 --- /dev/null +++ b/tests/box2d/freeglut/freeglut_menu.c @@ -0,0 +1,1002 @@ +/* + * freeglut_menu.c + * + * Pull-down menu creation and handling. + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, <olszta@sourceforge.net> + * Creation date: Thu Dec 16 1999 + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#define FREEGLUT_BUILDING_LIB +#include "freeglut.h" +#include "freeglut_internal.h" + +/* -- DEFINITIONS ---------------------------------------------------------- */ + +/* + * FREEGLUT_MENU_FONT can be any freeglut bitmapped font. + * (Stroked fonts would not be out of the question, but we'd need to alter + * code, since GLUT (hence freeglut) does not quite unify stroked and + * bitmapped font handling.) + * Old UNIX/X11 GLUT (BSD, UNIX, IRIX, LINUX, HPUX, ...) used a system + * font best approximated by an 18-pixel HELVETICA, I think. MS-WINDOWS + * GLUT used something closest to the 8x13 fixed-width font. (Old + * GLUT apparently uses host-system menus rather than building its own. + * freeglut is building its own menus from scratch.) + * + * FREEGLUT_MENU_HEIGHT gives the height of ONE menu box. This should be + * the distances between two adjacent menu entries. It should scale + * automatically with the font choice, so you needn't alter it---unless you + * use a stroked font. + * + * FREEGLUT_MENU_BORDER says how many pixels to allow around the edge of a + * menu. (It also seems to be the same as the number of pixels used as + * a border around *items* to separate them from neighbors. John says + * that that wasn't the original intent...if not, perhaps we need another + * symbolic constant, FREEGLUT_MENU_ITEM_BORDER, or such.) + */ +#if TARGET_HOST_MS_WINDOWS +#define FREEGLUT_MENU_FONT GLUT_BITMAP_8_BY_13 +#else +#define FREEGLUT_MENU_FONT GLUT_BITMAP_HELVETICA_18 +#endif + +#define FREEGLUT_MENU_HEIGHT (glutBitmapHeight(FREEGLUT_MENU_FONT) + \ + FREEGLUT_MENU_BORDER) +#define FREEGLUT_MENU_BORDER 2 + + +/* + * These variables are for rendering the freeglut menu items. + * + * The choices are fore- and background, with and without h for Highlighting. + * Old GLUT appeared to be system-dependant for its colors (sigh) so we are + * too. These variables should be stuffed into global state and initialized + * via the glutInit*() system. + */ +#if TARGET_HOST_MS_WINDOWS +static float menu_pen_fore [4] = {0.0f, 0.0f, 0.0f, 1.0f}; +static float menu_pen_back [4] = {0.85f, 0.85f, 0.85f, 1.0f}; +static float menu_pen_hfore [4] = {1.0f, 1.0f, 1.0f, 1.0f}; +static float menu_pen_hback [4] = {0.15f, 0.15f, 0.45f, 1.0f}; +#else +static float menu_pen_fore [4] = {0.0f, 0.0f, 0.0f, 1.0f}; +static float menu_pen_back [4] = {0.70f, 0.70f, 0.70f, 1.0f}; +static float menu_pen_hfore [4] = {0.0f, 0.0f, 0.0f, 1.0f}; +static float menu_pen_hback [4] = {1.0f, 1.0f, 1.0f, 1.0f}; +#endif + +/* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ + +/* + * Private function to find a menu entry by index + */ +static SFG_MenuEntry *fghFindMenuEntry( SFG_Menu* menu, int index ) +{ + SFG_MenuEntry *entry; + int i = 1; + + for( entry = (SFG_MenuEntry *)menu->Entries.First; + entry; + entry = (SFG_MenuEntry *)entry->Node.Next ) + { + if( i == index ) + break; + ++i; + } + + return entry; +} + +/* + * Deactivates a menu pointed by the function argument. + */ +static void fghDeactivateSubMenu( SFG_MenuEntry *menuEntry ) +{ + SFG_MenuEntry *subMenuIter; + /* Hide the present menu's window */ + fgSetWindow( menuEntry->SubMenu->Window ); + glutHideWindow( ); + + /* Forget about having that menu active anymore, now: */ + menuEntry->SubMenu->Window->ActiveMenu = NULL; + menuEntry->SubMenu->IsActive = GL_FALSE; + menuEntry->SubMenu->ActiveEntry = NULL; + + /* Hide all submenu windows, and the root menu's window. */ + for ( subMenuIter = (SFG_MenuEntry *)menuEntry->SubMenu->Entries.First; + subMenuIter; + subMenuIter = (SFG_MenuEntry *)subMenuIter->Node.Next ) + { + subMenuIter->IsActive = GL_FALSE; + + /* Is that an active submenu by any case? */ + if( subMenuIter->SubMenu ) + fghDeactivateSubMenu( subMenuIter ); + } + + fgSetWindow ( menuEntry->SubMenu->ParentWindow ) ; +} + +/* + * Private function to get the virtual maximum screen extent + */ +static GLvoid fghGetVMaxExtent( SFG_Window* window, int* x, int* y ) +{ + if( fgStructure.GameModeWindow ) + { +#if TARGET_HOST_POSIX_X11 + int wx, wy; + Window w; + + XTranslateCoordinates( + fgDisplay.Display, + window->Window.Handle, + fgDisplay.RootWindow, + 0, 0, &wx, &wy, &w); + + *x = fgState.GameModeSize.X + wx; + *y = fgState.GameModeSize.Y + wy; +#else + *x = glutGet ( GLUT_SCREEN_WIDTH ); + *y = glutGet ( GLUT_SCREEN_HEIGHT ); +#endif + } + else + { + *x = fgDisplay.ScreenWidth; + *y = fgDisplay.ScreenHeight; + } +} + +/* + * Private function to check for the current menu/sub menu activity state + */ +static GLboolean fghCheckMenuStatus( SFG_Menu* menu ) +{ + SFG_MenuEntry* menuEntry; + int x, y; + + /* First of all check any of the active sub menus... */ + for( menuEntry = (SFG_MenuEntry *)menu->Entries.First; + menuEntry; + menuEntry = (SFG_MenuEntry *)menuEntry->Node.Next ) + { + if( menuEntry->SubMenu && menuEntry->IsActive ) + { + /* + * OK, have the sub-menu checked, too. If it returns GL_TRUE, it + * will mean that it caught the mouse cursor and we do not need + * to regenerate the activity list, and so our parents do... + */ + GLboolean return_status; + + menuEntry->SubMenu->Window->State.MouseX = + menu->Window->State.MouseX + menu->X - menuEntry->SubMenu->X; + menuEntry->SubMenu->Window->State.MouseY = + menu->Window->State.MouseY + menu->Y - menuEntry->SubMenu->Y; + return_status = fghCheckMenuStatus( menuEntry->SubMenu ); + + if ( return_status ) + return GL_TRUE; + } + } + + /* That much about our sub menus, let's get to checking the current menu: */ + x = menu->Window->State.MouseX; + y = menu->Window->State.MouseY; + + /* Check if the mouse cursor is contained within the current menu box */ + if( ( x >= FREEGLUT_MENU_BORDER ) && + ( x < menu->Width - FREEGLUT_MENU_BORDER ) && + ( y >= FREEGLUT_MENU_BORDER ) && + ( y < menu->Height - FREEGLUT_MENU_BORDER ) ) + { + int menuID = ( y - FREEGLUT_MENU_BORDER ) / FREEGLUT_MENU_HEIGHT; + + /* The mouse cursor is somewhere over our box, check it out. */ + menuEntry = fghFindMenuEntry( menu, menuID + 1 ); + FREEGLUT_INTERNAL_ERROR_EXIT( menuEntry, "Cannot find menu entry", + "fghCheckMenuStatus" ); + + menuEntry->IsActive = GL_TRUE; + menuEntry->Ordinal = menuID; + + /* + * If this is not the same as the last active menu entry, deactivate + * the previous entry. Specifically, if the previous active entry + * was a submenu then deactivate it. + */ + if( menu->ActiveEntry && ( menuEntry != menu->ActiveEntry ) ) + if( menu->ActiveEntry->SubMenu ) + fghDeactivateSubMenu( menu->ActiveEntry ); + + if( menuEntry != menu->ActiveEntry ) + { + menu->Window->State.Redisplay = GL_TRUE; + if( menu->ActiveEntry ) + menu->ActiveEntry->IsActive = GL_FALSE; + } + + menu->ActiveEntry = menuEntry; + menu->IsActive = GL_TRUE; /* XXX Do we need this? */ + + /* + * OKi, we have marked that entry as active, but it would be also + * nice to have its contents updated, in case it's a sub menu. + * Also, ignore the return value of the check function: + */ + if( menuEntry->SubMenu ) + { + if ( ! menuEntry->SubMenu->IsActive ) + { + int max_x, max_y; + SFG_Window *current_window = fgStructure.CurrentWindow; + + /* Set up the initial menu position now... */ + menuEntry->SubMenu->IsActive = GL_TRUE; + + /* Set up the initial submenu position now: */ + fghGetVMaxExtent(menu->ParentWindow, &max_x, &max_y); + menuEntry->SubMenu->X = menu->X + menu->Width; + menuEntry->SubMenu->Y = menu->Y + + menuEntry->Ordinal * FREEGLUT_MENU_HEIGHT; + + if( menuEntry->SubMenu->X + menuEntry->SubMenu->Width > max_x ) + menuEntry->SubMenu->X = menu->X - menuEntry->SubMenu->Width; + + if( menuEntry->SubMenu->Y + menuEntry->SubMenu->Height > max_y ) + { + menuEntry->SubMenu->Y -= ( menuEntry->SubMenu->Height - + FREEGLUT_MENU_HEIGHT - + 2 * FREEGLUT_MENU_BORDER ); + if( menuEntry->SubMenu->Y < 0 ) + menuEntry->SubMenu->Y = 0; + } + + fgSetWindow( menuEntry->SubMenu->Window ); + glutPositionWindow( menuEntry->SubMenu->X, + menuEntry->SubMenu->Y ); + glutReshapeWindow( menuEntry->SubMenu->Width, + menuEntry->SubMenu->Height ); + glutPopWindow( ); + glutShowWindow( ); + menuEntry->SubMenu->Window->ActiveMenu = menuEntry->SubMenu; + fgSetWindow( current_window ); + menuEntry->SubMenu->Window->State.MouseX = + x + menu->X - menuEntry->SubMenu->X; + menuEntry->SubMenu->Window->State.MouseY = + y + menu->Y - menuEntry->SubMenu->Y; + fghCheckMenuStatus( menuEntry->SubMenu ); + } + + /* Activate it because its parent entry is active */ + menuEntry->SubMenu->IsActive = GL_TRUE; /* XXX Do we need this? */ + } + + /* Report back that we have caught the menu cursor */ + return GL_TRUE; + } + + /* Looks like the menu cursor is somewhere else... */ + if( menu->ActiveEntry && menu->ActiveEntry->IsActive && + ( !menu->ActiveEntry->SubMenu || + !menu->ActiveEntry->SubMenu->IsActive ) ) + { + menu->Window->State.Redisplay = GL_TRUE; + menu->ActiveEntry->IsActive = GL_FALSE; + menu->ActiveEntry = NULL; + } + + return GL_FALSE; +} + +/* + * Displays a menu box and all of its submenus (if they are active) + */ +static void fghDisplayMenuBox( SFG_Menu* menu ) +{ + SFG_MenuEntry *menuEntry; + int i; + int border = FREEGLUT_MENU_BORDER; + + /* + * Have the menu box drawn first. The +- values are + * here just to make it more nice-looking... + */ + /* a non-black dark version of the below. */ + glColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); + glBegin( GL_QUAD_STRIP ); + glVertex2i( menu->Width , 0 ); + glVertex2i( menu->Width - border, border); + glVertex2i( 0 , 0 ); + glVertex2i( border, border); + glVertex2i( 0 , menu->Height ); + glVertex2i( border, menu->Height - border); + glEnd( ); + + /* a non-black dark version of the below. */ + glColor4f( 0.5f, 0.5f, 0.5f, 1.0f ); + glBegin( GL_QUAD_STRIP ); + glVertex2i( 0 , menu->Height ); + glVertex2i( border, menu->Height - border); + glVertex2i( menu->Width , menu->Height ); + glVertex2i( menu->Width - border, menu->Height - border); + glVertex2i( menu->Width , 0 ); + glVertex2i( menu->Width - border, border); + glEnd( ); + + glColor4fv( menu_pen_back ); + glBegin( GL_QUADS ); + glVertex2i( border, border); + glVertex2i( menu->Width - border, border); + glVertex2i( menu->Width - border, menu->Height - border); + glVertex2i( border, menu->Height - border); + glEnd( ); + + /* Check if any of the submenus is currently active... */ + for( menuEntry = (SFG_MenuEntry *)menu->Entries.First; + menuEntry; + menuEntry = (SFG_MenuEntry *)menuEntry->Node.Next ) + { + /* Has the menu been marked as active, maybe? */ + if( menuEntry->IsActive ) + { + /* + * That's truly right, and we need to have it highlighted. + * There is an assumption that mouse cursor didn't move + * since the last check of menu activity state: + */ + int menuID = menuEntry->Ordinal; + + /* So have the highlight drawn... */ + glColor4fv( menu_pen_hback ); + glBegin( GL_QUADS ); + glVertex2i( border, + (menuID + 0)*FREEGLUT_MENU_HEIGHT + border ); + glVertex2i( menu->Width - border, + (menuID + 0)*FREEGLUT_MENU_HEIGHT + border ); + glVertex2i( menu->Width - border, + (menuID + 1)*FREEGLUT_MENU_HEIGHT + border ); + glVertex2i( border, + (menuID + 1)*FREEGLUT_MENU_HEIGHT + border ); + glEnd( ); + } + } + + /* Print the menu entries now... */ + + glColor4fv( menu_pen_fore ); + + for( menuEntry = (SFG_MenuEntry *)menu->Entries.First, i = 0; + menuEntry; + menuEntry = (SFG_MenuEntry *)menuEntry->Node.Next, ++i ) + { + /* If the menu entry is active, set the color to white */ + if( menuEntry->IsActive ) + glColor4fv( menu_pen_hfore ); + + /* Move the raster into position... */ + /* Try to center the text - JCJ 31 July 2003*/ + glRasterPos2i( + 2 * border, + ( i + 1 )*FREEGLUT_MENU_HEIGHT - + ( int )( FREEGLUT_MENU_HEIGHT*0.3 - border ) + ); + + /* Have the label drawn, character after character: */ + glutBitmapString( FREEGLUT_MENU_FONT, + (unsigned char *)menuEntry->Text); + + /* If it's a submenu, draw a right arrow */ + if( menuEntry->SubMenu ) + { + int width = glutBitmapWidth( FREEGLUT_MENU_FONT, '_' ); + int x_base = menu->Width - 2 - width; + int y_base = i*FREEGLUT_MENU_HEIGHT + border; + glBegin( GL_TRIANGLES ); + glVertex2i( x_base, y_base + 2*border); + glVertex2i( menu->Width - 2, y_base + + ( FREEGLUT_MENU_HEIGHT + border) / 2 ); + glVertex2i( x_base, y_base + FREEGLUT_MENU_HEIGHT - border ); + glEnd( ); + } + + /* If the menu entry is active, reset the color */ + if( menuEntry->IsActive ) + glColor4fv( menu_pen_fore ); + } +} + +/* + * Private static function to set the parent window of a submenu and all + * of its submenus + */ +static void fghSetMenuParentWindow( SFG_Window *window, SFG_Menu *menu ) +{ + SFG_MenuEntry *menuEntry; + + menu->ParentWindow = window; + + for( menuEntry = ( SFG_MenuEntry * )menu->Entries.First; + menuEntry; + menuEntry = ( SFG_MenuEntry * )menuEntry->Node.Next ) + if( menuEntry->SubMenu ) + fghSetMenuParentWindow( window, menuEntry->SubMenu ); +} + +/* + * Function to check for menu entry selection on menu deactivation + */ +static void fghExecuteMenuCallback( SFG_Menu* menu ) +{ + SFG_MenuEntry *menuEntry; + + /* First of all check any of the active sub menus... */ + for( menuEntry = (SFG_MenuEntry *)menu->Entries.First; + menuEntry; + menuEntry = (SFG_MenuEntry *)menuEntry->Node.Next) + { + if( menuEntry->IsActive ) + { + if( menuEntry->SubMenu ) + fghExecuteMenuCallback( menuEntry->SubMenu ); + else + if( menu->Callback ) + { + SFG_Menu *save_menu = fgStructure.CurrentMenu; + fgStructure.CurrentMenu = menu; + menu->Callback( menuEntry->ID ); + fgStructure.CurrentMenu = save_menu; + } + + return; + } + } +} + + +/* + * Displays the currently active menu for the current window + */ +void fgDisplayMenu( void ) +{ + SFG_Window* window = fgStructure.CurrentWindow; + SFG_Menu* menu = NULL; + + FREEGLUT_INTERNAL_ERROR_EXIT ( fgStructure.CurrentWindow, "Displaying menu in nonexistent window", + "fgDisplayMenu" ); + + /* Check if there is an active menu attached to this window... */ + menu = window->ActiveMenu; + freeglut_return_if_fail( menu ); + + fgSetWindow( menu->Window ); + + glPushAttrib( GL_DEPTH_BUFFER_BIT | GL_TEXTURE_BIT | GL_LIGHTING_BIT | + GL_POLYGON_BIT ); + + glDisable( GL_DEPTH_TEST ); + glDisable( GL_TEXTURE_2D ); + glDisable( GL_LIGHTING ); + glDisable( GL_CULL_FACE ); + + glMatrixMode( GL_PROJECTION ); + glPushMatrix( ); + glLoadIdentity( ); + glOrtho( + 0, glutGet( GLUT_WINDOW_WIDTH ), + glutGet( GLUT_WINDOW_HEIGHT ), 0, + -1, 1 + ); + + glMatrixMode( GL_MODELVIEW ); + glPushMatrix( ); + glLoadIdentity( ); + + fghDisplayMenuBox( menu ); + + glPopAttrib( ); + + glMatrixMode( GL_PROJECTION ); + glPopMatrix( ); + glMatrixMode( GL_MODELVIEW ); + glPopMatrix( ); + + glutSwapBuffers( ); + + fgSetWindow ( window ); +} + +/* + * Activates a menu pointed by the function argument + */ +static void fghActivateMenu( SFG_Window* window, int button ) +{ + int max_x, max_y; + + /* We'll be referencing this menu a lot, so remember its address: */ + SFG_Menu* menu = window->Menu[ button ]; + SFG_Window* current_window = fgStructure.CurrentWindow; + + /* If the menu is already active in another window, deactivate it there */ + if ( menu->ParentWindow ) + menu->ParentWindow->ActiveMenu = NULL ; + + /* Mark the menu as active, so that it gets displayed: */ + window->ActiveMenu = menu; + menu->IsActive = GL_TRUE; + fghSetMenuParentWindow ( window, menu ); + fgState.ActiveMenus++; + + /* Set up the initial menu position now: */ + fghGetVMaxExtent(menu->ParentWindow, &max_x, &max_y); + fgSetWindow( window ); + menu->X = window->State.MouseX + glutGet( GLUT_WINDOW_X ); + menu->Y = window->State.MouseY + glutGet( GLUT_WINDOW_Y ); + + if( menu->X + menu->Width > max_x ) + menu->X -=menu->Width; + + if( menu->Y + menu->Height > max_y ) + { + menu->Y -=menu->Height; + if( menu->Y < 0 ) + menu->Y = 0; + } + + menu->Window->State.MouseX = + window->State.MouseX + glutGet( GLUT_WINDOW_X ) - menu->X; + menu->Window->State.MouseY = + window->State.MouseY + glutGet( GLUT_WINDOW_Y ) - menu->Y; + + fgSetWindow( menu->Window ); + glutPositionWindow( menu->X, menu->Y ); + glutReshapeWindow( menu->Width, menu->Height ); + glutPopWindow( ); + glutShowWindow( ); + menu->Window->ActiveMenu = menu; + fghCheckMenuStatus( menu ); + fgSetWindow( current_window ); +} + +/* + * Update Highlight states of the menu + * + * Current mouse position is in menu->Window->State.MouseX/Y. + */ +void fgUpdateMenuHighlight ( SFG_Menu *menu ) +{ + fghCheckMenuStatus( menu ); +} + +/* + * Check whether an active menu absorbs a mouse click + */ +GLboolean fgCheckActiveMenu ( SFG_Window *window, int button, GLboolean pressed, + int mouse_x, int mouse_y ) +{ + /* + * Near as I can tell, this is the menu behaviour: + * - Down-click the menu button, menu not active: activate + * the menu with its upper left-hand corner at the mouse + * location. + * - Down-click any button outside the menu, menu active: + * deactivate the menu + * - Down-click any button inside the menu, menu active: + * select the menu entry and deactivate the menu + * - Up-click the menu button, menu not active: nothing happens + * - Up-click the menu button outside the menu, menu active: + * nothing happens + * - Up-click the menu button inside the menu, menu active: + * select the menu entry and deactivate the menu + * Since menus can have submenus, we need to check this recursively. + */ + if( window->ActiveMenu ) + { + if( window == window->ActiveMenu->ParentWindow ) + { + window->ActiveMenu->Window->State.MouseX = + mouse_x - window->ActiveMenu->X; + window->ActiveMenu->Window->State.MouseY = + mouse_y - window->ActiveMenu->Y; + } + + /* In the menu, invoke the callback and deactivate the menu */ + if( fghCheckMenuStatus( window->ActiveMenu ) ) + { + /* + * Save the current window and menu and set the current + * window to the window whose menu this is + */ + SFG_Window *save_window = fgStructure.CurrentWindow; + SFG_Menu *save_menu = fgStructure.CurrentMenu; + SFG_Window *parent_window = window->ActiveMenu->ParentWindow; + fgSetWindow( parent_window ); + fgStructure.CurrentMenu = window->ActiveMenu; + + /* Execute the menu callback */ + fghExecuteMenuCallback( window->ActiveMenu ); + fgDeactivateMenu( parent_window ); + + /* Restore the current window and menu */ + fgSetWindow( save_window ); + fgStructure.CurrentMenu = save_menu; + } + else if( pressed ) + /* + * Outside the menu, deactivate if it's a downclick + * + * XXX This isn't enough. A downclick outside of + * XXX the interior of our freeglut windows should also + * XXX deactivate the menu. This is more complicated. + */ + fgDeactivateMenu( window->ActiveMenu->ParentWindow ); + + /* + * XXX Why does an active menu require a redisplay at + * XXX this point? If this can come out cleanly, then + * XXX it probably should do so; if not, a comment should + * XXX explain it. + */ + if( ! window->IsMenu ) + window->State.Redisplay = GL_TRUE; + + return GL_TRUE; + } + + /* No active menu, let's check whether we need to activate one. */ + if( ( 0 <= button ) && + ( FREEGLUT_MAX_MENUS > button ) && + ( window->Menu[ button ] ) && + pressed ) + { + /* XXX Posting a requisite Redisplay seems bogus. */ + window->State.Redisplay = GL_TRUE; + fghActivateMenu( window, button ); + return GL_TRUE; + } + + return GL_FALSE; +} + +/* + * Deactivates a menu pointed by the function argument. + */ +void fgDeactivateMenu( SFG_Window *window ) +{ + SFG_Window *parent_window = NULL; + + /* Check if there is an active menu attached to this window... */ + SFG_Menu* menu = window->ActiveMenu; + SFG_MenuEntry *menuEntry; + + /* Did we find an active window? */ + freeglut_return_if_fail( menu ); + + parent_window = menu->ParentWindow; + + /* Hide the present menu's window */ + fgSetWindow( menu->Window ); + glutHideWindow( ); + + /* Forget about having that menu active anymore, now: */ + menu->Window->ActiveMenu = NULL; + menu->ParentWindow->ActiveMenu = NULL; + fghSetMenuParentWindow ( NULL, menu ); + menu->IsActive = GL_FALSE; + menu->ActiveEntry = NULL; + + fgState.ActiveMenus--; + + /* Hide all submenu windows, and the root menu's window. */ + for ( menuEntry = ( SFG_MenuEntry * )menu->Entries.First; + menuEntry; + menuEntry = ( SFG_MenuEntry * )menuEntry->Node.Next ) + { + menuEntry->IsActive = GL_FALSE; + + /* Is that an active submenu by any case? */ + if( menuEntry->SubMenu ) + fghDeactivateSubMenu( menuEntry ); + } + + fgSetWindow ( parent_window ) ; +} + +/* + * Recalculates current menu's box size + */ +void fghCalculateMenuBoxSize( void ) +{ + SFG_MenuEntry* menuEntry; + int width = 0, height = 0; + + /* Make sure there is a current menu set */ + freeglut_return_if_fail( fgStructure.CurrentMenu ); + + /* The menu's box size depends on the menu entries: */ + for( menuEntry = ( SFG_MenuEntry * )fgStructure.CurrentMenu->Entries.First; + menuEntry; + menuEntry = ( SFG_MenuEntry * )menuEntry->Node.Next ) + { + /* Update the menu entry's width value */ + menuEntry->Width = glutBitmapLength( + FREEGLUT_MENU_FONT, + (unsigned char *)menuEntry->Text + ); + + /* + * If the entry is a submenu, then it needs to be wider to + * accomodate the arrow. JCJ 31 July 2003 + */ + if (menuEntry->SubMenu ) + menuEntry->Width += glutBitmapLength( + FREEGLUT_MENU_FONT, + (unsigned char *)"_" + ); + + /* Check if it's the biggest we've found */ + if( menuEntry->Width > width ) + width = menuEntry->Width; + + height += FREEGLUT_MENU_HEIGHT; + } + + /* Store the menu's box size now: */ + fgStructure.CurrentMenu->Height = height + 2 * FREEGLUT_MENU_BORDER; + fgStructure.CurrentMenu->Width = width + 4 * FREEGLUT_MENU_BORDER; +} + + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +/* + * Creates a new menu object, adding it to the freeglut structure + */ +int FGAPIENTRY glutCreateMenu( void(* callback)( int ) ) +{ + /* The menu object creation code resides in freeglut_structure.c */ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateMenu" ); + return fgCreateMenu( callback )->ID; +} + +#if TARGET_HOST_MS_WINDOWS +int FGAPIENTRY __glutCreateMenuWithExit( void(* callback)( int ), void (__cdecl *exit_function)(int) ) +{ + __glutExitFunc = exit_function; + return glutCreateMenu( callback ); +} +#endif + +/* + * Destroys a menu object, removing all references to it + */ +void FGAPIENTRY glutDestroyMenu( int menuID ) +{ + SFG_Menu* menu; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDestroyMenu" ); + menu = fgMenuByID( menuID ); + + freeglut_return_if_fail( menu ); + + /* The menu object destruction code resides in freeglut_structure.c */ + fgDestroyMenu( menu ); +} + +/* + * Returns the ID number of the currently active menu + */ +int FGAPIENTRY glutGetMenu( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGetMenu" ); + + if( fgStructure.CurrentMenu ) + return fgStructure.CurrentMenu->ID; + + return 0; +} + +/* + * Sets the current menu given its menu ID + */ +void FGAPIENTRY glutSetMenu( int menuID ) +{ + SFG_Menu* menu; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetMenu" ); + menu = fgMenuByID( menuID ); + + freeglut_return_if_fail( menu ); + + fgStructure.CurrentMenu = menu; +} + +/* + * Adds a menu entry to the bottom of the current menu + */ +void FGAPIENTRY glutAddMenuEntry( const char* label, int value ) +{ + SFG_MenuEntry* menuEntry; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutAddMenuEntry" ); + menuEntry = (SFG_MenuEntry *)calloc( sizeof(SFG_MenuEntry), 1 ); + freeglut_return_if_fail( fgStructure.CurrentMenu ); + + menuEntry->Text = strdup( label ); + menuEntry->ID = value; + + /* Have the new menu entry attached to the current menu */ + fgListAppend( &fgStructure.CurrentMenu->Entries, &menuEntry->Node ); + + fghCalculateMenuBoxSize( ); +} + +/* + * Add a sub menu to the bottom of the current menu + */ +void FGAPIENTRY glutAddSubMenu( const char *label, int subMenuID ) +{ + SFG_MenuEntry *menuEntry; + SFG_Menu *subMenu; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutAddSubMenu" ); + menuEntry = ( SFG_MenuEntry * )calloc( sizeof( SFG_MenuEntry ), 1 ); + subMenu = fgMenuByID( subMenuID ); + + freeglut_return_if_fail( fgStructure.CurrentMenu ); + freeglut_return_if_fail( subMenu ); + + menuEntry->Text = strdup( label ); + menuEntry->SubMenu = subMenu; + menuEntry->ID = -1; + + fgListAppend( &fgStructure.CurrentMenu->Entries, &menuEntry->Node ); + fghCalculateMenuBoxSize( ); +} + +/* + * Changes the specified menu item in the current menu into a menu entry + */ +void FGAPIENTRY glutChangeToMenuEntry( int item, const char* label, int value ) +{ + SFG_MenuEntry* menuEntry = NULL; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutChangeToMenuEntry" ); + freeglut_return_if_fail( fgStructure.CurrentMenu ); + + /* Get n-th menu entry in the current menu, starting from one: */ + menuEntry = fghFindMenuEntry( fgStructure.CurrentMenu, item ); + + freeglut_return_if_fail( menuEntry ); + + /* We want it to become a normal menu entry, so: */ + if( menuEntry->Text ) + free( menuEntry->Text ); + + menuEntry->Text = strdup( label ); + menuEntry->ID = value; + menuEntry->SubMenu = NULL; + fghCalculateMenuBoxSize( ); +} + +/* + * Changes the specified menu item in the current menu into a sub-menu trigger. + */ +void FGAPIENTRY glutChangeToSubMenu( int item, const char* label, + int subMenuID ) +{ + SFG_Menu* subMenu; + SFG_MenuEntry* menuEntry; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutChangeToSubMenu" ); + subMenu = fgMenuByID( subMenuID ); + menuEntry = NULL; + + freeglut_return_if_fail( fgStructure.CurrentMenu ); + freeglut_return_if_fail( subMenu ); + + /* Get n-th menu entry in the current menu, starting from one: */ + menuEntry = fghFindMenuEntry( fgStructure.CurrentMenu, item ); + + freeglut_return_if_fail( menuEntry ); + + /* We want it to become a sub menu entry, so: */ + if( menuEntry->Text ) + free( menuEntry->Text ); + + menuEntry->Text = strdup( label ); + menuEntry->SubMenu = subMenu; + menuEntry->ID = -1; + fghCalculateMenuBoxSize( ); +} + +/* + * Removes the specified menu item from the current menu + */ +void FGAPIENTRY glutRemoveMenuItem( int item ) +{ + SFG_MenuEntry* menuEntry; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutRemoveMenuItem" ); + freeglut_return_if_fail( fgStructure.CurrentMenu ); + + /* Get n-th menu entry in the current menu, starting from one: */ + menuEntry = fghFindMenuEntry( fgStructure.CurrentMenu, item ); + + freeglut_return_if_fail( menuEntry ); + + fgListRemove( &fgStructure.CurrentMenu->Entries, &menuEntry->Node ); + if ( menuEntry->Text ) + free( menuEntry->Text ); + + free( menuEntry ); + fghCalculateMenuBoxSize( ); +} + +/* + * Attaches a menu to the current window + */ +void FGAPIENTRY glutAttachMenu( int button ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutAttachMenu" ); + + freeglut_return_if_fail( fgStructure.CurrentWindow ); + freeglut_return_if_fail( fgStructure.CurrentMenu ); + + freeglut_return_if_fail( button >= 0 ); + freeglut_return_if_fail( button < FREEGLUT_MAX_MENUS ); + + fgStructure.CurrentWindow->Menu[ button ] = fgStructure.CurrentMenu; +} + +/* + * Detaches a menu from the current window + */ +void FGAPIENTRY glutDetachMenu( int button ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDetachMenu" ); + + freeglut_return_if_fail( fgStructure.CurrentWindow ); + freeglut_return_if_fail( fgStructure.CurrentMenu ); + + freeglut_return_if_fail( button >= 0 ); + freeglut_return_if_fail( button < FREEGLUT_MAX_MENUS ); + + fgStructure.CurrentWindow->Menu[ button ] = NULL; +} + +/* + * A.Donev: Set and retrieve the menu's user data + */ +void* FGAPIENTRY glutGetMenuData( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGetMenuData" ); + return fgStructure.CurrentMenu->UserData; +} + +void FGAPIENTRY glutSetMenuData(void* data) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetMenuData" ); + fgStructure.CurrentMenu->UserData=data; +} + +/*** END OF FILE ***/ diff --git a/tests/box2d/freeglut/freeglut_misc.c b/tests/box2d/freeglut/freeglut_misc.c new file mode 100755 index 00000000..d0a65bde --- /dev/null +++ b/tests/box2d/freeglut/freeglut_misc.c @@ -0,0 +1,214 @@ +/* + * freeglut_misc.c + * + * Functions that didn't fit anywhere else... + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, <olszta@sourceforge.net> + * Creation date: Thu Dec 9 1999 + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "freeglut.h" +#include "freeglut_internal.h" + +/* + * TODO BEFORE THE STABLE RELEASE: + * + * glutSetColor() -- + * glutGetColor() -- + * glutCopyColormap() -- + * glutSetKeyRepeat() -- this is evil and should be removed from API + */ + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +/* + * This functions checks if an OpenGL extension is supported or not + * + * XXX Wouldn't this be simpler and clearer if we used strtok()? + */ +int FGAPIENTRY glutExtensionSupported( const char* extension ) +{ + const char *extensions, *start; + const size_t len = strlen( extension ); + + /* Make sure there is a current window, and thus a current context available */ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutExtensionSupported" ); + freeglut_return_val_if_fail( fgStructure.CurrentWindow != NULL, 0 ); + + if (strchr(extension, ' ')) + return 0; + start = extensions = (const char *) glGetString(GL_EXTENSIONS); + + /* XXX consider printing a warning to stderr that there's no current + * rendering context. + */ + freeglut_return_val_if_fail( extensions != NULL, 0 ); + + while (1) { + const char *p = strstr(extensions, extension); + if (!p) + return 0; /* not found */ + /* check that the match isn't a super string */ + if ((p == start || p[-1] == ' ') && (p[len] == ' ' || p[len] == 0)) + return 1; + /* skip the false match and continue */ + extensions = p + len; + } + + return 0 ; +} + +#ifndef GL_INVALID_FRAMEBUFFER_OPERATION +#ifdef GL_INVALID_FRAMEBUFFER_OPERATION_EXT +#define GL_INVALID_FRAMEBUFFER_OPERATION GL_INVALID_FRAMEBUFFER_OPERATION_EXT +#else +#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 +#endif +#endif + +#ifndef GL_TABLE_TOO_LARGE +#ifdef GL_TABLE_TOO_LARGE_EXT +#define GL_TABLE_TOO_LARGE GL_TABLE_TOO_LARGE_EXT +#else +#define GL_TABLE_TOO_LARGE 0x8031 +#endif +#endif + +#ifndef GL_TEXTURE_TOO_LARGE +#ifdef GL_TEXTURE_TOO_LARGE_EXT +#define GL_TEXTURE_TOO_LARGE GL_TEXTURE_TOO_LARGE_EXT +#else +#define GL_TEXTURE_TOO_LARGE 0x8065 +#endif +#endif + +/* + * A cut-down local version of gluErrorString to avoid depending on GLU. + */ +static const char* fghErrorString( GLenum error ) +{ + switch ( error ) { + case GL_INVALID_ENUM: return "invalid enumerant"; + case GL_INVALID_VALUE: return "invalid value"; + case GL_INVALID_OPERATION: return "invalid operation"; + case GL_STACK_OVERFLOW: return "stack overflow"; + case GL_STACK_UNDERFLOW: return "stack underflow"; + case GL_OUT_OF_MEMORY: return "out of memory"; + case GL_TABLE_TOO_LARGE: return "table too large"; + case GL_INVALID_FRAMEBUFFER_OPERATION: return "invalid framebuffer operation"; + case GL_TEXTURE_TOO_LARGE: return "texture too large"; + default: return "unknown GL error"; + } +} + +/* + * This function reports all the OpenGL errors that happened till now + */ +void FGAPIENTRY glutReportErrors( void ) +{ + GLenum error; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutReportErrors" ); + while( ( error = glGetError() ) != GL_NO_ERROR ) + fgWarning( "GL error: %s", fghErrorString( error ) ); +} + +/* + * Control the auto-repeat of keystrokes to the current window + */ +void FGAPIENTRY glutIgnoreKeyRepeat( int ignore ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutIgnoreKeyRepeat" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutIgnoreKeyRepeat" ); + + fgStructure.CurrentWindow->State.IgnoreKeyRepeat = ignore ? GL_TRUE : GL_FALSE; +} + +/* + * Set global auto-repeat of keystrokes + * + * RepeatMode should be either: + * GLUT_KEY_REPEAT_OFF + * GLUT_KEY_REPEAT_ON + * GLUT_KEY_REPEAT_DEFAULT + */ +void FGAPIENTRY glutSetKeyRepeat( int repeatMode ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetKeyRepeat" ); + + switch( repeatMode ) + { + case GLUT_KEY_REPEAT_OFF: + case GLUT_KEY_REPEAT_ON: + fgState.KeyRepeat = repeatMode; + break; + + case GLUT_KEY_REPEAT_DEFAULT: + fgState.KeyRepeat = GLUT_KEY_REPEAT_ON; + break; + + default: + fgError ("Invalid glutSetKeyRepeat mode: %d", repeatMode); + break; + } +} + +/* + * Forces the joystick callback to be executed + */ +void FGAPIENTRY glutForceJoystickFunc( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutForceJoystickFunc" ); +#if !defined(_WIN32_WCE) + freeglut_return_if_fail( fgStructure.CurrentWindow != NULL ); + freeglut_return_if_fail( FETCH_WCB( *( fgStructure.CurrentWindow ), Joystick ) ); + fgJoystickPollWindow( fgStructure.CurrentWindow ); +#endif /* !defined(_WIN32_WCE) */ +} + +/* + * + */ +void FGAPIENTRY glutSetColor( int nColor, GLfloat red, GLfloat green, GLfloat blue ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetColor" ); + /* We really need to do something here. */ +} + +/* + * + */ +GLfloat FGAPIENTRY glutGetColor( int color, int component ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGetColor" ); + /* We really need to do something here. */ + return( 0.0f ); +} + +/* + * + */ +void FGAPIENTRY glutCopyColormap( int window ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCopyColormap" ); + /* We really need to do something here. */ +} + +/*** END OF FILE ***/ diff --git a/tests/box2d/freeglut/freeglut_overlay.c b/tests/box2d/freeglut/freeglut_overlay.c new file mode 100755 index 00000000..fbc3250d --- /dev/null +++ b/tests/box2d/freeglut/freeglut_overlay.c @@ -0,0 +1,45 @@ +/* + * freeglut_overlay.c + * + * Overlay management functions (as defined by GLUT API) + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, <olszta@sourceforge.net> + * Creation date: Thu Dec 16 1999 + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "freeglut.h" +#include "freeglut_internal.h" + +/* + * NOTE: functions declared in this file probably will not be implemented. + */ + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +void FGAPIENTRY glutEstablishOverlay( void ) { /* Not implemented */ } +void FGAPIENTRY glutRemoveOverlay( void ) { /* Not implemented */ } +void FGAPIENTRY glutUseLayer( GLenum layer ) { /* Not implemented */ } +void FGAPIENTRY glutPostOverlayRedisplay( void ) { /* Not implemented */ } +void FGAPIENTRY glutPostWindowOverlayRedisplay( int ID ) { /* Not implemented */ } +void FGAPIENTRY glutShowOverlay( void ) { /* Not implemented */ } +void FGAPIENTRY glutHideOverlay( void ) { /* Not implemented */ } + +/*** END OF FILE ***/ diff --git a/tests/box2d/freeglut/freeglut_spaceball.c b/tests/box2d/freeglut/freeglut_spaceball.c new file mode 100755 index 00000000..a92a75c4 --- /dev/null +++ b/tests/box2d/freeglut/freeglut_spaceball.c @@ -0,0 +1,454 @@ +/* Spaceball support for Linux.
+ * Written by John Tsiombikas <nuclear@member.fsf.org>
+ *
+ * This code supports 3Dconnexion's 6-dof space-whatever devices.
+ * It can communicate with either the proprietary 3Dconnexion daemon (3dxsrv)
+ * free spacenavd (http://spacenav.sourceforge.net), through the "standard"
+ * magellan X-based protocol.
+ */
+
+#include "freeglut.h" +#include "freeglut_internal.h"
+
+#if TARGET_HOST_POSIX_X11
+#include <X11/Xlib.h>
+
+enum {
+ SPNAV_EVENT_ANY, /* used by spnav_remove_events() */
+ SPNAV_EVENT_MOTION,
+ SPNAV_EVENT_BUTTON /* includes both press and release */
+};
+
+struct spnav_event_motion {
+ int type;
+ int x, y, z;
+ int rx, ry, rz;
+ unsigned int period;
+ int *data;
+};
+
+struct spnav_event_button {
+ int type;
+ int press;
+ int bnum;
+};
+
+typedef union spnav_event {
+ int type;
+ struct spnav_event_motion motion;
+ struct spnav_event_button button;
+} spnav_event;
+
+
+static int spnav_x11_open(Display *dpy, Window win);
+static int spnav_x11_window(Window win);
+static int spnav_x11_event(const XEvent *xev, spnav_event *event);
+static int spnav_close(void);
+static int spnav_fd(void);
+static int spnav_remove_events(int type);
+
+static SFG_Window *spnav_win;
+#endif
+
+static int sball_initialized;
+
+
+void fgInitialiseSpaceball(void)
+{
+ if(sball_initialized) {
+ return;
+ }
+
+#if TARGET_HOST_POSIX_X11
+ {
+ Window w;
+
+ if(!fgStructure.CurrentWindow)
+ return;
+
+ w = fgStructure.CurrentWindow->Window.Handle;
+ if(spnav_x11_open(fgDisplay.Display, w) == -1) {
+ return;
+ }
+ }
+#endif
+
+ sball_initialized = 1;
+}
+
+void fgSpaceballClose(void)
+{
+#if TARGET_HOST_POSIX_X11
+ spnav_close();
+#endif
+}
+
+int fgHasSpaceball(void)
+{
+ if(!sball_initialized) {
+ fgInitialiseSpaceball();
+ if(!sball_initialized) {
+ fgWarning("fgInitialiseSpaceball failed\n");
+ return 0;
+ }
+ }
+
+#if TARGET_HOST_POSIX_X11
+ /* XXX this function should somehow query the driver if there's a device
+ * plugged in, as opposed to just checking if there's a driver to talk to.
+ */
+ return spnav_fd() == -1 ? 0 : 1;
+#else
+ return 0;
+#endif
+}
+
+int fgSpaceballNumButtons(void)
+{
+ if(!sball_initialized) {
+ fgInitialiseSpaceball();
+ if(!sball_initialized) {
+ fgWarning("fgInitialiseSpaceball failed\n");
+ return 0;
+ }
+ }
+
+#if TARGET_HOST_POSIX_X11
+ return 2; /* TODO implement this properly */
+#else
+ return 0;
+#endif
+}
+
+void fgSpaceballSetWindow(SFG_Window *window)
+{
+ if(!sball_initialized) {
+ fgInitialiseSpaceball();
+ if(!sball_initialized) {
+ return;
+ }
+ }
+
+#if TARGET_HOST_POSIX_X11
+ if(spnav_win != window) {
+ spnav_x11_window(window->Window.Handle);
+ spnav_win = window;
+ }
+#endif
+}
+
+
+#if TARGET_HOST_POSIX_X11
+int fgIsSpaceballXEvent(const XEvent *xev)
+{
+ spnav_event sev;
+
+ if(!sball_initialized) {
+ fgInitialiseSpaceball();
+ if(!sball_initialized) {
+ return 0;
+ }
+ }
+
+ return spnav_x11_event(xev, &sev);
+}
+
+void fgSpaceballHandleXEvent(const XEvent *xev)
+{
+ spnav_event sev;
+
+ if(!sball_initialized) {
+ fgInitialiseSpaceball();
+ if(!sball_initialized) {
+ return;
+ }
+ }
+
+ if(spnav_x11_event(xev, &sev)) {
+ switch(sev.type) {
+ case SPNAV_EVENT_MOTION:
+ if(sev.motion.x | sev.motion.y | sev.motion.z) {
+ INVOKE_WCB(*spnav_win, SpaceMotion, (sev.motion.x, sev.motion.y, sev.motion.z));
+ }
+ if(sev.motion.rx | sev.motion.ry | sev.motion.rz) {
+ INVOKE_WCB(*spnav_win, SpaceRotation, (sev.motion.rx, sev.motion.ry, sev.motion.rz));
+ }
+ spnav_remove_events(SPNAV_EVENT_MOTION);
+ break;
+
+ case SPNAV_EVENT_BUTTON:
+ INVOKE_WCB(*spnav_win, SpaceButton, (sev.button.bnum, sev.button.press ? GLUT_DOWN : GLUT_UP));
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+/*
+The following code is part of libspnav, part of the spacenav project (spacenav.sf.net)
+Copyright (C) 2007-2009 John Tsiombikas <nuclear@member.fsf.org>
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. 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.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+static Window get_daemon_window(Display *dpy);
+static int catch_badwin(Display *dpy, XErrorEvent *err);
+
+static Display *dpy;
+static Window app_win;
+static Atom motion_event, button_press_event, button_release_event, command_event;
+
+enum {
+ CMD_APP_WINDOW = 27695,
+ CMD_APP_SENS
+};
+
+#define IS_OPEN dpy
+
+struct event_node {
+ spnav_event event;
+ struct event_node *next;
+};
+
+static int spnav_x11_open(Display *display, Window win)
+{
+ if(IS_OPEN) {
+ return -1;
+ }
+
+ dpy = display;
+
+ motion_event = XInternAtom(dpy, "MotionEvent", True);
+ button_press_event = XInternAtom(dpy, "ButtonPressEvent", True);
+ button_release_event = XInternAtom(dpy, "ButtonReleaseEvent", True);
+ command_event = XInternAtom(dpy, "CommandEvent", True);
+
+ if(!motion_event || !button_press_event || !button_release_event || !command_event) {
+ dpy = 0;
+ return -1; /* daemon not started */
+ }
+
+ if(spnav_x11_window(win) == -1) {
+ dpy = 0;
+ return -1; /* daemon not started */
+ }
+
+ app_win = win;
+ return 0;
+}
+
+static int spnav_close(void)
+{
+ if(dpy) {
+ spnav_x11_window(DefaultRootWindow(dpy));
+ app_win = 0;
+ dpy = 0;
+ return 0;
+ }
+ return -1;
+}
+
+static int spnav_x11_window(Window win)
+{
+ int (*prev_xerr_handler)(Display*, XErrorEvent*);
+ XEvent xev;
+ Window daemon_win;
+
+ if(!IS_OPEN) {
+ return -1;
+ }
+
+ if(!(daemon_win = get_daemon_window(dpy))) {
+ return -1;
+ }
+
+ prev_xerr_handler = XSetErrorHandler(catch_badwin);
+
+ xev.type = ClientMessage;
+ xev.xclient.send_event = False;
+ xev.xclient.display = dpy;
+ xev.xclient.window = win;
+ xev.xclient.message_type = command_event;
+ xev.xclient.format = 16;
+ xev.xclient.data.s[0] = ((unsigned int)win & 0xffff0000) >> 16;
+ xev.xclient.data.s[1] = (unsigned int)win & 0xffff;
+ xev.xclient.data.s[2] = CMD_APP_WINDOW;
+
+ XSendEvent(dpy, daemon_win, False, 0, &xev);
+ XSync(dpy, False);
+
+ XSetErrorHandler(prev_xerr_handler);
+ return 0;
+}
+
+static int spnav_fd(void)
+{
+ if(dpy) {
+ return ConnectionNumber(dpy);
+ }
+ return -1;
+}
+
+/*static int spnav_wait_event(spnav_event *event)
+{
+ if(dpy) {
+ for(;;) {
+ XEvent xev;
+ XNextEvent(dpy, &xev);
+
+ if(spnav_x11_event(&xev, event) > 0) {
+ return event->type;
+ }
+ }
+ }
+ return 0;
+}
+
+static int spnav_poll_event(spnav_event *event)
+{
+ if(dpy) {
+ if(XPending(dpy)) {
+ XEvent xev;
+ XNextEvent(dpy, &xev);
+
+ return spnav_x11_event(&xev, event);
+ }
+ }
+ return 0;
+}*/
+
+static Bool match_events(Display *dpy, XEvent *xev, char *arg)
+{
+ int evtype = *(int*)arg;
+
+ if(xev->type != ClientMessage) {
+ return False;
+ }
+
+ if(xev->xclient.message_type == motion_event) {
+ return !evtype || evtype == SPNAV_EVENT_MOTION ? True : False;
+ }
+ if(xev->xclient.message_type == button_press_event ||
+ xev->xclient.message_type == button_release_event) {
+ return !evtype || evtype == SPNAV_EVENT_BUTTON ? True : False;
+ }
+ return False;
+}
+
+static int spnav_remove_events(int type)
+{
+ int rm_count = 0;
+
+ if(dpy) {
+ XEvent xev;
+
+ while(XCheckIfEvent(dpy, &xev, match_events, (char*)&type)) {
+ rm_count++;
+ }
+ return rm_count;
+ }
+ return 0;
+}
+
+static int spnav_x11_event(const XEvent *xev, spnav_event *event)
+{
+ int i;
+ int xmsg_type;
+
+ if(xev->type != ClientMessage) {
+ return 0;
+ }
+
+ xmsg_type = xev->xclient.message_type;
+
+ if(xmsg_type != motion_event && xmsg_type != button_press_event &&
+ xmsg_type != button_release_event) {
+ return 0;
+ }
+
+ if(xmsg_type == motion_event) {
+ event->type = SPNAV_EVENT_MOTION;
+ event->motion.data = &event->motion.x;
+
+ for(i=0; i<6; i++) {
+ event->motion.data[i] = xev->xclient.data.s[i + 2];
+ }
+ event->motion.period = xev->xclient.data.s[8];
+ } else {
+ event->type = SPNAV_EVENT_BUTTON;
+ event->button.press = xmsg_type == button_press_event ? 1 : 0;
+ event->button.bnum = xev->xclient.data.s[2];
+ }
+ return event->type;
+}
+
+
+static Window get_daemon_window(Display *dpy)
+{
+ Window win, root_win;
+ XTextProperty wname;
+ Atom type;
+ int fmt;
+ unsigned long nitems, bytes_after;
+ unsigned char *prop;
+
+ root_win = DefaultRootWindow(dpy);
+
+ XGetWindowProperty(dpy, root_win, command_event, 0, 1, False, AnyPropertyType, &type, &fmt, &nitems, &bytes_after, &prop);
+ if(!prop) {
+ return 0;
+ }
+
+ win = *(Window*)prop;
+ XFree(prop);
+
+ if(!XGetWMName(dpy, win, &wname) || strcmp("Magellan Window", (char*)wname.value) != 0) {
+ return 0;
+ }
+
+ return win;
+}
+
+static int catch_badwin(Display *dpy, XErrorEvent *err)
+{
+ char buf[256];
+
+ if(err->error_code == BadWindow) {
+ /* do nothing? */
+ } else {
+ XGetErrorText(dpy, err->error_code, buf, sizeof buf);
+ fprintf(stderr, "Caught unexpected X error: %s\n", buf);
+ }
+ return 0;
+}
+
+#endif /* TARGET_HOST_POSIX_X11 */
diff --git a/tests/box2d/freeglut/freeglut_state.c b/tests/box2d/freeglut/freeglut_state.c new file mode 100755 index 00000000..783e7b44 --- /dev/null +++ b/tests/box2d/freeglut/freeglut_state.c @@ -0,0 +1,895 @@ +/* + * freeglut_state.c + * + * Freeglut state query methods. + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, <olszta@sourceforge.net> + * Creation date: Thu Dec 16 1999 + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "freeglut.h" +#include "freeglut_internal.h" + +/* + * TODO BEFORE THE STABLE RELEASE: + * + * glutGet() -- X11 tests passed, but check if all enums + * handled (what about Win32?) + * glutDeviceGet() -- X11 tests passed, but check if all enums + * handled (what about Win32?) + * glutGetModifiers() -- OK, but could also remove the limitation + * glutLayerGet() -- what about GLUT_NORMAL_DAMAGED? + * + * The fail-on-call policy will help adding the most needed things imho. + */ + +/* -- LOCAL DEFINITIONS ---------------------------------------------------- */ + +/* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ + +#if TARGET_HOST_POSIX_X11 +/* + * Queries the GL context about some attributes + */ +static int fghGetConfig( int attribute ) +{ + int returnValue = 0; + int result; /* Not checked */ + + if( fgStructure.CurrentWindow ) + result = glXGetFBConfigAttrib( fgDisplay.Display, + *(fgStructure.CurrentWindow->Window.FBConfig), + attribute, + &returnValue ); + + return returnValue; +} +#endif + +/* Check if the window is in full screen state. */ +static int fghCheckFullScreen(void) +{ +#if TARGET_HOST_POSIX_X11 + return fgStructure.CurrentWindow->State.IsFullscreen; +#else + return 0; +#endif +} + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +/* + * General settings assignment method + */ +void FGAPIENTRY glutSetOption( GLenum eWhat, int value ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetOption" ); + + /* + * XXX In chronological code add order. (WHY in that order?) + */ + switch( eWhat ) + { + case GLUT_INIT_WINDOW_X: + fgState.Position.X = (GLint)value; + break; + + case GLUT_INIT_WINDOW_Y: + fgState.Position.Y = (GLint)value; + break; + + case GLUT_INIT_WINDOW_WIDTH: + fgState.Size.X = (GLint)value; + break; + + case GLUT_INIT_WINDOW_HEIGHT: + fgState.Size.Y = (GLint)value; + break; + + case GLUT_INIT_DISPLAY_MODE: + fgState.DisplayMode = (unsigned int)value; + break; + + case GLUT_ACTION_ON_WINDOW_CLOSE: + fgState.ActionOnWindowClose = value; + break; + + case GLUT_RENDERING_CONTEXT: + fgState.UseCurrentContext = + ( value == GLUT_USE_CURRENT_CONTEXT ) ? GL_TRUE : GL_FALSE; + break; + + case GLUT_DIRECT_RENDERING: + fgState.DirectContext = value; + break; + + case GLUT_WINDOW_CURSOR: + if( fgStructure.CurrentWindow != NULL ) + fgStructure.CurrentWindow->State.Cursor = value; + break; + + case GLUT_AUX: + fgState.AuxiliaryBufferNumber = value; + break; + + case GLUT_MULTISAMPLE: + fgState.SampleNumber = value; + break; + + default: + fgWarning( "glutSetOption(): missing enum handle %d", eWhat ); + break; + } +} + +#if TARGET_HOST_MS_WINDOWS +/* The following include file is available from SGI but is not standard: + * #include <GL/wglext.h> + * So we copy the necessary parts out of it to support the multisampling query + */ +#define WGL_SAMPLES_ARB 0x2042 +#endif + + +/* + * General settings query method + */ +int FGAPIENTRY glutGet( GLenum eWhat ) +{ +#if TARGET_HOST_MS_WINDOWS + int returnValue ; + GLboolean boolValue ; +#endif + + int nsamples = 0; + + switch (eWhat) + { + case GLUT_INIT_STATE: + return fgState.Initialised; + + case GLUT_ELAPSED_TIME: + return fgElapsedTime(); + } + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGet" ); + + /* XXX In chronological code add order. (WHY in that order?) */ + switch( eWhat ) + { + /* Following values are stored in fgState and fgDisplay global structures */ + case GLUT_SCREEN_WIDTH: return fgDisplay.ScreenWidth ; + case GLUT_SCREEN_HEIGHT: return fgDisplay.ScreenHeight ; + case GLUT_SCREEN_WIDTH_MM: return fgDisplay.ScreenWidthMM ; + case GLUT_SCREEN_HEIGHT_MM: return fgDisplay.ScreenHeightMM; + case GLUT_INIT_WINDOW_X: return fgState.Position.Use ? + fgState.Position.X : -1 ; + case GLUT_INIT_WINDOW_Y: return fgState.Position.Use ? + fgState.Position.Y : -1 ; + case GLUT_INIT_WINDOW_WIDTH: return fgState.Size.Use ? + fgState.Size.X : -1 ; + case GLUT_INIT_WINDOW_HEIGHT: return fgState.Size.Use ? + fgState.Size.Y : -1 ; + case GLUT_INIT_DISPLAY_MODE: return fgState.DisplayMode ; + case GLUT_INIT_MAJOR_VERSION: return fgState.MajorVersion ; + case GLUT_INIT_MINOR_VERSION: return fgState.MinorVersion ; + case GLUT_INIT_FLAGS: return fgState.ContextFlags ; + case GLUT_INIT_PROFILE: return fgState.ContextProfile ; + +#if TARGET_HOST_POSIX_X11 + /* + * The window/context specific queries are handled mostly by + * fghGetConfig(). + */ + case GLUT_WINDOW_NUM_SAMPLES: +#ifdef GLX_VERSION_1_3 + glGetIntegerv(GL_SAMPLES, &nsamples); +#endif + return nsamples; + + /* + * The rest of GLX queries under X are general enough to use a macro to + * check them + */ +# define GLX_QUERY(a,b) case a: return fghGetConfig( b ); + + GLX_QUERY( GLUT_WINDOW_RGBA, GLX_RGBA ); + GLX_QUERY( GLUT_WINDOW_DOUBLEBUFFER, GLX_DOUBLEBUFFER ); + GLX_QUERY( GLUT_WINDOW_BUFFER_SIZE, GLX_BUFFER_SIZE ); + GLX_QUERY( GLUT_WINDOW_STENCIL_SIZE, GLX_STENCIL_SIZE ); + GLX_QUERY( GLUT_WINDOW_DEPTH_SIZE, GLX_DEPTH_SIZE ); + GLX_QUERY( GLUT_WINDOW_RED_SIZE, GLX_RED_SIZE ); + GLX_QUERY( GLUT_WINDOW_GREEN_SIZE, GLX_GREEN_SIZE ); + GLX_QUERY( GLUT_WINDOW_BLUE_SIZE, GLX_BLUE_SIZE ); + GLX_QUERY( GLUT_WINDOW_ALPHA_SIZE, GLX_ALPHA_SIZE ); + GLX_QUERY( GLUT_WINDOW_ACCUM_RED_SIZE, GLX_ACCUM_RED_SIZE ); + GLX_QUERY( GLUT_WINDOW_ACCUM_GREEN_SIZE, GLX_ACCUM_GREEN_SIZE ); + GLX_QUERY( GLUT_WINDOW_ACCUM_BLUE_SIZE, GLX_ACCUM_BLUE_SIZE ); + GLX_QUERY( GLUT_WINDOW_ACCUM_ALPHA_SIZE, GLX_ACCUM_ALPHA_SIZE ); + GLX_QUERY( GLUT_WINDOW_STEREO, GLX_STEREO ); + +# undef GLX_QUERY + + /* Colormap size is handled in a bit different way than all the rest */ + case GLUT_WINDOW_COLORMAP_SIZE: + if( (fghGetConfig( GLX_RGBA )) || (fgStructure.CurrentWindow == NULL) ) + { + /* + * We've got a RGBA visual, so there is no colormap at all. + * The other possibility is that we have no current window set. + */ + return 0; + } + else + { + const GLXFBConfig * fbconfig = + fgStructure.CurrentWindow->Window.FBConfig; + + XVisualInfo * visualInfo = + glXGetVisualFromFBConfig( fgDisplay.Display, *fbconfig ); + + const int result = visualInfo->visual->map_entries; + + XFree(visualInfo); + + return result; + } + + /* + * Those calls are somewhat similiar, as they use XGetWindowAttributes() + * function + */ + case GLUT_WINDOW_X: + case GLUT_WINDOW_Y: + case GLUT_WINDOW_BORDER_WIDTH: + case GLUT_WINDOW_HEADER_HEIGHT: + { + int x, y; + Window w; + + if( fgStructure.CurrentWindow == NULL ) + return 0; + + XTranslateCoordinates( + fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle, + fgDisplay.RootWindow, + 0, 0, &x, &y, &w); + + switch ( eWhat ) + { + case GLUT_WINDOW_X: return x; + case GLUT_WINDOW_Y: return y; + } + + if ( w == 0 ) + return 0; + XTranslateCoordinates( + fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle, + w, 0, 0, &x, &y, &w); + + switch ( eWhat ) + { + case GLUT_WINDOW_BORDER_WIDTH: return x; + case GLUT_WINDOW_HEADER_HEIGHT: return y; + } + } + + case GLUT_WINDOW_WIDTH: + case GLUT_WINDOW_HEIGHT: + { + XWindowAttributes winAttributes; + + if( fgStructure.CurrentWindow == NULL ) + return 0; + XGetWindowAttributes( + fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle, + &winAttributes + ); + switch ( eWhat ) + { + case GLUT_WINDOW_WIDTH: return winAttributes.width ; + case GLUT_WINDOW_HEIGHT: return winAttributes.height ; + } + } + + /* I do not know yet if there will be a fgChooseVisual() function for Win32 */ + case GLUT_DISPLAY_MODE_POSSIBLE: + { + /* We should not have to call fgChooseFBConfig again here. */ + GLXFBConfig * fbconfig; + int isPossible; + + fbconfig = fgChooseFBConfig(); + + if (fbconfig == NULL) + { + isPossible = 0; + } + else + { + isPossible = 1; + XFree(fbconfig); + } + + return isPossible; + } + + /* This is system-dependant */ + case GLUT_WINDOW_FORMAT_ID: + if( fgStructure.CurrentWindow == NULL ) + return 0; + + return fghGetConfig( GLX_VISUAL_ID ); + +#elif TARGET_HOST_MS_WINDOWS + + case GLUT_WINDOW_NUM_SAMPLES: + glGetIntegerv(WGL_SAMPLES_ARB, &nsamples); + return nsamples; + + /* Handle the OpenGL inquiries */ + case GLUT_WINDOW_RGBA: +#if defined(_WIN32_WCE) + boolValue = (GLboolean)0; /* WinCE doesn't support this feature */ +#else + glGetBooleanv ( GL_RGBA_MODE, &boolValue ); + returnValue = boolValue ? 1 : 0; +#endif + return returnValue; + case GLUT_WINDOW_DOUBLEBUFFER: +#if defined(_WIN32_WCE) + boolValue = (GLboolean)0; /* WinCE doesn't support this feature */ +#else + glGetBooleanv ( GL_DOUBLEBUFFER, &boolValue ); + returnValue = boolValue ? 1 : 0; +#endif + return returnValue; + case GLUT_WINDOW_STEREO: +#if defined(_WIN32_WCE) + boolValue = (GLboolean)0; /* WinCE doesn't support this feature */ +#else + glGetBooleanv ( GL_STEREO, &boolValue ); + returnValue = boolValue ? 1 : 0; +#endif + return returnValue; + + case GLUT_WINDOW_RED_SIZE: + glGetIntegerv ( GL_RED_BITS, &returnValue ); + return returnValue; + case GLUT_WINDOW_GREEN_SIZE: + glGetIntegerv ( GL_GREEN_BITS, &returnValue ); + return returnValue; + case GLUT_WINDOW_BLUE_SIZE: + glGetIntegerv ( GL_BLUE_BITS, &returnValue ); + return returnValue; + case GLUT_WINDOW_ALPHA_SIZE: + glGetIntegerv ( GL_ALPHA_BITS, &returnValue ); + return returnValue; + case GLUT_WINDOW_ACCUM_RED_SIZE: +#if defined(_WIN32_WCE) + returnValue = 0; /* WinCE doesn't support this feature */ +#else + glGetIntegerv ( GL_ACCUM_RED_BITS, &returnValue ); +#endif + return returnValue; + case GLUT_WINDOW_ACCUM_GREEN_SIZE: +#if defined(_WIN32_WCE) + returnValue = 0; /* WinCE doesn't support this feature */ +#else + glGetIntegerv ( GL_ACCUM_GREEN_BITS, &returnValue ); +#endif + return returnValue; + case GLUT_WINDOW_ACCUM_BLUE_SIZE: +#if defined(_WIN32_WCE) + returnValue = 0; /* WinCE doesn't support this feature */ +#else + glGetIntegerv ( GL_ACCUM_BLUE_BITS, &returnValue ); +#endif + return returnValue; + case GLUT_WINDOW_ACCUM_ALPHA_SIZE: +#if defined(_WIN32_WCE) + returnValue = 0; /* WinCE doesn't support this feature */ +#else + glGetIntegerv ( GL_ACCUM_ALPHA_BITS, &returnValue ); +#endif + return returnValue; + case GLUT_WINDOW_DEPTH_SIZE: + glGetIntegerv ( GL_DEPTH_BITS, &returnValue ); + return returnValue; + + case GLUT_WINDOW_BUFFER_SIZE: + returnValue = 1 ; /* ????? */ + return returnValue; + case GLUT_WINDOW_STENCIL_SIZE: + returnValue = 0 ; /* ????? */ + return returnValue; + + case GLUT_WINDOW_X: + case GLUT_WINDOW_Y: + case GLUT_WINDOW_WIDTH: + case GLUT_WINDOW_HEIGHT: + { + /* + * There is considerable confusion about the "right thing to + * do" concerning window size and position. GLUT itself is + * not consistent between Windows and UNIX/X11; since + * platform independence is a virtue for "freeglut", we + * decided to break with GLUT's behaviour. + * + * Under UNIX/X11, it is apparently not possible to get the + * window border sizes in order to subtract them off the + * window's initial position until some time after the window + * has been created. Therefore we decided on the following + * behaviour, both under Windows and under UNIX/X11: + * - When you create a window with position (x,y) and size + * (w,h), the upper left hand corner of the outside of the + * window is at (x,y) and the size of the drawable area is + * (w,h). + * - When you query the size and position of the window--as + * is happening here for Windows--"freeglut" will return + * the size of the drawable area--the (w,h) that you + * specified when you created the window--and the coordinates + * of the upper left hand corner of the drawable + * area--which is NOT the (x,y) you specified. + */ + + RECT winRect; + + freeglut_return_val_if_fail( fgStructure.CurrentWindow != NULL, 0 ); + + /* + * We need to call GetWindowRect() first... + * (this returns the pixel coordinates of the outside of the window) + */ + GetWindowRect( fgStructure.CurrentWindow->Window.Handle, &winRect ); + + /* ...then we've got to correct the results we've just received... */ + +#if !defined(_WIN32_WCE) + if ( ( fgStructure.GameModeWindow != fgStructure.CurrentWindow ) && ( fgStructure.CurrentWindow->Parent == NULL ) && + ( ! fgStructure.CurrentWindow->IsMenu ) ) + { + winRect.left += GetSystemMetrics( SM_CXSIZEFRAME ); + winRect.right -= GetSystemMetrics( SM_CXSIZEFRAME ); + winRect.top += GetSystemMetrics( SM_CYSIZEFRAME ) + GetSystemMetrics( SM_CYCAPTION ); + winRect.bottom -= GetSystemMetrics( SM_CYSIZEFRAME ); + } +#endif /* !defined(_WIN32_WCE) */ + + switch( eWhat ) + { + case GLUT_WINDOW_X: return winRect.left ; + case GLUT_WINDOW_Y: return winRect.top ; + case GLUT_WINDOW_WIDTH: return winRect.right - winRect.left; + case GLUT_WINDOW_HEIGHT: return winRect.bottom - winRect.top; + } + } + break; + + case GLUT_WINDOW_BORDER_WIDTH : +#if defined(_WIN32_WCE) + return 0; +#else + return GetSystemMetrics( SM_CXSIZEFRAME ); +#endif /* !defined(_WIN32_WCE) */ + + case GLUT_WINDOW_HEADER_HEIGHT : +#if defined(_WIN32_WCE) + return 0; +#else + return GetSystemMetrics( SM_CYCAPTION ); +#endif /* defined(_WIN32_WCE) */ + + case GLUT_DISPLAY_MODE_POSSIBLE: +#if defined(_WIN32_WCE) + return 0; +#else + return fgSetupPixelFormat( fgStructure.CurrentWindow, GL_TRUE, + PFD_MAIN_PLANE ); +#endif /* defined(_WIN32_WCE) */ + + + case GLUT_WINDOW_FORMAT_ID: +#if !defined(_WIN32_WCE) + if( fgStructure.CurrentWindow != NULL ) + return GetPixelFormat( fgStructure.CurrentWindow->Window.Device ); +#endif /* defined(_WIN32_WCE) */ + return 0; + +#endif + + /* The window structure queries */ + case GLUT_WINDOW_PARENT: + if( fgStructure.CurrentWindow == NULL ) return 0; + if( fgStructure.CurrentWindow->Parent == NULL ) return 0; + return fgStructure.CurrentWindow->Parent->ID; + + case GLUT_WINDOW_NUM_CHILDREN: + if( fgStructure.CurrentWindow == NULL ) + return 0; + return fgListLength( &fgStructure.CurrentWindow->Children ); + + case GLUT_WINDOW_CURSOR: + if( fgStructure.CurrentWindow == NULL ) + return 0; + return fgStructure.CurrentWindow->State.Cursor; + + case GLUT_MENU_NUM_ITEMS: + if( fgStructure.CurrentMenu == NULL ) + return 0; + return fgListLength( &fgStructure.CurrentMenu->Entries ); + + case GLUT_ACTION_ON_WINDOW_CLOSE: + return fgState.ActionOnWindowClose; + + case GLUT_VERSION : + return VERSION_MAJOR * 10000 + VERSION_MINOR * 100 + VERSION_PATCH; + + case GLUT_RENDERING_CONTEXT: + return fgState.UseCurrentContext ? GLUT_USE_CURRENT_CONTEXT + : GLUT_CREATE_NEW_CONTEXT; + + case GLUT_DIRECT_RENDERING: + return fgState.DirectContext; + + case GLUT_FULL_SCREEN: + return fghCheckFullScreen(); + + case GLUT_AUX: + return fgState.AuxiliaryBufferNumber; + + case GLUT_MULTISAMPLE: + return fgState.SampleNumber; + + default: + fgWarning( "glutGet(): missing enum handle %d", eWhat ); + break; + } + return -1; +} + +/* + * Returns various device information. + */ +int FGAPIENTRY glutDeviceGet( GLenum eWhat ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDeviceGet" ); + + /* XXX WARNING: we are mostly lying in this function. */ + switch( eWhat ) + { + case GLUT_HAS_KEYBOARD: + /* + * Win32 is assumed a keyboard, and this cannot be queried, + * except for WindowsCE. + * + * X11 has a core keyboard by definition, although it can + * be present as a virtual/dummy keyboard. For now, there + * is no reliable way to tell if a real keyboard is present. + */ +#if defined(_WIN32_CE) + return ( GetKeyboardStatus() & KBDI_KEYBOARD_PRESENT ) ? 1 : 0; +# if FREEGLUT_LIB_PRAGMAS +# pragma comment (lib,"Kbdui.lib") +# endif + +#else + return 1; +#endif + +#if TARGET_HOST_POSIX_X11 + + /* X11 has a mouse by definition */ + case GLUT_HAS_MOUSE: + return 1 ; + + case GLUT_NUM_MOUSE_BUTTONS: + /* We should be able to pass NULL when the last argument is zero, + * but at least one X server has a bug where this causes a segfault. + * + * In XFree86/Xorg servers, a mouse wheel is seen as two buttons + * rather than an Axis; "freeglut_main.c" expects this when + * checking for a wheel event. + */ + { + unsigned char map; + int nbuttons = XGetPointerMapping(fgDisplay.Display, &map,0); + return nbuttons; + } + +#elif TARGET_HOST_MS_WINDOWS + + case GLUT_HAS_MOUSE: + /* + * MS Windows can be booted without a mouse. + */ + return GetSystemMetrics( SM_MOUSEPRESENT ); + + case GLUT_NUM_MOUSE_BUTTONS: +# if defined(_WIN32_WCE) + return 1; +# else + return GetSystemMetrics( SM_CMOUSEBUTTONS ); +# endif +#endif + + case GLUT_HAS_JOYSTICK: + return fgJoystickDetect (); + + case GLUT_OWNS_JOYSTICK: + return fgState.JoysticksInitialised; + + case GLUT_JOYSTICK_POLL_RATE: + return fgStructure.CurrentWindow ? fgStructure.CurrentWindow->State.JoystickPollRate : 0; + + /* XXX The following two are only for Joystick 0 but this is an improvement */ + case GLUT_JOYSTICK_BUTTONS: + return glutJoystickGetNumButtons ( 0 ); + + case GLUT_JOYSTICK_AXES: + return glutJoystickGetNumAxes ( 0 ); + + case GLUT_HAS_DIAL_AND_BUTTON_BOX: + return fgInputDeviceDetect (); + + case GLUT_NUM_DIALS: + if ( fgState.InputDevsInitialised ) return 8; + return 0; + + case GLUT_NUM_BUTTON_BOX_BUTTONS: + return 0; + + case GLUT_HAS_SPACEBALL: + return fgHasSpaceball(); + + case GLUT_HAS_TABLET: + return 0; + + case GLUT_NUM_SPACEBALL_BUTTONS: + return fgSpaceballNumButtons(); + + case GLUT_NUM_TABLET_BUTTONS: + return 0; + + case GLUT_DEVICE_IGNORE_KEY_REPEAT: + return fgStructure.CurrentWindow ? fgStructure.CurrentWindow->State.IgnoreKeyRepeat : 0; + + case GLUT_DEVICE_KEY_REPEAT: + return fgState.KeyRepeat; + + default: + fgWarning( "glutDeviceGet(): missing enum handle %d", eWhat ); + break; + } + + /* And now -- the failure. */ + return -1; +} + +/* + * This should return the current state of ALT, SHIFT and CTRL keys. + */ +int FGAPIENTRY glutGetModifiers( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGetModifiers" ); + if( fgState.Modifiers == INVALID_MODIFIERS ) + { + fgWarning( "glutGetModifiers() called outside an input callback" ); + return 0; + } + + return fgState.Modifiers; +} + +/* + * Return the state of the GLUT API overlay subsystem. A misery ;-) + */ +int FGAPIENTRY glutLayerGet( GLenum eWhat ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutLayerGet" ); + + /* + * This is easy as layers are not implemented ;-) + * + * XXX Can we merge the UNIX/X11 and WIN32 sections? Or + * XXX is overlay support planned? + */ + switch( eWhat ) + { + +#if TARGET_HOST_POSIX_X11 + + case GLUT_OVERLAY_POSSIBLE: + return 0; + + case GLUT_LAYER_IN_USE: + return GLUT_NORMAL; + + case GLUT_HAS_OVERLAY: + return 0; + + case GLUT_TRANSPARENT_INDEX: + /* + * Return just anything, which is always defined as zero + * + * XXX HUH? + */ + return 0; + + case GLUT_NORMAL_DAMAGED: + /* XXX Actually I do not know. Maybe. */ + return 0; + + case GLUT_OVERLAY_DAMAGED: + return -1; + +#elif TARGET_HOST_MS_WINDOWS + + case GLUT_OVERLAY_POSSIBLE: +/* return fgSetupPixelFormat( fgStructure.CurrentWindow, GL_TRUE, + PFD_OVERLAY_PLANE ); */ + return 0 ; + + case GLUT_LAYER_IN_USE: + return GLUT_NORMAL; + + case GLUT_HAS_OVERLAY: + return 0; + + case GLUT_TRANSPARENT_INDEX: + /* + * Return just anything, which is always defined as zero + * + * XXX HUH? + */ + return 0; + + case GLUT_NORMAL_DAMAGED: + /* XXX Actually I do not know. Maybe. */ + return 0; + + case GLUT_OVERLAY_DAMAGED: + return -1; +#endif + + default: + fgWarning( "glutLayerGet(): missing enum handle %d", eWhat ); + break; + } + + /* And fail. That's good. Programs do love failing. */ + return -1; +} + +int * FGAPIENTRY glutGetModeValues(GLenum eWhat, int * size) +{ + int * array; + +#if TARGET_HOST_POSIX_X11 + int attributes[9]; + GLXFBConfig * fbconfigArray; /* Array of FBConfigs */ + int fbconfigArraySize; /* Number of FBConfigs in the array */ + int attribute_name = 0; +#endif + + FREEGLUT_EXIT_IF_NOT_INITIALISED("glutGetModeValues"); + + array = NULL; + *size = 0; + + switch (eWhat) + { +#if TARGET_HOST_POSIX_X11 + case GLUT_AUX: + case GLUT_MULTISAMPLE: + + attributes[0] = GLX_BUFFER_SIZE; + attributes[1] = GLX_DONT_CARE; + + switch (eWhat) + { + case GLUT_AUX: + /* + FBConfigs are now sorted by increasing number of auxiliary + buffers. We want at least one buffer. + */ + attributes[2] = GLX_AUX_BUFFERS; + attributes[3] = 1; + attributes[4] = None; + + attribute_name = GLX_AUX_BUFFERS; + + break; + + + case GLUT_MULTISAMPLE: + attributes[2] = GLX_AUX_BUFFERS; + attributes[3] = GLX_DONT_CARE; + attributes[4] = GLX_SAMPLE_BUFFERS; + attributes[5] = 1; + /* + FBConfigs are now sorted by increasing number of samples per + pixel. We want at least one sample. + */ + attributes[6] = GLX_SAMPLES; + attributes[7] = 1; + attributes[8] = None; + + attribute_name = GLX_SAMPLES; + + break; + } + + fbconfigArray = glXChooseFBConfig(fgDisplay.Display, + fgDisplay.Screen, + attributes, + &fbconfigArraySize); + + if (fbconfigArray != NULL) + { + int * temp_array; + int result; /* Returned by glXGetFBConfigAttrib. Not checked. */ + int previous_value; + int i; + + temp_array = malloc(sizeof(int) * fbconfigArraySize); + previous_value = 0; + + for (i = 0; i < fbconfigArraySize; i++) + { + int value; + + result = glXGetFBConfigAttrib(fgDisplay.Display, + fbconfigArray[i], + attribute_name, + &value); + if (value > previous_value) + { + temp_array[*size] = value; + previous_value = value; + (*size)++; + } + } + + array = malloc(sizeof(int) * (*size)); + for (i = 0; i < *size; i++) + { + array[i] = temp_array[i]; + } + + free(temp_array); + XFree(fbconfigArray); + } + + break; +#endif + + default: + break; + } + + return array; +} + +/*** END OF FILE ***/ diff --git a/tests/box2d/freeglut/freeglut_std.h b/tests/box2d/freeglut/freeglut_std.h new file mode 100755 index 00000000..3a4207fa --- /dev/null +++ b/tests/box2d/freeglut/freeglut_std.h @@ -0,0 +1,583 @@ +#ifndef __FREEGLUT_STD_H__ +#define __FREEGLUT_STD_H__ + +/* + * freeglut_std.h + * + * The GLUT-compatible part of the freeglut library include file + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, <olszta@sourceforge.net> + * Creation date: Thu Dec 2 1999 + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifdef __cplusplus + extern "C" { +#endif + +#define FGAPI +#define FGAPIENTRY + +/* + * Under windows, we have to differentiate between static and dynamic libraries + */ +#ifdef _WIN32 +/* #pragma may not be supported by some compilers. + * Discussion by FreeGLUT developers suggests that + * Visual C++ specific code involving pragmas may + * need to move to a separate header. 24th Dec 2003 + */ + + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN 1 + #endif + + #define NOMINMAX + #include <windows.h> + +/* Drag in other Windows libraries as required by FreeGLUT */ +// # if FREEGLUT_LIB_PRAGMAS +// # pragma comment (lib, "glu32.lib") /* link OpenGL Utility lib */ +// # pragma comment (lib, "opengl32.lib") /* link Microsoft OpenGL lib */ +// # pragma comment (lib, "gdi32.lib") /* link Windows GDI lib */ +// # pragma comment (lib, "winmm.lib") /* link Windows MultiMedia lib */ +// # pragma comment (lib, "user32.lib") /* link Windows user lib */ +// # endif + +#endif + +/* + * The freeglut and GLUT API versions + */ +#define FREEGLUT 1 +#define GLUT_API_VERSION 4 +#define FREEGLUT_VERSION_2_0 1 +#define GLUT_XLIB_IMPLEMENTATION 13 + +/* + * Always include OpenGL and GLU headers + */ +#include <GL/gl.h> +#include <GL/glu.h> + +/* + * GLUT API macro definitions -- the special key codes: + */ +#define GLUT_KEY_F1 0x0001 +#define GLUT_KEY_F2 0x0002 +#define GLUT_KEY_F3 0x0003 +#define GLUT_KEY_F4 0x0004 +#define GLUT_KEY_F5 0x0005 +#define GLUT_KEY_F6 0x0006 +#define GLUT_KEY_F7 0x0007 +#define GLUT_KEY_F8 0x0008 +#define GLUT_KEY_F9 0x0009 +#define GLUT_KEY_F10 0x000A +#define GLUT_KEY_F11 0x000B +#define GLUT_KEY_F12 0x000C +#define GLUT_KEY_LEFT 0x0064 +#define GLUT_KEY_UP 0x0065 +#define GLUT_KEY_RIGHT 0x0066 +#define GLUT_KEY_DOWN 0x0067 +#define GLUT_KEY_PAGE_UP 0x0068 +#define GLUT_KEY_PAGE_DOWN 0x0069 +#define GLUT_KEY_HOME 0x006A +#define GLUT_KEY_END 0x006B +#define GLUT_KEY_INSERT 0x006C + +/* + * GLUT API macro definitions -- mouse state definitions + */ +#define GLUT_LEFT_BUTTON 0x0000 +#define GLUT_MIDDLE_BUTTON 0x0001 +#define GLUT_RIGHT_BUTTON 0x0002 +#define GLUT_DOWN 0x0000 +#define GLUT_UP 0x0001 +#define GLUT_LEFT 0x0000 +#define GLUT_ENTERED 0x0001 + +/* + * GLUT API macro definitions -- the display mode definitions + */ +#define GLUT_RGB 0x0000 +#define GLUT_RGBA 0x0000 +#define GLUT_INDEX 0x0001 +#define GLUT_SINGLE 0x0000 +#define GLUT_DOUBLE 0x0002 +#define GLUT_ACCUM 0x0004 +#define GLUT_ALPHA 0x0008 +#define GLUT_DEPTH 0x0010 +#define GLUT_STENCIL 0x0020 +#define GLUT_MULTISAMPLE 0x0080 +#define GLUT_STEREO 0x0100 +#define GLUT_LUMINANCE 0x0200 + +/* + * GLUT API macro definitions -- windows and menu related definitions + */ +#define GLUT_MENU_NOT_IN_USE 0x0000 +#define GLUT_MENU_IN_USE 0x0001 +#define GLUT_NOT_VISIBLE 0x0000 +#define GLUT_VISIBLE 0x0001 +#define GLUT_HIDDEN 0x0000 +#define GLUT_FULLY_RETAINED 0x0001 +#define GLUT_PARTIALLY_RETAINED 0x0002 +#define GLUT_FULLY_COVERED 0x0003 + +/* + * GLUT API macro definitions -- fonts definitions + * + * Steve Baker suggested to make it binary compatible with GLUT: + */ +#if defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__WATCOMC__) +# define GLUT_STROKE_ROMAN ((void *)0x0000) +# define GLUT_STROKE_MONO_ROMAN ((void *)0x0001) +# define GLUT_BITMAP_9_BY_15 ((void *)0x0002) +# define GLUT_BITMAP_8_BY_13 ((void *)0x0003) +# define GLUT_BITMAP_TIMES_ROMAN_10 ((void *)0x0004) +# define GLUT_BITMAP_TIMES_ROMAN_24 ((void *)0x0005) +# define GLUT_BITMAP_HELVETICA_10 ((void *)0x0006) +# define GLUT_BITMAP_HELVETICA_12 ((void *)0x0007) +# define GLUT_BITMAP_HELVETICA_18 ((void *)0x0008) +#else + /* + * I don't really know if it's a good idea... But here it goes: + */ + extern void* glutStrokeRoman; + extern void* glutStrokeMonoRoman; + extern void* glutBitmap9By15; + extern void* glutBitmap8By13; + extern void* glutBitmapTimesRoman10; + extern void* glutBitmapTimesRoman24; + extern void* glutBitmapHelvetica10; + extern void* glutBitmapHelvetica12; + extern void* glutBitmapHelvetica18; + + /* + * Those pointers will be used by following definitions: + */ +# define GLUT_STROKE_ROMAN ((void *) &glutStrokeRoman) +# define GLUT_STROKE_MONO_ROMAN ((void *) &glutStrokeMonoRoman) +# define GLUT_BITMAP_9_BY_15 ((void *) &glutBitmap9By15) +# define GLUT_BITMAP_8_BY_13 ((void *) &glutBitmap8By13) +# define GLUT_BITMAP_TIMES_ROMAN_10 ((void *) &glutBitmapTimesRoman10) +# define GLUT_BITMAP_TIMES_ROMAN_24 ((void *) &glutBitmapTimesRoman24) +# define GLUT_BITMAP_HELVETICA_10 ((void *) &glutBitmapHelvetica10) +# define GLUT_BITMAP_HELVETICA_12 ((void *) &glutBitmapHelvetica12) +# define GLUT_BITMAP_HELVETICA_18 ((void *) &glutBitmapHelvetica18) +#endif + +/* + * GLUT API macro definitions -- the glutGet parameters + */ +#define GLUT_WINDOW_X 0x0064 +#define GLUT_WINDOW_Y 0x0065 +#define GLUT_WINDOW_WIDTH 0x0066 +#define GLUT_WINDOW_HEIGHT 0x0067 +#define GLUT_WINDOW_BUFFER_SIZE 0x0068 +#define GLUT_WINDOW_STENCIL_SIZE 0x0069 +#define GLUT_WINDOW_DEPTH_SIZE 0x006A +#define GLUT_WINDOW_RED_SIZE 0x006B +#define GLUT_WINDOW_GREEN_SIZE 0x006C +#define GLUT_WINDOW_BLUE_SIZE 0x006D +#define GLUT_WINDOW_ALPHA_SIZE 0x006E +#define GLUT_WINDOW_ACCUM_RED_SIZE 0x006F +#define GLUT_WINDOW_ACCUM_GREEN_SIZE 0x0070 +#define GLUT_WINDOW_ACCUM_BLUE_SIZE 0x0071 +#define GLUT_WINDOW_ACCUM_ALPHA_SIZE 0x0072 +#define GLUT_WINDOW_DOUBLEBUFFER 0x0073 +#define GLUT_WINDOW_RGBA 0x0074 +#define GLUT_WINDOW_PARENT 0x0075 +#define GLUT_WINDOW_NUM_CHILDREN 0x0076 +#define GLUT_WINDOW_COLORMAP_SIZE 0x0077 +#define GLUT_WINDOW_NUM_SAMPLES 0x0078 +#define GLUT_WINDOW_STEREO 0x0079 +#define GLUT_WINDOW_CURSOR 0x007A + +#define GLUT_SCREEN_WIDTH 0x00C8 +#define GLUT_SCREEN_HEIGHT 0x00C9 +#define GLUT_SCREEN_WIDTH_MM 0x00CA +#define GLUT_SCREEN_HEIGHT_MM 0x00CB +#define GLUT_MENU_NUM_ITEMS 0x012C +#define GLUT_DISPLAY_MODE_POSSIBLE 0x0190 +#define GLUT_INIT_WINDOW_X 0x01F4 +#define GLUT_INIT_WINDOW_Y 0x01F5 +#define GLUT_INIT_WINDOW_WIDTH 0x01F6 +#define GLUT_INIT_WINDOW_HEIGHT 0x01F7 +#define GLUT_INIT_DISPLAY_MODE 0x01F8 +#define GLUT_ELAPSED_TIME 0x02BC +#define GLUT_WINDOW_FORMAT_ID 0x007B + +/* + * GLUT API macro definitions -- the glutDeviceGet parameters + */ +#define GLUT_HAS_KEYBOARD 0x0258 +#define GLUT_HAS_MOUSE 0x0259 +#define GLUT_HAS_SPACEBALL 0x025A +#define GLUT_HAS_DIAL_AND_BUTTON_BOX 0x025B +#define GLUT_HAS_TABLET 0x025C +#define GLUT_NUM_MOUSE_BUTTONS 0x025D +#define GLUT_NUM_SPACEBALL_BUTTONS 0x025E +#define GLUT_NUM_BUTTON_BOX_BUTTONS 0x025F +#define GLUT_NUM_DIALS 0x0260 +#define GLUT_NUM_TABLET_BUTTONS 0x0261 +#define GLUT_DEVICE_IGNORE_KEY_REPEAT 0x0262 +#define GLUT_DEVICE_KEY_REPEAT 0x0263 +#define GLUT_HAS_JOYSTICK 0x0264 +#define GLUT_OWNS_JOYSTICK 0x0265 +#define GLUT_JOYSTICK_BUTTONS 0x0266 +#define GLUT_JOYSTICK_AXES 0x0267 +#define GLUT_JOYSTICK_POLL_RATE 0x0268 + +/* + * GLUT API macro definitions -- the glutLayerGet parameters + */ +#define GLUT_OVERLAY_POSSIBLE 0x0320 +#define GLUT_LAYER_IN_USE 0x0321 +#define GLUT_HAS_OVERLAY 0x0322 +#define GLUT_TRANSPARENT_INDEX 0x0323 +#define GLUT_NORMAL_DAMAGED 0x0324 +#define GLUT_OVERLAY_DAMAGED 0x0325 + +/* + * GLUT API macro definitions -- the glutVideoResizeGet parameters + */ +#define GLUT_VIDEO_RESIZE_POSSIBLE 0x0384 +#define GLUT_VIDEO_RESIZE_IN_USE 0x0385 +#define GLUT_VIDEO_RESIZE_X_DELTA 0x0386 +#define GLUT_VIDEO_RESIZE_Y_DELTA 0x0387 +#define GLUT_VIDEO_RESIZE_WIDTH_DELTA 0x0388 +#define GLUT_VIDEO_RESIZE_HEIGHT_DELTA 0x0389 +#define GLUT_VIDEO_RESIZE_X 0x038A +#define GLUT_VIDEO_RESIZE_Y 0x038B +#define GLUT_VIDEO_RESIZE_WIDTH 0x038C +#define GLUT_VIDEO_RESIZE_HEIGHT 0x038D + +/* + * GLUT API macro definitions -- the glutUseLayer parameters + */ +#define GLUT_NORMAL 0x0000 +#define GLUT_OVERLAY 0x0001 + +/* + * GLUT API macro definitions -- the glutGetModifiers parameters + */ +#define GLUT_ACTIVE_SHIFT 0x0001 +#define GLUT_ACTIVE_CTRL 0x0002 +#define GLUT_ACTIVE_ALT 0x0004 + +/* + * GLUT API macro definitions -- the glutSetCursor parameters + */ +#define GLUT_CURSOR_RIGHT_ARROW 0x0000 +#define GLUT_CURSOR_LEFT_ARROW 0x0001 +#define GLUT_CURSOR_INFO 0x0002 +#define GLUT_CURSOR_DESTROY 0x0003 +#define GLUT_CURSOR_HELP 0x0004 +#define GLUT_CURSOR_CYCLE 0x0005 +#define GLUT_CURSOR_SPRAY 0x0006 +#define GLUT_CURSOR_WAIT 0x0007 +#define GLUT_CURSOR_TEXT 0x0008 +#define GLUT_CURSOR_CROSSHAIR 0x0009 +#define GLUT_CURSOR_UP_DOWN 0x000A +#define GLUT_CURSOR_LEFT_RIGHT 0x000B +#define GLUT_CURSOR_TOP_SIDE 0x000C +#define GLUT_CURSOR_BOTTOM_SIDE 0x000D +#define GLUT_CURSOR_LEFT_SIDE 0x000E +#define GLUT_CURSOR_RIGHT_SIDE 0x000F +#define GLUT_CURSOR_TOP_LEFT_CORNER 0x0010 +#define GLUT_CURSOR_TOP_RIGHT_CORNER 0x0011 +#define GLUT_CURSOR_BOTTOM_RIGHT_CORNER 0x0012 +#define GLUT_CURSOR_BOTTOM_LEFT_CORNER 0x0013 +#define GLUT_CURSOR_INHERIT 0x0064 +#define GLUT_CURSOR_NONE 0x0065 +#define GLUT_CURSOR_FULL_CROSSHAIR 0x0066 + +/* + * GLUT API macro definitions -- RGB color component specification definitions + */ +#define GLUT_RED 0x0000 +#define GLUT_GREEN 0x0001 +#define GLUT_BLUE 0x0002 + +/* + * GLUT API macro definitions -- additional keyboard and joystick definitions + */ +#define GLUT_KEY_REPEAT_OFF 0x0000 +#define GLUT_KEY_REPEAT_ON 0x0001 +#define GLUT_KEY_REPEAT_DEFAULT 0x0002 + +#define GLUT_JOYSTICK_BUTTON_A 0x0001 +#define GLUT_JOYSTICK_BUTTON_B 0x0002 +#define GLUT_JOYSTICK_BUTTON_C 0x0004 +#define GLUT_JOYSTICK_BUTTON_D 0x0008 + +/* + * GLUT API macro definitions -- game mode definitions + */ +#define GLUT_GAME_MODE_ACTIVE 0x0000 +#define GLUT_GAME_MODE_POSSIBLE 0x0001 +#define GLUT_GAME_MODE_WIDTH 0x0002 +#define GLUT_GAME_MODE_HEIGHT 0x0003 +#define GLUT_GAME_MODE_PIXEL_DEPTH 0x0004 +#define GLUT_GAME_MODE_REFRESH_RATE 0x0005 +#define GLUT_GAME_MODE_DISPLAY_CHANGED 0x0006 + +/* + * Initialization functions, see fglut_init.c + */ +FGAPI void FGAPIENTRY glutInit( int* pargc, char** argv ); +FGAPI void FGAPIENTRY glutInitWindowPosition( int x, int y ); +FGAPI void FGAPIENTRY glutInitWindowSize( int width, int height ); +FGAPI void FGAPIENTRY glutInitDisplayMode( unsigned int displayMode ); +FGAPI void FGAPIENTRY glutInitDisplayString( const char* displayMode ); + +/* + * Process loop function, see freeglut_main.c + */ +FGAPI void FGAPIENTRY glutMainLoop( void ); + +/* + * Window management functions, see freeglut_window.c + */ +FGAPI int FGAPIENTRY glutCreateWindow( const char* title ); +FGAPI int FGAPIENTRY glutCreateSubWindow( int window, int x, int y, int width, int height ); +FGAPI void FGAPIENTRY glutDestroyWindow( int window ); +FGAPI void FGAPIENTRY glutSetWindow( int window ); +FGAPI int FGAPIENTRY glutGetWindow( void ); +FGAPI void FGAPIENTRY glutSetWindowTitle( const char* title ); +FGAPI void FGAPIENTRY glutSetIconTitle( const char* title ); +FGAPI void FGAPIENTRY glutReshapeWindow( int width, int height ); +FGAPI void FGAPIENTRY glutPositionWindow( int x, int y ); +FGAPI void FGAPIENTRY glutShowWindow( void ); +FGAPI void FGAPIENTRY glutHideWindow( void ); +FGAPI void FGAPIENTRY glutIconifyWindow( void ); +FGAPI void FGAPIENTRY glutPushWindow( void ); +FGAPI void FGAPIENTRY glutPopWindow( void ); +FGAPI void FGAPIENTRY glutFullScreen( void ); + +/* + * Display-connected functions, see freeglut_display.c + */ +FGAPI void FGAPIENTRY glutPostWindowRedisplay( int window ); +FGAPI void FGAPIENTRY glutPostRedisplay( void ); +FGAPI void FGAPIENTRY glutSwapBuffers( void ); + +/* + * Mouse cursor functions, see freeglut_cursor.c + */ +FGAPI void FGAPIENTRY glutWarpPointer( int x, int y ); +FGAPI void FGAPIENTRY glutSetCursor( int cursor ); + +/* + * Overlay stuff, see freeglut_overlay.c + */ +FGAPI void FGAPIENTRY glutEstablishOverlay( void ); +FGAPI void FGAPIENTRY glutRemoveOverlay( void ); +FGAPI void FGAPIENTRY glutUseLayer( GLenum layer ); +FGAPI void FGAPIENTRY glutPostOverlayRedisplay( void ); +FGAPI void FGAPIENTRY glutPostWindowOverlayRedisplay( int window ); +FGAPI void FGAPIENTRY glutShowOverlay( void ); +FGAPI void FGAPIENTRY glutHideOverlay( void ); + +/* + * Menu stuff, see freeglut_menu.c + */ +FGAPI int FGAPIENTRY glutCreateMenu( void (* callback)( int menu ) ); +FGAPI void FGAPIENTRY glutDestroyMenu( int menu ); +FGAPI int FGAPIENTRY glutGetMenu( void ); +FGAPI void FGAPIENTRY glutSetMenu( int menu ); +FGAPI void FGAPIENTRY glutAddMenuEntry( const char* label, int value ); +FGAPI void FGAPIENTRY glutAddSubMenu( const char* label, int subMenu ); +FGAPI void FGAPIENTRY glutChangeToMenuEntry( int item, const char* label, int value ); +FGAPI void FGAPIENTRY glutChangeToSubMenu( int item, const char* label, int value ); +FGAPI void FGAPIENTRY glutRemoveMenuItem( int item ); +FGAPI void FGAPIENTRY glutAttachMenu( int button ); +FGAPI void FGAPIENTRY glutDetachMenu( int button ); + +/* + * Global callback functions, see freeglut_callbacks.c + */ +FGAPI void FGAPIENTRY glutTimerFunc( unsigned int time, void (* callback)( int ), int value ); +FGAPI void FGAPIENTRY glutIdleFunc( void (* callback)( void ) ); + +/* + * Window-specific callback functions, see freeglut_callbacks.c + */ +FGAPI void FGAPIENTRY glutKeyboardFunc( void (* callback)( unsigned char, int, int ) ); +FGAPI void FGAPIENTRY glutSpecialFunc( void (* callback)( int, int, int ) ); +FGAPI void FGAPIENTRY glutReshapeFunc( void (* callback)( int, int ) ); +FGAPI void FGAPIENTRY glutVisibilityFunc( void (* callback)( int ) ); +FGAPI void FGAPIENTRY glutDisplayFunc( void (* callback)( void ) ); +FGAPI void FGAPIENTRY glutMouseFunc( void (* callback)( int, int, int, int ) ); +FGAPI void FGAPIENTRY glutMotionFunc( void (* callback)( int, int ) ); +FGAPI void FGAPIENTRY glutPassiveMotionFunc( void (* callback)( int, int ) ); +FGAPI void FGAPIENTRY glutEntryFunc( void (* callback)( int ) ); + +FGAPI void FGAPIENTRY glutKeyboardUpFunc( void (* callback)( unsigned char, int, int ) ); +FGAPI void FGAPIENTRY glutSpecialUpFunc( void (* callback)( int, int, int ) ); +FGAPI void FGAPIENTRY glutJoystickFunc( void (* callback)( unsigned int, int, int, int ), int pollInterval ); +FGAPI void FGAPIENTRY glutMenuStateFunc( void (* callback)( int ) ); +FGAPI void FGAPIENTRY glutMenuStatusFunc( void (* callback)( int, int, int ) ); +FGAPI void FGAPIENTRY glutOverlayDisplayFunc( void (* callback)( void ) ); +FGAPI void FGAPIENTRY glutWindowStatusFunc( void (* callback)( int ) ); + +FGAPI void FGAPIENTRY glutSpaceballMotionFunc( void (* callback)( int, int, int ) ); +FGAPI void FGAPIENTRY glutSpaceballRotateFunc( void (* callback)( int, int, int ) ); +FGAPI void FGAPIENTRY glutSpaceballButtonFunc( void (* callback)( int, int ) ); +FGAPI void FGAPIENTRY glutButtonBoxFunc( void (* callback)( int, int ) ); +FGAPI void FGAPIENTRY glutDialsFunc( void (* callback)( int, int ) ); +FGAPI void FGAPIENTRY glutTabletMotionFunc( void (* callback)( int, int ) ); +FGAPI void FGAPIENTRY glutTabletButtonFunc( void (* callback)( int, int, int, int ) ); + +/* + * State setting and retrieval functions, see freeglut_state.c + */ +FGAPI int FGAPIENTRY glutGet( GLenum query ); +FGAPI int FGAPIENTRY glutDeviceGet( GLenum query ); +FGAPI int FGAPIENTRY glutGetModifiers( void ); +FGAPI int FGAPIENTRY glutLayerGet( GLenum query ); + +/* + * Font stuff, see freeglut_font.c + */ +FGAPI void FGAPIENTRY glutBitmapCharacter( void* font, int character ); +FGAPI int FGAPIENTRY glutBitmapWidth( void* font, int character ); +FGAPI void FGAPIENTRY glutStrokeCharacter( void* font, int character ); +FGAPI int FGAPIENTRY glutStrokeWidth( void* font, int character ); +FGAPI int FGAPIENTRY glutBitmapLength( void* font, const unsigned char* string ); +FGAPI int FGAPIENTRY glutStrokeLength( void* font, const unsigned char* string ); + +/* + * Geometry functions, see freeglut_geometry.c + */ +FGAPI void FGAPIENTRY glutWireCube( GLdouble size ); +FGAPI void FGAPIENTRY glutSolidCube( GLdouble size ); +FGAPI void FGAPIENTRY glutWireSphere( GLdouble radius, GLint slices, GLint stacks ); +FGAPI void FGAPIENTRY glutSolidSphere( GLdouble radius, GLint slices, GLint stacks ); +FGAPI void FGAPIENTRY glutWireCone( GLdouble base, GLdouble height, GLint slices, GLint stacks ); +FGAPI void FGAPIENTRY glutSolidCone( GLdouble base, GLdouble height, GLint slices, GLint stacks ); + +FGAPI void FGAPIENTRY glutWireTorus( GLdouble innerRadius, GLdouble outerRadius, GLint sides, GLint rings ); +FGAPI void FGAPIENTRY glutSolidTorus( GLdouble innerRadius, GLdouble outerRadius, GLint sides, GLint rings ); +FGAPI void FGAPIENTRY glutWireDodecahedron( void ); +FGAPI void FGAPIENTRY glutSolidDodecahedron( void ); +FGAPI void FGAPIENTRY glutWireOctahedron( void ); +FGAPI void FGAPIENTRY glutSolidOctahedron( void ); +FGAPI void FGAPIENTRY glutWireTetrahedron( void ); +FGAPI void FGAPIENTRY glutSolidTetrahedron( void ); +FGAPI void FGAPIENTRY glutWireIcosahedron( void ); +FGAPI void FGAPIENTRY glutSolidIcosahedron( void ); + +/* + * Teapot rendering functions, found in freeglut_teapot.c + */ +FGAPI void FGAPIENTRY glutWireTeapot( GLdouble size ); +FGAPI void FGAPIENTRY glutSolidTeapot( GLdouble size ); + +/* + * Game mode functions, see freeglut_gamemode.c + */ +FGAPI void FGAPIENTRY glutGameModeString( const char* string ); +FGAPI int FGAPIENTRY glutEnterGameMode( void ); +FGAPI void FGAPIENTRY glutLeaveGameMode( void ); +FGAPI int FGAPIENTRY glutGameModeGet( GLenum query ); + +/* + * Video resize functions, see freeglut_videoresize.c + */ +FGAPI int FGAPIENTRY glutVideoResizeGet( GLenum query ); +FGAPI void FGAPIENTRY glutSetupVideoResizing( void ); +FGAPI void FGAPIENTRY glutStopVideoResizing( void ); +FGAPI void FGAPIENTRY glutVideoResize( int x, int y, int width, int height ); +FGAPI void FGAPIENTRY glutVideoPan( int x, int y, int width, int height ); + +/* + * Colormap functions, see freeglut_misc.c + */ +FGAPI void FGAPIENTRY glutSetColor( int color, GLfloat red, GLfloat green, GLfloat blue ); +FGAPI GLfloat FGAPIENTRY glutGetColor( int color, int component ); +FGAPI void FGAPIENTRY glutCopyColormap( int window ); + +/* + * Misc keyboard and joystick functions, see freeglut_misc.c + */ +FGAPI void FGAPIENTRY glutIgnoreKeyRepeat( int ignore ); +FGAPI void FGAPIENTRY glutSetKeyRepeat( int repeatMode ); +FGAPI void FGAPIENTRY glutForceJoystickFunc( void ); + +/* + * Misc functions, see freeglut_misc.c + */ +FGAPI int FGAPIENTRY glutExtensionSupported( const char* extension ); +FGAPI void FGAPIENTRY glutReportErrors( void ); + +/* Comment from glut.h of classic GLUT: + + Win32 has an annoying issue where there are multiple C run-time + libraries (CRTs). If the executable is linked with a different CRT + from the GLUT DLL, the GLUT DLL will not share the same CRT static + data seen by the executable. In particular, atexit callbacks registered + in the executable will not be called if GLUT calls its (different) + exit routine). GLUT is typically built with the + "/MD" option (the CRT with multithreading DLL support), but the Visual + C++ linker default is "/ML" (the single threaded CRT). + + One workaround to this issue is requiring users to always link with + the same CRT as GLUT is compiled with. That requires users supply a + non-standard option. GLUT 3.7 has its own built-in workaround where + the executable's "exit" function pointer is covertly passed to GLUT. + GLUT then calls the executable's exit function pointer to ensure that + any "atexit" calls registered by the application are called if GLUT + needs to exit. + + Note that the __glut*WithExit routines should NEVER be called directly. + To avoid the atexit workaround, #define GLUT_DISABLE_ATEXIT_HACK. */ + +/* to get the prototype for exit() */ +#include <stdlib.h> + +#if defined(_WIN32) && !defined(GLUT_DISABLE_ATEXIT_HACK) && !defined(__WATCOMC__) +FGAPI void FGAPIENTRY __glutInitWithExit(int *argcp, char **argv, void (__cdecl *exitfunc)(int)); +FGAPI int FGAPIENTRY __glutCreateWindowWithExit(const char *title, void (__cdecl *exitfunc)(int)); +FGAPI int FGAPIENTRY __glutCreateMenuWithExit(void (* func)(int), void (__cdecl *exitfunc)(int)); +#ifndef FREEGLUT_BUILDING_LIB +#if defined(__GNUC__) +#define FGUNUSED __attribute__((unused)) +#else +#define FGUNUSED +#endif +static void FGAPIENTRY FGUNUSED glutInit_ATEXIT_HACK(int *argcp, char **argv) { __glutInitWithExit(argcp, argv, exit); } +#define glutInit glutInit_ATEXIT_HACK +static int FGAPIENTRY FGUNUSED glutCreateWindow_ATEXIT_HACK(const char *title) { return __glutCreateWindowWithExit(title, exit); } +#define glutCreateWindow glutCreateWindow_ATEXIT_HACK +static int FGAPIENTRY FGUNUSED glutCreateMenu_ATEXIT_HACK(void (* func)(int)) { return __glutCreateMenuWithExit(func, exit); } +#define glutCreateMenu glutCreateMenu_ATEXIT_HACK +#endif +#endif + +#ifdef __cplusplus + } +#endif + +/*** END OF FILE ***/ + +#endif /* __FREEGLUT_STD_H__ */ + diff --git a/tests/box2d/freeglut/freeglut_stroke_mono_roman.c b/tests/box2d/freeglut/freeglut_stroke_mono_roman.c new file mode 100755 index 00000000..f2a0d6d6 --- /dev/null +++ b/tests/box2d/freeglut/freeglut_stroke_mono_roman.c @@ -0,0 +1,2849 @@ +/* + * freeglut_stroke_mono_roman.c + * + * freeglut Monospace Roman stroke font definition + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, <olszta@sourceforge.net> + * Creation date: Thu Dec 16 1999 + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +/* This file has been automatically generated by the genstroke utility. */ + +#include "freeglut.h" +#include "freeglut_internal.h" + +/* char: 0x20 */ + +static const SFG_StrokeStrip ch32st[] = +{ + { 0, NULL } +}; + +static const SFG_StrokeChar ch32 = {104.762f,0,ch32st}; + +/* char: 0x21 */ + +static const SFG_StrokeVertex ch33st0[] = +{ + {52.381f,100.0f}, + {52.381f,33.3333f} +}; + +static const SFG_StrokeVertex ch33st1[] = +{ + {52.381f,9.5238f}, + {47.6191f,4.7619f}, + {52.381f,0.0f}, + {57.1429f,4.7619f}, + {52.381f,9.5238f} +}; + +static const SFG_StrokeStrip ch33st[] = +{ + {2,ch33st0}, + {5,ch33st1} +}; + +static const SFG_StrokeChar ch33 = {104.762f,2,ch33st}; + +/* char: 0x22 */ + +static const SFG_StrokeVertex ch34st0[] = +{ + {33.3334f,100.0f}, + {33.3334f,66.6667f} +}; + +static const SFG_StrokeVertex ch34st1[] = +{ + {71.4286f,100.0f}, + {71.4286f,66.6667f} +}; + +static const SFG_StrokeStrip ch34st[] = +{ + {2,ch34st0}, + {2,ch34st1} +}; + +static const SFG_StrokeChar ch34 = {104.762f,2,ch34st}; + +/* char: 0x23 */ + +static const SFG_StrokeVertex ch35st0[] = +{ + {54.7619f,119.048f}, + {21.4286f,-33.3333f} +}; + +static const SFG_StrokeVertex ch35st1[] = +{ + {83.3334f,119.048f}, + {50.0f,-33.3333f} +}; + +static const SFG_StrokeVertex ch35st2[] = +{ + {21.4286f,57.1429f}, + {88.0952f,57.1429f} +}; + +static const SFG_StrokeVertex ch35st3[] = +{ + {16.6667f,28.5714f}, + {83.3334f,28.5714f} +}; + +static const SFG_StrokeStrip ch35st[] = +{ + {2,ch35st0}, + {2,ch35st1}, + {2,ch35st2}, + {2,ch35st3} +}; + +static const SFG_StrokeChar ch35 = {104.762f,4,ch35st}; + +/* char: 0x24 */ + +static const SFG_StrokeVertex ch36st0[] = +{ + {42.8571f,119.048f}, + {42.8571f,-19.0476f} +}; + +static const SFG_StrokeVertex ch36st1[] = +{ + {61.9047f,119.048f}, + {61.9047f,-19.0476f} +}; + +static const SFG_StrokeVertex ch36st2[] = +{ + {85.7143f,85.7143f}, + {76.1905f,95.2381f}, + {61.9047f,100.0f}, + {42.8571f,100.0f}, + {28.5714f,95.2381f}, + {19.0476f,85.7143f}, + {19.0476f,76.1905f}, + {23.8095f,66.6667f}, + {28.5714f,61.9048f}, + {38.0952f,57.1429f}, + {66.6666f,47.619f}, + {76.1905f,42.8571f}, + {80.9524f,38.0952f}, + {85.7143f,28.5714f}, + {85.7143f,14.2857f}, + {76.1905f,4.7619f}, + {61.9047f,0.0f}, + {42.8571f,0.0f}, + {28.5714f,4.7619f}, + {19.0476f,14.2857f} +}; + +static const SFG_StrokeStrip ch36st[] = +{ + {2,ch36st0}, + {2,ch36st1}, + {20,ch36st2} +}; + +static const SFG_StrokeChar ch36 = {104.762f,3,ch36st}; + +/* char: 0x25 */ + +static const SFG_StrokeVertex ch37st0[] = +{ + {95.2381f,100.0f}, + {9.5238f,0.0f} +}; + +static const SFG_StrokeVertex ch37st1[] = +{ + {33.3333f,100.0f}, + {42.8571f,90.4762f}, + {42.8571f,80.9524f}, + {38.0952f,71.4286f}, + {28.5714f,66.6667f}, + {19.0476f,66.6667f}, + {9.5238f,76.1905f}, + {9.5238f,85.7143f}, + {14.2857f,95.2381f}, + {23.8095f,100.0f}, + {33.3333f,100.0f}, + {42.8571f,95.2381f}, + {57.1428f,90.4762f}, + {71.4286f,90.4762f}, + {85.7143f,95.2381f}, + {95.2381f,100.0f} +}; + +static const SFG_StrokeVertex ch37st2[] = +{ + {76.1905f,33.3333f}, + {66.6667f,28.5714f}, + {61.9048f,19.0476f}, + {61.9048f,9.5238f}, + {71.4286f,0.0f}, + {80.9524f,0.0f}, + {90.4762f,4.7619f}, + {95.2381f,14.2857f}, + {95.2381f,23.8095f}, + {85.7143f,33.3333f}, + {76.1905f,33.3333f} +}; + +static const SFG_StrokeStrip ch37st[] = +{ + {2,ch37st0}, + {16,ch37st1}, + {11,ch37st2} +}; + +static const SFG_StrokeChar ch37 = {104.762f,3,ch37st}; + +/* char: 0x26 */ + +static const SFG_StrokeVertex ch38st0[] = +{ + {100.0f,57.1429f}, + {100.0f,61.9048f}, + {95.2381f,66.6667f}, + {90.4762f,66.6667f}, + {85.7143f,61.9048f}, + {80.9524f,52.381f}, + {71.4286f,28.5714f}, + {61.9048f,14.2857f}, + {52.3809f,4.7619f}, + {42.8571f,0.0f}, + {23.8095f,0.0f}, + {14.2857f,4.7619f}, + {9.5238f,9.5238f}, + {4.7619f,19.0476f}, + {4.7619f,28.5714f}, + {9.5238f,38.0952f}, + {14.2857f,42.8571f}, + {47.619f,61.9048f}, + {52.3809f,66.6667f}, + {57.1429f,76.1905f}, + {57.1429f,85.7143f}, + {52.3809f,95.2381f}, + {42.8571f,100.0f}, + {33.3333f,95.2381f}, + {28.5714f,85.7143f}, + {28.5714f,76.1905f}, + {33.3333f,61.9048f}, + {42.8571f,47.619f}, + {66.6667f,14.2857f}, + {76.1905f,4.7619f}, + {85.7143f,0.0f}, + {95.2381f,0.0f}, + {100.0f,4.7619f}, + {100.0f,9.5238f} +}; + +static const SFG_StrokeStrip ch38st[] = +{ + {34,ch38st0} +}; + +static const SFG_StrokeChar ch38 = {104.762f,1,ch38st}; + +/* char: 0x27 */ + +static const SFG_StrokeVertex ch39st0[] = +{ + {52.381f,100.0f}, + {52.381f,66.6667f} +}; + +static const SFG_StrokeStrip ch39st[] = +{ + {2,ch39st0} +}; + +static const SFG_StrokeChar ch39 = {104.762f,1,ch39st}; + +/* char: 0x28 */ + +static const SFG_StrokeVertex ch40st0[] = +{ + {69.0476f,119.048f}, + {59.5238f,109.524f}, + {50.0f,95.2381f}, + {40.4762f,76.1905f}, + {35.7143f,52.381f}, + {35.7143f,33.3333f}, + {40.4762f,9.5238f}, + {50.0f,-9.5238f}, + {59.5238f,-23.8095f}, + {69.0476f,-33.3333f} +}; + +static const SFG_StrokeStrip ch40st[] = +{ + {10,ch40st0} +}; + +static const SFG_StrokeChar ch40 = {104.762f,1,ch40st}; + +/* char: 0x29 */ + +static const SFG_StrokeVertex ch41st0[] = +{ + {35.7143f,119.048f}, + {45.2381f,109.524f}, + {54.7619f,95.2381f}, + {64.2857f,76.1905f}, + {69.0476f,52.381f}, + {69.0476f,33.3333f}, + {64.2857f,9.5238f}, + {54.7619f,-9.5238f}, + {45.2381f,-23.8095f}, + {35.7143f,-33.3333f} +}; + +static const SFG_StrokeStrip ch41st[] = +{ + {10,ch41st0} +}; + +static const SFG_StrokeChar ch41 = {104.762f,1,ch41st}; + +/* char: 0x2a */ + +static const SFG_StrokeVertex ch42st0[] = +{ + {52.381f,71.4286f}, + {52.381f,14.2857f} +}; + +static const SFG_StrokeVertex ch42st1[] = +{ + {28.5715f,57.1429f}, + {76.1905f,28.5714f} +}; + +static const SFG_StrokeVertex ch42st2[] = +{ + {76.1905f,57.1429f}, + {28.5715f,28.5714f} +}; + +static const SFG_StrokeStrip ch42st[] = +{ + {2,ch42st0}, + {2,ch42st1}, + {2,ch42st2} +}; + +static const SFG_StrokeChar ch42 = {104.762f,3,ch42st}; + +/* char: 0x2b */ + +static const SFG_StrokeVertex ch43st0[] = +{ + {52.3809f,85.7143f}, + {52.3809f,0.0f} +}; + +static const SFG_StrokeVertex ch43st1[] = +{ + {9.5238f,42.8571f}, + {95.2381f,42.8571f} +}; + +static const SFG_StrokeStrip ch43st[] = +{ + {2,ch43st0}, + {2,ch43st1} +}; + +static const SFG_StrokeChar ch43 = {104.762f,2,ch43st}; + +/* char: 0x2c */ + +static const SFG_StrokeVertex ch44st0[] = +{ + {57.1429f,4.7619f}, + {52.381f,0.0f}, + {47.6191f,4.7619f}, + {52.381f,9.5238f}, + {57.1429f,4.7619f}, + {57.1429f,-4.7619f}, + {52.381f,-14.2857f}, + {47.6191f,-19.0476f} +}; + +static const SFG_StrokeStrip ch44st[] = +{ + {8,ch44st0} +}; + +static const SFG_StrokeChar ch44 = {104.762f,1,ch44st}; + +/* char: 0x2d */ + +static const SFG_StrokeVertex ch45st0[] = +{ + {9.5238f,42.8571f}, + {95.2381f,42.8571f} +}; + +static const SFG_StrokeStrip ch45st[] = +{ + {2,ch45st0} +}; + +static const SFG_StrokeChar ch45 = {104.762f,1,ch45st}; + +/* char: 0x2e */ + +static const SFG_StrokeVertex ch46st0[] = +{ + {52.381f,9.5238f}, + {47.6191f,4.7619f}, + {52.381f,0.0f}, + {57.1429f,4.7619f}, + {52.381f,9.5238f} +}; + +static const SFG_StrokeStrip ch46st[] = +{ + {5,ch46st0} +}; + +static const SFG_StrokeChar ch46 = {104.762f,1,ch46st}; + +/* char: 0x2f */ + +static const SFG_StrokeVertex ch47st0[] = +{ + {19.0476f,-14.2857f}, + {85.7143f,100.0f} +}; + +static const SFG_StrokeStrip ch47st[] = +{ + {2,ch47st0} +}; + +static const SFG_StrokeChar ch47 = {104.762f,1,ch47st}; + +/* char: 0x30 */ + +static const SFG_StrokeVertex ch48st0[] = +{ + {47.619f,100.0f}, + {33.3333f,95.2381f}, + {23.8095f,80.9524f}, + {19.0476f,57.1429f}, + {19.0476f,42.8571f}, + {23.8095f,19.0476f}, + {33.3333f,4.7619f}, + {47.619f,0.0f}, + {57.1428f,0.0f}, + {71.4286f,4.7619f}, + {80.9524f,19.0476f}, + {85.7143f,42.8571f}, + {85.7143f,57.1429f}, + {80.9524f,80.9524f}, + {71.4286f,95.2381f}, + {57.1428f,100.0f}, + {47.619f,100.0f} +}; + +static const SFG_StrokeStrip ch48st[] = +{ + {17,ch48st0} +}; + +static const SFG_StrokeChar ch48 = {104.762f,1,ch48st}; + +/* char: 0x31 */ + +static const SFG_StrokeVertex ch49st0[] = +{ + {40.4762f,80.9524f}, + {50.0f,85.7143f}, + {64.2857f,100.0f}, + {64.2857f,0.0f} +}; + +static const SFG_StrokeStrip ch49st[] = +{ + {4,ch49st0} +}; + +static const SFG_StrokeChar ch49 = {104.762f,1,ch49st}; + +/* char: 0x32 */ + +static const SFG_StrokeVertex ch50st0[] = +{ + {23.8095f,76.1905f}, + {23.8095f,80.9524f}, + {28.5714f,90.4762f}, + {33.3333f,95.2381f}, + {42.8571f,100.0f}, + {61.9047f,100.0f}, + {71.4286f,95.2381f}, + {76.1905f,90.4762f}, + {80.9524f,80.9524f}, + {80.9524f,71.4286f}, + {76.1905f,61.9048f}, + {66.6666f,47.619f}, + {19.0476f,0.0f}, + {85.7143f,0.0f} +}; + +static const SFG_StrokeStrip ch50st[] = +{ + {14,ch50st0} +}; + +static const SFG_StrokeChar ch50 = {104.762f,1,ch50st}; + +/* char: 0x33 */ + +static const SFG_StrokeVertex ch51st0[] = +{ + {28.5714f,100.0f}, + {80.9524f,100.0f}, + {52.3809f,61.9048f}, + {66.6666f,61.9048f}, + {76.1905f,57.1429f}, + {80.9524f,52.381f}, + {85.7143f,38.0952f}, + {85.7143f,28.5714f}, + {80.9524f,14.2857f}, + {71.4286f,4.7619f}, + {57.1428f,0.0f}, + {42.8571f,0.0f}, + {28.5714f,4.7619f}, + {23.8095f,9.5238f}, + {19.0476f,19.0476f} +}; + +static const SFG_StrokeStrip ch51st[] = +{ + {15,ch51st0} +}; + +static const SFG_StrokeChar ch51 = {104.762f,1,ch51st}; + +/* char: 0x34 */ + +static const SFG_StrokeVertex ch52st0[] = +{ + {64.2857f,100.0f}, + {16.6667f,33.3333f}, + {88.0952f,33.3333f} +}; + +static const SFG_StrokeVertex ch52st1[] = +{ + {64.2857f,100.0f}, + {64.2857f,0.0f} +}; + +static const SFG_StrokeStrip ch52st[] = +{ + {3,ch52st0}, + {2,ch52st1} +}; + +static const SFG_StrokeChar ch52 = {104.762f,2,ch52st}; + +/* char: 0x35 */ + +static const SFG_StrokeVertex ch53st0[] = +{ + {76.1905f,100.0f}, + {28.5714f,100.0f}, + {23.8095f,57.1429f}, + {28.5714f,61.9048f}, + {42.8571f,66.6667f}, + {57.1428f,66.6667f}, + {71.4286f,61.9048f}, + {80.9524f,52.381f}, + {85.7143f,38.0952f}, + {85.7143f,28.5714f}, + {80.9524f,14.2857f}, + {71.4286f,4.7619f}, + {57.1428f,0.0f}, + {42.8571f,0.0f}, + {28.5714f,4.7619f}, + {23.8095f,9.5238f}, + {19.0476f,19.0476f} +}; + +static const SFG_StrokeStrip ch53st[] = +{ + {17,ch53st0} +}; + +static const SFG_StrokeChar ch53 = {104.762f,1,ch53st}; + +/* char: 0x36 */ + +static const SFG_StrokeVertex ch54st0[] = +{ + {78.5714f,85.7143f}, + {73.8096f,95.2381f}, + {59.5238f,100.0f}, + {50.0f,100.0f}, + {35.7143f,95.2381f}, + {26.1905f,80.9524f}, + {21.4286f,57.1429f}, + {21.4286f,33.3333f}, + {26.1905f,14.2857f}, + {35.7143f,4.7619f}, + {50.0f,0.0f}, + {54.7619f,0.0f}, + {69.0476f,4.7619f}, + {78.5714f,14.2857f}, + {83.3334f,28.5714f}, + {83.3334f,33.3333f}, + {78.5714f,47.619f}, + {69.0476f,57.1429f}, + {54.7619f,61.9048f}, + {50.0f,61.9048f}, + {35.7143f,57.1429f}, + {26.1905f,47.619f}, + {21.4286f,33.3333f} +}; + +static const SFG_StrokeStrip ch54st[] = +{ + {23,ch54st0} +}; + +static const SFG_StrokeChar ch54 = {104.762f,1,ch54st}; + +/* char: 0x37 */ + +static const SFG_StrokeVertex ch55st0[] = +{ + {85.7143f,100.0f}, + {38.0952f,0.0f} +}; + +static const SFG_StrokeVertex ch55st1[] = +{ + {19.0476f,100.0f}, + {85.7143f,100.0f} +}; + +static const SFG_StrokeStrip ch55st[] = +{ + {2,ch55st0}, + {2,ch55st1} +}; + +static const SFG_StrokeChar ch55 = {104.762f,2,ch55st}; + +/* char: 0x38 */ + +static const SFG_StrokeVertex ch56st0[] = +{ + {42.8571f,100.0f}, + {28.5714f,95.2381f}, + {23.8095f,85.7143f}, + {23.8095f,76.1905f}, + {28.5714f,66.6667f}, + {38.0952f,61.9048f}, + {57.1428f,57.1429f}, + {71.4286f,52.381f}, + {80.9524f,42.8571f}, + {85.7143f,33.3333f}, + {85.7143f,19.0476f}, + {80.9524f,9.5238f}, + {76.1905f,4.7619f}, + {61.9047f,0.0f}, + {42.8571f,0.0f}, + {28.5714f,4.7619f}, + {23.8095f,9.5238f}, + {19.0476f,19.0476f}, + {19.0476f,33.3333f}, + {23.8095f,42.8571f}, + {33.3333f,52.381f}, + {47.619f,57.1429f}, + {66.6666f,61.9048f}, + {76.1905f,66.6667f}, + {80.9524f,76.1905f}, + {80.9524f,85.7143f}, + {76.1905f,95.2381f}, + {61.9047f,100.0f}, + {42.8571f,100.0f} +}; + +static const SFG_StrokeStrip ch56st[] = +{ + {29,ch56st0} +}; + +static const SFG_StrokeChar ch56 = {104.762f,1,ch56st}; + +/* char: 0x39 */ + +static const SFG_StrokeVertex ch57st0[] = +{ + {83.3334f,66.6667f}, + {78.5714f,52.381f}, + {69.0476f,42.8571f}, + {54.7619f,38.0952f}, + {50.0f,38.0952f}, + {35.7143f,42.8571f}, + {26.1905f,52.381f}, + {21.4286f,66.6667f}, + {21.4286f,71.4286f}, + {26.1905f,85.7143f}, + {35.7143f,95.2381f}, + {50.0f,100.0f}, + {54.7619f,100.0f}, + {69.0476f,95.2381f}, + {78.5714f,85.7143f}, + {83.3334f,66.6667f}, + {83.3334f,42.8571f}, + {78.5714f,19.0476f}, + {69.0476f,4.7619f}, + {54.7619f,0.0f}, + {45.2381f,0.0f}, + {30.9524f,4.7619f}, + {26.1905f,14.2857f} +}; + +static const SFG_StrokeStrip ch57st[] = +{ + {23,ch57st0} +}; + +static const SFG_StrokeChar ch57 = {104.762f,1,ch57st}; + +/* char: 0x3a */ + +static const SFG_StrokeVertex ch58st0[] = +{ + {52.381f,66.6667f}, + {47.6191f,61.9048f}, + {52.381f,57.1429f}, + {57.1429f,61.9048f}, + {52.381f,66.6667f} +}; + +static const SFG_StrokeVertex ch58st1[] = +{ + {52.381f,9.5238f}, + {47.6191f,4.7619f}, + {52.381f,0.0f}, + {57.1429f,4.7619f}, + {52.381f,9.5238f} +}; + +static const SFG_StrokeStrip ch58st[] = +{ + {5,ch58st0}, + {5,ch58st1} +}; + +static const SFG_StrokeChar ch58 = {104.762f,2,ch58st}; + +/* char: 0x3b */ + +static const SFG_StrokeVertex ch59st0[] = +{ + {52.381f,66.6667f}, + {47.6191f,61.9048f}, + {52.381f,57.1429f}, + {57.1429f,61.9048f}, + {52.381f,66.6667f} +}; + +static const SFG_StrokeVertex ch59st1[] = +{ + {57.1429f,4.7619f}, + {52.381f,0.0f}, + {47.6191f,4.7619f}, + {52.381f,9.5238f}, + {57.1429f,4.7619f}, + {57.1429f,-4.7619f}, + {52.381f,-14.2857f}, + {47.6191f,-19.0476f} +}; + +static const SFG_StrokeStrip ch59st[] = +{ + {5,ch59st0}, + {8,ch59st1} +}; + +static const SFG_StrokeChar ch59 = {104.762f,2,ch59st}; + +/* char: 0x3c */ + +static const SFG_StrokeVertex ch60st0[] = +{ + {90.4762f,85.7143f}, + {14.2857f,42.8571f}, + {90.4762f,0.0f} +}; + +static const SFG_StrokeStrip ch60st[] = +{ + {3,ch60st0} +}; + +static const SFG_StrokeChar ch60 = {104.762f,1,ch60st}; + +/* char: 0x3d */ + +static const SFG_StrokeVertex ch61st0[] = +{ + {9.5238f,57.1429f}, + {95.2381f,57.1429f} +}; + +static const SFG_StrokeVertex ch61st1[] = +{ + {9.5238f,28.5714f}, + {95.2381f,28.5714f} +}; + +static const SFG_StrokeStrip ch61st[] = +{ + {2,ch61st0}, + {2,ch61st1} +}; + +static const SFG_StrokeChar ch61 = {104.762f,2,ch61st}; + +/* char: 0x3e */ + +static const SFG_StrokeVertex ch62st0[] = +{ + {14.2857f,85.7143f}, + {90.4762f,42.8571f}, + {14.2857f,0.0f} +}; + +static const SFG_StrokeStrip ch62st[] = +{ + {3,ch62st0} +}; + +static const SFG_StrokeChar ch62 = {104.762f,1,ch62st}; + +/* char: 0x3f */ + +static const SFG_StrokeVertex ch63st0[] = +{ + {23.8095f,76.1905f}, + {23.8095f,80.9524f}, + {28.5714f,90.4762f}, + {33.3333f,95.2381f}, + {42.8571f,100.0f}, + {61.9047f,100.0f}, + {71.4285f,95.2381f}, + {76.1905f,90.4762f}, + {80.9524f,80.9524f}, + {80.9524f,71.4286f}, + {76.1905f,61.9048f}, + {71.4285f,57.1429f}, + {52.3809f,47.619f}, + {52.3809f,33.3333f} +}; + +static const SFG_StrokeVertex ch63st1[] = +{ + {52.3809f,9.5238f}, + {47.619f,4.7619f}, + {52.3809f,0.0f}, + {57.1428f,4.7619f}, + {52.3809f,9.5238f} +}; + +static const SFG_StrokeStrip ch63st[] = +{ + {14,ch63st0}, + {5,ch63st1} +}; + +static const SFG_StrokeChar ch63 = {104.762f,2,ch63st}; + +/* char: 0x40 */ + +static const SFG_StrokeVertex ch64st0[] = +{ + {64.2857f,52.381f}, + {54.7619f,57.1429f}, + {45.2381f,57.1429f}, + {40.4762f,47.619f}, + {40.4762f,42.8571f}, + {45.2381f,33.3333f}, + {54.7619f,33.3333f}, + {64.2857f,38.0952f} +}; + +static const SFG_StrokeVertex ch64st1[] = +{ + {64.2857f,57.1429f}, + {64.2857f,38.0952f}, + {69.0476f,33.3333f}, + {78.5714f,33.3333f}, + {83.3334f,42.8571f}, + {83.3334f,47.619f}, + {78.5714f,61.9048f}, + {69.0476f,71.4286f}, + {54.7619f,76.1905f}, + {50.0f,76.1905f}, + {35.7143f,71.4286f}, + {26.1905f,61.9048f}, + {21.4286f,47.619f}, + {21.4286f,42.8571f}, + {26.1905f,28.5714f}, + {35.7143f,19.0476f}, + {50.0f,14.2857f}, + {54.7619f,14.2857f}, + {69.0476f,19.0476f} +}; + +static const SFG_StrokeStrip ch64st[] = +{ + {8,ch64st0}, + {19,ch64st1} +}; + +static const SFG_StrokeChar ch64 = {104.762f,2,ch64st}; + +/* char: 0x41 */ + +static const SFG_StrokeVertex ch65st0[] = +{ + {52.3809f,100.0f}, + {14.2857f,0.0f} +}; + +static const SFG_StrokeVertex ch65st1[] = +{ + {52.3809f,100.0f}, + {90.4762f,0.0f} +}; + +static const SFG_StrokeVertex ch65st2[] = +{ + {28.5714f,33.3333f}, + {76.1905f,33.3333f} +}; + +static const SFG_StrokeStrip ch65st[] = +{ + {2,ch65st0}, + {2,ch65st1}, + {2,ch65st2} +}; + +static const SFG_StrokeChar ch65 = {104.762f,3,ch65st}; + +/* char: 0x42 */ + +static const SFG_StrokeVertex ch66st0[] = +{ + {19.0476f,100.0f}, + {19.0476f,0.0f} +}; + +static const SFG_StrokeVertex ch66st1[] = +{ + {19.0476f,100.0f}, + {61.9047f,100.0f}, + {76.1905f,95.2381f}, + {80.9524f,90.4762f}, + {85.7143f,80.9524f}, + {85.7143f,71.4286f}, + {80.9524f,61.9048f}, + {76.1905f,57.1429f}, + {61.9047f,52.381f} +}; + +static const SFG_StrokeVertex ch66st2[] = +{ + {19.0476f,52.381f}, + {61.9047f,52.381f}, + {76.1905f,47.619f}, + {80.9524f,42.8571f}, + {85.7143f,33.3333f}, + {85.7143f,19.0476f}, + {80.9524f,9.5238f}, + {76.1905f,4.7619f}, + {61.9047f,0.0f}, + {19.0476f,0.0f} +}; + +static const SFG_StrokeStrip ch66st[] = +{ + {2,ch66st0}, + {9,ch66st1}, + {10,ch66st2} +}; + +static const SFG_StrokeChar ch66 = {104.762f,3,ch66st}; + +/* char: 0x43 */ + +static const SFG_StrokeVertex ch67st0[] = +{ + {88.0952f,76.1905f}, + {83.3334f,85.7143f}, + {73.8096f,95.2381f}, + {64.2857f,100.0f}, + {45.2381f,100.0f}, + {35.7143f,95.2381f}, + {26.1905f,85.7143f}, + {21.4286f,76.1905f}, + {16.6667f,61.9048f}, + {16.6667f,38.0952f}, + {21.4286f,23.8095f}, + {26.1905f,14.2857f}, + {35.7143f,4.7619f}, + {45.2381f,0.0f}, + {64.2857f,0.0f}, + {73.8096f,4.7619f}, + {83.3334f,14.2857f}, + {88.0952f,23.8095f} +}; + +static const SFG_StrokeStrip ch67st[] = +{ + {18,ch67st0} +}; + +static const SFG_StrokeChar ch67 = {104.762f,1,ch67st}; + +/* char: 0x44 */ + +static const SFG_StrokeVertex ch68st0[] = +{ + {19.0476f,100.0f}, + {19.0476f,0.0f} +}; + +static const SFG_StrokeVertex ch68st1[] = +{ + {19.0476f,100.0f}, + {52.3809f,100.0f}, + {66.6666f,95.2381f}, + {76.1905f,85.7143f}, + {80.9524f,76.1905f}, + {85.7143f,61.9048f}, + {85.7143f,38.0952f}, + {80.9524f,23.8095f}, + {76.1905f,14.2857f}, + {66.6666f,4.7619f}, + {52.3809f,0.0f}, + {19.0476f,0.0f} +}; + +static const SFG_StrokeStrip ch68st[] = +{ + {2,ch68st0}, + {12,ch68st1} +}; + +static const SFG_StrokeChar ch68 = {104.762f,2,ch68st}; + +/* char: 0x45 */ + +static const SFG_StrokeVertex ch69st0[] = +{ + {21.4286f,100.0f}, + {21.4286f,0.0f} +}; + +static const SFG_StrokeVertex ch69st1[] = +{ + {21.4286f,100.0f}, + {83.3334f,100.0f} +}; + +static const SFG_StrokeVertex ch69st2[] = +{ + {21.4286f,52.381f}, + {59.5238f,52.381f} +}; + +static const SFG_StrokeVertex ch69st3[] = +{ + {21.4286f,0.0f}, + {83.3334f,0.0f} +}; + +static const SFG_StrokeStrip ch69st[] = +{ + {2,ch69st0}, + {2,ch69st1}, + {2,ch69st2}, + {2,ch69st3} +}; + +static const SFG_StrokeChar ch69 = {104.762f,4,ch69st}; + +/* char: 0x46 */ + +static const SFG_StrokeVertex ch70st0[] = +{ + {21.4286f,100.0f}, + {21.4286f,0.0f} +}; + +static const SFG_StrokeVertex ch70st1[] = +{ + {21.4286f,100.0f}, + {83.3334f,100.0f} +}; + +static const SFG_StrokeVertex ch70st2[] = +{ + {21.4286f,52.381f}, + {59.5238f,52.381f} +}; + +static const SFG_StrokeStrip ch70st[] = +{ + {2,ch70st0}, + {2,ch70st1}, + {2,ch70st2} +}; + +static const SFG_StrokeChar ch70 = {104.762f,3,ch70st}; + +/* char: 0x47 */ + +static const SFG_StrokeVertex ch71st0[] = +{ + {88.0952f,76.1905f}, + {83.3334f,85.7143f}, + {73.8096f,95.2381f}, + {64.2857f,100.0f}, + {45.2381f,100.0f}, + {35.7143f,95.2381f}, + {26.1905f,85.7143f}, + {21.4286f,76.1905f}, + {16.6667f,61.9048f}, + {16.6667f,38.0952f}, + {21.4286f,23.8095f}, + {26.1905f,14.2857f}, + {35.7143f,4.7619f}, + {45.2381f,0.0f}, + {64.2857f,0.0f}, + {73.8096f,4.7619f}, + {83.3334f,14.2857f}, + {88.0952f,23.8095f}, + {88.0952f,38.0952f} +}; + +static const SFG_StrokeVertex ch71st1[] = +{ + {64.2857f,38.0952f}, + {88.0952f,38.0952f} +}; + +static const SFG_StrokeStrip ch71st[] = +{ + {19,ch71st0}, + {2,ch71st1} +}; + +static const SFG_StrokeChar ch71 = {104.762f,2,ch71st}; + +/* char: 0x48 */ + +static const SFG_StrokeVertex ch72st0[] = +{ + {19.0476f,100.0f}, + {19.0476f,0.0f} +}; + +static const SFG_StrokeVertex ch72st1[] = +{ + {85.7143f,100.0f}, + {85.7143f,0.0f} +}; + +static const SFG_StrokeVertex ch72st2[] = +{ + {19.0476f,52.381f}, + {85.7143f,52.381f} +}; + +static const SFG_StrokeStrip ch72st[] = +{ + {2,ch72st0}, + {2,ch72st1}, + {2,ch72st2} +}; + +static const SFG_StrokeChar ch72 = {104.762f,3,ch72st}; + +/* char: 0x49 */ + +static const SFG_StrokeVertex ch73st0[] = +{ + {52.381f,100.0f}, + {52.381f,0.0f} +}; + +static const SFG_StrokeStrip ch73st[] = +{ + {2,ch73st0} +}; + +static const SFG_StrokeChar ch73 = {104.762f,1,ch73st}; + +/* char: 0x4a */ + +static const SFG_StrokeVertex ch74st0[] = +{ + {76.1905f,100.0f}, + {76.1905f,23.8095f}, + {71.4286f,9.5238f}, + {66.6667f,4.7619f}, + {57.1429f,0.0f}, + {47.6191f,0.0f}, + {38.0953f,4.7619f}, + {33.3334f,9.5238f}, + {28.5715f,23.8095f}, + {28.5715f,33.3333f} +}; + +static const SFG_StrokeStrip ch74st[] = +{ + {10,ch74st0} +}; + +static const SFG_StrokeChar ch74 = {104.762f,1,ch74st}; + +/* char: 0x4b */ + +static const SFG_StrokeVertex ch75st0[] = +{ + {19.0476f,100.0f}, + {19.0476f,0.0f} +}; + +static const SFG_StrokeVertex ch75st1[] = +{ + {85.7143f,100.0f}, + {19.0476f,33.3333f} +}; + +static const SFG_StrokeVertex ch75st2[] = +{ + {42.8571f,57.1429f}, + {85.7143f,0.0f} +}; + +static const SFG_StrokeStrip ch75st[] = +{ + {2,ch75st0}, + {2,ch75st1}, + {2,ch75st2} +}; + +static const SFG_StrokeChar ch75 = {104.762f,3,ch75st}; + +/* char: 0x4c */ + +static const SFG_StrokeVertex ch76st0[] = +{ + {23.8095f,100.0f}, + {23.8095f,0.0f} +}; + +static const SFG_StrokeVertex ch76st1[] = +{ + {23.8095f,0.0f}, + {80.9524f,0.0f} +}; + +static const SFG_StrokeStrip ch76st[] = +{ + {2,ch76st0}, + {2,ch76st1} +}; + +static const SFG_StrokeChar ch76 = {104.762f,2,ch76st}; + +/* char: 0x4d */ + +static const SFG_StrokeVertex ch77st0[] = +{ + {14.2857f,100.0f}, + {14.2857f,0.0f} +}; + +static const SFG_StrokeVertex ch77st1[] = +{ + {14.2857f,100.0f}, + {52.3809f,0.0f} +}; + +static const SFG_StrokeVertex ch77st2[] = +{ + {90.4762f,100.0f}, + {52.3809f,0.0f} +}; + +static const SFG_StrokeVertex ch77st3[] = +{ + {90.4762f,100.0f}, + {90.4762f,0.0f} +}; + +static const SFG_StrokeStrip ch77st[] = +{ + {2,ch77st0}, + {2,ch77st1}, + {2,ch77st2}, + {2,ch77st3} +}; + +static const SFG_StrokeChar ch77 = {104.762f,4,ch77st}; + +/* char: 0x4e */ + +static const SFG_StrokeVertex ch78st0[] = +{ + {19.0476f,100.0f}, + {19.0476f,0.0f} +}; + +static const SFG_StrokeVertex ch78st1[] = +{ + {19.0476f,100.0f}, + {85.7143f,0.0f} +}; + +static const SFG_StrokeVertex ch78st2[] = +{ + {85.7143f,100.0f}, + {85.7143f,0.0f} +}; + +static const SFG_StrokeStrip ch78st[] = +{ + {2,ch78st0}, + {2,ch78st1}, + {2,ch78st2} +}; + +static const SFG_StrokeChar ch78 = {104.762f,3,ch78st}; + +/* char: 0x4f */ + +static const SFG_StrokeVertex ch79st0[] = +{ + {42.8571f,100.0f}, + {33.3333f,95.2381f}, + {23.8095f,85.7143f}, + {19.0476f,76.1905f}, + {14.2857f,61.9048f}, + {14.2857f,38.0952f}, + {19.0476f,23.8095f}, + {23.8095f,14.2857f}, + {33.3333f,4.7619f}, + {42.8571f,0.0f}, + {61.9047f,0.0f}, + {71.4286f,4.7619f}, + {80.9524f,14.2857f}, + {85.7143f,23.8095f}, + {90.4762f,38.0952f}, + {90.4762f,61.9048f}, + {85.7143f,76.1905f}, + {80.9524f,85.7143f}, + {71.4286f,95.2381f}, + {61.9047f,100.0f}, + {42.8571f,100.0f} +}; + +static const SFG_StrokeStrip ch79st[] = +{ + {21,ch79st0} +}; + +static const SFG_StrokeChar ch79 = {104.762f,1,ch79st}; + +/* char: 0x50 */ + +static const SFG_StrokeVertex ch80st0[] = +{ + {19.0476f,100.0f}, + {19.0476f,0.0f} +}; + +static const SFG_StrokeVertex ch80st1[] = +{ + {19.0476f,100.0f}, + {61.9047f,100.0f}, + {76.1905f,95.2381f}, + {80.9524f,90.4762f}, + {85.7143f,80.9524f}, + {85.7143f,66.6667f}, + {80.9524f,57.1429f}, + {76.1905f,52.381f}, + {61.9047f,47.619f}, + {19.0476f,47.619f} +}; + +static const SFG_StrokeStrip ch80st[] = +{ + {2,ch80st0}, + {10,ch80st1} +}; + +static const SFG_StrokeChar ch80 = {104.762f,2,ch80st}; + +/* char: 0x51 */ + +static const SFG_StrokeVertex ch81st0[] = +{ + {42.8571f,100.0f}, + {33.3333f,95.2381f}, + {23.8095f,85.7143f}, + {19.0476f,76.1905f}, + {14.2857f,61.9048f}, + {14.2857f,38.0952f}, + {19.0476f,23.8095f}, + {23.8095f,14.2857f}, + {33.3333f,4.7619f}, + {42.8571f,0.0f}, + {61.9047f,0.0f}, + {71.4286f,4.7619f}, + {80.9524f,14.2857f}, + {85.7143f,23.8095f}, + {90.4762f,38.0952f}, + {90.4762f,61.9048f}, + {85.7143f,76.1905f}, + {80.9524f,85.7143f}, + {71.4286f,95.2381f}, + {61.9047f,100.0f}, + {42.8571f,100.0f} +}; + +static const SFG_StrokeVertex ch81st1[] = +{ + {57.1428f,19.0476f}, + {85.7143f,-9.5238f} +}; + +static const SFG_StrokeStrip ch81st[] = +{ + {21,ch81st0}, + {2,ch81st1} +}; + +static const SFG_StrokeChar ch81 = {104.762f,2,ch81st}; + +/* char: 0x52 */ + +static const SFG_StrokeVertex ch82st0[] = +{ + {19.0476f,100.0f}, + {19.0476f,0.0f} +}; + +static const SFG_StrokeVertex ch82st1[] = +{ + {19.0476f,100.0f}, + {61.9047f,100.0f}, + {76.1905f,95.2381f}, + {80.9524f,90.4762f}, + {85.7143f,80.9524f}, + {85.7143f,71.4286f}, + {80.9524f,61.9048f}, + {76.1905f,57.1429f}, + {61.9047f,52.381f}, + {19.0476f,52.381f} +}; + +static const SFG_StrokeVertex ch82st2[] = +{ + {52.3809f,52.381f}, + {85.7143f,0.0f} +}; + +static const SFG_StrokeStrip ch82st[] = +{ + {2,ch82st0}, + {10,ch82st1}, + {2,ch82st2} +}; + +static const SFG_StrokeChar ch82 = {104.762f,3,ch82st}; + +/* char: 0x53 */ + +static const SFG_StrokeVertex ch83st0[] = +{ + {85.7143f,85.7143f}, + {76.1905f,95.2381f}, + {61.9047f,100.0f}, + {42.8571f,100.0f}, + {28.5714f,95.2381f}, + {19.0476f,85.7143f}, + {19.0476f,76.1905f}, + {23.8095f,66.6667f}, + {28.5714f,61.9048f}, + {38.0952f,57.1429f}, + {66.6666f,47.619f}, + {76.1905f,42.8571f}, + {80.9524f,38.0952f}, + {85.7143f,28.5714f}, + {85.7143f,14.2857f}, + {76.1905f,4.7619f}, + {61.9047f,0.0f}, + {42.8571f,0.0f}, + {28.5714f,4.7619f}, + {19.0476f,14.2857f} +}; + +static const SFG_StrokeStrip ch83st[] = +{ + {20,ch83st0} +}; + +static const SFG_StrokeChar ch83 = {104.762f,1,ch83st}; + +/* char: 0x54 */ + +static const SFG_StrokeVertex ch84st0[] = +{ + {52.3809f,100.0f}, + {52.3809f,0.0f} +}; + +static const SFG_StrokeVertex ch84st1[] = +{ + {19.0476f,100.0f}, + {85.7143f,100.0f} +}; + +static const SFG_StrokeStrip ch84st[] = +{ + {2,ch84st0}, + {2,ch84st1} +}; + +static const SFG_StrokeChar ch84 = {104.762f,2,ch84st}; + +/* char: 0x55 */ + +static const SFG_StrokeVertex ch85st0[] = +{ + {19.0476f,100.0f}, + {19.0476f,28.5714f}, + {23.8095f,14.2857f}, + {33.3333f,4.7619f}, + {47.619f,0.0f}, + {57.1428f,0.0f}, + {71.4286f,4.7619f}, + {80.9524f,14.2857f}, + {85.7143f,28.5714f}, + {85.7143f,100.0f} +}; + +static const SFG_StrokeStrip ch85st[] = +{ + {10,ch85st0} +}; + +static const SFG_StrokeChar ch85 = {104.762f,1,ch85st}; + +/* char: 0x56 */ + +static const SFG_StrokeVertex ch86st0[] = +{ + {14.2857f,100.0f}, + {52.3809f,0.0f} +}; + +static const SFG_StrokeVertex ch86st1[] = +{ + {90.4762f,100.0f}, + {52.3809f,0.0f} +}; + +static const SFG_StrokeStrip ch86st[] = +{ + {2,ch86st0}, + {2,ch86st1} +}; + +static const SFG_StrokeChar ch86 = {104.762f,2,ch86st}; + +/* char: 0x57 */ + +static const SFG_StrokeVertex ch87st0[] = +{ + {4.7619f,100.0f}, + {28.5714f,0.0f} +}; + +static const SFG_StrokeVertex ch87st1[] = +{ + {52.3809f,100.0f}, + {28.5714f,0.0f} +}; + +static const SFG_StrokeVertex ch87st2[] = +{ + {52.3809f,100.0f}, + {76.1905f,0.0f} +}; + +static const SFG_StrokeVertex ch87st3[] = +{ + {100.0f,100.0f}, + {76.1905f,0.0f} +}; + +static const SFG_StrokeStrip ch87st[] = +{ + {2,ch87st0}, + {2,ch87st1}, + {2,ch87st2}, + {2,ch87st3} +}; + +static const SFG_StrokeChar ch87 = {104.762f,4,ch87st}; + +/* char: 0x58 */ + +static const SFG_StrokeVertex ch88st0[] = +{ + {19.0476f,100.0f}, + {85.7143f,0.0f} +}; + +static const SFG_StrokeVertex ch88st1[] = +{ + {85.7143f,100.0f}, + {19.0476f,0.0f} +}; + +static const SFG_StrokeStrip ch88st[] = +{ + {2,ch88st0}, + {2,ch88st1} +}; + +static const SFG_StrokeChar ch88 = {104.762f,2,ch88st}; + +/* char: 0x59 */ + +static const SFG_StrokeVertex ch89st0[] = +{ + {14.2857f,100.0f}, + {52.3809f,52.381f}, + {52.3809f,0.0f} +}; + +static const SFG_StrokeVertex ch89st1[] = +{ + {90.4762f,100.0f}, + {52.3809f,52.381f} +}; + +static const SFG_StrokeStrip ch89st[] = +{ + {3,ch89st0}, + {2,ch89st1} +}; + +static const SFG_StrokeChar ch89 = {104.762f,2,ch89st}; + +/* char: 0x5a */ + +static const SFG_StrokeVertex ch90st0[] = +{ + {85.7143f,100.0f}, + {19.0476f,0.0f} +}; + +static const SFG_StrokeVertex ch90st1[] = +{ + {19.0476f,100.0f}, + {85.7143f,100.0f} +}; + +static const SFG_StrokeVertex ch90st2[] = +{ + {19.0476f,0.0f}, + {85.7143f,0.0f} +}; + +static const SFG_StrokeStrip ch90st[] = +{ + {2,ch90st0}, + {2,ch90st1}, + {2,ch90st2} +}; + +static const SFG_StrokeChar ch90 = {104.762f,3,ch90st}; + +/* char: 0x5b */ + +static const SFG_StrokeVertex ch91st0[] = +{ + {35.7143f,119.048f}, + {35.7143f,-33.3333f} +}; + +static const SFG_StrokeVertex ch91st1[] = +{ + {40.4762f,119.048f}, + {40.4762f,-33.3333f} +}; + +static const SFG_StrokeVertex ch91st2[] = +{ + {35.7143f,119.048f}, + {69.0476f,119.048f} +}; + +static const SFG_StrokeVertex ch91st3[] = +{ + {35.7143f,-33.3333f}, + {69.0476f,-33.3333f} +}; + +static const SFG_StrokeStrip ch91st[] = +{ + {2,ch91st0}, + {2,ch91st1}, + {2,ch91st2}, + {2,ch91st3} +}; + +static const SFG_StrokeChar ch91 = {104.762f,4,ch91st}; + +/* char: 0x5c */ + +static const SFG_StrokeVertex ch92st0[] = +{ + {19.0476f,100.0f}, + {85.7143f,-14.2857f} +}; + +static const SFG_StrokeStrip ch92st[] = +{ + {2,ch92st0} +}; + +static const SFG_StrokeChar ch92 = {104.762f,1,ch92st}; + +/* char: 0x5d */ + +static const SFG_StrokeVertex ch93st0[] = +{ + {64.2857f,119.048f}, + {64.2857f,-33.3333f} +}; + +static const SFG_StrokeVertex ch93st1[] = +{ + {69.0476f,119.048f}, + {69.0476f,-33.3333f} +}; + +static const SFG_StrokeVertex ch93st2[] = +{ + {35.7143f,119.048f}, + {69.0476f,119.048f} +}; + +static const SFG_StrokeVertex ch93st3[] = +{ + {35.7143f,-33.3333f}, + {69.0476f,-33.3333f} +}; + +static const SFG_StrokeStrip ch93st[] = +{ + {2,ch93st0}, + {2,ch93st1}, + {2,ch93st2}, + {2,ch93st3} +}; + +static const SFG_StrokeChar ch93 = {104.762f,4,ch93st}; + +/* char: 0x5e */ + +static const SFG_StrokeVertex ch94st0[] = +{ + {52.3809f,109.524f}, + {14.2857f,42.8571f} +}; + +static const SFG_StrokeVertex ch94st1[] = +{ + {52.3809f,109.524f}, + {90.4762f,42.8571f} +}; + +static const SFG_StrokeStrip ch94st[] = +{ + {2,ch94st0}, + {2,ch94st1} +}; + +static const SFG_StrokeChar ch94 = {104.762f,2,ch94st}; + +/* char: 0x5f */ + +static const SFG_StrokeVertex ch95st0[] = +{ + {0,-33.3333f}, + {104.762f,-33.3333f}, + {104.762f,-28.5714f}, + {0,-28.5714f}, + {0,-33.3333f} +}; + +static const SFG_StrokeStrip ch95st[] = +{ + {5,ch95st0} +}; + +static const SFG_StrokeChar ch95 = {104.762f,1,ch95st}; + +/* char: 0x60 */ + +static const SFG_StrokeVertex ch96st0[] = +{ + {42.8572f,100.0f}, + {66.6667f,71.4286f} +}; + +static const SFG_StrokeVertex ch96st1[] = +{ + {42.8572f,100.0f}, + {38.0953f,95.2381f}, + {66.6667f,71.4286f} +}; + +static const SFG_StrokeStrip ch96st[] = +{ + {2,ch96st0}, + {3,ch96st1} +}; + +static const SFG_StrokeChar ch96 = {104.762f,2,ch96st}; + +/* char: 0x61 */ + +static const SFG_StrokeVertex ch97st0[] = +{ + {80.9524f,66.6667f}, + {80.9524f,0.0f} +}; + +static const SFG_StrokeVertex ch97st1[] = +{ + {80.9524f,52.381f}, + {71.4285f,61.9048f}, + {61.9047f,66.6667f}, + {47.619f,66.6667f}, + {38.0952f,61.9048f}, + {28.5714f,52.381f}, + {23.8095f,38.0952f}, + {23.8095f,28.5714f}, + {28.5714f,14.2857f}, + {38.0952f,4.7619f}, + {47.619f,0.0f}, + {61.9047f,0.0f}, + {71.4285f,4.7619f}, + {80.9524f,14.2857f} +}; + +static const SFG_StrokeStrip ch97st[] = +{ + {2,ch97st0}, + {14,ch97st1} +}; + +static const SFG_StrokeChar ch97 = {104.762f,2,ch97st}; + +/* char: 0x62 */ + +static const SFG_StrokeVertex ch98st0[] = +{ + {23.8095f,100.0f}, + {23.8095f,0.0f} +}; + +static const SFG_StrokeVertex ch98st1[] = +{ + {23.8095f,52.381f}, + {33.3333f,61.9048f}, + {42.8571f,66.6667f}, + {57.1428f,66.6667f}, + {66.6666f,61.9048f}, + {76.1905f,52.381f}, + {80.9524f,38.0952f}, + {80.9524f,28.5714f}, + {76.1905f,14.2857f}, + {66.6666f,4.7619f}, + {57.1428f,0.0f}, + {42.8571f,0.0f}, + {33.3333f,4.7619f}, + {23.8095f,14.2857f} +}; + +static const SFG_StrokeStrip ch98st[] = +{ + {2,ch98st0}, + {14,ch98st1} +}; + +static const SFG_StrokeChar ch98 = {104.762f,2,ch98st}; + +/* char: 0x63 */ + +static const SFG_StrokeVertex ch99st0[] = +{ + {80.9524f,52.381f}, + {71.4285f,61.9048f}, + {61.9047f,66.6667f}, + {47.619f,66.6667f}, + {38.0952f,61.9048f}, + {28.5714f,52.381f}, + {23.8095f,38.0952f}, + {23.8095f,28.5714f}, + {28.5714f,14.2857f}, + {38.0952f,4.7619f}, + {47.619f,0.0f}, + {61.9047f,0.0f}, + {71.4285f,4.7619f}, + {80.9524f,14.2857f} +}; + +static const SFG_StrokeStrip ch99st[] = +{ + {14,ch99st0} +}; + +static const SFG_StrokeChar ch99 = {104.762f,1,ch99st}; + +/* char: 0x64 */ + +static const SFG_StrokeVertex ch100st0[] = +{ + {80.9524f,100.0f}, + {80.9524f,0.0f} +}; + +static const SFG_StrokeVertex ch100st1[] = +{ + {80.9524f,52.381f}, + {71.4285f,61.9048f}, + {61.9047f,66.6667f}, + {47.619f,66.6667f}, + {38.0952f,61.9048f}, + {28.5714f,52.381f}, + {23.8095f,38.0952f}, + {23.8095f,28.5714f}, + {28.5714f,14.2857f}, + {38.0952f,4.7619f}, + {47.619f,0.0f}, + {61.9047f,0.0f}, + {71.4285f,4.7619f}, + {80.9524f,14.2857f} +}; + +static const SFG_StrokeStrip ch100st[] = +{ + {2,ch100st0}, + {14,ch100st1} +}; + +static const SFG_StrokeChar ch100 = {104.762f,2,ch100st}; + +/* char: 0x65 */ + +static const SFG_StrokeVertex ch101st0[] = +{ + {23.8095f,38.0952f}, + {80.9524f,38.0952f}, + {80.9524f,47.619f}, + {76.1905f,57.1429f}, + {71.4285f,61.9048f}, + {61.9047f,66.6667f}, + {47.619f,66.6667f}, + {38.0952f,61.9048f}, + {28.5714f,52.381f}, + {23.8095f,38.0952f}, + {23.8095f,28.5714f}, + {28.5714f,14.2857f}, + {38.0952f,4.7619f}, + {47.619f,0.0f}, + {61.9047f,0.0f}, + {71.4285f,4.7619f}, + {80.9524f,14.2857f} +}; + +static const SFG_StrokeStrip ch101st[] = +{ + {17,ch101st0} +}; + +static const SFG_StrokeChar ch101 = {104.762f,1,ch101st}; + +/* char: 0x66 */ + +static const SFG_StrokeVertex ch102st0[] = +{ + {71.4286f,100.0f}, + {61.9048f,100.0f}, + {52.381f,95.2381f}, + {47.6191f,80.9524f}, + {47.6191f,0.0f} +}; + +static const SFG_StrokeVertex ch102st1[] = +{ + {33.3334f,66.6667f}, + {66.6667f,66.6667f} +}; + +static const SFG_StrokeStrip ch102st[] = +{ + {5,ch102st0}, + {2,ch102st1} +}; + +static const SFG_StrokeChar ch102 = {104.762f,2,ch102st}; + +/* char: 0x67 */ + +static const SFG_StrokeVertex ch103st0[] = +{ + {80.9524f,66.6667f}, + {80.9524f,-9.5238f}, + {76.1905f,-23.8095f}, + {71.4285f,-28.5714f}, + {61.9047f,-33.3333f}, + {47.619f,-33.3333f}, + {38.0952f,-28.5714f} +}; + +static const SFG_StrokeVertex ch103st1[] = +{ + {80.9524f,52.381f}, + {71.4285f,61.9048f}, + {61.9047f,66.6667f}, + {47.619f,66.6667f}, + {38.0952f,61.9048f}, + {28.5714f,52.381f}, + {23.8095f,38.0952f}, + {23.8095f,28.5714f}, + {28.5714f,14.2857f}, + {38.0952f,4.7619f}, + {47.619f,0.0f}, + {61.9047f,0.0f}, + {71.4285f,4.7619f}, + {80.9524f,14.2857f} +}; + +static const SFG_StrokeStrip ch103st[] = +{ + {7,ch103st0}, + {14,ch103st1} +}; + +static const SFG_StrokeChar ch103 = {104.762f,2,ch103st}; + +/* char: 0x68 */ + +static const SFG_StrokeVertex ch104st0[] = +{ + {26.1905f,100.0f}, + {26.1905f,0.0f} +}; + +static const SFG_StrokeVertex ch104st1[] = +{ + {26.1905f,47.619f}, + {40.4762f,61.9048f}, + {50.0f,66.6667f}, + {64.2857f,66.6667f}, + {73.8095f,61.9048f}, + {78.5715f,47.619f}, + {78.5715f,0.0f} +}; + +static const SFG_StrokeStrip ch104st[] = +{ + {2,ch104st0}, + {7,ch104st1} +}; + +static const SFG_StrokeChar ch104 = {104.762f,2,ch104st}; + +/* char: 0x69 */ + +static const SFG_StrokeVertex ch105st0[] = +{ + {47.6191f,100.0f}, + {52.381f,95.2381f}, + {57.1429f,100.0f}, + {52.381f,104.762f}, + {47.6191f,100.0f} +}; + +static const SFG_StrokeVertex ch105st1[] = +{ + {52.381f,66.6667f}, + {52.381f,0.0f} +}; + +static const SFG_StrokeStrip ch105st[] = +{ + {5,ch105st0}, + {2,ch105st1} +}; + +static const SFG_StrokeChar ch105 = {104.762f,2,ch105st}; + +/* char: 0x6a */ + +static const SFG_StrokeVertex ch106st0[] = +{ + {57.1429f,100.0f}, + {61.9048f,95.2381f}, + {66.6667f,100.0f}, + {61.9048f,104.762f}, + {57.1429f,100.0f} +}; + +static const SFG_StrokeVertex ch106st1[] = +{ + {61.9048f,66.6667f}, + {61.9048f,-14.2857f}, + {57.1429f,-28.5714f}, + {47.6191f,-33.3333f}, + {38.0953f,-33.3333f} +}; + +static const SFG_StrokeStrip ch106st[] = +{ + {5,ch106st0}, + {5,ch106st1} +}; + +static const SFG_StrokeChar ch106 = {104.762f,2,ch106st}; + +/* char: 0x6b */ + +static const SFG_StrokeVertex ch107st0[] = +{ + {26.1905f,100.0f}, + {26.1905f,0.0f} +}; + +static const SFG_StrokeVertex ch107st1[] = +{ + {73.8095f,66.6667f}, + {26.1905f,19.0476f} +}; + +static const SFG_StrokeVertex ch107st2[] = +{ + {45.2381f,38.0952f}, + {78.5715f,0.0f} +}; + +static const SFG_StrokeStrip ch107st[] = +{ + {2,ch107st0}, + {2,ch107st1}, + {2,ch107st2} +}; + +static const SFG_StrokeChar ch107 = {104.762f,3,ch107st}; + +/* char: 0x6c */ + +static const SFG_StrokeVertex ch108st0[] = +{ + {52.381f,100.0f}, + {52.381f,0.0f} +}; + +static const SFG_StrokeStrip ch108st[] = +{ + {2,ch108st0} +}; + +static const SFG_StrokeChar ch108 = {104.762f,1,ch108st}; + +/* char: 0x6d */ + +static const SFG_StrokeVertex ch109st0[] = +{ + {0,66.6667f}, + {0,0.0f} +}; + +static const SFG_StrokeVertex ch109st1[] = +{ + {0,47.619f}, + {14.2857f,61.9048f}, + {23.8095f,66.6667f}, + {38.0952f,66.6667f}, + {47.619f,61.9048f}, + {52.381f,47.619f}, + {52.381f,0.0f} +}; + +static const SFG_StrokeVertex ch109st2[] = +{ + {52.381f,47.619f}, + {66.6667f,61.9048f}, + {76.1905f,66.6667f}, + {90.4762f,66.6667f}, + {100.0f,61.9048f}, + {104.762f,47.619f}, + {104.762f,0.0f} +}; + +static const SFG_StrokeStrip ch109st[] = +{ + {2,ch109st0}, + {7,ch109st1}, + {7,ch109st2} +}; + +static const SFG_StrokeChar ch109 = {104.762f,3,ch109st}; + +/* char: 0x6e */ + +static const SFG_StrokeVertex ch110st0[] = +{ + {26.1905f,66.6667f}, + {26.1905f,0.0f} +}; + +static const SFG_StrokeVertex ch110st1[] = +{ + {26.1905f,47.619f}, + {40.4762f,61.9048f}, + {50.0f,66.6667f}, + {64.2857f,66.6667f}, + {73.8095f,61.9048f}, + {78.5715f,47.619f}, + {78.5715f,0.0f} +}; + +static const SFG_StrokeStrip ch110st[] = +{ + {2,ch110st0}, + {7,ch110st1} +}; + +static const SFG_StrokeChar ch110 = {104.762f,2,ch110st}; + +/* char: 0x6f */ + +static const SFG_StrokeVertex ch111st0[] = +{ + {45.2381f,66.6667f}, + {35.7143f,61.9048f}, + {26.1905f,52.381f}, + {21.4286f,38.0952f}, + {21.4286f,28.5714f}, + {26.1905f,14.2857f}, + {35.7143f,4.7619f}, + {45.2381f,0.0f}, + {59.5238f,0.0f}, + {69.0476f,4.7619f}, + {78.5714f,14.2857f}, + {83.3334f,28.5714f}, + {83.3334f,38.0952f}, + {78.5714f,52.381f}, + {69.0476f,61.9048f}, + {59.5238f,66.6667f}, + {45.2381f,66.6667f} +}; + +static const SFG_StrokeStrip ch111st[] = +{ + {17,ch111st0} +}; + +static const SFG_StrokeChar ch111 = {104.762f,1,ch111st}; + +/* char: 0x70 */ + +static const SFG_StrokeVertex ch112st0[] = +{ + {23.8095f,66.6667f}, + {23.8095f,-33.3333f} +}; + +static const SFG_StrokeVertex ch112st1[] = +{ + {23.8095f,52.381f}, + {33.3333f,61.9048f}, + {42.8571f,66.6667f}, + {57.1428f,66.6667f}, + {66.6666f,61.9048f}, + {76.1905f,52.381f}, + {80.9524f,38.0952f}, + {80.9524f,28.5714f}, + {76.1905f,14.2857f}, + {66.6666f,4.7619f}, + {57.1428f,0.0f}, + {42.8571f,0.0f}, + {33.3333f,4.7619f}, + {23.8095f,14.2857f} +}; + +static const SFG_StrokeStrip ch112st[] = +{ + {2,ch112st0}, + {14,ch112st1} +}; + +static const SFG_StrokeChar ch112 = {104.762f,2,ch112st}; + +/* char: 0x71 */ + +static const SFG_StrokeVertex ch113st0[] = +{ + {80.9524f,66.6667f}, + {80.9524f,-33.3333f} +}; + +static const SFG_StrokeVertex ch113st1[] = +{ + {80.9524f,52.381f}, + {71.4285f,61.9048f}, + {61.9047f,66.6667f}, + {47.619f,66.6667f}, + {38.0952f,61.9048f}, + {28.5714f,52.381f}, + {23.8095f,38.0952f}, + {23.8095f,28.5714f}, + {28.5714f,14.2857f}, + {38.0952f,4.7619f}, + {47.619f,0.0f}, + {61.9047f,0.0f}, + {71.4285f,4.7619f}, + {80.9524f,14.2857f} +}; + +static const SFG_StrokeStrip ch113st[] = +{ + {2,ch113st0}, + {14,ch113st1} +}; + +static const SFG_StrokeChar ch113 = {104.762f,2,ch113st}; + +/* char: 0x72 */ + +static const SFG_StrokeVertex ch114st0[] = +{ + {33.3334f,66.6667f}, + {33.3334f,0.0f} +}; + +static const SFG_StrokeVertex ch114st1[] = +{ + {33.3334f,38.0952f}, + {38.0953f,52.381f}, + {47.6191f,61.9048f}, + {57.1429f,66.6667f}, + {71.4286f,66.6667f} +}; + +static const SFG_StrokeStrip ch114st[] = +{ + {2,ch114st0}, + {5,ch114st1} +}; + +static const SFG_StrokeChar ch114 = {104.762f,2,ch114st}; + +/* char: 0x73 */ + +static const SFG_StrokeVertex ch115st0[] = +{ + {78.5715f,52.381f}, + {73.8095f,61.9048f}, + {59.5238f,66.6667f}, + {45.2381f,66.6667f}, + {30.9524f,61.9048f}, + {26.1905f,52.381f}, + {30.9524f,42.8571f}, + {40.4762f,38.0952f}, + {64.2857f,33.3333f}, + {73.8095f,28.5714f}, + {78.5715f,19.0476f}, + {78.5715f,14.2857f}, + {73.8095f,4.7619f}, + {59.5238f,0.0f}, + {45.2381f,0.0f}, + {30.9524f,4.7619f}, + {26.1905f,14.2857f} +}; + +static const SFG_StrokeStrip ch115st[] = +{ + {17,ch115st0} +}; + +static const SFG_StrokeChar ch115 = {104.762f,1,ch115st}; + +/* char: 0x74 */ + +static const SFG_StrokeVertex ch116st0[] = +{ + {47.6191f,100.0f}, + {47.6191f,19.0476f}, + {52.381f,4.7619f}, + {61.9048f,0.0f}, + {71.4286f,0.0f} +}; + +static const SFG_StrokeVertex ch116st1[] = +{ + {33.3334f,66.6667f}, + {66.6667f,66.6667f} +}; + +static const SFG_StrokeStrip ch116st[] = +{ + {5,ch116st0}, + {2,ch116st1} +}; + +static const SFG_StrokeChar ch116 = {104.762f,2,ch116st}; + +/* char: 0x75 */ + +static const SFG_StrokeVertex ch117st0[] = +{ + {26.1905f,66.6667f}, + {26.1905f,19.0476f}, + {30.9524f,4.7619f}, + {40.4762f,0.0f}, + {54.7619f,0.0f}, + {64.2857f,4.7619f}, + {78.5715f,19.0476f} +}; + +static const SFG_StrokeVertex ch117st1[] = +{ + {78.5715f,66.6667f}, + {78.5715f,0.0f} +}; + +static const SFG_StrokeStrip ch117st[] = +{ + {7,ch117st0}, + {2,ch117st1} +}; + +static const SFG_StrokeChar ch117 = {104.762f,2,ch117st}; + +/* char: 0x76 */ + +static const SFG_StrokeVertex ch118st0[] = +{ + {23.8095f,66.6667f}, + {52.3809f,0.0f} +}; + +static const SFG_StrokeVertex ch118st1[] = +{ + {80.9524f,66.6667f}, + {52.3809f,0.0f} +}; + +static const SFG_StrokeStrip ch118st[] = +{ + {2,ch118st0}, + {2,ch118st1} +}; + +static const SFG_StrokeChar ch118 = {104.762f,2,ch118st}; + +/* char: 0x77 */ + +static const SFG_StrokeVertex ch119st0[] = +{ + {14.2857f,66.6667f}, + {33.3333f,0.0f} +}; + +static const SFG_StrokeVertex ch119st1[] = +{ + {52.3809f,66.6667f}, + {33.3333f,0.0f} +}; + +static const SFG_StrokeVertex ch119st2[] = +{ + {52.3809f,66.6667f}, + {71.4286f,0.0f} +}; + +static const SFG_StrokeVertex ch119st3[] = +{ + {90.4762f,66.6667f}, + {71.4286f,0.0f} +}; + +static const SFG_StrokeStrip ch119st[] = +{ + {2,ch119st0}, + {2,ch119st1}, + {2,ch119st2}, + {2,ch119st3} +}; + +static const SFG_StrokeChar ch119 = {104.762f,4,ch119st}; + +/* char: 0x78 */ + +static const SFG_StrokeVertex ch120st0[] = +{ + {26.1905f,66.6667f}, + {78.5715f,0.0f} +}; + +static const SFG_StrokeVertex ch120st1[] = +{ + {78.5715f,66.6667f}, + {26.1905f,0.0f} +}; + +static const SFG_StrokeStrip ch120st[] = +{ + {2,ch120st0}, + {2,ch120st1} +}; + +static const SFG_StrokeChar ch120 = {104.762f,2,ch120st}; + +/* char: 0x79 */ + +static const SFG_StrokeVertex ch121st0[] = +{ + {26.1905f,66.6667f}, + {54.7619f,0.0f} +}; + +static const SFG_StrokeVertex ch121st1[] = +{ + {83.3334f,66.6667f}, + {54.7619f,0.0f}, + {45.2381f,-19.0476f}, + {35.7143f,-28.5714f}, + {26.1905f,-33.3333f}, + {21.4286f,-33.3333f} +}; + +static const SFG_StrokeStrip ch121st[] = +{ + {2,ch121st0}, + {6,ch121st1} +}; + +static const SFG_StrokeChar ch121 = {104.762f,2,ch121st}; + +/* char: 0x7a */ + +static const SFG_StrokeVertex ch122st0[] = +{ + {78.5715f,66.6667f}, + {26.1905f,0.0f} +}; + +static const SFG_StrokeVertex ch122st1[] = +{ + {26.1905f,66.6667f}, + {78.5715f,66.6667f} +}; + +static const SFG_StrokeVertex ch122st2[] = +{ + {26.1905f,0.0f}, + {78.5715f,0.0f} +}; + +static const SFG_StrokeStrip ch122st[] = +{ + {2,ch122st0}, + {2,ch122st1}, + {2,ch122st2} +}; + +static const SFG_StrokeChar ch122 = {104.762f,3,ch122st}; + +/* char: 0x7b */ + +static const SFG_StrokeVertex ch123st0[] = +{ + {64.2857f,119.048f}, + {54.7619f,114.286f}, + {50.0f,109.524f}, + {45.2381f,100.0f}, + {45.2381f,90.4762f}, + {50.0f,80.9524f}, + {54.7619f,76.1905f}, + {59.5238f,66.6667f}, + {59.5238f,57.1429f}, + {50.0f,47.619f} +}; + +static const SFG_StrokeVertex ch123st1[] = +{ + {54.7619f,114.286f}, + {50.0f,104.762f}, + {50.0f,95.2381f}, + {54.7619f,85.7143f}, + {59.5238f,80.9524f}, + {64.2857f,71.4286f}, + {64.2857f,61.9048f}, + {59.5238f,52.381f}, + {40.4762f,42.8571f}, + {59.5238f,33.3333f}, + {64.2857f,23.8095f}, + {64.2857f,14.2857f}, + {59.5238f,4.7619f}, + {54.7619f,0.0f}, + {50.0f,-9.5238f}, + {50.0f,-19.0476f}, + {54.7619f,-28.5714f} +}; + +static const SFG_StrokeVertex ch123st2[] = +{ + {50.0f,38.0952f}, + {59.5238f,28.5714f}, + {59.5238f,19.0476f}, + {54.7619f,9.5238f}, + {50.0f,4.7619f}, + {45.2381f,-4.7619f}, + {45.2381f,-14.2857f}, + {50.0f,-23.8095f}, + {54.7619f,-28.5714f}, + {64.2857f,-33.3333f} +}; + +static const SFG_StrokeStrip ch123st[] = +{ + {10,ch123st0}, + {17,ch123st1}, + {10,ch123st2} +}; + +static const SFG_StrokeChar ch123 = {104.762f,3,ch123st}; + +/* char: 0x7c */ + +static const SFG_StrokeVertex ch124st0[] = +{ + {52.381f,119.048f}, + {52.381f,-33.3333f} +}; + +static const SFG_StrokeStrip ch124st[] = +{ + {2,ch124st0} +}; + +static const SFG_StrokeChar ch124 = {104.762f,1,ch124st}; + +/* char: 0x7d */ + +static const SFG_StrokeVertex ch125st0[] = +{ + {40.4762f,119.048f}, + {50.0f,114.286f}, + {54.7619f,109.524f}, + {59.5238f,100.0f}, + {59.5238f,90.4762f}, + {54.7619f,80.9524f}, + {50.0f,76.1905f}, + {45.2381f,66.6667f}, + {45.2381f,57.1429f}, + {54.7619f,47.619f} +}; + +static const SFG_StrokeVertex ch125st1[] = +{ + {50.0f,114.286f}, + {54.7619f,104.762f}, + {54.7619f,95.2381f}, + {50.0f,85.7143f}, + {45.2381f,80.9524f}, + {40.4762f,71.4286f}, + {40.4762f,61.9048f}, + {45.2381f,52.381f}, + {64.2857f,42.8571f}, + {45.2381f,33.3333f}, + {40.4762f,23.8095f}, + {40.4762f,14.2857f}, + {45.2381f,4.7619f}, + {50.0f,0.0f}, + {54.7619f,-9.5238f}, + {54.7619f,-19.0476f}, + {50.0f,-28.5714f} +}; + +static const SFG_StrokeVertex ch125st2[] = +{ + {54.7619f,38.0952f}, + {45.2381f,28.5714f}, + {45.2381f,19.0476f}, + {50.0f,9.5238f}, + {54.7619f,4.7619f}, + {59.5238f,-4.7619f}, + {59.5238f,-14.2857f}, + {54.7619f,-23.8095f}, + {50.0f,-28.5714f}, + {40.4762f,-33.3333f} +}; + +static const SFG_StrokeStrip ch125st[] = +{ + {10,ch125st0}, + {17,ch125st1}, + {10,ch125st2} +}; + +static const SFG_StrokeChar ch125 = {104.762f,3,ch125st}; + +/* char: 0x7e */ + +static const SFG_StrokeVertex ch126st0[] = +{ + {9.5238f,28.5714f}, + {9.5238f,38.0952f}, + {14.2857f,52.381f}, + {23.8095f,57.1429f}, + {33.3333f,57.1429f}, + {42.8571f,52.381f}, + {61.9048f,38.0952f}, + {71.4286f,33.3333f}, + {80.9524f,33.3333f}, + {90.4762f,38.0952f}, + {95.2381f,47.619f} +}; + +static const SFG_StrokeVertex ch126st1[] = +{ + {9.5238f,38.0952f}, + {14.2857f,47.619f}, + {23.8095f,52.381f}, + {33.3333f,52.381f}, + {42.8571f,47.619f}, + {61.9048f,33.3333f}, + {71.4286f,28.5714f}, + {80.9524f,28.5714f}, + {90.4762f,33.3333f}, + {95.2381f,47.619f}, + {95.2381f,57.1429f} +}; + +static const SFG_StrokeStrip ch126st[] = +{ + {11,ch126st0}, + {11,ch126st1} +}; + +static const SFG_StrokeChar ch126 = {104.762f,2,ch126st}; + +/* char: 0x7f */ + +static const SFG_StrokeVertex ch127st0[] = +{ + {71.4286f,100.0f}, + {33.3333f,-33.3333f} +}; + +static const SFG_StrokeVertex ch127st1[] = +{ + {47.619f,66.6667f}, + {33.3333f,61.9048f}, + {23.8095f,52.381f}, + {19.0476f,38.0952f}, + {19.0476f,23.8095f}, + {23.8095f,14.2857f}, + {33.3333f,4.7619f}, + {47.619f,0.0f}, + {57.1428f,0.0f}, + {71.4286f,4.7619f}, + {80.9524f,14.2857f}, + {85.7143f,28.5714f}, + {85.7143f,42.8571f}, + {80.9524f,52.381f}, + {71.4286f,61.9048f}, + {57.1428f,66.6667f}, + {47.619f,66.6667f} +}; + +static const SFG_StrokeStrip ch127st[] = +{ + {2,ch127st0}, + {17,ch127st1} +}; + +static const SFG_StrokeChar ch127 = {104.762f,2,ch127st}; + +static const SFG_StrokeChar *chars[] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + &ch32, &ch33, &ch34, &ch35, &ch36, &ch37, &ch38, &ch39, + &ch40, &ch41, &ch42, &ch43, &ch44, &ch45, &ch46, &ch47, + &ch48, &ch49, &ch50, &ch51, &ch52, &ch53, &ch54, &ch55, + &ch56, &ch57, &ch58, &ch59, &ch60, &ch61, &ch62, &ch63, + &ch64, &ch65, &ch66, &ch67, &ch68, &ch69, &ch70, &ch71, + &ch72, &ch73, &ch74, &ch75, &ch76, &ch77, &ch78, &ch79, + &ch80, &ch81, &ch82, &ch83, &ch84, &ch85, &ch86, &ch87, + &ch88, &ch89, &ch90, &ch91, &ch92, &ch93, &ch94, &ch95, + &ch96, &ch97, &ch98, &ch99, &ch100, &ch101, &ch102, &ch103, + &ch104, &ch105, &ch106, &ch107, &ch108, &ch109, &ch110, &ch111, + &ch112, &ch113, &ch114, &ch115, &ch116, &ch117, &ch118, &ch119, + &ch120, &ch121, &ch122, &ch123, &ch124, &ch125, &ch126, &ch127 +}; + +const SFG_StrokeFont fgStrokeMonoRoman = {"MonoRoman",128,152.381f,chars}; diff --git a/tests/box2d/freeglut/freeglut_stroke_roman.c b/tests/box2d/freeglut/freeglut_stroke_roman.c new file mode 100755 index 00000000..619a9044 --- /dev/null +++ b/tests/box2d/freeglut/freeglut_stroke_roman.c @@ -0,0 +1,2849 @@ +/* + * freeglut_stroke_roman.c + * + * freeglut Roman stroke font definition + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, <olszta@sourceforge.net> + * Creation date: Thu Dec 16 1999 + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +/* This file has been automatically generated by the genstroke utility. */ + +#include "freeglut.h" +#include "freeglut_internal.h" + +/* char: 0x20 */ + +static const SFG_StrokeStrip ch32st[] = +{ + { 0, NULL } +}; + +static const SFG_StrokeChar ch32 = {104.762f,0,ch32st}; + +/* char: 0x21 */ + +static const SFG_StrokeVertex ch33st0[] = +{ + {13.3819f,100.0f}, + {13.3819f,33.3333f} +}; + +static const SFG_StrokeVertex ch33st1[] = +{ + {13.3819f,9.5238f}, + {8.62f,4.7619f}, + {13.3819f,0.0f}, + {18.1438f,4.7619f}, + {13.3819f,9.5238f} +}; + +static const SFG_StrokeStrip ch33st[] = +{ + {2,ch33st0}, + {5,ch33st1} +}; + +static const SFG_StrokeChar ch33 = {26.6238f,2,ch33st}; + +/* char: 0x22 */ + +static const SFG_StrokeVertex ch34st0[] = +{ + {4.02f,100.0f}, + {4.02f,66.6667f} +}; + +static const SFG_StrokeVertex ch34st1[] = +{ + {42.1152f,100.0f}, + {42.1152f,66.6667f} +}; + +static const SFG_StrokeStrip ch34st[] = +{ + {2,ch34st0}, + {2,ch34st1} +}; + +static const SFG_StrokeChar ch34 = {51.4352f,2,ch34st}; + +/* char: 0x23 */ + +static const SFG_StrokeVertex ch35st0[] = +{ + {41.2952f,119.048f}, + {7.9619f,-33.3333f} +}; + +static const SFG_StrokeVertex ch35st1[] = +{ + {69.8667f,119.048f}, + {36.5333f,-33.3333f} +}; + +static const SFG_StrokeVertex ch35st2[] = +{ + {7.9619f,57.1429f}, + {74.6286f,57.1429f} +}; + +static const SFG_StrokeVertex ch35st3[] = +{ + {3.2f,28.5714f}, + {69.8667f,28.5714f} +}; + +static const SFG_StrokeStrip ch35st[] = +{ + {2,ch35st0}, + {2,ch35st1}, + {2,ch35st2}, + {2,ch35st3} +}; + +static const SFG_StrokeChar ch35 = {79.4886f,4,ch35st}; + +/* char: 0x24 */ + +static const SFG_StrokeVertex ch36st0[] = +{ + {28.6295f,119.048f}, + {28.6295f,-19.0476f} +}; + +static const SFG_StrokeVertex ch36st1[] = +{ + {47.6771f,119.048f}, + {47.6771f,-19.0476f} +}; + +static const SFG_StrokeVertex ch36st2[] = +{ + {71.4867f,85.7143f}, + {61.9629f,95.2381f}, + {47.6771f,100.0f}, + {28.6295f,100.0f}, + {14.3438f,95.2381f}, + {4.82f,85.7143f}, + {4.82f,76.1905f}, + {9.5819f,66.6667f}, + {14.3438f,61.9048f}, + {23.8676f,57.1429f}, + {52.439f,47.619f}, + {61.9629f,42.8571f}, + {66.7248f,38.0952f}, + {71.4867f,28.5714f}, + {71.4867f,14.2857f}, + {61.9629f,4.7619f}, + {47.6771f,0.0f}, + {28.6295f,0.0f}, + {14.3438f,4.7619f}, + {4.82f,14.2857f} +}; + +static const SFG_StrokeStrip ch36st[] = +{ + {2,ch36st0}, + {2,ch36st1}, + {20,ch36st2} +}; + +static const SFG_StrokeChar ch36 = {76.2067f,3,ch36st}; + +/* char: 0x25 */ + +static const SFG_StrokeVertex ch37st0[] = +{ + {92.0743f,100.0f}, + {6.36f,0.0f} +}; + +static const SFG_StrokeVertex ch37st1[] = +{ + {30.1695f,100.0f}, + {39.6933f,90.4762f}, + {39.6933f,80.9524f}, + {34.9314f,71.4286f}, + {25.4076f,66.6667f}, + {15.8838f,66.6667f}, + {6.36f,76.1905f}, + {6.36f,85.7143f}, + {11.1219f,95.2381f}, + {20.6457f,100.0f}, + {30.1695f,100.0f}, + {39.6933f,95.2381f}, + {53.979f,90.4762f}, + {68.2648f,90.4762f}, + {82.5505f,95.2381f}, + {92.0743f,100.0f} +}; + +static const SFG_StrokeVertex ch37st2[] = +{ + {73.0267f,33.3333f}, + {63.5029f,28.5714f}, + {58.741f,19.0476f}, + {58.741f,9.5238f}, + {68.2648f,0.0f}, + {77.7886f,0.0f}, + {87.3124f,4.7619f}, + {92.0743f,14.2857f}, + {92.0743f,23.8095f}, + {82.5505f,33.3333f}, + {73.0267f,33.3333f} +}; + +static const SFG_StrokeStrip ch37st[] = +{ + {2,ch37st0}, + {16,ch37st1}, + {11,ch37st2} +}; + +static const SFG_StrokeChar ch37 = {96.5743f,3,ch37st}; + +/* char: 0x26 */ + +static const SFG_StrokeVertex ch38st0[] = +{ + {101.218f,57.1429f}, + {101.218f,61.9048f}, + {96.4562f,66.6667f}, + {91.6943f,66.6667f}, + {86.9324f,61.9048f}, + {82.1705f,52.381f}, + {72.6467f,28.5714f}, + {63.1229f,14.2857f}, + {53.599f,4.7619f}, + {44.0752f,0.0f}, + {25.0276f,0.0f}, + {15.5038f,4.7619f}, + {10.7419f,9.5238f}, + {5.98f,19.0476f}, + {5.98f,28.5714f}, + {10.7419f,38.0952f}, + {15.5038f,42.8571f}, + {48.8371f,61.9048f}, + {53.599f,66.6667f}, + {58.361f,76.1905f}, + {58.361f,85.7143f}, + {53.599f,95.2381f}, + {44.0752f,100.0f}, + {34.5514f,95.2381f}, + {29.7895f,85.7143f}, + {29.7895f,76.1905f}, + {34.5514f,61.9048f}, + {44.0752f,47.619f}, + {67.8848f,14.2857f}, + {77.4086f,4.7619f}, + {86.9324f,0.0f}, + {96.4562f,0.0f}, + {101.218f,4.7619f}, + {101.218f,9.5238f} +}; + +static const SFG_StrokeStrip ch38st[] = +{ + {34,ch38st0} +}; + +static const SFG_StrokeChar ch38 = {101.758f,1,ch38st}; + +/* char: 0x27 */ + +static const SFG_StrokeVertex ch39st0[] = +{ + {4.44f,100.0f}, + {4.44f,66.6667f} +}; + +static const SFG_StrokeStrip ch39st[] = +{ + {2,ch39st0} +}; + +static const SFG_StrokeChar ch39 = {13.62f,1,ch39st}; + +/* char: 0x28 */ + +static const SFG_StrokeVertex ch40st0[] = +{ + {40.9133f,119.048f}, + {31.3895f,109.524f}, + {21.8657f,95.2381f}, + {12.3419f,76.1905f}, + {7.58f,52.381f}, + {7.58f,33.3333f}, + {12.3419f,9.5238f}, + {21.8657f,-9.5238f}, + {31.3895f,-23.8095f}, + {40.9133f,-33.3333f} +}; + +static const SFG_StrokeStrip ch40st[] = +{ + {10,ch40st0} +}; + +static const SFG_StrokeChar ch40 = {47.1733f,1,ch40st}; + +/* char: 0x29 */ + +static const SFG_StrokeVertex ch41st0[] = +{ + {5.28f,119.048f}, + {14.8038f,109.524f}, + {24.3276f,95.2381f}, + {33.8514f,76.1905f}, + {38.6133f,52.381f}, + {38.6133f,33.3333f}, + {33.8514f,9.5238f}, + {24.3276f,-9.5238f}, + {14.8038f,-23.8095f}, + {5.28f,-33.3333f} +}; + +static const SFG_StrokeStrip ch41st[] = +{ + {10,ch41st0} +}; + +static const SFG_StrokeChar ch41 = {47.5333f,1,ch41st}; + +/* char: 0x2a */ + +static const SFG_StrokeVertex ch42st0[] = +{ + {30.7695f,71.4286f}, + {30.7695f,14.2857f} +}; + +static const SFG_StrokeVertex ch42st1[] = +{ + {6.96f,57.1429f}, + {54.579f,28.5714f} +}; + +static const SFG_StrokeVertex ch42st2[] = +{ + {54.579f,57.1429f}, + {6.96f,28.5714f} +}; + +static const SFG_StrokeStrip ch42st[] = +{ + {2,ch42st0}, + {2,ch42st1}, + {2,ch42st2} +}; + +static const SFG_StrokeChar ch42 = {59.439f,3,ch42st}; + +/* char: 0x2b */ + +static const SFG_StrokeVertex ch43st0[] = +{ + {48.8371f,85.7143f}, + {48.8371f,0.0f} +}; + +static const SFG_StrokeVertex ch43st1[] = +{ + {5.98f,42.8571f}, + {91.6943f,42.8571f} +}; + +static const SFG_StrokeStrip ch43st[] = +{ + {2,ch43st0}, + {2,ch43st1} +}; + +static const SFG_StrokeChar ch43 = {97.2543f,2,ch43st}; + +/* char: 0x2c */ + +static const SFG_StrokeVertex ch44st0[] = +{ + {18.2838f,4.7619f}, + {13.5219f,0.0f}, + {8.76f,4.7619f}, + {13.5219f,9.5238f}, + {18.2838f,4.7619f}, + {18.2838f,-4.7619f}, + {13.5219f,-14.2857f}, + {8.76f,-19.0476f} +}; + +static const SFG_StrokeStrip ch44st[] = +{ + {8,ch44st0} +}; + +static const SFG_StrokeChar ch44 = {26.0638f,1,ch44st}; + +/* char: 0x2d */ + +static const SFG_StrokeVertex ch45st0[] = +{ + {7.38f,42.8571f}, + {93.0943f,42.8571f} +}; + +static const SFG_StrokeStrip ch45st[] = +{ + {2,ch45st0} +}; + +static const SFG_StrokeChar ch45 = {100.754f,1,ch45st}; + +/* char: 0x2e */ + +static const SFG_StrokeVertex ch46st0[] = +{ + {13.1019f,9.5238f}, + {8.34f,4.7619f}, + {13.1019f,0.0f}, + {17.8638f,4.7619f}, + {13.1019f,9.5238f} +}; + +static const SFG_StrokeStrip ch46st[] = +{ + {5,ch46st0} +}; + +static const SFG_StrokeChar ch46 = {26.4838f,1,ch46st}; + +/* char: 0x2f */ + +static const SFG_StrokeVertex ch47st0[] = +{ + {7.24f,-14.2857f}, + {73.9067f,100.0f} +}; + +static const SFG_StrokeStrip ch47st[] = +{ + {2,ch47st0} +}; + +static const SFG_StrokeChar ch47 = {82.1067f,1,ch47st}; + +/* char: 0x30 */ + +static const SFG_StrokeVertex ch48st0[] = +{ + {33.5514f,100.0f}, + {19.2657f,95.2381f}, + {9.7419f,80.9524f}, + {4.98f,57.1429f}, + {4.98f,42.8571f}, + {9.7419f,19.0476f}, + {19.2657f,4.7619f}, + {33.5514f,0.0f}, + {43.0752f,0.0f}, + {57.361f,4.7619f}, + {66.8848f,19.0476f}, + {71.6467f,42.8571f}, + {71.6467f,57.1429f}, + {66.8848f,80.9524f}, + {57.361f,95.2381f}, + {43.0752f,100.0f}, + {33.5514f,100.0f} +}; + +static const SFG_StrokeStrip ch48st[] = +{ + {17,ch48st0} +}; + +static const SFG_StrokeChar ch48 = {77.0667f,1,ch48st}; + +/* char: 0x31 */ + +static const SFG_StrokeVertex ch49st0[] = +{ + {11.82f,80.9524f}, + {21.3438f,85.7143f}, + {35.6295f,100.0f}, + {35.6295f,0.0f} +}; + +static const SFG_StrokeStrip ch49st[] = +{ + {4,ch49st0} +}; + +static const SFG_StrokeChar ch49 = {66.5295f,1,ch49st}; + +/* char: 0x32 */ + +static const SFG_StrokeVertex ch50st0[] = +{ + {10.1819f,76.1905f}, + {10.1819f,80.9524f}, + {14.9438f,90.4762f}, + {19.7057f,95.2381f}, + {29.2295f,100.0f}, + {48.2771f,100.0f}, + {57.801f,95.2381f}, + {62.5629f,90.4762f}, + {67.3248f,80.9524f}, + {67.3248f,71.4286f}, + {62.5629f,61.9048f}, + {53.039f,47.619f}, + {5.42f,0.0f}, + {72.0867f,0.0f} +}; + +static const SFG_StrokeStrip ch50st[] = +{ + {14,ch50st0} +}; + +static const SFG_StrokeChar ch50 = {77.6467f,1,ch50st}; + +/* char: 0x33 */ + +static const SFG_StrokeVertex ch51st0[] = +{ + {14.5238f,100.0f}, + {66.9048f,100.0f}, + {38.3333f,61.9048f}, + {52.619f,61.9048f}, + {62.1429f,57.1429f}, + {66.9048f,52.381f}, + {71.6667f,38.0952f}, + {71.6667f,28.5714f}, + {66.9048f,14.2857f}, + {57.381f,4.7619f}, + {43.0952f,0.0f}, + {28.8095f,0.0f}, + {14.5238f,4.7619f}, + {9.7619f,9.5238f}, + {5.0f,19.0476f} +}; + +static const SFG_StrokeStrip ch51st[] = +{ + {15,ch51st0} +}; + +static const SFG_StrokeChar ch51 = {77.0467f,1,ch51st}; + +/* char: 0x34 */ + +static const SFG_StrokeVertex ch52st0[] = +{ + {51.499f,100.0f}, + {3.88f,33.3333f}, + {75.3086f,33.3333f} +}; + +static const SFG_StrokeVertex ch52st1[] = +{ + {51.499f,100.0f}, + {51.499f,0.0f} +}; + +static const SFG_StrokeStrip ch52st[] = +{ + {3,ch52st0}, + {2,ch52st1} +}; + +static const SFG_StrokeChar ch52 = {80.1686f,2,ch52st}; + +/* char: 0x35 */ + +static const SFG_StrokeVertex ch53st0[] = +{ + {62.0029f,100.0f}, + {14.3838f,100.0f}, + {9.6219f,57.1429f}, + {14.3838f,61.9048f}, + {28.6695f,66.6667f}, + {42.9552f,66.6667f}, + {57.241f,61.9048f}, + {66.7648f,52.381f}, + {71.5267f,38.0952f}, + {71.5267f,28.5714f}, + {66.7648f,14.2857f}, + {57.241f,4.7619f}, + {42.9552f,0.0f}, + {28.6695f,0.0f}, + {14.3838f,4.7619f}, + {9.6219f,9.5238f}, + {4.86f,19.0476f} +}; + +static const SFG_StrokeStrip ch53st[] = +{ + {17,ch53st0} +}; + +static const SFG_StrokeChar ch53 = {77.6867f,1,ch53st}; + +/* char: 0x36 */ + +static const SFG_StrokeVertex ch54st0[] = +{ + {62.7229f,85.7143f}, + {57.961f,95.2381f}, + {43.6752f,100.0f}, + {34.1514f,100.0f}, + {19.8657f,95.2381f}, + {10.3419f,80.9524f}, + {5.58f,57.1429f}, + {5.58f,33.3333f}, + {10.3419f,14.2857f}, + {19.8657f,4.7619f}, + {34.1514f,0.0f}, + {38.9133f,0.0f}, + {53.199f,4.7619f}, + {62.7229f,14.2857f}, + {67.4848f,28.5714f}, + {67.4848f,33.3333f}, + {62.7229f,47.619f}, + {53.199f,57.1429f}, + {38.9133f,61.9048f}, + {34.1514f,61.9048f}, + {19.8657f,57.1429f}, + {10.3419f,47.619f}, + {5.58f,33.3333f} +}; + +static const SFG_StrokeStrip ch54st[] = +{ + {23,ch54st0} +}; + +static const SFG_StrokeChar ch54 = {73.8048f,1,ch54st}; + +/* char: 0x37 */ + +static const SFG_StrokeVertex ch55st0[] = +{ + {72.2267f,100.0f}, + {24.6076f,0.0f} +}; + +static const SFG_StrokeVertex ch55st1[] = +{ + {5.56f,100.0f}, + {72.2267f,100.0f} +}; + +static const SFG_StrokeStrip ch55st[] = +{ + {2,ch55st0}, + {2,ch55st1} +}; + +static const SFG_StrokeChar ch55 = {77.2267f,2,ch55st}; + +/* char: 0x38 */ + +static const SFG_StrokeVertex ch56st0[] = +{ + {29.4095f,100.0f}, + {15.1238f,95.2381f}, + {10.3619f,85.7143f}, + {10.3619f,76.1905f}, + {15.1238f,66.6667f}, + {24.6476f,61.9048f}, + {43.6952f,57.1429f}, + {57.981f,52.381f}, + {67.5048f,42.8571f}, + {72.2667f,33.3333f}, + {72.2667f,19.0476f}, + {67.5048f,9.5238f}, + {62.7429f,4.7619f}, + {48.4571f,0.0f}, + {29.4095f,0.0f}, + {15.1238f,4.7619f}, + {10.3619f,9.5238f}, + {5.6f,19.0476f}, + {5.6f,33.3333f}, + {10.3619f,42.8571f}, + {19.8857f,52.381f}, + {34.1714f,57.1429f}, + {53.219f,61.9048f}, + {62.7429f,66.6667f}, + {67.5048f,76.1905f}, + {67.5048f,85.7143f}, + {62.7429f,95.2381f}, + {48.4571f,100.0f}, + {29.4095f,100.0f} +}; + +static const SFG_StrokeStrip ch56st[] = +{ + {29,ch56st0} +}; + +static const SFG_StrokeChar ch56 = {77.6667f,1,ch56st}; + +/* char: 0x39 */ + +static const SFG_StrokeVertex ch57st0[] = +{ + {68.5048f,66.6667f}, + {63.7429f,52.381f}, + {54.219f,42.8571f}, + {39.9333f,38.0952f}, + {35.1714f,38.0952f}, + {20.8857f,42.8571f}, + {11.3619f,52.381f}, + {6.6f,66.6667f}, + {6.6f,71.4286f}, + {11.3619f,85.7143f}, + {20.8857f,95.2381f}, + {35.1714f,100.0f}, + {39.9333f,100.0f}, + {54.219f,95.2381f}, + {63.7429f,85.7143f}, + {68.5048f,66.6667f}, + {68.5048f,42.8571f}, + {63.7429f,19.0476f}, + {54.219f,4.7619f}, + {39.9333f,0.0f}, + {30.4095f,0.0f}, + {16.1238f,4.7619f}, + {11.3619f,14.2857f} +}; + +static const SFG_StrokeStrip ch57st[] = +{ + {23,ch57st0} +}; + +static const SFG_StrokeChar ch57 = {74.0648f,1,ch57st}; + +/* char: 0x3a */ + +static const SFG_StrokeVertex ch58st0[] = +{ + {14.0819f,66.6667f}, + {9.32f,61.9048f}, + {14.0819f,57.1429f}, + {18.8438f,61.9048f}, + {14.0819f,66.6667f} +}; + +static const SFG_StrokeVertex ch58st1[] = +{ + {14.0819f,9.5238f}, + {9.32f,4.7619f}, + {14.0819f,0.0f}, + {18.8438f,4.7619f}, + {14.0819f,9.5238f} +}; + +static const SFG_StrokeStrip ch58st[] = +{ + {5,ch58st0}, + {5,ch58st1} +}; + +static const SFG_StrokeChar ch58 = {26.2238f,2,ch58st}; + +/* char: 0x3b */ + +static const SFG_StrokeVertex ch59st0[] = +{ + {12.9619f,66.6667f}, + {8.2f,61.9048f}, + {12.9619f,57.1429f}, + {17.7238f,61.9048f}, + {12.9619f,66.6667f} +}; + +static const SFG_StrokeVertex ch59st1[] = +{ + {17.7238f,4.7619f}, + {12.9619f,0.0f}, + {8.2f,4.7619f}, + {12.9619f,9.5238f}, + {17.7238f,4.7619f}, + {17.7238f,-4.7619f}, + {12.9619f,-14.2857f}, + {8.2f,-19.0476f} +}; + +static const SFG_StrokeStrip ch59st[] = +{ + {5,ch59st0}, + {8,ch59st1} +}; + +static const SFG_StrokeChar ch59 = {26.3038f,2,ch59st}; + +/* char: 0x3c */ + +static const SFG_StrokeVertex ch60st0[] = +{ + {79.2505f,85.7143f}, + {3.06f,42.8571f}, + {79.2505f,0.0f} +}; + +static const SFG_StrokeStrip ch60st[] = +{ + {3,ch60st0} +}; + +static const SFG_StrokeChar ch60 = {81.6105f,1,ch60st}; + +/* char: 0x3d */ + +static const SFG_StrokeVertex ch61st0[] = +{ + {5.7f,57.1429f}, + {91.4143f,57.1429f} +}; + +static const SFG_StrokeVertex ch61st1[] = +{ + {5.7f,28.5714f}, + {91.4143f,28.5714f} +}; + +static const SFG_StrokeStrip ch61st[] = +{ + {2,ch61st0}, + {2,ch61st1} +}; + +static const SFG_StrokeChar ch61 = {97.2543f,2,ch61st}; + +/* char: 0x3e */ + +static const SFG_StrokeVertex ch62st0[] = +{ + {2.78f,85.7143f}, + {78.9705f,42.8571f}, + {2.78f,0.0f} +}; + +static const SFG_StrokeStrip ch62st[] = +{ + {3,ch62st0} +}; + +static const SFG_StrokeChar ch62 = {81.6105f,1,ch62st}; + +/* char: 0x3f */ + +static const SFG_StrokeVertex ch63st0[] = +{ + {8.42f,76.1905f}, + {8.42f,80.9524f}, + {13.1819f,90.4762f}, + {17.9438f,95.2381f}, + {27.4676f,100.0f}, + {46.5152f,100.0f}, + {56.039f,95.2381f}, + {60.801f,90.4762f}, + {65.5629f,80.9524f}, + {65.5629f,71.4286f}, + {60.801f,61.9048f}, + {56.039f,57.1429f}, + {36.9914f,47.619f}, + {36.9914f,33.3333f} +}; + +static const SFG_StrokeVertex ch63st1[] = +{ + {36.9914f,9.5238f}, + {32.2295f,4.7619f}, + {36.9914f,0.0f}, + {41.7533f,4.7619f}, + {36.9914f,9.5238f} +}; + +static const SFG_StrokeStrip ch63st[] = +{ + {14,ch63st0}, + {5,ch63st1} +}; + +static const SFG_StrokeChar ch63 = {73.9029f,2,ch63st}; + +/* char: 0x40 */ + +static const SFG_StrokeVertex ch64st0[] = +{ + {49.2171f,52.381f}, + {39.6933f,57.1429f}, + {30.1695f,57.1429f}, + {25.4076f,47.619f}, + {25.4076f,42.8571f}, + {30.1695f,33.3333f}, + {39.6933f,33.3333f}, + {49.2171f,38.0952f} +}; + +static const SFG_StrokeVertex ch64st1[] = +{ + {49.2171f,57.1429f}, + {49.2171f,38.0952f}, + {53.979f,33.3333f}, + {63.5029f,33.3333f}, + {68.2648f,42.8571f}, + {68.2648f,47.619f}, + {63.5029f,61.9048f}, + {53.979f,71.4286f}, + {39.6933f,76.1905f}, + {34.9314f,76.1905f}, + {20.6457f,71.4286f}, + {11.1219f,61.9048f}, + {6.36f,47.619f}, + {6.36f,42.8571f}, + {11.1219f,28.5714f}, + {20.6457f,19.0476f}, + {34.9314f,14.2857f}, + {39.6933f,14.2857f}, + {53.979f,19.0476f} +}; + +static const SFG_StrokeStrip ch64st[] = +{ + {8,ch64st0}, + {19,ch64st1} +}; + +static const SFG_StrokeChar ch64 = {74.3648f,2,ch64st}; + +/* char: 0x41 */ + +static const SFG_StrokeVertex ch65st0[] = +{ + {40.5952f,100.0f}, + {2.5f,0.0f} +}; + +static const SFG_StrokeVertex ch65st1[] = +{ + {40.5952f,100.0f}, + {78.6905f,0.0f} +}; + +static const SFG_StrokeVertex ch65st2[] = +{ + {16.7857f,33.3333f}, + {64.4048f,33.3333f} +}; + +static const SFG_StrokeStrip ch65st[] = +{ + {2,ch65st0}, + {2,ch65st1}, + {2,ch65st2} +}; + +static const SFG_StrokeChar ch65 = {80.4905f,3,ch65st}; + +/* char: 0x42 */ + +static const SFG_StrokeVertex ch66st0[] = +{ + {11.42f,100.0f}, + {11.42f,0.0f} +}; + +static const SFG_StrokeVertex ch66st1[] = +{ + {11.42f,100.0f}, + {54.2771f,100.0f}, + {68.5629f,95.2381f}, + {73.3248f,90.4762f}, + {78.0867f,80.9524f}, + {78.0867f,71.4286f}, + {73.3248f,61.9048f}, + {68.5629f,57.1429f}, + {54.2771f,52.381f} +}; + +static const SFG_StrokeVertex ch66st2[] = +{ + {11.42f,52.381f}, + {54.2771f,52.381f}, + {68.5629f,47.619f}, + {73.3248f,42.8571f}, + {78.0867f,33.3333f}, + {78.0867f,19.0476f}, + {73.3248f,9.5238f}, + {68.5629f,4.7619f}, + {54.2771f,0.0f}, + {11.42f,0.0f} +}; + +static const SFG_StrokeStrip ch66st[] = +{ + {2,ch66st0}, + {9,ch66st1}, + {10,ch66st2} +}; + +static const SFG_StrokeChar ch66 = {83.6267f,3,ch66st}; + +/* char: 0x43 */ + +static const SFG_StrokeVertex ch67st0[] = +{ + {78.0886f,76.1905f}, + {73.3267f,85.7143f}, + {63.8029f,95.2381f}, + {54.279f,100.0f}, + {35.2314f,100.0f}, + {25.7076f,95.2381f}, + {16.1838f,85.7143f}, + {11.4219f,76.1905f}, + {6.66f,61.9048f}, + {6.66f,38.0952f}, + {11.4219f,23.8095f}, + {16.1838f,14.2857f}, + {25.7076f,4.7619f}, + {35.2314f,0.0f}, + {54.279f,0.0f}, + {63.8029f,4.7619f}, + {73.3267f,14.2857f}, + {78.0886f,23.8095f} +}; + +static const SFG_StrokeStrip ch67st[] = +{ + {18,ch67st0} +}; + +static const SFG_StrokeChar ch67 = {84.4886f,1,ch67st}; + +/* char: 0x44 */ + +static const SFG_StrokeVertex ch68st0[] = +{ + {11.96f,100.0f}, + {11.96f,0.0f} +}; + +static const SFG_StrokeVertex ch68st1[] = +{ + {11.96f,100.0f}, + {45.2933f,100.0f}, + {59.579f,95.2381f}, + {69.1029f,85.7143f}, + {73.8648f,76.1905f}, + {78.6267f,61.9048f}, + {78.6267f,38.0952f}, + {73.8648f,23.8095f}, + {69.1029f,14.2857f}, + {59.579f,4.7619f}, + {45.2933f,0.0f}, + {11.96f,0.0f} +}; + +static const SFG_StrokeStrip ch68st[] = +{ + {2,ch68st0}, + {12,ch68st1} +}; + +static const SFG_StrokeChar ch68 = {85.2867f,2,ch68st}; + +/* char: 0x45 */ + +static const SFG_StrokeVertex ch69st0[] = +{ + {11.42f,100.0f}, + {11.42f,0.0f} +}; + +static const SFG_StrokeVertex ch69st1[] = +{ + {11.42f,100.0f}, + {73.3248f,100.0f} +}; + +static const SFG_StrokeVertex ch69st2[] = +{ + {11.42f,52.381f}, + {49.5152f,52.381f} +}; + +static const SFG_StrokeVertex ch69st3[] = +{ + {11.42f,0.0f}, + {73.3248f,0.0f} +}; + +static const SFG_StrokeStrip ch69st[] = +{ + {2,ch69st0}, + {2,ch69st1}, + {2,ch69st2}, + {2,ch69st3} +}; + +static const SFG_StrokeChar ch69 = {78.1848f,4,ch69st}; + +/* char: 0x46 */ + +static const SFG_StrokeVertex ch70st0[] = +{ + {11.42f,100.0f}, + {11.42f,0.0f} +}; + +static const SFG_StrokeVertex ch70st1[] = +{ + {11.42f,100.0f}, + {73.3248f,100.0f} +}; + +static const SFG_StrokeVertex ch70st2[] = +{ + {11.42f,52.381f}, + {49.5152f,52.381f} +}; + +static const SFG_StrokeStrip ch70st[] = +{ + {2,ch70st0}, + {2,ch70st1}, + {2,ch70st2} +}; + +static const SFG_StrokeChar ch70 = {78.7448f,3,ch70st}; + +/* char: 0x47 */ + +static const SFG_StrokeVertex ch71st0[] = +{ + {78.4886f,76.1905f}, + {73.7267f,85.7143f}, + {64.2029f,95.2381f}, + {54.679f,100.0f}, + {35.6314f,100.0f}, + {26.1076f,95.2381f}, + {16.5838f,85.7143f}, + {11.8219f,76.1905f}, + {7.06f,61.9048f}, + {7.06f,38.0952f}, + {11.8219f,23.8095f}, + {16.5838f,14.2857f}, + {26.1076f,4.7619f}, + {35.6314f,0.0f}, + {54.679f,0.0f}, + {64.2029f,4.7619f}, + {73.7267f,14.2857f}, + {78.4886f,23.8095f}, + {78.4886f,38.0952f} +}; + +static const SFG_StrokeVertex ch71st1[] = +{ + {54.679f,38.0952f}, + {78.4886f,38.0952f} +}; + +static const SFG_StrokeStrip ch71st[] = +{ + {19,ch71st0}, + {2,ch71st1} +}; + +static const SFG_StrokeChar ch71 = {89.7686f,2,ch71st}; + +/* char: 0x48 */ + +static const SFG_StrokeVertex ch72st0[] = +{ + {11.42f,100.0f}, + {11.42f,0.0f} +}; + +static const SFG_StrokeVertex ch72st1[] = +{ + {78.0867f,100.0f}, + {78.0867f,0.0f} +}; + +static const SFG_StrokeVertex ch72st2[] = +{ + {11.42f,52.381f}, + {78.0867f,52.381f} +}; + +static const SFG_StrokeStrip ch72st[] = +{ + {2,ch72st0}, + {2,ch72st1}, + {2,ch72st2} +}; + +static const SFG_StrokeChar ch72 = {89.0867f,3,ch72st}; + +/* char: 0x49 */ + +static const SFG_StrokeVertex ch73st0[] = +{ + {10.86f,100.0f}, + {10.86f,0.0f} +}; + +static const SFG_StrokeStrip ch73st[] = +{ + {2,ch73st0} +}; + +static const SFG_StrokeChar ch73 = {21.3f,1,ch73st}; + +/* char: 0x4a */ + +static const SFG_StrokeVertex ch74st0[] = +{ + {50.119f,100.0f}, + {50.119f,23.8095f}, + {45.3571f,9.5238f}, + {40.5952f,4.7619f}, + {31.0714f,0.0f}, + {21.5476f,0.0f}, + {12.0238f,4.7619f}, + {7.2619f,9.5238f}, + {2.5f,23.8095f}, + {2.5f,33.3333f} +}; + +static const SFG_StrokeStrip ch74st[] = +{ + {10,ch74st0} +}; + +static const SFG_StrokeChar ch74 = {59.999f,1,ch74st}; + +/* char: 0x4b */ + +static const SFG_StrokeVertex ch75st0[] = +{ + {11.28f,100.0f}, + {11.28f,0.0f} +}; + +static const SFG_StrokeVertex ch75st1[] = +{ + {77.9467f,100.0f}, + {11.28f,33.3333f} +}; + +static const SFG_StrokeVertex ch75st2[] = +{ + {35.0895f,57.1429f}, + {77.9467f,0.0f} +}; + +static const SFG_StrokeStrip ch75st[] = +{ + {2,ch75st0}, + {2,ch75st1}, + {2,ch75st2} +}; + +static const SFG_StrokeChar ch75 = {79.3267f,3,ch75st}; + +/* char: 0x4c */ + +static const SFG_StrokeVertex ch76st0[] = +{ + {11.68f,100.0f}, + {11.68f,0.0f} +}; + +static const SFG_StrokeVertex ch76st1[] = +{ + {11.68f,0.0f}, + {68.8229f,0.0f} +}; + +static const SFG_StrokeStrip ch76st[] = +{ + {2,ch76st0}, + {2,ch76st1} +}; + +static const SFG_StrokeChar ch76 = {71.3229f,2,ch76st}; + +/* char: 0x4d */ + +static const SFG_StrokeVertex ch77st0[] = +{ + {10.86f,100.0f}, + {10.86f,0.0f} +}; + +static const SFG_StrokeVertex ch77st1[] = +{ + {10.86f,100.0f}, + {48.9552f,0.0f} +}; + +static const SFG_StrokeVertex ch77st2[] = +{ + {87.0505f,100.0f}, + {48.9552f,0.0f} +}; + +static const SFG_StrokeVertex ch77st3[] = +{ + {87.0505f,100.0f}, + {87.0505f,0.0f} +}; + +static const SFG_StrokeStrip ch77st[] = +{ + {2,ch77st0}, + {2,ch77st1}, + {2,ch77st2}, + {2,ch77st3} +}; + +static const SFG_StrokeChar ch77 = {97.2105f,4,ch77st}; + +/* char: 0x4e */ + +static const SFG_StrokeVertex ch78st0[] = +{ + {11.14f,100.0f}, + {11.14f,0.0f} +}; + +static const SFG_StrokeVertex ch78st1[] = +{ + {11.14f,100.0f}, + {77.8067f,0.0f} +}; + +static const SFG_StrokeVertex ch78st2[] = +{ + {77.8067f,100.0f}, + {77.8067f,0.0f} +}; + +static const SFG_StrokeStrip ch78st[] = +{ + {2,ch78st0}, + {2,ch78st1}, + {2,ch78st2} +}; + +static const SFG_StrokeChar ch78 = {88.8067f,3,ch78st}; + +/* char: 0x4f */ + +static const SFG_StrokeVertex ch79st0[] = +{ + {34.8114f,100.0f}, + {25.2876f,95.2381f}, + {15.7638f,85.7143f}, + {11.0019f,76.1905f}, + {6.24f,61.9048f}, + {6.24f,38.0952f}, + {11.0019f,23.8095f}, + {15.7638f,14.2857f}, + {25.2876f,4.7619f}, + {34.8114f,0.0f}, + {53.859f,0.0f}, + {63.3829f,4.7619f}, + {72.9067f,14.2857f}, + {77.6686f,23.8095f}, + {82.4305f,38.0952f}, + {82.4305f,61.9048f}, + {77.6686f,76.1905f}, + {72.9067f,85.7143f}, + {63.3829f,95.2381f}, + {53.859f,100.0f}, + {34.8114f,100.0f} +}; + +static const SFG_StrokeStrip ch79st[] = +{ + {21,ch79st0} +}; + +static const SFG_StrokeChar ch79 = {88.8305f,1,ch79st}; + +/* char: 0x50 */ + +static const SFG_StrokeVertex ch80st0[] = +{ + {12.1f,100.0f}, + {12.1f,0.0f} +}; + +static const SFG_StrokeVertex ch80st1[] = +{ + {12.1f,100.0f}, + {54.9571f,100.0f}, + {69.2429f,95.2381f}, + {74.0048f,90.4762f}, + {78.7667f,80.9524f}, + {78.7667f,66.6667f}, + {74.0048f,57.1429f}, + {69.2429f,52.381f}, + {54.9571f,47.619f}, + {12.1f,47.619f} +}; + +static const SFG_StrokeStrip ch80st[] = +{ + {2,ch80st0}, + {10,ch80st1} +}; + +static const SFG_StrokeChar ch80 = {85.6667f,2,ch80st}; + +/* char: 0x51 */ + +static const SFG_StrokeVertex ch81st0[] = +{ + {33.8714f,100.0f}, + {24.3476f,95.2381f}, + {14.8238f,85.7143f}, + {10.0619f,76.1905f}, + {5.3f,61.9048f}, + {5.3f,38.0952f}, + {10.0619f,23.8095f}, + {14.8238f,14.2857f}, + {24.3476f,4.7619f}, + {33.8714f,0.0f}, + {52.919f,0.0f}, + {62.4429f,4.7619f}, + {71.9667f,14.2857f}, + {76.7286f,23.8095f}, + {81.4905f,38.0952f}, + {81.4905f,61.9048f}, + {76.7286f,76.1905f}, + {71.9667f,85.7143f}, + {62.4429f,95.2381f}, + {52.919f,100.0f}, + {33.8714f,100.0f} +}; + +static const SFG_StrokeVertex ch81st1[] = +{ + {48.1571f,19.0476f}, + {76.7286f,-9.5238f} +}; + +static const SFG_StrokeStrip ch81st[] = +{ + {21,ch81st0}, + {2,ch81st1} +}; + +static const SFG_StrokeChar ch81 = {88.0905f,2,ch81st}; + +/* char: 0x52 */ + +static const SFG_StrokeVertex ch82st0[] = +{ + {11.68f,100.0f}, + {11.68f,0.0f} +}; + +static const SFG_StrokeVertex ch82st1[] = +{ + {11.68f,100.0f}, + {54.5371f,100.0f}, + {68.8229f,95.2381f}, + {73.5848f,90.4762f}, + {78.3467f,80.9524f}, + {78.3467f,71.4286f}, + {73.5848f,61.9048f}, + {68.8229f,57.1429f}, + {54.5371f,52.381f}, + {11.68f,52.381f} +}; + +static const SFG_StrokeVertex ch82st2[] = +{ + {45.0133f,52.381f}, + {78.3467f,0.0f} +}; + +static const SFG_StrokeStrip ch82st[] = +{ + {2,ch82st0}, + {10,ch82st1}, + {2,ch82st2} +}; + +static const SFG_StrokeChar ch82 = {82.3667f,3,ch82st}; + +/* char: 0x53 */ + +static const SFG_StrokeVertex ch83st0[] = +{ + {74.6667f,85.7143f}, + {65.1429f,95.2381f}, + {50.8571f,100.0f}, + {31.8095f,100.0f}, + {17.5238f,95.2381f}, + {8.0f,85.7143f}, + {8.0f,76.1905f}, + {12.7619f,66.6667f}, + {17.5238f,61.9048f}, + {27.0476f,57.1429f}, + {55.619f,47.619f}, + {65.1429f,42.8571f}, + {69.9048f,38.0952f}, + {74.6667f,28.5714f}, + {74.6667f,14.2857f}, + {65.1429f,4.7619f}, + {50.8571f,0.0f}, + {31.8095f,0.0f}, + {17.5238f,4.7619f}, + {8.0f,14.2857f} +}; + +static const SFG_StrokeStrip ch83st[] = +{ + {20,ch83st0} +}; + +static const SFG_StrokeChar ch83 = {80.8267f,1,ch83st}; + +/* char: 0x54 */ + +static const SFG_StrokeVertex ch84st0[] = +{ + {35.6933f,100.0f}, + {35.6933f,0.0f} +}; + +static const SFG_StrokeVertex ch84st1[] = +{ + {2.36f,100.0f}, + {69.0267f,100.0f} +}; + +static const SFG_StrokeStrip ch84st[] = +{ + {2,ch84st0}, + {2,ch84st1} +}; + +static const SFG_StrokeChar ch84 = {71.9467f,2,ch84st}; + +/* char: 0x55 */ + +static const SFG_StrokeVertex ch85st0[] = +{ + {11.54f,100.0f}, + {11.54f,28.5714f}, + {16.3019f,14.2857f}, + {25.8257f,4.7619f}, + {40.1114f,0.0f}, + {49.6352f,0.0f}, + {63.921f,4.7619f}, + {73.4448f,14.2857f}, + {78.2067f,28.5714f}, + {78.2067f,100.0f} +}; + +static const SFG_StrokeStrip ch85st[] = +{ + {10,ch85st0} +}; + +static const SFG_StrokeChar ch85 = {89.4867f,1,ch85st}; + +/* char: 0x56 */ + +static const SFG_StrokeVertex ch86st0[] = +{ + {2.36f,100.0f}, + {40.4552f,0.0f} +}; + +static const SFG_StrokeVertex ch86st1[] = +{ + {78.5505f,100.0f}, + {40.4552f,0.0f} +}; + +static const SFG_StrokeStrip ch86st[] = +{ + {2,ch86st0}, + {2,ch86st1} +}; + +static const SFG_StrokeChar ch86 = {81.6105f,2,ch86st}; + +/* char: 0x57 */ + +static const SFG_StrokeVertex ch87st0[] = +{ + {2.22f,100.0f}, + {26.0295f,0.0f} +}; + +static const SFG_StrokeVertex ch87st1[] = +{ + {49.839f,100.0f}, + {26.0295f,0.0f} +}; + +static const SFG_StrokeVertex ch87st2[] = +{ + {49.839f,100.0f}, + {73.6486f,0.0f} +}; + +static const SFG_StrokeVertex ch87st3[] = +{ + {97.4581f,100.0f}, + {73.6486f,0.0f} +}; + +static const SFG_StrokeStrip ch87st[] = +{ + {2,ch87st0}, + {2,ch87st1}, + {2,ch87st2}, + {2,ch87st3} +}; + +static const SFG_StrokeChar ch87 = {100.518f,4,ch87st}; + +/* char: 0x58 */ + +static const SFG_StrokeVertex ch88st0[] = +{ + {2.5f,100.0f}, + {69.1667f,0.0f} +}; + +static const SFG_StrokeVertex ch88st1[] = +{ + {69.1667f,100.0f}, + {2.5f,0.0f} +}; + +static const SFG_StrokeStrip ch88st[] = +{ + {2,ch88st0}, + {2,ch88st1} +}; + +static const SFG_StrokeChar ch88 = {72.3667f,2,ch88st}; + +/* char: 0x59 */ + +static const SFG_StrokeVertex ch89st0[] = +{ + {1.52f,100.0f}, + {39.6152f,52.381f}, + {39.6152f,0.0f} +}; + +static const SFG_StrokeVertex ch89st1[] = +{ + {77.7105f,100.0f}, + {39.6152f,52.381f} +}; + +static const SFG_StrokeStrip ch89st[] = +{ + {3,ch89st0}, + {2,ch89st1} +}; + +static const SFG_StrokeChar ch89 = {79.6505f,2,ch89st}; + +/* char: 0x5a */ + +static const SFG_StrokeVertex ch90st0[] = +{ + {69.1667f,100.0f}, + {2.5f,0.0f} +}; + +static const SFG_StrokeVertex ch90st1[] = +{ + {2.5f,100.0f}, + {69.1667f,100.0f} +}; + +static const SFG_StrokeVertex ch90st2[] = +{ + {2.5f,0.0f}, + {69.1667f,0.0f} +}; + +static const SFG_StrokeStrip ch90st[] = +{ + {2,ch90st0}, + {2,ch90st1}, + {2,ch90st2} +}; + +static const SFG_StrokeChar ch90 = {73.7467f,3,ch90st}; + +/* char: 0x5b */ + +static const SFG_StrokeVertex ch91st0[] = +{ + {7.78f,119.048f}, + {7.78f,-33.3333f} +}; + +static const SFG_StrokeVertex ch91st1[] = +{ + {12.5419f,119.048f}, + {12.5419f,-33.3333f} +}; + +static const SFG_StrokeVertex ch91st2[] = +{ + {7.78f,119.048f}, + {41.1133f,119.048f} +}; + +static const SFG_StrokeVertex ch91st3[] = +{ + {7.78f,-33.3333f}, + {41.1133f,-33.3333f} +}; + +static const SFG_StrokeStrip ch91st[] = +{ + {2,ch91st0}, + {2,ch91st1}, + {2,ch91st2}, + {2,ch91st3} +}; + +static const SFG_StrokeChar ch91 = {46.1133f,4,ch91st}; + +/* char: 0x5c */ + +static const SFG_StrokeVertex ch92st0[] = +{ + {5.84f,100.0f}, + {72.5067f,-14.2857f} +}; + +static const SFG_StrokeStrip ch92st[] = +{ + {2,ch92st0} +}; + +static const SFG_StrokeChar ch92 = {78.2067f,1,ch92st}; + +/* char: 0x5d */ + +static const SFG_StrokeVertex ch93st0[] = +{ + {33.0114f,119.048f}, + {33.0114f,-33.3333f} +}; + +static const SFG_StrokeVertex ch93st1[] = +{ + {37.7733f,119.048f}, + {37.7733f,-33.3333f} +}; + +static const SFG_StrokeVertex ch93st2[] = +{ + {4.44f,119.048f}, + {37.7733f,119.048f} +}; + +static const SFG_StrokeVertex ch93st3[] = +{ + {4.44f,-33.3333f}, + {37.7733f,-33.3333f} +}; + +static const SFG_StrokeStrip ch93st[] = +{ + {2,ch93st0}, + {2,ch93st1}, + {2,ch93st2}, + {2,ch93st3} +}; + +static const SFG_StrokeChar ch93 = {46.3933f,4,ch93st}; + +/* char: 0x5e */ + +static const SFG_StrokeVertex ch94st0[] = +{ + {44.0752f,109.524f}, + {5.98f,42.8571f} +}; + +static const SFG_StrokeVertex ch94st1[] = +{ + {44.0752f,109.524f}, + {82.1705f,42.8571f} +}; + +static const SFG_StrokeStrip ch94st[] = +{ + {2,ch94st0}, + {2,ch94st1} +}; + +static const SFG_StrokeChar ch94 = {90.2305f,2,ch94st}; + +/* char: 0x5f */ + +static const SFG_StrokeVertex ch95st0[] = +{ + {-1.1f,-33.3333f}, + {103.662f,-33.3333f}, + {103.662f,-28.5714f}, + {-1.1f,-28.5714f}, + {-1.1f,-33.3333f} +}; + +static const SFG_StrokeStrip ch95st[] = +{ + {5,ch95st0} +}; + +static const SFG_StrokeChar ch95 = {104.062f,1,ch95st}; + +/* char: 0x60 */ + +static const SFG_StrokeVertex ch96st0[] = +{ + {33.0219f,100.0f}, + {56.8314f,71.4286f} +}; + +static const SFG_StrokeVertex ch96st1[] = +{ + {33.0219f,100.0f}, + {28.26f,95.2381f}, + {56.8314f,71.4286f} +}; + +static const SFG_StrokeStrip ch96st[] = +{ + {2,ch96st0}, + {3,ch96st1} +}; + +static const SFG_StrokeChar ch96 = {83.5714f,2,ch96st}; + +/* char: 0x61 */ + +static const SFG_StrokeVertex ch97st0[] = +{ + {63.8229f,66.6667f}, + {63.8229f,0.0f} +}; + +static const SFG_StrokeVertex ch97st1[] = +{ + {63.8229f,52.381f}, + {54.299f,61.9048f}, + {44.7752f,66.6667f}, + {30.4895f,66.6667f}, + {20.9657f,61.9048f}, + {11.4419f,52.381f}, + {6.68f,38.0952f}, + {6.68f,28.5714f}, + {11.4419f,14.2857f}, + {20.9657f,4.7619f}, + {30.4895f,0.0f}, + {44.7752f,0.0f}, + {54.299f,4.7619f}, + {63.8229f,14.2857f} +}; + +static const SFG_StrokeStrip ch97st[] = +{ + {2,ch97st0}, + {14,ch97st1} +}; + +static const SFG_StrokeChar ch97 = {66.6029f,2,ch97st}; + +/* char: 0x62 */ + +static const SFG_StrokeVertex ch98st0[] = +{ + {8.76f,100.0f}, + {8.76f,0.0f} +}; + +static const SFG_StrokeVertex ch98st1[] = +{ + {8.76f,52.381f}, + {18.2838f,61.9048f}, + {27.8076f,66.6667f}, + {42.0933f,66.6667f}, + {51.6171f,61.9048f}, + {61.141f,52.381f}, + {65.9029f,38.0952f}, + {65.9029f,28.5714f}, + {61.141f,14.2857f}, + {51.6171f,4.7619f}, + {42.0933f,0.0f}, + {27.8076f,0.0f}, + {18.2838f,4.7619f}, + {8.76f,14.2857f} +}; + +static const SFG_StrokeStrip ch98st[] = +{ + {2,ch98st0}, + {14,ch98st1} +}; + +static const SFG_StrokeChar ch98 = {70.4629f,2,ch98st}; + +/* char: 0x63 */ + +static const SFG_StrokeVertex ch99st0[] = +{ + {62.6629f,52.381f}, + {53.139f,61.9048f}, + {43.6152f,66.6667f}, + {29.3295f,66.6667f}, + {19.8057f,61.9048f}, + {10.2819f,52.381f}, + {5.52f,38.0952f}, + {5.52f,28.5714f}, + {10.2819f,14.2857f}, + {19.8057f,4.7619f}, + {29.3295f,0.0f}, + {43.6152f,0.0f}, + {53.139f,4.7619f}, + {62.6629f,14.2857f} +}; + +static const SFG_StrokeStrip ch99st[] = +{ + {14,ch99st0} +}; + +static const SFG_StrokeChar ch99 = {68.9229f,1,ch99st}; + +/* char: 0x64 */ + +static const SFG_StrokeVertex ch100st0[] = +{ + {61.7829f,100.0f}, + {61.7829f,0.0f} +}; + +static const SFG_StrokeVertex ch100st1[] = +{ + {61.7829f,52.381f}, + {52.259f,61.9048f}, + {42.7352f,66.6667f}, + {28.4495f,66.6667f}, + {18.9257f,61.9048f}, + {9.4019f,52.381f}, + {4.64f,38.0952f}, + {4.64f,28.5714f}, + {9.4019f,14.2857f}, + {18.9257f,4.7619f}, + {28.4495f,0.0f}, + {42.7352f,0.0f}, + {52.259f,4.7619f}, + {61.7829f,14.2857f} +}; + +static const SFG_StrokeStrip ch100st[] = +{ + {2,ch100st0}, + {14,ch100st1} +}; + +static const SFG_StrokeChar ch100 = {70.2629f,2,ch100st}; + +/* char: 0x65 */ + +static const SFG_StrokeVertex ch101st0[] = +{ + {5.72f,38.0952f}, + {62.8629f,38.0952f}, + {62.8629f,47.619f}, + {58.101f,57.1429f}, + {53.339f,61.9048f}, + {43.8152f,66.6667f}, + {29.5295f,66.6667f}, + {20.0057f,61.9048f}, + {10.4819f,52.381f}, + {5.72f,38.0952f}, + {5.72f,28.5714f}, + {10.4819f,14.2857f}, + {20.0057f,4.7619f}, + {29.5295f,0.0f}, + {43.8152f,0.0f}, + {53.339f,4.7619f}, + {62.8629f,14.2857f} +}; + +static const SFG_StrokeStrip ch101st[] = +{ + {17,ch101st0} +}; + +static const SFG_StrokeChar ch101 = {68.5229f,1,ch101st}; + +/* char: 0x66 */ + +static const SFG_StrokeVertex ch102st0[] = +{ + {38.7752f,100.0f}, + {29.2514f,100.0f}, + {19.7276f,95.2381f}, + {14.9657f,80.9524f}, + {14.9657f,0.0f} +}; + +static const SFG_StrokeVertex ch102st1[] = +{ + {0.68f,66.6667f}, + {34.0133f,66.6667f} +}; + +static const SFG_StrokeStrip ch102st[] = +{ + {5,ch102st0}, + {2,ch102st1} +}; + +static const SFG_StrokeChar ch102 = {38.6552f,2,ch102st}; + +/* char: 0x67 */ + +static const SFG_StrokeVertex ch103st0[] = +{ + {62.5029f,66.6667f}, + {62.5029f,-9.5238f}, + {57.741f,-23.8095f}, + {52.979f,-28.5714f}, + {43.4552f,-33.3333f}, + {29.1695f,-33.3333f}, + {19.6457f,-28.5714f} +}; + +static const SFG_StrokeVertex ch103st1[] = +{ + {62.5029f,52.381f}, + {52.979f,61.9048f}, + {43.4552f,66.6667f}, + {29.1695f,66.6667f}, + {19.6457f,61.9048f}, + {10.1219f,52.381f}, + {5.36f,38.0952f}, + {5.36f,28.5714f}, + {10.1219f,14.2857f}, + {19.6457f,4.7619f}, + {29.1695f,0.0f}, + {43.4552f,0.0f}, + {52.979f,4.7619f}, + {62.5029f,14.2857f} +}; + +static const SFG_StrokeStrip ch103st[] = +{ + {7,ch103st0}, + {14,ch103st1} +}; + +static const SFG_StrokeChar ch103 = {70.9829f,2,ch103st}; + +/* char: 0x68 */ + +static const SFG_StrokeVertex ch104st0[] = +{ + {9.6f,100.0f}, + {9.6f,0.0f} +}; + +static const SFG_StrokeVertex ch104st1[] = +{ + {9.6f,47.619f}, + {23.8857f,61.9048f}, + {33.4095f,66.6667f}, + {47.6952f,66.6667f}, + {57.219f,61.9048f}, + {61.981f,47.619f}, + {61.981f,0.0f} +}; + +static const SFG_StrokeStrip ch104st[] = +{ + {2,ch104st0}, + {7,ch104st1} +}; + +static const SFG_StrokeChar ch104 = {71.021f,2,ch104st}; + +/* char: 0x69 */ + +static const SFG_StrokeVertex ch105st0[] = +{ + {10.02f,100.0f}, + {14.7819f,95.2381f}, + {19.5438f,100.0f}, + {14.7819f,104.762f}, + {10.02f,100.0f} +}; + +static const SFG_StrokeVertex ch105st1[] = +{ + {14.7819f,66.6667f}, + {14.7819f,0.0f} +}; + +static const SFG_StrokeStrip ch105st[] = +{ + {5,ch105st0}, + {2,ch105st1} +}; + +static const SFG_StrokeChar ch105 = {28.8638f,2,ch105st}; + +/* char: 0x6a */ + +static const SFG_StrokeVertex ch106st0[] = +{ + {17.3876f,100.0f}, + {22.1495f,95.2381f}, + {26.9114f,100.0f}, + {22.1495f,104.762f}, + {17.3876f,100.0f} +}; + +static const SFG_StrokeVertex ch106st1[] = +{ + {22.1495f,66.6667f}, + {22.1495f,-14.2857f}, + {17.3876f,-28.5714f}, + {7.8638f,-33.3333f}, + {-1.66f,-33.3333f} +}; + +static const SFG_StrokeStrip ch106st[] = +{ + {5,ch106st0}, + {5,ch106st1} +}; + +static const SFG_StrokeChar ch106 = {36.2314f,2,ch106st}; + +/* char: 0x6b */ + +static const SFG_StrokeVertex ch107st0[] = +{ + {9.6f,100.0f}, + {9.6f,0.0f} +}; + +static const SFG_StrokeVertex ch107st1[] = +{ + {57.219f,66.6667f}, + {9.6f,19.0476f} +}; + +static const SFG_StrokeVertex ch107st2[] = +{ + {28.6476f,38.0952f}, + {61.981f,0.0f} +}; + +static const SFG_StrokeStrip ch107st[] = +{ + {2,ch107st0}, + {2,ch107st1}, + {2,ch107st2} +}; + +static const SFG_StrokeChar ch107 = {62.521f,3,ch107st}; + +/* char: 0x6c */ + +static const SFG_StrokeVertex ch108st0[] = +{ + {10.02f,100.0f}, + {10.02f,0.0f} +}; + +static const SFG_StrokeStrip ch108st[] = +{ + {2,ch108st0} +}; + +static const SFG_StrokeChar ch108 = {19.34f,1,ch108st}; + +/* char: 0x6d */ + +static const SFG_StrokeVertex ch109st0[] = +{ + {9.6f,66.6667f}, + {9.6f,0.0f} +}; + +static const SFG_StrokeVertex ch109st1[] = +{ + {9.6f,47.619f}, + {23.8857f,61.9048f}, + {33.4095f,66.6667f}, + {47.6952f,66.6667f}, + {57.219f,61.9048f}, + {61.981f,47.619f}, + {61.981f,0.0f} +}; + +static const SFG_StrokeVertex ch109st2[] = +{ + {61.981f,47.619f}, + {76.2667f,61.9048f}, + {85.7905f,66.6667f}, + {100.076f,66.6667f}, + {109.6f,61.9048f}, + {114.362f,47.619f}, + {114.362f,0.0f} +}; + +static const SFG_StrokeStrip ch109st[] = +{ + {2,ch109st0}, + {7,ch109st1}, + {7,ch109st2} +}; + +static const SFG_StrokeChar ch109 = {123.962f,3,ch109st}; + +/* char: 0x6e */ + +static const SFG_StrokeVertex ch110st0[] = +{ + {9.18f,66.6667f}, + {9.18f,0.0f} +}; + +static const SFG_StrokeVertex ch110st1[] = +{ + {9.18f,47.619f}, + {23.4657f,61.9048f}, + {32.9895f,66.6667f}, + {47.2752f,66.6667f}, + {56.799f,61.9048f}, + {61.561f,47.619f}, + {61.561f,0.0f} +}; + +static const SFG_StrokeStrip ch110st[] = +{ + {2,ch110st0}, + {7,ch110st1} +}; + +static const SFG_StrokeChar ch110 = {70.881f,2,ch110st}; + +/* char: 0x6f */ + +static const SFG_StrokeVertex ch111st0[] = +{ + {28.7895f,66.6667f}, + {19.2657f,61.9048f}, + {9.7419f,52.381f}, + {4.98f,38.0952f}, + {4.98f,28.5714f}, + {9.7419f,14.2857f}, + {19.2657f,4.7619f}, + {28.7895f,0.0f}, + {43.0752f,0.0f}, + {52.599f,4.7619f}, + {62.1229f,14.2857f}, + {66.8848f,28.5714f}, + {66.8848f,38.0952f}, + {62.1229f,52.381f}, + {52.599f,61.9048f}, + {43.0752f,66.6667f}, + {28.7895f,66.6667f} +}; + +static const SFG_StrokeStrip ch111st[] = +{ + {17,ch111st0} +}; + +static const SFG_StrokeChar ch111 = {71.7448f,1,ch111st}; + +/* char: 0x70 */ + +static const SFG_StrokeVertex ch112st0[] = +{ + {9.46f,66.6667f}, + {9.46f,-33.3333f} +}; + +static const SFG_StrokeVertex ch112st1[] = +{ + {9.46f,52.381f}, + {18.9838f,61.9048f}, + {28.5076f,66.6667f}, + {42.7933f,66.6667f}, + {52.3171f,61.9048f}, + {61.841f,52.381f}, + {66.6029f,38.0952f}, + {66.6029f,28.5714f}, + {61.841f,14.2857f}, + {52.3171f,4.7619f}, + {42.7933f,0.0f}, + {28.5076f,0.0f}, + {18.9838f,4.7619f}, + {9.46f,14.2857f} +}; + +static const SFG_StrokeStrip ch112st[] = +{ + {2,ch112st0}, + {14,ch112st1} +}; + +static const SFG_StrokeChar ch112 = {70.8029f,2,ch112st}; + +/* char: 0x71 */ + +static const SFG_StrokeVertex ch113st0[] = +{ + {61.9829f,66.6667f}, + {61.9829f,-33.3333f} +}; + +static const SFG_StrokeVertex ch113st1[] = +{ + {61.9829f,52.381f}, + {52.459f,61.9048f}, + {42.9352f,66.6667f}, + {28.6495f,66.6667f}, + {19.1257f,61.9048f}, + {9.6019f,52.381f}, + {4.84f,38.0952f}, + {4.84f,28.5714f}, + {9.6019f,14.2857f}, + {19.1257f,4.7619f}, + {28.6495f,0.0f}, + {42.9352f,0.0f}, + {52.459f,4.7619f}, + {61.9829f,14.2857f} +}; + +static const SFG_StrokeStrip ch113st[] = +{ + {2,ch113st0}, + {14,ch113st1} +}; + +static const SFG_StrokeChar ch113 = {70.7429f,2,ch113st}; + +/* char: 0x72 */ + +static const SFG_StrokeVertex ch114st0[] = +{ + {9.46f,66.6667f}, + {9.46f,0.0f} +}; + +static const SFG_StrokeVertex ch114st1[] = +{ + {9.46f,38.0952f}, + {14.2219f,52.381f}, + {23.7457f,61.9048f}, + {33.2695f,66.6667f}, + {47.5552f,66.6667f} +}; + +static const SFG_StrokeStrip ch114st[] = +{ + {2,ch114st0}, + {5,ch114st1} +}; + +static const SFG_StrokeChar ch114 = {49.4952f,2,ch114st}; + +/* char: 0x73 */ + +static const SFG_StrokeVertex ch115st0[] = +{ + {57.081f,52.381f}, + {52.319f,61.9048f}, + {38.0333f,66.6667f}, + {23.7476f,66.6667f}, + {9.4619f,61.9048f}, + {4.7f,52.381f}, + {9.4619f,42.8571f}, + {18.9857f,38.0952f}, + {42.7952f,33.3333f}, + {52.319f,28.5714f}, + {57.081f,19.0476f}, + {57.081f,14.2857f}, + {52.319f,4.7619f}, + {38.0333f,0.0f}, + {23.7476f,0.0f}, + {9.4619f,4.7619f}, + {4.7f,14.2857f} +}; + +static const SFG_StrokeStrip ch115st[] = +{ + {17,ch115st0} +}; + +static const SFG_StrokeChar ch115 = {62.321f,1,ch115st}; + +/* char: 0x74 */ + +static const SFG_StrokeVertex ch116st0[] = +{ + {14.8257f,100.0f}, + {14.8257f,19.0476f}, + {19.5876f,4.7619f}, + {29.1114f,0.0f}, + {38.6352f,0.0f} +}; + +static const SFG_StrokeVertex ch116st1[] = +{ + {0.54f,66.6667f}, + {33.8733f,66.6667f} +}; + +static const SFG_StrokeStrip ch116st[] = +{ + {5,ch116st0}, + {2,ch116st1} +}; + +static const SFG_StrokeChar ch116 = {39.3152f,2,ch116st}; + +/* char: 0x75 */ + +static const SFG_StrokeVertex ch117st0[] = +{ + {9.46f,66.6667f}, + {9.46f,19.0476f}, + {14.2219f,4.7619f}, + {23.7457f,0.0f}, + {38.0314f,0.0f}, + {47.5552f,4.7619f}, + {61.841f,19.0476f} +}; + +static const SFG_StrokeVertex ch117st1[] = +{ + {61.841f,66.6667f}, + {61.841f,0.0f} +}; + +static const SFG_StrokeStrip ch117st[] = +{ + {7,ch117st0}, + {2,ch117st1} +}; + +static const SFG_StrokeChar ch117 = {71.161f,2,ch117st}; + +/* char: 0x76 */ + +static const SFG_StrokeVertex ch118st0[] = +{ + {1.8f,66.6667f}, + {30.3714f,0.0f} +}; + +static const SFG_StrokeVertex ch118st1[] = +{ + {58.9429f,66.6667f}, + {30.3714f,0.0f} +}; + +static const SFG_StrokeStrip ch118st[] = +{ + {2,ch118st0}, + {2,ch118st1} +}; + +static const SFG_StrokeChar ch118 = {60.6029f,2,ch118st}; + +/* char: 0x77 */ + +static const SFG_StrokeVertex ch119st0[] = +{ + {2.5f,66.6667f}, + {21.5476f,0.0f} +}; + +static const SFG_StrokeVertex ch119st1[] = +{ + {40.5952f,66.6667f}, + {21.5476f,0.0f} +}; + +static const SFG_StrokeVertex ch119st2[] = +{ + {40.5952f,66.6667f}, + {59.6429f,0.0f} +}; + +static const SFG_StrokeVertex ch119st3[] = +{ + {78.6905f,66.6667f}, + {59.6429f,0.0f} +}; + +static const SFG_StrokeStrip ch119st[] = +{ + {2,ch119st0}, + {2,ch119st1}, + {2,ch119st2}, + {2,ch119st3} +}; + +static const SFG_StrokeChar ch119 = {80.4905f,4,ch119st}; + +/* char: 0x78 */ + +static const SFG_StrokeVertex ch120st0[] = +{ + {1.66f,66.6667f}, + {54.041f,0.0f} +}; + +static const SFG_StrokeVertex ch120st1[] = +{ + {54.041f,66.6667f}, + {1.66f,0.0f} +}; + +static const SFG_StrokeStrip ch120st[] = +{ + {2,ch120st0}, + {2,ch120st1} +}; + +static const SFG_StrokeChar ch120 = {56.401f,2,ch120st}; + +/* char: 0x79 */ + +static const SFG_StrokeVertex ch121st0[] = +{ + {6.5619f,66.6667f}, + {35.1333f,0.0f} +}; + +static const SFG_StrokeVertex ch121st1[] = +{ + {63.7048f,66.6667f}, + {35.1333f,0.0f}, + {25.6095f,-19.0476f}, + {16.0857f,-28.5714f}, + {6.5619f,-33.3333f}, + {1.8f,-33.3333f} +}; + +static const SFG_StrokeStrip ch121st[] = +{ + {2,ch121st0}, + {6,ch121st1} +}; + +static const SFG_StrokeChar ch121 = {66.0648f,2,ch121st}; + +/* char: 0x7a */ + +static const SFG_StrokeVertex ch122st0[] = +{ + {56.821f,66.6667f}, + {4.44f,0.0f} +}; + +static const SFG_StrokeVertex ch122st1[] = +{ + {4.44f,66.6667f}, + {56.821f,66.6667f} +}; + +static const SFG_StrokeVertex ch122st2[] = +{ + {4.44f,0.0f}, + {56.821f,0.0f} +}; + +static const SFG_StrokeStrip ch122st[] = +{ + {2,ch122st0}, + {2,ch122st1}, + {2,ch122st2} +}; + +static const SFG_StrokeChar ch122 = {61.821f,3,ch122st}; + +/* char: 0x7b */ + +static const SFG_StrokeVertex ch123st0[] = +{ + {31.1895f,119.048f}, + {21.6657f,114.286f}, + {16.9038f,109.524f}, + {12.1419f,100.0f}, + {12.1419f,90.4762f}, + {16.9038f,80.9524f}, + {21.6657f,76.1905f}, + {26.4276f,66.6667f}, + {26.4276f,57.1429f}, + {16.9038f,47.619f} +}; + +static const SFG_StrokeVertex ch123st1[] = +{ + {21.6657f,114.286f}, + {16.9038f,104.762f}, + {16.9038f,95.2381f}, + {21.6657f,85.7143f}, + {26.4276f,80.9524f}, + {31.1895f,71.4286f}, + {31.1895f,61.9048f}, + {26.4276f,52.381f}, + {7.38f,42.8571f}, + {26.4276f,33.3333f}, + {31.1895f,23.8095f}, + {31.1895f,14.2857f}, + {26.4276f,4.7619f}, + {21.6657f,0.0f}, + {16.9038f,-9.5238f}, + {16.9038f,-19.0476f}, + {21.6657f,-28.5714f} +}; + +static const SFG_StrokeVertex ch123st2[] = +{ + {16.9038f,38.0952f}, + {26.4276f,28.5714f}, + {26.4276f,19.0476f}, + {21.6657f,9.5238f}, + {16.9038f,4.7619f}, + {12.1419f,-4.7619f}, + {12.1419f,-14.2857f}, + {16.9038f,-23.8095f}, + {21.6657f,-28.5714f}, + {31.1895f,-33.3333f} +}; + +static const SFG_StrokeStrip ch123st[] = +{ + {10,ch123st0}, + {17,ch123st1}, + {10,ch123st2} +}; + +static const SFG_StrokeChar ch123 = {41.6295f,3,ch123st}; + +/* char: 0x7c */ + +static const SFG_StrokeVertex ch124st0[] = +{ + {11.54f,119.048f}, + {11.54f,-33.3333f} +}; + +static const SFG_StrokeStrip ch124st[] = +{ + {2,ch124st0} +}; + +static const SFG_StrokeChar ch124 = {23.78f,1,ch124st}; + +/* char: 0x7d */ + +static const SFG_StrokeVertex ch125st0[] = +{ + {9.18f,119.048f}, + {18.7038f,114.286f}, + {23.4657f,109.524f}, + {28.2276f,100.0f}, + {28.2276f,90.4762f}, + {23.4657f,80.9524f}, + {18.7038f,76.1905f}, + {13.9419f,66.6667f}, + {13.9419f,57.1429f}, + {23.4657f,47.619f} +}; + +static const SFG_StrokeVertex ch125st1[] = +{ + {18.7038f,114.286f}, + {23.4657f,104.762f}, + {23.4657f,95.2381f}, + {18.7038f,85.7143f}, + {13.9419f,80.9524f}, + {9.18f,71.4286f}, + {9.18f,61.9048f}, + {13.9419f,52.381f}, + {32.9895f,42.8571f}, + {13.9419f,33.3333f}, + {9.18f,23.8095f}, + {9.18f,14.2857f}, + {13.9419f,4.7619f}, + {18.7038f,0.0f}, + {23.4657f,-9.5238f}, + {23.4657f,-19.0476f}, + {18.7038f,-28.5714f} +}; + +static const SFG_StrokeVertex ch125st2[] = +{ + {23.4657f,38.0952f}, + {13.9419f,28.5714f}, + {13.9419f,19.0476f}, + {18.7038f,9.5238f}, + {23.4657f,4.7619f}, + {28.2276f,-4.7619f}, + {28.2276f,-14.2857f}, + {23.4657f,-23.8095f}, + {18.7038f,-28.5714f}, + {9.18f,-33.3333f} +}; + +static const SFG_StrokeStrip ch125st[] = +{ + {10,ch125st0}, + {17,ch125st1}, + {10,ch125st2} +}; + +static const SFG_StrokeChar ch125 = {41.4695f,3,ch125st}; + +/* char: 0x7e */ + +static const SFG_StrokeVertex ch126st0[] = +{ + {2.92f,28.5714f}, + {2.92f,38.0952f}, + {7.6819f,52.381f}, + {17.2057f,57.1429f}, + {26.7295f,57.1429f}, + {36.2533f,52.381f}, + {55.301f,38.0952f}, + {64.8248f,33.3333f}, + {74.3486f,33.3333f}, + {83.8724f,38.0952f}, + {88.6343f,47.619f} +}; + +static const SFG_StrokeVertex ch126st1[] = +{ + {2.92f,38.0952f}, + {7.6819f,47.619f}, + {17.2057f,52.381f}, + {26.7295f,52.381f}, + {36.2533f,47.619f}, + {55.301f,33.3333f}, + {64.8248f,28.5714f}, + {74.3486f,28.5714f}, + {83.8724f,33.3333f}, + {88.6343f,47.619f}, + {88.6343f,57.1429f} +}; + +static const SFG_StrokeStrip ch126st[] = +{ + {11,ch126st0}, + {11,ch126st1} +}; + +static const SFG_StrokeChar ch126 = {91.2743f,2,ch126st}; + +/* char: 0x7f */ + +static const SFG_StrokeVertex ch127st0[] = +{ + {52.381f,100.0f}, + {14.2857f,-33.3333f} +}; + +static const SFG_StrokeVertex ch127st1[] = +{ + {28.5714f,66.6667f}, + {14.2857f,61.9048f}, + {4.7619f,52.381f}, + {0.0f,38.0952f}, + {0.0f,23.8095f}, + {4.7619f,14.2857f}, + {14.2857f,4.7619f}, + {28.5714f,0.0f}, + {38.0952f,0.0f}, + {52.381f,4.7619f}, + {61.9048f,14.2857f}, + {66.6667f,28.5714f}, + {66.6667f,42.8571f}, + {61.9048f,52.381f}, + {52.381f,61.9048f}, + {38.0952f,66.6667f}, + {28.5714f,66.6667f} +}; + +static const SFG_StrokeStrip ch127st[] = +{ + {2,ch127st0}, + {17,ch127st1} +}; + +static const SFG_StrokeChar ch127 = {66.6667f,2,ch127st}; + +static const SFG_StrokeChar *chars[] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + &ch32, &ch33, &ch34, &ch35, &ch36, &ch37, &ch38, &ch39, + &ch40, &ch41, &ch42, &ch43, &ch44, &ch45, &ch46, &ch47, + &ch48, &ch49, &ch50, &ch51, &ch52, &ch53, &ch54, &ch55, + &ch56, &ch57, &ch58, &ch59, &ch60, &ch61, &ch62, &ch63, + &ch64, &ch65, &ch66, &ch67, &ch68, &ch69, &ch70, &ch71, + &ch72, &ch73, &ch74, &ch75, &ch76, &ch77, &ch78, &ch79, + &ch80, &ch81, &ch82, &ch83, &ch84, &ch85, &ch86, &ch87, + &ch88, &ch89, &ch90, &ch91, &ch92, &ch93, &ch94, &ch95, + &ch96, &ch97, &ch98, &ch99, &ch100, &ch101, &ch102, &ch103, + &ch104, &ch105, &ch106, &ch107, &ch108, &ch109, &ch110, &ch111, + &ch112, &ch113, &ch114, &ch115, &ch116, &ch117, &ch118, &ch119, + &ch120, &ch121, &ch122, &ch123, &ch124, &ch125, &ch126, &ch127 +}; + +const SFG_StrokeFont fgStrokeRoman = {"Roman",128,152.381f,chars}; diff --git a/tests/box2d/freeglut/freeglut_structure.c b/tests/box2d/freeglut/freeglut_structure.c new file mode 100755 index 00000000..524242c9 --- /dev/null +++ b/tests/box2d/freeglut/freeglut_structure.c @@ -0,0 +1,596 @@ +/* + * freeglut_structure.c + * + * Windows and menus need tree structure + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, <olszta@sourceforge.net> + * Creation date: Sat Dec 18 1999 + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "freeglut.h" +#include "freeglut_internal.h" + +/* -- GLOBAL EXPORTS ------------------------------------------------------- */ + +/* + * The SFG_Structure container holds information about windows and menus + * created between glutInit() and glutMainLoop() return. + */ + +SFG_Structure fgStructure = { { NULL, NULL }, /* The list of windows */ + { NULL, NULL }, /* The list of menus */ + { NULL, NULL }, /* Windows to Destroy list */ + NULL, /* The current window */ + NULL, /* The current menu */ + NULL, /* The menu OpenGL context */ + NULL, /* The game mode window */ + 0, /* The current new window ID */ + 0 }; /* The current new menu ID */ + + +/* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ + +static void fghClearCallBacks( SFG_Window *window ) +{ + if( window ) + { + int i; + for( i = 0; i < TOTAL_CALLBACKS; ++i ) + window->CallBacks[ i ] = NULL; + } +} + +/* + * This private function creates, opens and adds to the hierarchy + * a freeglut window complete with OpenGL context and stuff... + * + * If parent is set to NULL, the window created will be a topmost one. + */ +SFG_Window* fgCreateWindow( SFG_Window* parent, const char* title, + GLboolean positionUse, int x, int y, + GLboolean sizeUse, int w, int h, + GLboolean gameMode, GLboolean isMenu ) +{ + /* Have the window object created */ + SFG_Window *window = (SFG_Window *)calloc( sizeof(SFG_Window), 1 ); + +#if TARGET_HOST_UNIX_X11 + window->Window.FBConfig = NULL; +#endif + fghClearCallBacks( window ); + + /* Initialize the object properties */ + window->ID = ++fgStructure.WindowID; + window->State.OldHeight = window->State.OldWidth = -1; + + fgListInit( &window->Children ); + if( parent ) + { + fgListAppend( &parent->Children, &window->Node ); + window->Parent = parent; + } + else + fgListAppend( &fgStructure.Windows, &window->Node ); + + /* Set the default mouse cursor and reset the modifiers value */ + window->State.Cursor = GLUT_CURSOR_INHERIT; + + window->IsMenu = isMenu; + + window->State.IgnoreKeyRepeat = GL_FALSE; + window->State.KeyRepeating = GL_FALSE; + window->State.IsFullscreen = GL_FALSE; + + /* + * Open the window now. The fgOpenWindow() function is system + * dependant, and resides in freeglut_window.c. Uses fgState. + */ + fgOpenWindow( window, title, positionUse, x, y, sizeUse, w, h, gameMode, + (GLboolean)(parent ? GL_TRUE : GL_FALSE) ); + + return window; +} + +/* + * This private function creates a menu and adds it to the menus list + */ +SFG_Menu* fgCreateMenu( FGCBMenu menuCallback ) +{ + int x = 100, y = 100, w = 100, h = 100; + SFG_Window *current_window = fgStructure.CurrentWindow; + + /* Have the menu object created */ + SFG_Menu* menu = (SFG_Menu *)calloc( sizeof(SFG_Menu), 1 ); + + menu->ParentWindow = NULL; + + /* Create a window for the menu to reside in. */ + + fgCreateWindow( NULL, "freeglut menu", GL_TRUE, x, y, GL_TRUE, w, h, + GL_FALSE, GL_TRUE ); + menu->Window = fgStructure.CurrentWindow; + glutDisplayFunc( fgDisplayMenu ); + + glutHideWindow( ); /* Hide the window for now */ + fgSetWindow( current_window ); + + /* Initialize the object properties: */ + menu->ID = ++fgStructure.MenuID; + menu->Callback = menuCallback; + menu->ActiveEntry = NULL; + + fgListInit( &menu->Entries ); + fgListAppend( &fgStructure.Menus, &menu->Node ); + + /* Newly created menus implicitly become current ones */ + fgStructure.CurrentMenu = menu; + + return menu; +} + +/* + * Function to add a window to the linked list of windows to destroy. + * Subwindows are automatically added because they hang from the window + * structure. + */ +void fgAddToWindowDestroyList( SFG_Window* window ) +{ + SFG_WindowList *new_list_entry = + ( SFG_WindowList* )malloc( sizeof(SFG_WindowList ) ); + new_list_entry->window = window; + fgListAppend( &fgStructure.WindowsToDestroy, &new_list_entry->node ); + + /* Check if the window is the current one... */ + if( fgStructure.CurrentWindow == window ) + fgStructure.CurrentWindow = NULL; + + /* + * Clear all window callbacks except Destroy, which will + * be invoked later. Right now, we are potentially carrying + * out a freeglut operation at the behest of a client callback, + * so we are reluctant to re-enter the client with the Destroy + * callback, right now. The others are all wiped out, however, + * to ensure that they are no longer called after this point. + */ + { + FGCBDestroy destroy = (FGCBDestroy)FETCH_WCB( *window, Destroy ); + fghClearCallBacks( window ); + SET_WCB( *window, Destroy, destroy ); + } +} + +/* + * Function to close down all the windows in the "WindowsToDestroy" list + */ +void fgCloseWindows( ) +{ + while( fgStructure.WindowsToDestroy.First ) + { + SFG_WindowList *window_ptr = fgStructure.WindowsToDestroy.First; + fgDestroyWindow( window_ptr->window ); + fgListRemove( &fgStructure.WindowsToDestroy, &window_ptr->node ); + free( window_ptr ); + } +} + +/* + * This function destroys a window and all of its subwindows. Actually, + * another function, defined in freeglut_window.c is called, but this is + * a whole different story... + */ +void fgDestroyWindow( SFG_Window* window ) +{ + FREEGLUT_INTERNAL_ERROR_EXIT ( window, "Window destroy function called with null window", + "fgDestroyWindow" ); + + while( window->Children.First ) + fgDestroyWindow( ( SFG_Window * )window->Children.First ); + + { + SFG_Window *activeWindow = fgStructure.CurrentWindow; + INVOKE_WCB( *window, Destroy, ( ) ); + fgSetWindow( activeWindow ); + } + + if( window->Parent ) + fgListRemove( &window->Parent->Children, &window->Node ); + else + fgListRemove( &fgStructure.Windows, &window->Node ); + + if( window->ActiveMenu ) + fgDeactivateMenu( window ); + + fghClearCallBacks( window ); + fgCloseWindow( window ); + free( window ); + if( fgStructure.CurrentWindow == window ) + fgStructure.CurrentWindow = NULL; +} + +/* + * This is a helper static function that removes a menu (given its pointer) + * from any windows that can be accessed from a given parent... + */ +static void fghRemoveMenuFromWindow( SFG_Window* window, SFG_Menu* menu ) +{ + SFG_Window *subWindow; + int i; + + /* Check whether this is the active menu in the window */ + if ( menu == window->ActiveMenu ) + window->ActiveMenu = NULL ; + + /* + * Check if the menu is attached to the current window, + * if so, have it detached (by overwriting with a NULL): + */ + for( i = 0; i < FREEGLUT_MAX_MENUS; i++ ) + if( window->Menu[ i ] == menu ) + window->Menu[ i ] = NULL; + + /* Call this function for all of the window's children recursively: */ + for( subWindow = (SFG_Window *)window->Children.First; + subWindow; + subWindow = (SFG_Window *)subWindow->Node.Next) + fghRemoveMenuFromWindow( subWindow, menu ); +} + +/* + * This is a static helper function that removes menu references + * from another menu, given two pointers to them... + */ +static void fghRemoveMenuFromMenu( SFG_Menu* from, SFG_Menu* menu ) +{ + SFG_MenuEntry *entry; + + for( entry = (SFG_MenuEntry *)from->Entries.First; + entry; + entry = ( SFG_MenuEntry * )entry->Node.Next ) + if( entry->SubMenu == menu ) + entry->SubMenu = NULL; +} + +/* + * This function destroys a menu specified by the parameter. All menus + * and windows are updated to make sure no ill pointers hang around. + */ +void fgDestroyMenu( SFG_Menu* menu ) +{ + SFG_Window *window; + SFG_Menu *from; + + FREEGLUT_INTERNAL_ERROR_EXIT ( menu, "Menu destroy function called with null menu", + "fgDestroyMenu" ); + + /* First of all, have all references to this menu removed from all windows: */ + for( window = (SFG_Window *)fgStructure.Windows.First; + window; + window = (SFG_Window *)window->Node.Next ) + fghRemoveMenuFromWindow( window, menu ); + + /* Now proceed with removing menu entries that lead to this menu */ + for( from = ( SFG_Menu * )fgStructure.Menus.First; + from; + from = ( SFG_Menu * )from->Node.Next ) + fghRemoveMenuFromMenu( from, menu ); + + /* + * If the programmer defined a destroy callback, call it + * A. Donev: But first make this the active menu + */ + if( menu->Destroy ) + { + SFG_Menu *activeMenu=fgStructure.CurrentMenu; + fgStructure.CurrentMenu = menu; + menu->Destroy( ); + fgStructure.CurrentMenu = activeMenu; + } + + /* + * Now we are pretty sure the menu is not used anywhere + * and that we can remove all of its entries + */ + while( menu->Entries.First ) + { + SFG_MenuEntry *entry = ( SFG_MenuEntry * ) menu->Entries.First; + + fgListRemove( &menu->Entries, &entry->Node ); + + if( entry->Text ) + free( entry->Text ); + entry->Text = NULL; + + free( entry ); + } + + if( fgStructure.CurrentWindow == menu->Window ) + fgSetWindow( NULL ); + fgDestroyWindow( menu->Window ); + fgListRemove( &fgStructure.Menus, &menu->Node ); + if( fgStructure.CurrentMenu == menu ) + fgStructure.CurrentMenu = NULL; + + free( menu ); +} + +/* + * This function should be called on glutInit(). It will prepare the internal + * structure of freeglut to be used in the application. The structure will be + * destroyed using fgDestroyStructure() on glutMainLoop() return. In that + * case further use of freeglut should be preceeded with a glutInit() call. + */ +void fgCreateStructure( void ) +{ + /* + * We will be needing two lists: the first containing windows, + * and the second containing the user-defined menus. + * Also, no current window/menu is set, as none has been created yet. + */ + + fgListInit(&fgStructure.Windows); + fgListInit(&fgStructure.Menus); + fgListInit(&fgStructure.WindowsToDestroy); + + fgStructure.CurrentWindow = NULL; + fgStructure.CurrentMenu = NULL; + fgStructure.MenuContext = NULL; + fgStructure.GameModeWindow = NULL; + fgStructure.WindowID = 0; + fgStructure.MenuID = 0; +} + +/* + * This function is automatically called on glutMainLoop() return. + * It should deallocate and destroy all remnants of previous + * glutInit()-enforced structure initialization... + */ +void fgDestroyStructure( void ) +{ + /* Clean up the WindowsToDestroy list. */ + fgCloseWindows( ); + + /* Make sure all windows and menus have been deallocated */ + while( fgStructure.Menus.First ) + fgDestroyMenu( ( SFG_Menu * )fgStructure.Menus.First ); + + while( fgStructure.Windows.First ) + fgDestroyWindow( ( SFG_Window * )fgStructure.Windows.First ); +} + +/* + * Helper function to enumerate through all registered top-level windows + */ +void fgEnumWindows( FGCBenumerator enumCallback, SFG_Enumerator* enumerator ) +{ + SFG_Window *window; + + FREEGLUT_INTERNAL_ERROR_EXIT ( enumCallback && enumerator, + "Enumerator or callback missing from window enumerator call", + "fgEnumWindows" ); + + /* Check every of the top-level windows */ + for( window = ( SFG_Window * )fgStructure.Windows.First; + window; + window = ( SFG_Window * )window->Node.Next ) + { + enumCallback( window, enumerator ); + if( enumerator->found ) + return; + } +} + +/* + * Helper function to enumerate through all a window's subwindows + * (single level descent) + */ +void fgEnumSubWindows( SFG_Window* window, FGCBenumerator enumCallback, + SFG_Enumerator* enumerator ) +{ + SFG_Window *child; + + FREEGLUT_INTERNAL_ERROR_EXIT ( enumCallback && enumerator, + "Enumerator or callback missing from subwindow enumerator call", + "fgEnumSubWindows" ); + FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Window Enumeration" ); + + for( child = ( SFG_Window * )window->Children.First; + child; + child = ( SFG_Window * )child->Node.Next ) + { + enumCallback( child, enumerator ); + if( enumerator->found ) + return; + } +} + +/* + * A static helper function to look for a window given its handle + */ +static void fghcbWindowByHandle( SFG_Window *window, + SFG_Enumerator *enumerator ) +{ + if ( enumerator->found ) + return; + + /* Check the window's handle. Hope this works. Looks ugly. That's for sure. */ + if( window->Window.Handle == (SFG_WindowHandleType) (enumerator->data) ) + { + enumerator->found = GL_TRUE; + enumerator->data = window; + + return; + } + + /* Otherwise, check this window's children */ + fgEnumSubWindows( window, fghcbWindowByHandle, enumerator ); +} + +/* + * fgWindowByHandle returns a (SFG_Window *) value pointing to the + * first window in the queue matching the specified window handle. + * The function is defined in freeglut_structure.c file. + */ +SFG_Window* fgWindowByHandle ( SFG_WindowHandleType hWindow ) +{ + SFG_Enumerator enumerator; + + /* This is easy and makes use of the windows enumeration defined above */ + enumerator.found = GL_FALSE; + enumerator.data = (void *)hWindow; + fgEnumWindows( fghcbWindowByHandle, &enumerator ); + + if( enumerator.found ) + return( SFG_Window *) enumerator.data; + return NULL; +} + +/* + * A static helper function to look for a window given its ID + */ +static void fghcbWindowByID( SFG_Window *window, SFG_Enumerator *enumerator ) +{ + /* Make sure we do not overwrite our precious results... */ + if( enumerator->found ) + return; + + /* Check the window's handle. Hope this works. Looks ugly. That's for sure. */ + if( window->ID == *( int *)(enumerator->data) ) + { + enumerator->found = GL_TRUE; + enumerator->data = window; + + return; + } + + /* Otherwise, check this window's children */ + fgEnumSubWindows( window, fghcbWindowByID, enumerator ); +} + +/* + * This function is similiar to the previous one, except it is + * looking for a specified (sub)window identifier. The function + * is defined in freeglut_structure.c file. + */ +SFG_Window* fgWindowByID( int windowID ) +{ + SFG_Enumerator enumerator; + + /* Uses a method very similiar for fgWindowByHandle... */ + enumerator.found = GL_FALSE; + enumerator.data = ( void * )&windowID; + fgEnumWindows( fghcbWindowByID, &enumerator ); + if( enumerator.found ) + return ( SFG_Window * )enumerator.data; + return NULL; +} + +/* + * Looks up a menu given its ID. This is easier that fgWindowByXXX + * as all menus are placed in one doubly linked list... + */ +SFG_Menu* fgMenuByID( int menuID ) +{ + SFG_Menu *menu = NULL; + + /* It's enough to check all entries in fgStructure.Menus... */ + for( menu = (SFG_Menu *)fgStructure.Menus.First; + menu; + menu = (SFG_Menu *)menu->Node.Next ) + if( menu->ID == menuID ) + return menu; + return NULL; +} + +/* + * List functions... + */ +void fgListInit(SFG_List *list) +{ + list->First = NULL; + list->Last = NULL; +} + +void fgListAppend(SFG_List *list, SFG_Node *node) +{ + if ( list->Last ) + { + SFG_Node *ln = (SFG_Node *) list->Last; + ln->Next = node; + node->Prev = ln; + } + else + { + node->Prev = NULL; + list->First = node; + } + + node->Next = NULL; + list->Last = node; +} + +void fgListRemove(SFG_List *list, SFG_Node *node) +{ + if( node->Next ) + ( ( SFG_Node * )node->Next )->Prev = node->Prev; + if( node->Prev ) + ( ( SFG_Node * )node->Prev )->Next = node->Next; + if( ( ( SFG_Node * )list->First ) == node ) + list->First = node->Next; + if( ( ( SFG_Node * )list->Last ) == node ) + list->Last = node->Prev; +} + +int fgListLength(SFG_List *list) +{ + SFG_Node *node; + int length = 0; + + for( node =( SFG_Node * )list->First; + node; + node = ( SFG_Node * )node->Next ) + ++length; + + return length; +} + + +void fgListInsert(SFG_List *list, SFG_Node *next, SFG_Node *node) +{ + SFG_Node *prev; + + if( (node->Next = next) ) + { + prev = next->Prev; + next->Prev = node; + } + else + { + prev = list->Last; + list->Last = node; + } + + if( (node->Prev = prev) ) + prev->Next = node; + else + list->First = node; +} + +/*** END OF FILE ***/ diff --git a/tests/box2d/freeglut/freeglut_teapot.c b/tests/box2d/freeglut/freeglut_teapot.c new file mode 100755 index 00000000..2b4fc24e --- /dev/null +++ b/tests/box2d/freeglut/freeglut_teapot.c @@ -0,0 +1,200 @@ +/* + * freeglut_teapot.c + * + * Teapot(tm) rendering code. + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, <olszta@sourceforge.net> + * Creation date: Fri Dec 24 1999 + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * Original teapot code copyright follows: + */ + +/* + * (c) Copyright 1993, Silicon Graphics, Inc. + * + * ALL RIGHTS RESERVED + * + * Permission to use, copy, modify, and distribute this software + * for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that + * both the copyright notice and this permission notice appear in + * supporting documentation, and that the name of Silicon + * Graphics, Inc. not be used in advertising or publicity + * pertaining to distribution of the software without specific, + * written prior permission. + * + * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU + * "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR + * OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. IN NO + * EVENT SHALL SILICON GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE + * ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER, + * INCLUDING WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE, + * SAVINGS OR REVENUE, OR THE CLAIMS OF THIRD PARTIES, WHETHER OR + * NOT SILICON GRAPHICS, INC. HAS BEEN ADVISED OF THE POSSIBILITY + * OF SUCH LOSS, HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * ARISING OUT OF OR IN CONNECTION WITH THE POSSESSION, USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * US Government Users Restricted Rights + * + * Use, duplication, or disclosure by the Government is subject to + * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph + * (c)(1)(ii) of the Rights in Technical Data and Computer + * Software clause at DFARS 252.227-7013 and/or in similar or + * successor clauses in the FAR or the DOD or NASA FAR + * Supplement. Unpublished-- rights reserved under the copyright + * laws of the United States. Contractor/manufacturer is Silicon + * Graphics, Inc., 2011 N. Shoreline Blvd., Mountain View, CA + * 94039-7311. + * + * OpenGL(TM) is a trademark of Silicon Graphics, Inc. + */ + +#include "freeglut.h" +#include "freeglut_internal.h" +#include "freeglut_teapot_data.h" + +/* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ + + +static void fghTeapot( GLint grid, GLdouble scale, GLenum type ) +{ +#if defined(_WIN32_WCE) + int i, numV=sizeof(strip_vertices)/4, numI=sizeof(strip_normals)/4; +#else + double p[4][4][3], q[4][4][3], r[4][4][3], s[4][4][3]; + long i, j, k, l; +#endif + + glPushAttrib( GL_ENABLE_BIT | GL_EVAL_BIT ); + glEnable( GL_AUTO_NORMAL ); + glEnable( GL_NORMALIZE ); + glEnable( GL_MAP2_VERTEX_3 ); + glEnable( GL_MAP2_TEXTURE_COORD_2 ); + + glPushMatrix(); + glRotated( 270.0, 1.0, 0.0, 0.0 ); + glScaled( 0.5 * scale, 0.5 * scale, 0.5 * scale ); + glTranslated( 0.0, 0.0, -1.5 ); + +#if defined(_WIN32_WCE) + glRotated( 90.0, 1.0, 0.0, 0.0 ); + glBegin( GL_TRIANGLE_STRIP ); + + for( i = 0; i < numV-1; i++ ) + { + int vidx = strip_vertices[i], + nidx = strip_normals[i]; + + if( vidx != -1 ) + { + glNormal3fv( normals[nidx] ); + glVertex3fv( vertices[vidx] ); + } + else + { + glEnd(); + glBegin( GL_TRIANGLE_STRIP ); + } + } + + glEnd(); +#else + for (i = 0; i < 10; i++) { + for (j = 0; j < 4; j++) { + for (k = 0; k < 4; k++) { + for (l = 0; l < 3; l++) { + p[j][k][l] = cpdata[patchdata[i][j * 4 + k]][l]; + q[j][k][l] = cpdata[patchdata[i][j * 4 + (3 - k)]][l]; + if (l == 1) + q[j][k][l] *= -1.0; + if (i < 6) { + r[j][k][l] = + cpdata[patchdata[i][j * 4 + (3 - k)]][l]; + if (l == 0) + r[j][k][l] *= -1.0; + s[j][k][l] = cpdata[patchdata[i][j * 4 + k]][l]; + if (l == 0) + s[j][k][l] *= -1.0; + if (l == 1) + s[j][k][l] *= -1.0; + } + } + } + } + + glMap2d(GL_MAP2_TEXTURE_COORD_2, 0.0, 1.0, 2, 2, 0.0, 1.0, 4, 2, + &tex[0][0][0]); + glMap2d(GL_MAP2_VERTEX_3, 0.0, 1.0, 3, 4, 0.0, 1.0, 12, 4, + &p[0][0][0]); + glMapGrid2d(grid, 0.0, 1.0, grid, 0.0, 1.0); + glEvalMesh2(type, 0, grid, 0, grid); + glMap2d(GL_MAP2_VERTEX_3, 0.0, 1.0, 3, 4, 0.0, 1.0, 12, 4, + &q[0][0][0]); + glEvalMesh2(type, 0, grid, 0, grid); + if (i < 6) { + glMap2d(GL_MAP2_VERTEX_3, 0.0, 1.0, 3, 4, 0.0, 1.0, 12, 4, + &r[0][0][0]); + glEvalMesh2(type, 0, grid, 0, grid); + glMap2d(GL_MAP2_VERTEX_3, 0.0, 1.0, 3, 4, 0.0, 1.0, 12, 4, + &s[0][0][0]); + glEvalMesh2(type, 0, grid, 0, grid); + } + } +#endif /* defined(_WIN32_WCE) */ + + glPopMatrix(); + glPopAttrib(); +} + + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +/* + * Renders a beautiful wired teapot... + */ +void FGAPIENTRY glutWireTeapot( GLdouble size ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireTeapot" ); + /* We will use the general teapot rendering code */ + fghTeapot( 10, size, GL_LINE ); +} + +/* + * Renders a beautiful filled teapot... + */ +void FGAPIENTRY glutSolidTeapot( GLdouble size ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidTeapot" ); + /* We will use the general teapot rendering code */ + fghTeapot( 7, size, GL_FILL ); +} + +/*** END OF FILE ***/ + + + + + diff --git a/tests/box2d/freeglut/freeglut_teapot_data.h b/tests/box2d/freeglut/freeglut_teapot_data.h new file mode 100755 index 00000000..3bf83e11 --- /dev/null +++ b/tests/box2d/freeglut/freeglut_teapot_data.h @@ -0,0 +1,2429 @@ +/* + * freeglut_teapot_data.h + * + * The freeglut library teapot data include file. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef FREEGLUT_TEAPOT_DATA_H +#define FREEGLUT_TEAPOT_DATA_H + +#if defined(_WIN32_WCE) +/* + * Submitted through the kind offices of Daniel Wagner (daniel@ims.tuwien.ac.at) + */ + +/* 530 vertices */ + +const int numVertices = 530; +const float vertices[530][3] = { +2.1f, 3.6f, 0.0f, +2.071f, 3.711f, 0.0f, +2.105f, 3.748f, 0.0f, +2.174f, 3.711f, 0.0f, +2.25f, 3.6f, 0.0f, +1.937f, 3.6f, 0.8242f, +1.91f, 3.711f, 0.8128f, +1.942f, 3.748f, 0.8261f, +2.005f, 3.711f, 0.8532f, +2.076f, 3.6f, 0.8831f, +1.491f, 3.6f, 1.491f, +1.47f, 3.711f, 1.47f, +1.494f, 3.748f, 1.494f, +1.543f, 3.711f, 1.543f, +1.597f, 3.6f, 1.597f, +0.8242f, 3.6f, 1.937f, +0.8128f, 3.711f, 1.91f, +0.8261f, 3.748f, 1.942f, +0.8532f, 3.711f, 2.005f, +0.8831f, 3.6f, 2.076f, +0.0f, 3.6f, 2.1f, +0.0f, 3.711f, 2.071f, +0.0f, 3.748f, 2.105f, +0.0f, 3.711f, 2.174f, +0.0f, 3.6f, 2.25f, +-0.8812f, 3.6f, 1.937f, +-0.8368f, 3.711f, 1.91f, +-0.8332f, 3.748f, 1.942f, +-0.8541f, 3.711f, 2.005f, +-0.8831f, 3.6f, 2.076f, +-1.542f, 3.6f, 1.491f, +-1.492f, 3.711f, 1.47f, +-1.501f, 3.748f, 1.494f, +-1.544f, 3.711f, 1.543f, +-1.597f, 3.6f, 1.597f, +-1.956f, 3.6f, 0.8242f, +-1.918f, 3.711f, 0.8128f, +-1.944f, 3.748f, 0.8261f, +-2.006f, 3.711f, 0.8532f, +-2.076f, 3.6f, 0.8831f, +-2.1f, 3.6f, 0.0f, +-2.071f, 3.711f, 0.0f, +-2.105f, 3.748f, 0.0f, +-2.174f, 3.711f, 0.0f, +-2.25f, 3.6f, 0.0f, +-1.937f, 3.6f, -0.8242f, +-1.91f, 3.711f, -0.8128f, +-1.942f, 3.748f, -0.8261f, +-2.005f, 3.711f, -0.8532f, +-2.076f, 3.6f, -0.8831f, +-1.491f, 3.6f, -1.491f, +-1.47f, 3.711f, -1.47f, +-1.494f, 3.748f, -1.494f, +-1.543f, 3.711f, -1.543f, +-1.597f, 3.6f, -1.597f, +-0.8242f, 3.6f, -1.937f, +-0.8128f, 3.711f, -1.91f, +-0.8261f, 3.748f, -1.942f, +-0.8532f, 3.711f, -2.005f, +-0.8831f, 3.6f, -2.076f, +0.0f, 3.6f, -2.1f, +0.0f, 3.711f, -2.071f, +0.0f, 3.748f, -2.105f, +0.0f, 3.711f, -2.174f, +0.0f, 3.6f, -2.25f, +0.8242f, 3.6f, -1.937f, +0.8128f, 3.711f, -1.91f, +0.8261f, 3.748f, -1.942f, +0.8532f, 3.711f, -2.005f, +0.8831f, 3.6f, -2.076f, +1.491f, 3.6f, -1.491f, +1.47f, 3.711f, -1.47f, +1.494f, 3.748f, -1.494f, +1.543f, 3.711f, -1.543f, +1.597f, 3.6f, -1.597f, +1.937f, 3.6f, -0.8242f, +1.91f, 3.711f, -0.8128f, +1.942f, 3.748f, -0.8261f, +2.005f, 3.711f, -0.8532f, +2.076f, 3.6f, -0.8831f, +2.525f, 3.011f, 0.0f, +2.766f, 2.433f, 0.0f, +2.936f, 1.876f, 0.0f, +3.0f, 1.35f, 0.0f, +2.33f, 3.011f, 0.9912f, +2.551f, 2.433f, 1.086f, +2.708f, 1.876f, 1.152f, +2.767f, 1.35f, 1.178f, +1.793f, 3.011f, 1.793f, +1.964f, 2.433f, 1.964f, +2.084f, 1.876f, 2.084f, +2.13f, 1.35f, 2.13f, +0.9912f, 3.011f, 2.33f, +1.086f, 2.433f, 2.551f, +1.152f, 1.876f, 2.708f, +1.178f, 1.35f, 2.767f, +0.0f, 3.011f, 2.525f, +0.0f, 2.433f, 2.766f, +0.0f, 1.876f, 2.936f, +0.0f, 1.35f, 3.0f, +-0.9912f, 3.011f, 2.33f, +-1.086f, 2.433f, 2.551f, +-1.152f, 1.876f, 2.708f, +-1.178f, 1.35f, 2.767f, +-1.793f, 3.011f, 1.793f, +-1.964f, 2.433f, 1.964f, +-2.084f, 1.876f, 2.084f, +-2.13f, 1.35f, 2.13f, +-2.33f, 3.011f, 0.9912f, +-2.551f, 2.433f, 1.086f, +-2.708f, 1.876f, 1.152f, +-2.767f, 1.35f, 1.178f, +-2.525f, 3.011f, 0.0f, +-2.766f, 2.433f, 0.0f, +-2.936f, 1.876f, 0.0f, +-3.0f, 1.35f, 0.0f, +-2.33f, 3.011f, -0.9912f, +-2.551f, 2.433f, -1.086f, +-2.708f, 1.876f, -1.152f, +-2.767f, 1.35f, -1.178f, +-1.793f, 3.011f, -1.793f, +-1.964f, 2.433f, -1.964f, +-2.084f, 1.876f, -2.084f, +-2.13f, 1.35f, -2.13f, +-0.9912f, 3.011f, -2.33f, +-1.086f, 2.433f, -2.551f, +-1.152f, 1.876f, -2.708f, +-1.178f, 1.35f, -2.767f, +0.0f, 3.011f, -2.525f, +0.0f, 2.433f, -2.766f, +0.0f, 1.876f, -2.936f, +0.0f, 1.35f, -3.0f, +0.9912f, 3.011f, -2.33f, +1.086f, 2.433f, -2.551f, +1.152f, 1.876f, -2.708f, +1.178f, 1.35f, -2.767f, +1.793f, 3.011f, -1.793f, +1.964f, 2.433f, -1.964f, +2.084f, 1.876f, -2.084f, +2.13f, 1.35f, -2.13f, +2.33f, 3.011f, -0.9912f, +2.551f, 2.433f, -1.086f, +2.708f, 1.876f, -1.152f, +2.767f, 1.35f, -1.178f, +2.883f, 0.9053f, 0.0f, +2.625f, 0.5766f, 0.0f, +2.367f, 0.3533f, 0.0f, +2.25f, 0.225f, 0.0f, +2.659f, 0.9053f, 1.132f, +2.422f, 0.5766f, 1.03f, +2.184f, 0.3533f, 0.9291f, +2.076f, 0.225f, 0.8831f, +2.047f, 0.9053f, 2.047f, +1.864f, 0.5766f, 1.864f, +1.681f, 0.3533f, 1.681f, +1.597f, 0.225f, 1.597f, +1.132f, 0.9053f, 2.659f, +1.03f, 0.5766f, 2.422f, +0.9291f, 0.3533f, 2.184f, +0.8831f, 0.225f, 2.076f, +0.0f, 0.9053f, 2.883f, +0.0f, 0.5766f, 2.625f, +0.0f, 0.3533f, 2.367f, +0.0f, 0.225f, 2.25f, +-1.132f, 0.9053f, 2.659f, +-1.03f, 0.5766f, 2.422f, +-0.9291f, 0.3533f, 2.184f, +-0.8831f, 0.225f, 2.076f, +-2.047f, 0.9053f, 2.047f, +-1.864f, 0.5766f, 1.864f, +-1.681f, 0.3533f, 1.681f, +-1.597f, 0.225f, 1.597f, +-2.659f, 0.9053f, 1.132f, +-2.422f, 0.5766f, 1.03f, +-2.184f, 0.3533f, 0.9291f, +-2.076f, 0.225f, 0.8831f, +-2.883f, 0.9053f, 0.0f, +-2.625f, 0.5766f, 0.0f, +-2.367f, 0.3533f, 0.0f, +-2.25f, 0.225f, 0.0f, +-2.659f, 0.9053f, -1.132f, +-2.422f, 0.5766f, -1.03f, +-2.184f, 0.3533f, -0.9291f, +-2.076f, 0.225f, -0.8831f, +-2.047f, 0.9053f, -2.047f, +-1.864f, 0.5766f, -1.864f, +-1.681f, 0.3533f, -1.681f, +-1.597f, 0.225f, -1.597f, +-1.132f, 0.9053f, -2.659f, +-1.03f, 0.5766f, -2.422f, +-0.9291f, 0.3533f, -2.184f, +-0.8831f, 0.225f, -2.076f, +0.0f, 0.9053f, -2.883f, +0.0f, 0.5766f, -2.625f, +0.0f, 0.3533f, -2.367f, +0.0f, 0.225f, -2.25f, +1.132f, 0.9053f, -2.659f, +1.03f, 0.5766f, -2.422f, +0.9291f, 0.3533f, -2.184f, +0.8831f, 0.225f, -2.076f, +2.047f, 0.9053f, -2.047f, +1.864f, 0.5766f, -1.864f, +1.681f, 0.3533f, -1.681f, +1.597f, 0.225f, -1.597f, +2.659f, 0.9053f, -1.132f, +2.422f, 0.5766f, -1.03f, +2.184f, 0.3533f, -0.9291f, +2.076f, 0.225f, -0.8831f, +2.199f, 0.1424f, 0.0f, +1.927f, 0.07031f, 0.0f, +1.253f, 0.01934f, 0.0f, +0.0f, 0.0f, 0.0f, +2.029f, 0.1424f, 0.8631f, +1.777f, 0.07031f, 0.7562f, +1.156f, 0.01934f, 0.4919f, +1.561f, 0.1424f, 1.561f, +1.368f, 0.07031f, 1.368f, +0.8899f, 0.01934f, 0.8899f, +0.8631f, 0.1424f, 2.029f, +0.7562f, 0.07031f, 1.777f, +0.4919f, 0.01934f, 1.156f, +0.0f, 0.1424f, 2.199f, +0.0f, 0.07031f, 1.927f, +0.0f, 0.01934f, 1.253f, +-0.8631f, 0.1424f, 2.029f, +-0.7562f, 0.07031f, 1.777f, +-0.4919f, 0.01934f, 1.156f, +-1.561f, 0.1424f, 1.561f, +-1.368f, 0.07031f, 1.368f, +-0.8899f, 0.01934f, 0.8899f, +-2.029f, 0.1424f, 0.8631f, +-1.777f, 0.07031f, 0.7562f, +-1.156f, 0.01934f, 0.4919f, +-2.199f, 0.1424f, 0.0f, +-1.927f, 0.07031f, 0.0f, +-1.253f, 0.01934f, 0.0f, +-2.029f, 0.1424f, -0.8631f, +-1.777f, 0.07031f, -0.7562f, +-1.156f, 0.01934f, -0.4919f, +-1.561f, 0.1424f, -1.561f, +-1.368f, 0.07031f, -1.368f, +-0.8899f, 0.01934f, -0.8899f, +-0.8631f, 0.1424f, -2.029f, +-0.7562f, 0.07031f, -1.777f, +-0.4919f, 0.01934f, -1.156f, +0.0f, 0.1424f, -2.199f, +0.0f, 0.07031f, -1.927f, +0.0f, 0.01934f, -1.253f, +0.8631f, 0.1424f, -2.029f, +0.7562f, 0.07031f, -1.777f, +0.4919f, 0.01934f, -1.156f, +1.561f, 0.1424f, -1.561f, +1.368f, 0.07031f, -1.368f, +0.8899f, 0.01934f, -0.8899f, +2.029f, 0.1424f, -0.8631f, +1.777f, 0.07031f, -0.7562f, +1.156f, 0.01934f, -0.4919f, +-2.4f, 3.038f, 0.0f, +-3.101f, 3.032f, 0.0f, +-3.619f, 2.995f, 0.0f, +-3.94f, 2.895f, 0.0f, +-4.05f, 2.7f, 0.0f, +-2.377f, 3.09f, 0.2531f, +-3.122f, 3.084f, 0.2531f, +-3.669f, 3.041f, 0.2531f, +-4.005f, 2.926f, 0.2531f, +-4.12f, 2.7f, 0.2531f, +-2.325f, 3.206f, 0.3375f, +-3.168f, 3.198f, 0.3375f, +-3.778f, 3.143f, 0.3375f, +-4.15f, 2.993f, 0.3375f, +-4.275f, 2.7f, 0.3375f, +-2.273f, 3.322f, 0.2531f, +-3.214f, 3.313f, 0.2531f, +-3.888f, 3.244f, 0.2531f, +-4.294f, 3.06f, 0.2531f, +-4.43f, 2.7f, 0.2531f, +-2.25f, 3.375f, 0.0f, +-3.234f, 3.364f, 0.0f, +-3.938f, 3.291f, 0.0f, +-4.359f, 3.09f, 0.0f, +-4.5f, 2.7f, 0.0f, +-2.273f, 3.322f, -0.2531f, +-3.214f, 3.313f, -0.2531f, +-3.888f, 3.244f, -0.2531f, +-4.294f, 3.06f, -0.2531f, +-4.43f, 2.7f, -0.2531f, +-2.325f, 3.206f, -0.3375f, +-3.168f, 3.198f, -0.3375f, +-3.778f, 3.143f, -0.3375f, +-4.15f, 2.993f, -0.3375f, +-4.275f, 2.7f, -0.3375f, +-2.377f, 3.09f, -0.2531f, +-3.122f, 3.084f, -0.2531f, +-3.669f, 3.041f, -0.2531f, +-4.005f, 2.926f, -0.2531f, +-4.12f, 2.7f, -0.2531f, +-3.991f, 2.394f, 0.0f, +-3.806f, 2.025f, 0.0f, +-3.48f, 1.656f, 0.0f, +-3.0f, 1.35f, 0.0f, +-4.055f, 2.365f, 0.2531f, +-3.852f, 1.98f, 0.2531f, +-3.496f, 1.6f, 0.2531f, +-2.977f, 1.28f, 0.2531f, +-4.196f, 2.3f, 0.3375f, +-3.952f, 1.881f, 0.3375f, +-3.531f, 1.478f, 0.3375f, +-2.925f, 1.125f, 0.3375f, +-4.336f, 2.235f, 0.2531f, +-4.051f, 1.782f, 0.2531f, +-3.566f, 1.356f, 0.2531f, +-2.873f, 0.9703f, 0.2531f, +-4.4f, 2.205f, 0.0f, +-4.097f, 1.737f, 0.0f, +-3.582f, 1.3f, 0.0f, +-2.85f, 0.9f, 0.0f, +-4.336f, 2.235f, -0.2531f, +-4.051f, 1.782f, -0.2531f, +-3.566f, 1.356f, -0.2531f, +-2.873f, 0.9703f, -0.2531f, +-4.196f, 2.3f, -0.3375f, +-3.952f, 1.881f, -0.3375f, +-3.531f, 1.478f, -0.3375f, +-2.925f, 1.125f, -0.3375f, +-4.055f, 2.365f, -0.2531f, +-3.852f, 1.98f, -0.2531f, +-3.496f, 1.6f, -0.2531f, +-2.977f, 1.28f, -0.2531f, +2.55f, 2.137f, 0.0f, +3.27f, 2.303f, 0.0f, +3.581f, 2.7f, 0.0f, +3.752f, 3.182f, 0.0f, +4.05f, 3.6f, 0.0f, +2.55f, 1.944f, 0.5569f, +3.324f, 2.159f, 0.5028f, +3.652f, 2.617f, 0.3839f, +3.838f, 3.151f, 0.265f, +4.191f, 3.6f, 0.2109f, +2.55f, 1.519f, 0.7425f, +3.445f, 1.844f, 0.6704f, +3.806f, 2.433f, 0.5119f, +4.027f, 3.085f, 0.3533f, +4.5f, 3.6f, 0.2813f, +2.55f, 1.093f, 0.5569f, +3.566f, 1.529f, 0.5028f, +3.961f, 2.249f, 0.3839f, +4.215f, 3.018f, 0.265f, +4.809f, 3.6f, 0.2109f, +2.55f, 0.9f, 0.0f, +3.621f, 1.385f, 0.0f, +4.031f, 2.166f, 0.0f, +4.301f, 2.988f, 0.0f, +4.95f, 3.6f, 0.0f, +2.55f, 1.093f, -0.5569f, +3.566f, 1.529f, -0.5028f, +3.961f, 2.249f, -0.3839f, +4.215f, 3.018f, -0.265f, +4.809f, 3.6f, -0.2109f, +2.55f, 1.519f, -0.7425f, +3.445f, 1.844f, -0.6704f, +3.806f, 2.433f, -0.5119f, +4.027f, 3.085f, -0.3533f, +4.5f, 3.6f, -0.2813f, +2.55f, 1.944f, -0.5569f, +3.324f, 2.159f, -0.5028f, +3.652f, 2.617f, -0.3839f, +3.838f, 3.151f, -0.265f, +4.191f, 3.6f, -0.2109f, +4.158f, 3.663f, 0.0f, +4.238f, 3.684f, 0.0f, +4.261f, 3.663f, 0.0f, +4.2f, 3.6f, 0.0f, +4.308f, 3.666f, 0.1978f, +4.379f, 3.689f, 0.1687f, +4.381f, 3.668f, 0.1397f, +4.294f, 3.6f, 0.1266f, +4.64f, 3.673f, 0.2637f, +4.69f, 3.7f, 0.225f, +4.645f, 3.677f, 0.1863f, +4.5f, 3.6f, 0.1688f, +4.971f, 3.68f, 0.1978f, +5.001f, 3.711f, 0.1687f, +4.909f, 3.687f, 0.1397f, +4.706f, 3.6f, 0.1266f, +5.122f, 3.683f, 0.0f, +5.142f, 3.716f, 0.0f, +5.029f, 3.691f, 0.0f, +4.8f, 3.6f, 0.0f, +4.971f, 3.68f, -0.1978f, +5.001f, 3.711f, -0.1687f, +4.909f, 3.687f, -0.1397f, +4.706f, 3.6f, -0.1266f, +4.64f, 3.673f, -0.2637f, +4.69f, 3.7f, -0.225f, +4.645f, 3.677f, -0.1863f, +4.5f, 3.6f, -0.1688f, +4.308f, 3.666f, -0.1978f, +4.379f, 3.689f, -0.1687f, +4.381f, 3.668f, -0.1397f, +4.294f, 3.6f, -0.1266f, +0.0f, 4.725f, 0.0f, +0.5109f, 4.651f, 0.0f, +0.4875f, 4.472f, 0.0f, +0.2953f, 4.25f, 0.0f, +0.3f, 4.05f, 0.0f, +0.4715f, 4.651f, 0.2011f, +0.4499f, 4.472f, 0.1918f, +0.2725f, 4.25f, 0.1161f, +0.2768f, 4.05f, 0.1178f, +0.3632f, 4.651f, 0.3632f, +0.3465f, 4.472f, 0.3465f, +0.2098f, 4.25f, 0.2098f, +0.213f, 4.05f, 0.213f, +0.2011f, 4.651f, 0.4715f, +0.1918f, 4.472f, 0.4499f, +0.1161f, 4.25f, 0.2725f, +0.1178f, 4.05f, 0.2768f, +0.0f, 4.651f, 0.5109f, +0.0f, 4.472f, 0.4875f, +0.0f, 4.25f, 0.2953f, +0.0f, 4.05f, 0.3f, +-0.2011f, 4.651f, 0.4715f, +-0.1918f, 4.472f, 0.4499f, +-0.1161f, 4.25f, 0.2725f, +-0.1178f, 4.05f, 0.2768f, +-0.3632f, 4.651f, 0.3632f, +-0.3465f, 4.472f, 0.3465f, +-0.2098f, 4.25f, 0.2098f, +-0.213f, 4.05f, 0.213f, +-0.4715f, 4.651f, 0.2011f, +-0.4499f, 4.472f, 0.1918f, +-0.2725f, 4.25f, 0.1161f, +-0.2768f, 4.05f, 0.1178f, +-0.5109f, 4.651f, 0.0f, +-0.4875f, 4.472f, 0.0f, +-0.2953f, 4.25f, 0.0f, +-0.3f, 4.05f, 0.0f, +-0.4715f, 4.651f, -0.2011f, +-0.4499f, 4.472f, -0.1918f, +-0.2725f, 4.25f, -0.1161f, +-0.2768f, 4.05f, -0.1178f, +-0.3632f, 4.651f, -0.3632f, +-0.3465f, 4.472f, -0.3465f, +-0.2098f, 4.25f, -0.2098f, +-0.213f, 4.05f, -0.213f, +-0.2011f, 4.651f, -0.4715f, +-0.1918f, 4.472f, -0.4499f, +-0.1161f, 4.25f, -0.2725f, +-0.1178f, 4.05f, -0.2768f, +0.0f, 4.651f, -0.5109f, +0.0f, 4.472f, -0.4875f, +0.0f, 4.25f, -0.2953f, +0.0f, 4.05f, -0.3f, +0.2011f, 4.651f, -0.4715f, +0.1918f, 4.472f, -0.4499f, +0.1161f, 4.25f, -0.2725f, +0.1178f, 4.05f, -0.2768f, +0.3632f, 4.651f, -0.3632f, +0.3465f, 4.472f, -0.3465f, +0.2098f, 4.25f, -0.2098f, +0.213f, 4.05f, -0.213f, +0.4715f, 4.651f, -0.2011f, +0.4499f, 4.472f, -0.1918f, +0.2725f, 4.25f, -0.1161f, +0.2768f, 4.05f, -0.1178f, +0.6844f, 3.916f, 0.0f, +1.237f, 3.825f, 0.0f, +1.734f, 3.734f, 0.0f, +1.95f, 3.6f, 0.0f, +0.6313f, 3.916f, 0.2686f, +1.142f, 3.825f, 0.4857f, +1.6f, 3.734f, 0.6807f, +1.799f, 3.6f, 0.7654f, +0.4859f, 3.916f, 0.4859f, +0.8786f, 3.825f, 0.8786f, +1.231f, 3.734f, 1.231f, +1.385f, 3.6f, 1.385f, +0.2686f, 3.916f, 0.6313f, +0.4857f, 3.825f, 1.142f, +0.6807f, 3.734f, 1.6f, +0.7654f, 3.6f, 1.799f, +0.0f, 3.916f, 0.6844f, +0.0f, 3.825f, 1.237f, +0.0f, 3.734f, 1.734f, +0.0f, 3.6f, 1.95f, +-0.2686f, 3.916f, 0.6313f, +-0.4857f, 3.825f, 1.142f, +-0.6807f, 3.734f, 1.6f, +-0.7654f, 3.6f, 1.799f, +-0.4859f, 3.916f, 0.4859f, +-0.8786f, 3.825f, 0.8786f, +-1.231f, 3.734f, 1.231f, +-1.385f, 3.6f, 1.385f, +-0.6313f, 3.916f, 0.2686f, +-1.142f, 3.825f, 0.4857f, +-1.6f, 3.734f, 0.6807f, +-1.799f, 3.6f, 0.7654f, +-0.6844f, 3.916f, 0.0f, +-1.237f, 3.825f, 0.0f, +-1.734f, 3.734f, 0.0f, +-1.95f, 3.6f, 0.0f, +-0.6313f, 3.916f, -0.2686f, +-1.142f, 3.825f, -0.4857f, +-1.6f, 3.734f, -0.6807f, +-1.799f, 3.6f, -0.7654f, +-0.4859f, 3.916f, -0.4859f, +-0.8786f, 3.825f, -0.8786f, +-1.231f, 3.734f, -1.231f, +-1.385f, 3.6f, -1.385f, +-0.2686f, 3.916f, -0.6313f, +-0.4857f, 3.825f, -1.142f, +-0.6807f, 3.734f, -1.6f, +-0.7654f, 3.6f, -1.799f, +0.0f, 3.916f, -0.6844f, +0.0f, 3.825f, -1.237f, +0.0f, 3.734f, -1.734f, +0.0f, 3.6f, -1.95f, +0.2686f, 3.916f, -0.6313f, +0.4857f, 3.825f, -1.142f, +0.6807f, 3.734f, -1.6f, +0.7654f, 3.6f, -1.799f, +0.4859f, 3.916f, -0.4859f, +0.8786f, 3.825f, -0.8786f, +1.231f, 3.734f, -1.231f, +1.385f, 3.6f, -1.385f, +0.6313f, 3.916f, -0.2686f, +1.142f, 3.825f, -0.4857f, +1.6f, 3.734f, -0.6807f, +1.799f, 3.6f, -0.7654f +}; + + +/* 530 normals */ +const int numNormals = 530; +const float normals[530][3] = { +0.0486f, -0.9986f, 0.0168f, +0.9976f, -0.0678f, -0.0008f, +-0.233f, 0.8502f, -0.4719f, +-0.2299f, 0.9679f, 0.1004f, +-0.1648f, 0.985f, 0.0501f, +-0.0117f, 0.7461f, 0.6656f, +-0.0888f, 0.9692f, 0.2294f, +0.6449f, -0.7172f, -0.2637f, +-0.066f, 0.9851f, 0.1583f, +-0.6585f, -0.342f, -0.6703f, +-0.293f, 0.9558f, 0.0209f, +0.179f, 0.9825f, -0.0513f, +-0.0094f, 0.903f, 0.4295f, +-0.0059f, -0.986f, -0.1662f, +-0.7355f, 0.6774f, -0.0026f, +-0.997f, 0.0763f, 0.0019f, +-0.1478f, 0.9333f, 0.3271f, +-0.3014f, -0.6034f, -0.7382f, +-0.7048f, -0.0681f, 0.706f, +-0.3361f, 0.9332f, 0.1263f, +0.3709f, 0.1524f, -0.916f, +-0.3399f, -0.4121f, 0.8453f, +0.1921f, 0.9724f, -0.1316f, +-0.2671f, 0.7429f, 0.6137f, +0.0888f, 0.9692f, -0.2294f, +0.066f, 0.9851f, -0.1583f, +0.9411f, 0.338f, 0.001f, +0.8666f, -0.2559f, 0.4282f, +-0.8029f, 0.4968f, 0.3293f, +-0.0008f, -0.0678f, -0.9976f, +-0.8453f, -0.4121f, -0.3399f, +-0.4801f, -0.8741f, 0.0733f, +0.6355f, -0.772f, 0.0006f, +-0.9215f, -0.0678f, 0.3822f, +-0.6698f, -0.6907f, -0.2723f, +0.3734f, 0.876f, -0.3051f, +0.3548f, -0.4118f, 0.8393f, +-0.3629f, 0.2429f, 0.8995f, +0.9033f, 0.2079f, 0.375f, +-0.2824f, 0.5939f, 0.7532f, +0.8938f, 0.4452f, 0.0532f, +0.1478f, 0.9333f, -0.3271f, +0.0085f, -0.0031f, -0.9999f, +0.3595f, 0.933f, 0.0115f, +0.8995f, 0.2429f, 0.3629f, +0.7048f, -0.0681f, -0.706f, +-0.6428f, -0.7172f, -0.2688f, +0.6366f, -0.447f, 0.6283f, +-0.1213f, -0.9861f, -0.1128f, +0.8003f, 0.4978f, 0.334f, +0.3361f, 0.9332f, -0.1263f, +0.3399f, -0.4121f, -0.8453f, +-0.3909f, 0.4452f, 0.8055f, +0.0117f, 0.7462f, -0.6655f, +0.9215f, -0.0678f, -0.3822f, +0.3582f, -0.7656f, 0.5343f, +-0.9782f, 0.2075f, -0.0011f, +0.2824f, 0.5939f, -0.7532f, +0.035f, -0.8413f, 0.5393f, +-0.8044f, 0.5934f, 0.0262f, +-0.1128f, -0.9861f, 0.1213f, +0.13f, -0.1396f, 0.9816f, +0.6644f, 0.3392f, 0.6659f, +-0.0042f, -0.6898f, -0.7239f, +-0.1587f, 0.9851f, 0.065f, +-0.8719f, -0.3415f, 0.3508f, +0.6486f, 0.4756f, -0.5941f, +-0.4991f, 0.8499f, -0.1684f, +-0.3969f, 0.6342f, -0.6634f, +0.7041f, -0.3863f, -0.5956f, +0.3909f, 0.4452f, -0.8055f, +-0.0391f, -0.0113f, 0.9991f, +-0.3321f, 0.5936f, -0.733f, +0.8523f, -0.5219f, -0.0338f, +0.329f, 0.4978f, 0.8023f, +0.8044f, 0.5934f, -0.0262f, +0.1128f, -0.9861f, -0.1213f, +0.0178f, 0.9861f, -0.1651f, +0.3491f, 0.4045f, 0.8452f, +-0.2727f, 0.8505f, 0.4496f, +0.065f, 0.9851f, 0.1587f, +-0.0005f, 0.4037f, 0.9148f, +-0.0077f, -0.4109f, -0.9116f, +0.5609f, -0.604f, 0.5661f, +0.8236f, 0.5668f, -0.0138f, +0.1587f, 0.9851f, -0.065f, +0.8719f, -0.3415f, -0.3508f, +-0.7382f, -0.6034f, 0.3014f, +0.0346f, 0.8495f, 0.5263f, +-0.4373f, -0.7921f, -0.4257f, +-0.0532f, 0.4452f, 0.8938f, +0.0689f, -0.9861f, 0.1509f, +-0.1509f, -0.9861f, 0.0689f, +0.7706f, -0.2424f, -0.5893f, +-0.7543f, -0.6564f, 0.0105f, +0.0005f, 0.4037f, -0.9148f, +-0.9116f, -0.4109f, 0.0077f, +0.0058f, -0.0438f, 0.999f, +0.1719f, 0.985f, 0.0005f, +-0.1697f, 0.9693f, 0.1774f, +0.5874f, -0.5124f, 0.6263f, +0.7382f, -0.6034f, -0.3014f, +-0.1518f, 0.985f, -0.081f, +0.646f, 0.4051f, 0.6468f, +0.334f, 0.4978f, -0.8003f, +-0.7354f, -0.6034f, -0.3082f, +-0.6919f, 0.2428f, -0.6798f, +0.0532f, 0.4452f, -0.8938f, +0.3547f, -0.3173f, 0.8794f, +0.9879f, -0.1547f, -0.0033f, +-0.0462f, -0.9986f, 0.0223f, +-0.6088f, 0.4806f, 0.6311f, +-0.109f, -0.1969f, -0.9743f, +0.1509f, -0.9861f, -0.0689f, +-0.0568f, 0.9983f, 0.0009f, +0.9074f, -0.3096f, -0.2839f, +0.8677f, 0.4969f, 0.0026f, +-0.2723f, -0.6907f, 0.6698f, +-0.4734f, -0.6798f, 0.5599f, +0.9116f, -0.4109f, -0.0077f, +0.1697f, 0.9693f, -0.1774f, +0.5875f, 0.5937f, 0.5497f, +-0.3232f, 0.6846f, 0.6533f, +-0.5078f, -0.6913f, 0.5139f, +-0.4612f, 0.7474f, -0.478f, +-0.2071f, -0.8049f, 0.556f, +-0.6976f, -0.7164f, -0.0027f, +-0.8697f, 0.3388f, 0.3587f, +0.0462f, -0.9986f, -0.0223f, +0.2723f, -0.6907f, -0.6698f, +-0.829f, -0.4466f, -0.3365f, +0.9148f, 0.4037f, 0.0005f, +-0.1583f, 0.9851f, -0.066f, +0.148f, 0.9838f, 0.1002f, +-0.1717f, 0.985f, -0.0162f, +-0.4282f, -0.2559f, 0.8666f, +0.3094f, -0.2556f, 0.9159f, +0.2803f, -0.6907f, 0.6665f, +-0.6154f, 0.497f, 0.6117f, +-0.0262f, 0.5934f, -0.8044f, +0.0286f, 0.1639f, -0.986f, +-0.6924f, 0.2083f, 0.6907f, +-0.0105f, 0.9975f, -0.0685f, +0.5078f, -0.6913f, -0.5139f, +0.2071f, -0.8049f, -0.556f, +-0.4903f, -0.7178f, -0.4942f, +-0.2637f, -0.7172f, -0.6449f, +-0.3822f, -0.0678f, -0.9215f, +0.8697f, 0.3388f, -0.3587f, +0.2461f, -0.805f, 0.5397f, +-0.2615f, 0.9334f, 0.2452f, +0.6187f, 0.747f, -0.243f, +0.0375f, -0.8401f, -0.5411f, +0.0054f, 0.9691f, 0.2464f, +0.3587f, 0.3388f, 0.8697f, +0.3993f, 0.6582f, -0.6381f, +-0.3476f, -0.4464f, -0.8245f, +0.099f, 0.9692f, 0.2251f, +-0.3666f, -0.3412f, 0.8655f, +0.0396f, 0.153f, -0.9874f, +0.0349f, 0.9969f, -0.0698f, +0.1096f, 0.985f, 0.1324f, +-0.0578f, -0.9861f, 0.1556f, +0.4479f, -0.5145f, -0.7311f, +0.6924f, 0.2083f, -0.6907f, +0.6096f, 0.747f, 0.265f, +-0.3508f, -0.3415f, -0.8719f, +-0.6215f, 0.4454f, -0.6443f, +-0.4942f, -0.7178f, 0.4903f, +-0.9402f, -0.3403f, -0.0085f, +0.0056f, -0.0358f, 0.9993f, +0.2615f, 0.9334f, -0.2452f, +-0.0024f, 0.0291f, -0.9995f, +-0.2667f, 0.9637f, -0.001f, +0.0569f, -0.2712f, -0.9608f, +0.7463f, 0.254f, 0.615f, +0.5153f, 0.6516f, -0.5564f, +0.0223f, -0.9986f, 0.0462f, +0.3666f, -0.3412f, -0.8655f, +0.0578f, -0.9861f, -0.1556f, +0.6111f, 0.4984f, 0.6148f, +-0.243f, 0.747f, -0.6187f, +-0.0092f, 0.2338f, -0.9722f, +0.478f, 0.7474f, -0.4612f, +-0.0058f, -0.4457f, -0.8951f, +-0.4856f, -0.6774f, -0.5524f, +0.54f, 0.6414f, 0.5448f, +-0.3365f, -0.4466f, 0.829f, +-0.2257f, 0.795f, 0.5629f, +0.8055f, 0.4452f, 0.3909f, +0.3729f, 0.208f, 0.9042f, +-0.727f, -0.2562f, 0.6369f, +-0.0514f, -0.9986f, 0.0029f, +0.9159f, 0.1555f, -0.3699f, +0.0019f, -0.2377f, -0.9713f, +0.4942f, -0.7178f, -0.4903f, +0.6497f, -0.4127f, 0.6383f, +0.0089f, 0.0486f, -0.9987f, +-0.0213f, 0.6301f, -0.7761f, +-0.9269f, -0.3751f, 0.0038f, +-0.1215f, 0.9852f, 0.1207f, +-0.5856f, 0.5198f, 0.6218f, +0.8655f, -0.3412f, 0.3666f, +-0.2464f, 0.9691f, 0.0054f, +0.0123f, 0.1386f, 0.9902f, +0.0179f, -0.0369f, 0.9991f, +-0.1207f, 0.9852f, -0.1215f, +-0.0081f, 0.5671f, 0.8235f, +-0.8689f, 0.3387f, -0.3607f, +0.0062f, 0.0309f, -0.9995f, +0.3365f, -0.4466f, -0.829f, +-0.3787f, 0.2424f, -0.8931f, +-0.2904f, 0.4454f, -0.8468f, +-0.8707f, 0.4915f, 0.0133f, +0.163f, -0.8182f, 0.5512f, +0.4337f, -0.8052f, 0.4041f, +0.0514f, -0.9986f, -0.0029f, +-0.0084f, 0.1303f, 0.9914f, +-0.706f, -0.0681f, -0.7048f, +-0.556f, -0.8049f, -0.2071f, +0.8448f, 0.4045f, 0.3501f, +0.4259f, -0.5474f, 0.7203f, +-0.6907f, 0.2083f, -0.6924f, +0.1215f, 0.9852f, -0.1207f, +-0.1263f, 0.9332f, -0.3361f, +0.7711f, -0.0741f, -0.6323f, +0.2464f, 0.9691f, -0.0054f, +0.1774f, 0.9693f, 0.1697f, +-0.9042f, 0.208f, 0.3729f, +-0.8393f, -0.4118f, 0.3548f, +0.6888f, -0.7219f, -0.0648f, +0.1556f, -0.9861f, 0.0578f, +0.3271f, 0.9333f, 0.1478f, +-0.0024f, 0.2379f, 0.9712f, +-0.0026f, 0.4969f, 0.8677f, +0.0f, 1.0f, 0.0f, +0.1912f, -0.9815f, -0.0025f, +-0.3762f, -0.6681f, 0.6418f, +-0.7759f, 0.0432f, 0.6292f, +-0.0208f, -0.8044f, -0.5936f, +-0.2274f, 0.8822f, -0.4122f, +0.7532f, 0.5939f, 0.2824f, +-0.9221f, -0.0681f, -0.3807f, +-0.2198f, 0.8494f, 0.4796f, +0.0065f, -0.7656f, 0.6431f, +-0.5876f, 0.4472f, -0.6742f, +0.7981f, -0.6024f, 0.0036f, +-0.0383f, -0.9986f, -0.0341f, +-0.6369f, -0.2562f, -0.727f, +-0.5497f, 0.5937f, 0.5875f, +0.1084f, 0.9431f, 0.314f, +0.9042f, 0.208f, -0.3729f, +-0.6659f, 0.3392f, 0.6644f, +0.8393f, -0.4118f, -0.3548f, +0.0029f, -0.9986f, 0.0514f, +-0.9647f, -0.2552f, -0.0635f, +-0.2294f, 0.9692f, -0.0888f, +0.0026f, 0.4969f, -0.8677f, +0.2452f, 0.9334f, 0.2615f, +0.5171f, -0.4876f, -0.7033f, +-0.8951f, -0.4457f, 0.0058f, +-0.5936f, -0.8044f, 0.0208f, +0.5642f, -0.5426f, -0.6222f, +0.5938f, 0.4451f, 0.6702f, +0.5497f, 0.5937f, -0.5875f, +0.6657f, 0.4653f, 0.5832f, +0.4857f, -0.6243f, 0.6117f, +-0.0486f, -0.9986f, -0.0168f, +-0.6468f, 0.4051f, 0.646f, +0.6659f, 0.3392f, -0.6644f, +0.1833f, 0.9735f, -0.1365f, +0.3955f, 0.8505f, 0.3465f, +0.5139f, -0.6913f, 0.5078f, +0.8023f, 0.4978f, -0.329f, +-0.001f, 0.338f, 0.9411f, +-0.2496f, 0.8321f, -0.4951f, +0.8951f, -0.4457f, -0.0058f, +0.233f, 0.8502f, 0.4719f, +-0.0168f, -0.9986f, 0.0486f, +0.5936f, -0.8044f, -0.0208f, +-0.05f, 0.3155f, 0.9475f, +0.6585f, -0.342f, 0.6703f, +0.4909f, -0.1864f, -0.8509f, +-0.37f, 0.9238f, -0.0973f, +0.6468f, 0.4051f, -0.646f, +0.0059f, -0.986f, 0.1662f, +-0.3724f, 0.9278f, -0.0202f, +-0.3501f, 0.4045f, 0.8448f, +-0.0425f, 0.8398f, -0.5411f, +-0.1684f, 0.8499f, 0.4991f, +-0.6665f, -0.6907f, 0.2803f, +-0.2251f, 0.9692f, 0.099f, +0.9241f, -0.3816f, -0.0169f, +0.001f, 0.338f, -0.9411f, +-0.9411f, 0.338f, -0.001f, +-0.8666f, -0.2559f, -0.4282f, +0.0262f, 0.5183f, -0.8547f, +0.3014f, -0.6034f, 0.7382f, +0.0168f, -0.9986f, -0.0486f, +-0.3548f, -0.4118f, -0.8393f, +-0.6023f, -0.5297f, 0.5971f, +-0.9033f, 0.2079f, -0.375f, +-0.8938f, 0.4452f, -0.0532f, +0.6044f, 0.7397f, 0.2957f, +0.0008f, -0.0678f, 0.9976f, +0.7058f, 0.0906f, -0.7025f, +0.8453f, -0.4121f, 0.3399f, +-0.3595f, 0.933f, -0.0115f, +0.6698f, -0.6907f, 0.2723f, +-0.8995f, 0.2429f, -0.3629f, +-0.6366f, -0.447f, -0.6283f, +0.3501f, 0.4045f, -0.8448f, +-0.01f, -0.0605f, 0.9981f, +-0.8003f, 0.4978f, -0.334f, +0.1684f, 0.8499f, -0.4991f, +0.6665f, -0.6907f, -0.2803f, +0.2251f, 0.9692f, -0.099f, +-0.0036f, -0.6024f, 0.7981f, +0.6637f, -0.2967f, -0.6865f, +-0.081f, 0.985f, 0.1518f, +0.0084f, 0.2423f, 0.9701f, +0.0071f, -0.9029f, -0.4296f, +-0.8679f, 0.4966f, -0.0026f, +0.0123f, 0.5735f, 0.819f, +-0.0005f, 0.985f, 0.1719f, +0.6428f, -0.7172f, 0.2688f, +0.6588f, -0.3366f, 0.6727f, +0.1213f, -0.9861f, 0.1128f, +-0.8931f, 0.2424f, 0.3787f, +-0.1662f, -0.986f, 0.0059f, +0.9994f, 0.0313f, 0.0095f, +0.762f, -0.146f, 0.6308f, +-0.7731f, 0.0861f, -0.6283f, +-0.6644f, 0.3392f, -0.6659f, +-0.0027f, -0.7164f, 0.6976f, +0.0036f, -0.6024f, -0.7981f, +0.9782f, 0.2075f, 0.0011f, +0.0405f, -0.9991f, -0.0018f, +0.6882f, -0.703f, 0.179f, +-0.0115f, 0.933f, 0.3595f, +0.0911f, 0.0518f, -0.9944f, +0.0005f, 0.985f, -0.1719f, +0.5337f, -0.5852f, -0.6104f, +0.0042f, -0.6898f, 0.7239f, +0.4863f, 0.2366f, 0.8411f, +0.4991f, 0.8499f, 0.1684f, +-0.6543f, 0.7561f, 0.0071f, +0.265f, 0.747f, -0.6096f, +-0.329f, 0.4978f, -0.8023f, +0.1662f, -0.986f, -0.0059f, +-0.3491f, 0.4045f, -0.8452f, +0.3321f, 0.5936f, 0.733f, +-0.065f, 0.9851f, -0.1587f, +-0.6283f, -0.447f, 0.6366f, +0.0027f, -0.7164f, -0.6976f, +-0.1316f, 0.6339f, 0.762f, +-0.5609f, -0.604f, -0.5661f, +-0.8452f, 0.4045f, 0.3491f, +-0.5263f, 0.8495f, 0.0346f, +0.0115f, 0.933f, -0.3595f, +-0.0346f, 0.8495f, -0.5263f, +0.0077f, -0.4109f, 0.9116f, +0.5758f, -0.8175f, -0.0017f, +-0.0011f, 0.2075f, 0.9782f, +-0.0689f, -0.9861f, -0.1509f, +0.2934f, -0.5928f, -0.7499f, +0.0724f, 0.1198f, -0.9901f, +-0.7367f, -0.275f, -0.6176f, +-0.3131f, 0.8154f, 0.4868f, +-0.0114f, 0.0022f, 0.9999f, +0.6283f, -0.447f, -0.6366f, +0.8452f, 0.4045f, -0.3491f, +0.5263f, 0.8495f, -0.0346f, +-0.6383f, -0.4127f, 0.6497f, +-0.1719f, 0.985f, -0.0005f, +-0.6703f, -0.342f, 0.6585f, +-0.0085f, -0.3403f, 0.9402f, +-0.646f, 0.4051f, -0.6468f, +0.0011f, 0.2075f, -0.9782f, +-0.7216f, -0.3071f, 0.6204f, +0.0282f, 0.0023f, -0.9995f, +-0.2483f, 0.6806f, -0.6892f, +0.1518f, 0.985f, 0.081f, +0.047f, 0.0466f, -0.9978f, +0.7354f, -0.6034f, 0.3082f, +0.6919f, 0.2428f, 0.6798f, +0.4086f, -0.3626f, -0.8375f, +0.6383f, -0.4127f, -0.6497f, +-0.5875f, 0.5937f, -0.5497f, +0.6703f, -0.342f, -0.6585f, +-0.8245f, -0.4464f, 0.3476f, +0.0085f, -0.3403f, -0.9402f, +-0.0591f, -0.0663f, 0.996f, +0.0f, -1.0f, 0.0f, +0.4612f, 0.7474f, 0.478f, +0.6976f, -0.7164f, 0.0027f, +-0.9148f, 0.4037f, -0.0005f, +0.173f, -0.8158f, -0.5518f, +-0.3607f, 0.3387f, 0.8689f, +0.7836f, -0.2411f, 0.5724f, +-0.1985f, 0.8026f, -0.5623f, +-0.3094f, -0.2556f, -0.9159f, +-0.2803f, -0.6907f, -0.6665f, +0.8245f, -0.4464f, -0.3476f, +0.829f, -0.4466f, 0.3365f, +-0.4848f, 0.7385f, 0.4683f, +0.1583f, 0.9851f, 0.066f, +-0.0077f, 0.7656f, -0.6432f, +-0.0162f, 0.985f, 0.1717f, +0.1717f, 0.985f, 0.0162f, +0.0244f, 0.9805f, -0.1949f, +-0.2461f, -0.805f, -0.5397f, +0.0262f, 0.5934f, 0.8044f, +0.142f, 0.1881f, 0.9718f, +0.1846f, 0.1002f, 0.9776f, +0.4903f, -0.7178f, 0.4942f, +0.2637f, -0.7172f, 0.6449f, +0.3822f, -0.0678f, 0.9215f, +-0.0054f, 0.9691f, -0.2464f, +0.3607f, 0.3387f, -0.8689f, +-0.3587f, 0.3388f, -0.8697f, +-0.5694f, -0.8219f, 0.0081f, +-0.1324f, 0.985f, 0.1096f, +-0.099f, 0.9692f, -0.2251f, +-0.6702f, 0.4451f, 0.5938f, +0.0077f, -0.9976f, 0.0684f, +-0.5661f, -0.604f, 0.5609f, +-0.1096f, 0.985f, -0.1324f, +-0.6096f, 0.747f, -0.265f, +-0.0015f, 0.0295f, -0.9995f, +0.3476f, -0.4464f, 0.8245f, +-0.0635f, -0.2552f, 0.9647f, +-0.8468f, 0.4454f, 0.2904f, +-0.4719f, 0.8502f, 0.233f, +-0.0502f, 0.8385f, 0.5425f, +-0.6671f, 0.7448f, -0.0116f, +0.3508f, -0.3415f, 0.8719f, +-0.4119f, 0.6135f, -0.6736f, +-0.2688f, -0.7172f, 0.6428f, +-0.4041f, -0.8052f, 0.4337f, +-0.375f, 0.2079f, 0.9033f, +-0.0223f, -0.9986f, -0.0462f, +0.6702f, 0.4451f, -0.5938f, +0.9402f, -0.3403f, 0.0085f, +0.5661f, -0.604f, -0.5609f, +-0.6252f, 0.7406f, 0.246f, +-0.0341f, -0.9986f, 0.0383f, +-0.6111f, 0.4984f, -0.6148f, +0.6655f, 0.7462f, 0.0117f, +0.1233f, 0.199f, 0.9722f, +0.8468f, 0.4454f, -0.2904f, +0.7383f, 0.2702f, -0.6179f, +-0.8055f, 0.4452f, -0.3909f, +-0.3729f, 0.208f, -0.9042f, +0.4719f, 0.8502f, -0.233f, +0.243f, 0.747f, 0.6187f, +-0.6497f, -0.4127f, -0.6383f, +-0.5406f, 0.5651f, -0.623f, +0.0058f, -0.4457f, 0.8951f, +-0.3082f, -0.6034f, 0.7354f, +-0.8655f, -0.3412f, -0.3666f, +0.2688f, -0.7172f, -0.6428f, +0.4041f, -0.8052f, -0.4337f, +0.375f, 0.2079f, -0.9033f, +0.0341f, -0.9986f, -0.0383f, +-0.9701f, 0.2423f, 0.0084f, +-0.3807f, -0.0681f, 0.9221f, +0.9643f, -0.2551f, 0.0705f, +-0.8758f, 0.4808f, 0.0415f, +0.1207f, 0.9852f, 0.1215f, +0.4821f, 0.7724f, 0.4133f, +-0.0522f, 0.9982f, 0.0278f, +-0.4337f, -0.8052f, -0.4041f, +-0.6164f, 0.4198f, 0.6661f, +-0.8448f, 0.4045f, -0.3501f, +0.3082f, -0.6034f, -0.7354f, +0.8689f, 0.3387f, 0.3607f, +0.6894f, -0.7242f, 0.0091f, +0.3787f, 0.2424f, 0.8931f, +0.2904f, 0.4454f, 0.8468f, +0.6148f, 0.4984f, -0.6111f, +0.0501f, 0.985f, 0.1648f, +-0.5397f, -0.805f, 0.2461f, +-0.9159f, -0.2556f, 0.3094f, +0.706f, -0.0681f, 0.7048f, +-0.3341f, 0.4972f, 0.8006f, +0.556f, -0.8049f, 0.2071f, +-0.1774f, 0.9693f, -0.1697f, +0.6907f, 0.2083f, 0.6924f, +0.1263f, 0.9332f, 0.3361f, +0.3807f, -0.0681f, -0.9221f, +-0.1556f, -0.9861f, -0.0578f, +-0.3271f, 0.9333f, -0.1478f, +-0.3465f, 0.8505f, 0.3955f, +0.5315f, 0.8438f, -0.0735f, +0.9737f, 0.2276f, -0.0003f, +0.6441f, 0.7648f, -0.0112f, +-0.7239f, -0.6898f, 0.0042f, +-0.7532f, 0.5939f, -0.2824f, +0.1093f, 0.1415f, -0.9838f, +0.5397f, -0.805f, -0.2461f, +-0.7981f, -0.6024f, -0.0036f, +0.9456f, 0.3251f, -0.0052f, +0.1278f, 0.9696f, -0.2085f, +0.0208f, -0.8044f, 0.5936f, +0.1635f, 0.1348f, -0.9772f, +-0.733f, 0.5936f, 0.3321f, +-0.0505f, 0.9852f, -0.1635f, +0.4089f, -0.9069f, -0.1015f, +-0.0029f, -0.9986f, -0.0514f, +-0.1796f, 0.814f, -0.5522f, +0.9221f, -0.0681f, 0.3807f, +0.0383f, -0.9986f, 0.0341f, +0.6369f, -0.2562f, 0.727f, +0.3465f, 0.8505f, -0.3955f, +-0.2452f, 0.9334f, -0.2615f, +0.4921f, -0.247f, 0.8346f, +-0.9976f, -0.0678f, 0.0008f, +-0.5396f, 0.8418f, -0.0094f, +0.2294f, 0.9692f, 0.0888f, +0.7239f, -0.6898f, -0.0042f, +-0.4472f, 0.5952f, 0.6675f, +-0.6449f, -0.7172f, 0.2637f, +0.4543f, 0.2732f, -0.8478f, +-0.6798f, 0.2428f, 0.6919f, +-0.5938f, 0.4451f, -0.6702f, +0.733f, 0.5936f, -0.3321f, +-0.3955f, 0.8505f, -0.3465f, +-0.5139f, -0.6913f, -0.5078f, +-0.623f, -0.5156f, -0.5881f +}; + +/* 1 color */ +/*255 255 0 */ + +/* 1024 faces */ +/* numIdx fidx0 fidx1 fidx2 nidx0 nidx1 nidx2 coloridx */ + +const int numFaces = 1024; +const int faces[1024][8] = { +3, 0, 5, 6, 255, 295, 309, 0, +3, 6, 1, 0, 309, 465, 255, 0, +3, 1, 6, 7, 465, 309, 134, 0, +3, 7, 2, 1, 134, 4, 465, 0, +3, 2, 7, 8, 4, 134, 165, 0, +3, 8, 3, 2, 165, 448, 4, 0, +3, 3, 8, 9, 448, 165, 49, 0, +3, 9, 4, 3, 49, 116, 448, 0, +3, 5, 10, 11, 295, 248, 106, 0, +3, 11, 6, 5, 106, 309, 295, 0, +3, 6, 11, 12, 309, 106, 102, 0, +3, 12, 7, 6, 102, 134, 309, 0, +3, 7, 12, 13, 134, 102, 394, 0, +3, 13, 8, 7, 394, 165, 134, 0, +3, 8, 13, 14, 165, 394, 180, 0, +3, 14, 9, 8, 180, 49, 165, 0, +3, 10, 15, 16, 248, 401, 211, 0, +3, 16, 11, 10, 211, 106, 248, 0, +3, 11, 16, 17, 106, 211, 427, 0, +3, 17, 12, 11, 427, 102, 106, 0, +3, 12, 17, 18, 102, 427, 455, 0, +3, 18, 13, 12, 455, 394, 102, 0, +3, 13, 18, 19, 394, 455, 74, 0, +3, 19, 14, 13, 74, 180, 394, 0, +3, 15, 20, 21, 401, 174, 182, 0, +3, 21, 16, 15, 182, 211, 401, 0, +3, 16, 21, 22, 211, 182, 507, 0, +3, 22, 17, 16, 507, 427, 211, 0, +3, 17, 22, 23, 427, 507, 5, 0, +3, 23, 18, 17, 5, 455, 427, 0, +3, 18, 23, 24, 455, 5, 234, 0, +3, 24, 19, 18, 234, 74, 455, 0, +3, 20, 25, 26, 174, 386, 20, 0, +3, 26, 21, 20, 20, 182, 174, 0, +3, 21, 26, 27, 182, 20, 410, 0, +3, 27, 22, 21, 410, 507, 182, 0, +3, 22, 27, 28, 507, 410, 23, 0, +3, 28, 23, 22, 23, 5, 507, 0, +3, 23, 28, 29, 5, 23, 485, 0, +3, 29, 24, 23, 485, 234, 5, 0, +3, 25, 30, 31, 386, 69, 305, 0, +3, 31, 26, 25, 305, 20, 386, 0, +3, 26, 31, 32, 20, 305, 503, 0, +3, 32, 27, 26, 503, 410, 20, 0, +3, 27, 32, 33, 410, 503, 405, 0, +3, 33, 28, 27, 405, 23, 410, 0, +3, 28, 33, 34, 23, 405, 138, 0, +3, 34, 29, 28, 138, 485, 23, 0, +3, 30, 35, 36, 69, 115, 193, 0, +3, 36, 31, 30, 193, 305, 69, 0, +3, 31, 36, 37, 305, 193, 270, 0, +3, 37, 32, 31, 270, 503, 305, 0, +3, 32, 37, 38, 503, 270, 445, 0, +3, 38, 33, 32, 445, 405, 503, 0, +3, 33, 38, 39, 405, 445, 28, 0, +3, 39, 34, 33, 28, 138, 405, 0, +3, 35, 40, 41, 115, 467, 495, 0, +3, 41, 36, 35, 495, 193, 115, 0, +3, 36, 41, 42, 193, 495, 11, 0, +3, 42, 37, 36, 11, 270, 193, 0, +3, 37, 42, 43, 270, 11, 435, 0, +3, 43, 38, 37, 435, 445, 270, 0, +3, 38, 43, 44, 445, 435, 322, 0, +3, 44, 39, 38, 322, 28, 445, 0, +3, 40, 45, 46, 467, 27, 44, 0, +3, 46, 41, 40, 44, 495, 467, 0, +3, 41, 46, 47, 495, 44, 409, 0, +3, 47, 42, 41, 409, 11, 495, 0, +3, 42, 47, 48, 11, 409, 428, 0, +3, 48, 43, 42, 428, 435, 11, 0, +3, 43, 48, 49, 435, 428, 313, 0, +3, 49, 44, 43, 313, 322, 435, 0, +3, 45, 50, 51, 27, 513, 385, 0, +3, 51, 46, 45, 385, 44, 27, 0, +3, 46, 51, 52, 44, 385, 382, 0, +3, 52, 47, 46, 382, 409, 44, 0, +3, 47, 52, 53, 409, 382, 124, 0, +3, 53, 48, 47, 124, 428, 409, 0, +3, 48, 53, 54, 428, 124, 447, 0, +3, 54, 49, 48, 447, 313, 428, 0, +3, 50, 55, 56, 513, 136, 478, 0, +3, 56, 51, 50, 478, 385, 513, 0, +3, 51, 56, 57, 385, 478, 161, 0, +3, 57, 52, 51, 161, 382, 385, 0, +3, 52, 57, 58, 382, 161, 181, 0, +3, 58, 53, 52, 181, 124, 382, 0, +3, 53, 58, 59, 124, 181, 348, 0, +3, 59, 54, 53, 348, 447, 124, 0, +3, 55, 60, 61, 136, 431, 320, 0, +3, 61, 56, 55, 320, 478, 136, 0, +3, 56, 61, 62, 478, 320, 481, 0, +3, 62, 57, 56, 481, 161, 478, 0, +3, 57, 62, 63, 161, 481, 53, 0, +3, 63, 58, 57, 53, 181, 161, 0, +3, 58, 63, 64, 181, 53, 257, 0, +3, 64, 59, 58, 257, 348, 181, 0, +3, 60, 65, 66, 431, 135, 37, 0, +3, 66, 61, 60, 37, 320, 431, 0, +3, 61, 66, 67, 320, 37, 408, 0, +3, 67, 62, 61, 408, 481, 320, 0, +3, 62, 67, 68, 481, 408, 347, 0, +3, 68, 63, 62, 347, 53, 481, 0, +3, 63, 68, 69, 53, 347, 104, 0, +3, 69, 64, 63, 104, 257, 53, 0, +3, 65, 70, 71, 135, 191, 524, 0, +3, 71, 66, 65, 524, 37, 135, 0, +3, 66, 71, 72, 37, 524, 319, 0, +3, 72, 67, 66, 319, 408, 37, 0, +3, 67, 72, 73, 408, 319, 183, 0, +3, 73, 68, 67, 183, 347, 408, 0, +3, 68, 73, 74, 347, 183, 480, 0, +3, 74, 69, 68, 480, 104, 347, 0, +3, 70, 75, 76, 191, 483, 328, 0, +3, 76, 71, 70, 328, 524, 191, 0, +3, 71, 76, 77, 524, 328, 422, 0, +3, 77, 72, 71, 422, 319, 524, 0, +3, 72, 77, 78, 319, 422, 151, 0, +3, 78, 73, 72, 151, 183, 319, 0, +3, 73, 78, 79, 183, 151, 273, 0, +3, 79, 74, 73, 273, 480, 183, 0, +3, 75, 0, 1, 483, 255, 465, 0, +3, 1, 76, 75, 465, 328, 483, 0, +3, 76, 1, 2, 328, 465, 4, 0, +3, 2, 77, 76, 4, 422, 328, 0, +3, 77, 2, 3, 422, 4, 448, 0, +3, 3, 78, 77, 448, 151, 422, 0, +3, 78, 3, 4, 151, 448, 116, 0, +3, 4, 79, 78, 116, 273, 151, 0, +3, 4, 9, 84, 116, 49, 220, 0, +3, 84, 80, 4, 220, 131, 116, 0, +3, 80, 84, 85, 131, 220, 476, 0, +3, 85, 81, 80, 476, 26, 131, 0, +3, 81, 85, 86, 26, 476, 38, 0, +3, 86, 82, 81, 38, 336, 26, 0, +3, 82, 86, 87, 336, 38, 511, 0, +3, 87, 83, 82, 511, 1, 336, 0, +3, 9, 14, 88, 49, 180, 103, 0, +3, 88, 84, 9, 103, 220, 49, 0, +3, 84, 88, 89, 220, 103, 62, 0, +3, 89, 85, 84, 62, 476, 220, 0, +3, 85, 89, 90, 476, 62, 488, 0, +3, 90, 86, 85, 488, 38, 476, 0, +3, 86, 90, 91, 38, 488, 484, 0, +3, 91, 87, 86, 484, 511, 38, 0, +3, 14, 19, 92, 180, 74, 78, 0, +3, 92, 88, 14, 78, 103, 180, 0, +3, 88, 92, 93, 103, 78, 154, 0, +3, 93, 89, 88, 154, 62, 103, 0, +3, 89, 93, 94, 62, 154, 190, 0, +3, 94, 90, 89, 190, 488, 62, 0, +3, 90, 94, 95, 488, 190, 417, 0, +3, 95, 91, 90, 417, 484, 488, 0, +3, 19, 24, 96, 74, 234, 81, 0, +3, 96, 92, 19, 81, 78, 74, 0, +3, 92, 96, 97, 78, 81, 274, 0, +3, 97, 93, 92, 274, 154, 78, 0, +3, 93, 97, 98, 154, 274, 363, 0, +3, 98, 94, 93, 363, 190, 154, 0, +3, 94, 98, 99, 190, 363, 304, 0, +3, 99, 95, 94, 304, 417, 190, 0, +3, 24, 29, 100, 234, 485, 287, 0, +3, 100, 96, 24, 287, 81, 234, 0, +3, 96, 100, 101, 81, 287, 398, 0, +3, 101, 97, 96, 398, 274, 81, 0, +3, 97, 101, 102, 274, 398, 440, 0, +3, 102, 98, 97, 440, 363, 274, 0, +3, 98, 102, 103, 363, 440, 466, 0, +3, 103, 99, 98, 466, 304, 363, 0, +3, 29, 34, 104, 485, 138, 268, 0, +3, 104, 100, 29, 268, 287, 485, 0, +3, 100, 104, 105, 287, 268, 252, 0, +3, 105, 101, 100, 252, 398, 287, 0, +3, 101, 105, 106, 398, 252, 141, 0, +3, 106, 102, 101, 141, 440, 398, 0, +3, 102, 106, 107, 440, 141, 18, 0, +3, 107, 103, 102, 18, 466, 440, 0, +3, 34, 39, 108, 138, 28, 357, 0, +3, 108, 104, 34, 357, 268, 138, 0, +3, 104, 108, 109, 268, 357, 127, 0, +3, 109, 105, 104, 127, 252, 268, 0, +3, 105, 109, 110, 252, 127, 228, 0, +3, 110, 106, 105, 228, 141, 252, 0, +3, 106, 110, 111, 141, 228, 33, 0, +3, 111, 107, 106, 33, 18, 141, 0, +3, 39, 44, 112, 28, 322, 396, 0, +3, 112, 108, 39, 396, 357, 28, 0, +3, 108, 112, 113, 357, 396, 294, 0, +3, 113, 109, 108, 294, 127, 357, 0, +3, 109, 113, 114, 127, 294, 56, 0, +3, 114, 110, 109, 56, 228, 127, 0, +3, 110, 114, 115, 228, 56, 517, 0, +3, 115, 111, 110, 517, 33, 228, 0, +3, 44, 49, 116, 322, 313, 474, 0, +3, 116, 112, 44, 474, 396, 322, 0, +3, 112, 116, 117, 396, 474, 208, 0, +3, 117, 113, 112, 208, 294, 396, 0, +3, 113, 117, 118, 294, 208, 301, 0, +3, 118, 114, 113, 301, 56, 294, 0, +3, 114, 118, 119, 56, 301, 242, 0, +3, 119, 115, 114, 242, 517, 56, 0, +3, 49, 54, 120, 313, 447, 377, 0, +3, 120, 116, 49, 377, 474, 313, 0, +3, 116, 120, 121, 474, 377, 333, 0, +3, 121, 117, 116, 333, 208, 474, 0, +3, 117, 121, 122, 208, 333, 222, 0, +3, 122, 118, 117, 222, 301, 208, 0, +3, 118, 122, 123, 301, 222, 218, 0, +3, 123, 119, 118, 218, 242, 301, 0, +3, 54, 59, 124, 447, 348, 350, 0, +3, 124, 120, 54, 350, 377, 447, 0, +3, 120, 124, 125, 377, 350, 420, 0, +3, 125, 121, 120, 420, 333, 377, 0, +3, 121, 125, 126, 333, 420, 453, 0, +3, 126, 122, 121, 453, 222, 333, 0, +3, 122, 126, 127, 222, 453, 147, 0, +3, 127, 123, 122, 147, 218, 222, 0, +3, 59, 64, 128, 348, 257, 95, 0, +3, 128, 124, 59, 95, 350, 348, 0, +3, 124, 128, 129, 350, 95, 293, 0, +3, 129, 125, 124, 293, 420, 350, 0, +3, 125, 129, 130, 420, 293, 378, 0, +3, 130, 126, 125, 378, 453, 420, 0, +3, 126, 130, 131, 453, 378, 29, 0, +3, 131, 127, 126, 29, 147, 453, 0, +3, 64, 69, 132, 257, 104, 311, 0, +3, 132, 128, 64, 311, 95, 257, 0, +3, 128, 132, 133, 95, 311, 419, 0, +3, 133, 129, 128, 419, 293, 95, 0, +3, 129, 133, 134, 293, 419, 463, 0, +3, 134, 130, 129, 463, 378, 293, 0, +3, 130, 134, 135, 378, 463, 490, 0, +3, 135, 131, 130, 490, 29, 378, 0, +3, 69, 74, 136, 104, 480, 284, 0, +3, 136, 132, 69, 284, 311, 104, 0, +3, 132, 136, 137, 311, 284, 269, 0, +3, 137, 133, 132, 269, 419, 311, 0, +3, 133, 137, 138, 419, 269, 164, 0, +3, 138, 134, 133, 164, 463, 419, 0, +3, 134, 138, 139, 463, 164, 45, 0, +3, 139, 135, 134, 45, 490, 463, 0, +3, 74, 79, 140, 480, 273, 371, 0, +3, 140, 136, 74, 371, 284, 480, 0, +3, 136, 140, 141, 284, 371, 148, 0, +3, 141, 137, 136, 148, 269, 284, 0, +3, 137, 141, 142, 269, 148, 251, 0, +3, 142, 138, 137, 251, 164, 269, 0, +3, 138, 142, 143, 164, 251, 54, 0, +3, 143, 139, 138, 54, 45, 164, 0, +3, 79, 4, 80, 273, 116, 131, 0, +3, 80, 140, 79, 131, 371, 273, 0, +3, 140, 80, 81, 371, 131, 26, 0, +3, 81, 141, 140, 26, 148, 371, 0, +3, 141, 81, 82, 148, 26, 336, 0, +3, 82, 142, 141, 336, 251, 148, 0, +3, 142, 82, 83, 251, 336, 1, 0, +3, 83, 143, 142, 1, 54, 251, 0, +3, 83, 87, 148, 1, 511, 404, 0, +3, 148, 144, 83, 404, 276, 1, 0, +3, 144, 148, 149, 276, 404, 308, 0, +3, 149, 145, 144, 308, 520, 276, 0, +3, 145, 149, 150, 520, 308, 325, 0, +3, 150, 146, 145, 325, 395, 520, 0, +3, 146, 150, 151, 395, 325, 384, 0, +3, 151, 147, 146, 384, 246, 395, 0, +3, 87, 91, 152, 511, 484, 47, 0, +3, 152, 148, 87, 47, 404, 511, 0, +3, 148, 152, 153, 404, 47, 272, 0, +3, 153, 149, 148, 272, 308, 404, 0, +3, 149, 153, 154, 308, 272, 415, 0, +3, 154, 150, 149, 415, 325, 308, 0, +3, 150, 154, 155, 325, 415, 83, 0, +3, 155, 151, 150, 83, 384, 325, 0, +3, 91, 95, 156, 484, 417, 430, 0, +3, 156, 152, 91, 430, 47, 484, 0, +3, 152, 156, 157, 47, 430, 137, 0, +3, 157, 153, 152, 137, 272, 47, 0, +3, 153, 157, 158, 272, 137, 416, 0, +3, 158, 154, 153, 416, 415, 272, 0, +3, 154, 158, 159, 415, 416, 297, 0, +3, 159, 155, 154, 297, 83, 415, 0, +3, 95, 99, 160, 417, 304, 458, 0, +3, 160, 156, 95, 458, 430, 417, 0, +3, 156, 160, 161, 430, 458, 343, 0, +3, 161, 157, 156, 343, 137, 430, 0, +3, 157, 161, 162, 137, 343, 334, 0, +3, 162, 158, 157, 334, 416, 137, 0, +3, 158, 162, 163, 416, 334, 317, 0, +3, 163, 159, 158, 317, 297, 416, 0, +3, 99, 103, 164, 304, 466, 187, 0, +3, 164, 160, 99, 187, 458, 304, 0, +3, 160, 164, 165, 458, 187, 117, 0, +3, 165, 161, 160, 117, 343, 458, 0, +3, 161, 165, 166, 343, 117, 438, 0, +3, 166, 162, 161, 438, 334, 343, 0, +3, 162, 166, 167, 334, 438, 459, 0, +3, 167, 163, 162, 459, 317, 334, 0, +3, 103, 107, 168, 466, 18, 353, 0, +3, 168, 164, 103, 353, 187, 466, 0, +3, 164, 168, 169, 187, 353, 123, 0, +3, 169, 165, 164, 123, 117, 187, 0, +3, 165, 169, 170, 117, 123, 168, 0, +3, 170, 166, 165, 168, 438, 117, 0, +3, 166, 170, 171, 438, 168, 426, 0, +3, 171, 167, 166, 426, 459, 438, 0, +3, 107, 111, 172, 18, 33, 390, 0, +3, 172, 168, 107, 390, 353, 18, 0, +3, 168, 172, 173, 353, 390, 290, 0, +3, 173, 169, 168, 290, 123, 353, 0, +3, 169, 173, 174, 123, 290, 522, 0, +3, 174, 170, 169, 522, 168, 123, 0, +3, 170, 174, 175, 168, 522, 87, 0, +3, 175, 171, 170, 87, 426, 168, 0, +3, 111, 115, 176, 33, 517, 260, 0, +3, 176, 172, 111, 260, 390, 33, 0, +3, 172, 176, 177, 390, 260, 497, 0, +3, 177, 173, 172, 497, 290, 390, 0, +3, 173, 177, 178, 290, 497, 126, 0, +3, 178, 174, 173, 126, 522, 290, 0, +3, 174, 178, 179, 522, 126, 501, 0, +3, 179, 175, 174, 501, 87, 522, 0, +3, 115, 119, 180, 517, 242, 130, 0, +3, 180, 176, 115, 130, 260, 517, 0, +3, 176, 180, 181, 260, 130, 34, 0, +3, 181, 177, 176, 34, 497, 260, 0, +3, 177, 181, 182, 497, 34, 46, 0, +3, 182, 178, 177, 46, 126, 497, 0, +3, 178, 182, 183, 126, 46, 105, 0, +3, 183, 179, 178, 105, 501, 126, 0, +3, 119, 123, 184, 242, 218, 310, 0, +3, 184, 180, 119, 310, 130, 242, 0, +3, 180, 184, 185, 130, 310, 528, 0, +3, 185, 181, 180, 528, 34, 130, 0, +3, 181, 185, 186, 34, 528, 145, 0, +3, 186, 182, 181, 145, 46, 34, 0, +3, 182, 186, 187, 46, 145, 356, 0, +3, 187, 183, 182, 356, 105, 46, 0, +3, 123, 127, 188, 218, 147, 156, 0, +3, 188, 184, 123, 156, 310, 218, 0, +3, 184, 188, 189, 310, 156, 402, 0, +3, 189, 185, 184, 402, 528, 310, 0, +3, 185, 189, 190, 528, 402, 146, 0, +3, 190, 186, 185, 146, 145, 528, 0, +3, 186, 190, 191, 145, 146, 17, 0, +3, 191, 187, 186, 17, 356, 145, 0, +3, 127, 131, 192, 147, 29, 184, 0, +3, 192, 188, 127, 184, 156, 147, 0, +3, 188, 192, 193, 156, 184, 63, 0, +3, 193, 189, 188, 63, 402, 156, 0, +3, 189, 193, 194, 402, 63, 354, 0, +3, 194, 190, 189, 354, 146, 402, 0, +3, 190, 194, 195, 146, 354, 335, 0, +3, 195, 191, 190, 335, 17, 146, 0, +3, 131, 135, 196, 29, 490, 210, 0, +3, 196, 192, 131, 210, 184, 29, 0, +3, 192, 196, 197, 184, 210, 129, 0, +3, 197, 193, 192, 129, 63, 184, 0, +3, 193, 197, 198, 63, 129, 461, 0, +3, 198, 194, 193, 461, 354, 63, 0, +3, 194, 198, 199, 354, 461, 475, 0, +3, 199, 195, 194, 475, 335, 354, 0, +3, 135, 139, 200, 490, 45, 370, 0, +3, 200, 196, 135, 370, 210, 490, 0, +3, 196, 200, 201, 210, 370, 143, 0, +3, 201, 197, 196, 143, 129, 210, 0, +3, 197, 201, 202, 129, 143, 195, 0, +3, 202, 198, 197, 195, 461, 129, 0, +3, 198, 202, 203, 461, 195, 444, 0, +3, 203, 199, 198, 444, 475, 461, 0, +3, 139, 143, 204, 45, 54, 403, 0, +3, 204, 200, 139, 403, 370, 45, 0, +3, 200, 204, 205, 370, 403, 315, 0, +3, 205, 201, 200, 315, 143, 370, 0, +3, 201, 205, 206, 143, 315, 7, 0, +3, 206, 202, 201, 7, 195, 143, 0, +3, 202, 206, 207, 195, 7, 101, 0, +3, 207, 203, 202, 101, 444, 195, 0, +3, 143, 83, 144, 54, 1, 276, 0, +3, 144, 204, 143, 276, 403, 54, 0, +3, 204, 144, 145, 403, 276, 520, 0, +3, 145, 205, 204, 520, 315, 403, 0, +3, 205, 145, 146, 315, 520, 395, 0, +3, 146, 206, 205, 395, 7, 315, 0, +3, 206, 146, 147, 7, 395, 246, 0, +3, 147, 207, 206, 246, 101, 7, 0, +3, 147, 151, 212, 246, 384, 486, 0, +3, 212, 208, 147, 486, 279, 246, 0, +3, 208, 212, 213, 279, 486, 231, 0, +3, 213, 209, 208, 231, 349, 279, 0, +3, 209, 213, 214, 349, 231, 0, 0, +3, 214, 210, 209, 0, 216, 349, 0, +3, 210, 214, 211, 216, 0, 393, 0, +3, 211, 211, 210, 393, 393, 216, 0, +3, 151, 155, 215, 384, 83, 215, 0, +3, 215, 212, 151, 215, 486, 384, 0, +3, 212, 215, 216, 486, 215, 327, 0, +3, 216, 213, 212, 327, 231, 486, 0, +3, 213, 216, 217, 231, 327, 512, 0, +3, 217, 214, 213, 512, 0, 231, 0, +3, 214, 217, 211, 0, 512, 393, 0, +3, 211, 211, 214, 393, 393, 0, 0, +3, 155, 159, 218, 83, 297, 149, 0, +3, 218, 215, 155, 149, 215, 83, 0, +3, 215, 218, 219, 215, 149, 91, 0, +3, 219, 216, 215, 91, 327, 215, 0, +3, 216, 219, 220, 327, 91, 177, 0, +3, 220, 217, 216, 177, 512, 327, 0, +3, 217, 220, 211, 512, 177, 393, 0, +3, 211, 211, 217, 393, 393, 512, 0, +3, 159, 163, 221, 297, 317, 504, 0, +3, 221, 218, 159, 504, 149, 297, 0, +3, 218, 221, 222, 149, 504, 285, 0, +3, 222, 219, 218, 285, 91, 149, 0, +3, 219, 222, 223, 91, 285, 254, 0, +3, 223, 220, 219, 254, 177, 91, 0, +3, 220, 223, 211, 177, 254, 393, 0, +3, 211, 211, 220, 393, 393, 177, 0, +3, 163, 167, 224, 317, 459, 125, 0, +3, 224, 221, 163, 125, 504, 317, 0, +3, 221, 224, 225, 504, 125, 162, 0, +3, 225, 222, 221, 162, 285, 504, 0, +3, 222, 225, 226, 285, 162, 278, 0, +3, 226, 223, 222, 278, 254, 285, 0, +3, 223, 226, 211, 254, 278, 393, 0, +3, 211, 211, 223, 393, 393, 254, 0, +3, 167, 171, 227, 459, 426, 439, 0, +3, 227, 224, 167, 439, 125, 459, 0, +3, 224, 227, 228, 125, 439, 60, 0, +3, 228, 225, 224, 60, 162, 125, 0, +3, 225, 228, 229, 162, 60, 446, 0, +3, 229, 226, 225, 446, 278, 162, 0, +3, 226, 229, 211, 278, 446, 393, 0, +3, 211, 211, 226, 393, 393, 278, 0, +3, 171, 175, 230, 426, 87, 482, 0, +3, 230, 227, 171, 482, 439, 426, 0, +3, 227, 230, 231, 439, 482, 92, 0, +3, 231, 228, 227, 92, 60, 439, 0, +3, 228, 231, 232, 60, 92, 110, 0, +3, 232, 229, 228, 110, 446, 60, 0, +3, 229, 232, 211, 446, 110, 393, 0, +3, 211, 211, 229, 393, 393, 446, 0, +3, 175, 179, 233, 87, 501, 261, 0, +3, 233, 230, 175, 261, 482, 87, 0, +3, 230, 233, 234, 482, 261, 329, 0, +3, 234, 231, 230, 329, 92, 482, 0, +3, 231, 234, 235, 92, 329, 192, 0, +3, 235, 232, 231, 192, 110, 92, 0, +3, 232, 235, 211, 110, 192, 393, 0, +3, 211, 211, 232, 393, 393, 110, 0, +3, 179, 183, 236, 501, 105, 219, 0, +3, 236, 233, 179, 219, 261, 501, 0, +3, 233, 236, 237, 261, 219, 491, 0, +3, 237, 234, 233, 491, 329, 261, 0, +3, 234, 237, 238, 329, 491, 267, 0, +3, 238, 235, 234, 267, 192, 329, 0, +3, 235, 238, 211, 192, 267, 393, 0, +3, 211, 211, 235, 393, 393, 192, 0, +3, 183, 187, 239, 105, 356, 472, 0, +3, 239, 236, 183, 472, 219, 105, 0, +3, 236, 239, 240, 219, 472, 48, 0, +3, 240, 237, 236, 48, 491, 219, 0, +3, 237, 240, 241, 491, 48, 247, 0, +3, 241, 238, 237, 247, 267, 491, 0, +3, 238, 241, 211, 267, 247, 393, 0, +3, 211, 211, 238, 393, 393, 267, 0, +3, 187, 191, 242, 356, 17, 411, 0, +3, 242, 239, 187, 411, 472, 356, 0, +3, 239, 242, 243, 472, 411, 364, 0, +3, 243, 240, 239, 364, 48, 472, 0, +3, 240, 243, 244, 48, 364, 441, 0, +3, 244, 241, 240, 441, 247, 48, 0, +3, 241, 244, 211, 247, 441, 393, 0, +3, 211, 211, 241, 393, 393, 247, 0, +3, 191, 195, 245, 17, 335, 239, 0, +3, 245, 242, 191, 239, 411, 17, 0, +3, 242, 245, 246, 411, 239, 13, 0, +3, 246, 243, 242, 13, 364, 411, 0, +3, 243, 246, 247, 364, 13, 509, 0, +3, 247, 244, 243, 509, 441, 364, 0, +3, 244, 247, 211, 441, 509, 393, 0, +3, 211, 211, 244, 393, 393, 441, 0, +3, 195, 199, 248, 335, 475, 144, 0, +3, 248, 245, 195, 144, 239, 335, 0, +3, 245, 248, 249, 239, 144, 179, 0, +3, 249, 246, 245, 179, 13, 239, 0, +3, 246, 249, 250, 13, 179, 298, 0, +3, 250, 247, 246, 298, 509, 13, 0, +3, 247, 250, 211, 509, 298, 393, 0, +3, 211, 211, 247, 393, 393, 509, 0, +3, 199, 203, 251, 475, 444, 462, 0, +3, 251, 248, 199, 462, 144, 475, 0, +3, 248, 251, 252, 144, 462, 76, 0, +3, 252, 249, 248, 76, 179, 144, 0, +3, 249, 252, 253, 179, 76, 464, 0, +3, 253, 250, 249, 464, 298, 179, 0, +3, 250, 253, 211, 298, 464, 393, 0, +3, 211, 211, 250, 393, 393, 298, 0, +3, 203, 207, 254, 444, 101, 500, 0, +3, 254, 251, 203, 500, 462, 444, 0, +3, 251, 254, 255, 462, 500, 113, 0, +3, 255, 252, 251, 113, 76, 462, 0, +3, 252, 255, 256, 76, 113, 128, 0, +3, 256, 253, 252, 128, 464, 76, 0, +3, 253, 256, 211, 464, 128, 393, 0, +3, 211, 211, 253, 393, 393, 464, 0, +3, 207, 147, 208, 101, 246, 279, 0, +3, 208, 254, 207, 279, 500, 101, 0, +3, 254, 208, 209, 500, 279, 349, 0, +3, 209, 255, 254, 349, 113, 500, 0, +3, 255, 209, 210, 113, 349, 216, 0, +3, 210, 256, 255, 216, 128, 113, 0, +3, 256, 210, 211, 128, 216, 393, 0, +3, 211, 211, 256, 393, 393, 128, 0, +3, 257, 262, 263, 425, 244, 58, 0, +3, 263, 258, 257, 58, 337, 425, 0, +3, 258, 263, 264, 337, 58, 214, 0, +3, 264, 259, 258, 214, 236, 337, 0, +3, 259, 264, 265, 236, 214, 266, 0, +3, 265, 260, 259, 266, 32, 236, 0, +3, 260, 265, 266, 32, 266, 331, 0, +3, 266, 261, 260, 331, 109, 32, 0, +3, 262, 267, 268, 244, 233, 369, 0, +3, 268, 263, 262, 369, 58, 244, 0, +3, 263, 268, 269, 58, 369, 71, 0, +3, 269, 264, 263, 71, 214, 58, 0, +3, 264, 269, 270, 214, 71, 392, 0, +3, 270, 265, 264, 392, 266, 214, 0, +3, 265, 270, 271, 266, 392, 312, 0, +3, 271, 266, 265, 312, 331, 266, 0, +3, 267, 272, 273, 233, 12, 434, 0, +3, 273, 268, 267, 434, 369, 233, 0, +3, 268, 273, 274, 369, 434, 188, 0, +3, 274, 269, 268, 188, 71, 369, 0, +3, 269, 274, 275, 71, 188, 201, 0, +3, 275, 270, 269, 201, 392, 71, 0, +3, 270, 275, 276, 392, 201, 238, 0, +3, 276, 271, 270, 238, 312, 392, 0, +3, 272, 277, 278, 12, 142, 114, 0, +3, 278, 273, 272, 114, 434, 12, 0, +3, 273, 278, 279, 434, 114, 173, 0, +3, 279, 274, 273, 173, 188, 434, 0, +3, 274, 279, 280, 188, 173, 14, 0, +3, 280, 275, 274, 14, 201, 188, 0, +3, 275, 280, 281, 201, 14, 15, 0, +3, 281, 276, 275, 15, 238, 201, 0, +3, 277, 282, 283, 142, 407, 288, 0, +3, 283, 278, 277, 288, 114, 142, 0, +3, 278, 283, 284, 114, 288, 400, 0, +3, 284, 279, 278, 400, 173, 114, 0, +3, 279, 284, 285, 173, 400, 457, 0, +3, 285, 280, 279, 457, 14, 173, 0, +3, 280, 285, 286, 14, 457, 332, 0, +3, 286, 281, 280, 332, 15, 14, 0, +3, 282, 287, 288, 407, 194, 42, 0, +3, 288, 283, 282, 42, 288, 407, 0, +3, 283, 288, 289, 288, 42, 380, 0, +3, 289, 284, 283, 380, 400, 288, 0, +3, 284, 289, 290, 400, 380, 383, 0, +3, 290, 285, 284, 383, 457, 400, 0, +3, 285, 290, 291, 457, 383, 197, 0, +3, 291, 286, 285, 197, 332, 457, 0, +3, 287, 292, 293, 194, 321, 152, 0, +3, 293, 288, 287, 152, 42, 194, 0, +3, 288, 293, 294, 42, 152, 397, 0, +3, 294, 289, 288, 397, 380, 42, 0, +3, 289, 294, 295, 380, 397, 342, 0, +3, 295, 290, 289, 342, 383, 380, 0, +3, 290, 295, 296, 383, 342, 225, 0, +3, 296, 291, 290, 225, 197, 383, 0, +3, 292, 257, 258, 321, 425, 337, 0, +3, 258, 293, 292, 337, 152, 321, 0, +3, 293, 258, 259, 152, 337, 236, 0, +3, 259, 294, 293, 236, 397, 152, 0, +3, 294, 259, 260, 397, 236, 32, 0, +3, 260, 295, 294, 32, 342, 397, 0, +3, 295, 260, 261, 342, 32, 109, 0, +3, 261, 296, 295, 109, 225, 342, 0, +3, 261, 266, 301, 109, 331, 175, 0, +3, 301, 297, 261, 175, 502, 109, 0, +3, 297, 301, 302, 502, 175, 265, 0, +3, 302, 298, 297, 265, 84, 502, 0, +3, 298, 302, 303, 84, 265, 186, 0, +3, 303, 299, 298, 186, 496, 84, 0, +3, 299, 303, 304, 496, 186, 470, 0, +3, 304, 300, 299, 470, 494, 496, 0, +3, 266, 271, 305, 331, 312, 170, 0, +3, 305, 301, 266, 170, 175, 331, 0, +3, 301, 305, 306, 175, 170, 97, 0, +3, 306, 302, 301, 97, 265, 175, 0, +3, 302, 306, 307, 265, 97, 205, 0, +3, 307, 303, 302, 205, 186, 265, 0, +3, 303, 307, 308, 186, 205, 449, 0, +3, 308, 304, 303, 449, 470, 186, 0, +3, 271, 276, 309, 312, 238, 379, 0, +3, 309, 305, 271, 379, 170, 312, 0, +3, 305, 309, 310, 170, 379, 300, 0, +3, 310, 306, 305, 300, 97, 170, 0, +3, 306, 310, 311, 97, 300, 118, 0, +3, 311, 307, 306, 118, 205, 97, 0, +3, 307, 311, 312, 205, 118, 237, 0, +3, 312, 308, 307, 237, 449, 205, 0, +3, 276, 281, 313, 238, 15, 199, 0, +3, 313, 309, 276, 199, 379, 238, 0, +3, 309, 313, 314, 379, 199, 94, 0, +3, 314, 310, 309, 94, 300, 379, 0, +3, 310, 314, 315, 300, 94, 421, 0, +3, 315, 311, 310, 421, 118, 300, 0, +3, 311, 315, 316, 118, 421, 31, 0, +3, 316, 312, 311, 31, 237, 118, 0, +3, 281, 286, 317, 15, 332, 367, 0, +3, 317, 313, 281, 367, 199, 15, 0, +3, 313, 317, 318, 199, 367, 529, 0, +3, 318, 314, 313, 529, 94, 199, 0, +3, 314, 318, 319, 94, 529, 185, 0, +3, 319, 315, 314, 185, 421, 94, 0, +3, 315, 319, 320, 421, 185, 89, 0, +3, 320, 316, 315, 89, 31, 421, 0, +3, 286, 291, 321, 332, 197, 172, 0, +3, 321, 317, 286, 172, 367, 332, 0, +3, 317, 321, 322, 367, 172, 209, 0, +3, 322, 318, 317, 209, 529, 367, 0, +3, 318, 322, 323, 529, 209, 429, 0, +3, 323, 319, 318, 429, 185, 529, 0, +3, 319, 323, 324, 185, 429, 112, 0, +3, 324, 320, 319, 112, 89, 185, 0, +3, 291, 296, 325, 197, 225, 451, 0, +3, 325, 321, 291, 451, 172, 197, 0, +3, 321, 325, 326, 172, 451, 66, 0, +3, 326, 322, 321, 66, 209, 172, 0, +3, 322, 326, 327, 209, 66, 176, 0, +3, 327, 323, 322, 176, 429, 209, 0, +3, 323, 327, 328, 429, 176, 155, 0, +3, 328, 324, 323, 155, 112, 429, 0, +3, 296, 261, 297, 225, 109, 502, 0, +3, 297, 325, 296, 502, 451, 225, 0, +3, 325, 297, 298, 451, 502, 84, 0, +3, 298, 326, 325, 84, 66, 451, 0, +3, 326, 298, 299, 66, 84, 496, 0, +3, 299, 327, 326, 496, 176, 66, 0, +3, 327, 299, 300, 176, 496, 494, 0, +3, 300, 328, 327, 494, 155, 176, 0, +3, 329, 334, 335, 3, 355, 122, 0, +3, 335, 330, 329, 122, 518, 3, 0, +3, 330, 335, 336, 518, 122, 111, 0, +3, 336, 331, 330, 111, 213, 518, 0, +3, 331, 336, 337, 213, 111, 473, 0, +3, 337, 332, 331, 473, 468, 213, 0, +3, 332, 337, 338, 468, 473, 521, 0, +3, 338, 333, 332, 521, 346, 468, 0, +3, 334, 339, 340, 355, 61, 414, 0, +3, 340, 335, 334, 414, 122, 355, 0, +3, 335, 340, 341, 122, 414, 413, 0, +3, 341, 336, 335, 413, 111, 122, 0, +3, 336, 341, 342, 111, 413, 204, 0, +3, 342, 337, 336, 204, 473, 111, 0, +3, 337, 342, 343, 473, 204, 217, 0, +3, 343, 338, 337, 217, 521, 473, 0, +3, 339, 344, 345, 61, 55, 100, 0, +3, 345, 340, 339, 100, 414, 61, 0, +3, 340, 345, 346, 414, 100, 399, 0, +3, 346, 341, 340, 399, 413, 414, 0, +3, 341, 346, 347, 413, 399, 326, 0, +3, 347, 342, 341, 326, 204, 413, 0, +3, 342, 347, 348, 204, 326, 221, 0, +3, 348, 343, 342, 221, 217, 204, 0, +3, 344, 349, 350, 55, 508, 477, 0, +3, 350, 345, 344, 477, 100, 55, 0, +3, 345, 350, 351, 100, 477, 292, 0, +3, 351, 346, 345, 292, 399, 100, 0, +3, 346, 351, 352, 399, 292, 73, 0, +3, 352, 347, 346, 73, 326, 399, 0, +3, 347, 352, 353, 326, 73, 362, 0, +3, 353, 348, 347, 362, 221, 326, 0, +3, 349, 354, 355, 508, 365, 262, 0, +3, 355, 350, 349, 262, 477, 508, 0, +3, 350, 355, 356, 477, 262, 93, 0, +3, 356, 351, 350, 93, 292, 477, 0, +3, 351, 356, 357, 292, 93, 318, 0, +3, 357, 352, 351, 318, 73, 292, 0, +3, 352, 357, 358, 73, 318, 163, 0, +3, 358, 353, 352, 163, 362, 73, 0, +3, 354, 359, 360, 365, 140, 340, 0, +3, 360, 355, 354, 340, 262, 365, 0, +3, 355, 360, 361, 262, 340, 505, 0, +3, 361, 356, 355, 505, 93, 262, 0, +3, 356, 361, 362, 93, 505, 499, 0, +3, 362, 357, 356, 499, 318, 93, 0, +3, 357, 362, 363, 318, 499, 159, 0, +3, 363, 358, 357, 159, 163, 318, 0, +3, 359, 364, 365, 140, 510, 68, 0, +3, 365, 360, 359, 68, 340, 140, 0, +3, 360, 365, 366, 340, 68, 167, 0, +3, 366, 361, 360, 167, 505, 340, 0, +3, 361, 366, 367, 505, 167, 245, 0, +3, 367, 362, 361, 245, 499, 505, 0, +3, 362, 367, 368, 499, 245, 437, 0, +3, 368, 363, 362, 437, 159, 499, 0, +3, 364, 329, 330, 510, 3, 518, 0, +3, 330, 365, 364, 518, 68, 510, 0, +3, 365, 330, 331, 68, 518, 213, 0, +3, 331, 366, 365, 213, 167, 68, 0, +3, 366, 331, 332, 167, 213, 468, 0, +3, 332, 367, 366, 468, 245, 167, 0, +3, 367, 332, 333, 245, 468, 346, 0, +3, 333, 368, 367, 346, 437, 245, 0, +3, 333, 338, 373, 346, 521, 79, 0, +3, 373, 369, 333, 79, 286, 346, 0, +3, 369, 373, 374, 286, 79, 77, 0, +3, 374, 370, 369, 77, 22, 286, 0, +3, 370, 374, 375, 22, 77, 523, 0, +3, 375, 371, 370, 523, 330, 22, 0, +3, 371, 375, 376, 330, 523, 259, 0, +3, 376, 372, 371, 259, 338, 330, 0, +3, 338, 343, 377, 521, 217, 207, 0, +3, 377, 373, 338, 207, 79, 521, 0, +3, 373, 377, 378, 79, 207, 471, 0, +3, 378, 374, 373, 471, 77, 79, 0, +3, 374, 378, 379, 77, 471, 198, 0, +3, 379, 375, 374, 198, 523, 77, 0, +3, 375, 379, 380, 523, 198, 366, 0, +3, 380, 376, 375, 366, 259, 523, 0, +3, 343, 348, 381, 217, 221, 516, 0, +3, 381, 377, 343, 516, 207, 217, 0, +3, 377, 381, 382, 207, 516, 250, 0, +3, 382, 378, 377, 250, 471, 207, 0, +3, 378, 382, 383, 471, 250, 240, 0, +3, 383, 379, 378, 240, 198, 471, 0, +3, 379, 383, 384, 198, 240, 381, 0, +3, 384, 380, 379, 381, 366, 198, 0, +3, 348, 353, 385, 221, 362, 230, 0, +3, 385, 381, 348, 230, 516, 221, 0, +3, 381, 385, 386, 516, 230, 303, 0, +3, 386, 382, 381, 303, 250, 516, 0, +3, 382, 386, 387, 250, 303, 10, 0, +3, 387, 383, 382, 10, 240, 250, 0, +3, 383, 387, 388, 240, 10, 283, 0, +3, 388, 384, 383, 283, 381, 240, 0, +3, 353, 358, 389, 362, 163, 282, 0, +3, 389, 385, 353, 282, 230, 362, 0, +3, 385, 389, 390, 230, 282, 35, 0, +3, 390, 386, 385, 35, 303, 230, 0, +3, 386, 390, 391, 303, 35, 243, 0, +3, 391, 387, 386, 243, 10, 303, 0, +3, 387, 391, 392, 10, 243, 368, 0, +3, 392, 388, 387, 368, 283, 10, 0, +3, 358, 363, 393, 163, 159, 296, 0, +3, 393, 389, 358, 296, 282, 163, 0, +3, 389, 393, 394, 282, 296, 160, 0, +3, 394, 390, 389, 160, 35, 282, 0, +3, 390, 394, 395, 35, 160, 323, 0, +3, 395, 391, 390, 323, 243, 35, 0, +3, 391, 395, 396, 243, 323, 280, 0, +3, 396, 392, 391, 280, 368, 243, 0, +3, 363, 368, 397, 159, 437, 275, 0, +3, 397, 393, 363, 275, 296, 159, 0, +3, 393, 397, 398, 296, 275, 133, 0, +3, 398, 394, 393, 133, 160, 296, 0, +3, 394, 398, 399, 160, 133, 344, 0, +3, 399, 395, 394, 344, 323, 160, 0, +3, 395, 399, 400, 323, 344, 108, 0, +3, 400, 396, 395, 108, 280, 323, 0, +3, 368, 333, 369, 437, 346, 286, 0, +3, 369, 397, 368, 286, 275, 437, 0, +3, 397, 369, 370, 275, 286, 22, 0, +3, 370, 398, 397, 22, 133, 275, 0, +3, 398, 370, 371, 133, 22, 330, 0, +3, 371, 399, 398, 330, 344, 133, 0, +3, 399, 371, 372, 344, 330, 338, 0, +3, 372, 400, 399, 338, 108, 344, 0, +3, 401, 401, 406, 235, 235, 189, 0, +3, 406, 402, 401, 189, 40, 235, 0, +3, 402, 406, 407, 40, 189, 306, 0, +3, 407, 403, 402, 306, 119, 40, 0, +3, 403, 407, 408, 119, 306, 202, 0, +3, 408, 404, 403, 202, 443, 119, 0, +3, 404, 408, 409, 443, 202, 241, 0, +3, 409, 405, 404, 241, 75, 443, 0, +3, 401, 401, 410, 235, 235, 263, 0, +3, 410, 406, 401, 263, 189, 235, 0, +3, 406, 410, 411, 189, 263, 196, 0, +3, 411, 407, 406, 196, 306, 189, 0, +3, 407, 411, 412, 306, 196, 281, 0, +3, 412, 408, 407, 281, 202, 306, 0, +3, 408, 412, 413, 202, 281, 121, 0, +3, 413, 409, 408, 121, 241, 202, 0, +3, 401, 401, 414, 235, 235, 479, 0, +3, 414, 410, 401, 479, 263, 235, 0, +3, 410, 414, 415, 263, 479, 36, 0, +3, 415, 411, 410, 36, 196, 263, 0, +3, 411, 415, 416, 196, 36, 436, 0, +3, 416, 412, 411, 436, 281, 196, 0, +3, 412, 416, 417, 281, 436, 351, 0, +3, 417, 413, 412, 351, 121, 281, 0, +3, 401, 401, 418, 235, 235, 90, 0, +3, 418, 414, 401, 90, 479, 235, 0, +3, 414, 418, 419, 479, 90, 361, 0, +3, 419, 415, 414, 361, 36, 479, 0, +3, 415, 419, 420, 36, 361, 376, 0, +3, 420, 416, 415, 376, 436, 36, 0, +3, 416, 420, 421, 436, 376, 412, 0, +3, 421, 417, 416, 412, 351, 436, 0, +3, 401, 401, 422, 235, 235, 52, 0, +3, 422, 418, 401, 52, 90, 235, 0, +3, 418, 422, 423, 90, 52, 21, 0, +3, 423, 419, 418, 21, 361, 90, 0, +3, 419, 423, 424, 361, 21, 158, 0, +3, 424, 420, 419, 158, 376, 361, 0, +3, 420, 424, 425, 376, 158, 39, 0, +3, 425, 421, 420, 39, 412, 376, 0, +3, 401, 401, 426, 235, 235, 424, 0, +3, 426, 422, 401, 424, 52, 235, 0, +3, 422, 426, 427, 52, 424, 373, 0, +3, 427, 423, 422, 373, 21, 52, 0, +3, 423, 427, 428, 21, 373, 375, 0, +3, 428, 424, 423, 375, 158, 21, 0, +3, 424, 428, 429, 158, 375, 249, 0, +3, 429, 425, 424, 249, 39, 158, 0, +3, 401, 401, 430, 235, 235, 432, 0, +3, 430, 426, 401, 432, 424, 235, 0, +3, 426, 430, 431, 424, 432, 229, 0, +3, 431, 427, 426, 229, 373, 424, 0, +3, 427, 431, 432, 373, 229, 65, 0, +3, 432, 428, 427, 65, 375, 373, 0, +3, 428, 432, 433, 375, 65, 506, 0, +3, 433, 429, 428, 506, 249, 375, 0, +3, 401, 401, 434, 235, 235, 302, 0, +3, 434, 430, 401, 302, 432, 235, 0, +3, 430, 434, 435, 432, 302, 96, 0, +3, 435, 431, 430, 96, 229, 432, 0, +3, 431, 435, 436, 229, 96, 169, 0, +3, 436, 432, 431, 169, 65, 229, 0, +3, 432, 436, 437, 65, 169, 59, 0, +3, 437, 433, 432, 59, 506, 65, 0, +3, 401, 401, 438, 235, 235, 452, 0, +3, 438, 434, 401, 452, 302, 235, 0, +3, 434, 438, 439, 302, 452, 30, 0, +3, 439, 435, 434, 30, 96, 302, 0, +3, 435, 439, 440, 96, 30, 460, 0, +3, 440, 436, 435, 460, 169, 96, 0, +3, 436, 440, 441, 169, 460, 498, 0, +3, 441, 437, 436, 498, 59, 169, 0, +3, 401, 401, 442, 235, 235, 525, 0, +3, 442, 438, 401, 525, 452, 235, 0, +3, 438, 442, 443, 452, 525, 456, 0, +3, 443, 439, 438, 456, 30, 452, 0, +3, 439, 443, 444, 30, 456, 9, 0, +3, 444, 440, 439, 9, 460, 30, 0, +3, 440, 444, 445, 460, 9, 388, 0, +3, 445, 441, 440, 388, 498, 460, 0, +3, 401, 401, 446, 235, 235, 212, 0, +3, 446, 442, 401, 212, 525, 235, 0, +3, 442, 446, 447, 525, 212, 299, 0, +3, 447, 443, 442, 299, 456, 525, 0, +3, 443, 447, 448, 456, 299, 166, 0, +3, 448, 444, 443, 166, 9, 456, 0, +3, 444, 448, 449, 9, 166, 72, 0, +3, 449, 445, 444, 72, 388, 9, 0, +3, 401, 401, 450, 235, 235, 107, 0, +3, 450, 446, 401, 107, 212, 235, 0, +3, 446, 450, 451, 212, 107, 82, 0, +3, 451, 447, 446, 82, 299, 212, 0, +3, 447, 451, 452, 299, 82, 391, 0, +3, 452, 448, 447, 391, 166, 299, 0, +3, 448, 452, 453, 166, 391, 139, 0, +3, 453, 449, 448, 139, 72, 166, 0, +3, 401, 401, 454, 235, 235, 70, 0, +3, 454, 450, 401, 70, 107, 235, 0, +3, 450, 454, 455, 107, 70, 51, 0, +3, 455, 451, 450, 51, 82, 107, 0, +3, 451, 455, 456, 82, 51, 178, 0, +3, 456, 452, 451, 178, 391, 82, 0, +3, 452, 456, 457, 391, 178, 57, 0, +3, 457, 453, 452, 57, 139, 391, 0, +3, 401, 401, 458, 235, 235, 442, 0, +3, 458, 454, 401, 442, 70, 235, 0, +3, 454, 458, 459, 70, 442, 387, 0, +3, 459, 455, 454, 387, 51, 70, 0, +3, 455, 459, 460, 51, 387, 389, 0, +3, 460, 456, 455, 389, 178, 51, 0, +3, 456, 460, 461, 178, 389, 264, 0, +3, 461, 457, 456, 264, 57, 178, 0, +3, 401, 401, 462, 235, 235, 450, 0, +3, 462, 458, 401, 450, 442, 235, 0, +3, 458, 462, 463, 442, 450, 253, 0, +3, 463, 459, 458, 253, 387, 442, 0, +3, 459, 463, 464, 387, 253, 86, 0, +3, 464, 460, 459, 86, 389, 387, 0, +3, 460, 464, 465, 389, 86, 526, 0, +3, 465, 461, 460, 526, 264, 389, 0, +3, 401, 401, 402, 235, 235, 40, 0, +3, 402, 462, 401, 40, 450, 235, 0, +3, 462, 402, 403, 450, 40, 119, 0, +3, 403, 463, 462, 119, 253, 450, 0, +3, 463, 403, 404, 253, 119, 443, 0, +3, 404, 464, 463, 443, 86, 253, 0, +3, 464, 404, 405, 86, 443, 75, 0, +3, 405, 465, 464, 75, 526, 86, 0, +3, 405, 409, 470, 75, 241, 519, 0, +3, 470, 466, 405, 519, 226, 75, 0, +3, 466, 470, 471, 226, 519, 406, 0, +3, 471, 467, 466, 406, 98, 226, 0, +3, 467, 471, 472, 98, 406, 232, 0, +3, 472, 468, 467, 232, 43, 98, 0, +3, 468, 472, 473, 43, 232, 345, 0, +3, 473, 469, 468, 345, 372, 43, 0, +3, 409, 413, 474, 241, 121, 227, 0, +3, 474, 470, 409, 227, 519, 241, 0, +3, 470, 474, 475, 519, 227, 469, 0, +3, 475, 471, 470, 469, 406, 519, 0, +3, 471, 475, 476, 406, 469, 258, 0, +3, 476, 472, 471, 258, 232, 406, 0, +3, 472, 476, 477, 232, 258, 271, 0, +3, 477, 473, 472, 271, 345, 232, 0, +3, 413, 417, 478, 121, 351, 157, 0, +3, 478, 474, 413, 157, 227, 121, 0, +3, 474, 478, 479, 227, 157, 80, 0, +3, 479, 475, 474, 80, 469, 227, 0, +3, 475, 479, 480, 469, 80, 489, 0, +3, 480, 476, 475, 489, 258, 469, 0, +3, 476, 480, 481, 258, 489, 277, 0, +3, 481, 477, 476, 277, 271, 258, 0, +3, 417, 421, 482, 351, 412, 153, 0, +3, 482, 478, 417, 153, 157, 351, 0, +3, 478, 482, 483, 157, 153, 324, 0, +3, 483, 479, 478, 324, 80, 157, 0, +3, 479, 483, 484, 80, 324, 339, 0, +3, 484, 480, 479, 339, 489, 80, 0, +3, 480, 484, 485, 489, 339, 88, 0, +3, 485, 481, 480, 88, 277, 489, 0, +3, 421, 425, 486, 412, 39, 6, 0, +3, 486, 482, 421, 6, 153, 412, 0, +3, 482, 486, 487, 153, 6, 8, 0, +3, 487, 483, 482, 8, 324, 153, 0, +3, 483, 487, 488, 324, 8, 16, 0, +3, 488, 484, 483, 16, 339, 324, 0, +3, 484, 488, 489, 339, 16, 289, 0, +3, 489, 485, 484, 289, 88, 339, 0, +3, 425, 429, 490, 39, 249, 99, 0, +3, 490, 486, 425, 99, 6, 39, 0, +3, 486, 490, 491, 6, 99, 200, 0, +3, 491, 487, 486, 200, 8, 6, 0, +3, 487, 491, 492, 8, 200, 150, 0, +3, 492, 488, 487, 150, 16, 8, 0, +3, 488, 492, 493, 16, 150, 493, 0, +3, 493, 489, 488, 493, 289, 16, 0, +3, 429, 433, 494, 249, 506, 291, 0, +3, 494, 490, 429, 291, 99, 249, 0, +3, 490, 494, 495, 99, 291, 64, 0, +3, 495, 491, 490, 64, 200, 99, 0, +3, 491, 495, 496, 200, 64, 19, 0, +3, 496, 492, 491, 19, 150, 200, 0, +3, 492, 496, 497, 150, 19, 433, 0, +3, 497, 493, 492, 433, 493, 150, 0, +3, 433, 437, 498, 506, 59, 203, 0, +3, 498, 494, 433, 203, 291, 506, 0, +3, 494, 498, 499, 291, 203, 374, 0, +3, 499, 495, 494, 374, 64, 291, 0, +3, 495, 499, 500, 64, 374, 307, 0, +3, 500, 496, 495, 307, 19, 64, 0, +3, 496, 500, 501, 19, 307, 358, 0, +3, 501, 497, 496, 358, 433, 19, 0, +3, 437, 441, 502, 59, 498, 256, 0, +3, 502, 498, 437, 256, 203, 59, 0, +3, 498, 502, 503, 203, 256, 132, 0, +3, 503, 499, 498, 132, 374, 203, 0, +3, 499, 503, 504, 374, 132, 492, 0, +3, 504, 500, 499, 492, 307, 374, 0, +3, 500, 504, 505, 307, 492, 67, 0, +3, 505, 501, 500, 67, 358, 307, 0, +3, 441, 445, 506, 498, 388, 487, 0, +3, 506, 502, 441, 487, 256, 498, 0, +3, 502, 506, 507, 256, 487, 206, 0, +3, 507, 503, 502, 206, 132, 256, 0, +3, 503, 507, 508, 132, 206, 515, 0, +3, 508, 504, 503, 515, 492, 132, 0, +3, 504, 508, 509, 492, 515, 527, 0, +3, 509, 505, 504, 527, 67, 492, 0, +3, 445, 449, 510, 388, 72, 423, 0, +3, 510, 506, 445, 423, 487, 388, 0, +3, 506, 510, 511, 487, 423, 352, 0, +3, 511, 507, 506, 352, 206, 487, 0, +3, 507, 511, 512, 206, 352, 224, 0, +3, 512, 508, 507, 224, 515, 206, 0, +3, 508, 512, 513, 515, 224, 2, 0, +3, 513, 509, 508, 2, 527, 515, 0, +3, 449, 453, 514, 72, 139, 418, 0, +3, 514, 510, 449, 418, 423, 72, 0, +3, 510, 514, 515, 423, 418, 341, 0, +3, 515, 511, 510, 341, 352, 423, 0, +3, 511, 515, 516, 352, 341, 359, 0, +3, 516, 512, 511, 359, 224, 352, 0, +3, 512, 516, 517, 224, 359, 360, 0, +3, 517, 513, 512, 360, 2, 224, 0, +3, 453, 457, 518, 139, 57, 24, 0, +3, 518, 514, 453, 24, 418, 139, 0, +3, 514, 518, 519, 418, 24, 25, 0, +3, 519, 515, 514, 25, 341, 418, 0, +3, 515, 519, 520, 341, 25, 41, 0, +3, 520, 516, 515, 41, 359, 341, 0, +3, 516, 520, 521, 359, 41, 314, 0, +3, 521, 517, 516, 314, 360, 359, 0, +3, 457, 461, 522, 57, 264, 120, 0, +3, 522, 518, 457, 120, 24, 57, 0, +3, 518, 522, 523, 24, 120, 223, 0, +3, 523, 519, 518, 223, 25, 24, 0, +3, 519, 523, 524, 25, 223, 171, 0, +3, 524, 520, 519, 171, 41, 25, 0, +3, 520, 524, 525, 41, 171, 514, 0, +3, 525, 521, 520, 514, 314, 41, 0, +3, 461, 465, 526, 264, 526, 316, 0, +3, 526, 522, 461, 316, 120, 264, 0, +3, 522, 526, 527, 120, 316, 85, 0, +3, 527, 523, 522, 85, 223, 120, 0, +3, 523, 527, 528, 223, 85, 50, 0, +3, 528, 524, 523, 50, 171, 223, 0, +3, 524, 528, 529, 171, 50, 454, 0, +3, 529, 525, 524, 454, 514, 171, 0, +3, 465, 405, 466, 526, 75, 226, 0, +3, 466, 526, 465, 226, 316, 526, 0, +3, 526, 466, 467, 316, 226, 98, 0, +3, 467, 527, 526, 98, 85, 316, 0, +3, 527, 467, 468, 85, 98, 43, 0, +3, 468, 528, 527, 43, 50, 85, 0, +3, 528, 468, 469, 50, 43, 372, 0, +3, 469, 529, 528, 372, 454, 50, 0 +}; + + +const int strip_vertices[] = { +508, 508, 504, 509, 504, 505, 500, 501, 496, 497, 492, 493, 488, 489, 484, 485, 480, 481, 476, 477, 472, 473, -1, +476, 475, 480, 479, 484, 483, 488, 487, 492, 491, 496, 495, 500, 499, 504, 499, 503, 498, 502, 437, 441, -1, +527, 526, 467, 466, 471, 470, 475, 474, 479, 478, 483, 482, 487, 486, 491, 490, 495, 494, 499, 494, 498, -1, +490, 490, 425, 486, 421, 482, 417, 478, 413, 474, 409, 470, 405, 466, 465, 526, 465, 461, 460, 456, 455, 451, -1, +405, 465, 464, 460, 459, 455, 454, 450, -1, +455, 451, 450, 446, 450, 401, 454, 458, 459, 463, 464, 404, 405, 404, 409, 408, 413, 412, 417, 416, 421, 420, -1, +421, 420, 425, 420, 424, 419, 423, 418, 422, 418, 401, 414, 410, 415, 411, 416, 411, 412, 407, 408, 403, 404, 403, 463, -1, +418, 418, 414, 419, 415, 420, 416, -1, +407, 403, 402, 462, -1, +403, 463, 462, 458, 462, 401, 402, 406, 407, 406, 411, 406, 410, 401, -1, +494, 494, 498, 433, 437, 432, 436, 431, 435, 430, 434, 430, 401, 426, 422, 427, 423, 428, 424, 429, 425, 490, -1, +430, 430, 426, 431, 427, 432, 428, 433, 429, 494, 490, -1, +437, 437, 441, 436, 440, 435, 439, 434, 438, 401, 442, 446, 447, 451, 452, 456, 457, 461, 522, 526, 527, -1, +452, 448, 447, -1, +510, 445, 449, 444, 448, 443, 447, 443, 442, 443, 438, 443, 439, 444, 440, 445, 441, 506, 502, 507, 503, -1, +510, 506, 445, -1, +507, 506, 511, 510, 515, 510, 514, 449, 453, 448, 453, 452, 457, -1, +527, 523, 522, 518, 457, 518, 453, 518, 514, 519, 515, -1, +523, 519, 518, -1, +504, 503, 508, 507, 512, 511, 516, 515, 520, 519, 524, 523, 528, 527, 468, 467, 472, 471, 476, 475, -1, +472, 473, 468, 469, 528, 529, 524, 525, 520, 521, 516, 517, 512, 513, 508, 509, -1, +211, 211, 214, 210, 209, -1, +212, 215, 216, 219, 220, 223, 220, 211, 217, 214, 213, 209, 213, 208, 212, 147, -1, +220, 217, 216, 213, 212, -1, +251, 251, 248, 252, 249, 253, 250, 253, 211, 256, 210, 255, 209, 254, 208, 207, 147, 206, 147, 146, 147, 151, 212, 215, -1, +206, 206, 202, 207, 203, 254, 251, 255, 252, 256, 253, -1, +223, 223, 222, 219, 218, 215, 155, 151, 150, 146, 145, 146, 205, 206, 201, 202, 197, 202, 198, 203, 199, 251, 248, -1, +145, 149, 150, 154, 155, 159, 218, 221, 222, 225, 226, 229, -1, +204, 204, 145, 144, 149, 148, 149, 153, 154, 158, 159, 163, 221, 224, 225, 228, 229, 232, 229, 211, 226, 223, 222, -1, +224, 224, 167, 163, 162, 158, 157, 153, 152, 148, 87, 148, 83, 144, 143, 204, 139, 200, 135, 196, 131, 192, -1, +82, 83, 142, 143, 138, 139, 134, 135, 130, 131, 126, 127, 122, 123, 118, 123, 119, 184, 180, 185, 181, -1, +81, 82, 141, 142, 137, 138, 133, 134, 129, 130, 125, 126, 121, 122, 117, 118, 113, 114, 109, 110, -1, +80, 81, 140, 141, 136, 137, 132, 133, 128, 129, 124, 125, 120, 121, 116, 117, 112, 113, 108, 109, -1, +4, 80, 79, 140, 74, 136, 69, 132, 64, 128, 59, 124, 54, 120, 49, 116, 44, 112, 39, 108, -1, +79, 79, 73, 74, 68, 69, 63, 64, 58, 59, 53, 54, 48, 49, 48, 43, 42, 37, 36, 31, 30, 31, 25, -1, +42, 42, 48, 47, 53, 52, 58, 57, 63, 62, 68, 67, 73, 72, 78, 77, 3, 2, 8, 7, 13, -1, +36, 36, 42, 41, 47, 46, 52, 51, 57, 56, 62, 61, 67, 66, 72, 71, 77, 76, 2, 1, 7, -1, +66, 66, 60, 61, 55, 56, 50, 51, 45, 46, 40, 41, 35, 36, 30, -1, +31, 31, 25, 26, 20, 21, 15, 16, 10, 11, 5, 6, 0, 1, 75, 76, 70, 71, 65, 66, 60, -1, +1, 1, 7, 6, 12, 11, 17, 16, 22, 21, 27, 26, 32, 31, 32, 37, 38, 43, 44, 49, -1, +7, 7, 13, 12, 18, 17, 23, 22, 28, 27, 33, 32, 33, 38, -1, +44, 44, 38, 39, 33, 34, 28, 29, 23, 24, 18, 19, 13, 14, 8, 9, 3, 4, 78, 79, 73, -1, +39, 108, 34, 104, 29, 100, 24, 96, 19, 92, 14, 88, 9, 84, 4, 84, 80, 85, 81, 86, 81, 82, -1, +108, 109, 104, 105, 100, 101, 96, 97, 92, 93, 88, 89, 84, 85, -1, +109, 110, 105, 106, 101, 102, 97, 98, 93, 94, 89, 90, 85, 86, -1, +118, 119, 114, 115, 110, 111, 106, 107, 102, 103, 98, 99, 94, 95, 90, 91, 86, 87, 82, 83, -1, +111, 115, 176, -1, +107, 111, 172, 176, 177, -1, +103, 107, 168, 172, 173, 177, 178, -1, +99, 103, 164, 168, 169, 173, 174, 178, 179, -1, +95, 99, 160, 164, 165, 169, 170, 174, 175, 179, 233, -1, +91, 95, 156, 160, 161, 165, 166, 170, 171, 175, 230, 233, 234, -1, +87, 91, 152, 156, 157, 161, 162, 166, 167, 171, 227, 230, 231, 234, 235, 234, 238, 234, 237, 233, 236, 179, -1, +185, 185, 181, 186, 182, 187, 183, 239, 236, 240, 237, 241, 238, 211, 235, 232, 231, 228, 227, 224, 167, -1, +236, 179, 183, 178, 182, 177, 181, 176, 180, 115, 119, -1, +131, 192, 127, 188, 123, 188, 184, 189, 185, 190, 186, 191, 187, 242, 239, 243, 240, 244, 241, 244, 211, 247, -1, +192, 192, 188, 193, 189, 194, 190, 195, 191, 245, 242, 246, 243, 247, 244, -1, +211, 247, 250, 246, 249, 245, 248, 195, 199, 194, 198, 193, 197, 192, 197, 196, 201, 200, 205, 204, 145, -1, +393, 393, 394, 398, 399, 371, -1, +399, 395, 394, -1, +363, 363, 393, 397, 398, 370, 371, 375, -1, +379, 375, 374, 370, 369, 397, 368, 363, 362, -1, +396, 395, 400, 399, 372, 371, 376, 375, 380, 379, 384, 383, 388, 387, 392, 391, 396, 391, 395, 390, 394, -1, +374, 378, 379, 378, 383, 382, 387, 386, 391, 386, 390, 385, 389, 353, 358, 352, 357, 351, 356, 350, 355, -1, +341, 341, 347, 346, 352, 346, 351, 345, 350, -1, +335, 334, 340, 339, 345, 344, 350, 349, 355, 354, -1, +390, 390, 394, 389, 393, 358, 363, 357, 362, 356, 361, 355, 360, 354, 360, 359, 365, 364, 330, 329, 335, 334, -1, +345, 346, 340, 341, 335, 336, 330, 331, 365, 366, 360, 366, 361, 367, 362, 367, 368, 333, 369, 373, 374, 378, -1, +353, 353, 348, 385, 381, 386, 381, 382, 377, 378, 377, 373, 338, 333, 332, 367, 332, 366, 332, 331, 337, 336, 342, 341, 347, -1, +332, 337, 338, 343, 377, 343, 381, 343, 348, 342, 348, 347, 353, 352, -1, +337, 342, 343, -1, +314, 314, 319, 318, 323, 322, 323, 327, -1, +309, 309, 314, 313, 318, 317, 322, 321, 322, 326, 327, 299, -1, +271, 271, 309, 276, 313, 281, 317, 286, 321, 291, 321, 325, 326, 298, 299, 303, -1, +265, 265, 271, 270, 276, 275, 281, 280, 286, 285, 291, 290, 291, 296, 325, 297, 298, 302, 303, 307, -1, +259, 259, 265, 264, 270, 269, 275, 274, 280, 279, 285, 284, 290, 289, 290, 295, 296, 261, 297, 301, 302, 306, 307, 311, -1, +293, 293, 259, 258, 264, 263, 269, 268, 274, 273, 279, 278, 284, 283, 289, 288, 289, 294, 295, 260, 261, 266, -1, +309, 305, 271, 266, 265, 260, 259, 294, 293, 288, 287, 288, 282, 283, 277, 278, 272, 273, 267, 268, 262, -1, +268, 268, 262, 263, 257, 258, 292, 293, 287, -1, +261, 266, 301, 305, 306, 310, 311, 315, 316, 320, -1, +316, 316, 311, 312, 307, 308, 303, 304, 299, 300, 327, 328, 323, 324, 319, 320, 319, 315, 314, 310, 309, 305, -1 +}; + + +const int strip_normals[] = { +515, 515, 492, 527, 492, 67, 307, 358, 19, 433, 150, 493, 16, 289, 339, 88, 489, 277, 258, 271, 232, 345, -1, +258, 469, 489, 80, 339, 324, 16, 8, 150, 200, 19, 64, 307, 374, 492, 374, 132, 203, 256, 59, 498, -1, +85, 316, 98, 226, 406, 519, 469, 227, 80, 157, 324, 153, 8, 6, 200, 99, 64, 291, 374, 291, 203, -1, +99, 99, 39, 6, 412, 153, 351, 157, 121, 227, 241, 519, 75, 226, 526, 316, 526, 264, 389, 178, 51, 82, -1, +75, 526, 86, 389, 387, 51, 70, 107, -1, +51, 82, 107, 212, 107, 235, 70, 442, 387, 253, 86, 443, 75, 443, 241, 202, 121, 281, 351, 436, 412, 376, -1, +412, 376, 39, 376, 158, 361, 21, 90, 52, 90, 235, 479, 263, 36, 196, 436, 196, 281, 306, 202, 119, 443, 119, 253, -1, +90, 90, 479, 361, 36, 376, 436, -1, +306, 119, 40, 450, -1, +119, 253, 450, 442, 450, 235, 40, 189, 306, 189, 196, 189, 263, 235, -1, +291, 291, 203, 506, 59, 65, 169, 229, 96, 432, 302, 432, 235, 424, 52, 373, 21, 375, 158, 249, 39, 99, -1, +432, 432, 424, 229, 373, 65, 375, 506, 249, 291, 99, -1, +59, 59, 498, 169, 460, 96, 30, 302, 452, 235, 525, 212, 299, 82, 391, 178, 57, 264, 120, 316, 85, -1, +391, 166, 299, -1, +423, 388, 72, 9, 166, 456, 299, 456, 525, 456, 452, 456, 30, 9, 460, 388, 498, 487, 256, 206, 132, -1, +423, 487, 388, -1, +206, 487, 352, 423, 341, 423, 418, 72, 139, 166, 139, 391, 57, -1, +85, 223, 120, 24, 57, 24, 139, 24, 418, 25, 341, -1, +223, 25, 24, -1, +492, 132, 515, 206, 224, 352, 359, 341, 41, 25, 171, 223, 50, 85, 43, 98, 232, 406, 258, 469, -1, +232, 345, 43, 372, 50, 454, 171, 514, 41, 314, 359, 360, 224, 2, 515, 527, -1, +393, 393, 0, 216, 349, -1, +486, 215, 327, 91, 177, 254, 177, 393, 512, 0, 231, 349, 231, 279, 486, 246, -1, +177, 512, 327, 231, 486, -1, +462, 462, 144, 76, 179, 464, 298, 464, 393, 128, 216, 113, 349, 500, 279, 101, 246, 7, 246, 395, 246, 384, 486, 215, -1, +7, 7, 195, 101, 444, 500, 462, 113, 76, 128, 464, -1, +254, 254, 285, 91, 149, 215, 83, 384, 325, 395, 520, 395, 315, 7, 143, 195, 129, 195, 461, 444, 475, 462, 144, -1, +520, 308, 325, 415, 83, 297, 149, 504, 285, 162, 278, 446, -1, +403, 403, 520, 276, 308, 404, 308, 272, 415, 416, 297, 317, 504, 125, 162, 60, 446, 110, 446, 393, 278, 254, 285, -1, +125, 125, 459, 317, 334, 416, 137, 272, 47, 404, 511, 404, 1, 276, 54, 403, 45, 370, 490, 210, 29, 184, -1, +336, 1, 251, 54, 164, 45, 463, 490, 378, 29, 453, 147, 222, 218, 301, 218, 242, 310, 130, 528, 34, -1, +26, 336, 148, 251, 269, 164, 419, 463, 293, 378, 420, 453, 333, 222, 208, 301, 294, 56, 127, 228, -1, +131, 26, 371, 148, 284, 269, 311, 419, 95, 293, 350, 420, 377, 333, 474, 208, 396, 294, 357, 127, -1, +116, 131, 273, 371, 480, 284, 104, 311, 257, 95, 348, 350, 447, 377, 313, 474, 322, 396, 28, 357, -1, +273, 273, 183, 480, 347, 104, 53, 257, 181, 348, 124, 447, 428, 313, 428, 435, 11, 270, 193, 305, 69, 305, 386, -1, +11, 11, 428, 409, 124, 382, 181, 161, 53, 481, 347, 408, 183, 319, 151, 422, 448, 4, 165, 134, 394, -1, +193, 193, 11, 495, 409, 44, 382, 385, 161, 478, 481, 320, 408, 37, 319, 524, 422, 328, 4, 465, 134, -1, +37, 37, 431, 320, 136, 478, 513, 385, 27, 44, 467, 495, 115, 193, 69, -1, +305, 305, 386, 20, 174, 182, 401, 211, 248, 106, 295, 309, 255, 465, 483, 328, 191, 524, 135, 37, 431, -1, +465, 465, 134, 309, 102, 106, 427, 211, 507, 182, 410, 20, 503, 305, 503, 270, 445, 435, 322, 313, -1, +134, 134, 394, 102, 455, 427, 5, 507, 23, 410, 405, 503, 405, 445, -1, +322, 322, 445, 28, 405, 138, 23, 485, 5, 234, 455, 74, 394, 180, 165, 49, 448, 116, 151, 273, 183, -1, +28, 357, 138, 268, 485, 287, 234, 81, 74, 78, 180, 103, 49, 220, 116, 220, 131, 476, 26, 38, 26, 336, -1, +357, 127, 268, 252, 287, 398, 81, 274, 78, 154, 103, 62, 220, 476, -1, +127, 228, 252, 141, 398, 440, 274, 363, 154, 190, 62, 488, 476, 38, -1, +301, 242, 56, 517, 228, 33, 141, 18, 440, 466, 363, 304, 190, 417, 488, 484, 38, 511, 336, 1, -1, +33, 517, 260, -1, +18, 33, 390, 260, 497, -1, +466, 18, 353, 390, 290, 497, 126, -1, +304, 466, 187, 353, 123, 290, 522, 126, 501, -1, +417, 304, 458, 187, 117, 123, 168, 522, 87, 501, 261, -1, +484, 417, 430, 458, 343, 117, 438, 168, 426, 87, 482, 261, 329, -1, +511, 484, 47, 430, 137, 343, 334, 438, 459, 426, 439, 482, 92, 329, 192, 329, 267, 329, 491, 261, 219, 501, -1, +528, 528, 34, 145, 46, 356, 105, 472, 219, 48, 491, 247, 267, 393, 192, 110, 92, 60, 439, 125, 459, -1, +219, 501, 105, 126, 46, 497, 34, 260, 130, 517, 242, -1, +29, 184, 147, 156, 218, 156, 310, 402, 528, 146, 145, 17, 356, 411, 472, 364, 48, 441, 247, 441, 393, 509, -1, +184, 184, 156, 63, 402, 354, 146, 335, 17, 239, 411, 13, 364, 509, 441, -1, +393, 509, 298, 13, 179, 239, 144, 335, 475, 354, 461, 63, 129, 184, 129, 210, 143, 370, 315, 403, 520, -1, +296, 296, 160, 133, 344, 330, -1, +344, 323, 160, -1, +159, 159, 296, 275, 133, 22, 330, 523, -1, +198, 523, 77, 22, 286, 275, 437, 159, 499, -1, +280, 323, 108, 344, 338, 330, 259, 523, 366, 198, 381, 240, 283, 10, 368, 243, 280, 243, 323, 35, 160, -1, +77, 471, 198, 471, 240, 250, 10, 303, 243, 303, 35, 230, 282, 362, 163, 73, 318, 292, 93, 477, 262, -1, +413, 413, 326, 399, 73, 399, 292, 100, 477, -1, +122, 355, 414, 61, 100, 55, 477, 508, 262, 365, -1, +35, 35, 160, 282, 296, 163, 159, 318, 499, 93, 505, 262, 340, 365, 340, 140, 68, 510, 518, 3, 122, 355, -1, +100, 399, 414, 413, 122, 111, 518, 213, 68, 167, 340, 167, 505, 245, 499, 245, 437, 346, 286, 79, 77, 471, -1, +362, 362, 221, 230, 516, 303, 516, 250, 207, 471, 207, 79, 521, 346, 468, 245, 468, 167, 468, 213, 473, 111, 204, 413, 326, -1, +468, 473, 521, 217, 207, 217, 516, 217, 221, 204, 221, 326, 362, 73, -1, +473, 204, 217, -1, +94, 94, 185, 529, 429, 209, 429, 176, -1, +379, 379, 94, 199, 529, 367, 209, 172, 209, 66, 176, 496, -1, +312, 312, 379, 238, 199, 15, 367, 332, 172, 197, 172, 451, 66, 84, 496, 186, -1, +266, 266, 312, 392, 238, 201, 15, 14, 332, 457, 197, 383, 197, 225, 451, 502, 84, 265, 186, 205, -1, +236, 236, 266, 214, 392, 71, 201, 188, 14, 173, 457, 400, 383, 380, 383, 342, 225, 109, 502, 175, 265, 97, 205, 118, -1, +152, 152, 236, 337, 214, 58, 71, 369, 188, 434, 173, 114, 400, 288, 380, 42, 380, 397, 342, 32, 109, 331, -1, +379, 170, 312, 331, 266, 32, 236, 397, 152, 42, 194, 42, 407, 288, 142, 114, 12, 434, 233, 369, 244, -1, +369, 369, 244, 58, 425, 337, 321, 152, 194, -1, +109, 331, 175, 170, 97, 300, 118, 421, 31, 89, -1, +31, 31, 118, 237, 205, 449, 186, 470, 496, 494, 176, 155, 429, 112, 185, 89, 185, 421, 94, 300, 379, 170, -1 +}; + +#else /* defined(_WIN32_WCE) */ + +/* + * Original teapot code copyright follows: + */ + +/* + * (c) Copyright 1993, Silicon Graphics, Inc. + * + * ALL RIGHTS RESERVED + * + * Permission to use, copy, modify, and distribute this software + * for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that + * both the copyright notice and this permission notice appear in + * supporting documentation, and that the name of Silicon + * Graphics, Inc. not be used in advertising or publicity + * pertaining to distribution of the software without specific, + * written prior permission. + * + * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU + * "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR + * OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. IN NO + * EVENT SHALL SILICON GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE + * ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER, + * INCLUDING WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE, + * SAVINGS OR REVENUE, OR THE CLAIMS OF THIRD PARTIES, WHETHER OR + * NOT SILICON GRAPHICS, INC. HAS BEEN ADVISED OF THE POSSIBILITY + * OF SUCH LOSS, HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * ARISING OUT OF OR IN CONNECTION WITH THE POSSESSION, USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * US Government Users Restricted Rights + * + * Use, duplication, or disclosure by the Government is subject to + * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph + * (c)(1)(ii) of the Rights in Technical Data and Computer + * Software clause at DFARS 252.227-7013 and/or in similar or + * successor clauses in the FAR or the DOD or NASA FAR + * Supplement. Unpublished-- rights reserved under the copyright + * laws of the United States. Contractor/manufacturer is Silicon + * Graphics, Inc., 2011 N. Shoreline Blvd., Mountain View, CA + * 94039-7311. + * + * OpenGL(TM) is a trademark of Silicon Graphics, Inc. + */ + +/* + * Rim, body, lid, and bottom data must be reflected in x and y; + * handle and spout data across the y axis only. + */ +static int patchdata[][16] = +{ + { 102, 103, 104, 105, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, /* rim */ + { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27 }, /* body */ + { 24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 }, + { 96, 96, 96, 96, 97, 98, 99, 100, 101, 101, 101, 101, 0, 1, 2, 3 }, /* lid */ + { 0, 1, 2, 3, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117 }, + { 118, 118, 118, 118, 124, 122, 119, 121, 123, 126, 125, 120, 40, 39, 38, 37 }, /* bottom */ + { 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56 }, /* handle */ + { 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 28, 65, 66, 67 }, + { 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83 }, /* spout */ + { 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95 } +}; + +static double cpdata[][3] = +{ + {0.2, 0, 2.7}, {0.2, -0.112, 2.7}, {0.112, -0.2, 2.7}, {0, + -0.2, 2.7}, {1.3375, 0, 2.53125}, {1.3375, -0.749, 2.53125}, + {0.749, -1.3375, 2.53125}, {0, -1.3375, 2.53125}, {1.4375, + 0, 2.53125}, {1.4375, -0.805, 2.53125}, {0.805, -1.4375, + 2.53125}, {0, -1.4375, 2.53125}, {1.5, 0, 2.4}, {1.5, -0.84, + 2.4}, {0.84, -1.5, 2.4}, {0, -1.5, 2.4}, {1.75, 0, 1.875}, + {1.75, -0.98, 1.875}, {0.98, -1.75, 1.875}, {0, -1.75, + 1.875}, {2, 0, 1.35}, {2, -1.12, 1.35}, {1.12, -2, 1.35}, + {0, -2, 1.35}, {2, 0, 0.9}, {2, -1.12, 0.9}, {1.12, -2, + 0.9}, {0, -2, 0.9}, {-2, 0, 0.9}, {2, 0, 0.45}, {2, -1.12, + 0.45}, {1.12, -2, 0.45}, {0, -2, 0.45}, {1.5, 0, 0.225}, + {1.5, -0.84, 0.225}, {0.84, -1.5, 0.225}, {0, -1.5, 0.225}, + {1.5, 0, 0.15}, {1.5, -0.84, 0.15}, {0.84, -1.5, 0.15}, {0, + -1.5, 0.15}, {-1.6, 0, 2.025}, {-1.6, -0.3, 2.025}, {-1.5, + -0.3, 2.25}, {-1.5, 0, 2.25}, {-2.3, 0, 2.025}, {-2.3, -0.3, + 2.025}, {-2.5, -0.3, 2.25}, {-2.5, 0, 2.25}, {-2.7, 0, + 2.025}, {-2.7, -0.3, 2.025}, {-3, -0.3, 2.25}, {-3, 0, + 2.25}, {-2.7, 0, 1.8}, {-2.7, -0.3, 1.8}, {-3, -0.3, 1.8}, + {-3, 0, 1.8}, {-2.7, 0, 1.575}, {-2.7, -0.3, 1.575}, {-3, + -0.3, 1.35}, {-3, 0, 1.35}, {-2.5, 0, 1.125}, {-2.5, -0.3, + 1.125}, {-2.65, -0.3, 0.9375}, {-2.65, 0, 0.9375}, {-2, + -0.3, 0.9}, {-1.9, -0.3, 0.6}, {-1.9, 0, 0.6}, {1.7, 0, + 1.425}, {1.7, -0.66, 1.425}, {1.7, -0.66, 0.6}, {1.7, 0, + 0.6}, {2.6, 0, 1.425}, {2.6, -0.66, 1.425}, {3.1, -0.66, + 0.825}, {3.1, 0, 0.825}, {2.3, 0, 2.1}, {2.3, -0.25, 2.1}, + {2.4, -0.25, 2.025}, {2.4, 0, 2.025}, {2.7, 0, 2.4}, {2.7, + -0.25, 2.4}, {3.3, -0.25, 2.4}, {3.3, 0, 2.4}, {2.8, 0, + 2.475}, {2.8, -0.25, 2.475}, {3.525, -0.25, 2.49375}, + {3.525, 0, 2.49375}, {2.9, 0, 2.475}, {2.9, -0.15, 2.475}, + {3.45, -0.15, 2.5125}, {3.45, 0, 2.5125}, {2.8, 0, 2.4}, + {2.8, -0.15, 2.4}, {3.2, -0.15, 2.4}, {3.2, 0, 2.4}, {0, 0, + 3.15}, {0.8, 0, 3.15}, {0.8, -0.45, 3.15}, {0.45, -0.8, + 3.15}, {0, -0.8, 3.15}, {0, 0, 2.85}, {1.4, 0, 2.4}, {1.4, + -0.784, 2.4}, {0.784, -1.4, 2.4}, {0, -1.4, 2.4}, {0.4, 0, + 2.55}, {0.4, -0.224, 2.55}, {0.224, -0.4, 2.55}, {0, -0.4, + 2.55}, {1.3, 0, 2.55}, {1.3, -0.728, 2.55}, {0.728, -1.3, + 2.55}, {0, -1.3, 2.55}, {1.3, 0, 2.4}, {1.3, -0.728, 2.4}, + {0.728, -1.3, 2.4}, {0, -1.3, 2.4}, {0, 0, 0}, {1.425, + -0.798, 0}, {1.5, 0, 0.075}, {1.425, 0, 0}, {0.798, -1.425, + 0}, {0, -1.5, 0.075}, {0, -1.425, 0}, {1.5, -0.84, 0.075}, + {0.84, -1.5, 0.075} +}; + +static double tex[2][2][2] = +{ + { {0.0, 0.0}, {1.0, 0.0} }, + { {0.0, 1.0}, {1.0, 1.0} } +}; +#endif /* defined(_WIN32_WCE) */ + + +#endif /* FREEGLUT_TEAPOT_DATA_H */ + diff --git a/tests/box2d/freeglut/freeglut_videoresize.c b/tests/box2d/freeglut/freeglut_videoresize.c new file mode 100755 index 00000000..2b27ddeb --- /dev/null +++ b/tests/box2d/freeglut/freeglut_videoresize.c @@ -0,0 +1,50 @@ +/* + * freeglut_videoresize.c + * + * Video resize functions (as defined by GLUT API) + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, <olszta@sourceforge.net> + * Creation date: Thu Dec 16 1999 + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "freeglut.h" +#include "freeglut_internal.h" + +/* + * NOTE: functions declared in this file probably will not be implemented. + */ + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +int FGAPIENTRY glutVideoResizeGet( GLenum eWhat ) { return( 0x00 ); } +void FGAPIENTRY glutSetupVideoResizing( void ) { /* Not implemented */ } +void FGAPIENTRY glutStopVideoResizing( void ) { /* Not implemented */ } +void FGAPIENTRY glutVideoResize( int x, int y, int w, int h ) { /* Not implemented */ } +void FGAPIENTRY glutVideoPan( int x, int y, int w, int h ) { /* Not implemented */ } + +/*** END OF FILE ***/ + + + + + + + diff --git a/tests/box2d/freeglut/freeglut_window.c b/tests/box2d/freeglut/freeglut_window.c new file mode 100755 index 00000000..176487e7 --- /dev/null +++ b/tests/box2d/freeglut/freeglut_window.c @@ -0,0 +1,1743 @@ +/* + * freeglut_window.c + * + * Window management methods. + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, <olszta@sourceforge.net> + * Creation date: Fri Dec 3 1999 + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#define FREEGLUT_BUILDING_LIB +#include "freeglut.h" +#include "freeglut_internal.h" + +#if TARGET_HOST_POSIX_X11 +#include <limits.h> /* LONG_MAX */ +#endif + +#if defined(_WIN32_WCE) +# include <Aygshell.h> +# ifdef FREEGLUT_LIB_PRAGMAS +# pragma comment( lib, "Aygshell.lib" ) +# endif + +static wchar_t* fghWstrFromStr(const char* str) +{ + int i,len=strlen(str); + wchar_t* wstr = (wchar_t*)malloc(2*len+2); + for(i=0; i<len; i++) + wstr[i] = str[i]; + wstr[len] = 0; + return wstr; +} + +#endif /* defined(_WIN32_WCE) */ + +/* pushing attribute/value pairs into an array */ +#define ATTRIB(a) attributes[where++]=(a) +#define ATTRIB_VAL(a,v) {ATTRIB(a); ATTRIB(v);} + +/* + * TODO BEFORE THE STABLE RELEASE: + * + * fgChooseFBConfig() -- OK, but what about glutInitDisplayString()? + * fgSetupPixelFormat -- ignores the display mode settings + * fgOpenWindow() -- check the Win32 version, -iconic handling! + * fgCloseWindow() -- check the Win32 version + * glutCreateWindow() -- Check when default position and size is {-1,-1} + * glutCreateSubWindow() -- Check when default position and size is {-1,-1} + * glutDestroyWindow() -- check the Win32 version + * glutSetWindow() -- check the Win32 version + * glutGetWindow() -- OK + * glutSetWindowTitle() -- check the Win32 version + * glutSetIconTitle() -- check the Win32 version + * glutShowWindow() -- check the Win32 version + * glutHideWindow() -- check the Win32 version + * glutIconifyWindow() -- check the Win32 version + * glutReshapeWindow() -- check the Win32 version + * glutPositionWindow() -- check the Win32 version + * glutPushWindow() -- check the Win32 version + * glutPopWindow() -- check the Win32 version + */ + +/* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ + +static int fghIsLegacyContextVersionRequested( void ) +{ + return fgState.MajorVersion == 1 && fgState.MinorVersion == 0; +} + +static int fghIsLegacyContextRequested( void ) +{ + return fghIsLegacyContextVersionRequested() && + fgState.ContextFlags == 0 && + fgState.ContextProfile == 0; +} + +static int fghNumberOfAuxBuffersRequested( void ) +{ + if ( fgState.DisplayMode & GLUT_AUX4 ) { + return 4; + } + if ( fgState.DisplayMode & GLUT_AUX3 ) { + return 3; + } + if ( fgState.DisplayMode & GLUT_AUX2 ) { + return 2; + } + if ( fgState.DisplayMode & GLUT_AUX1 ) { /* NOTE: Same as GLUT_AUX! */ + return fgState.AuxiliaryBufferNumber; + } + return 0; +} + +static int fghMapBit( int mask, int from, int to ) +{ + return ( mask & from ) ? to : 0; + +} + +static void fghContextCreationError( void ) +{ + fgError( "Unable to create OpenGL %d.%d context (flags %x, profile %x)", + fgState.MajorVersion, fgState.MinorVersion, fgState.ContextFlags, + fgState.ContextProfile ); +} + +/* + * Chooses a visual basing on the current display mode settings + */ +#if TARGET_HOST_POSIX_X11 + +#ifndef GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB +#define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20B2 +#endif + +GLXFBConfig* fgChooseFBConfig( void ) +{ + GLboolean wantIndexedMode = GL_FALSE; + int attributes[ 100 ]; + int where = 0, numAuxBuffers; + + /* First we have to process the display mode settings... */ + if( fgState.DisplayMode & GLUT_INDEX ) { + ATTRIB_VAL( GLX_BUFFER_SIZE, 8 ); + /* Buffer size is selected later. */ + + ATTRIB_VAL( GLX_RENDER_TYPE, GLX_COLOR_INDEX_BIT ); + wantIndexedMode = GL_TRUE; + } else { + ATTRIB_VAL( GLX_RED_SIZE, 1 ); + ATTRIB_VAL( GLX_GREEN_SIZE, 1 ); + ATTRIB_VAL( GLX_BLUE_SIZE, 1 ); + if( fgState.DisplayMode & GLUT_ALPHA ) { + ATTRIB_VAL( GLX_ALPHA_SIZE, 1 ); + } + } + + if( fgState.DisplayMode & GLUT_DOUBLE ) { + ATTRIB_VAL( GLX_DOUBLEBUFFER, True ); + } + + if( fgState.DisplayMode & GLUT_STEREO ) { + ATTRIB_VAL( GLX_STEREO, True ); + } + + if( fgState.DisplayMode & GLUT_DEPTH ) { + ATTRIB_VAL( GLX_DEPTH_SIZE, 1 ); + } + + if( fgState.DisplayMode & GLUT_STENCIL ) { + ATTRIB_VAL( GLX_STENCIL_SIZE, 1 ); + } + + if( fgState.DisplayMode & GLUT_ACCUM ) { + ATTRIB_VAL( GLX_ACCUM_RED_SIZE, 1 ); + ATTRIB_VAL( GLX_ACCUM_GREEN_SIZE, 1 ); + ATTRIB_VAL( GLX_ACCUM_BLUE_SIZE, 1 ); + if( fgState.DisplayMode & GLUT_ALPHA ) { + ATTRIB_VAL( GLX_ACCUM_ALPHA_SIZE, 1 ); + } + } + + numAuxBuffers = fghNumberOfAuxBuffersRequested(); + if ( numAuxBuffers > 0 ) { + ATTRIB_VAL( GLX_AUX_BUFFERS, numAuxBuffers ); + } + + if( fgState.DisplayMode & GLUT_SRGB ) { + ATTRIB_VAL( GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, True ); + } + + if (fgState.DisplayMode & GLUT_MULTISAMPLE) { + ATTRIB_VAL(GLX_SAMPLE_BUFFERS, 1); + ATTRIB_VAL(GLX_SAMPLES, fgState.SampleNumber); + } + + /* Push a terminator at the end of the list */ + ATTRIB( None ); + + { + GLXFBConfig * fbconfigArray; /* Array of FBConfigs */ + GLXFBConfig * fbconfig; /* The FBConfig we want */ + int fbconfigArraySize; /* Number of FBConfigs in the array */ + + + /* Get all FBConfigs that match "attributes". */ + fbconfigArray = glXChooseFBConfig( fgDisplay.Display, + fgDisplay.Screen, + attributes, + &fbconfigArraySize ); + + if (fbconfigArray != NULL) + { + int result; /* Returned by glXGetFBConfigAttrib, not checked. */ + + + if( wantIndexedMode ) + { + /* + * In index mode, we want the largest buffer size, i.e. visual + * depth. Here, FBConfigs are sorted by increasing buffer size + * first, so FBConfigs with the largest size come last. + */ + + int bufferSizeMin, bufferSizeMax; + + /* Get bufferSizeMin. */ + result = + glXGetFBConfigAttrib( fgDisplay.Display, + fbconfigArray[0], + GLX_BUFFER_SIZE, + &bufferSizeMin ); + /* Get bufferSizeMax. */ + result = + glXGetFBConfigAttrib( fgDisplay.Display, + fbconfigArray[fbconfigArraySize - 1], + GLX_BUFFER_SIZE, + &bufferSizeMax ); + + if (bufferSizeMax > bufferSizeMin) + { + /* + * Free and reallocate fbconfigArray, keeping only FBConfigs + * with the largest buffer size. + */ + XFree(fbconfigArray); + + /* Add buffer size token at the end of the list. */ + where--; + ATTRIB_VAL( GLX_BUFFER_SIZE, bufferSizeMax ); + ATTRIB( None ); + + fbconfigArray = glXChooseFBConfig( fgDisplay.Display, + fgDisplay.Screen, + attributes, + &fbconfigArraySize ); + } + } + + /* + * We now have an array of FBConfigs, the first one being the "best" + * one. So we should return only this FBConfig: + * + * int fbconfigXID; + * + * - pick the XID of the FBConfig we want + * result = glXGetFBConfigAttrib( fgDisplay.Display, + * fbconfigArray[0], + * GLX_FBCONFIG_ID, + * &fbconfigXID ); + * + * - free the array + * XFree(fbconfigArray); + * + * - reset "attributes" with the XID + * where = 0; + * ATTRIB_VAL( GLX_FBCONFIG_ID, fbconfigXID ); + * ATTRIB( None ); + * + * - get our FBConfig only + * fbconfig = glXChooseFBConfig( fgDisplay.Display, + * fgDisplay.Screen, + * attributes, + * &fbconfigArraySize ); + * + * However, for some configurations (for instance multisampling with + * Mesa 6.5.2 and ATI drivers), this does not work: + * glXChooseFBConfig returns NULL, whereas fbconfigXID is a valid + * XID. Further investigation is needed. + * + * So, for now, we return the whole array of FBConfigs. This should + * not produce any side effects elsewhere. + */ + fbconfig = fbconfigArray; + } + else + { + fbconfig = NULL; + } + + return fbconfig; + } +} +#endif /* TARGET_HOST_POSIX_X11 */ + +/* + * Setup the pixel format for a Win32 window + */ +#if TARGET_HOST_MS_WINDOWS +/* The following include file is available from SGI but is not standard: + * #include <GL/wglext.h> + * So we copy the necessary parts out of it. + * XXX: should local definitions for extensions be put in a separate include file? + */ +typedef const char * (WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC) (HDC hdc); + +typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); + +#define WGL_DRAW_TO_WINDOW_ARB 0x2001 +#define WGL_ACCELERATION_ARB 0x2003 +#define WGL_SUPPORT_OPENGL_ARB 0x2010 +#define WGL_DOUBLE_BUFFER_ARB 0x2011 +#define WGL_COLOR_BITS_ARB 0x2014 +#define WGL_ALPHA_BITS_ARB 0x201B +#define WGL_DEPTH_BITS_ARB 0x2022 +#define WGL_STENCIL_BITS_ARB 0x2023 +#define WGL_FULL_ACCELERATION_ARB 0x2027 + +#define WGL_SAMPLE_BUFFERS_ARB 0x2041 +#define WGL_SAMPLES_ARB 0x2042 + +#define WGL_TYPE_RGBA_FLOAT_ARB 0x21A0 + +#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9 + +#ifndef WGL_ARB_create_context +#define WGL_ARB_create_context 1 +#ifdef WGL_WGLEXT_PROTOTYPES +extern HGLRC WINAPI wglCreateContextAttribsARB (HDC, HGLRC, const int *); +#endif /* WGL_WGLEXT_PROTOTYPES */ +typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, HGLRC hShareContext, const int *attribList); + +#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093 +#define WGL_CONTEXT_FLAGS_ARB 0x2094 +#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 + +#define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001 +#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 + +#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 + +#define ERROR_INVALID_VERSION_ARB 0x2095 +#define ERROR_INVALID_PROFILE_ARB 0x2096 +#endif + +static void fghFillContextAttributes( int *attributes ) { + int where = 0, contextFlags, contextProfile; + + if ( !fghIsLegacyContextVersionRequested() ) { + ATTRIB_VAL( WGL_CONTEXT_MAJOR_VERSION_ARB, fgState.MajorVersion ); + ATTRIB_VAL( WGL_CONTEXT_MINOR_VERSION_ARB, fgState.MinorVersion ); + } + + contextFlags = + fghMapBit( fgState.ContextFlags, GLUT_DEBUG, WGL_CONTEXT_DEBUG_BIT_ARB ) | + fghMapBit( fgState.ContextFlags, GLUT_FORWARD_COMPATIBLE, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB ); + if ( contextFlags != 0 ) { + ATTRIB_VAL( WGL_CONTEXT_FLAGS_ARB, contextFlags ); + } + + contextProfile = + fghMapBit( fgState.ContextProfile, GLUT_CORE_PROFILE, WGL_CONTEXT_CORE_PROFILE_BIT_ARB ) | + fghMapBit( fgState.ContextProfile, GLUT_COMPATIBILITY_PROFILE, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB ); + if ( contextProfile != 0 ) { + ATTRIB_VAL( WGL_CONTEXT_PROFILE_MASK_ARB, contextProfile ); + } + + ATTRIB( 0 ); +} + +static int fghIsExtensionSupported( HDC hdc, const char *extension ) { + const char *pWglExtString; + PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetEntensionsStringARB = + (PFNWGLGETEXTENSIONSSTRINGARBPROC) wglGetProcAddress("wglGetExtensionsStringARB"); + if ( wglGetEntensionsStringARB == NULL ) + { + return FALSE; + } + pWglExtString = wglGetEntensionsStringARB( hdc ); + return ( pWglExtString != NULL ) && ( strstr(pWglExtString, extension) != NULL ); +} + +void fgNewWGLCreateContext( SFG_Window* window ) +{ + HGLRC context; + int attributes[9]; + PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB; + + /* If nothing fancy has been required, leave the context as it is */ + if ( fghIsLegacyContextRequested() ) + { + return; + } + + wglMakeCurrent( window->Window.Device, window->Window.Context ); + + if ( !fghIsExtensionSupported( window->Window.Device, "WGL_ARB_create_context" ) ) + { + return; + } + + /* new context creation */ + fghFillContextAttributes( attributes ); + + wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) wglGetProcAddress( "wglCreateContextAttribsARB" ); + if ( wglCreateContextAttribsARB == NULL ) + { + fgError( "wglCreateContextAttribsARB not found" ); + } + + context = wglCreateContextAttribsARB( window->Window.Device, 0, attributes ); + if ( context == NULL ) + { + fghContextCreationError(); + } + + wglMakeCurrent( NULL, NULL ); + wglDeleteContext( window->Window.Context ); + window->Window.Context = context; +} + +#if !defined(_WIN32_WCE) + +static void fghFillPFD( PIXELFORMATDESCRIPTOR *ppfd, HDC hdc, unsigned char layer_type ) +{ + int flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL; + if ( fgState.DisplayMode & GLUT_DOUBLE ) { + flags |= PFD_DOUBLEBUFFER; + } + if ( fgState.DisplayMode & GLUT_STEREO ) { + flags |= PFD_STEREO; + } + +//#if defined(_MSC_VER) +//#pragma message( "fgSetupPixelFormat(): there is still some work to do here!" ) +//#endif + + /* Specify which pixel format do we opt for... */ + ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR); + ppfd->nVersion = 1; + ppfd->dwFlags = flags; + + if( fgState.DisplayMode & GLUT_INDEX ) { + ppfd->iPixelType = PFD_TYPE_COLORINDEX; + ppfd->cRedBits = 0; + ppfd->cGreenBits = 0; + ppfd->cBlueBits = 0; + ppfd->cAlphaBits = 0; + } else { + ppfd->iPixelType = PFD_TYPE_RGBA; + ppfd->cRedBits = 8; + ppfd->cGreenBits = 8; + ppfd->cBlueBits = 8; + ppfd->cAlphaBits = ( fgState.DisplayMode & GLUT_ALPHA ) ? 8 : 0; + } + + ppfd->cColorBits = 24; + ppfd->cRedShift = 0; + ppfd->cGreenShift = 0; + ppfd->cBlueShift = 0; + ppfd->cAlphaShift = 0; + ppfd->cAccumBits = 0; + ppfd->cAccumRedBits = 0; + ppfd->cAccumGreenBits = 0; + ppfd->cAccumBlueBits = 0; + ppfd->cAccumAlphaBits = 0; + + /* Hmmm, or 32/0 instead of 24/8? */ + ppfd->cDepthBits = 24; + ppfd->cStencilBits = 8; + + ppfd->cAuxBuffers = fghNumberOfAuxBuffersRequested(); + ppfd->iLayerType = layer_type; + ppfd->bReserved = 0; + ppfd->dwLayerMask = 0; + ppfd->dwVisibleMask = 0; + ppfd->dwDamageMask = 0; + + ppfd->cColorBits = (BYTE) GetDeviceCaps( hdc, BITSPIXEL ); +} + +static void fghFillPixelFormatAttributes( int *attributes, const PIXELFORMATDESCRIPTOR *ppfd ) +{ + int where = 0; + + ATTRIB_VAL( WGL_DRAW_TO_WINDOW_ARB, GL_TRUE ); + ATTRIB_VAL( WGL_SUPPORT_OPENGL_ARB, GL_TRUE ); + ATTRIB_VAL( WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB ); + + ATTRIB_VAL( WGL_COLOR_BITS_ARB, ppfd->cColorBits ); + ATTRIB_VAL( WGL_ALPHA_BITS_ARB, ppfd->cAlphaBits ); + ATTRIB_VAL( WGL_DEPTH_BITS_ARB, ppfd->cDepthBits ); + ATTRIB_VAL( WGL_STENCIL_BITS_ARB, ppfd->cStencilBits ); + + ATTRIB_VAL( WGL_DOUBLE_BUFFER_ARB, ( fgState.DisplayMode & GLUT_DOUBLE ) != 0 ); + + if ( fgState.DisplayMode & GLUT_SRGB ) { + ATTRIB_VAL( WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, TRUE ); + } + + ATTRIB_VAL( WGL_SAMPLE_BUFFERS_ARB, GL_TRUE ); + ATTRIB_VAL( WGL_SAMPLES_ARB, fgState.SampleNumber ); + ATTRIB( 0 ); +} +#endif + +GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly, + unsigned char layer_type ) +{ +#if defined(_WIN32_WCE) + return GL_TRUE; +#else + PIXELFORMATDESCRIPTOR pfd; + PIXELFORMATDESCRIPTOR* ppfd = &pfd; + int pixelformat; + + fghFillPFD( ppfd, window->Window.Device, layer_type ); + pixelformat = ChoosePixelFormat( window->Window.Device, ppfd ); + + /* windows hack for multismapling/sRGB */ + if ( ( fgState.DisplayMode & GLUT_MULTISAMPLE ) || + ( fgState.DisplayMode & GLUT_SRGB ) ) + { + HGLRC rc, rc_before=wglGetCurrentContext(); + HWND hWnd; + HDC hDC, hDC_before=wglGetCurrentDC(); + WNDCLASS wndCls; + + /* create a dummy window */ + ZeroMemory(&wndCls, sizeof(wndCls)); + wndCls.lpfnWndProc = DefWindowProc; + wndCls.hInstance = fgDisplay.Instance; + wndCls.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; + wndCls.lpszClassName = _T("FREEGLUT_dummy"); + RegisterClass( &wndCls ); + + hWnd=CreateWindow(_T("FREEGLUT_dummy"), _T(""), WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW , 0,0,0,0, 0, 0, fgDisplay.Instance, 0 ); + hDC=GetDC(hWnd); + SetPixelFormat( hDC, pixelformat, ppfd ); + + rc = wglCreateContext( hDC ); + wglMakeCurrent(hDC, rc); + + if ( fghIsExtensionSupported( hDC, "WGL_ARB_multisample" ) ) + { + PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARBProc = + (PFNWGLCHOOSEPIXELFORMATARBPROC) wglGetProcAddress("wglChoosePixelFormatARB"); + if ( wglChoosePixelFormatARBProc ) + { + int attributes[100]; + int iPixelFormat; + BOOL bValid; + float fAttributes[] = { 0, 0 }; + UINT numFormats; + fghFillPixelFormatAttributes( attributes, ppfd ); + bValid = wglChoosePixelFormatARBProc(window->Window.Device, attributes, fAttributes, 1, &iPixelFormat, &numFormats); + + if ( bValid && numFormats > 0 ) + { + pixelformat = iPixelFormat; + } + } + } + + wglMakeCurrent( hDC_before, rc_before); + wglDeleteContext(rc); + ReleaseDC(hWnd, hDC); + DestroyWindow(hWnd); + UnregisterClass(_T("FREEGLUT_dummy"), fgDisplay.Instance); + } + + return ( pixelformat != 0 ) && ( checkOnly || SetPixelFormat( window->Window.Device, pixelformat, ppfd ) ); +#endif /* defined(_WIN32_WCE) */ +} +#endif /* TARGET_HOST_MS_WINDOWS */ + +/* + * Sets the OpenGL context and the fgStructure "Current Window" pointer to + * the window structure passed in. + */ +void fgSetWindow ( SFG_Window *window ) +{ +#if TARGET_HOST_POSIX_X11 + if ( window ) + { + glXMakeContextCurrent( + fgDisplay.Display, + window->Window.Handle, + window->Window.Handle, + window->Window.Context + ); + + /* also register this window to receive spaceball events */ + fgSpaceballSetWindow(window); + } +#elif TARGET_HOST_MS_WINDOWS + if( fgStructure.CurrentWindow ) + ReleaseDC( fgStructure.CurrentWindow->Window.Handle, + fgStructure.CurrentWindow->Window.Device ); + + if ( window ) + { + window->Window.Device = GetDC( window->Window.Handle ); + wglMakeCurrent( + window->Window.Device, + window->Window.Context + ); + } +#endif + fgStructure.CurrentWindow = window; +} + + + +#if TARGET_HOST_POSIX_X11 + +#ifndef GLX_CONTEXT_MAJOR_VERSION_ARB +#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#endif + +#ifndef GLX_CONTEXT_MINOR_VERSION_ARB +#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 +#endif + +#ifndef GLX_CONTEXT_FLAGS_ARB +#define GLX_CONTEXT_FLAGS_ARB 0x2094 +#endif + +#ifndef GLX_CONTEXT_PROFILE_MASK_ARB +#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126 +#endif + +#ifndef GLX_CONTEXT_DEBUG_BIT_ARB +#define GLX_CONTEXT_DEBUG_BIT_ARB 0x0001 +#endif + +#ifndef GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB +#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 +#endif + +#ifndef GLX_CONTEXT_CORE_PROFILE_BIT_ARB +#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#endif + +#ifndef GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB +#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +#endif + +#ifndef GLX_RGBA_FLOAT_TYPE +#define GLX_RGBA_FLOAT_TYPE 0x20B9 +#endif + +#ifndef GLX_RGBA_FLOAT_BIT +#define GLX_RGBA_FLOAT_BIT 0x00000004 +#endif + +static void fghFillContextAttributes( int *attributes ) { + int where = 0, contextFlags, contextProfile; + + if ( !fghIsLegacyContextVersionRequested() ) { + ATTRIB_VAL( GLX_CONTEXT_MAJOR_VERSION_ARB, fgState.MajorVersion ); + ATTRIB_VAL( GLX_CONTEXT_MINOR_VERSION_ARB, fgState.MinorVersion ); + } + + contextFlags = + fghMapBit( fgState.ContextFlags, GLUT_DEBUG, GLX_CONTEXT_DEBUG_BIT_ARB ) | + fghMapBit( fgState.ContextFlags, GLUT_FORWARD_COMPATIBLE, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB ); + if ( contextFlags != 0 ) { + ATTRIB_VAL( GLX_CONTEXT_FLAGS_ARB, contextFlags ); + } + + contextProfile = + fghMapBit( fgState.ContextProfile, GLUT_CORE_PROFILE, GLX_CONTEXT_CORE_PROFILE_BIT_ARB ) | + fghMapBit( fgState.ContextProfile, GLUT_COMPATIBILITY_PROFILE, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB ); + if ( contextProfile != 0 ) { + ATTRIB_VAL( GLX_CONTEXT_PROFILE_MASK_ARB, contextProfile ); + } + + ATTRIB( 0 ); +} + +typedef GLXContext (*CreateContextAttribsProc)(Display *dpy, GLXFBConfig config, + GLXContext share_list, Bool direct, + const int *attrib_list); + +static GLXContext fghCreateNewContext( SFG_Window* window ) +{ + /* for color model calculation */ + int menu = ( window->IsMenu && !fgStructure.MenuContext ); + int index_mode = ( fgState.DisplayMode & GLUT_INDEX ); + + /* "classic" context creation */ + Display *dpy = fgDisplay.Display; + GLXFBConfig config = *(window->Window.FBConfig); + int render_type = ( !menu && index_mode ) ? GLX_COLOR_INDEX_TYPE : GLX_RGBA_TYPE; + GLXContext share_list = NULL; + Bool direct = ( fgState.DirectContext != GLUT_FORCE_INDIRECT_CONTEXT ); + GLXContext context; + + /* new context creation */ + int attributes[9]; + CreateContextAttribsProc createContextAttribs; + + /* If nothing fancy has been required, simply use the old context creation GLX API entry */ + if ( fghIsLegacyContextRequested() ) + { + context = glXCreateNewContext( dpy, config, render_type, share_list, direct ); + if ( context == NULL ) { + fghContextCreationError(); + } + return context; + } + + /* color index mode is not available anymore with OpenGL 3.0 */ + if ( render_type == GLX_COLOR_INDEX_TYPE ) { + fgWarning( "color index mode is deprecated, using RGBA mode" ); + } + + fghFillContextAttributes( attributes ); + + createContextAttribs = (CreateContextAttribsProc) fghGetProcAddress( "glXCreateContextAttribsARB" ); + if ( createContextAttribs == NULL ) { + fgError( "glXCreateContextAttribsARB not found" ); + } + + context = createContextAttribs( dpy, config, share_list, direct, attributes ); + if ( context == NULL ) { + fghContextCreationError(); + } + return context; +} +#endif + + +/* + * Opens a window. Requires a SFG_Window object created and attached + * to the freeglut structure. OpenGL context is created here. + */ +void fgOpenWindow( SFG_Window* window, const char* title, + GLboolean positionUse, int x, int y, + GLboolean sizeUse, int w, int h, + GLboolean gameMode, GLboolean isSubWindow ) +{ +#if TARGET_HOST_POSIX_X11 + XVisualInfo * visualInfo; + XSetWindowAttributes winAttr; + XTextProperty textProperty; + XSizeHints sizeHints; + XWMHints wmHints; + unsigned long mask; + unsigned int current_DisplayMode = fgState.DisplayMode ; + + /* Save the display mode if we are creating a menu window */ + if( window->IsMenu && ( ! fgStructure.MenuContext ) ) + fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB ; + + window->Window.FBConfig = fgChooseFBConfig( ); + + if( window->IsMenu && ( ! fgStructure.MenuContext ) ) + fgState.DisplayMode = current_DisplayMode ; + + if( ! window->Window.FBConfig ) + { + /* + * The "fgChooseFBConfig" returned a null meaning that the visual + * context is not available. + * Try a couple of variations to see if they will work. + */ + if( !( fgState.DisplayMode & GLUT_DOUBLE ) ) + { + fgState.DisplayMode |= GLUT_DOUBLE ; + window->Window.FBConfig = fgChooseFBConfig( ); + fgState.DisplayMode &= ~GLUT_DOUBLE; + } + + if( fgState.DisplayMode & GLUT_MULTISAMPLE ) + { + fgState.DisplayMode &= ~GLUT_MULTISAMPLE ; + window->Window.FBConfig = fgChooseFBConfig( ); + fgState.DisplayMode |= GLUT_MULTISAMPLE; + } + } + + FREEGLUT_INTERNAL_ERROR_EXIT( window->Window.FBConfig != NULL, + "FBConfig with necessary capabilities not found", "fgOpenWindow" ); + + /* Get the X visual. */ + visualInfo = glXGetVisualFromFBConfig( fgDisplay.Display, + *(window->Window.FBConfig) ); + + /* + * XXX HINT: the masks should be updated when adding/removing callbacks. + * XXX This might speed up message processing. Is that true? + * XXX + * XXX A: Not appreciably, but it WILL make it easier to debug. + * XXX Try tracing old GLUT and try tracing freeglut. Old GLUT + * XXX turns off events that it doesn't need and is a whole lot + * XXX more pleasant to trace. (Think mouse-motion! Tons of + * XXX ``bonus'' GUI events stream in.) + */ + winAttr.event_mask = + StructureNotifyMask | SubstructureNotifyMask | ExposureMask | + ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | + VisibilityChangeMask | EnterWindowMask | LeaveWindowMask | + PointerMotionMask | ButtonMotionMask; + winAttr.background_pixmap = None; + winAttr.background_pixel = 0; + winAttr.border_pixel = 0; + + winAttr.colormap = XCreateColormap( + fgDisplay.Display, fgDisplay.RootWindow, + visualInfo->visual, AllocNone + ); + + mask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask; + + if( window->IsMenu || ( gameMode == GL_TRUE ) ) + { + winAttr.override_redirect = True; + mask |= CWOverrideRedirect; + } + + if( ! positionUse ) + x = y = -1; /* default window position */ + if( ! sizeUse ) + w = h = 300; /* default window size */ + + window->Window.Handle = XCreateWindow( + fgDisplay.Display, + window->Parent == NULL ? fgDisplay.RootWindow : + window->Parent->Window.Handle, + x, y, w, h, 0, + visualInfo->depth, InputOutput, + visualInfo->visual, mask, + &winAttr + ); + + /* + * The GLX context creation, possibly trying the direct context rendering + * or else use the current context if the user has so specified + */ + + if( window->IsMenu ) + { + /* + * If there isn't already an OpenGL rendering context for menu + * windows, make one + */ + if( !fgStructure.MenuContext ) + { + fgStructure.MenuContext = + (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) ); + fgStructure.MenuContext->MContext = fghCreateNewContext( window ); + } + + /* window->Window.Context = fgStructure.MenuContext->MContext; */ + window->Window.Context = fghCreateNewContext( window ); + } + else if( fgState.UseCurrentContext ) + { + window->Window.Context = glXGetCurrentContext( ); + + if( ! window->Window.Context ) + window->Window.Context = fghCreateNewContext( window ); + } + else + window->Window.Context = fghCreateNewContext( window ); + +#if !defined( __FreeBSD__ ) && !defined( __NetBSD__ ) + if( !glXIsDirect( fgDisplay.Display, window->Window.Context ) ) + { + if( fgState.DirectContext == GLUT_FORCE_DIRECT_CONTEXT ) + fgError( "Unable to force direct context rendering for window '%s'", + title ); + } +#endif + + /* + * XXX Assume the new window is visible by default + * XXX Is this a safe assumption? + */ + window->State.Visible = GL_TRUE; + + sizeHints.flags = 0; + if ( positionUse ) + sizeHints.flags |= USPosition; + if ( sizeUse ) + sizeHints.flags |= USSize; + + /* + * Fill in the size hints values now (the x, y, width and height + * settings are obsolete, are there any more WMs that support them?) + * Unless the X servers actually stop supporting these, we should + * continue to fill them in. It is *not* our place to tell the user + * that they should replace a window manager that they like, and which + * works, just because *we* think that it's not "modern" enough. + */ + sizeHints.x = x; + sizeHints.y = y; + sizeHints.width = w; + sizeHints.height = h; + + wmHints.flags = StateHint; + wmHints.initial_state = fgState.ForceIconic ? IconicState : NormalState; + /* Prepare the window and iconified window names... */ + XStringListToTextProperty( (char **) &title, 1, &textProperty ); + + XSetWMProperties( + fgDisplay.Display, + window->Window.Handle, + &textProperty, + &textProperty, + 0, + 0, + &sizeHints, + &wmHints, + NULL + ); + XFree( textProperty.value ); + + XSetWMProtocols( fgDisplay.Display, window->Window.Handle, + &fgDisplay.DeleteWindow, 1 ); + + glXMakeContextCurrent( + fgDisplay.Display, + window->Window.Handle, + window->Window.Handle, + window->Window.Context + ); + + XMapWindow( fgDisplay.Display, window->Window.Handle ); + + XFree(visualInfo); + +#elif TARGET_HOST_MS_WINDOWS + + WNDCLASS wc; + DWORD flags; + DWORD exFlags = 0; + ATOM atom; + int WindowStyle = 0; + + /* Grab the window class we have registered on glutInit(): */ + atom = GetClassInfo( fgDisplay.Instance, _T("FREEGLUT"), &wc ); + FREEGLUT_INTERNAL_ERROR_EXIT ( atom, "Window Class Info Not Found", + "fgOpenWindow" ); + + if( gameMode ) + { + FREEGLUT_INTERNAL_ERROR_EXIT ( window->Parent == NULL, + "Game mode being invoked on a subwindow", + "fgOpenWindow" ); + + /* + * Set the window creation flags appropriately to make the window + * entirely visible: + */ + flags = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE; + } + else + { + int worig = w, horig = h; + +#if !defined(_WIN32_WCE) + if ( ( ! isSubWindow ) && ( ! window->IsMenu ) ) + { + /* + * Update the window dimensions, taking account of window + * decorations. "freeglut" is to create the window with the + * outside of its border at (x,y) and with dimensions (w,h). + */ + w += (GetSystemMetrics( SM_CXSIZEFRAME ) )*2; + h += (GetSystemMetrics( SM_CYSIZEFRAME ) )*2 + + GetSystemMetrics( SM_CYCAPTION ); + } +#endif /* defined(_WIN32_WCE) */ + + if( ! positionUse ) + { + x = CW_USEDEFAULT; + y = CW_USEDEFAULT; + } + /* setting State.Width/Height to call resize callback later */ + if( ! sizeUse ) + { + if( ! window->IsMenu ) + { + w = CW_USEDEFAULT; + h = CW_USEDEFAULT; + } + else /* fail safe - Windows can make a window of size (0, 0) */ + w = h = 300; /* default window size */ + window->State.Width = window->State.Height = -1; + } + else + { + window->State.Width = worig; + window->State.Height = horig; + } + + /* + * There's a small difference between creating the top, child and + * game mode windows + */ + flags = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE; + + if ( window->IsMenu ) + { + flags |= WS_POPUP; + exFlags |= WS_EX_TOOLWINDOW; + } +#if !defined(_WIN32_WCE) + else if( window->Parent == NULL ) + flags |= WS_OVERLAPPEDWINDOW; +#endif + else + flags |= WS_CHILD; + } + +#if defined(_WIN32_WCE) + { + wchar_t* wstr = fghWstrFromStr(title); + + window->Window.Handle = CreateWindow( + _T("FREEGLUT"), + wstr, + WS_VISIBLE | WS_POPUP, + 0,0, 240,320, + NULL, + NULL, + fgDisplay.Instance, + (LPVOID) window + ); + + free(wstr); + + SHFullScreen(window->Window.Handle, SHFS_HIDESTARTICON); + SHFullScreen(window->Window.Handle, SHFS_HIDESIPBUTTON); + SHFullScreen(window->Window.Handle, SHFS_HIDETASKBAR); + MoveWindow(window->Window.Handle, 0, 0, 240, 320, TRUE); + ShowWindow(window->Window.Handle, SW_SHOW); + UpdateWindow(window->Window.Handle); + } +#else + window->Window.Handle = CreateWindowEx( + exFlags, + _T("FREEGLUT"), + title, + flags, + x, y, w, h, + (HWND) window->Parent == NULL ? NULL : window->Parent->Window.Handle, + (HMENU) NULL, + fgDisplay.Instance, + (LPVOID) window + ); +#endif /* defined(_WIN32_WCE) */ + + if( !( window->Window.Handle ) ) + fgError( "Failed to create a window (%s)!", title ); + + /* Make a menu window always on top - fix Feature Request 947118 */ + if( window->IsMenu || gameMode ) + SetWindowPos( + window->Window.Handle, + HWND_TOPMOST, + 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE + ); + + /* Hack to remove the caption (title bar) and/or border + * and all the system menu controls. + */ + WindowStyle = GetWindowLong(window->Window.Handle, GWL_STYLE); + if ( fgState.DisplayMode & GLUT_CAPTIONLESS ) + { + SetWindowLong ( window->Window.Handle, GWL_STYLE, + WindowStyle & ~(WS_DLGFRAME | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX)); + } + else if ( fgState.DisplayMode & GLUT_BORDERLESS ) + { + SetWindowLong ( window->Window.Handle, GWL_STYLE, + WindowStyle & ~(WS_BORDER | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX)); + } +/* SetWindowPos(window->Window.Handle, NULL, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); */ + + +#if defined(_WIN32_WCE) + ShowWindow( window->Window.Handle, SW_SHOW ); +#else + ShowWindow( window->Window.Handle, + fgState.ForceIconic ? SW_SHOWMINIMIZED : SW_SHOW ); +#endif /* defined(_WIN32_WCE) */ + + UpdateWindow( window->Window.Handle ); + ShowCursor( TRUE ); /* XXX Old comments say "hide cursor"! */ + +#endif + + fgSetWindow( window ); + + window->Window.DoubleBuffered = + ( fgState.DisplayMode & GLUT_DOUBLE ) ? 1 : 0; + + if ( ! window->Window.DoubleBuffered ) + { + glDrawBuffer ( GL_FRONT ); + glReadBuffer ( GL_FRONT ); + } +} + +/* + * Closes a window, destroying the frame and OpenGL context + */ +void fgCloseWindow( SFG_Window* window ) +{ +#if TARGET_HOST_POSIX_X11 + + if( window->Window.Context ) + glXDestroyContext( fgDisplay.Display, window->Window.Context ); + XFree( window->Window.FBConfig ); + XDestroyWindow( fgDisplay.Display, window->Window.Handle ); + /* XFlush( fgDisplay.Display ); */ /* XXX Shouldn't need this */ + +#elif TARGET_HOST_MS_WINDOWS + + /* Make sure we don't close a window with current context active */ + if( fgStructure.CurrentWindow == window ) + wglMakeCurrent( NULL, NULL ); + + /* + * Step through the list of windows. If the rendering context + * is not being used by another window, then we delete it. + */ + { + int used = FALSE ; + SFG_Window *iter ; + + for( iter = (SFG_Window *)fgStructure.Windows.First; + iter; + iter = (SFG_Window *)iter->Node.Next ) + { + if( ( iter->Window.Context == window->Window.Context ) && + ( iter != window ) ) + used = TRUE; + } + + if( ! used ) + wglDeleteContext( window->Window.Context ); + } + + DestroyWindow( window->Window.Handle ); +#endif +} + + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +/* + * Creates a new top-level freeglut window + */ +int FGAPIENTRY glutCreateWindow( const char* title ) +{ + /* XXX GLUT does not exit; it simply calls "glutInit" quietly if the + * XXX application has not already done so. The "freeglut" community + * XXX decided not to go this route (freeglut-developer e-mail from + * XXX Steve Baker, 12/16/04, 4:22 PM CST, "Re: [Freeglut-developer] + * XXX Desired 'freeglut' behaviour when there is no current window" + */ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateWindow" ); + + return fgCreateWindow( NULL, title, fgState.Position.Use, + fgState.Position.X, fgState.Position.Y, + fgState.Size.Use, fgState.Size.X, fgState.Size.Y, + GL_FALSE, GL_FALSE )->ID; +} + +#if TARGET_HOST_MS_WINDOWS +int FGAPIENTRY __glutCreateWindowWithExit( const char *title, void (__cdecl *exit_function)(int) ) +{ + __glutExitFunc = exit_function; + return glutCreateWindow( title ); +} +#endif + +/* + * This function creates a sub window. + */ +int FGAPIENTRY glutCreateSubWindow( int parentID, int x, int y, int w, int h ) +{ + int ret = 0; + SFG_Window* window = NULL; + SFG_Window* parent = NULL; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateSubWindow" ); + parent = fgWindowByID( parentID ); + freeglut_return_val_if_fail( parent != NULL, 0 ); + if ( x < 0 ) + { + x = parent->State.Width + x ; + if ( w >= 0 ) x -= w ; + } + + if ( w < 0 ) w = parent->State.Width - x + w ; + if ( w < 0 ) + { + x += w ; + w = -w ; + } + + if ( y < 0 ) + { + y = parent->State.Height + y ; + if ( h >= 0 ) y -= h ; + } + + if ( h < 0 ) h = parent->State.Height - y + h ; + if ( h < 0 ) + { + y += h ; + h = -h ; + } + + window = fgCreateWindow( parent, "", GL_TRUE, x, y, GL_TRUE, w, h, GL_FALSE, GL_FALSE ); + ret = window->ID; + + return ret; +} + +/* + * Destroys a window and all of its subwindows + */ +void FGAPIENTRY glutDestroyWindow( int windowID ) +{ + SFG_Window* window; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDestroyWindow" ); + window = fgWindowByID( windowID ); + freeglut_return_if_fail( window != NULL ); + { + fgExecutionState ExecState = fgState.ExecState; + fgAddToWindowDestroyList( window ); + fgState.ExecState = ExecState; + } +} + +/* + * This function selects the current window + */ +void FGAPIENTRY glutSetWindow( int ID ) +{ + SFG_Window* window = NULL; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindow" ); + if( fgStructure.CurrentWindow != NULL ) + if( fgStructure.CurrentWindow->ID == ID ) + return; + + window = fgWindowByID( ID ); + if( window == NULL ) + { + fgWarning( "glutSetWindow(): window ID %d not found!", ID ); + return; + } + + fgSetWindow( window ); +} + +/* + * This function returns the ID number of the current window, 0 if none exists + */ +int FGAPIENTRY glutGetWindow( void ) +{ + SFG_Window *win = fgStructure.CurrentWindow; + /* + * Since GLUT did not throw an error if this function was called without a prior call to + * "glutInit", this function shouldn't do so here. Instead let us return a zero. + * See Feature Request "[ 1307049 ] glutInit check". + */ + if ( ! fgState.Initialised ) + return 0; + + while ( win && win->IsMenu ) + win = win->Parent; + return win ? win->ID : 0; +} + +/* + * This function makes the current window visible + */ +void FGAPIENTRY glutShowWindow( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutShowWindow" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutShowWindow" ); + +#if TARGET_HOST_POSIX_X11 + + XMapWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle ); + XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ + +#elif TARGET_HOST_MS_WINDOWS + + ShowWindow( fgStructure.CurrentWindow->Window.Handle, SW_SHOW ); + +#endif + + fgStructure.CurrentWindow->State.Redisplay = GL_TRUE; +} + +/* + * This function hides the current window + */ +void FGAPIENTRY glutHideWindow( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutHideWindow" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutHideWindow" ); + +#if TARGET_HOST_POSIX_X11 + + if( fgStructure.CurrentWindow->Parent == NULL ) + XWithdrawWindow( fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle, + fgDisplay.Screen ); + else + XUnmapWindow( fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle ); + XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ + +#elif TARGET_HOST_MS_WINDOWS + + ShowWindow( fgStructure.CurrentWindow->Window.Handle, SW_HIDE ); + +#endif + + fgStructure.CurrentWindow->State.Redisplay = GL_FALSE; +} + +/* + * Iconify the current window (top-level windows only) + */ +void FGAPIENTRY glutIconifyWindow( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutIconifyWindow" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutIconifyWindow" ); + + fgStructure.CurrentWindow->State.Visible = GL_FALSE; +#if TARGET_HOST_POSIX_X11 + + XIconifyWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle, + fgDisplay.Screen ); + XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ + +#elif TARGET_HOST_MS_WINDOWS + + ShowWindow( fgStructure.CurrentWindow->Window.Handle, SW_MINIMIZE ); + +#endif + + fgStructure.CurrentWindow->State.Redisplay = GL_FALSE; +} + +/* + * Set the current window's title + */ +void FGAPIENTRY glutSetWindowTitle( const char* title ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindowTitle" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetWindowTitle" ); + if( ! fgStructure.CurrentWindow->Parent ) + { +#if TARGET_HOST_POSIX_X11 + + XTextProperty text; + + text.value = (unsigned char *) title; + text.encoding = XA_STRING; + text.format = 8; + text.nitems = strlen( title ); + + XSetWMName( + fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle, + &text + ); + + XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ + +#elif TARGET_HOST_MS_WINDOWS +# ifdef _WIN32_WCE + { + wchar_t* wstr = fghWstrFromStr(title); + SetWindowText( fgStructure.CurrentWindow->Window.Handle, wstr ); + free(wstr); + } +# else + SetWindowText( fgStructure.CurrentWindow->Window.Handle, title ); +# endif + +#endif + } +} + +/* + * Set the current window's iconified title + */ +void FGAPIENTRY glutSetIconTitle( const char* title ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetIconTitle" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetIconTitle" ); + + if( ! fgStructure.CurrentWindow->Parent ) + { +#if TARGET_HOST_POSIX_X11 + + XTextProperty text; + + text.value = (unsigned char *) title; + text.encoding = XA_STRING; + text.format = 8; + text.nitems = strlen( title ); + + XSetWMIconName( + fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle, + &text + ); + + XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ + +#elif TARGET_HOST_MS_WINDOWS +# ifdef _WIN32_WCE + { + wchar_t* wstr = fghWstrFromStr(title); + SetWindowText( fgStructure.CurrentWindow->Window.Handle, wstr ); + free(wstr); + } +# else + SetWindowText( fgStructure.CurrentWindow->Window.Handle, title ); +# endif + +#endif + } +} + +/* + * Change the current window's size + */ +void FGAPIENTRY glutReshapeWindow( int width, int height ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutReshapeWindow" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutReshapeWindow" ); + + if (glutGet(GLUT_FULL_SCREEN)) + { + /* Leave full screen state before resizing. */ + glutFullScreenToggle(); + } + + fgStructure.CurrentWindow->State.NeedToResize = GL_TRUE; + fgStructure.CurrentWindow->State.Width = width ; + fgStructure.CurrentWindow->State.Height = height; +} + +/* + * Change the current window's position + */ +void FGAPIENTRY glutPositionWindow( int x, int y ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPositionWindow" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPositionWindow" ); + + if (glutGet(GLUT_FULL_SCREEN)) + { + /* Leave full screen state before moving. */ + glutFullScreenToggle(); + } + +#if TARGET_HOST_POSIX_X11 + + XMoveWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle, + x, y ); + XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ + +#elif TARGET_HOST_MS_WINDOWS + + { + RECT winRect; + + /* "GetWindowRect" returns the pixel coordinates of the outside of the window */ + GetWindowRect( fgStructure.CurrentWindow->Window.Handle, &winRect ); + MoveWindow( + fgStructure.CurrentWindow->Window.Handle, + x, + y, + winRect.right - winRect.left, + winRect.bottom - winRect.top, + TRUE + ); + } + +#endif +} + +/* + * Lowers the current window (by Z order change) + */ +void FGAPIENTRY glutPushWindow( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPushWindow" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPushWindow" ); + +#if TARGET_HOST_POSIX_X11 + + XLowerWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle ); + +#elif TARGET_HOST_MS_WINDOWS + + SetWindowPos( + fgStructure.CurrentWindow->Window.Handle, + HWND_BOTTOM, + 0, 0, 0, 0, + SWP_NOSIZE | SWP_NOMOVE + ); + +#endif +} + +/* + * Raises the current window (by Z order change) + */ +void FGAPIENTRY glutPopWindow( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPopWindow" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPopWindow" ); + +#if TARGET_HOST_POSIX_X11 + + XRaiseWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle ); + +#elif TARGET_HOST_MS_WINDOWS + + SetWindowPos( + fgStructure.CurrentWindow->Window.Handle, + HWND_TOP, + 0, 0, 0, 0, + SWP_NOSIZE | SWP_NOMOVE + ); + +#endif +} + +#if TARGET_HOST_POSIX_X11 +static int ewmh_fullscr_toggle(void); +static int resize_fullscr_toogle(void); + +static int toggle_fullscreen(void) +{ + /* first try the EWMH (_NET_WM_STATE) method ... */ + if(ewmh_fullscr_toggle() != -1) { + return 0; + } + + /* fall back to resizing the window */ + if(resize_fullscr_toogle() != -1) { + return 0; + } + return -1; +} + +#define _NET_WM_STATE_TOGGLE 2 +static int ewmh_fullscr_toggle(void) +{ + XEvent xev; + long evmask = SubstructureRedirectMask | SubstructureNotifyMask; + + if(!fgDisplay.State || !fgDisplay.StateFullScreen) { + return -1; + } + + xev.type = ClientMessage; + xev.xclient.window = fgStructure.CurrentWindow->Window.Handle; + xev.xclient.message_type = fgDisplay.State; + xev.xclient.format = 32; + xev.xclient.data.l[0] = _NET_WM_STATE_TOGGLE; + xev.xclient.data.l[1] = fgDisplay.StateFullScreen; + xev.xclient.data.l[2] = 0; /* no second property to toggle */ + xev.xclient.data.l[3] = 1; /* source indication: application */ + xev.xclient.data.l[4] = 0; /* unused */ + + if(!XSendEvent(fgDisplay.Display, fgDisplay.RootWindow, 0, evmask, &xev)) { + return -1; + } + return 0; +} + +static int resize_fullscr_toogle(void) +{ + XWindowAttributes attributes; + + if(glutGet(GLUT_FULL_SCREEN)) { + /* restore original window size */ + SFG_Window *win = fgStructure.CurrentWindow; + fgStructure.CurrentWindow->State.NeedToResize = GL_TRUE; + fgStructure.CurrentWindow->State.Width = win->State.OldWidth; + fgStructure.CurrentWindow->State.Height = win->State.OldHeight; + + } else { + /* resize the window to cover the entire screen */ + XGetWindowAttributes(fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle, + &attributes); + + /* + * The "x" and "y" members of "attributes" are the window's coordinates + * relative to its parent, i.e. to the decoration window. + */ + XMoveResizeWindow(fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle, + -attributes.x, + -attributes.y, + fgDisplay.ScreenWidth, + fgDisplay.ScreenHeight); + } + return 0; +} +#endif /* TARGET_HOST_POSIX_X11 */ + + +/* + * Resize the current window so that it fits the whole screen + */ +void FGAPIENTRY glutFullScreen( void ) +{ + SFG_Window *win; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreen" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreen" ); + + win = fgStructure.CurrentWindow; + +#if TARGET_HOST_POSIX_X11 + if(!glutGet(GLUT_FULL_SCREEN)) { + if(toggle_fullscreen() != -1) { + win->State.IsFullscreen = GL_TRUE; + } + } + +#elif TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) /* FIXME: what about WinCE */ + + if (glutGet(GLUT_FULL_SCREEN)) + { + /* Leave full screen state before resizing. */ + glutFullScreenToggle(); + } + + { + RECT rect; + + /* For fullscreen mode, force the top-left corner to 0,0 + * and adjust the window rectangle so that the client area + * covers the whole screen. + */ + + rect.left = 0; + rect.top = 0; + rect.right = fgDisplay.ScreenWidth; + rect.bottom = fgDisplay.ScreenHeight; + + AdjustWindowRect ( &rect, WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | + WS_CLIPCHILDREN, FALSE ); + + /* + * SWP_NOACTIVATE Do not activate the window + * SWP_NOOWNERZORDER Do not change position in z-order + * SWP_NOSENDCHANGING Supress WM_WINDOWPOSCHANGING message + * SWP_NOZORDER Retains the current Z order (ignore 2nd param) + */ + + SetWindowPos( fgStructure.CurrentWindow->Window.Handle, + HWND_TOP, + rect.left, + rect.top, + rect.right - rect.left, + rect.bottom - rect.top, + SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | + SWP_NOZORDER + ); + + win->State.IsFullscreen = GL_TRUE; + } +#endif +} + +/* + * Toggle the window's full screen state. + */ +void FGAPIENTRY glutFullScreenToggle( void ) +{ + SFG_Window *win; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreenToggle" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreenToggle" ); + + win = fgStructure.CurrentWindow; + +#if TARGET_HOST_POSIX_X11 + if(toggle_fullscreen() != -1) { + win->State.IsFullscreen = !win->State.IsFullscreen; + } +#elif TARGET_HOST_MS_WINDOWS + glutFullScreen(); + win->State.IsFullscreen = !win->State.IsFullscreen; +#endif +} + +/* + * A.Donev: Set and retrieve the window's user data + */ +void* FGAPIENTRY glutGetWindowData( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGetWindowData" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutGetWindowData" ); + return fgStructure.CurrentWindow->UserData; +} + +void FGAPIENTRY glutSetWindowData(void* data) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindowData" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetWindowData" ); + fgStructure.CurrentWindow->UserData = data; +} + +/*** END OF FILE ***/ diff --git a/tests/box2d/glui/CMakeLists.txt b/tests/box2d/glui/CMakeLists.txt new file mode 100755 index 00000000..1e502988 --- /dev/null +++ b/tests/box2d/glui/CMakeLists.txt @@ -0,0 +1,49 @@ +add_definitions( -DFREEGLUT_STATIC -D_CRT_SECURE_NO_WARNINGS )
+
+if(MSVC)
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W1")
+endif(MSVC)
+
+set(glui_SRCS
+ algebra3.cpp
+ arcball.cpp
+ glui_add_controls.cpp
+ glui_bitmap_img_data.cpp
+ glui_bitmaps.cpp
+ glui_button.cpp
+ glui_checkbox.cpp
+ glui_column.cpp
+ glui_commandline.cpp
+ glui_control.cpp
+ glui_edittext.cpp
+ glui_filebrowser.cpp
+ glui_list.cpp
+ glui_listbox.cpp
+ glui_mouse_iaction.cpp
+ glui_node.cpp
+ glui_panel.cpp
+ glui_radio.cpp
+ glui_rollout.cpp
+ glui_rotation.cpp
+ glui_scrollbar.cpp
+ glui_separator.cpp
+ glui_spinner.cpp
+ glui_statictext.cpp
+ glui_string.cpp
+ glui_textbox.cpp
+ glui_translation.cpp
+ glui_tree.cpp
+ glui_treepanel.cpp
+ glui_window.cpp
+ glui.cpp
+ quaternion.cpp
+)
+
+include_directories (
+ ${OPENGL_INCLUDE_DIR}
+ ../
+)
+
+add_library(glui
+ ${glui_SRCS}
+)
diff --git a/tests/box2d/glui/algebra3.cpp b/tests/box2d/glui/algebra3.cpp new file mode 100755 index 00000000..ddc18f4f --- /dev/null +++ b/tests/box2d/glui/algebra3.cpp @@ -0,0 +1,1609 @@ +/*
+
+ algebra3.cpp, algebra3.h - C++ Vector and Matrix Algebra routines
+
+ GLUI User Interface Toolkit (LGPL)
+ Copyright (c) 1998 Paul Rademacher
+
+ WWW: http://sourceforge.net/projects/glui/
+ Forums: http://sourceforge.net/forum/?group_id=92496
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+
+/**************************************************************************
+
+ There are three vector classes and two matrix classes: vec2, vec3,
+ vec4, mat3, and mat4.
+
+ All the standard arithmetic operations are defined, with '*'
+ for dot product of two vectors and multiplication of two matrices,
+ and '^' for cross product of two vectors.
+
+ Additional functions include length(), normalize(), homogenize for
+ vectors, and print(), set(), apply() for all classes.
+
+ There is a function transpose() for matrices, but note that it
+ does not actually change the matrix,
+
+ When multiplied with a matrix, a vector is treated as a row vector
+ if it precedes the matrix (v*M), and as a column vector if it
+ follows the matrix (M*v).
+
+ Matrices are stored in row-major form.
+
+ A vector of one dimension (2d, 3d, or 4d) can be cast to a vector
+ of a higher or lower dimension. If casting to a higher dimension,
+ the new component is set by default to 1.0, unless a value is
+ specified:
+ vec3 a(1.0, 2.0, 3.0 );
+ vec4 b( a, 4.0 ); // now b == {1.0, 2.0, 3.0, 4.0};
+ When casting to a lower dimension, the vector is homogenized in
+ the lower dimension. E.g., if a 4d {X,Y,Z,W} is cast to 3d, the
+ resulting vector is {X/W, Y/W, Z/W}. It is up to the user to
+ insure the fourth component is not zero before casting.
+
+ There are also the following function for building matrices:
+ identity2D(), translation2D(), rotation2D(),
+ scaling2D(), identity3D(), translation3D(),
+ rotation3D(), rotation3Drad(), scaling3D(),
+ perspective3D()
+
+
+ ---------------------------------------------------------------------
+
+ Author: Jean-Francois DOUEg
+ Revised: Paul Rademacher
+ Version 3.2 - Feb 1998
+ Revised: Nigel Stewart (GLUI Code Cleaning)
+
+**************************************************************************/
+
+#include "algebra3.h"
+#include "glui_internal.h"
+#include <cmath>
+
+#ifdef VEC_ERROR_FATAL
+#ifndef VEC_ERROR
+#define VEC_ERROR(E) { printf( "VERROR %s\n", E ); exit(1); }
+#endif
+#else
+#ifndef VEC_ERROR
+#define VEC_ERROR(E) { printf( "VERROR %s\n", E ); }
+#endif
+#endif
+
+/****************************************************************
+ * *
+ * vec2 Member functions *
+ * *
+ ****************************************************************/
+
+/******************** vec2 CONSTRUCTORS ********************/
+
+vec2::vec2()
+{
+ n[VX] = n[VY] = 0.0;
+}
+
+vec2::vec2(float x, float y)
+{
+ n[VX] = x;
+ n[VY] = y;
+}
+
+vec2::vec2(const vec2 &v)
+{
+ n[VX] = v.n[VX];
+ n[VY] = v.n[VY];
+}
+
+vec2::vec2(const vec3 &v) // it is up to caller to avoid divide-by-zero
+{
+ n[VX] = v.n[VX]/v.n[VZ];
+ n[VY] = v.n[VY]/v.n[VZ];
+}
+
+vec2::vec2(const vec3 &v, int dropAxis)
+{
+ switch (dropAxis)
+ {
+ case VX: n[VX] = v.n[VY]; n[VY] = v.n[VZ]; break;
+ case VY: n[VX] = v.n[VX]; n[VY] = v.n[VZ]; break;
+ default: n[VX] = v.n[VX]; n[VY] = v.n[VY]; break;
+ }
+}
+
+/******************** vec2 ASSIGNMENT OPERATORS ******************/
+
+vec2 & vec2::operator=(const vec2 &v)
+{
+ n[VX] = v.n[VX];
+ n[VY] = v.n[VY];
+ return *this;
+}
+
+vec2 & vec2::operator+=(const vec2 &v)
+{
+ n[VX] += v.n[VX];
+ n[VY] += v.n[VY];
+ return *this;
+}
+
+vec2 & vec2::operator-=(const vec2 &v)
+{
+ n[VX] -= v.n[VX];
+ n[VY] -= v.n[VY];
+ return *this;
+}
+
+vec2 &vec2::operator*=(float d)
+{
+ n[VX] *= d;
+ n[VY] *= d;
+ return *this;
+}
+
+vec2 &vec2::operator/=(float d)
+{
+ float d_inv = 1.0f/d;
+ n[VX] *= d_inv;
+ n[VY] *= d_inv;
+ return *this;
+}
+
+float &vec2::operator[](int i)
+{
+ if (i < VX || i > VY)
+ //VEC_ERROR("vec2 [] operator: illegal access; index = " << i << '\n')
+ VEC_ERROR("vec2 [] operator: illegal access" );
+ return n[i];
+}
+
+const float &vec2::operator[](int i) const
+{
+ if (i < VX || i > VY)
+ //VEC_ERROR("vec2 [] operator: illegal access; index = " << i << '\n')
+ VEC_ERROR("vec2 [] operator: illegal access" );
+
+ return n[i];
+}
+
+/******************** vec2 SPECIAL FUNCTIONS ********************/
+
+float vec2::length() const
+{
+ return (float) sqrt(length2());
+}
+
+float vec2::length2() const
+{
+ return n[VX]*n[VX] + n[VY]*n[VY];
+}
+
+vec2 &vec2::normalize() // it is up to caller to avoid divide-by-zero
+{
+ *this /= length();
+ return *this;
+}
+
+vec2 &vec2::apply(V_FCT_PTR fct)
+{
+ n[VX] = (*fct)(n[VX]);
+ n[VY] = (*fct)(n[VY]);
+ return *this;
+}
+
+void vec2::set( float x, float y )
+{
+ n[VX] = x; n[VY] = y;
+}
+
+/******************** vec2 FRIENDS *****************************/
+
+vec2 operator-(const vec2 &a)
+{
+ return vec2(-a.n[VX],-a.n[VY]);
+}
+
+vec2 operator+(const vec2 &a, const vec2& b)
+{
+ return vec2(a.n[VX]+b.n[VX], a.n[VY]+b.n[VY]);
+}
+
+vec2 operator-(const vec2 &a, const vec2& b)
+{
+ return vec2(a.n[VX]-b.n[VX], a.n[VY]-b.n[VY]);
+}
+
+vec2 operator*(const vec2 &a, float d)
+{
+ return vec2(d*a.n[VX], d*a.n[VY]);
+}
+
+vec2 operator*(float d, const vec2 &a)
+{
+ return a*d;
+}
+
+vec2 operator*(const mat3 &a, const vec2 &v)
+{
+ vec3 av;
+
+ av.n[VX] = a.v[0].n[VX]*v.n[VX] + a.v[0].n[VY]*v.n[VY] + a.v[0].n[VZ];
+ av.n[VY] = a.v[1].n[VX]*v.n[VX] + a.v[1].n[VY]*v.n[VY] + a.v[1].n[VZ];
+ av.n[VZ] = a.v[2].n[VX]*v.n[VX] + a.v[2].n[VY]*v.n[VY] + a.v[2].n[VZ];
+
+ return av;
+}
+
+vec2 operator*(const vec2 &v, const mat3 &a)
+{
+ return a.transpose() * v;
+}
+
+vec3 operator*(const mat3 &a, const vec3 &v)
+{
+ vec3 av;
+
+ av.n[VX] = a.v[0].n[VX]*v.n[VX] + a.v[0].n[VY]*v.n[VY] + a.v[0].n[VZ]*v.n[VZ];
+ av.n[VY] = a.v[1].n[VX]*v.n[VX] + a.v[1].n[VY]*v.n[VY] + a.v[1].n[VZ]*v.n[VZ];
+ av.n[VZ] = a.v[2].n[VX]*v.n[VX] + a.v[2].n[VY]*v.n[VY] + a.v[2].n[VZ]*v.n[VZ];
+
+ return av;
+}
+
+vec3 operator*(const vec3 &v, const mat3 &a)
+{
+ return a.transpose() * v;
+}
+
+float operator*(const vec2 &a, const vec2 &b)
+{
+ return a.n[VX]*b.n[VX] + a.n[VY]*b.n[VY];
+}
+
+vec2 operator/(const vec2 &a, float d)
+{
+ float d_inv = 1.0f/d;
+ return vec2(a.n[VX]*d_inv, a.n[VY]*d_inv);
+}
+
+vec3 operator^(const vec2 &a, const vec2 &b)
+{
+ return vec3(0.0, 0.0, a.n[VX] * b.n[VY] - b.n[VX] * a.n[VY]);
+}
+
+int operator==(const vec2 &a, const vec2 &b)
+{
+ return (a.n[VX] == b.n[VX]) && (a.n[VY] == b.n[VY]);
+}
+
+int operator!=(const vec2 &a, const vec2 &b)
+{
+ return !(a == b);
+}
+
+/*ostream& operator << (ostream& s, vec2& v)
+{ return s << "| " << v.n[VX] << ' ' << v.n[VY] << " |"; }
+*/
+
+/*istream& operator >> (istream& s, vec2& v) {
+ vec2 v_tmp;
+ char c = ' ';
+
+ while (isspace(c))
+ s >> c;
+ // The vectors can be formatted either as x y or | x y |
+ if (c == '|') {
+ s >> v_tmp[VX] >> v_tmp[VY];
+ while (s >> c && isspace(c)) ;
+ if (c != '|')
+ ;//s.set(_bad);
+ }
+ else {
+ s.putback(c);
+ s >> v_tmp[VX] >> v_tmp[VY];
+ }
+ if (s)
+ v = v_tmp;
+ return s;
+}
+*/
+
+void swap(vec2 &a, vec2 &b)
+{
+ vec2 tmp(a);
+ a = b;
+ b = tmp;
+}
+
+vec2 min_vec(const vec2 &a, const vec2 &b)
+{
+ return vec2(MIN(a.n[VX], b.n[VX]), MIN(a.n[VY], b.n[VY]));
+}
+
+vec2 max_vec(const vec2 &a, const vec2 &b)
+{
+ return vec2(MAX(a.n[VX], b.n[VX]), MAX(a.n[VY], b.n[VY]));
+}
+
+vec2 prod(const vec2 &a, const vec2 &b)
+{
+ return vec2(a.n[VX] * b.n[VX], a.n[VY] * b.n[VY]);
+}
+
+/****************************************************************
+ * *
+ * vec3 Member functions *
+ * *
+ ****************************************************************/
+
+// CONSTRUCTORS
+
+vec3::vec3()
+{
+ n[VX] = n[VY] = n[VZ] = 0.0;
+}
+
+vec3::vec3(float x, float y, float z)
+{
+ n[VX] = x;
+ n[VY] = y;
+ n[VZ] = z;
+}
+
+vec3::vec3(const vec3 &v)
+{
+ n[VX] = v.n[VX]; n[VY] = v.n[VY]; n[VZ] = v.n[VZ];
+}
+
+vec3::vec3(const vec2 &v)
+{
+ n[VX] = v.n[VX];
+ n[VY] = v.n[VY];
+ n[VZ] = 1.0;
+}
+
+vec3::vec3(const vec2 &v, float d)
+{
+ n[VX] = v.n[VX];
+ n[VY] = v.n[VY];
+ n[VZ] = d;
+}
+
+vec3::vec3(const vec4 &v) // it is up to caller to avoid divide-by-zero
+{
+ n[VX] = v.n[VX] / v.n[VW];
+ n[VY] = v.n[VY] / v.n[VW];
+ n[VZ] = v.n[VZ] / v.n[VW];
+}
+
+vec3::vec3(const vec4 &v, int dropAxis)
+{
+ switch (dropAxis)
+ {
+ case VX: n[VX] = v.n[VY]; n[VY] = v.n[VZ]; n[VZ] = v.n[VW]; break;
+ case VY: n[VX] = v.n[VX]; n[VY] = v.n[VZ]; n[VZ] = v.n[VW]; break;
+ case VZ: n[VX] = v.n[VX]; n[VY] = v.n[VY]; n[VZ] = v.n[VW]; break;
+ default: n[VX] = v.n[VX]; n[VY] = v.n[VY]; n[VZ] = v.n[VZ]; break;
+ }
+}
+
+
+// ASSIGNMENT OPERATORS
+
+vec3 &vec3::operator=(const vec3 &v)
+{
+ n[VX] = v.n[VX];
+ n[VY] = v.n[VY];
+ n[VZ] = v.n[VZ];
+ return *this;
+}
+
+vec3 &vec3::operator+=(const vec3 &v)
+{
+ n[VX] += v.n[VX];
+ n[VY] += v.n[VY];
+ n[VZ] += v.n[VZ];
+ return *this;
+}
+
+vec3 &vec3::operator-=(const vec3& v)
+{
+ n[VX] -= v.n[VX];
+ n[VY] -= v.n[VY];
+ n[VZ] -= v.n[VZ];
+ return *this;
+}
+
+vec3 &vec3::operator*=(float d)
+{
+ n[VX] *= d;
+ n[VY] *= d;
+ n[VZ] *= d;
+ return *this;
+}
+
+vec3 &vec3::operator/=(float d)
+{
+ float d_inv = 1.0f/d;
+ n[VX] *= d_inv;
+ n[VY] *= d_inv;
+ n[VZ] *= d_inv;
+ return *this;
+}
+
+float &vec3::operator[](int i)
+{
+ if (i < VX || i > VZ)
+ //VEC_ERROR("vec3 [] operator: illegal access; index = " << i << '\n')
+ VEC_ERROR("vec3 [] operator: illegal access" );
+
+ return n[i];
+}
+
+const float &vec3::operator[](int i) const
+{
+ if (i < VX || i > VZ)
+ //VEC_ERROR("vec3 [] operator: illegal access; index = " << i << '\n')
+ VEC_ERROR("vec3 [] operator: illegal access" );
+
+ return n[i];
+}
+
+// SPECIAL FUNCTIONS
+
+float vec3::length() const
+{
+ return (float) sqrt(length2());
+}
+
+float vec3::length2() const
+{
+ return n[VX]*n[VX] + n[VY]*n[VY] + n[VZ]*n[VZ];
+}
+
+vec3 &vec3::normalize() // it is up to caller to avoid divide-by-zero
+{
+ *this /= length();
+ return *this;
+}
+
+vec3 &vec3::homogenize(void) // it is up to caller to avoid divide-by-zero
+{
+ n[VX] /= n[VZ];
+ n[VY] /= n[VZ];
+ n[VZ] = 1.0;
+ return *this;
+}
+
+vec3 &vec3::apply(V_FCT_PTR fct)
+{
+ n[VX] = (*fct)(n[VX]);
+ n[VY] = (*fct)(n[VY]);
+ n[VZ] = (*fct)(n[VZ]);
+ return *this;
+}
+
+void vec3::set(float x, float y, float z) // set vector
+{
+ n[VX] = x;
+ n[VY] = y;
+ n[VZ] = z;
+}
+
+void vec3::print(FILE *file, const char *name) const // print vector to a file
+{
+ fprintf( file, "%s: <%f, %f, %f>\n", name, n[VX], n[VY], n[VZ] );
+}
+
+// FRIENDS
+
+vec3 operator-(const vec3 &a)
+{
+ return vec3(-a.n[VX],-a.n[VY],-a.n[VZ]);
+}
+
+vec3 operator+(const vec3 &a, const vec3 &b)
+{
+ return vec3(a.n[VX]+ b.n[VX], a.n[VY] + b.n[VY], a.n[VZ] + b.n[VZ]);
+}
+
+vec3 operator-(const vec3 &a, const vec3 &b)
+{
+ return vec3(a.n[VX]-b.n[VX], a.n[VY]-b.n[VY], a.n[VZ]-b.n[VZ]);
+}
+
+vec3 operator*(const vec3 &a, float d)
+{
+ return vec3(d*a.n[VX], d*a.n[VY], d*a.n[VZ]);
+}
+
+vec3 operator*(float d, const vec3 &a)
+{
+ return a*d;
+}
+
+vec3 operator*(const mat4 &a, const vec3 &v)
+{
+ return a*vec4(v);
+}
+
+vec3 operator*(const vec3 &v, mat4 &a)
+{
+ return a.transpose()*v;
+}
+
+float operator*(const vec3 &a, const vec3 &b)
+{
+ return a.n[VX]*b.n[VX] + a.n[VY]*b.n[VY] + a.n[VZ]*b.n[VZ];
+}
+
+vec3 operator/(const vec3 &a, float d)
+{
+ float d_inv = 1.0f/d;
+ return vec3(a.n[VX]*d_inv, a.n[VY]*d_inv, a.n[VZ]*d_inv);
+}
+
+vec3 operator^(const vec3 &a, const vec3 &b)
+{
+ return
+ vec3(a.n[VY]*b.n[VZ] - a.n[VZ]*b.n[VY],
+ a.n[VZ]*b.n[VX] - a.n[VX]*b.n[VZ],
+ a.n[VX]*b.n[VY] - a.n[VY]*b.n[VX]);
+}
+
+int operator==(const vec3 &a, const vec3 &b)
+{
+ return (a.n[VX] == b.n[VX]) && (a.n[VY] == b.n[VY]) && (a.n[VZ] == b.n[VZ]);
+}
+
+int operator!=(const vec3 &a, const vec3 &b)
+{
+ return !(a == b);
+}
+
+/*ostream& operator << (ostream& s, vec3& v)
+{ return s << "| " << v.n[VX] << ' ' << v.n[VY] << ' ' << v.n[VZ] << " |"; }
+
+istream& operator >> (istream& s, vec3& v) {
+ vec3 v_tmp;
+ char c = ' ';
+
+ while (isspace(c))
+ s >> c;
+ // The vectors can be formatted either as x y z or | x y z |
+ if (c == '|') {
+ s >> v_tmp[VX] >> v_tmp[VY] >> v_tmp[VZ];
+ while (s >> c && isspace(c)) ;
+ if (c != '|')
+ ;//s.set(_bad);
+ }
+ else {
+ s.putback(c);
+ s >> v_tmp[VX] >> v_tmp[VY] >> v_tmp[VZ];
+ }
+ if (s)
+ v = v_tmp;
+ return s;
+}
+*/
+
+void swap(vec3 &a, vec3 &b)
+{
+ vec3 tmp(a);
+ a = b;
+ b = tmp;
+}
+
+vec3 min_vec(const vec3 &a, const vec3 &b)
+{
+ return vec3(
+ MIN(a.n[VX], b.n[VX]),
+ MIN(a.n[VY], b.n[VY]),
+ MIN(a.n[VZ], b.n[VZ]));
+}
+
+vec3 max_vec(const vec3 &a, const vec3 &b)
+{
+ return vec3(
+ MAX(a.n[VX], b.n[VX]),
+ MAX(a.n[VY], b.n[VY]),
+ MAX(a.n[VZ], b.n[VZ]));
+}
+
+vec3 prod(const vec3 &a, const vec3 &b)
+{
+ return vec3(a.n[VX]*b.n[VX], a.n[VY]*b.n[VY], a.n[VZ]*b.n[VZ]);
+}
+
+/****************************************************************
+ * *
+ * vec4 Member functions *
+ * *
+ ****************************************************************/
+
+// CONSTRUCTORS
+
+vec4::vec4()
+{
+ n[VX] = n[VY] = n[VZ] = 0.0;
+ n[VW] = 1.0;
+}
+
+vec4::vec4(float x, float y, float z, float w)
+{
+ n[VX] = x;
+ n[VY] = y;
+ n[VZ] = z;
+ n[VW] = w;
+}
+
+vec4::vec4(const vec4 &v)
+{
+ n[VX] = v.n[VX];
+ n[VY] = v.n[VY];
+ n[VZ] = v.n[VZ];
+ n[VW] = v.n[VW];
+}
+
+vec4::vec4(const vec3 &v)
+{
+ n[VX] = v.n[VX];
+ n[VY] = v.n[VY];
+ n[VZ] = v.n[VZ];
+ n[VW] = 1.0;
+}
+
+vec4::vec4(const vec3 &v, float d)
+{
+ n[VX] = v.n[VX];
+ n[VY] = v.n[VY];
+ n[VZ] = v.n[VZ];
+ n[VW] = d;
+}
+
+// ASSIGNMENT OPERATORS
+
+vec4 &vec4::operator=(const vec4 &v)
+{
+ n[VX] = v.n[VX];
+ n[VY] = v.n[VY];
+ n[VZ] = v.n[VZ];
+ n[VW] = v.n[VW];
+ return *this;
+}
+
+vec4 &vec4::operator+=(const vec4 &v)
+{
+ n[VX] += v.n[VX];
+ n[VY] += v.n[VY];
+ n[VZ] += v.n[VZ];
+ n[VW] += v.n[VW];
+ return *this;
+}
+
+vec4 &vec4::operator-=(const vec4 &v)
+{
+ n[VX] -= v.n[VX];
+ n[VY] -= v.n[VY];
+ n[VZ] -= v.n[VZ];
+ n[VW] -= v.n[VW];
+ return *this;
+}
+
+vec4 &vec4::operator*=(float d)
+{
+ n[VX] *= d;
+ n[VY] *= d;
+ n[VZ] *= d;
+ n[VW] *= d;
+ return *this;
+}
+
+vec4 &vec4::operator/=(float d)
+{
+ float d_inv = 1.0f/d;
+ n[VX] *= d_inv;
+ n[VY] *= d_inv;
+ n[VZ] *= d_inv;
+ n[VW] *= d_inv;
+ return *this;
+}
+
+float &vec4::operator[](int i)
+{
+ if (i < VX || i > VW)
+ //VEC_ERROR("vec4 [] operator: illegal access; index = " << i << '\n')
+ VEC_ERROR("vec4 [] operator: illegal access" );
+
+ return n[i];
+}
+
+const float &vec4::operator[](int i) const
+{
+ if (i < VX || i > VW)
+ //VEC_ERROR("vec4 [] operator: illegal access; index = " << i << '\n')
+ VEC_ERROR("vec4 [] operator: illegal access" );
+
+ return n[i];
+}
+
+// SPECIAL FUNCTIONS
+
+float vec4::length() const
+{
+ return (float) sqrt(length2());
+}
+
+float vec4::length2() const
+{
+ return n[VX]*n[VX] + n[VY]*n[VY] + n[VZ]*n[VZ] + n[VW]*n[VW];
+}
+
+vec4 &vec4::normalize() // it is up to caller to avoid divide-by-zero
+{
+ *this /= length();
+ return *this;
+}
+
+vec4 &vec4::homogenize() // it is up to caller to avoid divide-by-zero
+{
+ n[VX] /= n[VW];
+ n[VY] /= n[VW];
+ n[VZ] /= n[VW];
+ n[VW] = 1.0;
+ return *this;
+}
+
+vec4 &vec4::apply(V_FCT_PTR fct)
+{
+ n[VX] = (*fct)(n[VX]);
+ n[VY] = (*fct)(n[VY]);
+ n[VZ] = (*fct)(n[VZ]);
+ n[VW] = (*fct)(n[VW]);
+ return *this;
+}
+
+void vec4::print(FILE *file, const char *name) const // print vector to a file
+{
+ fprintf( file, "%s: <%f, %f, %f, %f>\n", name, n[VX], n[VY], n[VZ], n[VW]);
+}
+
+void vec4::set(float x, float y, float z, float a)
+{
+ n[0] = x;
+ n[1] = y;
+ n[2] = z;
+ n[3] = a;
+}
+
+
+// FRIENDS
+
+vec4 operator-(const vec4 &a)
+{
+ return vec4(-a.n[VX],-a.n[VY],-a.n[VZ],-a.n[VW]);
+}
+
+vec4 operator+(const vec4 &a, const vec4 &b)
+{
+ return vec4(
+ a.n[VX] + b.n[VX],
+ a.n[VY] + b.n[VY],
+ a.n[VZ] + b.n[VZ],
+ a.n[VW] + b.n[VW]);
+}
+
+vec4 operator-(const vec4 &a, const vec4 &b)
+{
+ return vec4(
+ a.n[VX] - b.n[VX],
+ a.n[VY] - b.n[VY],
+ a.n[VZ] - b.n[VZ],
+ a.n[VW] - b.n[VW]);
+}
+
+vec4 operator*(const vec4 &a, float d)
+{
+ return vec4(d*a.n[VX], d*a.n[VY], d*a.n[VZ], d*a.n[VW]);
+}
+
+vec4 operator*(float d, const vec4 &a)
+{
+ return a*d;
+}
+
+vec4 operator*(const mat4 &a, const vec4 &v)
+{
+ #define ROWCOL(i) \
+ a.v[i].n[0]*v.n[VX] + \
+ a.v[i].n[1]*v.n[VY] + \
+ a.v[i].n[2]*v.n[VZ] + \
+ a.v[i].n[3]*v.n[VW]
+
+ return vec4(ROWCOL(0), ROWCOL(1), ROWCOL(2), ROWCOL(3));
+
+ #undef ROWCOL
+}
+
+vec4 operator*(const vec4 &v, const mat4 &a)
+{
+ return a.transpose()*v;
+}
+
+float operator*(const vec4 &a, const vec4 &b)
+{
+ return
+ a.n[VX]*b.n[VX] +
+ a.n[VY]*b.n[VY] +
+ a.n[VZ]*b.n[VZ] +
+ a.n[VW]*b.n[VW];
+}
+
+vec4 operator/(const vec4 &a, float d)
+{
+ float d_inv = 1.0f/d;
+ return vec4(
+ a.n[VX]*d_inv,
+ a.n[VY]*d_inv,
+ a.n[VZ]*d_inv,
+ a.n[VW]*d_inv);
+}
+
+int operator==(const vec4 &a, const vec4 &b)
+{
+ return
+ (a.n[VX] == b.n[VX]) &&
+ (a.n[VY] == b.n[VY]) &&
+ (a.n[VZ] == b.n[VZ]) &&
+ (a.n[VW] == b.n[VW]);
+}
+
+int operator!=(const vec4 &a, const vec4 &b)
+{
+ return !(a == b);
+}
+
+/*ostream& operator << (ostream& s, vec4& v)
+{ return s << "| " << v.n[VX] << ' ' << v.n[VY] << ' ' << v.n[VZ] << ' '
+ << v.n[VW] << " |"; }
+
+istream& operator >> (istream& s, vec4& v) {
+ vec4 v_tmp;
+ char c = ' ';
+
+ while (isspace(c))
+ s >> c;
+ // The vectors can be formatted either as x y z w or | x y z w |
+ if (c == '|') {
+ s >> v_tmp[VX] >> v_tmp[VY] >> v_tmp[VZ] >> v_tmp[VW];
+ while (s >> c && isspace(c)) ;
+ if (c != '|')
+ ;//s.set(_bad);
+ }
+ else {
+ s.putback(c);
+ s >> v_tmp[VX] >> v_tmp[VY] >> v_tmp[VZ] >> v_tmp[VW];
+ }
+ if (s)
+ v = v_tmp;
+ return s;
+}
+*/
+
+void swap(vec4 &a, vec4 &b)
+{
+ vec4 tmp(a);
+ a = b;
+ b = tmp;
+}
+
+vec4 min_vec(const vec4 &a, const vec4 &b)
+{
+ return vec4(
+ MIN(a.n[VX], b.n[VX]),
+ MIN(a.n[VY], b.n[VY]),
+ MIN(a.n[VZ], b.n[VZ]),
+ MIN(a.n[VW], b.n[VW]));
+}
+
+vec4 max_vec(const vec4 &a, const vec4 &b)
+{
+ return vec4(
+ MAX(a.n[VX], b.n[VX]),
+ MAX(a.n[VY], b.n[VY]),
+ MAX(a.n[VZ], b.n[VZ]),
+ MAX(a.n[VW], b.n[VW]));
+}
+
+vec4 prod(const vec4 &a, const vec4 &b)
+{
+ return vec4(
+ a.n[VX] * b.n[VX],
+ a.n[VY] * b.n[VY],
+ a.n[VZ] * b.n[VZ],
+ a.n[VW] * b.n[VW]);
+}
+
+/****************************************************************
+ * *
+ * mat3 member functions *
+ * *
+ ****************************************************************/
+
+// CONSTRUCTORS
+
+mat3::mat3()
+{
+ *this = identity2D();
+}
+
+mat3::mat3(const vec3 &v0, const vec3 &v1, const vec3 &v2)
+{
+ set(v0, v1, v2);
+}
+
+mat3::mat3(const mat3 &m)
+{
+ v[0] = m.v[0];
+ v[1] = m.v[1];
+ v[2] = m.v[2];
+}
+
+// ASSIGNMENT OPERATORS
+
+mat3 &mat3::operator=(const mat3 &m)
+{
+ v[0] = m.v[0];
+ v[1] = m.v[1];
+ v[2] = m.v[2];
+ return *this;
+}
+
+mat3 &mat3::operator+=(const mat3& m)
+{
+ v[0] += m.v[0];
+ v[1] += m.v[1];
+ v[2] += m.v[2];
+ return *this;
+}
+
+mat3 &mat3::operator-=(const mat3& m)
+{
+ v[0] -= m.v[0];
+ v[1] -= m.v[1];
+ v[2] -= m.v[2];
+ return *this;
+}
+
+mat3 &mat3::operator*=(float d)
+{
+ v[0] *= d;
+ v[1] *= d;
+ v[2] *= d;
+ return *this;
+}
+
+mat3 &mat3::operator/=(float d)
+{
+ v[0] /= d;
+ v[1] /= d;
+ v[2] /= d;
+ return *this;
+}
+
+vec3 &mat3::operator[](int i)
+{
+ if (i < VX || i > VZ)
+ //VEC_ERROR("mat3 [] operator: illegal access; index = " << i << '\n')
+ VEC_ERROR("mat3 [] operator: illegal access" );
+
+ return v[i];
+}
+
+const vec3 &mat3::operator[](int i) const
+{
+ if (i < VX || i > VZ)
+ //VEC_ERROR("mat3 [] operator: illegal access; index = " << i << '\n')
+ VEC_ERROR("mat3 [] operator: illegal access" );
+
+ return v[i];
+}
+
+void mat3::set(const vec3 &v0, const vec3 &v1, const vec3 &v2)
+{
+ v[0] = v0;
+ v[1] = v1;
+ v[2] = v2;
+}
+
+// SPECIAL FUNCTIONS
+
+mat3 mat3::transpose() const
+{
+ return mat3(
+ vec3(v[0][0], v[1][0], v[2][0]),
+ vec3(v[0][1], v[1][1], v[2][1]),
+ vec3(v[0][2], v[1][2], v[2][2]));
+}
+
+mat3 mat3::inverse() const // Gauss-Jordan elimination with partial pivoting
+{
+ mat3 a(*this); // As a evolves from original mat into identity
+ mat3 b(identity2D()); // b evolves from identity into inverse(a)
+ int i, j, i1;
+
+ // Loop over cols of a from left to right, eliminating above and below diag
+ for (j=0; j<3; j++) // Find largest pivot in column j among rows j..2
+ {
+ i1 = j; // Row with largest pivot candidate
+ for (i=j+1; i<3; i++)
+ if (fabs(a.v[i].n[j]) > fabs(a.v[i1].n[j]))
+ i1 = i;
+
+ // Swap rows i1 and j in a and b to put pivot on diagonal
+ swap(a.v[i1], a.v[j]);
+ swap(b.v[i1], b.v[j]);
+
+ // Scale row j to have a unit diagonal
+ if (a.v[j].n[j]==0.)
+ VEC_ERROR("mat3::inverse: singular matrix; can't invert\n");
+
+ b.v[j] /= a.v[j].n[j];
+ a.v[j] /= a.v[j].n[j];
+
+ // Eliminate off-diagonal elems in col j of a, doing identical ops to b
+ for (i=0; i<3; i++)
+ if (i!=j)
+ {
+ b.v[i] -= a.v[i].n[j]*b.v[j];
+ a.v[i] -= a.v[i].n[j]*a.v[j];
+ }
+ }
+
+ return b;
+}
+
+mat3 &mat3::apply(V_FCT_PTR fct)
+{
+ v[VX].apply(fct);
+ v[VY].apply(fct);
+ v[VZ].apply(fct);
+ return *this;
+}
+
+
+// FRIENDS
+
+mat3 operator-(const mat3 &a)
+{
+ return mat3(-a.v[0], -a.v[1], -a.v[2]);
+}
+
+mat3 operator+(const mat3 &a, const mat3 &b)
+{
+ return mat3(a.v[0]+b.v[0], a.v[1]+b.v[1], a.v[2]+b.v[2]);
+}
+
+mat3 operator-(const mat3 &a, const mat3 &b)
+{
+ return mat3(a.v[0]-b.v[0], a.v[1]-b.v[1], a.v[2]-b.v[2]);
+}
+
+mat3 operator*(const mat3 &a, const mat3 &b)
+{
+ #define ROWCOL(i, j) \
+ a.v[i].n[0]*b.v[0][j] + a.v[i].n[1]*b.v[1][j] + a.v[i].n[2]*b.v[2][j]
+
+ return mat3(
+ vec3(ROWCOL(0,0), ROWCOL(0,1), ROWCOL(0,2)),
+ vec3(ROWCOL(1,0), ROWCOL(1,1), ROWCOL(1,2)),
+ vec3(ROWCOL(2,0), ROWCOL(2,1), ROWCOL(2,2)));
+
+ #undef ROWCOL
+}
+
+mat3 operator*(const mat3 &a, float d)
+{
+ return mat3(a.v[0]*d, a.v[1]*d, a.v[2]*d);
+}
+
+mat3 operator*(float d, const mat3 &a)
+{
+ return a*d;
+}
+
+mat3 operator/(const mat3 &a, float d)
+{
+ return mat3(a.v[0]/d, a.v[1]/d, a.v[2]/d);
+}
+
+int operator==(const mat3 &a, const mat3 &b)
+{
+ return
+ (a.v[0] == b.v[0]) &&
+ (a.v[1] == b.v[1]) &&
+ (a.v[2] == b.v[2]);
+}
+
+int operator!=(const mat3 &a, const mat3 &b)
+{
+ return !(a == b);
+}
+
+/*ostream& operator << (ostream& s, mat3& m)
+{ return s << m.v[VX] << '\n' << m.v[VY] << '\n' << m.v[VZ]; }
+
+istream& operator >> (istream& s, mat3& m) {
+ mat3 m_tmp;
+
+ s >> m_tmp[VX] >> m_tmp[VY] >> m_tmp[VZ];
+ if (s)
+ m = m_tmp;
+ return s;
+}
+*/
+
+void swap(mat3 &a, mat3 &b)
+{
+ mat3 tmp(a);
+ a = b;
+ b = tmp;
+}
+
+void mat3::print(FILE *file, const char *name) const
+{
+ int i, j;
+
+ fprintf( stderr, "%s:\n", name );
+
+ for( i = 0; i < 3; i++ )
+ {
+ fprintf( stderr, " " );
+ for( j = 0; j < 3; j++ )
+ {
+ fprintf( stderr, "%f ", v[i][j] );
+ }
+ fprintf( stderr, "\n" );
+ }
+}
+
+
+
+/****************************************************************
+ * *
+ * mat4 member functions *
+ * *
+ ****************************************************************/
+
+// CONSTRUCTORS
+
+mat4::mat4()
+{
+ *this = identity3D();
+}
+
+mat4::mat4(const vec4& v0, const vec4& v1, const vec4& v2, const vec4& v3)
+{
+ v[0] = v0;
+ v[1] = v1;
+ v[2] = v2;
+ v[3] = v3;
+}
+
+mat4::mat4(const mat4 &m)
+{
+ v[0] = m.v[0];
+ v[1] = m.v[1];
+ v[2] = m.v[2];
+ v[3] = m.v[3];
+}
+
+mat4::mat4(
+ float a00, float a01, float a02, float a03,
+ float a10, float a11, float a12, float a13,
+ float a20, float a21, float a22, float a23,
+ float a30, float a31, float a32, float a33 )
+{
+ v[0][0] = a00; v[0][1] = a01; v[0][2] = a02; v[0][3] = a03;
+ v[1][0] = a10; v[1][1] = a11; v[1][2] = a12; v[1][3] = a13;
+ v[2][0] = a20; v[2][1] = a21; v[2][2] = a22; v[2][3] = a23;
+ v[3][0] = a30; v[3][1] = a31; v[3][2] = a32; v[3][3] = a33;
+}
+
+// ASSIGNMENT OPERATORS
+
+mat4 &mat4::operator=(const mat4 &m)
+{
+ v[0] = m.v[0];
+ v[1] = m.v[1];
+ v[2] = m.v[2];
+ v[3] = m.v[3];
+ return *this;
+}
+
+mat4 &mat4::operator+=(const mat4 &m)
+{
+ v[0] += m.v[0];
+ v[1] += m.v[1];
+ v[2] += m.v[2];
+ v[3] += m.v[3];
+ return *this;
+}
+
+mat4 &mat4::operator-=(const mat4 &m)
+{
+ v[0] -= m.v[0];
+ v[1] -= m.v[1];
+ v[2] -= m.v[2];
+ v[3] -= m.v[3];
+ return *this;
+}
+
+mat4 &mat4::operator*=(float d)
+{
+ v[0] *= d;
+ v[1] *= d;
+ v[2] *= d;
+ v[3] *= d;
+ return *this;
+}
+
+mat4 &mat4::operator/=(float d)
+{
+ v[0] /= d;
+ v[1] /= d;
+ v[2] /= d;
+ v[3] /= d;
+ return *this;
+}
+
+vec4 &mat4::operator[](int i)
+{
+ if (i < VX || i > VW)
+ //VEC_ERROR("mat4 [] operator: illegal access; index = " << i << '\n')
+ VEC_ERROR("mat4 [] operator: illegal access" );
+ return v[i];
+}
+
+const vec4 &mat4::operator[](int i) const
+{
+ if (i < VX || i > VW)
+ //VEC_ERROR("mat4 [] operator: illegal access; index = " << i << '\n')
+ VEC_ERROR("mat4 [] operator: illegal access" );
+ return v[i];
+}
+
+// SPECIAL FUNCTIONS;
+
+mat4 mat4::transpose() const
+{
+ return mat4(
+ vec4(v[0][0], v[1][0], v[2][0], v[3][0]),
+ vec4(v[0][1], v[1][1], v[2][1], v[3][1]),
+ vec4(v[0][2], v[1][2], v[2][2], v[3][2]),
+ vec4(v[0][3], v[1][3], v[2][3], v[3][3]));
+}
+
+mat4 mat4::inverse() const // Gauss-Jordan elimination with partial pivoting
+{
+ mat4 a(*this); // As a evolves from original mat into identity
+ mat4 b(identity3D()); // b evolves from identity into inverse(a)
+ int i, j, i1;
+
+ // Loop over cols of a from left to right, eliminating above and below diag
+ for (j=0; j<4; j++) // Find largest pivot in column j among rows j..3
+ {
+ i1 = j; // Row with largest pivot candidate
+ for (i=j+1; i<4; i++)
+ if (fabs(a.v[i].n[j]) > fabs(a.v[i1].n[j]))
+ i1 = i;
+
+ // Swap rows i1 and j in a and b to put pivot on diagonal
+ swap(a.v[i1], a.v[j]);
+ swap(b.v[i1], b.v[j]);
+
+ // Scale row j to have a unit diagonal
+ if (a.v[j].n[j]==0.)
+ VEC_ERROR("mat4::inverse: singular matrix; can't invert\n");
+
+ b.v[j] /= a.v[j].n[j];
+ a.v[j] /= a.v[j].n[j];
+
+ // Eliminate off-diagonal elems in col j of a, doing identical ops to b
+ for (i=0; i<4; i++)
+ if (i!=j)
+ {
+ b.v[i] -= a.v[i].n[j]*b.v[j];
+ a.v[i] -= a.v[i].n[j]*a.v[j];
+ }
+ }
+
+ return b;
+}
+
+mat4 &mat4::apply(V_FCT_PTR fct)
+{
+ v[VX].apply(fct);
+ v[VY].apply(fct);
+ v[VZ].apply(fct);
+ v[VW].apply(fct);
+ return *this;
+}
+
+void mat4::print(FILE *file, const char *name) const
+{
+ int i, j;
+
+ fprintf( stderr, "%s:\n", name );
+
+ for( i = 0; i < 4; i++ )
+ {
+ fprintf( stderr, " " );
+ for( j = 0; j < 4; j++ )
+ {
+ fprintf( stderr, "%f ", v[i][j] );
+ }
+ fprintf( stderr, "\n" );
+ }
+}
+
+void mat4::swap_rows(int i, int j)
+{
+ vec4 t;
+
+ t = v[i];
+ v[i] = v[j];
+ v[j] = t;
+}
+
+void mat4::swap_cols(int i, int j)
+{
+ float t;
+ int k;
+
+ for (k=0; k<4; k++)
+ {
+ t = v[k][i];
+ v[k][i] = v[k][j];
+ v[k][j] = t;
+ }
+}
+
+
+// FRIENDS
+
+mat4 operator-(const mat4 &a)
+{
+ return mat4(-a.v[0],-a.v[1],-a.v[2],-a.v[3]);
+}
+
+mat4 operator+(const mat4 &a, const mat4 &b)
+{
+ return mat4(
+ a.v[0] + b.v[0],
+ a.v[1] + b.v[1],
+ a.v[2] + b.v[2],
+ a.v[3] + b.v[3]);
+}
+
+mat4 operator-(const mat4 &a, const mat4 &b)
+{
+ return mat4(
+ a.v[0] - b.v[0],
+ a.v[1] - b.v[1],
+ a.v[2] - b.v[2],
+ a.v[3] - b.v[3]);
+}
+
+mat4 operator*(const mat4 &a, const mat4 &b)
+{
+ #define ROWCOL(i, j) \
+ a.v[i].n[0]*b.v[0][j] + \
+ a.v[i].n[1]*b.v[1][j] + \
+ a.v[i].n[2]*b.v[2][j] + \
+ a.v[i].n[3]*b.v[3][j]
+
+ return mat4(
+ vec4(ROWCOL(0,0), ROWCOL(0,1), ROWCOL(0,2), ROWCOL(0,3)),
+ vec4(ROWCOL(1,0), ROWCOL(1,1), ROWCOL(1,2), ROWCOL(1,3)),
+ vec4(ROWCOL(2,0), ROWCOL(2,1), ROWCOL(2,2), ROWCOL(2,3)),
+ vec4(ROWCOL(3,0), ROWCOL(3,1), ROWCOL(3,2), ROWCOL(3,3))
+ );
+
+ #undef ROWCOL
+}
+
+mat4 operator*(const mat4 &a, float d)
+{
+ return mat4(a.v[0]*d, a.v[1]*d, a.v[2]*d, a.v[3]*d);
+}
+
+mat4 operator*(float d, const mat4 &a)
+{
+ return a*d;
+}
+
+mat4 operator/(const mat4 &a, float d)
+{
+ return mat4(a.v[0]/d, a.v[1]/d, a.v[2]/d, a.v[3]/d);
+}
+
+int operator==(const mat4 &a, const mat4 &b)
+{
+ return
+ (a.v[0] == b.v[0]) &&
+ (a.v[1] == b.v[1]) &&
+ (a.v[2] == b.v[2]) &&
+ (a.v[3] == b.v[3]);
+}
+
+int operator!=(const mat4 &a, const mat4 &b)
+{
+ return !(a == b);
+}
+
+/*ostream& operator << (ostream& s, mat4& m)
+{ return s << m.v[VX] << '\n' << m.v[VY] << '\n' << m.v[VZ] << '\n' << m.v[VW]; }
+
+istream& operator >> (istream& s, mat4& m)
+{
+ mat4 m_tmp;
+
+ s >> m_tmp[VX] >> m_tmp[VY] >> m_tmp[VZ] >> m_tmp[VW];
+ if (s)
+ m = m_tmp;
+ return s;
+}
+*/
+
+void swap(mat4 &a, mat4 &b)
+{
+ mat4 tmp(a);
+ a = b;
+ b = tmp;
+}
+
+/****************************************************************
+ * *
+ * 2D functions and 3D functions *
+ * *
+ ****************************************************************/
+
+mat3 identity2D()
+{
+ return mat3(
+ vec3(1.0, 0.0, 0.0),
+ vec3(0.0, 1.0, 0.0),
+ vec3(0.0, 0.0, 1.0));
+}
+
+mat3 translation2D(const vec2 &v)
+{
+ return mat3(
+ vec3(1.0, 0.0, v[VX]),
+ vec3(0.0, 1.0, v[VY]),
+ vec3(0.0, 0.0, 1.0));
+}
+
+mat3 rotation2D(const vec2 &Center, float angleDeg)
+{
+ float angleRad = (float) (angleDeg * M_PI / 180.0);
+ float c = (float) cos(angleRad);
+ float s = (float) sin(angleRad);
+
+ return mat3(
+ vec3(c, -s, Center[VX] * (1.0f-c) + Center[VY] * s),
+ vec3(s, c, Center[VY] * (1.0f-c) - Center[VX] * s),
+ vec3(0.0, 0.0, 1.0));
+}
+
+mat3 scaling2D(const vec2 &scaleVector)
+{
+ return mat3(
+ vec3(scaleVector[VX], 0.0, 0.0),
+ vec3(0.0, scaleVector[VY], 0.0),
+ vec3(0.0, 0.0, 1.0));
+}
+
+mat4 identity3D()
+{
+ return mat4(
+ vec4(1.0, 0.0, 0.0, 0.0),
+ vec4(0.0, 1.0, 0.0, 0.0),
+ vec4(0.0, 0.0, 1.0, 0.0),
+ vec4(0.0, 0.0, 0.0, 1.0));
+}
+
+mat4 translation3D(const vec3 &v)
+{
+ return mat4(
+ vec4(1.0, 0.0, 0.0, v[VX]),
+ vec4(0.0, 1.0, 0.0, v[VY]),
+ vec4(0.0, 0.0, 1.0, v[VZ]),
+ vec4(0.0, 0.0, 0.0, 1.0));
+}
+
+mat4 rotation3D(const vec3 &Axis, float angleDeg)
+{
+ float angleRad = (float) (angleDeg * M_PI / 180.0);
+ float c = (float) cos(angleRad);
+ float s = (float) sin(angleRad);
+ float t = 1.0f - c;
+
+ vec3 axis(Axis);
+ axis.normalize();
+
+ return mat4(
+ vec4(t * axis[VX] * axis[VX] + c,
+ t * axis[VX] * axis[VY] - s * axis[VZ],
+ t * axis[VX] * axis[VZ] + s * axis[VY],
+ 0.0),
+ vec4(t * axis[VX] * axis[VY] + s * axis[VZ],
+ t * axis[VY] * axis[VY] + c,
+ t * axis[VY] * axis[VZ] - s * axis[VX],
+ 0.0),
+ vec4(t * axis[VX] * axis[VZ] - s * axis[VY],
+ t * axis[VY] * axis[VZ] + s * axis[VX],
+ t * axis[VZ] * axis[VZ] + c,
+ 0.0),
+ vec4(0.0, 0.0, 0.0, 1.0));
+}
+
+mat4 rotation3Drad(const vec3 &Axis, float angleRad)
+{
+ float c = (float) cos(angleRad);
+ float s = (float) sin(angleRad);
+ float t = 1.0f - c;
+
+ vec3 axis(Axis);
+ axis.normalize();
+
+ return mat4(
+ vec4(t * axis[VX] * axis[VX] + c,
+ t * axis[VX] * axis[VY] - s * axis[VZ],
+ t * axis[VX] * axis[VZ] + s * axis[VY],
+ 0.0),
+ vec4(t * axis[VX] * axis[VY] + s * axis[VZ],
+ t * axis[VY] * axis[VY] + c,
+ t * axis[VY] * axis[VZ] - s * axis[VX],
+ 0.0),
+ vec4(t * axis[VX] * axis[VZ] - s * axis[VY],
+ t * axis[VY] * axis[VZ] + s * axis[VX],
+ t * axis[VZ] * axis[VZ] + c,
+ 0.0),
+ vec4(0.0, 0.0, 0.0, 1.0));
+}
+
+mat4 scaling3D(const vec3 &scaleVector)
+{
+ return mat4(
+ vec4(scaleVector[VX], 0.0, 0.0, 0.0),
+ vec4(0.0, scaleVector[VY], 0.0, 0.0),
+ vec4(0.0, 0.0, scaleVector[VZ], 0.0),
+ vec4(0.0, 0.0, 0.0, 1.0));
+}
+
+mat4 perspective3D(float d)
+{
+ return mat4(
+ vec4(1.0f, 0.0f, 0.0f, 0.0f),
+ vec4(0.0f, 1.0f, 0.0f, 0.0f),
+ vec4(0.0f, 0.0f, 1.0f, 0.0f),
+ vec4(0.0f, 0.0f, 1.0f/d, 0.0f));
+}
diff --git a/tests/box2d/glui/algebra3.h b/tests/box2d/glui/algebra3.h new file mode 100755 index 00000000..7849673d --- /dev/null +++ b/tests/box2d/glui/algebra3.h @@ -0,0 +1,475 @@ +/*
+
+ algebra3.cpp, algebra3.h - C++ Vector and Matrix Algebra routines
+
+ GLUI User Interface Toolkit (LGPL)
+ Copyright (c) 1998 Paul Rademacher
+
+ WWW: http://sourceforge.net/projects/glui/
+ Forums: http://sourceforge.net/forum/?group_id=92496
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+
+/**************************************************************************
+
+ There are three vector classes and two matrix classes: vec2, vec3,
+ vec4, mat3, and mat4.
+
+ All the standard arithmetic operations are defined, with '*'
+ for dot product of two vectors and multiplication of two matrices,
+ and '^' for cross product of two vectors.
+
+ Additional functions include length(), normalize(), homogenize for
+ vectors, and print(), set(), apply() for all classes.
+
+ There is a function transpose() for matrices, but note that it
+ does not actually change the matrix,
+
+ When multiplied with a matrix, a vector is treated as a row vector
+ if it precedes the matrix (v*M), and as a column vector if it
+ follows the matrix (M*v).
+
+ Matrices are stored in row-major form.
+
+ A vector of one dimension (2d, 3d, or 4d) can be cast to a vector
+ of a higher or lower dimension. If casting to a higher dimension,
+ the new component is set by default to 1.0, unless a value is
+ specified:
+ vec3 a(1.0, 2.0, 3.0 );
+ vec4 b( a, 4.0 ); // now b == {1.0, 2.0, 3.0, 4.0};
+ When casting to a lower dimension, the vector is homogenized in
+ the lower dimension. E.g., if a 4d {X,Y,Z,W} is cast to 3d, the
+ resulting vector is {X/W, Y/W, Z/W}. It is up to the user to
+ insure the fourth component is not zero before casting.
+
+ There are also the following function for building matrices:
+ identity2D(), translation2D(), rotation2D(),
+ scaling2D(), identity3D(), translation3D(),
+ rotation3D(), rotation3Drad(), scaling3D(),
+ perspective3D()
+
+ NOTE: When compiling for Windows, include this file first, to avoid
+ certain name conflicts
+
+ ---------------------------------------------------------------------
+
+ Author: Jean-Francois DOUEg
+ Revised: Paul Rademacher
+ Version 3.2 - Feb 1998
+ Revised: Nigel Stewart (GLUI Code Cleaning)
+
+**************************************************************************/
+
+#ifndef GLUI_ALGEBRA3_H
+#define GLUI_ALGEBRA3_H
+
+#include <cmath>
+#include <cstdio>
+#include <cstdlib>
+
+// this line defines a new type: pointer to a function which returns a
+// float and takes as argument a float
+typedef float (*V_FCT_PTR)(float);
+
+class vec2;
+class vec3;
+class vec4;
+class mat3;
+class mat4;
+
+#ifndef M_PI
+#define M_PI 3.141592654
+#endif
+
+enum {VX, VY, VZ, VW}; // axes
+enum {PA, PB, PC, PD}; // planes
+enum {RED, GREEN, BLUE, ALPHA}; // colors
+enum {KA, KD, KS, ES}; // phong coefficients
+
+/****************************************************************
+ * *
+ * 2D Vector *
+ * *
+ ****************************************************************/
+
+class vec2
+{
+ friend class vec3;
+
+protected:
+
+ float n[2];
+
+public:
+
+ // Constructors
+
+ vec2();
+ vec2(float x, float y);
+ vec2(const vec2 &v); // copy constructor
+ vec2(const vec3 &v); // cast v3 to v2
+ vec2(const vec3 &v, int dropAxis); // cast v3 to v2
+
+ // Assignment operators
+
+ vec2 &operator = (const vec2 &v); // assignment of a vec2
+ vec2 &operator += (const vec2 &v); // incrementation by a vec2
+ vec2 &operator -= (const vec2 &v); // decrementation by a vec2
+ vec2 &operator *= (float d); // multiplication by a constant
+ vec2 &operator /= (float d); // division by a constant
+
+ // special functions
+
+ float length() const; // length of a vec2
+ float length2() const; // squared length of a vec2
+ vec2 &normalize(); // normalize a vec2
+ vec2 &apply(V_FCT_PTR fct); // apply a func. to each component
+ void set(float x, float y); // set vector
+
+ float &operator [] (int i); // indexing
+ const float &operator [] (int i) const; // indexing
+
+ // friends
+
+ friend vec2 operator - (const vec2 &v); // -v1
+ friend vec2 operator + (const vec2 &a, const vec2 &b); // v1 + v2
+ friend vec2 operator - (const vec2 &a, const vec2 &b); // v1 - v2
+ friend vec2 operator * (const vec2 &a, float d); // v1 * 3.0
+ friend vec2 operator * (float d, const vec2 &a); // 3.0 * v1
+ friend vec2 operator * (const mat3 &a, const vec2 &v); // M . v
+ friend vec2 operator * (const vec2 &v, const mat3 &a); // v . M
+ friend float operator * (const vec2 &a, const vec2 &b); // dot product
+ friend vec2 operator / (const vec2 &a, float d); // v1 / 3.0
+ friend vec3 operator ^ (const vec2 &a, const vec2 &b); // cross product
+ friend int operator == (const vec2 &a, const vec2 &b); // v1 == v2 ?
+ friend int operator != (const vec2 &a, const vec2 &b); // v1 != v2 ?
+ //friend ostream& operator << (ostream& s, vec2& v); // output to stream
+ //friend istream& operator >> (istream& s, vec2& v); // input from strm.
+ friend void swap(vec2 &a, vec2 &b); // swap v1 & v2
+ friend vec2 min_vec(const vec2 &a, const vec2 &b); // min(v1, v2)
+ friend vec2 max_vec(const vec2 &a, const vec2 &b); // max(v1, v2)
+ friend vec2 prod (const vec2 &a, const vec2 &b); // term by term *
+};
+
+/****************************************************************
+ * *
+ * 3D Vector *
+ * *
+ ****************************************************************/
+
+class vec3
+{
+ friend class vec2;
+ friend class vec4;
+ friend class mat3;
+
+protected:
+
+ float n[3];
+
+public:
+
+ // Constructors
+
+ vec3();
+ vec3(float x, float y, float z);
+ vec3(const vec3 &v); // copy constructor
+ vec3(const vec2 &v); // cast v2 to v3
+ vec3(const vec2 &v, float d); // cast v2 to v3
+ vec3(const vec4 &v); // cast v4 to v3
+ vec3(const vec4 &v, int dropAxis); // cast v4 to v3
+
+ // Assignment operators
+
+ vec3 &operator = (const vec3 &v); // assignment of a vec3
+ vec3 &operator += (const vec3 &v); // incrementation by a vec3
+ vec3 &operator -= (const vec3 &v); // decrementation by a vec3
+ vec3 &operator *= (float d); // multiplication by a constant
+ vec3 &operator /= (float d); // division by a constant
+
+ // special functions
+
+ float length() const; // length of a vec3
+ float length2() const; // squared length of a vec3
+ vec3& normalize(); // normalize a vec3
+ vec3& homogenize(); // homogenize (div by Z)
+ vec3& apply(V_FCT_PTR fct); // apply a func. to each component
+ void set(float x, float y, float z); // set vector
+
+ void print(FILE *file, const char *name) const; // print vector to a file
+
+
+ float &operator [] (int i); // indexing
+ const float &operator [] (int i) const; // indexing
+
+ // friends
+
+ friend vec3 operator - (const vec3 &v); // -v1
+ friend vec3 operator + (const vec3 &a, const vec3 &b); // v1 + v2
+ friend vec3 operator - (const vec3 &a, const vec3 &b); // v1 - v2
+ friend vec3 operator * (const vec3 &a, float d); // v1 * 3.0
+ friend vec3 operator * (float d, const vec3 &a); // 3.0 * v1
+ friend vec3 operator * (const mat4 &a, const vec3 &v); // M . v
+ friend vec3 operator * (const vec3 &v, const mat4 &a); // v . M
+ friend float operator * (const vec3 &a, const vec3 &b); // dot product
+ friend vec3 operator / (const vec3 &a, float d); // v1 / 3.0
+ friend vec3 operator ^ (const vec3 &a, const vec3 &b); // cross product
+ friend int operator == (const vec3 &a, const vec3 &b); // v1 == v2 ?
+ friend int operator != (const vec3 &a, const vec3 &b); // v1 != v2 ?
+ //friend ostream& operator << (ostream& s, vec3& v); // output to stream
+ //friend istream& operator >> (istream& s, vec3& v); // input from strm.
+ friend void swap(vec3 &a, vec3 &b); // swap v1 & v2
+ friend vec3 min_vec(const vec3 &a, const vec3 &b); // min(v1, v2)
+ friend vec3 max_vec(const vec3 &a, const vec3 &b); // max(v1, v2)
+ friend vec3 prod(const vec3 &a, const vec3 &b); // term by term *
+
+ // necessary friend declarations
+
+ friend vec2 operator * (const mat3 &a, const vec2 &v); // linear transform
+ friend vec3 operator * (const mat3 &a, const vec3 &v); // linear transform
+ friend mat3 operator * (const mat3 &a, const mat3 &b); // matrix 3 product
+};
+
+/****************************************************************
+ * *
+ * 4D Vector *
+ * *
+ ****************************************************************/
+
+class vec4
+{
+ friend class vec3;
+ friend class mat4;
+
+protected:
+
+ float n[4];
+
+public:
+
+ // Constructors
+
+ vec4();
+ vec4(float x, float y, float z, float w);
+ vec4(const vec4 &v); // copy constructor
+ vec4(const vec3 &v); // cast vec3 to vec4
+ vec4(const vec3 &v, float d); // cast vec3 to vec4
+
+ // Assignment operators
+
+ vec4 &operator = (const vec4 &v); // assignment of a vec4
+ vec4 &operator += (const vec4 &v); // incrementation by a vec4
+ vec4 &operator -= (const vec4 &v); // decrementation by a vec4
+ vec4 &operator *= (float d); // multiplication by a constant
+ vec4 &operator /= (float d); // division by a constant
+
+ // special functions
+
+ float length() const; // length of a vec4
+ float length2() const; // squared length of a vec4
+ vec4 &normalize(); // normalize a vec4
+ vec4 &apply(V_FCT_PTR fct); // apply a func. to each component
+ vec4 &homogenize();
+
+ void print(FILE *file, const char *name) const; // print vector to a file
+
+ void set(float x, float y, float z, float a);
+
+ float &operator [] (int i); // indexing
+ const float &operator [] (int i) const; // indexing
+
+ // friends
+
+ friend vec4 operator - (const vec4 &v); // -v1
+ friend vec4 operator + (const vec4 &a, const vec4 &b); // v1 + v2
+ friend vec4 operator - (const vec4 &a, const vec4 &b); // v1 - v2
+ friend vec4 operator * (const vec4 &a, float d); // v1 * 3.0
+ friend vec4 operator * (float d, const vec4 &a); // 3.0 * v1
+ friend vec4 operator * (const mat4 &a, const vec4 &v); // M . v
+ friend vec4 operator * (const vec4 &v, const mat4 &a); // v . M
+ friend float operator * (const vec4 &a, const vec4 &b); // dot product
+ friend vec4 operator / (const vec4 &a, float d); // v1 / 3.0
+ friend int operator == (const vec4 &a, const vec4 &b); // v1 == v2 ?
+ friend int operator != (const vec4 &a, const vec4 &b); // v1 != v2 ?
+ //friend ostream& operator << (ostream& s, vec4& v); // output to stream
+ //friend istream& operator >> (istream& s, vec4& v); // input from strm.
+ friend void swap(vec4 &a, vec4 &b); // swap v1 & v2
+ friend vec4 min_vec(const vec4 &a, const vec4 &b); // min(v1, v2)
+ friend vec4 max_vec(const vec4 &a, const vec4 &b); // max(v1, v2)
+ friend vec4 prod (const vec4 &a, const vec4 &b); // term by term *
+
+ // necessary friend declarations
+
+ friend vec3 operator * (const mat4 &a, const vec3 &v); // linear transform
+ friend mat4 operator * (const mat4 &a, const mat4 &b); // matrix 4 product
+};
+
+/****************************************************************
+ * *
+ * 3x3 Matrix *
+ * *
+ ****************************************************************/
+
+class mat3
+{
+protected:
+
+ vec3 v[3];
+
+public:
+
+ // Constructors
+
+ mat3();
+ mat3(const vec3 &v0, const vec3 &v1, const vec3 &v2);
+ mat3(const mat3 &m);
+
+ // Assignment operators
+
+ mat3 &operator = (const mat3 &m); // assignment of a mat3
+ mat3 &operator += (const mat3 &m); // incrementation by a mat3
+ mat3 &operator -= (const mat3 &m); // decrementation by a mat3
+ mat3 &operator *= (float d); // multiplication by a constant
+ mat3 &operator /= (float d); // division by a constant
+
+ // special functions
+
+ mat3 transpose() const; // transpose
+ mat3 inverse() const; // inverse
+ mat3 &apply(V_FCT_PTR fct); // apply a func. to each element
+
+ void print(FILE *file, const char *name ) const; // print matrix to a file
+
+ void set(const vec3 &v0, const vec3 &v1, const vec3 &v2);
+
+ vec3 &operator [] (int i); // indexing
+ const vec3 &operator [] (int i) const; // indexing
+
+ // friends
+
+ friend mat3 operator - (const mat3 &a); // -m1
+ friend mat3 operator + (const mat3 &a, const mat3 &b); // m1 + m2
+ friend mat3 operator - (const mat3 &a, const mat3 &b); // m1 - m2
+ friend mat3 operator * (const mat3 &a, const mat3 &b); // m1 * m2
+ friend mat3 operator * (const mat3 &a, float d); // m1 * 3.0
+ friend mat3 operator * (float d, const mat3 &a); // 3.0 * m1
+ friend mat3 operator / (const mat3 &a, float d); // m1 / 3.0
+ friend int operator == (const mat3 &a, const mat3 &b); // m1 == m2 ?
+ friend int operator != (const mat3 &a, const mat3 &b); // m1 != m2 ?
+ //friend ostream& operator << (ostream& s, mat3& m); // output to stream
+ //friend istream& operator >> (istream& s, mat3& m); // input from strm.
+ friend void swap(mat3 &a, mat3 &b); // swap m1 & m2
+
+ // necessary friend declarations
+
+ friend vec3 operator * (const mat3 &a, const vec3 &v); // linear transform
+ friend vec2 operator * (const mat3 &a, const vec2 &v); // linear transform
+};
+
+/****************************************************************
+ * *
+ * 4x4 Matrix *
+ * *
+ ****************************************************************/
+
+class mat4
+{
+protected:
+
+ vec4 v[4];
+
+public:
+
+ // Constructors
+
+ mat4();
+ mat4(const vec4 &v0, const vec4 &v1, const vec4 &v2, const vec4 &v3);
+ mat4(const mat4 &m);
+ mat4(float a00, float a01, float a02, float a03,
+ float a10, float a11, float a12, float a13,
+ float a20, float a21, float a22, float a23,
+ float a30, float a31, float a32, float a33 );
+
+
+ // Assignment operators
+
+ mat4 &operator = (const mat4 &m); // assignment of a mat4
+ mat4 &operator += (const mat4 &m); // incrementation by a mat4
+ mat4 &operator -= (const mat4 &m); // decrementation by a mat4
+ mat4 &operator *= (float d); // multiplication by a constant
+ mat4 &operator /= (float d); // division by a constant
+
+ // special functions
+
+ mat4 transpose() const; // transpose
+ mat4 inverse() const; // inverse
+ mat4 &apply(V_FCT_PTR fct); // apply a func. to each element
+
+ void print(FILE *file, const char *name) const; // print matrix to a file
+
+ vec4 &operator [] (int i); // indexing
+ const vec4 &operator [] (int i) const; // indexing
+
+ void swap_rows(int i, int j); // swap rows i and j
+ void swap_cols(int i, int j); // swap cols i and j
+
+ // friends
+
+ friend mat4 operator - (const mat4 &a); // -m1
+ friend mat4 operator + (const mat4 &a, const mat4 &b); // m1 + m2
+ friend mat4 operator - (const mat4 &a, const mat4 &b); // m1 - m2
+ friend mat4 operator * (const mat4 &a, const mat4 &b); // m1 * m2
+ friend mat4 operator * (const mat4 &a, float d); // m1 * 4.0
+ friend mat4 operator * (float d, const mat4 &a); // 4.0 * m1
+ friend mat4 operator / (const mat4 &a, float d); // m1 / 3.0
+ friend int operator == (const mat4 &a, const mat4 &b); // m1 == m2 ?
+ friend int operator != (const mat4 &a, const mat4 &b); // m1 != m2 ?
+ //friend ostream& operator << (ostream& s, mat4& m); // output to stream
+ //friend istream& operator >> (istream& s, mat4& m); // input from strm.
+ friend void swap(mat4 &a, mat4 &b); // swap m1 & m2
+
+ // necessary friend declarations
+
+ friend vec4 operator * (const mat4 &a, const vec4 &v); // linear transform
+ //friend vec4 operator * (const vec4& v, const mat4& a); // linear transform
+ friend vec3 operator * (const mat4 &a, const vec3 &v); // linear transform
+ friend vec3 operator * (const vec3 &v, const mat4 &a); // linear transform
+};
+
+/****************************************************************
+ * *
+ * 2D functions and 3D functions *
+ * *
+ ****************************************************************/
+
+mat3 identity2D (); // identity 2D
+mat3 translation2D(const vec2 &v); // translation 2D
+mat3 rotation2D (const vec2 &Center, float angleDeg); // rotation 2D
+mat3 scaling2D (const vec2 &scaleVector); // scaling 2D
+mat4 identity3D (); // identity 3D
+mat4 translation3D(const vec3 &v); // translation 3D
+mat4 rotation3D (const vec3 &Axis, float angleDeg); // rotation 3D
+mat4 rotation3Drad(const vec3 &Axis, float angleRad); // rotation 3D
+mat4 scaling3D (const vec3 &scaleVector); // scaling 3D
+mat4 perspective3D(float d); // perspective 3D
+
+vec3 operator * (const vec3 &v, const mat3 &a);
+vec2 operator * (const vec2 &v, const mat3 &a);
+vec3 operator * (const vec3 &v, const mat4 &a);
+vec4 operator * (const vec4 &v, const mat4 &a);
+
+#endif
diff --git a/tests/box2d/glui/arcball.cpp b/tests/box2d/glui/arcball.cpp new file mode 100755 index 00000000..d233c7fc --- /dev/null +++ b/tests/box2d/glui/arcball.cpp @@ -0,0 +1,237 @@ +/**********************************************************************
+
+ arcball.cpp
+
+
+ --------------------------------------------------
+
+ GLUI User Interface Toolkit (LGPL)
+ Copyright (c) 1998 Paul Rademacher
+ Feb 1998, Paul Rademacher (rademach@cs.unc.edu)
+ Oct 2003, Nigel Stewart - GLUI Code Cleaning
+
+ WWW: http://sourceforge.net/projects/glui/
+ Forums: http://sourceforge.net/forum/?group_id=92496
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+**********************************************************************/
+
+#include "arcball.h"
+
+#include <cstdio>
+
+
+/**************************************** Arcball::Arcball() ****/
+/* Default (void) constructor for Arcball */
+
+Arcball::Arcball()
+{
+ rot_ptr = &rot;
+ init();
+}
+
+/**************************************** Arcball::Arcball() ****/
+/* Takes as argument a mat4 to use instead of the internal rot */
+
+Arcball::Arcball(mat4 *mtx)
+{
+ rot_ptr = mtx;
+}
+
+
+/**************************************** Arcball::Arcball() ****/
+/* A constructor that accepts the screen center and arcball radius*/
+
+Arcball::Arcball(const vec2 &_center, float _radius)
+{
+ rot_ptr = &rot;
+ init();
+ set_params(_center, _radius);
+}
+
+
+/************************************** Arcball::set_params() ****/
+
+void Arcball::set_params(const vec2 &_center, float _radius)
+{
+ center = _center;
+ radius = _radius;
+}
+
+/*************************************** Arcball::init() **********/
+
+void Arcball::init()
+{
+ center.set( 0.0, 0.0 );
+ radius = 1.0;
+ q_now = quat_identity();
+ *rot_ptr = identity3D();
+ q_increment = quat_identity();
+ rot_increment = identity3D();
+ is_mouse_down = false;
+ is_spinning = false;
+ damp_factor = 0.0;
+ zero_increment = true;
+}
+
+/*********************************** Arcball::mouse_to_sphere() ****/
+
+vec3 Arcball::mouse_to_sphere(const vec2 &p)
+{
+ float mag;
+ vec2 v2 = (p - center) / radius;
+ vec3 v3( v2[0], v2[1], 0.0 );
+
+ mag = v2*v2;
+
+ if ( mag > 1.0 )
+ v3.normalize();
+ else
+ v3[VZ] = (float) sqrt( 1.0 - mag );
+
+ /* Now we add constraints - X takes precedence over Y */
+ if ( constraint_x )
+ {
+ v3 = constrain_vector( v3, vec3( 1.0, 0.0, 0.0 ));
+ }
+ else if ( constraint_y )
+ {
+ v3 = constrain_vector( v3, vec3( 0.0, 1.0, 0.0 ));
+ }
+
+ return v3;
+}
+
+
+/************************************ Arcball::constrain_vector() ****/
+
+vec3 Arcball::constrain_vector(const vec3 &vector, const vec3 &axis)
+{
+ return (vector-(vector*axis)*axis).normalize();
+}
+
+/************************************ Arcball::mouse_down() **********/
+
+void Arcball::mouse_down(int x, int y)
+{
+ down_pt.set( (float)x, (float) y );
+ is_mouse_down = true;
+
+ q_increment = quat_identity();
+ rot_increment = identity3D();
+ zero_increment = true;
+}
+
+
+/************************************ Arcball::mouse_up() **********/
+
+void Arcball::mouse_up()
+{
+ q_now = q_drag * q_now;
+ is_mouse_down = false;
+}
+
+
+/********************************** Arcball::mouse_motion() **********/
+
+void Arcball::mouse_motion(int x, int y, int shift, int ctrl, int alt)
+{
+ /* Set the X constraint if CONTROL key is pressed, Y if ALT key */
+ set_constraints( ctrl != 0, alt != 0 );
+
+ vec2 new_pt( (float)x, (float) y );
+ vec3 v0 = mouse_to_sphere( down_pt );
+ vec3 v1 = mouse_to_sphere( new_pt );
+
+ vec3 cross = v0^v1;
+
+ q_drag.set( cross, v0 * v1 );
+
+ // *rot_ptr = (q_drag * q_now).to_mat4();
+ mat4 temp = q_drag.to_mat4();
+ *rot_ptr = *rot_ptr * temp;
+
+ down_pt = new_pt;
+
+ /* We keep a copy of the current incremental rotation (= q_drag) */
+ q_increment = q_drag;
+ rot_increment = q_increment.to_mat4();
+
+ set_constraints(false, false);
+
+ if ( q_increment.s < .999999 )
+ {
+ is_spinning = true;
+ zero_increment = false;
+ }
+ else
+ {
+ is_spinning = false;
+ zero_increment = true;
+ }
+}
+
+
+/********************************** Arcball::mouse_motion() **********/
+
+void Arcball::mouse_motion(int x, int y)
+{
+ mouse_motion(x, y, 0, 0, 0);
+}
+
+
+/***************************** Arcball::set_constraints() **********/
+
+void Arcball::set_constraints(bool _constraint_x, bool _constraint_y)
+{
+ constraint_x = _constraint_x;
+ constraint_y = _constraint_y;
+}
+
+/***************************** Arcball::idle() *********************/
+
+void Arcball::idle()
+{
+ if (is_mouse_down)
+ {
+ is_spinning = false;
+ zero_increment = true;
+ }
+
+ if (damp_factor < 1.0f)
+ q_increment.scale_angle(1.0f - damp_factor);
+
+ rot_increment = q_increment.to_mat4();
+
+ if (q_increment.s >= .999999f)
+ {
+ is_spinning = false;
+ zero_increment = true;
+ }
+}
+
+
+/************************ Arcball::set_damping() *********************/
+
+void Arcball::set_damping(float d)
+{
+ damp_factor = d;
+}
+
+
+
+
+
diff --git a/tests/box2d/glui/arcball.h b/tests/box2d/glui/arcball.h new file mode 100755 index 00000000..ef69afc9 --- /dev/null +++ b/tests/box2d/glui/arcball.h @@ -0,0 +1,97 @@ +/**********************************************************************
+
+ arcball.h
+
+ GLUI User Interface Toolkit (LGPL)
+ Copyright (c) 1998 Paul Rademacher
+ Feb 1998, Paul Rademacher (rademach@cs.unc.edu)
+ Oct 2003, Nigel Stewart - GLUI Code Cleaning
+
+
+ WWW: http://sourceforge.net/projects/glui/
+ Forums: http://sourceforge.net/forum/?group_id=92496
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ ---------------------------------------------------------------------
+
+ A C++ class that implements the Arcball, as described by Ken
+ Shoemake in Graphics Gems IV.
+ This class takes as input mouse events (mouse down, mouse drag,
+ mouse up), and creates the appropriate quaternions and 4x4 matrices
+ to represent the rotation given by the mouse.
+
+ This class is used as follows:
+ - initialize [either in the constructor or with set_params()], the
+ center position (x,y) of the arcball on the screen, and the radius
+ - on mouse down, call mouse_down(x,y) with the mouse position
+ - as the mouse is dragged, repeatedly call mouse_motion() with the
+ current x and y positions. One can optionally pass in the current
+ state of the SHIFT, ALT, and CONTROL keys (passing zero if keys
+ are not pressed, non-zero otherwise), which constrains
+ the rotation to certain axes (X for CONTROL, Y for ALT).
+ - when the mouse button is released, call mouse_up()
+
+ Axis constraints can also be explicitly set with the
+ set_constraints() function.
+
+ The current rotation is stored in the 4x4 float matrix 'rot'.
+ It is also stored in the quaternion 'q_now'.
+
+**********************************************************************/
+
+#ifndef GLUI_ARCBALL_H
+#define GLUI_ARCBALL_H
+
+#include "glui_internal.h"
+#include "algebra3.h"
+#include "quaternion.h"
+
+class Arcball
+{
+public:
+ Arcball();
+ Arcball(mat4 *mtx);
+ Arcball(const vec2 ¢er, float radius);
+
+ void set_damping(float d);
+ void idle();
+ void mouse_down(int x, int y);
+ void mouse_up();
+ void mouse_motion(int x, int y, int shift, int ctrl, int alt);
+ void mouse_motion(int x, int y);
+ void set_constraints(bool constrain_x, bool constrain_y);
+ void set_params(const vec2 ¢er, float radius);
+ void reset_mouse();
+ void init();
+
+ vec3 constrain_vector(const vec3 &vector, const vec3 &axis);
+ vec3 mouse_to_sphere(const vec2 &p);
+
+ //public:
+ int is_mouse_down; /* true for down, false for up */
+ int is_spinning;
+ quat q_now, q_down, q_drag, q_increment;
+ vec2 down_pt;
+ mat4 rot, rot_increment;
+ mat4 *rot_ptr;
+
+ bool constraint_x, constraint_y;
+ vec2 center;
+ float radius, damp_factor;
+ int zero_increment;
+};
+
+#endif
diff --git a/tests/box2d/glui/glui.cpp b/tests/box2d/glui/glui.cpp new file mode 100755 index 00000000..221e68d2 --- /dev/null +++ b/tests/box2d/glui/glui.cpp @@ -0,0 +1,2105 @@ +/****************************************************************************
+
+ GLUI User Interface Toolkit (LGPL)
+ ---------------------------
+
+ glui.cpp
+
+ --------------------------------------------------
+
+ Copyright (c) 1998 Paul Rademacher
+
+ WWW: http://sourceforge.net/projects/glui/
+ Forums: http://sourceforge.net/forum/?group_id=92496
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+#include "glui_internal_control.h"
+
+
+/**
+ Note: moving this routine here from glui_add_controls.cpp prevents the linker
+ from touching glui_add_controls.o in non-deprecated programs, which
+ descreases the linked size of small GLUI programs substantially (100K+). (OSL 2006/06)
+*/
+void GLUI_Node::add_child_to_control(GLUI_Node *parent,GLUI_Control *child)
+{
+ GLUI_Control *parent_control;
+
+ /*** Collapsible nodes have to be handled differently, b/c the first and
+ last children are swapped in and out ***/
+ parent_control = ((GLUI_Control*)parent);
+ if ( parent_control->collapsible == true ) {
+ if ( NOT parent_control->is_open ) {
+ /** Swap in the original first and last children **/
+ parent_control->child_head = parent_control->collapsed_node.child_head;
+ parent_control->child_tail = parent_control->collapsed_node.child_tail;
+
+ /*** Link this control ***/
+ child->link_this_to_parent_last( parent_control );
+
+ /** Swap the children back out ***/
+ parent_control->collapsed_node.child_head = parent_control->child_head;
+ parent_control->collapsed_node.child_tail = parent_control->child_tail;
+ parent_control->child_head = NULL;
+ parent_control->child_tail = NULL;
+ }
+ else {
+ child->link_this_to_parent_last( parent_control );
+ }
+ }
+ else {
+ child->link_this_to_parent_last( parent_control );
+ }
+ child->glui = (GLUI*) parent_control->glui;
+ child->update_size();
+ child->enabled = parent_control->enabled;
+ child->glui->refresh();
+
+ /** Now set the 'hidden' var based on the parent **/
+ if ( parent_control->hidden OR
+ (parent_control->collapsible AND NOT parent_control->is_open ) )
+ {
+ child->hidden = true;
+ }
+}
+
+
+/************************************ GLUI_Node::add_control() **************/
+
+int GLUI_Node::add_control( GLUI_Control *child )
+{
+ add_child_to_control(this,child);
+ return true;
+}
+
+/************************************ GLUI_Main::add_control() **************/
+
+int GLUI_Main::add_control( GLUI_Node *parent, GLUI_Control *control )
+{
+ add_child_to_control(parent,control);
+ return true;
+}
+
+
+
+/*** This object must be used to create a GLUI ***/
+
+GLUI_Master_Object GLUI_Master;
+
+/************************************ finish_drawing() ***********
+ Probably a silly routine. Called after all event handling callbacks.
+*/
+
+static void finish_drawing(void)
+{
+ glFinish();
+}
+
+/************************************ GLUI_CB::operator()() ************/
+void GLUI_CB::operator()(GLUI_Control*ctrl) const
+{
+ if (idCB) idCB(ctrl->user_id);
+ if (objCB) objCB(ctrl);
+}
+
+
+/************************************************ GLUI::GLUI() **********/
+
+int GLUI::init( const char *text, long flags, int x, int y, int parent_window )
+{
+ int old_glut_window;
+
+ this->flags = flags;
+
+ window_name = text;
+
+ buffer_mode = buffer_back; ///< New smooth way
+ //buffer_mode = buffer_front; ///< Old flickery way (a bit faster).
+
+ /*** We copy over the current window callthroughs ***/
+ /*** (I think this might actually only be needed for subwindows) ***/
+ /* glut_keyboard_CB = GLUI_Master.glut_keyboard_CB;
+ glut_reshape_CB = GLUI_Master.glut_reshape_CB;
+ glut_special_CB = GLUI_Master.glut_special_CB;
+ glut_mouse_CB = GLUI_Master.glut_mouse_CB;*/
+
+
+ if ( (flags & GLUI_SUBWINDOW) != GLUI_SUBWINDOW ) { /* not a subwindow, creating a new top-level window */
+ old_glut_window = glutGetWindow();
+
+ create_standalone_window( window_name.c_str(), x, y );
+ setup_default_glut_callbacks();
+
+ if ( old_glut_window > 0 )
+ glutSetWindow( old_glut_window );
+
+ top_level_glut_window_id = glut_window_id;
+ }
+ else /* *is* a subwindow */
+ {
+ old_glut_window = glutGetWindow();
+
+ create_subwindow( parent_window, flags );
+ setup_default_glut_callbacks();
+
+ if ( old_glut_window > 0 )
+ glutSetWindow( old_glut_window );
+
+ top_level_glut_window_id = parent_window;
+
+ /*
+ glutReshapeFunc( glui_parent_window_reshape_func );
+ glutSpecialFunc( glui_parent_window_special_func );
+ glutKeyboardFunc( glui_parent_window_keyboard_func );
+ glutMouseFunc( glui_parent_window_mouse_func );
+ */
+
+ }
+
+ return true;
+}
+
+
+/**************************** GLUI_Main::create_standalone_window() ********/
+
+void GLUI_Main::create_standalone_window( const char *name, int x, int y )
+{
+ glutInitWindowSize( 100, 100 );
+ if ( x >= 0 OR y >= 0 )
+ glutInitWindowPosition( x, y );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );
+ glut_window_id = glutCreateWindow( name );
+}
+
+
+/******************************** GLUI_Main::create_subwindow() **********/
+
+void GLUI_Main::create_subwindow( int parent_window, int window_alignment )
+{
+ glut_window_id = glutCreateSubWindow(parent_window, 0,0, 100, 100);
+ this->parent_window = parent_window;
+}
+
+
+/**************************** GLUI_Main::setup_default_glut_callbacks() *****/
+
+void GLUI_Main::setup_default_glut_callbacks( void )
+{
+ glutDisplayFunc( glui_display_func );
+ glutReshapeFunc( glui_reshape_func );
+ glutKeyboardFunc( glui_keyboard_func );
+ glutSpecialFunc( glui_special_func );
+ glutMouseFunc( glui_mouse_func );
+ glutMotionFunc( glui_motion_func );
+ glutPassiveMotionFunc( glui_passive_motion_func );
+ glutEntryFunc( glui_entry_func );
+ glutVisibilityFunc( glui_visibility_func );
+ /* glutIdleFunc( glui_idle_func ); // FIXME! 100% CPU usage! */
+}
+
+
+/********************************************** glui_display_func() ********/
+
+void glui_display_func(void)
+{
+ GLUI *glui;
+
+ /* printf( "display func\n" ); */
+
+ glui = GLUI_Master.find_glui_by_window_id( glutGetWindow() );
+
+ if ( glui ) {
+ glui->display();
+ /*
+ Do not do anything after the above line, b/c the GLUI
+ window might have just closed itself
+ */
+ }
+}
+
+
+/********************************************** glui_reshape_func() ********/
+
+void glui_reshape_func(int w,int h )
+{
+ GLUI *glui;
+ GLUI_Glut_Window *glut_window;
+ int current_window;
+
+ /*printf( "glui_reshape_func(): %d w/h: %d/%d\n", glutGetWindow(), w, h ); */
+
+ current_window = glutGetWindow();
+
+ /*** First check if this is main glut window ***/
+ glut_window = GLUI_Master.find_glut_window( current_window );
+ if ( glut_window ) {
+ if (glut_window->glut_reshape_CB) glut_window->glut_reshape_CB(w,h);
+
+ /*** Now send reshape events to all subwindows ***/
+ glui = (GLUI*) GLUI_Master.gluis.first_child();
+ while(glui) {
+ if ( TEST_AND( glui->flags, GLUI_SUBWINDOW) AND
+ glui->parent_window == current_window ) {
+ glutSetWindow( glui->get_glut_window_id());
+ glui->reshape(w,h);
+ /* glui->check_subwindow_position(); */
+ }
+ glui = (GLUI*) glui->next();
+ }
+ }
+ else {
+ /*** A standalone GLUI window ***/
+
+ glui = GLUI_Master.find_glui_by_window_id( current_window );
+
+ if ( glui ) {
+ glui->reshape(w,h);
+ }
+ }
+}
+
+/********************************************** glui_keyboard_func() ********/
+
+void glui_keyboard_func(unsigned char key, int x, int y)
+{
+ GLUI *glui;
+ int current_window;
+ GLUI_Glut_Window *glut_window;
+
+ current_window = glutGetWindow();
+ glut_window = GLUI_Master.find_glut_window( current_window );
+
+ /*printf( "key: %d\n", current_window ); */
+
+ if ( glut_window ) { /** Was event in a GLUT window? **/
+ if ( GLUI_Master.active_control_glui AND GLUI_Master.active_control ) {
+ glutSetWindow( GLUI_Master.active_control_glui->get_glut_window_id() );
+
+ GLUI_Master.active_control_glui->keyboard(key,x,y);
+ finish_drawing();
+
+ glutSetWindow( current_window );
+ }
+ else {
+ if (glut_window->glut_keyboard_CB)
+ glut_window->glut_keyboard_CB( key, x, y );
+ }
+ }
+ else { /*** Nope, event was in a standalone GLUI window **/
+ glui = GLUI_Master.find_glui_by_window_id( glutGetWindow() );
+
+ if ( glui ) {
+ glui->keyboard(key,x,y);
+ finish_drawing();
+ }
+ }
+}
+
+
+/************************************************ glui_special_func() ********/
+
+void glui_special_func(int key, int x, int y)
+{
+ GLUI *glui;
+ int current_window;
+ GLUI_Glut_Window *glut_window;
+
+ current_window = glutGetWindow();
+ glut_window = GLUI_Master.find_glut_window( current_window );
+
+ if (glut_window) /** Was event in a GLUT window? **/
+ {
+ if ( GLUI_Master.active_control_glui AND GLUI_Master.active_control )
+ {
+ glutSetWindow( GLUI_Master.active_control_glui->get_glut_window_id() );
+
+ GLUI_Master.active_control_glui->special(key,x,y);
+ finish_drawing();
+
+ glutSetWindow( current_window );
+ }
+ else
+ {
+ if (glut_window->glut_special_CB)
+ glut_window->glut_special_CB( key, x, y );
+ }
+ }
+ else /*** Nope, event was in a standalone GLUI window **/
+ {
+ glui = GLUI_Master.find_glui_by_window_id(glutGetWindow());
+
+ if ( glui )
+ {
+ glui->special(key,x,y);
+ finish_drawing();
+ }
+ }
+}
+
+/********************************************** glui_mouse_func() ********/
+
+void glui_mouse_func(int button, int state, int x, int y)
+{
+ GLUI *glui;
+ int current_window;
+ GLUI_Glut_Window *glut_window;
+
+ current_window = glutGetWindow();
+ glut_window = GLUI_Master.find_glut_window( current_window );
+
+ if ( glut_window ) { /** Was event in a GLUT window? **/
+ if ( GLUI_Master.active_control_glui != NULL )
+ GLUI_Master.active_control_glui->deactivate_current_control();
+
+ if (glut_window->glut_mouse_CB)
+ glut_window->glut_mouse_CB( button, state, x, y );
+ finish_drawing();
+ }
+ else { /** Nope - event was in a GLUI standalone window **/
+ glui = GLUI_Master.find_glui_by_window_id( glutGetWindow() );
+ if ( glui ) {
+ glui->passive_motion( 0,0 );
+ glui->mouse( button, state, x, y );
+ finish_drawing();
+ }
+ }
+}
+
+
+/********************************************** glui_motion_func() ********/
+
+void glui_motion_func(int x, int y)
+{
+ GLUI *glui;
+
+ glui = GLUI_Master.find_glui_by_window_id( glutGetWindow() );
+
+ if ( glui ) {
+ glui->motion(x,y);
+ finish_drawing();
+ }
+
+}
+
+
+/**************************************** glui_passive_motion_func() ********/
+
+void glui_passive_motion_func(int x, int y)
+{
+ GLUI *glui;
+
+ glui = GLUI_Master.find_glui_by_window_id( glutGetWindow() );
+
+ if ( glui ) {
+ glui->passive_motion(x,y);
+ finish_drawing();
+ }
+}
+
+
+/********************************************** glui_entry_func() ********/
+
+void glui_entry_func(int state)
+{
+ GLUI *glui;
+
+ glui = GLUI_Master.find_glui_by_window_id( glutGetWindow() );
+
+ if ( glui ) {
+ glui->entry(state);
+ }
+}
+
+
+/******************************************** glui_visibility_func() ********/
+
+void glui_visibility_func(int state)
+{
+ GLUI *glui;
+
+ /* printf( "IN GLUI VISIBILITY()\n" ); */
+ /* fflush( stdout ); */
+
+ glui = GLUI_Master.find_glui_by_window_id( glutGetWindow() );
+
+ if ( glui ) {
+ glui->visibility(state);
+ }
+}
+
+
+/********************************************** glui_idle_func() ********/
+/* Send idle event to each glui, then to the main window */
+
+void glui_idle_func(void)
+{
+ GLUI *glui;
+
+ glui = (GLUI*) GLUI_Master.gluis.first_child();
+ while( glui ) {
+ glui->idle();
+ finish_drawing();
+
+ glui = (GLUI*) glui->next();
+ }
+
+ if ( GLUI_Master.glut_idle_CB ) {
+ /*** We set the current glut window before calling the user's
+ idle function, even though glut explicitly says the window id is
+ undefined in an idle callback. ***/
+
+ /** Check what the current window is first ***/
+
+ /*** Arbitrarily set the window id to the main gfx window of the
+ first glui window ***/
+ /* int current_window, new_window; */
+ /* current_window = glutGetWindow(); */
+ /* if (GLUI_Master.gluis.first_child() != NULL ) { */
+ /* new_window = ((GLUI_Main*)GLUI_Master.gluis.first_child())-> */
+ /* main_gfx_window_id; */
+ /* if ( new_window > 0 AND new_window != old_window ) { */
+ /* --- Window is changed only if its not already the current window ---*/
+ /* glutSetWindow( new_window ); */
+ /* } */
+ /*} */
+
+ GLUI_Master.glut_idle_CB();
+ }
+}
+
+/*********************************** GLUI_Master_Object::GLUI_Master_Object() ******/
+
+GLUI_Master_Object::GLUI_Master_Object()
+: glui_id_counter(1),
+ glut_idle_CB(NULL)
+{
+}
+
+GLUI_Master_Object::~GLUI_Master_Object()
+{
+}
+
+/*********************************** GLUI_Master_Object::create_glui() ******/
+
+GLUI *GLUI_Master_Object::create_glui( const char *name, long flags,int x,int y )
+{
+ GLUI *new_glui = new GLUI;
+ new_glui->init( name, flags, x, y, -1 );
+ new_glui->link_this_to_parent_last( &this->gluis );
+ return new_glui;
+}
+
+
+/************************** GLUI_Master_Object::create_glui_subwindow() ******/
+
+GLUI *GLUI_Master_Object::create_glui_subwindow( int parent_window,
+ long flags )
+{
+ GLUI *new_glui = new GLUI;
+ GLUI_String new_name;
+ glui_format_str( new_name, "subwin_%p", this );
+
+ new_glui->init( new_name.c_str(), flags | GLUI_SUBWINDOW, 0,0,
+ parent_window );
+ new_glui->main_panel->set_int_val( GLUI_PANEL_EMBOSSED );
+ new_glui->link_this_to_parent_last( &this->gluis );
+ return new_glui;
+}
+
+
+/********************** GLUI_Master_Object::find_glui_by_window_id() ********/
+
+GLUI *GLUI_Master_Object::find_glui_by_window_id( int window_id )
+{
+ GLUI_Node *node;
+
+ node = gluis.first_child();
+ while( node ) {
+ if ( ((GLUI*)node)->get_glut_window_id() == window_id )
+ return (GLUI*) node;
+
+ node = node->next();
+ }
+ return NULL;
+}
+
+
+/******************************************** GLUI_Main::display() **********/
+
+void GLUI_Main::display( void )
+{
+ int win_w, win_h;
+
+ /* SUBTLE: on freeGLUT, the correct window is always already set.
+ But older versions of GLUT need this call, or else subwindows
+ don't update properly when resizing or damage-painting.
+ */
+ glutSetWindow( glut_window_id );
+
+ /* Set up OpenGL state for widget drawing */
+ glDisable( GL_DEPTH_TEST );
+ glCullFace( GL_BACK );
+ glDisable( GL_CULL_FACE );
+ glDisable( GL_LIGHTING );
+ set_current_draw_buffer();
+
+ /**** This function is used as a special place to do 'safe' processing,
+ e.g., handling window close requests.
+ That is, we can't close the window directly in the callback, so
+ we set a flag, post a redisplay message (which eventually calls
+ this function), then close the window safely in here. ****/
+ if ( closing ) {
+ close_internal();
+ return;
+ }
+
+ /* if ( TEST_AND( this->flags, GLUI_SUBWINDOW ))
+ check_subwindow_position();
+ */
+
+ win_w = glutGet( GLUT_WINDOW_WIDTH );
+ win_h = glutGet( GLUT_WINDOW_HEIGHT );
+
+ /*** Check here if the window needs resizing ***/
+ if ( win_w != main_panel->w OR win_h != main_panel->h ) {
+ glutReshapeWindow( main_panel->w, main_panel->h );
+ return;
+ }
+
+ /******* Draw GLUI window ******/
+ glClearColor( (float) bkgd_color.r / 255.0,
+ (float) bkgd_color.g / 255.0,
+ (float) bkgd_color.b / 255.0,
+ 1.0 );
+ glClear( GL_COLOR_BUFFER_BIT ); /* | GL_DEPTH_BUFFER_BIT ); */
+
+ set_ortho_projection();
+
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+
+ /*** Rotate image so y increases downward.
+ In normal OpenGL, y increases upward. ***/
+ glTranslatef( (float) win_w/2.0, (float) win_h/2.0, 0.0 );
+ glRotatef( 180.0, 0.0, 1.0, 0.0 );
+ glRotatef( 180.0, 0.0, 0.0, 1.0 );
+ glTranslatef( (float) -win_w/2.0, (float) -win_h/2.0, 0.0 );
+
+ // Recursively draw the main panel
+ // main_panel->draw_bkgd_box( 0, 0, win_w, win_h );
+ main_panel->draw_recursive( 0, 0 );
+
+ switch (buffer_mode) {
+ case buffer_front: /* Make sure drawing gets to screen */
+ glFlush();
+ break;
+ case buffer_back: /* Bring back buffer to front */
+ glutSwapBuffers();
+ break;
+ }
+}
+
+
+
+
+/*************************************** _glutBitmapWidthString() **********/
+
+int _glutBitmapWidthString( void *font, const char *s )
+{
+ const char *p = s;
+ int width = 0;
+
+ while( *p != '\0' ) {
+ width += glutBitmapWidth( font, *p );
+ p++;
+ }
+
+ return width;
+}
+
+/************************************ _glutBitmapString *********************/
+/* Displays the contents of a string using GLUT's bitmap character function */
+/* Does not handle newlines */
+
+void _glutBitmapString( void *font, const char *s )
+{
+ const char *p = s;
+
+ while( *p != '\0' ) {
+ glutBitmapCharacter( font, *p );
+ p++;
+ }
+}
+
+
+
+/****************************** GLUI_Main::reshape() **************/
+
+void GLUI_Main::reshape( int reshape_w, int reshape_h )
+{
+ int new_w, new_h;
+
+ pack_controls();
+
+ new_w = main_panel->w;/* + 1; */
+ new_h = main_panel->h;/* + 1; */
+
+ if ( reshape_w != new_w OR reshape_h != new_h ) {
+ this->w = new_w;
+ this->h = new_h;
+
+ glutReshapeWindow( new_w, new_h );
+ }
+ else {
+ }
+
+ if ( TEST_AND( this->flags, GLUI_SUBWINDOW ) ) {
+ check_subwindow_position();
+
+ /***** if ( TEST_AND(this->flags,GLUI_SUBWINDOW_LEFT )) {
+ }
+ else if ( TEST_AND(this->flags,GLUI_SUBWINDOW_LEFT )) {
+ }
+ else if ( TEST_AND(this->flags,GLUI_SUBWINDOW_LEFT )) {
+ }
+ else if ( TEST_AND(this->flags,GLUI_SUBWINDOW_RIGHT )) {
+ }
+ ****/
+ }
+
+ glViewport( 0, 0, new_w, new_h );
+
+ /* printf( "%d: %d\n", glutGetWindow(), this->flags ); */
+
+ glutPostRedisplay();
+}
+
+
+/****************************** GLUI_Main::keyboard() **************/
+
+void GLUI_Main::keyboard(unsigned char key, int x, int y)
+{
+ GLUI_Control *new_control;
+
+ curr_modifiers = glutGetModifiers();
+
+ /*** If it's a tab or shift tab, we don't pass it on to the controls.
+ Instead, we use it to cycle through active controls ***/
+ if ( key == '\t' AND !mouse_button_down AND
+ (!active_control || !active_control->wants_tabs())) {
+ if ( curr_modifiers & GLUT_ACTIVE_SHIFT ) {
+ new_control = find_prev_control( active_control );
+ }
+ else {
+ new_control = find_next_control( active_control );
+ }
+
+ /* if ( new_control )
+ printf( "new_control: %s\n", new_control->name );
+ */
+
+ deactivate_current_control();
+ activate_control( new_control, GLUI_ACTIVATE_TAB );
+ }
+ else if ( key == ' ' AND active_control
+ AND active_control->spacebar_mouse_click ) {
+ /*** If the user presses the spacebar, and a non-edittext control
+ is active, we send it a mouse down event followed by a mouse up
+ event (simulated mouse-click) ***/
+
+ active_control->mouse_down_handler( 0, 0 );
+ active_control->mouse_up_handler( 0, 0, true );
+ } else {
+ /*** Pass the keystroke onto the active control, if any ***/
+ if ( active_control != NULL )
+ active_control->key_handler( key, curr_modifiers );
+ }
+}
+
+
+/****************************** GLUI_Main::special() **************/
+
+void GLUI_Main::special(int key, int x, int y)
+{
+ curr_modifiers = glutGetModifiers();
+
+ /*** Pass the keystroke onto the active control, if any ***/
+ if ( active_control != NULL )
+ active_control->special_handler( key, glutGetModifiers() );
+}
+
+
+
+/****************************** GLUI_Main::mouse() **************/
+
+void GLUI_Main::mouse(int button, int state, int x, int y)
+{
+ int callthrough;
+ GLUI_Control *control;
+
+ /* printf( "MOUSE: %d %d\n", button, state ); */
+
+ callthrough = true;
+
+ curr_modifiers = glutGetModifiers();
+
+ if ( button == GLUT_LEFT ) {
+ control = find_control( x, y );
+
+ /*if ( control ) printf( "control: %s\n", control->name.c_str() ); */
+
+ if ( mouse_button_down AND active_control != NULL AND
+ state == GLUT_UP )
+ {
+ /** We just released the mouse, which was depressed at some control **/
+
+ callthrough = active_control->
+ mouse_up_handler( x, y, control==active_control);
+ glutSetCursor( GLUT_CURSOR_LEFT_ARROW );
+
+ if ( active_control AND
+ active_control->active_type == GLUI_CONTROL_ACTIVE_MOUSEDOWN AND 0)
+ {
+ /*** This is a control that needs to be deactivated when the
+ mouse button is released ****/
+ deactivate_current_control();
+ }
+ }
+ else {
+ if ( control ) {
+ if ( NOT mouse_button_down AND state == GLUT_DOWN ) {
+ /*** We just pressed the mouse down at some control ***/
+
+ if ( active_control != control ) {
+ if ( active_control != NULL ) {
+ /** There is an active control still - deactivate it ***/
+ deactivate_current_control();
+ }
+ }
+
+ if ( control->enabled ) {
+ activate_control( control, GLUI_ACTIVATE_MOUSE );
+ callthrough = control->mouse_down_handler( x, y );
+ }
+ }
+ }
+ }
+
+ if ( state == GLUT_DOWN )
+ mouse_button_down = true;
+ else if ( state == GLUT_UP )
+ mouse_button_down = false;
+ }
+
+ /**
+ NO CALLTHROUGH NEEDED FOR MOUSE EVENTS
+ if ( callthrough AND glut_mouse_CB )
+ glut_mouse_CB( button, state, x, y );
+ **/
+
+ callthrough=callthrough; /* To get rid of compiler warnings */
+}
+
+
+/****************************** GLUI_Main::motion() **************/
+
+void GLUI_Main::motion(int x, int y)
+{
+ int callthrough;
+ GLUI_Control *control;
+
+ /* printf( "MOTION: %d %d\n", x, y ); */
+
+ callthrough = true;
+
+ control = find_control(x,y);
+
+ if ( mouse_button_down AND active_control != NULL ) {
+ callthrough =
+ active_control->mouse_held_down_handler(x,y,control==active_control);
+ }
+
+ /**
+ NO CALLTHROUGH NEEDED FOR MOUSE EVENTS
+
+ if ( callthrough AND glut_motion_CB )
+ glut_motion_CB(x,y);
+ **/
+
+ callthrough=callthrough; /* To get rid of compiler warnings */
+}
+
+
+/*********************** GLUI_Main::passive_motion() **************/
+
+void GLUI_Main::passive_motion(int x, int y)
+{
+ GLUI_Control *control;
+
+ control = find_control( x, y );
+
+ /* printf( "%p %p\n", control, mouse_over_control ); */
+
+ if ( control != mouse_over_control ) {
+ if ( mouse_over_control ) {
+ mouse_over_control->mouse_over( false, x, y );
+ }
+
+ if ( control ) {
+ control->mouse_over( true, x, y );
+ mouse_over_control = control;
+ }
+ }
+
+ /*
+ if ( curr_cursor != GLUT_CURSOR_INHERIT ) {
+ curr_cursor = GLUT_CURSOR_INHERIT;
+ glutSetCursor( GLUT_CURSOR_INHERIT );
+ }*/
+
+}
+
+
+/****************************** GLUI_Main::entry() **************/
+
+void GLUI_Main::entry(int state)
+{
+ /*if ( NOT active_control OR ( active_control AND ( active_control->type == GLUI_CONTROL_EDITTEXT
+ OR active_control->type == GLUI_CONTROL_SPINNER) ) )*/
+ glutSetCursor( GLUT_CURSOR_LEFT_ARROW );
+}
+
+
+/****************************** GLUI_Main::visibility() **************/
+
+void GLUI_Main::visibility(int state)
+{
+}
+
+
+/****************************** GLUI_Main::idle() **************/
+
+void GLUI_Main::idle(void)
+{
+ /*** Pass the idle event onto the active control, if any ***/
+
+ /* printf( "IDLE \t" ); */
+
+ if ( active_control != NULL ) {
+ /* First we check if the control actually needs the idle right now.
+ Otherwise, let's avoid wasting cycles and OpenGL context switching */
+
+ if ( active_control->needs_idle() ) {
+ /*** Set the current glut window to the glui window */
+ /*** But don't change the window if we're already at that window ***/
+
+ if ( glut_window_id > 0 AND glutGetWindow() != glut_window_id ) {
+ glutSetWindow( glut_window_id );
+ }
+
+ active_control->idle();
+ }
+ }
+}
+
+int GLUI_Main::needs_idle( void )
+{
+ return active_control != NULL && active_control->needs_idle();
+}
+
+
+/******************************************* GLUI_Main::find_control() ******/
+
+GLUI_Control *GLUI_Main::find_control( int x, int y )
+{
+ GLUI_Control *node, *last_container;
+
+ last_container = NULL;
+
+ node = main_panel;
+ while( node != NULL ) {
+ if ( !dynamic_cast<GLUI_Column*>(node) AND
+ PT_IN_BOX( x, y,
+ node->x_abs, node->x_abs + node->w,
+ node->y_abs, node->y_abs + node->h )
+ )
+ {
+ /*** Point is inside current node ***/
+
+ if ( node->first_child() == NULL ) {
+ /*** SPECIAL CASE: for edittext boxes, we make sure click is
+ in box, and not on name string. This should be generalized
+ for all controls later... ***/
+ if ( dynamic_cast<GLUI_EditText*>(node) ) {
+ if ( x < node->x_abs + ((GLUI_EditText*)node)->text_x_offset )
+ return (GLUI_Control*) node->parent();
+ }
+
+ return node; /* point is inside this node, and node has no children,
+ so return this node as the selected node */
+ }
+ else {
+ /*** This is a container class ***/
+ last_container = node;
+ node = (GLUI_Control*) node->first_child(); /* Descend into child */
+ }
+
+ }
+ else {
+ node = (GLUI_Control*) node->next();
+ }
+ }
+
+ /** No leaf-level nodes found to accept the mouse click, so
+ return the last container control found which DOES accept the click **/
+
+ if ( last_container ) {
+ /* printf( "ctrl: '%s'\n", last_container->name ); */
+
+ return last_container;
+ }
+ else {
+ return NULL;
+ }
+}
+
+
+/************************************* GLUI_Main::pack_controls() ***********/
+
+void GLUI_Main::pack_controls( void )
+{
+ main_panel->pack(0,0);
+
+ /**** Now align controls within their bounds ****/
+ align_controls( main_panel );
+
+ /*** If this is a subwindow, expand panel to fit parent window ***/
+ if ( TEST_AND( this->flags, GLUI_SUBWINDOW ) ) {
+ int parent_h, parent_w;
+ int orig_window;
+
+ orig_window = glutGetWindow();
+ glutSetWindow( this->top_level_glut_window_id );
+ parent_h = glutGet( GLUT_WINDOW_HEIGHT );
+ parent_w = glutGet( GLUT_WINDOW_WIDTH );
+
+ glutSetWindow( orig_window );
+
+ /* printf( "%d %d\n", parent_h, parent_w ); */
+
+ if ( 1 ) {
+ if ( TEST_AND(this->flags,GLUI_SUBWINDOW_TOP )) {
+ main_panel->w = MAX( main_panel->w, parent_w );
+ }
+ else if ( TEST_AND(this->flags,GLUI_SUBWINDOW_LEFT )) {
+ main_panel->h = MAX( main_panel->h, parent_h );
+ }
+ else if ( TEST_AND(this->flags,GLUI_SUBWINDOW_BOTTOM )) {
+ main_panel->w = MAX( main_panel->w, parent_w );
+ }
+ else if ( TEST_AND(this->flags,GLUI_SUBWINDOW_RIGHT )) {
+ main_panel->h = MAX( main_panel->h, parent_h );
+ }
+ }
+ }
+
+ this->w = main_panel->w;
+ this->h = main_panel->h;
+}
+
+
+/************************************ GLUI_Main::align_controls() **********/
+
+void GLUI_Main::align_controls( GLUI_Control *control )
+{
+ GLUI_Control *child;
+
+ control->align();
+
+ child = (GLUI_Control*) control->first_child();
+
+ while( child != NULL ) {
+ align_controls( child );
+
+ child = (GLUI_Control*)child->next();
+ }
+}
+
+
+
+/*********************************** GLUI::set_main_gfx_window() ************/
+
+void GLUI::set_main_gfx_window( int window_id )
+{
+ main_gfx_window_id = window_id;
+}
+
+
+/********************************* GLUI_Main::post_update_main_gfx() ********/
+
+void GLUI_Main::post_update_main_gfx( void )
+{
+ int old_window;
+
+ if ( main_gfx_window_id > 0 ) {
+ old_window = glutGetWindow();
+ glutSetWindow( main_gfx_window_id );
+ glutPostRedisplay();
+ if( old_window > 0 )
+ glutSetWindow( old_window );
+ }
+}
+
+/********************************* GLUI_Main::should_redraw_now() ********/
+/** Return true if this control should redraw itself immediately (front buffer);
+ Or queue up a redraw and return false if it shouldn't (back buffer).
+
+ Called from GLUI_Control::redraw.
+*/
+bool GLUI_Main::should_redraw_now(GLUI_Control *ctl)
+{
+ switch (buffer_mode) {
+ case buffer_front: return true; /* always draw in front-buffer mode */
+ case buffer_back: {
+ int orig = ctl->set_to_glut_window();
+ glutPostRedisplay(); /* redraw soon */
+ ctl->restore_window(orig);
+ return false; /* don't draw now. */
+ }
+ }
+ return false; /* never executed */
+}
+
+/********************************* GLUI_Main::set_current_draw_buffer() ********/
+
+int GLUI_Main::set_current_draw_buffer( void )
+{
+ /* Save old buffer */
+ GLint state;
+ glGetIntegerv( GL_DRAW_BUFFER, &state );
+ /* Switch to new buffer */
+ switch (buffer_mode) {
+ case buffer_front: glDrawBuffer(GL_FRONT); break;
+ case buffer_back: glDrawBuffer(GL_BACK); break; /* might not be needed... */
+ }
+ return (int)state;
+}
+
+
+/********************************* GLUI_Main::restore_draw_buffer() **********/
+
+void GLUI_Main::restore_draw_buffer( int buffer_state )
+{
+ glDrawBuffer( buffer_state );
+}
+
+
+/******************************************** GLUI_Main::GLUI_Main() ********/
+
+GLUI_Main::GLUI_Main( void )
+{
+ mouse_button_down = false;
+ w = 0;
+ h = 0;
+ active_control = NULL;
+ mouse_over_control = NULL;
+ main_gfx_window_id = -1;
+ glut_window_id = -1;
+ curr_modifiers = 0;
+ closing = false;
+ parent_window = -1;
+ glui_id = GLUI_Master.glui_id_counter;
+ GLUI_Master.glui_id_counter++;
+
+ font = GLUT_BITMAP_HELVETICA_12;
+ curr_cursor = GLUT_CURSOR_LEFT_ARROW;
+
+ int r=200, g=200, b=200;
+ bkgd_color.set( r,g,b );
+ bkgd_color_f[0] = r / 255.0;
+ bkgd_color_f[1] = g / 255.0;
+ bkgd_color_f[2] = b / 255.0;
+
+ /*** Create the main panel ***/
+ main_panel = new GLUI_Panel;
+ main_panel->set_int_val( GLUI_PANEL_NONE );
+ main_panel->glui = (GLUI*) this;
+ main_panel->name = "\0";
+}
+
+/************************************ GLUI_Main::draw_raised_box() **********/
+
+void GLUI_Main::draw_raised_box( int x, int y, int w, int h )
+{
+ w = w+x;
+ h = h+y;
+
+ glColor3ub( bkgd_color.r, bkgd_color.g, bkgd_color.b );
+ glBegin( GL_LINE_LOOP );
+ glVertex2i( x+1, y+1 ); glVertex2i( w-1, y+1 );
+ glVertex2i( w-1, h-1 ); glVertex2i( x+1, h-1 );
+ glEnd();
+
+ glColor3d( 1.0, 1.0, 1.0 );
+ glBegin( GL_LINE_STRIP );
+ glVertex2i( x, h ); glVertex2i( x, y ); glVertex2i( w, y );
+ glEnd();
+
+ glColor3d( 0.0, 0.0, 0.0 );
+ glBegin( GL_LINE_STRIP );
+ glVertex2i( w, y ); glVertex2i( w, h ); glVertex2i( x, h );
+ glEnd();
+
+ glColor3d( .5, .5, .5 );
+ glBegin( GL_LINE_STRIP );
+ glVertex2i( w-1, y+1 ); glVertex2i( w-1, h-1 ); glVertex2i( x+1, h-1 );
+ glEnd();
+}
+
+
+/************************************ GLUI_Main::draw_lowered_box() **********/
+/* Not quite perfect... **/
+
+void GLUI_Main::draw_lowered_box( int x, int y, int w, int h )
+{
+ w = w+x;
+ h = h+y;
+
+ glColor3ub( bkgd_color.r, bkgd_color.g, bkgd_color.b );
+ glBegin( GL_LINE_LOOP );
+ glVertex2i( x+1, y+1 ); glVertex2i( w-1, y+1 );
+ glVertex2i( w-1, h-1 ); glVertex2i( x+1, h-1 );
+ glEnd();
+
+ glColor3d( 0.0, 0.0, 0.0 );
+ glBegin( GL_LINE_STRIP );
+ glVertex2i( x, h ); glVertex2i( x, y ); glVertex2i( w, y );
+ glEnd();
+
+ glColor3d( 1.0, 1.0, 1.0 );
+ glBegin( GL_LINE_STRIP );
+ glVertex2i( w, y ); glVertex2i( w, h ); glVertex2i( x, h );
+ glEnd();
+
+ glColor3d( .5, .5, .5 );
+ glBegin( GL_LINE_STRIP );
+ glVertex2i( w-1, y+1 ); glVertex2i( w-1, h-1 ); glVertex2i( x+1, h-1 );
+ glEnd();
+}
+
+
+/************************************* GLUI_Main::activate_control() *********/
+
+void GLUI_Main::activate_control( GLUI_Control *control, int how )
+{
+ /** Are we not activating a control in the same window as the
+ previous active control? */
+ if ( GLUI_Master.active_control_glui AND
+ this != (GLUI_Main*) GLUI_Master.active_control_glui ) {
+ GLUI_Master.active_control_glui->deactivate_current_control();
+ }
+
+ /******* Now activate it *****/
+ if ( control != NULL AND control->can_activate AND control->enabled ) {
+ active_control = control;
+
+ control->activate(how);
+
+ /*if ( NOT active_control->is_container OR */
+ /* active_control->type == GLUI_CONTROL_ROLLOUT) { */
+ active_control->redraw();
+ /*} */
+ }
+ else {
+ active_control = NULL;
+ }
+
+ /* printf( "activate: %d\n", glutGetWindow() ); */
+ GLUI_Master.active_control = active_control;
+ GLUI_Master.active_control_glui = (GLUI*) this;
+}
+
+
+/************************* GLUI_Main::deactivate_current_control() **********/
+
+void GLUI_Main::deactivate_current_control( void )
+{
+ int orig;
+
+ if ( active_control != NULL ) {
+ orig = active_control->set_to_glut_window();
+
+ active_control->deactivate();
+
+ /** If this isn't a container control, then redraw it in its
+ deactivated state. Container controls, such as panels, look
+ the same activated or not **/
+
+ /*if ( NOT active_control->is_container OR */
+ /* active_control->type == GLUI_CONTROL_ROLLOUT ) { */
+ active_control->redraw();
+ /*} */
+
+ active_control->restore_window( orig );
+
+ active_control = NULL;
+ }
+
+ /* printf( "deactivate: %d\n", glutGetWindow() ); */
+ GLUI_Master.active_control = NULL;
+ GLUI_Master.active_control_glui = NULL;
+}
+
+
+/****************************** GLUI_Main::find_next_control() **************/
+
+GLUI_Control *GLUI_Main::find_next_control_( GLUI_Control *control )
+{
+ /*** THIS IS NOT find_next_control()! This is an unused older
+ version (look at the underscore at the end) ***/
+
+ if ( control == NULL )
+ return find_next_control_rec( main_panel );
+ else
+ return find_next_control_rec( control );
+}
+
+/****************************** GLUI_Main::find_next_control() **************/
+
+GLUI_Control *GLUI_Main::find_next_control_rec( GLUI_Control *control )
+{
+ GLUI_Control *child = NULL, *rec_control, *sibling;
+
+ /*** Recursively investigate children ***/
+ child = (GLUI_Control*) control->first_child();
+ if ( child ) {
+ /*** If we can activate the first child, then do so ***/
+ if ( child->can_activate AND child->enabled )
+ return child;
+ else /*** Recurse into first child ***/
+ rec_control = find_next_control_rec( child );
+
+ if ( rec_control )
+ return rec_control;
+ }
+
+ /*** At this point, either we don't have children, or the child cannot
+ be activated. So let's try the next sibling ***/
+
+ sibling = (GLUI_Control*) control->next();
+ if ( sibling ) {
+ if ( sibling->can_activate AND sibling->enabled )
+ return sibling;
+ else /*** Recurse into sibling ***/
+ rec_control = find_next_control_rec( sibling );
+
+ if ( rec_control )
+ return rec_control;
+ }
+
+ return NULL;
+}
+
+
+/****************************** GLUI_Main::find_next_control() **************/
+
+GLUI_Control *GLUI_Main::find_next_control( GLUI_Control *control )
+{
+ GLUI_Control *tmp_control = NULL;
+ int back_up;
+
+ if ( control == NULL )
+ control = main_panel;
+
+ while( control != NULL ) {
+ /** see if this control has a child **/
+ tmp_control = (GLUI_Control*) control->first_child();
+
+ if ( tmp_control != NULL ) {
+ if ( tmp_control->can_activate AND tmp_control->enabled )
+ return tmp_control;
+
+ control = tmp_control; /* Descend into child */
+ continue;
+ }
+
+ /*** At this point, control has no children ***/
+
+ /** see if this control has a next sibling **/
+ tmp_control = (GLUI_Control*) control->next();
+
+ if ( tmp_control != NULL ) {
+ if ( tmp_control->can_activate AND tmp_control->enabled )
+ return tmp_control;
+
+ control = tmp_control;
+ continue;
+ }
+
+ /** back up until we find a sibling of an ancestor **/
+ back_up = true;
+ while ( control->parent() AND back_up ) {
+ control = (GLUI_Control*) control->parent();
+
+ if ( control->next() ) {
+ control = (GLUI_Control*) control->next();
+ if ( control->can_activate AND control->enabled )
+ return control;
+ else
+ back_up = false;
+
+ /*** if ( control->is_container ) {
+ tmp_control = control;
+ control = NULL;
+ break;
+ }
+ else {
+ back_up = false;
+ }
+ ***/
+ }
+ }
+
+ /** Check if we've cycled back to the top... if so, return NULL **/
+ if ( control == main_panel ) {
+ return NULL;
+ }
+ }
+ /*
+ if ( tmp_control != NULL AND tmp_control->can_activate AND
+ tmp_control->enabled ) {
+ return tmp_control;
+ }*/
+
+ return NULL;
+}
+
+
+/****************************** GLUI_Main::find_prev_control() **************/
+
+GLUI_Control *GLUI_Main::find_prev_control( GLUI_Control *control )
+{
+ GLUI_Control *tmp_control, *next_control;
+
+ if ( control == NULL ) { /* here we find the last valid control */
+ next_control = main_panel;
+
+ do {
+ tmp_control = next_control;
+ next_control = find_next_control( tmp_control );
+ } while( next_control != NULL );
+
+ return tmp_control;
+ }
+ else { /* here we find the actual previous control */
+ next_control = main_panel;
+
+ do {
+ tmp_control = next_control;
+ next_control = find_next_control( tmp_control );
+ } while( next_control != NULL AND next_control != control );
+
+ if ( next_control == NULL OR tmp_control == main_panel )
+ return NULL;
+ else
+ return tmp_control;
+ }
+}
+
+/************************* GLUI_Master_Object::set_glutIdleFunc() ***********/
+
+void GLUI_Master_Object::set_glutIdleFunc(void (*f)(void))
+{
+ glut_idle_CB = f;
+ GLUI_Master.glui_setIdleFuncIfNecessary();
+}
+
+
+/**************************************** GLUI::disable() ********************/
+
+void GLUI::disable( void )
+{
+ deactivate_current_control();
+ main_panel->disable();
+}
+
+
+/******************************************** GLUI::sync_live() **************/
+
+void GLUI::sync_live( void )
+{
+ main_panel->sync_live(true, true);
+}
+
+
+/********************************* GLUI_Master_Object::sync_live_all() *****/
+
+void GLUI_Master_Object::sync_live_all( void )
+{
+ GLUI *glui;
+
+ glui = (GLUI*) GLUI_Master.gluis.first_child();
+ while( glui ) {
+
+ glui->sync_live(); /** sync it **/
+
+ glui = (GLUI*) glui->next();
+ }
+}
+
+
+/************************************* GLUI_Master_Object::close() **********/
+
+void GLUI_Master_Object::close_all( void )
+{
+ GLUI *glui;
+
+ glui = (GLUI*) GLUI_Master.gluis.first_child();
+ while( glui ) {
+
+ glui->close(); /** Set flag to close **/
+
+ glui = (GLUI*) glui->next();
+ }
+}
+
+
+/************************************* GLUI_Main::close_internal() **********/
+
+void GLUI_Main::close_internal( void )
+{
+ glutDestroyWindow(glutGetWindow()); /** Close this window **/
+
+ this->unlink();
+
+ if ( GLUI_Master.active_control_glui == this ) {
+ GLUI_Master.active_control = NULL;
+ GLUI_Master.active_control_glui = NULL;
+ }
+
+ if ( parent_window != -1 ) {
+ glutSetWindow( parent_window );
+ int win_w = glutGet( GLUT_WINDOW_WIDTH );
+ int win_h = glutGet( GLUT_WINDOW_HEIGHT );
+ glutReshapeWindow(win_w+1, win_h);
+ glutReshapeWindow(win_w-1, win_h);
+ }
+
+ delete this->main_panel;
+
+ delete this;
+}
+
+
+/************************************************** GLUI::close() **********/
+
+void GLUI::close( void )
+{
+ int old_glut_window;
+
+ closing = true;
+
+ old_glut_window = glutGetWindow();
+ glutSetWindow( get_glut_window_id() );
+ glutPostRedisplay();
+
+ glutSetWindow( old_glut_window );
+}
+
+
+/************************** GLUI_Main::check_subwindow_position() **********/
+
+void GLUI_Main::check_subwindow_position( void )
+{
+ /*** Reposition this window if subwindow ***/
+ if ( TEST_AND( this->flags, GLUI_SUBWINDOW ) ) {
+
+ int parent_w, parent_h, new_x, new_y;
+ int old_window = glutGetWindow();
+
+ glutSetWindow( glut_window_id );
+
+ glutSetWindow( glutGet( GLUT_WINDOW_PARENT ));
+ parent_w = glutGet( GLUT_WINDOW_WIDTH );
+ parent_h = glutGet( GLUT_WINDOW_HEIGHT );
+
+ glutSetWindow( glut_window_id );
+
+ if ( TEST_AND(this->flags,GLUI_SUBWINDOW_RIGHT )) {
+ new_x = parent_w - this->w;
+ new_y = 0;
+ }
+ else if ( TEST_AND(this->flags,GLUI_SUBWINDOW_LEFT )) {
+ new_x = 0;
+ new_y = 0;
+ }
+ else if ( TEST_AND(this->flags,GLUI_SUBWINDOW_BOTTOM )) {
+ new_x = 0;
+ new_y = parent_h - this->h;
+ }
+ else { /*** GLUI_SUBWINDOW_TOP ***/
+ new_x = 0;
+ new_y = 0;
+ }
+
+ /** Now make adjustments based on presence of other subwindows **/
+ GLUI *curr_glui;
+ curr_glui = (GLUI*) GLUI_Master.gluis.first_child();
+ while( curr_glui ) {
+ if ( TEST_AND( curr_glui->flags, GLUI_SUBWINDOW) AND
+ curr_glui->parent_window == this->parent_window ) {
+
+ if ( TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_LEFT ) ) {
+ }
+ else if ( TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_BOTTOM ) ) {
+ }
+ else if ( TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_RIGHT ) ) {
+ }
+ else if ( TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_TOP ) AND
+ ( TEST_AND( this->flags,GLUI_SUBWINDOW_LEFT ) OR
+ TEST_AND( this->flags,GLUI_SUBWINDOW_RIGHT ) ) ) {
+ /** If we are a RIGHT or LEFT subwindow, and there exists some
+ TOP subwindow, bump our position down **/
+
+ new_y += curr_glui->h;
+ }
+
+ /** CHeck multiple subwins at same position **/
+ /** We check the glui_id's: only the glui with the higher
+ ID number (meaning it was created later) gets bumped over **/
+ if ( curr_glui != this AND this->glui_id > curr_glui->glui_id ) {
+ if ( TEST_AND( this->flags,GLUI_SUBWINDOW_LEFT ) AND
+ TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_LEFT ) ) {
+ new_x += curr_glui->w;
+ }
+ else if ( TEST_AND( this->flags,GLUI_SUBWINDOW_TOP ) AND
+ TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_TOP ) ) {
+ new_y += curr_glui->h;
+ }
+ else if ( TEST_AND( this->flags,GLUI_SUBWINDOW_BOTTOM ) AND
+ TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_BOTTOM ) ) {
+ new_y -= curr_glui->h;
+ }
+ else if ( TEST_AND( this->flags,GLUI_SUBWINDOW_RIGHT ) AND
+ TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_RIGHT ) ) {
+ new_x -= curr_glui->w;
+ }
+
+ }
+ }
+
+ curr_glui = (GLUI*) curr_glui->next();
+ }
+
+
+
+ CLAMP( new_x, 0, new_x );
+ CLAMP( new_y, 0, new_y );
+
+ glutPositionWindow( new_x, new_y );
+ /* glutPostRedisplay(); */
+
+ glutSetWindow( old_window );
+ }
+}
+
+
+/********************************* GLUI_Master_Object::reshape() **********/
+/* This gets called by the user from a GLUT reshape callback. So we look */
+/* for subwindows that belong to the current window */
+
+void GLUI_Master_Object::reshape( void )
+{
+ GLUI *glui;
+ int current_window;
+
+ current_window = glutGetWindow();
+
+ glui = (GLUI*) GLUI_Master.gluis.first_child();
+ while( glui ) {
+ if ( TEST_AND( glui->flags, GLUI_SUBWINDOW) AND
+ glui->parent_window == current_window ) {
+ glutSetWindow( glui->get_glut_window_id());
+ glui->check_subwindow_position();
+ }
+
+ glui = (GLUI*) glui->next();
+ }
+
+ glutSetWindow(current_window);
+}
+
+
+/**************************** GLUI_Master_Object::set_glutReshapeFunc() *****/
+
+void GLUI_Master_Object::set_glutReshapeFunc(void (*f)(int width, int height))
+{
+ glutReshapeFunc( glui_reshape_func );
+ add_cb_to_glut_window( glutGetWindow(), GLUI_GLUT_RESHAPE, (void*) f);
+}
+
+
+/**************************** GLUI_Master_Object::set_glutKeyboardFunc() ****/
+
+void GLUI_Master_Object::set_glutKeyboardFunc(void (*f)(unsigned char key,
+ int x, int y))
+{
+ glutKeyboardFunc( glui_keyboard_func );
+ add_cb_to_glut_window( glutGetWindow(), GLUI_GLUT_KEYBOARD, (void*) f);
+}
+
+
+/*********************** GLUI_Master_Object::set_glutSpecialFunc() **********/
+
+void GLUI_Master_Object::set_glutSpecialFunc(void (*f)(int key,
+ int x, int y))
+{
+ glutSpecialFunc( glui_special_func );
+ add_cb_to_glut_window( glutGetWindow(), GLUI_GLUT_SPECIAL, (void*) f);
+}
+
+
+/*********************** GLUI_Master_Object::set_glutMouseFunc() **********/
+
+void GLUI_Master_Object::set_glutMouseFunc(void (*f)(int button, int state,
+ int x, int y))
+{
+ glutMouseFunc( glui_mouse_func );
+ add_cb_to_glut_window( glutGetWindow(), GLUI_GLUT_MOUSE, (void*) f);
+}
+
+
+/****************************** glui_parent_window_reshape_func() **********/
+/* This is the reshape callback for a window that contains subwindows */
+
+void glui_parent_window_reshape_func( int w, int h )
+{
+ int current_window;
+ GLUI *glui;
+ int first = true;
+
+ /* printf( "glui_parent_window_reshape_func: %d\n", glutGetWindow() ); */
+
+ current_window = glutGetWindow();
+
+ glui = (GLUI*) GLUI_Master.gluis.first_child();
+ while( glui ) {
+ if ( TEST_AND( glui->flags, GLUI_SUBWINDOW) AND
+ glui->parent_window == current_window ) {
+ glutSetWindow( glui->get_glut_window_id());
+ glui->check_subwindow_position();
+ glutSetWindow( current_window );
+
+ if ( first ) {
+ if (glui->glut_reshape_CB) glui->glut_reshape_CB( w, h );
+
+ first = false;
+ }
+ }
+
+ glui = (GLUI*) glui->next();
+ }
+}
+
+
+/****************************** glui_parent_window_keyboard_func() **********/
+
+void glui_parent_window_keyboard_func(unsigned char key, int x, int y)
+{
+ /* printf( "glui_parent_window_keyboard_func: %d\n", glutGetWindow() ); */
+
+ int current_window;
+ GLUI *glui;
+
+ current_window = glutGetWindow();
+
+ if ( GLUI_Master.active_control_glui AND GLUI_Master.active_control ) {
+ glutSetWindow( GLUI_Master.active_control_glui->get_glut_window_id() );
+
+ GLUI_Master.active_control_glui->keyboard(key,x,y);
+
+ glutSetWindow( current_window );
+ }
+ else {
+ glui = (GLUI*) GLUI_Master.gluis.first_child();
+ while( glui ) {
+ if ( TEST_AND( glui->flags, GLUI_SUBWINDOW) AND
+ glui->parent_window == current_window AND
+ glui->glut_keyboard_CB )
+ {
+ glui->glut_keyboard_CB( key, x, y );
+ break;
+ }
+
+ glui = (GLUI*) glui->next();
+ }
+ }
+}
+
+
+/****************************** glui_parent_window_special_func() **********/
+
+void glui_parent_window_special_func(int key, int x, int y)
+{
+ /*printf( "glui_parent_window_special_func: %d\n", glutGetWindow() ); */
+
+ int current_window;
+ GLUI *glui;
+
+ /** If clicking in the main area of a window w/subwindows,
+ deactivate any current control **/
+ if ( GLUI_Master.active_control_glui != NULL )
+ GLUI_Master.active_control_glui->deactivate_current_control();
+
+ /*** Now pass on the mouse event ***/
+
+ current_window = glutGetWindow();
+
+ glui = (GLUI*) GLUI_Master.gluis.first_child();
+ while( glui ) {
+ if ( TEST_AND( glui->flags, GLUI_SUBWINDOW) AND
+ glui->parent_window == current_window )
+ {
+ glutSetWindow( glui->get_glut_window_id());
+ if (glui->glut_special_CB) glui->glut_special_CB( key, x, y );
+ break;
+ }
+
+ glui = (GLUI*) glui->next();
+ }
+}
+
+
+/****************************** glui_parent_window_mouse_func() **********/
+
+void glui_parent_window_mouse_func(int button, int state, int x, int y)
+{
+ int current_window;
+ GLUI *glui;
+
+ /** If clicking in the main area of a window w/subwindows,
+ deactivate any current control **/
+ if ( GLUI_Master.active_control_glui != NULL )
+ GLUI_Master.active_control_glui->deactivate_current_control();
+
+
+ /*** Now pass on the mouse event ***/
+
+ current_window = glutGetWindow();
+
+ glui = (GLUI*) GLUI_Master.gluis.first_child();
+ while( glui ) {
+ if ( TEST_AND( glui->flags, GLUI_SUBWINDOW) AND
+ glui->parent_window == current_window AND
+ glui->glut_mouse_CB)
+ {
+ glutSetWindow( glui->get_glut_window_id());
+ glui->glut_mouse_CB( button, state, x, y );
+ break;
+ }
+
+ glui = (GLUI*) glui->next();
+ }
+}
+
+
+/************************** GLUI_Master_Object::find_glut_window() **********/
+
+GLUI_Glut_Window *GLUI_Master_Object::find_glut_window( int window_id )
+{
+ GLUI_Glut_Window *window;
+
+ window = (GLUI_Glut_Window*) glut_windows.first_child();
+ while( window ) {
+ if ( window->glut_window_id == window_id )
+ return window;
+
+ window = (GLUI_Glut_Window*) window->next();
+ }
+
+ /*** Window not found - return NULL ***/
+ return NULL;
+}
+
+
+/******************** GLUI_Master_Object::add_cb_to_glut_window() **********/
+
+void GLUI_Master_Object::add_cb_to_glut_window(int window_id,
+ int cb_type,void *cb)
+{
+ GLUI_Glut_Window *window;
+
+ window = find_glut_window( window_id );
+ if ( NOT window ) {
+ /*** Allocate new window structure ***/
+
+ window = new GLUI_Glut_Window;
+ window->glut_window_id = window_id;
+ window->link_this_to_parent_last( (GLUI_Node*) &this->glut_windows );
+ }
+
+ switch( cb_type ) {
+ case GLUI_GLUT_RESHAPE:
+ window->glut_reshape_CB = (void(*)(int,int)) cb;
+ break;
+ case GLUI_GLUT_DISPLAY:
+ window->glut_display_CB = (void(*)()) cb;
+ break;
+ case GLUI_GLUT_KEYBOARD:
+ window->glut_keyboard_CB = (void(*)(unsigned char,int,int)) cb;
+ break;
+ case GLUI_GLUT_SPECIAL:
+ window->glut_special_CB = (void(*)(int,int,int)) cb;
+ break;
+ case GLUI_GLUT_MOUSE:
+ window->glut_mouse_CB = (void(*)(int,int,int,int)) cb;
+ break;
+ case GLUI_GLUT_MOTION:
+ window->glut_motion_CB = (void(*)(int,int)) cb;
+ break;
+ case GLUI_GLUT_PASSIVE_MOTION:
+ window->glut_passive_motion_CB = (void(*)(int,int)) cb;
+ break;
+ case GLUI_GLUT_ENTRY:
+ window->glut_entry_CB = (void(*)(int)) cb;
+ break;
+ case GLUI_GLUT_VISIBILITY:
+ window->glut_visibility_CB= (void(*)(int)) cb;
+ break;
+ }
+}
+
+
+/************* GLUI_Master_Object::set_left_button_glut_menu_control() *****/
+
+void GLUI_Master_Object::set_left_button_glut_menu_control(
+ GLUI_Control *control )
+{
+ curr_left_button_glut_menu = control;
+}
+
+
+/******************************* GLUI_Main::set_ortho_projection() **********/
+
+void GLUI_Main::set_ortho_projection( void )
+{
+ int win_h, win_w;
+
+ win_w = glutGet( GLUT_WINDOW_WIDTH );
+ win_h = glutGet( GLUT_WINDOW_HEIGHT );
+
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ /* gluOrtho2D( 0.0, (float) win_w, 0.0, (float) win_h ); */
+ glOrtho( 0.0, (float)win_w, 0.0, (float) win_h, -1000.0, 1000.0 );
+
+ glMatrixMode( GL_MODELVIEW );
+
+ return; /****-----------------------------------------------***/
+
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+
+ /*** Rotate image so y increases upwards, contrary to OpenGL axes ***/
+ glTranslatef( (float) win_w/2.0, (float) win_h/2.0, 0.0 );
+ glRotatef( 180.0, 0.0, 1.0, 0.0 );
+ glRotatef( 180.0, 0.0, 0.0, 1.0 );
+ glTranslatef( (float) -win_w/2.0, (float) -win_h/2.0, 0.0 );
+}
+
+
+/******************************* GLUI_Main::set_viewport() **********/
+
+void GLUI_Main::set_viewport( void )
+{
+ glViewport( 0, 0, main_panel->w, main_panel->h );
+}
+
+
+/****************************** GLUI_Main::refresh() ****************/
+
+void GLUI_Main::refresh( void )
+{
+ int orig;
+
+ /****** GLUI_Glut_Window *glut_window;
+ int current_window;
+ current_window = glutGetWindow();
+ glut_window = GLUI_Master.find_glut_window( current_window );
+ if ( glut_window ) {
+ glut_window->glut_reshape_CB(w,h);
+ ******/
+
+ orig = glutGetWindow();
+
+ pack_controls();
+
+ if ( glut_window_id > 0 )
+ glutSetWindow( glut_window_id );
+
+
+ if ( TEST_AND( this->flags, GLUI_SUBWINDOW ) ) {
+ /*** GLUI subwindow ***/
+
+ check_subwindow_position();
+ }
+ else {
+ /*** Standalone GLUI window ***/
+
+ glutReshapeWindow( this->h, this->w );
+
+ }
+
+ glutPostRedisplay();
+ glutSetWindow( orig);
+}
+
+
+
+/***************** GLUI_Master_Object::get_main_gfx_viewport() ***********/
+
+void GLUI_Master_Object::get_viewport_area( int *x, int *y,
+ int *w, int *h )
+{
+ GLUI *curr_glui;
+ int curr_x, curr_y, curr_w, curr_h;
+ int curr_window;
+
+ curr_window = glutGetWindow();
+ curr_x = 0;
+ curr_y = 0;
+ curr_w = glutGet( GLUT_WINDOW_WIDTH );
+ curr_h = glutGet( GLUT_WINDOW_HEIGHT );
+
+ curr_glui = (GLUI*) gluis.first_child();
+ while( curr_glui ) {
+ if ( TEST_AND( curr_glui->flags, GLUI_SUBWINDOW) AND
+ curr_glui->parent_window == curr_window ) {
+
+ /* printf( "%s -> %d %d %d\n", curr_glui->window_name.c_str(), curr_glui->flags,
+ curr_glui->w, curr_glui->h );*/
+
+ if ( TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_LEFT ) ) {
+ curr_x += curr_glui->w;
+ curr_w -= curr_glui->w;
+ }
+ else if ( TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_BOTTOM ) ) {
+ curr_y += curr_glui->h;
+ curr_h -= curr_glui->h;
+ }
+ else if ( TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_RIGHT ) ) {
+ curr_w -= curr_glui->w;
+ }
+ else if ( TEST_AND( curr_glui->flags,GLUI_SUBWINDOW_TOP ) ) {
+ curr_h -= curr_glui->h;
+ }
+ }
+
+ curr_glui = (GLUI*) curr_glui->next();
+ }
+
+ curr_x = MAX( 0, curr_x );
+ curr_y = MAX( 0, curr_y );
+ curr_w = MAX( 0, curr_w );
+ curr_h = MAX( 0, curr_h );
+
+ *x = curr_x;
+ *y = curr_y;
+ *w = curr_w;
+ *h = curr_h;
+}
+
+
+/*****************GLUI_Master_Object::auto_set_main_gfx_viewport() **********/
+
+void GLUI_Master_Object::auto_set_viewport( void )
+{
+ int x, y, w, h;
+
+ get_viewport_area( &x, &y, &w, &h );
+ glViewport( MAX(x,0), MAX(y,0), MAX(w,0), MAX(h,0) );
+}
+
+
+
+/***************************************** GLUI::show() **********************/
+
+void GLUI::show( void )
+{
+ int orig_window;
+
+ orig_window = main_panel->set_to_glut_window();
+
+ glutShowWindow();
+
+ main_panel->restore_window(orig_window);
+}
+
+
+
+/***************************************** GLUI::hide() **********************/
+
+void GLUI::hide( void )
+{
+ int orig_window;
+
+ this->deactivate_current_control();
+
+ orig_window = main_panel->set_to_glut_window();
+
+ glutHideWindow();
+
+ main_panel->restore_window(orig_window);
+}
+
+
+/**************** GLUI_DrawingSentinal **************/
+GLUI_DrawingSentinal::GLUI_DrawingSentinal(GLUI_Control *c_)
+ :c(c_)
+{
+ orig_win = c->set_to_glut_window();
+ orig_buf = c->glui->set_current_draw_buffer();
+}
+GLUI_DrawingSentinal::~GLUI_DrawingSentinal() {
+ c->glui->restore_draw_buffer(orig_buf);
+ c->restore_window(orig_win);
+}
+
+
+void GLUI_Master_Object::glui_setIdleFuncIfNecessary( void )
+{
+ GLUI *glui;
+
+ glui = (GLUI*) GLUI_Master.gluis.first_child();
+ int necessary;
+ if (this->glut_idle_CB)
+ necessary = true;
+ else {
+ necessary = false;
+ while( glui ) {
+ if( glui->needs_idle() ) {
+ necessary = true;
+ break;
+ }
+ glui = (GLUI*) glui->next();
+ }
+ }
+ if( necessary )
+ glutIdleFunc( glui_idle_func );
+ else
+ glutIdleFunc( NULL );
+}
diff --git a/tests/box2d/glui/glui.h b/tests/box2d/glui/glui.h new file mode 100755 index 00000000..f1daea8e --- /dev/null +++ b/tests/box2d/glui/glui.h @@ -0,0 +1,2568 @@ +/****************************************************************************
+
+ GLUI User Interface Toolkit (LGPL)
+ ----------------------------------
+
+ glui.h - Main (and only) external header for
+ GLUI User Interface Toolkit
+
+ --------------------------------------------------
+
+ Copyright (c) 1998 Paul Rademacher
+
+ WWW: http://sourceforge.net/projects/glui/
+ Forums: http://sourceforge.net/forum/?group_id=92496
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+#ifndef GLUI_GLUI_H
+#define GLUI_GLUI_H
+
+#ifdef __APPLE__
+ #include <GLUT/glut.h>
+#else
+ #include "freeglut/freeglut.h"
+#endif
+
+#include <cstdlib>
+#include <cstdio>
+#include <cstring>
+#include <string>
+#include <vector>
+
+#define GLUI_VERSION 2.3f /********** Current version **********/
+
+#if defined(_WIN32)
+#if !defined(GLUI_NO_LIB_PRAGMA)
+//#pragma comment(lib, "glui32.lib") // Link automatically with GLUI library
+#endif
+#endif
+
+/********** Do some basic defines *******/
+
+#ifndef Byte
+#define Byte unsigned char
+#endif
+
+#ifndef _RGBC_
+class RGBc {
+public:
+ Byte r, g, b;
+
+ void set(Byte r,Byte g,Byte b) {this->r=r;this->g=g;this->b=b;}
+
+ RGBc( void ) {}
+ RGBc( Byte r, Byte g, Byte b ) { set( r, g, b ); }
+};
+#define _RGBC_
+#endif
+
+/********** List of GLUT callbacks ********/
+
+enum GLUI_Glut_CB_Types
+{
+ GLUI_GLUT_RESHAPE,
+ GLUI_GLUT_KEYBOARD,
+ GLUI_GLUT_DISPLAY,
+ GLUI_GLUT_MOUSE,
+ GLUI_GLUT_MOTION,
+ GLUI_GLUT_SPECIAL,
+ GLUI_GLUT_PASSIVE_MOTION,
+ GLUI_GLUT_ENTRY,
+ GLUI_GLUT_VISIBILITY
+};
+
+/********* Constants for window placement **********/
+
+#define GLUI_XOFF 6
+#define GLUI_YOFF 6
+#define GLUI_ITEMSPACING 3
+#define GLUI_CHECKBOX_SIZE 13
+#define GLUI_RADIOBUTTON_SIZE 13
+#define GLUI_BUTTON_SIZE 20
+#define GLUI_STATICTEXT_SIZE 13
+#define GLUI_SEPARATOR_HEIGHT 8
+#define GLUI_DEFAULT_CONTROL_WIDTH 100
+#define GLUI_DEFAULT_CONTROL_HEIGHT 13
+#define GLUI_EDITTEXT_BOXINNERMARGINX 3
+#define GLUI_EDITTEXT_HEIGHT 20
+#define GLUI_EDITTEXT_WIDTH 130
+#define GLUI_EDITTEXT_MIN_INT_WIDTH 35
+#define GLUI_EDITTEXT_MIN_TEXT_WIDTH 50
+#define GLUI_PANEL_NAME_DROP 8
+#define GLUI_PANEL_EMBOSS_TOP 4
+/* #define GLUI_ROTATION_WIDTH 60 */
+/* #define GLUI_ROTATION_HEIGHT 78 */
+#define GLUI_ROTATION_WIDTH 50
+#define GLUI_ROTATION_HEIGHT (GLUI_ROTATION_WIDTH+18)
+#define GLUI_MOUSE_INTERACTION_WIDTH 50
+#define GLUI_MOUSE_INTERACTION_HEIGHT (GLUI_MOUSE_INTERACTION_WIDTH)+18
+
+/** Different panel control types **/
+#define GLUI_PANEL_NONE 0
+#define GLUI_PANEL_EMBOSSED 1
+#define GLUI_PANEL_RAISED 2
+
+/** Max # of els in control's float_array **/
+#define GLUI_DEF_MAX_ARRAY 30
+
+/********* The control's 'active' behavior *********/
+#define GLUI_CONTROL_ACTIVE_MOUSEDOWN 1
+#define GLUI_CONTROL_ACTIVE_PERMANENT 2
+
+/********* Control alignment types **********/
+#define GLUI_ALIGN_CENTER 1
+#define GLUI_ALIGN_RIGHT 2
+#define GLUI_ALIGN_LEFT 3
+
+/********** Limit types - how to limit spinner values *********/
+#define GLUI_LIMIT_NONE 0
+#define GLUI_LIMIT_CLAMP 1
+#define GLUI_LIMIT_WRAP 2
+
+/********** Translation control types ********************/
+#define GLUI_TRANSLATION_XY 0
+#define GLUI_TRANSLATION_Z 1
+#define GLUI_TRANSLATION_X 2
+#define GLUI_TRANSLATION_Y 3
+
+#define GLUI_TRANSLATION_LOCK_NONE 0
+#define GLUI_TRANSLATION_LOCK_X 1
+#define GLUI_TRANSLATION_LOCK_Y 2
+
+/********** How was a control activated? *****************/
+#define GLUI_ACTIVATE_MOUSE 1
+#define GLUI_ACTIVATE_TAB 2
+
+/********** What type of live variable does a control have? **********/
+#define GLUI_LIVE_NONE 0
+#define GLUI_LIVE_INT 1
+#define GLUI_LIVE_FLOAT 2
+#define GLUI_LIVE_TEXT 3
+#define GLUI_LIVE_STRING 6
+#define GLUI_LIVE_DOUBLE 4
+#define GLUI_LIVE_FLOAT_ARRAY 5
+
+/************* Textbox and List Defaults - JVK ******************/
+#define GLUI_TEXTBOX_HEIGHT 130
+#define GLUI_TEXTBOX_WIDTH 130
+#define GLUI_LIST_HEIGHT 130
+#define GLUI_LIST_WIDTH 130
+#define GLUI_DOUBLE_CLICK 1
+#define GLUI_SINGLE_CLICK 0
+#define GLUI_TAB_WIDTH 50 /* In pixels */
+#define GLUI_TEXTBOX_BOXINNERMARGINX 3
+#define GLUI_TEXTBOX_MIN_TEXT_WIDTH 50
+#define GLUI_LIST_BOXINNERMARGINX 3
+#define GLUI_LIST_MIN_TEXT_WIDTH 50
+
+/*********************** TreePanel Defaults - JVK *****************************/
+#define GLUI_TREEPANEL_DEFAULTS 0 // bar, standard bar color
+#define GLUI_TREEPANEL_ALTERNATE_COLOR 1 // Alternate between 8 different bar colors
+#define GLUI_TREEPANEL_ENABLE_BAR 2 // enable the bar
+#define GLUI_TREEPANEL_DISABLE_BAR 4 // disable the bar
+#define GLUI_TREEPANEL_DISABLE_DEEPEST_BAR 8 // disable only the deepest bar
+#define GLUI_TREEPANEL_CONNECT_CHILDREN_ONLY 16 // disable only the bar of the last child of each root
+#define GLUI_TREEPANEL_DISPLAY_HIERARCHY 32 // display some sort of hierachy in the tree node title
+#define GLUI_TREEPANEL_HIERARCHY_NUMERICDOT 64 // display hierarchy in 1.3.2 (etc... ) format
+#define GLUI_TREEPANEL_HIERARCHY_LEVEL_ONLY 128 // display hierarchy as only the level depth
+
+/******************* GLUI Scrollbar Defaults - JVK ***************************/
+#define GLUI_SCROLL_ARROW_WIDTH 16
+#define GLUI_SCROLL_ARROW_HEIGHT 16
+#define GLUI_SCROLL_BOX_MIN_HEIGHT 5
+#define GLUI_SCROLL_BOX_STD_HEIGHT 16
+#define GLUI_SCROLL_STATE_NONE 0
+#define GLUI_SCROLL_STATE_UP 1
+#define GLUI_SCROLL_STATE_DOWN 2
+#define GLUI_SCROLL_STATE_BOTH 3
+#define GLUI_SCROLL_STATE_SCROLL 4
+#define GLUI_SCROLL_DEFAULT_GROWTH_EXP 1.05f
+#define GLUI_SCROLL_VERTICAL 0
+#define GLUI_SCROLL_HORIZONTAL 1
+
+
+/** Size of the character width hash table for faster lookups.
+ Make sure to keep this a power of two to avoid the slow divide.
+ This is also a speed/memory tradeoff; 128 is enough for low ASCII.
+*/
+#define CHAR_WIDTH_HASH_SIZE 128
+
+/********** Translation codes **********/
+
+enum TranslationCodes
+{
+ GLUI_TRANSLATION_MOUSE_NONE = 0,
+ GLUI_TRANSLATION_MOUSE_UP,
+ GLUI_TRANSLATION_MOUSE_DOWN,
+ GLUI_TRANSLATION_MOUSE_LEFT,
+ GLUI_TRANSLATION_MOUSE_RIGHT,
+ GLUI_TRANSLATION_MOUSE_UP_LEFT,
+ GLUI_TRANSLATION_MOUSE_UP_RIGHT,
+ GLUI_TRANSLATION_MOUSE_DOWN_LEFT,
+ GLUI_TRANSLATION_MOUSE_DOWN_RIGHT
+};
+
+/************ A string type for us to use **********/
+
+typedef std::string GLUI_String;
+GLUI_String& glui_format_str(GLUI_String &str, const char* fmt, ...);
+
+/********* Pre-declare classes as needed *********/
+
+class GLUI;
+class GLUI_Control;
+class GLUI_Listbox;
+class GLUI_StaticText;
+class GLUI_EditText;
+class GLUI_Panel;
+class GLUI_Spinner;
+class GLUI_RadioButton;
+class GLUI_RadioGroup;
+class GLUI_Glut_Window;
+class GLUI_TreePanel;
+class GLUI_Scrollbar;
+class GLUI_List;
+
+class Arcball;
+
+/*** Flags for GLUI class constructor ***/
+#define GLUI_SUBWINDOW ((long)(1<<1))
+#define GLUI_SUBWINDOW_TOP ((long)(1<<2))
+#define GLUI_SUBWINDOW_BOTTOM ((long)(1<<3))
+#define GLUI_SUBWINDOW_LEFT ((long)(1<<4))
+#define GLUI_SUBWINDOW_RIGHT ((long)(1<<5))
+
+/*** Codes for different type of edittext boxes and spinners ***/
+#define GLUI_EDITTEXT_TEXT 1
+#define GLUI_EDITTEXT_INT 2
+#define GLUI_EDITTEXT_FLOAT 3
+#define GLUI_SPINNER_INT GLUI_EDITTEXT_INT
+#define GLUI_SPINNER_FLOAT GLUI_EDITTEXT_FLOAT
+#define GLUI_SCROLL_INT GLUI_EDITTEXT_INT
+#define GLUI_SCROLL_FLOAT GLUI_EDITTEXT_FLOAT
+// This is only for deprecated interface
+#define GLUI_EDITTEXT_STRING 4
+
+/*** Definition of callbacks ***/
+typedef void (*GLUI_Update_CB) (int id);
+typedef void (*GLUI_Control_CB)(GLUI_Control *);
+typedef void (*Int1_CB) (int);
+typedef void (*Int2_CB) (int, int);
+typedef void (*Int3_CB) (int, int, int);
+typedef void (*Int4_CB) (int, int, int, int);
+
+/************************************************************/
+/**
+ Callback Adapter Class
+ Allows us to support different types of callbacks;
+ like a GLUI_Update_CB function pointer--which takes an int;
+ and a GLUI_Control_CB function pointer--which takes a GUI_Control object.
+*/
+class GLUI_CB
+{
+public:
+ GLUI_CB() : idCB(0),objCB(0) {}
+ GLUI_CB(GLUI_Update_CB cb) : idCB(cb),objCB(0) {}
+ GLUI_CB(GLUI_Control_CB cb) : idCB(0),objCB(cb) {}
+ // (Compiler generated copy constructor)
+
+ /** This control just activated. Fire our callback.*/
+ void operator()(GLUI_Control *ctrl) const;
+ bool operator!() const { return !idCB && !objCB; }
+ operator bool() const { return !(!(*this)); }
+private:
+ GLUI_Update_CB idCB;
+ GLUI_Control_CB objCB;
+};
+
+/************************************************************/
+/* */
+/* Base class, for hierarchical relationships */
+/* */
+/************************************************************/
+
+class GLUI_Control;
+
+/**
+ GLUI_Node is a node in a sort of tree of GLUI controls.
+ Each GLUI_Node has a list of siblings (in a circular list)
+ and a linked list of children.
+
+ Everything onscreen is a GLUI_Node--windows, buttons, etc.
+ The nodes are traversed for event processing, sizing, redraws, etc.
+*/
+class GLUI_Node
+{
+ friend class GLUI_Tree; /* JVK */
+ friend class GLUI_Rollout;
+ friend class GLUI_Main;
+
+public:
+ GLUI_Node();
+ virtual ~GLUI_Node() {}
+
+ GLUI_Node *first_sibling();
+ GLUI_Node *last_sibling();
+ GLUI_Node *prev();
+ GLUI_Node *next();
+
+ GLUI_Node *first_child() { return child_head; }
+ GLUI_Node *last_child() { return child_tail; }
+ GLUI_Node *parent() { return parent_node; }
+
+ /** Link in a new child control */
+ virtual int add_control( GLUI_Control *control );
+
+ void link_this_to_parent_last (GLUI_Node *parent );
+ void link_this_to_parent_first(GLUI_Node *parent );
+ void link_this_to_sibling_next(GLUI_Node *sibling );
+ void link_this_to_sibling_prev(GLUI_Node *sibling );
+ void unlink();
+
+ void dump( FILE *out, const char *name );
+
+protected:
+ static void add_child_to_control(GLUI_Node *parent,GLUI_Control *child);
+ GLUI_Node *parent_node;
+ GLUI_Node *child_head;
+ GLUI_Node *child_tail;
+ GLUI_Node *next_sibling;
+ GLUI_Node *prev_sibling;
+};
+
+
+/************************************************************/
+/* */
+/* Standard Bitmap stuff */
+/* */
+/************************************************************/
+
+enum GLUI_StdBitmaps_Codes
+{
+ GLUI_STDBITMAP_CHECKBOX_OFF = 0,
+ GLUI_STDBITMAP_CHECKBOX_ON,
+ GLUI_STDBITMAP_RADIOBUTTON_OFF,
+ GLUI_STDBITMAP_RADIOBUTTON_ON,
+ GLUI_STDBITMAP_UP_ARROW,
+ GLUI_STDBITMAP_DOWN_ARROW,
+ GLUI_STDBITMAP_LEFT_ARROW,
+ GLUI_STDBITMAP_RIGHT_ARROW,
+ GLUI_STDBITMAP_SPINNER_UP_OFF,
+ GLUI_STDBITMAP_SPINNER_UP_ON,
+ GLUI_STDBITMAP_SPINNER_DOWN_OFF,
+ GLUI_STDBITMAP_SPINNER_DOWN_ON,
+ GLUI_STDBITMAP_CHECKBOX_OFF_DIS, /*** Disactivated control bitmaps ***/
+ GLUI_STDBITMAP_CHECKBOX_ON_DIS,
+ GLUI_STDBITMAP_RADIOBUTTON_OFF_DIS,
+ GLUI_STDBITMAP_RADIOBUTTON_ON_DIS,
+ GLUI_STDBITMAP_SPINNER_UP_DIS,
+ GLUI_STDBITMAP_SPINNER_DOWN_DIS,
+ GLUI_STDBITMAP_LISTBOX_UP,
+ GLUI_STDBITMAP_LISTBOX_DOWN,
+ GLUI_STDBITMAP_LISTBOX_UP_DIS,
+ GLUI_STDBITMAP_NUM_ITEMS
+};
+
+/************************************************************/
+/* */
+/* Class GLUI_Bitmap */
+/* */
+/************************************************************/
+
+/**
+ GLUI_Bitmap is a simple 2D texture map. It's used
+ to represent small textures like checkboxes, arrows, etc.
+ via the GLUI_StdBitmaps class.
+*/
+class GLUI_Bitmap
+{
+ friend class GLUI_StdBitmaps;
+
+public:
+ GLUI_Bitmap();
+ ~GLUI_Bitmap();
+
+ /** Create bitmap from greyscale byte image */
+ void init_grey(unsigned char *array);
+
+ /** Create bitmap from color int image */
+ void init(int *array);
+
+private:
+ /** RGB pixel data */
+ unsigned char *pixels;
+ int w, h;
+};
+
+
+/************************************************************/
+/* */
+/* Class GLUI_StdBitmap */
+/* */
+/************************************************************/
+
+/**
+ Keeps an array of GLUI_Bitmap objects to represent all the
+ images used in the UI: checkboxes, arrows, etc.
+*/
+class GLUI_StdBitmaps
+{
+public:
+ GLUI_StdBitmaps();
+ ~GLUI_StdBitmaps();
+
+ /** Return the width (in pixels) of the n'th standard bitmap. */
+ int width (int n) const;
+ /** Return the height (in pixels) of the n'th standard bitmap. */
+ int height(int n) const;
+
+ /** Draw the n'th standard bitmap (one of the enums
+ listed in GLUI_StdBitmaps_Codes) at pixel corner (x,y).
+ */
+ void draw(int n, int x, int y) const;
+
+private:
+ GLUI_Bitmap bitmaps[GLUI_STDBITMAP_NUM_ITEMS];
+};
+
+/************************************************************/
+/* */
+/* Master GLUI Class */
+/* */
+/************************************************************/
+
+/**
+ The master manages our interaction with GLUT.
+ There's only one GLUI_Master_Object.
+*/
+class GLUI_Master_Object
+{
+
+ friend void glui_idle_func();
+
+public:
+
+ GLUI_Master_Object();
+ ~GLUI_Master_Object();
+
+ GLUI_Node gluis;
+ GLUI_Control *active_control, *curr_left_button_glut_menu;
+ GLUI *active_control_glui;
+ int glui_id_counter;
+
+ GLUI_Glut_Window *find_glut_window( int window_id );
+
+ void set_glutIdleFunc(void (*f)(void));
+
+ /**************
+ void (*glut_keyboard_CB)(unsigned char, int, int);
+ void (*glut_reshape_CB)(int, int);
+ void (*glut_special_CB)(int, int, int);
+ void (*glut_mouse_CB)(int,int,int,int);
+
+ void (*glut_passive_motion_CB)(int,int);
+ void (*glut_visibility_CB)(int);
+ void (*glut_motion_CB)(int,int);
+ void (*glut_display_CB)(void);
+ void (*glut_entry_CB)(int);
+ **********/
+
+ void set_left_button_glut_menu_control( GLUI_Control *control );
+
+ /********** GLUT callthroughs **********/
+ /* These are the glut callbacks that we do not handle */
+
+ void set_glutReshapeFunc (void (*f)(int width, int height));
+ void set_glutKeyboardFunc(void (*f)(unsigned char key, int x, int y));
+ void set_glutSpecialFunc (void (*f)(int key, int x, int y));
+ void set_glutMouseFunc (void (*f)(int, int, int, int ));
+
+ void set_glutDisplayFunc(void (*f)(void)) {glutDisplayFunc(f);}
+ void set_glutTimerFunc(unsigned int millis, void (*f)(int value), int value)
+ { ::glutTimerFunc(millis,f,value);}
+ void set_glutOverlayDisplayFunc(void(*f)(void)){glutOverlayDisplayFunc(f);}
+ void set_glutSpaceballMotionFunc(Int3_CB f) {glutSpaceballMotionFunc(f);}
+ void set_glutSpaceballRotateFunc(Int3_CB f) {glutSpaceballRotateFunc(f);}
+ void set_glutSpaceballButtonFunc(Int2_CB f) {glutSpaceballButtonFunc(f);}
+ void set_glutTabletMotionFunc(Int2_CB f) {glutTabletMotionFunc(f);}
+ void set_glutTabletButtonFunc(Int4_CB f) {glutTabletButtonFunc(f);}
+ /* void set_glutWindowStatusFunc(Int1_CB f) {glutWindowStatusFunc(f);} */
+ void set_glutMenuStatusFunc(Int3_CB f) {glutMenuStatusFunc(f);}
+ void set_glutMenuStateFunc(Int1_CB f) {glutMenuStateFunc(f);}
+ void set_glutButtonBoxFunc(Int2_CB f) {glutButtonBoxFunc(f);}
+ void set_glutDialsFunc(Int2_CB f) {glutDialsFunc(f);}
+
+
+ GLUI *create_glui( const char *name, long flags=0, int x=-1, int y=-1 );
+ GLUI *create_glui_subwindow( int parent_window, long flags=0 );
+ GLUI *find_glui_by_window_id( int window_id );
+ void get_viewport_area( int *x, int *y, int *w, int *h );
+ void auto_set_viewport();
+ void close_all();
+ void sync_live_all();
+
+ void reshape();
+
+ float get_version() { return GLUI_VERSION; }
+
+ void glui_setIdleFuncIfNecessary(void);
+
+private:
+ GLUI_Node glut_windows;
+ void (*glut_idle_CB)(void);
+
+ void add_cb_to_glut_window(int window,int cb_type,void *cb);
+};
+
+/**
+ This is the only GLUI_Master_Object in existence.
+*/
+extern GLUI_Master_Object GLUI_Master;
+
+/************************************************************/
+/* */
+/* Class for managing a GLUT window */
+/* */
+/************************************************************/
+
+/**
+ A top-level window. The GLUI_Master GLUT callback can route events
+ to the callbacks in this class, for arbitrary use by external users.
+ (see GLUI_Master_Object::set_glutKeyboardFunc).
+
+ This entire approach seems to be superceded by the "subwindow" flavor
+ of GLUI.
+*/
+class GLUI_Glut_Window : public GLUI_Node
+{
+public:
+ GLUI_Glut_Window();
+
+ int glut_window_id;
+
+ /*********** Pointers to GLUT callthrough functions *****/
+ void (*glut_keyboard_CB)(unsigned char, int, int);
+ void (*glut_special_CB)(int, int, int);
+ void (*glut_reshape_CB)(int, int);
+ void (*glut_passive_motion_CB)(int,int);
+ void (*glut_mouse_CB)(int,int,int,int);
+ void (*glut_visibility_CB)(int);
+ void (*glut_motion_CB)(int,int);
+ void (*glut_display_CB)(void);
+ void (*glut_entry_CB)(int);
+};
+
+/************************************************************/
+/* */
+/* Main Window GLUI class (not user-level) */
+/* */
+/************************************************************/
+
+/**
+ A GLUI_Main handles GLUT events for one window, routing them to the
+ appropriate controls. The central user-visible "GLUI" class
+ inherits from this class; users should not allocate GLUT_Main objects.
+
+ There's a separate GLUI_Main object for:
+ - Each top-level window with GUI stuff in it.
+ - Each "subwindow" of another top-level window.
+
+ All the GLUI_Main objects are listed in GLUI_Master.gluis.
+ A better name for this class might be "GLUI_Environment";
+ this class provides the window-level context for every control.
+*/
+class GLUI_Main : public GLUI_Node
+{
+ /********** Friend classes *************/
+
+ friend class GLUI_Control;
+ friend class GLUI_Rotation;
+ friend class GLUI_Translation;
+ friend class GLUI;
+ friend class GLUI_Master_Object;
+
+ /*********** Friend functions **********/
+
+ friend void glui_mouse_func(int button, int state, int x, int y);
+ friend void glui_keyboard_func(unsigned char key, int x, int y);
+ friend void glui_special_func(int key, int x, int y);
+ friend void glui_passive_motion_func(int x, int y);
+ friend void glui_reshape_func( int w, int h );
+ friend void glui_visibility_func(int state);
+ friend void glui_motion_func(int x, int y);
+ friend void glui_entry_func(int state);
+ friend void glui_display_func( void );
+ friend void glui_idle_func(void);
+
+ friend void glui_parent_window_reshape_func( int w, int h );
+ friend void glui_parent_window_keyboard_func( unsigned char, int, int );
+ friend void glui_parent_window_special_func( int, int, int );
+ friend void glui_parent_window_mouse_func( int, int, int, int );
+
+protected:
+ /*** Variables ***/
+ int main_gfx_window_id;
+ int mouse_button_down;
+ int glut_window_id;
+ int top_level_glut_window_id;
+ GLUI_Control *active_control;
+ GLUI_Control *mouse_over_control;
+ GLUI_Panel *main_panel;
+ enum buffer_mode_t {
+ buffer_front=1, ///< Draw updated controls directly to screen.
+ buffer_back=2 ///< Double buffering: postpone updates until next redraw.
+ };
+ buffer_mode_t buffer_mode; ///< Current drawing mode
+ int curr_cursor;
+ int w, h;
+ long flags;
+ bool closing;
+ int parent_window;
+ int glui_id;
+
+ /********** Misc functions *************/
+
+ GLUI_Control *find_control( int x, int y );
+ GLUI_Control *find_next_control( GLUI_Control *control );
+ GLUI_Control *find_next_control_rec( GLUI_Control *control );
+ GLUI_Control *find_next_control_( GLUI_Control *control );
+ GLUI_Control *find_prev_control( GLUI_Control *control );
+ void create_standalone_window( const char *name, int x=-1, int y=-1 );
+ void create_subwindow( int parent,int window_alignment );
+ void setup_default_glut_callbacks( void );
+
+ void mouse(int button, int state, int x, int y);
+ void keyboard(unsigned char key, int x, int y);
+ void special(int key, int x, int y);
+ void passive_motion(int x, int y);
+ void reshape( int w, int h );
+ void visibility(int state);
+ void motion(int x, int y);
+ void entry(int state);
+ void display( void );
+ void idle(void);
+ int needs_idle(void);
+
+ void (*glut_mouse_CB)(int, int, int, int);
+ void (*glut_keyboard_CB)(unsigned char, int, int);
+ void (*glut_special_CB)(int, int, int);
+ void (*glut_reshape_CB)(int, int);
+
+
+ /*********** Controls ************/
+
+ virtual int add_control( GLUI_Node *parent, GLUI_Control *control );
+
+
+ /********** Constructors and Destructors ***********/
+
+ GLUI_Main( void );
+
+public:
+ GLUI_StdBitmaps std_bitmaps;
+ GLUI_String window_name;
+ RGBc bkgd_color;
+ float bkgd_color_f[3];
+
+ void *font;
+ int curr_modifiers;
+
+ void adjust_glut_xy( int &x, int &y ) { x; y = h-y; }
+ void activate_control( GLUI_Control *control, int how );
+ void align_controls( GLUI_Control *control );
+ void deactivate_current_control( void );
+
+ /** Draw a 3D-look pushed-out box around this rectangle */
+ void draw_raised_box( int x, int y, int w, int h );
+ /** Draw a 3D-look pushed-in box around this rectangle */
+ void draw_lowered_box( int x, int y, int w, int h );
+
+ /** Return true if this control should redraw itself immediately (front buffer);
+ Or queue up a redraw and return false if it shouldn't (back buffer).
+ */
+ bool should_redraw_now(GLUI_Control *ctl);
+
+ /** Switch to the appropriate draw buffer now. Returns the old draw buffer.
+ This routine should probably only be called from inside the GLUI_DrawingSentinal,
+ in glui_internal_control.h
+ */
+ int set_current_draw_buffer();
+ /** Go back to using this draw buffer. Undoes set_current_draw_buffer. */
+ void restore_draw_buffer( int buffer_state );
+
+ /** Pack, resize the window, and redraw all the controls. */
+ void refresh();
+
+ /** Redraw the main graphics window */
+ void post_update_main_gfx();
+
+ /** Recompute the sizes and positions of all controls */
+ void pack_controls();
+
+ void close_internal();
+ void check_subwindow_position();
+ void set_ortho_projection();
+ void set_viewport();
+ int get_glut_window_id( void ) { return glut_window_id; } /* JVK */
+};
+
+/************************************************************/
+/* */
+/* GLUI_Control: base class for all controls */
+/* */
+/************************************************************/
+
+/**
+ All the GUI objects inherit from GLUI_Control: buttons,
+ checkboxes, labels, edit boxes, scrollbars, etc.
+ Most of the work of this class is in routing events,
+ like keystrokes, mouseclicks, redraws, and sizing events.
+
+ Yes, this is a huge and hideous class. It needs to be
+ split up into simpler subobjects. None of the data members
+ should be directly accessed by users (they should be protected,
+ not public); only subclasses.
+*/
+class GLUI_Control : public GLUI_Node
+{
+public:
+
+/** Onscreen coordinates */
+ int w, h; /* dimensions of control */
+ int x_abs, y_abs;
+ int x_off, y_off_top, y_off_bot; /* INNER margins, by which child
+ controls are indented */
+ int contain_x, contain_y;
+ int contain_w, contain_h;
+ /* if this is a container control (e.g.,
+ radiogroup or panel) this indicated dimensions
+ of inner area in which controls reside */
+
+/** "activation" for tabbing between controls. */
+ int active_type; ///< "GLUI_CONTROL_ACTIVE_..."
+ bool active; ///< If true, we've got the focus
+ bool can_activate; ///< If false, remove from tab order.
+ bool spacebar_mouse_click; ///< Spacebar simulates click.
+
+/** Callbacks */
+ long user_id; ///< Integer to pass to callback function.
+ GLUI_CB callback; ///< User callback function, or NULL.
+
+/** Variable value storage */
+ float float_val; /**< Our float value */
+ int int_val; /**< Our integer value */
+ float float_array_val[GLUI_DEF_MAX_ARRAY];
+ int float_array_size;
+ GLUI_String text; /**< The text inside this control */
+
+/** "Live variable" updating */
+ void *ptr_val; /**< A pointer to the user's live variable value */
+ int live_type;
+ bool live_inited;
+ /* These variables store the last value that live variable was known to have. */
+ int last_live_int;
+ float last_live_float;
+ GLUI_String last_live_text;
+ float last_live_float_array[GLUI_DEF_MAX_ARRAY];
+
+/** Properties of our control */
+ GLUI *glui; /**< Our containing event handler (NEVER NULL during event processing!) */
+ bool is_container; /**< Is this a container class (e.g., panel) */
+ int alignment;
+ bool enabled; /**< Is this control grayed out? */
+ GLUI_String name; /**< The name of this control */
+ void *font; /**< Our glutbitmap font */
+ bool collapsible, is_open;
+ GLUI_Node collapsed_node;
+ bool hidden; /* Collapsed controls (and children) are hidden */
+ int char_widths[CHAR_WIDTH_HASH_SIZE][2]; /* Character width hash table */
+
+public:
+ /*** Get/Set values ***/
+ virtual void set_name( const char *string );
+ virtual void set_int_val( int new_int ) { int_val = new_int; output_live(true); }
+ virtual void set_float_val( float new_float ) { float_val = new_float; output_live(true); }
+ virtual void set_ptr_val( void *new_ptr ) { ptr_val = new_ptr; output_live(true); }
+ virtual void set_float_array_val( float *array_ptr );
+
+ virtual float get_float_val( void ) { return float_val; }
+ virtual int get_int_val( void ) { return int_val; }
+ virtual void get_float_array_val( float *array_ptr );
+ virtual int get_id( void ) const { return int(user_id); }
+ virtual void set_id( int id ) { user_id=id; }
+
+ virtual int mouse_down_handler( int local_x, int local_y ) { local_x; local_y; return false; }
+ virtual int mouse_up_handler( int local_x, int local_y, bool inside ) { local_x; local_y; inside; return false; }
+ virtual int mouse_held_down_handler( int local_x, int local_y, bool inside) { local_x; local_y; inside; return false; }
+ virtual int key_handler( unsigned char key, int modifiers ) { key; modifiers; return false; }
+ virtual int special_handler( int key,int modifiers ) { key; modifiers; return false; }
+
+ virtual void update_size( void ) { }
+ virtual void idle( void ) { }
+ virtual int mouse_over( int state, int x, int y ) { state; x; y; return false; }
+
+ virtual void enable( void );
+ virtual void disable( void );
+ virtual void activate( int how ) { how; active = true; }
+ virtual void deactivate( void ) { active = false; }
+
+ /** Hide (shrink into a rollout) and unhide (expose from a rollout) */
+ void hide_internal( int recurse );
+ void unhide_internal( int recurse );
+
+ /** Return true if it currently makes sense to draw this class. */
+ int can_draw( void ) { return (glui != NULL && hidden == false); }
+
+ /** Redraw this control.
+ In single-buffering mode (drawing to GL_FRONT), this is just
+ a call to translate_and_draw_front (after a can_draw() check).
+ In double-buffering mode (drawing to GL_BACK), this queues up
+ a redraw and returns false, since you shouldn't draw yet.
+ */
+ void redraw(void);
+
+ /** Redraw everybody in our window. */
+ void redraw_window(void);
+
+ virtual void align( void );
+ void pack( int x, int y ); /* Recalculate positions and offsets */
+ void pack_old( int x, int y );
+ void draw_recursive( int x, int y );
+ int set_to_glut_window( void );
+ void restore_window( int orig );
+ void translate_and_draw_front( void );
+ void translate_to_origin( void )
+ {glTranslatef((float)x_abs+.5f,(float)y_abs+.5f,0.0f);}
+ virtual void draw( int x, int y )=0;
+ void set_font( void *new_font );
+ void *get_font( void );
+ int string_width( const char *text );
+ int string_width( const GLUI_String &str )
+ { return string_width(str.c_str()); }
+ int char_width( char c );
+
+ void draw_name( int x, int y );
+ void draw_box_inwards_outline( int x_min, int x_max,
+ int y_min, int y_max );
+ void draw_box( int x_min, int x_max, int y_min, int y_max,
+ float r, float g, float b );
+ void draw_bkgd_box( int x_min, int x_max, int y_min, int y_max );
+ void draw_emboss_box( int x_min, int x_max,int y_min,int y_max);
+ void draw_string( const char *text );
+ void draw_string( const GLUI_String &s )
+ { draw_string(s.c_str()); }
+ void draw_char( char c );
+ void draw_active_box( int x_min, int x_max, int y_min, int y_max );
+ void set_to_bkgd_color( void );
+
+ void set_w( int new_w );
+ void set_h( int new_w );
+ void set_alignment( int new_align );
+ void sync_live( int recurse, int draw ); /* Reads live variable */
+ void init_live( void );
+ void output_live( int update_main_gfx ); /** Writes live variable **/
+ virtual void set_text( const char *t ) { t; }
+ void execute_callback( void );
+ void get_this_column_dims( int *col_x, int *col_y,
+ int *col_w, int *col_h,
+ int *col_x_off, int *col_y_off );
+ virtual bool needs_idle( void ) const;
+ virtual bool wants_tabs() const { return false; }
+
+ GLUI_Control(void)
+ {
+ x_off = GLUI_XOFF;
+ y_off_top = GLUI_YOFF;
+ y_off_bot = GLUI_YOFF;
+ x_abs = GLUI_XOFF;
+ y_abs = GLUI_YOFF;
+ active = false;
+ enabled = true;
+ int_val = 0;
+ last_live_int = 0;
+ float_array_size = 0;
+ glui_format_str(name, "Control: %p", this);
+ float_val = 0.0;
+ last_live_float = 0.0;
+ ptr_val = NULL;
+ glui = NULL;
+ w = GLUI_DEFAULT_CONTROL_WIDTH;
+ h = GLUI_DEFAULT_CONTROL_HEIGHT;
+ font = NULL;
+ active_type = GLUI_CONTROL_ACTIVE_MOUSEDOWN;
+ alignment = GLUI_ALIGN_LEFT;
+ is_container = false;
+ can_activate = true; /* By default, you can activate a control */
+ spacebar_mouse_click = true; /* Does spacebar simulate a mouse click? */
+ live_type = GLUI_LIVE_NONE;
+ text = "";
+ last_live_text == "";
+ live_inited = false;
+ collapsible = false;
+ is_open = true;
+ hidden = false;
+ memset(char_widths, -1, sizeof(char_widths)); /* JVK */
+ int i;
+ for( i=0; i<GLUI_DEF_MAX_ARRAY; i++ )
+ float_array_val[i] = last_live_float_array[i] = 0.0;
+ }
+
+ virtual ~GLUI_Control();
+};
+
+/************************************************************/
+/* */
+/* Button class (container) */
+/* */
+/************************************************************/
+/**
+ An onscreen, clickable button--an outlined label that
+ can be clicked. When clicked, a button
+ calls its GLUI_CB callback with its ID.
+*/
+class GLUI_Button : public GLUI_Control
+{
+public:
+ bool currently_inside;
+
+ int mouse_down_handler( int local_x, int local_y );
+ int mouse_up_handler( int local_x, int local_y, bool inside );
+ int mouse_held_down_handler( int local_x, int local_y, bool inside );
+ int key_handler( unsigned char key,int modifiers );
+
+ void draw( int x, int y );
+ void draw_pressed( void );
+ void draw_text( int sunken );
+
+ void update_size( void );
+
+/**
+ Create a new button.
+
+ @param parent The panel our object is inside; or the main GLUI object.
+ @param name The text inside the button.
+ @param id Optional ID number, to pass to the optional callback function.
+ @param callback Optional callback function, taking either the int ID or control.
+*/
+ GLUI_Button( GLUI_Node *parent, const char *name,
+ int id=-1, GLUI_CB cb=GLUI_CB() );
+ GLUI_Button( void ) { common_init(); };
+
+protected:
+ void common_init(void) {
+ glui_format_str(name, "Button: %p", this );
+ h = GLUI_BUTTON_SIZE;
+ w = 100;
+ alignment = GLUI_ALIGN_CENTER;
+ can_activate = true;
+ }
+};
+
+
+/************************************************************/
+/* */
+/* Checkbox class (container) */
+/* */
+/************************************************************/
+
+/**
+ A checkbox, which can be checked on or off. Can be linked
+ to an int value, which gets 1 for on and 0 for off.
+*/
+class GLUI_Checkbox : public GLUI_Control
+{
+public:
+ int orig_value;
+ bool currently_inside;
+ int text_x_offset;
+
+ int mouse_down_handler( int local_x, int local_y );
+ int mouse_up_handler( int local_x, int local_y, bool inside );
+ int mouse_held_down_handler( int local_x, int local_y, bool inside );
+ int key_handler( unsigned char key,int modifiers );
+
+ void update_size( void );
+
+ void draw( int x, int y );
+
+ void draw_active_area( void );
+ void draw_empty_box( void );
+ void set_int_val( int new_val );
+
+/**
+ Create a new checkbox object.
+
+ @param parent The panel our object is inside; or the main GLUI object.
+ @param name Label next to our checkbox.
+ @param value_ptr Optional integer value to attach to this checkbox. When the
+ checkbox is checked or unchecked, *value_ptr will also be changed. ("Live Vars").
+ @param id Optional ID number, to pass to the optional callback function.
+ @param callback Optional callback function, taking either the int ID or control.
+*/
+ GLUI_Checkbox(GLUI_Node *parent, const char *name, int *value_ptr=NULL,
+ int id=-1, GLUI_CB callback=GLUI_CB());
+ GLUI_Checkbox( void ) { common_init(); }
+
+protected:
+ void common_init(void) {
+ glui_format_str( name, "Checkbox: %p", this );
+ w = 100;
+ h = GLUI_CHECKBOX_SIZE;
+ orig_value = -1;
+ text_x_offset = 18;
+ can_activate = true;
+ live_type = GLUI_LIVE_INT; /* This control has an 'int' live var */
+ }
+};
+
+/************************************************************/
+/* */
+/* Column class */
+/* */
+/************************************************************/
+
+/**
+ A GLUI_Column object separates all previous controls
+ from subsequent controls with a vertical bar.
+*/
+class GLUI_Column : public GLUI_Control
+{
+public:
+ void draw( int x, int y );
+
+/**
+ Create a new column, which separates the previous controls
+ from subsequent controls.
+
+ @param parent The panel our object is inside; or the main GLUI object.
+ @param draw_bar If true, draw a visible bar between new and old controls.
+*/
+ GLUI_Column( GLUI_Node *parent, int draw_bar = true );
+ GLUI_Column( void ) { common_init(); }
+
+protected:
+ void common_init() {
+ w = 0;
+ h = 0;
+ int_val = 0;
+ can_activate = false;
+ }
+};
+
+
+/************************************************************/
+/* */
+/* Panel class (container) */
+/* */
+/************************************************************/
+
+/**
+ A GLUI_Panel contains a group of related controls.
+*/
+class GLUI_Panel : public GLUI_Control
+{
+public:
+
+/**
+ Create a new panel. A panel groups together a set of related controls.
+
+ @param parent The outer panel our panel is inside; or the main GLUI object.
+ @param name The string name at the top of our panel.
+ @param type Optional style to display the panel with--GLUI_PANEL_EMBOSSED by default.
+ GLUI_PANEL_RAISED causes the panel to appear higher than the surroundings.
+ GLUI_PANEL_NONE causes the panel's outline to be invisible.
+*/
+ GLUI_Panel( GLUI_Node *parent, const char *name,
+ int type=GLUI_PANEL_EMBOSSED );
+ GLUI_Panel() { common_init(); }
+
+ void draw( int x, int y );
+ void set_name( const char *text );
+ void set_type( int new_type );
+
+ void update_size( void );
+
+protected:
+ void common_init( void ) {
+ w = 300;
+ h = GLUI_DEFAULT_CONTROL_HEIGHT + 7;
+ int_val = GLUI_PANEL_EMBOSSED;
+ alignment = GLUI_ALIGN_CENTER;
+ is_container = true;
+ can_activate = false;
+ name="";
+ };
+};
+
+/************************************************************/
+/* */
+/* File Browser class (container) */
+/* JVK */
+/************************************************************/
+
+/**
+ A list of files the user can select from.
+*/
+class GLUI_FileBrowser : public GLUI_Panel
+{
+public:
+/**
+ Create a new list of files the user can select from.
+
+ @param parent The panel our object is inside; or the main GLUI object.
+ @param name Prompt to give to the user at the top of the file browser.
+ @param frame_type Optional style to display the panel with--GLUI_PANEL_EMBOSSED by default.
+ GLUI_PANEL_RAISED causes the panel to appear higher than the surroundings.
+ GLUI_PANEL_NONE causes the panel's outline to be invisible.
+ @param id Optional ID number, to pass to the optional callback function.
+ @param callback Optional callback function, taking either the int ID or control.
+*/
+ GLUI_FileBrowser( GLUI_Node *parent,
+ const char *name,
+ int frame_type = GLUI_PANEL_EMBOSSED,
+ int user_id = -1,
+ GLUI_CB callback = GLUI_CB());
+
+ GLUI_List *list;
+ GLUI_String current_dir;
+
+ void fbreaddir(const char *);
+ static void dir_list_callback(GLUI_Control*);
+
+ void set_w(int w);
+ void set_h(int h);
+ const char* get_file() { return file.c_str(); }
+ void set_allow_change_dir(int c) { allow_change_dir = c; }
+
+protected:
+ void common_init()
+ {
+ w = GLUI_DEFAULT_CONTROL_WIDTH;
+ h = GLUI_DEFAULT_CONTROL_HEIGHT;
+ int_val = GLUI_PANEL_EMBOSSED;
+ alignment = GLUI_ALIGN_CENTER;
+ is_container = true;
+ can_activate = false;
+ allow_change_dir = true;
+ last_item = -1;
+ user_id = -1;
+ name = "";
+ current_dir = ".";
+ file = "";
+ };
+
+private:
+ int last_item;
+ GLUI_String file;
+ int allow_change_dir;
+
+};
+
+/************************************************************/
+/* */
+/* Rollout class (container) */
+/* */
+/************************************************************/
+/**
+ A rollout contains a set of controls,
+ like a panel, but can be collapsed to just the name.
+*/
+class GLUI_Rollout : public GLUI_Panel
+{
+public:
+
+/**
+ Create a new rollout. A rollout contains a set of controls,
+ like a panel, but can be collapsed to just the name.
+
+ @param parent The panel our object is inside; or the main GLUI object.
+ @param name String to show at the top of the rollout.
+ @param open Optional boolean. If true (the default), the rollout's controls are displayed.
+ If false, the rollout is closed to display only the name.
+ @param type Optional style to display the panel with--GLUI_PANEL_EMBOSSED by default.
+ GLUI_PANEL_RAISED causes the panel to appear higher than the surroundings.
+ GLUI_PANEL_NONE causes the panel's outline to be invisible.
+*/
+ GLUI_Rollout( GLUI_Node *parent, const char *name, int open=true,
+ int type=GLUI_PANEL_EMBOSSED );
+ GLUI_Rollout( void ) { common_init(); }
+
+
+ bool currently_inside, initially_inside;
+ GLUI_Button button;
+
+ void draw( int x, int y );
+ void draw_pressed( void );
+ int mouse_down_handler( int local_x, int local_y );
+ int mouse_up_handler( int local_x, int local_y, bool inside );
+ int mouse_held_down_handler( int local_x, int local_y, bool inside );
+
+ void open( void );
+ void close( void );
+
+ void update_size( void );
+
+protected:
+ void common_init() {
+ currently_inside = false;
+ initially_inside = false;
+ can_activate = true;
+ is_container = true;
+ h = GLUI_DEFAULT_CONTROL_HEIGHT + 7;
+ w = GLUI_DEFAULT_CONTROL_WIDTH;
+ y_off_top = 21;
+ collapsible = true;
+ name = "";
+ }
+};
+
+/************************************************************/
+/* */
+/* Tree Panel class (container) */
+/* JVK */
+/************************************************************/
+
+/**
+ One collapsible entry in a GLUI_TreePanel.
+*/
+class GLUI_Tree : public GLUI_Panel
+{
+public:
+ GLUI_Tree(GLUI_Node *parent, const char *name,
+ int open=false, int inset=0);
+
+private:
+ int level; // how deep is this node
+ float red; //Color coding of column line
+ float green;
+ float blue;
+ float lred; //Color coding of level name
+ float lgreen;
+ float lblue;
+ int id;
+ GLUI_Column *column;
+ int is_current; // Whether this tree is the
+ // current root in a treePanel
+ int child_number;
+ int format;
+
+public:
+ bool currently_inside, initially_inside;
+ GLUI_Button button;
+ GLUI_String level_name; // level name, eg: 1.1.2, III, or 3
+ GLUI_TreePanel *panel;
+
+ void draw( int x, int y );
+ void draw_pressed( void );
+ int mouse_down_handler( int local_x, int local_y );
+ int mouse_up_handler( int local_x, int local_y, bool inside );
+ int mouse_held_down_handler( int local_x, int local_y, bool inside );
+ void set_column(GLUI_Column *c) { column = c; }
+ void open( void );
+ void close( void );
+
+ /* void set_name( const char *text ) { panel.set_name( text ); }; */
+ void update_size( void );
+ void set_id(int i) { id = i; }
+ void set_level(int l) { level = l; }
+ void set_format(int f) { format = f; }
+ void set_current(int c) { is_current = c; }
+ int get_id() { return id; }
+ int get_level() { return level; }
+ int get_child_number() { return child_number; }
+ void enable_bar() { if (column) { column->int_val = 1; set_color(red, green, blue); } }
+ void disable_bar() { if (column) { column->int_val = 0; } }
+ void set_child_number(int c) { child_number = c; }
+ void set_level_color(float r, float g, float b) {
+ lred = r;
+ lgreen = g;
+ lblue = b;
+ }
+ void set_color(float r, float g, float b) {
+ red = r;
+ green = g;
+ blue = b;
+ }
+protected:
+ void common_init()
+ {
+ currently_inside = false;
+ initially_inside = false;
+ can_activate = true;
+ is_container = true;
+ h = GLUI_DEFAULT_CONTROL_HEIGHT + 7;
+ w = GLUI_DEFAULT_CONTROL_WIDTH;
+ y_off_top = 21;
+ collapsible = true;
+ red = .5;
+ green = .5;
+ blue = .5;
+ lred = 0;
+ lgreen = 0;
+ lblue = 0;
+ column = NULL;
+ is_current = 0;
+ child_number = 0;
+ format = 0;
+ panel = NULL;
+ name = "";
+ level_name = "";
+ level = 0;
+
+ };
+};
+
+
+/************************************************************/
+/* */
+/* TreePanel class (container) JVK */
+/* */
+/************************************************************/
+
+/**
+ Manages, maintains, and formats a tree of GLUI_Tree objects.
+ These are shown in a heirarchical, collapsible display.
+
+ FIXME: There's an infinite loop in the traversal code (OSL 2006/06)
+*/
+class GLUI_TreePanel : public GLUI_Panel
+{
+public:
+ GLUI_TreePanel(GLUI_Node *parent, const char *name,
+ bool open=false, int inset=0);
+
+ int max_levels;
+ int next_id;
+ int format;
+ float red;
+ float green;
+ float blue;
+ float lred;
+ float lgreen;
+ float lblue;
+ int root_children;
+ /* These variables allow the tree panel to traverse the tree
+ using only two function calls. (Well, four, if you count
+ going in reverse */
+
+ GLUI_Tree *curr_branch; /* Current Branch */
+ GLUI_Panel *curr_root; /* Current Root */
+
+public:
+ void set_color(float r, float g, float b);
+ void set_level_color(float r, float g, float b);
+ void set_format(int f) { format = f; }
+
+ /* Adds branch to curr_root */
+ GLUI_Tree * ab(const char *name, GLUI_Tree *root = NULL);
+ /* Goes up one level, resets curr_root and curr_branch to parents*/
+ void fb(GLUI_Tree *branch= NULL);
+ /* Deletes the curr_branch, goes up one level using fb */
+ void db(GLUI_Tree *branch = NULL);
+ /* Finds the very last branch of curr_root, resets vars */
+ void descendBranch(GLUI_Panel *root = NULL);
+ /* Resets curr_root and curr branch to TreePanel and lastChild */
+ void resetToRoot(GLUI_Panel *new_root = NULL);
+ void next( void );
+ void refresh( void );
+ void expand_all( void );
+ void collapse_all( void );
+ void update_all( void );
+ void initNode(GLUI_Tree *temp);
+ void formatNode(GLUI_Tree *temp);
+
+protected:
+ int uniqueID( void ) { next_id++; return next_id - 1; }
+ void common_init()
+ {
+ GLUI_Panel();
+ next_id = 0;
+ curr_root = this;
+ curr_branch = NULL;
+ red = .5;
+ green = .5;
+ blue = .5;
+ root_children = 0;
+ }
+};
+
+/************************************************************/
+/* */
+/* User-Level GLUI class */
+/* */
+/************************************************************/
+
+class GLUI_Rotation;
+class GLUI_Translation;
+
+/**
+ The main user-visible interface object to GLUI.
+
+*/
+class GLUI : public GLUI_Main
+{
+public:
+/** DEPRECATED interface for creating new GLUI objects */
+ int add_control( GLUI_Control *control ) { return main_panel->add_control(control); }
+
+ void add_column( int draw_bar = true );
+ void add_column_to_panel( GLUI_Panel *panel, int draw_bar = true );
+
+ void add_separator( void );
+ void add_separator_to_panel( GLUI_Panel *panel );
+
+ GLUI_RadioGroup
+ *add_radiogroup( int *live_var=NULL,
+ int user_id=-1,GLUI_CB callback=GLUI_CB());
+
+ GLUI_RadioGroup
+ *add_radiogroup_to_panel( GLUI_Panel *panel,
+ int *live_var=NULL,
+ int user_id=-1, GLUI_CB callback=GLUI_CB() );
+ GLUI_RadioButton
+ *add_radiobutton_to_group( GLUI_RadioGroup *group,
+ const char *name );
+
+ GLUI_Listbox *add_listbox( const char *name, int *live_var=NULL,
+ int id=-1, GLUI_CB callback=GLUI_CB() );
+ GLUI_Listbox *add_listbox_to_panel( GLUI_Panel *panel,
+ const char *name, int *live_var=NULL,
+ int id=-1, GLUI_CB callback=GLUI_CB());
+
+ GLUI_Rotation *add_rotation( const char *name, float *live_var=NULL,
+ int id=-1, GLUI_CB callback=GLUI_CB() );
+ GLUI_Rotation *add_rotation_to_panel( GLUI_Panel *panel,
+ const char *name, float *live_var=NULL,
+ int id=-1, GLUI_CB callback=GLUI_CB());
+
+ GLUI_Translation *add_translation( const char *name,
+ int trans_type, float *live_var=NULL,
+ int id=-1, GLUI_CB callback=GLUI_CB() );
+ GLUI_Translation *add_translation_to_panel(
+ GLUI_Panel *panel, const char *name,
+ int trans_type, float *live_var=NULL,
+ int id=-1, GLUI_CB callback=GLUI_CB());
+
+ GLUI_Checkbox *add_checkbox( const char *name,
+ int *live_var=NULL,
+ int id=-1, GLUI_CB callback=GLUI_CB());
+ GLUI_Checkbox *add_checkbox_to_panel( GLUI_Panel *panel, const char *name,
+ int *live_var=NULL, int id=-1,
+ GLUI_CB callback=GLUI_CB());
+
+ GLUI_Button *add_button( const char *name, int id=-1,
+ GLUI_CB callback=GLUI_CB());
+ GLUI_Button *add_button_to_panel( GLUI_Panel *panel, const char *name,
+ int id=-1, GLUI_CB callback=GLUI_CB() );
+
+ GLUI_StaticText *add_statictext( const char *name );
+ GLUI_StaticText *add_statictext_to_panel( GLUI_Panel *panel, const char *name );
+
+ GLUI_EditText *add_edittext( const char *name,
+ int data_type=GLUI_EDITTEXT_TEXT,
+ void*live_var=NULL,
+ int id=-1, GLUI_CB callback=GLUI_CB() );
+ GLUI_EditText *add_edittext_to_panel( GLUI_Panel *panel,
+ const char *name,
+ int data_type=GLUI_EDITTEXT_TEXT,
+ void *live_var=NULL, int id=-1,
+ GLUI_CB callback=GLUI_CB() );
+ GLUI_EditText *add_edittext( const char *name, GLUI_String& live_var,
+ int id=-1, GLUI_CB callback=GLUI_CB() );
+ GLUI_EditText *add_edittext_to_panel( GLUI_Panel *panel, const char *name,
+ GLUI_String& live_var, int id=-1,
+ GLUI_CB callback=GLUI_CB() );
+
+ GLUI_Spinner *add_spinner( const char *name,
+ int data_type=GLUI_SPINNER_INT,
+ void *live_var=NULL,
+ int id=-1, GLUI_CB callback=GLUI_CB() );
+ GLUI_Spinner *add_spinner_to_panel( GLUI_Panel *panel,
+ const char *name,
+ int data_type=GLUI_SPINNER_INT,
+ void *live_var=NULL,
+ int id=-1,
+ GLUI_CB callback=GLUI_CB() );
+
+ GLUI_Panel *add_panel( const char *name, int type=GLUI_PANEL_EMBOSSED );
+ GLUI_Panel *add_panel_to_panel( GLUI_Panel *panel, const char *name,
+ int type=GLUI_PANEL_EMBOSSED );
+
+
+ GLUI_Rollout *add_rollout( const char *name, int open=true,
+ int type=GLUI_PANEL_EMBOSSED);
+ GLUI_Rollout *add_rollout_to_panel( GLUI_Panel *panel, const char *name,
+ int open=true,
+ int type=GLUI_PANEL_EMBOSSED);
+
+
+/** Set the window where our widgets should be displayed. */
+ void set_main_gfx_window( int window_id );
+ int get_glut_window_id( void ) { return glut_window_id; }
+
+ void enable( void ) { main_panel->enable(); }
+ void disable( void );
+
+ void sync_live( void );
+
+ void close( void );
+
+ void show( void );
+ void hide( void );
+
+ /***** GLUT callback setup functions *****/
+ /*
+ void set_glutDisplayFunc(void (*f)(void));
+ void set_glutReshapeFunc(void (*f)(int width, int height));
+ void set_glutKeyboardFunc(void (*f)(unsigned char key, int x, int y));
+ void set_glutSpecialFunc(void (*f)(int key, int x, int y));
+ void set_glutMouseFunc(void (*f)(int button, int state, int x, int y));
+ void set_glutMotionFunc(void (*f)(int x, int y));
+ void set_glutPassiveMotionFunc(void (*f)(int x, int y));
+ void set_glutEntryFunc(void (*f)(int state));
+ void set_glutVisibilityFunc(void (*f)(int state));
+ void set_glutInit( int *argcp, const char **argv );
+ void set_glutInitWindowSize(int width, int height);
+ void set_glutInitWindowPosition(int x, int y);
+ void set_glutInitDisplayMode(unsigned int mode);
+ int set_glutCreateWindow(const char *name);
+ */
+
+ /***** Constructors and desctructors *****/
+
+ int init( const char *name, long flags, int x, int y, int parent_window );
+protected:
+ virtual int add_control( GLUI_Node *parent, GLUI_Control *control ) {
+ return GLUI_Main::add_control( parent, control );
+ }
+};
+
+/************************************************************/
+/* */
+/* EditText class */
+/* */
+/************************************************************/
+
+class GLUI_EditText : public GLUI_Control
+{
+public:
+ int has_limits;
+ int data_type;
+ GLUI_String orig_text;
+ int insertion_pt;
+ int title_x_offset;
+ int text_x_offset;
+ int substring_start; /*substring that gets displayed in box*/
+ int substring_end;
+ int sel_start, sel_end; /* current selection */
+ int num_periods;
+ int last_insertion_pt;
+ float float_low, float_high;
+ int int_low, int_high;
+ GLUI_Spinner *spinner;
+ int debug;
+ int draw_text_only;
+
+
+ int mouse_down_handler( int local_x, int local_y );
+ int mouse_up_handler( int local_x, int local_y, bool inside );
+ int mouse_held_down_handler( int local_x, int local_y, bool inside );
+ int key_handler( unsigned char key,int modifiers );
+ int special_handler( int key, int modifiers );
+
+ void activate( int how );
+ void deactivate( void );
+
+ void draw( int x, int y );
+
+ int mouse_over( int state, int x, int y );
+
+ int find_word_break( int start, int direction );
+ int substring_width( int start, int end );
+ void clear_substring( int start, int end );
+ int find_insertion_pt( int x, int y );
+ int update_substring_bounds( void );
+ void update_and_draw_text( void );
+ void draw_text( int x, int y );
+ void draw_insertion_pt( void );
+ void set_numeric_text( void );
+ void update_x_offsets( void );
+ void update_size( void );
+
+ void set_float_limits( float low,float high,int limit_type=GLUI_LIMIT_CLAMP);
+ void set_int_limits( int low, int high, int limit_type=GLUI_LIMIT_CLAMP );
+ void set_float_val( float new_val );
+ void set_int_val( int new_val );
+ void set_text( const char *text );
+ void set_text( const GLUI_String &s) { set_text(s.c_str()); }
+ const char *get_text() { return text.c_str(); }
+
+ void dump( FILE *out, const char *text );
+
+ // Constructor, no live variable
+ GLUI_EditText( GLUI_Node *parent, const char *name,
+ int text_type=GLUI_EDITTEXT_TEXT,
+ int id=-1, GLUI_CB callback=GLUI_CB() );
+ // Constructor, int live variable
+ GLUI_EditText( GLUI_Node *parent, const char *name,
+ int *live_var,
+ int id=-1, GLUI_CB callback=GLUI_CB() );
+ // Constructor, float live variable
+ GLUI_EditText( GLUI_Node *parent, const char *name,
+ float *live_var,
+ int id=-1, GLUI_CB callback=GLUI_CB() );
+ // Constructor, char* live variable
+ GLUI_EditText( GLUI_Node *parent, const char *name,
+ char *live_var,
+ int id=-1, GLUI_CB callback=GLUI_CB() );
+ // Constructor, std::string live variable
+ GLUI_EditText( GLUI_Node *parent, const char *name,
+ std::string &live_var,
+ int id=-1, GLUI_CB callback=GLUI_CB() );
+
+ // Deprecated constructor, only called internally
+ GLUI_EditText( GLUI_Node *parent, const char *name,
+ int text_type, void *live_var,
+ int id, GLUI_CB callback );
+ // Deprecated constructor, only called internally
+ GLUI_EditText( void ) { common_init(); }
+
+protected:
+ void common_init( void ) {
+ h = GLUI_EDITTEXT_HEIGHT;
+ w = GLUI_EDITTEXT_WIDTH;
+ title_x_offset = 0;
+ text_x_offset = 55;
+ insertion_pt = -1;
+ last_insertion_pt = -1;
+ name = "";
+ substring_start = 0;
+ data_type = GLUI_EDITTEXT_TEXT;
+ substring_end = 2;
+ num_periods = 0;
+ has_limits = GLUI_LIMIT_NONE;
+ sel_start = 0;
+ sel_end = 0;
+ active_type = GLUI_CONTROL_ACTIVE_PERMANENT;
+ can_activate = true;
+ spacebar_mouse_click = false;
+ spinner = NULL;
+ debug = false;
+ draw_text_only = false;
+ }
+ void common_construct( GLUI_Node *parent, const char *name,
+ int data_type, int live_type, void *live_var,
+ int id, GLUI_CB callback );
+};
+
+/************************************************************/
+/* */
+/* CommandLine class */
+/* */
+/************************************************************/
+
+class GLUI_CommandLine : public GLUI_EditText
+{
+public:
+ typedef GLUI_EditText Super;
+
+ enum { HIST_SIZE = 100 };
+ std::vector<GLUI_String> hist_list;
+ int curr_hist;
+ int oldest_hist;
+ int newest_hist;
+ bool commit_flag;
+
+public:
+ int key_handler( unsigned char key,int modifiers );
+ int special_handler( int key,int modifiers );
+ void deactivate( void );
+
+ virtual const char *get_history( int command_number ) const
+ { return hist_list[command_number - oldest_hist].c_str(); }
+ virtual GLUI_String& get_history_str( int command_number )
+ { return hist_list[command_number - oldest_hist]; }
+ virtual const GLUI_String& get_history_str( int command_number ) const
+ { return hist_list[command_number - oldest_hist]; }
+ virtual void recall_history( int history_number );
+ virtual void scroll_history( int direction );
+ virtual void add_to_history( const char *text );
+ virtual void reset_history( void );
+
+ void dump( FILE *out, const char *text );
+
+
+ GLUI_CommandLine( GLUI_Node *parent, const char *name, void *live_var=NULL,
+ int id=-1, GLUI_CB callback=GLUI_CB() );
+ GLUI_CommandLine( void ) { common_init(); }
+protected:
+ void common_init() {
+ hist_list.resize(HIST_SIZE);
+ curr_hist = 0;
+ oldest_hist = 0;
+ newest_hist = 0;
+ commit_flag = false;
+ }
+};
+
+/************************************************************/
+/* */
+/* RadioGroup class (container) */
+/* */
+/************************************************************/
+
+class GLUI_RadioGroup : public GLUI_Control
+{
+public:
+ int num_buttons;
+
+ void draw( int x, int y );
+ void set_name( const char *text );
+ void set_int_val( int int_val );
+ void set_selected( int int_val );
+
+ void draw_group( int translate );
+
+ GLUI_RadioGroup( GLUI_Node *parent, int *live_var=NULL,
+ int user_id=-1,GLUI_CB callback=GLUI_CB() );
+ GLUI_RadioGroup( void ) { common_init(); }
+
+protected:
+ void common_init( void ) {
+ x_off = 0;
+ y_off_top = 0;
+ y_off_bot = 0;
+ is_container = true;
+ w = 300;
+ h = 300;
+ num_buttons = 0;
+ name = "";
+ can_activate = false;
+ live_type = GLUI_LIVE_INT;
+ }
+};
+
+/************************************************************/
+/* */
+/* RadioButton class (container) */
+/* */
+/************************************************************/
+
+class GLUI_RadioButton : public GLUI_Control
+{
+public:
+ int orig_value;
+ bool currently_inside;
+ int text_x_offset;
+
+ int mouse_down_handler( int local_x, int local_y );
+ int mouse_up_handler( int local_x, int local_y, bool inside );
+ int mouse_held_down_handler( int local_x, int local_y, bool inside );
+
+ void draw( int x, int y );
+ void update_size( void );
+
+ void draw_active_area( void );
+ void draw_checked( void );
+ void draw_unchecked( void );
+ void draw_O( void );
+
+ GLUI_RadioButton( GLUI_RadioGroup *group, const char *name );
+ GLUI_RadioGroup *group;
+
+protected:
+ void common_init()
+ {
+ glui_format_str( name, "RadioButton: %p", (void *) this );
+ h = GLUI_RADIOBUTTON_SIZE;
+ group = NULL;
+ orig_value = -1;
+ text_x_offset = 18;
+ can_activate = true;
+ }
+};
+
+
+/************************************************************/
+/* */
+/* Separator class (container) */
+/* */
+/************************************************************/
+
+class GLUI_Separator : public GLUI_Control
+{
+public:
+ void draw( int x, int y );
+
+ GLUI_Separator( GLUI_Node *parent );
+ GLUI_Separator( void ) { common_init(); }
+
+protected:
+ void common_init() {
+ w = 100;
+ h = GLUI_SEPARATOR_HEIGHT;
+ can_activate = false;
+ }
+};
+
+#define GLUI_SPINNER_ARROW_WIDTH 12
+#define GLUI_SPINNER_ARROW_HEIGHT 8
+#define GLUI_SPINNER_ARROW_Y 2
+
+#define GLUI_SPINNER_STATE_NONE 0
+#define GLUI_SPINNER_STATE_UP 1
+#define GLUI_SPINNER_STATE_DOWN 2
+#define GLUI_SPINNER_STATE_BOTH 3
+
+#define GLUI_SPINNER_DEFAULT_GROWTH_EXP 1.05f
+
+/************************************************************/
+/* */
+/* Spinner class (container) */
+/* */
+/************************************************************/
+
+class GLUI_Spinner : public GLUI_Control
+{
+public:
+ // Constructor, no live var
+ GLUI_Spinner( GLUI_Node* parent, const char *name,
+ int data_type=GLUI_SPINNER_INT, int id=-1, GLUI_CB callback=GLUI_CB() );
+ // Constructor, int live var
+ GLUI_Spinner( GLUI_Node* parent, const char *name,
+ int *live_var, int id=-1, GLUI_CB callback=GLUI_CB() );
+ // Constructor, float live var
+ GLUI_Spinner( GLUI_Node* parent, const char *name,
+ float *live_var, int id=-1, GLUI_CB callback=GLUI_CB() );
+ // Deprecated constructor
+ GLUI_Spinner( GLUI_Node* parent, const char *name,
+ int data_type,
+ void *live_var,
+ int id=-1, GLUI_CB callback=GLUI_CB() );
+ // Deprecated constructor
+ GLUI_Spinner( void ) { common_init(); }
+
+ bool currently_inside;
+ int state;
+ float growth, growth_exp;
+ int last_x, last_y;
+ int data_type;
+ int callback_count;
+ int last_int_val;
+ float last_float_val;
+ int first_callback;
+ float user_speed;
+
+ GLUI_EditText *edittext;
+
+ int mouse_down_handler( int local_x, int local_y );
+ int mouse_up_handler( int local_x, int local_y, bool inside );
+ int mouse_held_down_handler( int local_x, int local_y, bool inside );
+ int key_handler( unsigned char key,int modifiers );
+ int special_handler( int key,int modifiers );
+
+ void draw( int x, int y );
+ void draw_pressed( void );
+ void draw_unpressed( void );
+ void draw_text( int sunken );
+
+ void update_size( void );
+
+ void set_float_limits( float low,float high,int limit_type=GLUI_LIMIT_CLAMP);
+ void set_int_limits( int low, int high,int limit_type=GLUI_LIMIT_CLAMP);
+ int find_arrow( int local_x, int local_y );
+ void do_drag( int x, int y );
+ void do_callbacks( void );
+ void do_click( void );
+ void idle( void );
+ bool needs_idle( void ) const;
+
+ const char *get_text( void );
+
+ void set_float_val( float new_val );
+ void set_int_val( int new_val );
+ float get_float_val( void );
+ int get_int_val( void );
+ void increase_growth( void );
+ void reset_growth( void );
+
+ void set_speed( float speed ) { user_speed = speed; }
+
+protected:
+ void common_init() {
+ glui_format_str( name, "Spinner: %p", this );
+ h = GLUI_EDITTEXT_HEIGHT;
+ w = GLUI_EDITTEXT_WIDTH;
+ x_off = 0;
+ y_off_top = 0;
+ y_off_bot = 0;
+ can_activate = true;
+ state = GLUI_SPINNER_STATE_NONE;
+ edittext = NULL;
+ growth_exp = GLUI_SPINNER_DEFAULT_GROWTH_EXP;
+ callback_count = 0;
+ first_callback = true;
+ user_speed = 1.0;
+ }
+ void common_construct( GLUI_Node* parent, const char *name,
+ int data_type, void *live_var,
+ int id, GLUI_CB callback );
+};
+
+/************************************************************/
+/* */
+/* StaticText class */
+/* */
+/************************************************************/
+
+class GLUI_StaticText : public GLUI_Control
+{
+public:
+ void set_text( const char *text );
+ void draw( int x, int y );
+ void draw_text( void );
+ void update_size( void );
+ void erase_text( void );
+
+ GLUI_StaticText(GLUI_Node *parent, const char *name);
+ GLUI_StaticText( void ) { common_init(); }
+
+protected:
+ void common_init() {
+ h = GLUI_STATICTEXT_SIZE;
+ name = "";
+ can_activate = false;
+ }
+};
+
+/************************************************************/
+/* */
+/* TextBox class - JVK */
+/* */
+/************************************************************/
+
+class GLUI_TextBox : public GLUI_Control
+{
+public:
+ /* GLUI Textbox - JVK */
+ GLUI_TextBox(GLUI_Node *parent, GLUI_String &live_var,
+ bool scroll = false, int id=-1, GLUI_CB callback=GLUI_CB() );
+ GLUI_TextBox( GLUI_Node *parent,
+ bool scroll = false, int id=-1,
+ GLUI_CB callback=GLUI_CB() );
+
+ GLUI_String orig_text;
+ int insertion_pt;
+ int substring_start; /*substring that gets displayed in box*/
+ int substring_end;
+ int sel_start, sel_end; /* current selection */
+ int last_insertion_pt;
+ int debug;
+ int draw_text_only;
+ int tab_width;
+ int start_line;
+ int num_lines;
+ int curr_line;
+ int visible_lines;
+ int insert_x; /* Similar to "insertion_pt", these variables keep */
+ int insert_y; /* track of where the ptr is, but in pixels */
+ int keygoal_x; /* where up down keys would like to put insertion pt*/
+ GLUI_Scrollbar *scrollbar;
+
+ int mouse_down_handler( int local_x, int local_y );
+ int mouse_up_handler( int local_x, int local_y, bool inside );
+ int mouse_held_down_handler( int local_x, int local_y, bool inside );
+ int key_handler( unsigned char key,int modifiers );
+ int special_handler( int key,int modifiers );
+
+ void activate( int how );
+ void deactivate( void );
+
+ void enable( void );
+ void disable( void );
+
+ void draw( int x, int y );
+
+ int mouse_over( int state, int x, int y );
+
+ int get_box_width();
+ int find_word_break( int start, int direction );
+ int substring_width( int start, int end, int initial_width=0 );
+ void clear_substring( int start, int end );
+ int find_insertion_pt( int x, int y );
+ int update_substring_bounds( void );
+ void update_and_draw_text( void );
+ void draw_text( int x, int y );
+ void draw_insertion_pt( void );
+ void update_x_offsets( void );
+ void update_size( void );
+
+ void set_text( const char *text );
+ const char *get_text( void ) { return text.c_str(); }
+
+ void dump( FILE *out, char *text );
+ void set_tab_w(int w) { tab_width = w; }
+ void set_start_line(int l) { start_line = l; }
+ static void scrollbar_callback(GLUI_Control*);
+
+ bool wants_tabs( void ) const { return true; }
+
+protected:
+ void common_init()
+ {
+ h = GLUI_TEXTBOX_HEIGHT;
+ w = GLUI_TEXTBOX_WIDTH;
+ tab_width = GLUI_TAB_WIDTH;
+ num_lines = 0;
+ visible_lines = 0;
+ start_line = 0;
+ curr_line = 0;
+ insert_y = -1;
+ insert_x = -1;
+ insertion_pt = -1;
+ last_insertion_pt = -1;
+ name[0] = '\0';
+ substring_start = 0;
+ substring_end = 2;
+ sel_start = 0;
+ sel_end = 0;
+ active_type = GLUI_CONTROL_ACTIVE_PERMANENT;
+ can_activate = true;
+ spacebar_mouse_click = false;
+ scrollbar = NULL;
+ debug = false;
+ draw_text_only = false;
+ }
+ void common_construct(
+ GLUI_Node *parent, GLUI_String *live_var,
+ bool scroll, int id, GLUI_CB callback);
+};
+
+/************************************************************/
+/* */
+/* List class - JVK */
+/* */
+/************************************************************/
+
+class GLUI_List_Item : public GLUI_Node
+{
+public:
+ GLUI_String text;
+ int id;
+};
+
+/************************************************************/
+/* */
+/* List class - JVK */
+/* */
+/************************************************************/
+
+class GLUI_List : public GLUI_Control
+{
+public:
+ /* GLUI List - JVK */
+ GLUI_List( GLUI_Node *parent, bool scroll = false,
+ int id=-1, GLUI_CB callback=GLUI_CB() );
+ /*, GLUI_Control *object = NULL
+ ,GLUI_InterObject_CB obj_cb = NULL);*/
+
+ GLUI_List( GLUI_Node *parent,
+ GLUI_String& live_var, bool scroll = false,
+ int id=-1,
+ GLUI_CB callback=GLUI_CB()
+ /*,GLUI_Control *object = NULL */
+ /*,GLUI_InterObject_CB obj_cb = NULL*/);
+
+
+ GLUI_String orig_text;
+ int debug;
+ int draw_text_only;
+ int start_line;
+ int num_lines;
+ int curr_line;
+ int visible_lines;
+ GLUI_Scrollbar *scrollbar;
+ GLUI_List_Item items_list;
+ GLUI_Control *associated_object;
+ GLUI_CB obj_cb;
+ int cb_click_type;
+ int last_line;
+ int last_click_time;
+
+ int mouse_down_handler( int local_x, int local_y );
+ int mouse_up_handler( int local_x, int local_y, bool inside );
+ int mouse_held_down_handler( int local_x, int local_y, bool inside );
+ int key_handler( unsigned char key,int modifiers );
+ int special_handler( int key,int modifiers );
+
+ void activate( int how );
+ void deactivate( void );
+
+ void draw( int x, int y );
+
+ int mouse_over( int state, int x, int y );
+
+ int get_box_width();
+ int find_word_break( int start, int direction );
+ int substring_width( const char *t, int start, int end );
+ int find_line( int x, int y );
+ void update_and_draw_text( void );
+ void draw_text( const char *t, int selected, int x, int y );
+ void update_size( void );
+
+
+ int add_item( int id, const char *text );
+ int delete_item( const char *text );
+ int delete_item( int id );
+ int delete_all();
+
+ GLUI_List_Item *get_item_ptr( const char *text );
+ GLUI_List_Item *get_item_ptr( int id );
+
+ void dump( FILE *out, const char *text );
+ void set_start_line(int l) { start_line = l; }
+ static void scrollbar_callback(GLUI_Control*);
+ int get_current_item() { return curr_line; }
+ void set_click_type(int d) {
+ cb_click_type = d; }
+ void set_object_callback(GLUI_CB cb=GLUI_CB(), GLUI_Control*obj=NULL)
+ { obj_cb=cb; associated_object=obj; }
+
+protected:
+ void common_init()
+ {
+ h = GLUI_LIST_HEIGHT;
+ w = GLUI_LIST_WIDTH;
+ num_lines = 0;
+ visible_lines = 0;
+ start_line = 0;
+ curr_line = 0;
+ name[0] = '\0';
+ active_type = GLUI_CONTROL_ACTIVE_PERMANENT;
+ can_activate = true;
+ spacebar_mouse_click = false;
+ scrollbar = NULL;
+ debug = false;
+ draw_text_only = false;
+ cb_click_type = GLUI_SINGLE_CLICK;
+ last_line = -1;
+ last_click_time = 0;
+ associated_object = NULL;
+ };
+ void common_construct(
+ GLUI_Node *parent,
+ GLUI_String* live_var, bool scroll,
+ int id,
+ GLUI_CB callback
+ /*,GLUI_Control *object*/
+ /*,GLUI_InterObject_CB obj_cb*/);
+};
+
+/************************************************************/
+/* */
+/* Scrollbar class - JVK */
+/* */
+/************************************************************/
+
+class GLUI_Scrollbar : public GLUI_Control
+{
+public:
+ // Constructor, no live var
+ GLUI_Scrollbar( GLUI_Node *parent,
+ const char *name,
+ int horz_vert=GLUI_SCROLL_HORIZONTAL,
+ int data_type=GLUI_SCROLL_INT,
+ int id=-1, GLUI_CB callback=GLUI_CB()
+ /*,GLUI_Control *object = NULL*/
+ /*,GLUI_InterObject_CB obj_cb = NULL*/
+ );
+
+ // Constructor, int live var
+ GLUI_Scrollbar( GLUI_Node *parent, const char *name, int horz_vert,
+ int *live_var,
+ int id=-1, GLUI_CB callback=GLUI_CB()
+ /*,GLUI_Control *object = NULL*/
+ /*,GLUI_InterObject_CB obj_cb = NULL*/
+ );
+
+ // Constructor, float live var
+ GLUI_Scrollbar( GLUI_Node *parent, const char *name, int horz_vert,
+ float *live_var,
+ int id=-1, GLUI_CB callback=GLUI_CB()
+ /*,GLUI_Control *object = NULL*/
+ /*,GLUI_InterObject_CB obj_cb = NULL*/
+ );
+
+ bool currently_inside;
+ int state;
+ float growth, growth_exp;
+ int last_x, last_y;
+ int data_type;
+ int callback_count;
+ int last_int_val; ///< Used to prevent repeated callbacks.
+ float last_float_val;
+ int first_callback;
+ float user_speed;
+ float float_min, float_max;
+ int int_min, int_max;
+ int horizontal;
+ double last_update_time; ///< GLUI_Time() we last advanced scrollbar.
+ double velocity_limit; ///< Maximum distance to advance per second.
+ int box_length;
+ int box_start_position;
+ int box_end_position;
+ int track_length;
+
+
+ /* Rather than directly access an Editbox or Textbox for
+ changing variables, a pointer to some object is defined
+ along with a static callback in the form func(void *, int) -
+ the int is the new value, the void * must be cast to that
+ particular object type before use.
+ */
+ void * associated_object; /* Lets the Spinner manage it's own callbacks */
+ GLUI_CB object_cb; /* function pointer to object call_back */
+
+ int mouse_down_handler( int local_x, int local_y );
+ int mouse_up_handler( int local_x, int local_y, bool inside );
+ int mouse_held_down_handler( int local_x, int local_y, bool inside );
+ int key_handler( unsigned char key,int modifiers );
+ int special_handler( int key,int modifiers );
+
+ void draw( int x, int y );
+ void draw_pressed( void );
+ void draw_unpressed( void );
+ void draw_text( int sunken );
+
+ void update_size( void );
+
+ void set_int_limits( int low, int high,int limit_type=GLUI_LIMIT_CLAMP);
+ void set_float_limits( float low,float high,int limit_type=GLUI_LIMIT_CLAMP);
+ int find_arrow( int local_x, int local_y );
+ void do_drag( int x, int y );
+ void do_callbacks( void );
+ void draw_scroll( void );
+ void do_click( void );
+ void idle( void );
+ bool needs_idle( void ) const;
+ void set_int_val( int new_val );
+ void set_float_val( float new_val );
+ void increase_growth( void );
+ void reset_growth( void );
+
+ void set_speed( float speed ) { user_speed = speed; };
+ void update_scroll_parameters();
+ void set_object_callback(GLUI_CB cb=GLUI_CB(), GLUI_Control*obj=NULL)
+ { object_cb=cb; associated_object=obj; }
+
+protected:
+ void common_init ( void );
+ void common_construct(
+ GLUI_Node *parent,
+ const char *name,
+ int horz_vert,
+ int data_type, void* live_var,
+ int id, GLUI_CB callback
+ /*,GLUI_Control *object
+ ,GLUI_InterObject_CB obj_cb*/
+ );
+
+ virtual void draw_scroll_arrow(int arrowtype, int x, int y);
+ virtual void draw_scroll_box(int x, int y, int w, int h);
+};
+
+/************************************************************/
+/* */
+/* Listbox class */
+/* */
+/************************************************************/
+
+class GLUI_Listbox_Item : public GLUI_Node
+{
+public:
+ GLUI_String text;
+ int id;
+};
+
+class GLUI_Listbox : public GLUI_Control
+{
+public:
+ GLUI_String curr_text;
+ GLUI_Listbox_Item items_list;
+ int depressed;
+
+ int orig_value;
+ bool currently_inside;
+ int text_x_offset, title_x_offset;
+ int glut_menu_id;
+
+ int mouse_down_handler( int local_x, int local_y );
+ int mouse_up_handler( int local_x, int local_y, bool inside );
+ int mouse_held_down_handler( int local_x, int local_y, bool inside );
+ int key_handler( unsigned char key,int modifiers );
+ int special_handler( int key,int modifiers );
+
+ void update_size( void );
+ void draw( int x, int y );
+ int mouse_over( int state, int x, int y );
+
+ void set_int_val( int new_val );
+ void dump( FILE *output );
+
+ int add_item( int id, const char *text );
+ int delete_item( const char *text );
+ int delete_item( int id );
+ int sort_items( void );
+
+ int do_selection( int item );
+
+ GLUI_Listbox_Item *get_item_ptr( const char *text );
+ GLUI_Listbox_Item *get_item_ptr( int id );
+
+
+ GLUI_Listbox( GLUI_Node *parent,
+ const char *name, int *live_var=NULL,
+ int id=-1, GLUI_CB callback=GLUI_CB() );
+ GLUI_Listbox( void ) { common_init(); }
+
+protected:
+ /** Change w and return true if we need to be widened to fit the current item. */
+ bool recalculate_item_width( void );
+ void common_init() {
+ glui_format_str( name, "Listbox: %p", this );
+ w = GLUI_EDITTEXT_WIDTH;
+ h = GLUI_EDITTEXT_HEIGHT;
+ orig_value = -1;
+ title_x_offset = 0;
+ text_x_offset = 55;
+ can_activate = true;
+ curr_text = "";
+ live_type = GLUI_LIVE_INT; /* This has an integer live var */
+ depressed = false;
+ glut_menu_id = -1;
+ }
+
+ ~GLUI_Listbox();
+};
+
+/************************************************************/
+/* */
+/* Mouse_Interaction class */
+/* */
+/************************************************************/
+
+/**
+ This is the superclass of translation and rotation widgets.
+*/
+class GLUI_Mouse_Interaction : public GLUI_Control
+{
+public:
+ /*int get_main_area_size( void ) { return MIN( h-18, */
+ int draw_active_area_only;
+
+ int mouse_down_handler( int local_x, int local_y );
+ int mouse_up_handler( int local_x, int local_y, bool inside );
+ int mouse_held_down_handler( int local_x, int local_y, bool inside );
+ int special_handler( int key, int modifiers );
+ void update_size( void );
+ void draw( int x, int y );
+ void draw_active_area( void );
+
+ /*** The following methods (starting with "iaction_") need to
+ be overloaded ***/
+ virtual int iaction_mouse_down_handler( int local_x, int local_y ) = 0;
+ virtual int iaction_mouse_up_handler( int local_x, int local_y, bool inside )=0;
+ virtual int iaction_mouse_held_down_handler( int local_x, int local_y, bool inside )=0;
+ virtual int iaction_special_handler( int key, int modifiers )=0;
+ virtual void iaction_draw_active_area_persp( void )=0;
+ virtual void iaction_draw_active_area_ortho( void )=0;
+ virtual void iaction_dump( FILE *output )=0;
+ virtual void iaction_init( void ) = 0;
+
+ GLUI_Mouse_Interaction( void ) {
+ glui_format_str( name, "Mouse_Interaction: %p", this );
+ w = GLUI_MOUSE_INTERACTION_WIDTH;
+ h = GLUI_MOUSE_INTERACTION_HEIGHT;
+ can_activate = true;
+ live_type = GLUI_LIVE_NONE;
+ alignment = GLUI_ALIGN_CENTER;
+ draw_active_area_only = false;
+ }
+};
+
+/************************************************************/
+/* */
+/* Rotation class */
+/* */
+/************************************************************/
+
+/**
+ An onscreen rotation controller--allows the user to interact with
+ a 3D rotation via a spaceball-like interface.
+*/
+class GLUI_Rotation : public GLUI_Mouse_Interaction
+{
+public:
+ Arcball *ball;
+ GLUquadricObj *quadObj;
+ bool can_spin, spinning;
+ float damping;
+
+ int iaction_mouse_down_handler( int local_x, int local_y );
+ int iaction_mouse_up_handler( int local_x, int local_y, bool inside );
+ int iaction_mouse_held_down_handler( int local_x, int local_y, bool inside );
+ int iaction_special_handler( int key, int modifiers );
+ void iaction_init( void ) { init_ball(); }
+ void iaction_draw_active_area_persp( void );
+ void iaction_draw_active_area_ortho( void );
+ void iaction_dump( FILE *output );
+
+ /* void update_size( void ); */
+ /* void draw( int x, int y ); */
+ /* int mouse_over( int state, int x, int y ); */
+
+ void setup_texture( void );
+ void setup_lights( void );
+ void draw_ball( float radius );
+
+ void init_ball( void );
+
+ void reset( void );
+
+ bool needs_idle( void ) const;
+ void idle( void );
+
+ void copy_float_array_to_ball( void );
+ void copy_ball_to_float_array( void );
+
+ void set_spin( float damp_factor );
+
+ GLUI_Rotation( GLUI_Node *parent, const char *name, float *live_var=NULL,
+ int id=-1, GLUI_CB callback=GLUI_CB() );
+ GLUI_Rotation(void) { common_init(); }
+
+protected:
+ void common_init();
+};
+
+/************************************************************/
+/* */
+/* Translation class */
+/* */
+/************************************************************/
+
+/**
+ An onscreen translation controller--allows the user to interact with
+ a 3D translation.
+*/
+class GLUI_Translation : public GLUI_Mouse_Interaction
+{
+public:
+ int trans_type; /* Is this an XY or a Z controller? */
+ int down_x, down_y;
+ float scale_factor;
+ GLUquadricObj *quadObj;
+ int trans_mouse_code;
+ float orig_x, orig_y, orig_z;
+ int locked;
+
+ int iaction_mouse_down_handler( int local_x, int local_y );
+ int iaction_mouse_up_handler( int local_x, int local_y, bool inside );
+ int iaction_mouse_held_down_handler( int local_x, int local_y, bool inside );
+ int iaction_special_handler( int key, int modifiers );
+ void iaction_init( void ) { }
+ void iaction_draw_active_area_persp( void );
+ void iaction_draw_active_area_ortho( void );
+ void iaction_dump( FILE *output );
+
+ void set_speed( float s ) { scale_factor = s; }
+
+ void setup_texture( void );
+ void setup_lights( void );
+ void draw_2d_arrow( int radius, int filled, int orientation );
+ void draw_2d_x_arrows( int radius );
+ void draw_2d_y_arrows( int radius );
+ void draw_2d_z_arrows( int radius );
+ void draw_2d_xy_arrows( int radius );
+
+ int get_mouse_code( int x, int y );
+
+ /* Float array is either a single float (for single-axis controls),
+ or two floats for X and Y (if an XY controller) */
+
+ float get_z( void ) { return float_array_val[0]; }
+ float get_x( void ) { return float_array_val[0]; }
+ float get_y( void ) {
+ if ( trans_type == GLUI_TRANSLATION_XY ) return float_array_val[1];
+ else return float_array_val[0];
+ }
+
+ void set_z( float val );
+ void set_x( float val );
+ void set_y( float val );
+ void set_one_val( float val, int index );
+
+ GLUI_Translation( GLUI_Node *parent, const char *name,
+ int trans_type, float *live_var=NULL,
+ int id=-1, GLUI_CB callback=GLUI_CB() );
+ GLUI_Translation( void ) { common_init(); }
+
+protected:
+ void common_init() {
+ locked = GLUI_TRANSLATION_LOCK_NONE;
+ glui_format_str( name, "Translation: %p", this );
+ w = GLUI_MOUSE_INTERACTION_WIDTH;
+ h = GLUI_MOUSE_INTERACTION_HEIGHT;
+ can_activate = true;
+ live_type = GLUI_LIVE_FLOAT_ARRAY;
+ float_array_size = 0;
+ alignment = GLUI_ALIGN_CENTER;
+ trans_type = GLUI_TRANSLATION_XY;
+ scale_factor = 1.0;
+ quadObj = NULL;
+ trans_mouse_code = GLUI_TRANSLATION_MOUSE_NONE;
+ }
+};
+
+/********** Misc functions *********************/
+int _glutBitmapWidthString( void *font, const char *s );
+void _glutBitmapString( void *font, const char *s );
+
+/********** Our own callbacks for glut *********/
+/* These are the callbacks that we pass to glut. They take
+ some action if necessary, then (possibly) call the user-level
+ glut callbacks.
+*/
+
+void glui_display_func( void );
+void glui_reshape_func( int w, int h );
+void glui_keyboard_func(unsigned char key, int x, int y);
+void glui_special_func(int key, int x, int y);
+void glui_mouse_func(int button, int state, int x, int y);
+void glui_motion_func(int x, int y);
+void glui_passive_motion_func(int x, int y);
+void glui_entry_func(int state);
+void glui_visibility_func(int state);
+void glui_idle_func(void);
+
+void glui_parent_window_reshape_func( int w, int h );
+void glui_parent_window_keyboard_func(unsigned char key, int x, int y);
+void glui_parent_window_mouse_func(int, int, int, int );
+void glui_parent_window_special_func(int key, int x, int y);
+
+#endif
diff --git a/tests/box2d/glui/glui_add_controls.cpp b/tests/box2d/glui/glui_add_controls.cpp new file mode 100755 index 00000000..9db92939 --- /dev/null +++ b/tests/box2d/glui/glui_add_controls.cpp @@ -0,0 +1,319 @@ +/****************************************************************************
+
+ GLUI User Interface Toolkit (LGPL)
+ ---------------------------
+
+ glui_add_controls.cpp - Routines for adding controls to a GLUI window
+
+Note: these routines are all deprecated. Keeping them all here
+prevents the linker from dragging in all the .o files, even for controls
+that aren't used.
+
+ --------------------------------------------------
+
+ Copyright (c) 1998 Paul Rademacher
+
+ WWW: http://sourceforge.net/projects/glui/
+ Forums: http://sourceforge.net/forum/?group_id=92496
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+#include "glui.h"
+#include "glui_internal.h"
+
+
+/*********************************** GLUI:: add_checkbox() ************/
+
+GLUI_Checkbox *GLUI:: add_checkbox( const char *name, int *value_ptr,
+ int id, GLUI_CB callback )
+{
+ return add_checkbox_to_panel( main_panel,
+ name, value_ptr, id, callback );
+}
+
+
+/*********************************** GLUI:: add_checkbox_to_panel() **********/
+
+GLUI_Checkbox *GLUI::add_checkbox_to_panel( GLUI_Panel *panel,
+ const char *name, int *value_ptr,
+ int id,
+ GLUI_CB callback )
+{
+ return new GLUI_Checkbox( panel, name, value_ptr, id, callback );
+}
+
+/********************************************* GLUI::add_panel() *************/
+
+GLUI_Panel *GLUI::add_panel( const char *name, int type )
+{
+ return add_panel_to_panel( main_panel, name, type );
+}
+
+
+/**************************************** GLUI::add_panel_to_panel() *********/
+
+GLUI_Panel *GLUI::add_panel_to_panel( GLUI_Panel *parent_panel,
+ const char *name, int type )
+{
+ return new GLUI_Panel( parent_panel, name, type );
+}
+
+
+/***************************** GLUI::add_radiogroup() ***************/
+
+GLUI_RadioGroup *GLUI::add_radiogroup( int *value_ptr,
+ int user_id, GLUI_CB callback)
+{
+ return add_radiogroup_to_panel( main_panel, value_ptr,
+ user_id, callback );
+}
+
+
+/***************************** GLUI::add_radiogroup_to_panel() ***************/
+
+GLUI_RadioGroup *GLUI::add_radiogroup_to_panel(
+ GLUI_Panel *panel, int *value_ptr,
+ int user_id, GLUI_CB callback
+ )
+{
+ return new GLUI_RadioGroup( panel, value_ptr, user_id, callback );
+}
+
+
+/***************************** GLUI::add_radiobutton_to_group() *************/
+
+GLUI_RadioButton *GLUI::add_radiobutton_to_group( GLUI_RadioGroup *group,
+ const char *name )
+{
+ return new GLUI_RadioButton( group, name );
+}
+
+
+/********************************** GLUI::add_statictext() ************/
+
+GLUI_StaticText *GLUI::add_statictext( const char *name )
+{
+ return add_statictext_to_panel( main_panel, name );
+}
+
+
+/******************************* GLUI::add_statictext_to_panel() **********/
+
+GLUI_StaticText *GLUI::add_statictext_to_panel( GLUI_Panel *panel,
+ const char *name )
+{
+ return new GLUI_StaticText( panel, name );
+}
+
+
+/***************************************** GLUI:: add_button() ************/
+
+GLUI_Button *GLUI:: add_button( const char *name,
+ int id, GLUI_CB callback )
+{
+ return add_button_to_panel( main_panel,
+ name, id, callback );
+}
+
+/*********************************** GLUI:: add_button_to_panel() **********/
+
+GLUI_Button *GLUI::add_button_to_panel( GLUI_Panel *panel,
+ const char *name,
+ int id,
+ GLUI_CB callback )
+{
+ return new GLUI_Button( panel, name, id, callback );
+}
+
+/********************************** GLUI::add_separator() ************/
+
+void GLUI::add_separator( void )
+{
+ add_separator_to_panel( main_panel );
+}
+
+
+/******************************* GLUI::add_separator_to_panel() **********/
+
+void GLUI::add_separator_to_panel( GLUI_Panel *panel )
+{
+ new GLUI_Separator( panel );
+}
+
+
+/********************************** GLUI::add_edittext() ************/
+
+GLUI_EditText *GLUI::add_edittext( const char *name,
+ int data_type, void *data,
+ int id, GLUI_CB callback)
+{
+ return add_edittext_to_panel( main_panel, name, data_type, data,
+ id, callback );
+}
+
+
+/******************************* GLUI::add_edittext_to_panel() **********/
+
+GLUI_EditText *GLUI::add_edittext_to_panel( GLUI_Panel *panel,
+ const char *name,
+ int data_type, void *data,
+ int id, GLUI_CB callback)
+{
+ return new GLUI_EditText( panel, name, data_type, data, id, callback );
+}
+
+/********************************** GLUI::add_edittext() ************/
+
+GLUI_EditText *GLUI::add_edittext( const char *name,
+ GLUI_String & data,
+ int id, GLUI_CB callback)
+{
+ return add_edittext_to_panel( main_panel, name, data, id, callback );
+}
+
+
+/******************************* GLUI::add_edittext_to_panel() **********/
+
+GLUI_EditText*
+GLUI::add_edittext_to_panel( GLUI_Panel *panel, const char *name,
+ GLUI_String& data,
+ int id, GLUI_CB callback)
+{
+ return new GLUI_EditText( panel, name, GLUI_EDITTEXT_STRING, &data, id, callback );
+}
+
+/********************************** GLUI::add_spinner() ************/
+
+GLUI_Spinner *GLUI::add_spinner( const char *name,
+ int data_type, void *data,
+ int id, GLUI_CB callback)
+{
+ return add_spinner_to_panel( main_panel, name, data_type, data,
+ id, callback );
+}
+
+
+/******************************* GLUI::add_spinner_to_panel() **********/
+
+GLUI_Spinner *GLUI::add_spinner_to_panel(
+ GLUI_Panel *panel, const char *name,
+ int data_type, void *data,
+ int id, GLUI_CB callback
+)
+{
+ return new GLUI_Spinner( panel, name, data_type, data, id, callback );
+}
+
+
+/********************************** GLUI::add_column() ************/
+
+void GLUI::add_column( int draw_bar )
+{
+ add_column_to_panel( main_panel, draw_bar );
+}
+
+
+/******************************* GLUI::add_column_to_panel() **********/
+
+void GLUI::add_column_to_panel( GLUI_Panel *panel, int draw_bar )
+{
+ new GLUI_Column( panel, draw_bar );
+}
+
+
+/*********************************** GLUI:: add_listbox() ************/
+
+GLUI_Listbox *GLUI:: add_listbox( const char *name, int *value_ptr,
+ int id, GLUI_CB callback )
+{
+ return add_listbox_to_panel( main_panel,
+ name, value_ptr, id, callback );
+}
+
+
+/*********************************** GLUI:: add_listbox_to_panel() **********/
+
+GLUI_Listbox *GLUI::add_listbox_to_panel( GLUI_Panel *panel,
+ const char *name, int *value_ptr,
+ int id,
+ GLUI_CB callback )
+{
+ return new GLUI_Listbox( panel, name, value_ptr, id, callback );
+}
+
+
+/*********************************** GLUI:: add_rotation() ************/
+
+GLUI_Rotation *GLUI:: add_rotation( const char *name, float *value_ptr,
+ int id, GLUI_CB callback )
+{
+ return add_rotation_to_panel( main_panel, name, value_ptr, id, callback );
+}
+
+
+/*********************************** GLUI:: add_rotation_to_panel() **********/
+
+GLUI_Rotation *GLUI::add_rotation_to_panel( GLUI_Panel *panel,
+ const char *name, float *value_ptr,
+ int id,
+ GLUI_CB callback )
+{
+ return new GLUI_Rotation( panel, name, value_ptr, id, callback );
+}
+
+
+/*********************************** GLUI:: add_translation() ************/
+
+GLUI_Translation *GLUI:: add_translation( const char *name, int trans_type,
+ float *value_ptr, int id,
+ GLUI_CB callback )
+{
+ return add_translation_to_panel( main_panel,name,trans_type,
+ value_ptr, id, callback );
+}
+
+
+/*********************************** GLUI:: add_translation_to_panel() **********/
+
+GLUI_Translation *GLUI::add_translation_to_panel(
+ GLUI_Panel *panel, const char *name,
+ int trans_type, float *value_ptr,
+ int id, GLUI_CB callback
+ )
+{
+ return new GLUI_Translation(panel, name, trans_type, value_ptr, id, callback);
+}
+
+
+/********************************** GLUI::add_rollout() **************/
+
+GLUI_Rollout *GLUI::add_rollout( const char *name, int open, int type)
+{
+ return add_rollout_to_panel( main_panel, name, open, type);
+}
+
+
+/****************************** GLUI::add_rollout_to_panel() *********/
+
+GLUI_Rollout *GLUI::add_rollout_to_panel(GLUI_Panel *panel, const char *name,
+ int open, int type)
+{
+ return new GLUI_Rollout( panel, name, open, type );
+}
+
+
+
diff --git a/tests/box2d/glui/glui_bitmap_img_data.cpp b/tests/box2d/glui/glui_bitmap_img_data.cpp new file mode 100755 index 00000000..6ec7e6df --- /dev/null +++ b/tests/box2d/glui/glui_bitmap_img_data.cpp @@ -0,0 +1,138 @@ +/**
+ Bitmaps for all GLUI images.
+
+ These were converted from original PPM images
+ (mostly lost) with the tools/ppm2array program.
+
+ The images here are extracted in typical OpenGL
+ bottom-to-top fashion.
+
+ FIXME: don't use greyscale brightness here--this prevents
+ people changing the background color. Instead, use a code
+ indicating the underlying purpose of the pixel:
+ 0 = shadows; outlines; UI elements (check boxes, arrows)
+ 64 = disabled shadows and UI elements
+ 128 = shadowing, disabled
+ 192 = disabled white; background
+ 255 = highlights; checkbox/radio background
+
+ I'm thinking the way to do this would be to have an
+enum {
+ BG = 0, // Background shines through-- totally alpha transparent
+ BS, // Background of scrollbar/spin box-- opaque gray
+ SB, // Shadowed-black element-- strong alpha blend to black
+ SD, // Shadowed-dark element-- weak alpha blend to black
+ HL, // Highlight-light-- weak alpha blend to white
+ HW, // Highlight-white-- strong alpha blend to white
+ UB, // User-interface black-- arrows, checkboxes, radio buttons
+ UW, // User-interface white-- backgrounds of checkboxes and radio buttons
+};
+
+ Orion Sky Lawlor, olawlor@acm.org, 2006/05/04 (LGPL)
+*/
+
+/*----------------------- checkboxes --------------------------*/
+unsigned char glui_img_checkbox_0[] = { 13, 13, /* width, height */
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 255,
+};
+
+
+unsigned char glui_img_checkbox_0_dis[] = { 13, 13, /* width, height */
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 192, 255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 255,
+};
+
+
+unsigned char glui_img_checkbox_1[] = { 13, 13, /* width, height */
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 128, 0, 255, 255, 255, 0, 255, 255, 255, 255, 255, 192, 255, 128, 0, 255, 255, 0, 0, 0, 255, 255, 255, 255, 192, 255, 128, 0, 255, 0, 0, 0, 0, 0, 255, 255, 255, 192, 255, 128, 0, 255, 0, 0, 255, 0, 0, 0, 255, 255, 192, 255, 128, 0, 255, 0, 255, 255, 255, 0, 0, 0, 255, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 0, 0, 255, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 255, 0, 255, 192, 255, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 255,
+};
+
+
+unsigned char glui_img_checkbox_1_dis[] = { 13, 13, /* width, height */
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 192, 192, 192, 64, 192, 192, 192, 192, 192, 192, 255, 128, 64, 192, 192, 64, 64, 64, 192, 192, 192, 192, 192, 255, 128, 64, 192, 64, 64, 64, 64, 64, 192, 192, 192, 192, 255, 128, 64, 192, 64, 64, 192, 64, 64, 64, 192, 192, 192, 255, 128, 64, 192, 64, 192, 192, 192, 64, 64, 64, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 64, 64, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 192, 64, 192, 192, 255, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 128, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 192, 255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 255,
+};
+
+
+/*------------------------------- arrows -------------------------------------*/
+unsigned char glui_img_downarrow[] = { 16, 16, /* width, height */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 0, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 0, 0, 0, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 0, 0, 0, 0, 0, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 0, 0, 0, 0, 0, 0, 0, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0,
+};
+
+
+unsigned char glui_img_leftarrow[] = { 16, 16, /* width, height */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 0, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 0, 0, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 0, 0, 0, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 0, 0, 0, 0, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 0, 0, 0, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 0, 0, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 0, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0,
+};
+
+unsigned char glui_img_rightarrow[] = { 16, 16, /* width, height */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 0, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 0, 0, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 0, 0, 0, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 0, 0, 0, 0, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 0, 0, 0, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 0, 0, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 0, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0,
+};
+
+unsigned char glui_img_uparrow[] = { 16, 16, /* width, height */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 0, 0, 0, 0, 0, 0, 0, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 0, 0, 0, 0, 0, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 0, 0, 0, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 0, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 0, 192, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0,
+};
+
+/*------------------ listboxes ---------------------*/
+unsigned char glui_img_listbox_down[] = { 11, 17, /* width, height */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 127, 191, 191, 191, 191, 127, 191, 191, 191, 127, 0, 127, 191, 191, 191, 127, 127, 127, 191, 191, 127, 0, 127, 191, 191, 127, 127, 127, 127, 127, 191, 127, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 0,
+};
+
+
+unsigned char glui_img_listbox_up[] = { 11, 17, /* width, height */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 191, 127, 127, 127, 127, 127, 127, 127, 127, 127, 0, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 0, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 0, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 0, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 0, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 0, 191, 255, 191, 191, 191, 0, 191, 191, 191, 127, 0, 191, 255, 191, 191, 0, 0, 0, 191, 191, 127, 0, 191, 255, 191, 0, 0, 0, 0, 0, 191, 127, 0, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 0, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 0, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 0, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 0, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 0, 191, 255, 255, 255, 255, 255, 255, 255, 255, 127, 0, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 0,
+};
+
+unsigned char glui_img_listbox_up_dis[] = { 11, 17, /* width, height */
+127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 191, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 127, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 127, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 127, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 127, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 127, 191, 255, 191, 191, 191, 254, 191, 191, 191, 127, 127, 191, 255, 191, 191, 127, 127, 254, 191, 191, 127, 127, 191, 255, 191, 127, 127, 127, 127, 254, 191, 127, 127, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 127, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 127, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 127, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 127, 191, 255, 191, 191, 191, 191, 191, 191, 191, 127, 127, 191, 255, 255, 255, 255, 255, 255, 255, 255, 127, 127, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 127,
+};
+
+/*--------------------------- radio buttons -------------------------*/
+unsigned char glui_img_radiobutton_0[] = { 14, 14, /* width, height */
+192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 255, 255, 255, 192, 192, 192, 192, 192, 192, 192, 192, 255, 255, 192, 192, 192, 192, 255, 255, 192, 192, 192, 192, 192, 128, 192, 192, 255, 255, 255, 255, 192, 192, 255, 192, 192, 192, 192, 128, 0, 255, 255, 255, 255, 255, 255, 192, 255, 192, 192, 192, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 192, 192, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 192, 192, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 192, 192, 128, 0, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 192, 192, 192, 128, 0, 255, 255, 255, 255, 255, 255, 192, 255, 192, 192, 192, 192, 128, 0, 0, 255, 255, 255, 255, 0, 0, 255, 192, 192, 192, 192, 192, 128, 128, 0, 0, 0, 0, 128, 128, 192, 192, 192, 192, 192, 192, 192, 192, 128, 128, 128, 128, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
+};
+
+
+unsigned char glui_img_radiobutton_0_dis[] = { 14, 14, /* width, height */
+192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 255, 255, 255, 192, 192, 192, 192, 192, 192, 192, 192, 255, 255, 192, 192, 192, 192, 255, 255, 192, 192, 192, 192, 192, 128, 192, 192, 192, 192, 192, 192, 192, 192, 255, 192, 192, 192, 192, 128, 64, 192, 192, 192, 192, 192, 192, 192, 255, 192, 192, 192, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 192, 192, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 192, 192, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 192, 192, 128, 64, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 192, 192, 192, 128, 64, 192, 192, 192, 192, 192, 192, 192, 255, 192, 192, 192, 192, 128, 64, 64, 192, 192, 192, 192, 64, 64, 255, 192, 192, 192, 192, 192, 128, 128, 64, 64, 64, 64, 128, 128, 192, 192, 192, 192, 192, 192, 192, 192, 128, 128, 128, 128, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
+};
+
+
+unsigned char glui_img_radiobutton_1[] = { 14, 14, /* width, height */
+192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 255, 255, 255, 192, 192, 192, 192, 192, 192, 192, 192, 255, 255, 192, 192, 192, 192, 255, 255, 192, 192, 192, 192, 192, 128, 192, 192, 255, 255, 255, 255, 192, 192, 255, 192, 192, 192, 192, 128, 0, 255, 255, 255, 255, 255, 255, 192, 255, 192, 192, 192, 128, 0, 255, 255, 255, 0, 0, 255, 255, 255, 192, 255, 192, 192, 128, 0, 255, 255, 0, 0, 0, 0, 255, 255, 192, 255, 192, 192, 128, 0, 255, 255, 0, 0, 0, 0, 255, 255, 192, 255, 192, 192, 128, 0, 255, 255, 255, 0, 0, 255, 255, 255, 192, 255, 192, 192, 192, 128, 0, 255, 255, 255, 255, 255, 255, 192, 255, 192, 192, 192, 192, 128, 0, 0, 255, 255, 255, 255, 0, 0, 255, 192, 192, 192, 192, 192, 128, 128, 0, 0, 0, 0, 128, 128, 192, 192, 192, 192, 192, 192, 192, 192, 128, 128, 128, 128, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
+};
+
+
+unsigned char glui_img_radiobutton_1_dis[] = { 14, 14, /* width, height */
+192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 255, 255, 255, 255, 192, 192, 192, 192, 192, 192, 192, 192, 255, 255, 192, 192, 192, 192, 255, 255, 192, 192, 192, 192, 192, 128, 192, 192, 192, 192, 192, 192, 192, 192, 255, 192, 192, 192, 192, 128, 64, 192, 192, 192, 192, 192, 192, 192, 255, 192, 192, 192, 128, 64, 192, 192, 192, 64, 64, 192, 192, 192, 192, 255, 192, 192, 128, 64, 192, 192, 64, 64, 64, 64, 192, 192, 192, 255, 192, 192, 128, 64, 192, 192, 64, 64, 64, 64, 192, 192, 192, 255, 192, 192, 128, 64, 192, 192, 192, 64, 64, 192, 192, 192, 192, 255, 192, 192, 192, 128, 64, 192, 192, 192, 192, 192, 192, 192, 255, 192, 192, 192, 192, 128, 64, 64, 192, 192, 192, 192, 64, 64, 255, 192, 192, 192, 192, 192, 128, 128, 64, 64, 64, 64, 128, 128, 192, 192, 192, 192, 192, 192, 192, 192, 128, 128, 128, 128, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
+};
+
+
+
+/*----------------- spinners ----------------------------*/
+unsigned char glui_img_spindown_0[] = { 12, 8, /* width, height */
+255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 0, 255, 191, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 255, 191, 191, 191, 191, 0, 127, 191, 191, 191, 127, 0, 255, 191, 191, 191, 0, 0, 0, 127, 191, 191, 127, 0, 255, 191, 191, 0, 0, 0, 0, 0, 127, 191, 127, 0, 255, 191, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0,
+};
+
+
+unsigned char glui_img_spindown_1[] = { 12, 8, /* width, height */
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 191, 255, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 191, 255, 0, 127, 191, 191, 191, 127, 0, 191, 191, 191, 191, 255, 0, 127, 191, 191, 127, 0, 0, 0, 191, 191, 191, 255, 0, 127, 191, 127, 0, 0, 0, 0, 0, 191, 191, 255, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 191, 255, 0, 127, 127, 127, 127, 127, 127, 127, 127, 127, 191, 255,
+};
+
+
+unsigned char glui_img_spindown_dis[] = { 12, 8, /* width, height */
+255, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 255, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 64, 255, 191, 191, 191, 191, 191, 191, 191, 191, 191, 127, 64, 255, 191, 191, 191, 191, 127, 255, 191, 191, 191, 127, 64, 255, 191, 191, 191, 127, 127, 127, 255, 191, 191, 127, 64, 255, 191, 191, 127, 127, 127, 127, 127, 255, 191, 127, 64, 255, 191, 191, 191, 191, 191, 191, 191, 191, 191, 127, 64, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 64,
+};
+
+
+unsigned char glui_img_spinup_0[] = { 12, 8, /* width, height */
+255, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 0, 255, 191, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 255, 191, 191, 0, 0, 0, 0, 0, 127, 191, 127, 0, 255, 191, 191, 191, 0, 0, 0, 127, 191, 191, 127, 0, 255, 191, 191, 191, 191, 0, 127, 191, 191, 191, 127, 0, 255, 191, 191, 191, 191, 191, 191, 191, 191, 191, 127, 0, 255, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+};
+
+
+unsigned char glui_img_spinup_1[] = { 12, 8, /* width, height */
+ 0, 127, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 191, 255, 0, 127, 191, 127, 0, 0, 0, 0, 0, 191, 191, 255, 0, 127, 191, 191, 127, 0, 0, 0, 191, 191, 191, 255, 0, 127, 191, 191, 191, 127, 0, 191, 191, 191, 191, 255, 0, 127, 191, 191, 191, 191, 191, 191, 191, 191, 191, 255, 0, 127, 127, 127, 127, 127, 127, 127, 127, 127, 191, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255,
+};
+
+
+unsigned char glui_img_spinup_dis[] = { 12, 8, /* width, height */
+255, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 64, 255, 191, 191, 191, 191, 191, 191, 191, 191, 191, 127, 64, 255, 191, 191, 127, 127, 127, 127, 127, 255, 191, 127, 64, 255, 191, 191, 191, 127, 127, 127, 255, 191, 191, 127, 64, 255, 191, 191, 191, 191, 127, 255, 191, 191, 191, 127, 64, 255, 191, 191, 191, 191, 191, 191, 191, 191, 191, 127, 64, 255, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 64, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+};
+
diff --git a/tests/box2d/glui/glui_bitmaps.cpp b/tests/box2d/glui/glui_bitmaps.cpp new file mode 100755 index 00000000..d04e9b11 --- /dev/null +++ b/tests/box2d/glui/glui_bitmaps.cpp @@ -0,0 +1,176 @@ +/****************************************************************************
+
+ GLUI User Interface Toolkit
+ ---------------------------
+
+ glui_bitmaps.cpp
+
+Draws the hardcoded images listed in glui_bitmap_img_data with OpenGL.
+
+FIXME: upload the images to a texture. This will allow them to be:
+ - Drawn with alpha blending
+ - Drawn at random sizes and angles onscreen
+ - Drawn much faster than with glDrawPixels
+
+ --------------------------------------------------
+
+ Copyright (c) 1998 Paul Rademacher
+
+ WWW: http://sourceforge.net/projects/glui/
+ Forums: http://sourceforge.net/forum/?group_id=92496
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+#include "glui.h"
+#include "glui_internal.h"
+#include <cassert>
+
+/************ Image Bitmap arrays **********/
+
+extern unsigned char glui_img_checkbox_0[];
+extern unsigned char glui_img_checkbox_1[];
+extern unsigned char glui_img_radiobutton_0[];
+extern unsigned char glui_img_radiobutton_1[];
+extern unsigned char glui_img_uparrow[];
+extern unsigned char glui_img_downarrow[];
+extern unsigned char glui_img_leftarrow[];
+extern unsigned char glui_img_rightarrow[];
+extern unsigned char glui_img_spinup_0[];
+extern unsigned char glui_img_spinup_1[];
+extern unsigned char glui_img_spindown_0[];
+extern unsigned char glui_img_spindown_1[];
+extern unsigned char glui_img_checkbox_0_dis[];
+extern unsigned char glui_img_checkbox_1_dis[];
+extern unsigned char glui_img_radiobutton_0_dis[];
+extern unsigned char glui_img_radiobutton_1_dis[];
+extern unsigned char glui_img_spinup_dis[];
+extern unsigned char glui_img_spindown_dis[];
+extern unsigned char glui_img_listbox_up[];
+extern unsigned char glui_img_listbox_down[];
+extern unsigned char glui_img_listbox_up_dis[];
+
+
+// These must be in the same order as the GLUI_STDBITMAP enums from glui.h!
+unsigned char *bitmap_arrays[] = {
+ glui_img_checkbox_0,
+ glui_img_checkbox_1,
+ glui_img_radiobutton_0,
+ glui_img_radiobutton_1,
+ glui_img_uparrow,
+ glui_img_downarrow,
+ glui_img_leftarrow,
+ glui_img_rightarrow,
+ glui_img_spinup_0,
+ glui_img_spinup_1,
+ glui_img_spindown_0,
+ glui_img_spindown_1,
+ glui_img_checkbox_0_dis,
+ glui_img_checkbox_1_dis,
+ glui_img_radiobutton_0_dis,
+ glui_img_radiobutton_1_dis,
+ glui_img_spinup_dis,
+ glui_img_spindown_dis,
+ glui_img_listbox_up,
+ glui_img_listbox_down,
+ glui_img_listbox_up_dis,
+};
+
+
+/************************************ GLUI_Bitmap::load_from_array() ********/
+
+GLUI_Bitmap::GLUI_Bitmap()
+: pixels(NULL),
+ w(0),
+ h(0)
+{
+}
+
+GLUI_Bitmap::~GLUI_Bitmap()
+{
+ if (pixels)
+ {
+ free(pixels);
+ pixels = NULL;
+ }
+}
+
+/* Create bitmap from greyscale byte array */
+void GLUI_Bitmap::init_grey(unsigned char *array)
+{
+ w = array[0]; h = array[1];
+ pixels = (unsigned char *) malloc(w*h*3);
+ assert(pixels);
+
+ for(int i = 0; i<w*h; i++ )
+ for (int j = 0; j<3; j++) /* copy grey to r,g,b channels */
+ pixels[i*3+j] = (unsigned char) array[i+2];
+}
+
+
+/* Create bitmap from color int array.
+ (OSL) This used to be how all GLUI bitmaps were stored, which was horribly
+ inefficient--three ints per pixel, or 12 bytes per pixel!
+*/
+void GLUI_Bitmap::init(int *array)
+{
+ w = array[0]; h = array[1];
+ pixels = (unsigned char *) malloc(w*h*3);
+ assert(pixels);
+
+ for (int i = 0; i<w*h*3; i++)
+ pixels[i] = (unsigned char) array[i+2];
+}
+
+
+/*********************************** GLUI_StdBitmaps::draw() *****************/
+
+GLUI_StdBitmaps::GLUI_StdBitmaps()
+{
+ for (int i=0; i<GLUI_STDBITMAP_NUM_ITEMS; i++)
+ bitmaps[i].init_grey(bitmap_arrays[i]);
+}
+
+GLUI_StdBitmaps::~GLUI_StdBitmaps()
+{
+}
+
+int GLUI_StdBitmaps::width(int i) const
+{
+ assert(i>=0 && i<GLUI_STDBITMAP_NUM_ITEMS);
+ return bitmaps[i].w;
+}
+
+int GLUI_StdBitmaps::height(int i) const
+{
+ assert(i>=0 && i<GLUI_STDBITMAP_NUM_ITEMS);
+ return bitmaps[i].h;
+}
+
+void GLUI_StdBitmaps::draw(int i, int x, int y) const
+{
+ assert(i>=0 && i<GLUI_STDBITMAP_NUM_ITEMS);
+
+ if (bitmaps[i].pixels != NULL )
+ {
+ glPixelStorei(GL_UNPACK_ALIGNMENT,1);
+ glRasterPos2f(0.5f+x, 0.5f+y+bitmaps[i].h);
+ glDrawPixels(
+ bitmaps[i].w, bitmaps[i].h,
+ GL_RGB, GL_UNSIGNED_BYTE, bitmaps[i].pixels);
+ }
+}
+
diff --git a/tests/box2d/glui/glui_button.cpp b/tests/box2d/glui/glui_button.cpp new file mode 100755 index 00000000..0b912d2c --- /dev/null +++ b/tests/box2d/glui/glui_button.cpp @@ -0,0 +1,186 @@ +/****************************************************************************
+
+ GLUI User Interface Toolkit
+ ---------------------------
+
+ glui_button.cpp - GLUI_Button control class
+
+
+ --------------------------------------------------
+
+ Copyright (c) 1998 Paul Rademacher
+
+ WWW: http://sourceforge.net/projects/glui/
+ Forums: http://sourceforge.net/forum/?group_id=92496
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+#include "glui_internal_control.h"
+
+/****************************** GLUI_Button::GLUI_Button() **********/
+
+GLUI_Button::GLUI_Button( GLUI_Node *parent, const char *name,
+ int id, GLUI_CB cb )
+{
+ common_init();
+ user_id = id;
+ callback = cb;
+ set_name( name );
+ currently_inside = false;
+
+ parent->add_control( this );
+}
+
+
+/****************************** GLUI_Button::mouse_down_handler() **********/
+
+int GLUI_Button::mouse_down_handler( int local_x, int local_y )
+{
+ int_val = 1; /** A button always in unpressed before here, so
+ now we invariably set it to 'depressed' **/
+
+ currently_inside = true;
+ redraw();
+
+ return false;
+}
+
+
+/****************************** GLUI_Button::mouse_up_handler() **********/
+
+int GLUI_Button::mouse_up_handler( int local_x, int local_y, bool inside )
+{
+ set_int_val( 0 ); /** A button always turns off after you press it **/
+
+ currently_inside = false;
+ redraw();
+
+ if ( inside ) {
+ /*** Invoke the user's callback ***/
+ execute_callback();
+ }
+
+ return false;
+}
+
+
+/****************************** GLUI_Button::mouse_held_down_handler() ******/
+
+int GLUI_Button::mouse_held_down_handler( int local_x, int local_y,
+ bool new_inside)
+{
+ if (new_inside != currently_inside) {
+ currently_inside = new_inside;
+ redraw();
+ }
+
+ return false;
+}
+
+
+/****************************** GLUI_Button::key_handler() **********/
+
+int GLUI_Button::key_handler( unsigned char key,int modifiers )
+{
+ return false;
+}
+
+/********************************************** GLUI_Button::draw() **********/
+
+void GLUI_Button::draw( int x, int y )
+{
+ if (currently_inside) draw_pressed();
+ else {
+ glui->draw_raised_box( 0, 0, w, h );
+ draw_text( 0 );
+ }
+}
+
+
+/************************************** GLUI_Button::draw_pressed() ******/
+
+void GLUI_Button::draw_pressed( void )
+{
+ glColor3f( 0.0, 0.0, 0.0 );
+
+ draw_text( 1 );
+
+ glBegin( GL_LINE_LOOP );
+ glVertex2i( 0, 0 ); glVertex2i( w, 0 );
+ glVertex2i( w, h ); glVertex2i( 0, h );
+ glEnd();
+
+ glBegin( GL_LINE_LOOP );
+ glVertex2i( 1, 1 ); glVertex2i( w-1, 1 );
+ glVertex2i( w-1, h-1 ); glVertex2i( 1, h-1 );
+ glEnd();
+}
+
+
+/**************************************** GLUI_Button::draw_text() **********/
+
+void GLUI_Button::draw_text( int sunken )
+{
+ int string_width;
+
+ glColor3ub( glui->bkgd_color.r, glui->bkgd_color.g, glui->bkgd_color.b );
+ glDisable( GL_CULL_FACE );
+ glBegin( GL_QUADS );
+ glVertex2i( 2, 2 ); glVertex2i( w-2, 2 );
+ glVertex2i( w-2, h-2 ); glVertex2i( 2, h-2 );
+ glEnd();
+
+ glColor3ub( 0,0,0 );
+
+ string_width = _glutBitmapWidthString( glui->font,
+ this->name.c_str() );
+ if ( NOT sunken ) {
+ draw_name( MAX((w-string_width),0)/2, 13);
+ }
+ else {
+ draw_name( MAX((w-string_width),0)/2 + 1, 13 + 1);
+ }
+
+ if ( active ) {
+ glEnable( GL_LINE_STIPPLE );
+ glLineStipple( 1, 0x5555 );
+
+ glColor3f( 0., 0., 0. );
+
+ glBegin( GL_LINE_LOOP );
+ glVertex2i( 3, 3 ); glVertex2i( w-3, 3 );
+ glVertex2i( w-3, h-3 ); glVertex2i( 3, h-3 );
+ glEnd();
+
+ glDisable( GL_LINE_STIPPLE );
+ }
+}
+
+
+/************************************** GLUI_Button::update_size() **********/
+
+void GLUI_Button::update_size( void )
+{
+ int text_size;
+
+ if ( NOT glui )
+ return;
+
+ text_size = string_width( name );
+
+ if ( w < text_size + 16 )
+ w = text_size + 16 ;
+}
diff --git a/tests/box2d/glui/glui_checkbox.cpp b/tests/box2d/glui/glui_checkbox.cpp new file mode 100755 index 00000000..3bf3984d --- /dev/null +++ b/tests/box2d/glui/glui_checkbox.cpp @@ -0,0 +1,188 @@ +
+/****************************************************************************
+
+ GLUI User Interface Toolkit (LGPL)
+ ---------------------------
+
+ glui_checkbox - GLUI_Checkbox control class
+
+
+ --------------------------------------------------
+
+ Copyright (c) 1998 Paul Rademacher
+
+ WWW: http://sourceforge.net/projects/glui/
+ Forums: http://sourceforge.net/forum/?group_id=92496
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+#include "glui_internal_control.h"
+
+/****************************** GLUI_Checkbox::GLUI_Checkbox() **********/
+
+GLUI_Checkbox::GLUI_Checkbox( GLUI_Node *parent,
+ const char *name, int *value_ptr,
+ int id,
+ GLUI_CB cb )
+{
+ common_init();
+
+ set_ptr_val( value_ptr );
+ set_name( name );
+ user_id = id;
+ callback = cb;
+
+ parent->add_control( this );
+
+ init_live();
+}
+
+/****************************** GLUI_Checkbox::mouse_down_handler() **********/
+
+int GLUI_Checkbox::mouse_down_handler( int local_x, int local_y )
+{
+ orig_value = int_val;
+ int_val = !int_val;
+
+ currently_inside = true;
+ redraw();
+
+ return false;
+}
+
+
+/****************************** GLUI_Checkbox::mouse_up_handler() **********/
+
+int GLUI_Checkbox::mouse_up_handler( int local_x, int local_y, bool inside )
+{
+ if ( NOT inside ) { /* undo effect on value */
+ int_val = orig_value;
+ }
+ else {
+ set_int_val( int_val );
+
+ /*** Invoke the callback ***/
+ execute_callback();
+ }
+
+ return false;
+}
+
+
+/****************************** GLUI_Checkbox::mouse_held_down_handler() ******/
+
+int GLUI_Checkbox::mouse_held_down_handler( int local_x, int local_y,
+ bool inside)
+{
+ /********** Toggle checked and unchecked bitmap if we're entering or
+ leaving the checkbox area **********/
+ if ( inside != currently_inside ) {
+ int_val = !int_val;
+ currently_inside = inside;
+ redraw();
+ }
+
+ return false;
+}
+
+
+/****************************** GLUI_Checkbox::key_handler() **********/
+
+int GLUI_Checkbox::key_handler( unsigned char key,int modifiers )
+{
+ return false;
+}
+
+
+/****************************** GLUI_Checkbox::draw() **********/
+
+void GLUI_Checkbox::draw( int x, int y )
+{
+ GLUI_DRAWINGSENTINAL_IDIOM
+
+ if ( int_val != 0 ) {
+ if ( enabled )
+ glui->std_bitmaps.draw( GLUI_STDBITMAP_CHECKBOX_ON, 0, 0 );
+ else
+ glui->std_bitmaps.draw( GLUI_STDBITMAP_CHECKBOX_ON_DIS, 0, 0 );
+ }
+ else {
+ if ( enabled )
+ glui->std_bitmaps.draw( GLUI_STDBITMAP_CHECKBOX_OFF, 0, 0 );
+ else
+ glui->std_bitmaps.draw( GLUI_STDBITMAP_CHECKBOX_OFF_DIS, 0, 0 );
+ }
+
+ draw_active_area();
+
+ draw_name( text_x_offset, 10);
+}
+
+/**************************** GLUI_Checkbox::draw_active_area() **************/
+
+void GLUI_Checkbox::draw_active_area( void )
+{
+ GLUI_DRAWINGSENTINAL_IDIOM
+ int text_width, left, right;
+
+ text_width = _glutBitmapWidthString( glui->font, name.c_str() );
+ left = text_x_offset-3;
+ right = left + 7 + text_width;
+
+ if ( active ) {
+ glEnable( GL_LINE_STIPPLE );
+ glLineStipple( 1, 0x5555 );
+ glColor3f( 0., 0., 0. );
+ } else {
+ glColor3ub( glui->bkgd_color.r, glui->bkgd_color.g, glui->bkgd_color.b );
+ }
+
+ glBegin( GL_LINE_LOOP );
+ glVertex2i(left,0); glVertex2i( right,0);
+ glVertex2i(right,h+1); glVertex2i( left,h+1);
+ glEnd();
+
+ glDisable( GL_LINE_STIPPLE );
+}
+
+
+/************************************ GLUI_Checkbox::update_size() **********/
+
+void GLUI_Checkbox::update_size( void )
+{
+ int text_size;
+
+ if ( NOT glui )
+ return;
+
+ text_size = _glutBitmapWidthString( glui->font, name.c_str() );
+
+ /* if ( w < text_x_offset + text_size + 6 ) */
+ w = text_x_offset + text_size + 6 ;
+}
+
+
+/********************************* GLUI_Checkbox::set_int_val() **************/
+
+void GLUI_Checkbox::set_int_val( int new_val )
+{
+ int_val = new_val;
+
+ /*** Update the variable we're (possibly) pointing to ***/
+ output_live(true);
+ redraw();
+}
diff --git a/tests/box2d/glui/glui_column.cpp b/tests/box2d/glui/glui_column.cpp new file mode 100755 index 00000000..172d3c1e --- /dev/null +++ b/tests/box2d/glui/glui_column.cpp @@ -0,0 +1,89 @@ +/****************************************************************************
+ GLUI User Interface Toolkit
+ ---------------------------
+
+ glui_column.cpp - GLUI_Column control class
+
+
+ --------------------------------------------------
+
+ Copyright (c) 1998 Paul Rademacher
+
+ WWW: http://sourceforge.net/projects/glui/
+ Forums: http://sourceforge.net/forum/?group_id=92496
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+#include "glui_internal_control.h"
+
+/******************************** GLUI_Column::GLUI_Column() ************/
+
+GLUI_Column::GLUI_Column( GLUI_Node *parent, int draw_bar )
+{
+ common_init();
+ int_val = draw_bar; /* Whether to draw vertical bar or not */
+
+ parent->add_control( this );
+}
+
+/**************************************** GLUI_Column::draw() ************/
+
+void GLUI_Column::draw( int x, int y )
+{
+ int panel_x, panel_y, panel_w, panel_h, panel_x_off, panel_y_off;
+ int y_diff;
+
+ if ( int_val == 1 ) { /* Draw a vertical bar */
+ GLUI_DRAWINGSENTINAL_IDIOM
+ if ( parent() != NULL ) {
+ get_this_column_dims(&panel_x, &panel_y, &panel_w, &panel_h,
+ &panel_x_off, &panel_y_off);
+
+ y_diff = y_abs - panel_y;
+
+ if ( 0 ) {
+ glLineWidth(1.0);
+ glBegin( GL_LINES );
+ glColor3f( .5, .5, .5 );
+ glVertex2i( -GLUI_XOFF+1, -y_diff + GLUI_SEPARATOR_HEIGHT/2 );
+ glVertex2i( -GLUI_XOFF+1, -y_diff + panel_h - GLUI_SEPARATOR_HEIGHT/2);
+
+ glColor3f( 1.0, 1.0, 1.0 );
+ glVertex2i( -GLUI_XOFF+2, -y_diff + GLUI_SEPARATOR_HEIGHT/2 );
+ glVertex2i( -GLUI_XOFF+2, -y_diff + panel_h - GLUI_SEPARATOR_HEIGHT/2);
+ glEnd();
+ }
+ else {
+ glLineWidth(1.0);
+ glBegin( GL_LINES );
+ glColor3f( .5, .5, .5 );
+ glVertex2i( -2, 0 );
+ glVertex2i( -2, h );
+ /*glVertex2i( 0, -y_diff + GLUI_SEPARATOR_HEIGHT/2 ); */
+ /*glVertex2i( 0, -y_diff + panel_h - GLUI_SEPARATOR_HEIGHT/2); */
+
+ glColor3f( 1.0, 1.0, 1.0 );
+ glVertex2i( -1, 0 );
+ glVertex2i( -1, h );
+ /*glVertex2i( 1, -y_diff + GLUI_SEPARATOR_HEIGHT/2 ); */
+ /*glVertex2i( 1, -y_diff + panel_h - GLUI_SEPARATOR_HEIGHT/2); */
+ glEnd();
+ }
+ }
+ }
+}
+
diff --git a/tests/box2d/glui/glui_commandline.cpp b/tests/box2d/glui/glui_commandline.cpp new file mode 100755 index 00000000..e98c2e1e --- /dev/null +++ b/tests/box2d/glui/glui_commandline.cpp @@ -0,0 +1,197 @@ +/****************************************************************************
+
+ GLUI User Interface Toolkit
+ ---------------------------
+
+ glui_commandline.cpp - GLUI_CommandLine control class
+
+
+ --------------------------------------------------
+
+ Copyright (c) 1998 Paul Rademacher, 2005 William Baxter
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA
+
+ This program is -not- in the public domain.
+
+*****************************************************************************/
+
+#include "glui.h"
+#include "glui_internal.h"
+
+/****************************** GLUI_CommandLine::GLUI_CommandLine() **********/
+GLUI_CommandLine::GLUI_CommandLine( GLUI_Node *parent, const char *name,
+ void *data, int id, GLUI_CB cb )
+{
+ common_init();
+ set_name( name );
+
+ data_type = GLUI_EDITTEXT_TEXT;
+ ptr_val = data;
+ user_id = id;
+ callback = cb;
+
+ live_type = GLUI_LIVE_TEXT;
+
+ parent->add_control( this );
+
+ init_live();
+}
+
+/****************************** GLUI_CommandLine::key_handler() **********/
+
+int GLUI_CommandLine::key_handler( unsigned char key,int modifiers )
+{
+ int ret;
+
+ if ( NOT glui )
+ return false;
+
+ if ( debug )
+ dump( stdout, "-> CMD_TEXT KEY HANDLER" );
+
+ if ( key == 13 ) { /* RETURN */
+ commit_flag = true;
+ }
+
+ ret = Super::key_handler( key, modifiers );
+
+ if ( debug )
+ dump( stdout, "<- CMD_TEXT KEY HANDLER" );
+
+ return ret;
+}
+
+
+/****************************** GLUI_CommandLine::deactivate() **********/
+
+void GLUI_CommandLine::deactivate( void )
+{
+ // if the commit_flag is set, add the current command to
+ // history and call deactivate as normal
+
+ // Trick deactivate into calling callback if and only if commit_flag set.
+ // A bit subtle, but deactivate checks that orig_text and text
+ // are the same to decide whether or not to call the callback.
+ // Force them to be different for commit, and the same for no commit.
+ if (commit_flag) {
+ add_to_history(text.c_str());
+ orig_text = "";
+ Super::deactivate( );
+ set_text( "" );
+ commit_flag = false;
+ }
+ else {
+ orig_text = text;
+ }
+}
+
+/**************************** GLUI_CommandLine::special_handler() **********/
+
+int GLUI_CommandLine::special_handler( int key,int modifiers )
+{
+ if ( NOT glui )
+ return false;
+
+ if ( debug )
+ printf( "CMD_TEXT SPECIAL:%d - mod:%d subs:%d/%d ins:%d sel:%d/%d\n",
+ key, modifiers, substring_start, substring_end,insertion_pt,
+ sel_start, sel_end );
+
+ if ( key == GLUT_KEY_UP ) // PREVIOUS HISTORY
+ {
+ scroll_history(-1);
+ }
+ else if ( key == GLUT_KEY_DOWN ) // NEXT HISTORY
+ {
+ scroll_history(+1);
+ }
+ else {
+ return Super::special_handler( key, modifiers );
+ }
+ return false;
+}
+
+
+
+/**************************** GLUI_CommandLine::scroll_history() ********/
+
+void GLUI_CommandLine::scroll_history( int direction )
+{
+ recall_history(curr_hist + direction);
+}
+
+/**************************** GLUI_CommandLine::recall_history() ********/
+
+void GLUI_CommandLine::recall_history( int hist_num )
+{
+ if (hist_num < oldest_hist OR
+ hist_num > newest_hist OR
+ hist_num == curr_hist)
+ return;
+
+ // Commit the current text first before we blow it away!
+ if (curr_hist == newest_hist) {
+ get_history_str(newest_hist) = text;
+ }
+
+ curr_hist = hist_num;
+ set_text(get_history_str(curr_hist));
+ sel_end = sel_start = insertion_pt = (int)text.length();
+ update_and_draw_text();
+}
+
+/**************************** GLUI_CommandLine::add_to_history() ********/
+
+void GLUI_CommandLine::add_to_history( const char *cmd )
+{
+ if (cmd[0]=='\0') return; // don't add if it's empty
+
+ curr_hist = newest_hist;
+ get_history_str(newest_hist) = text;
+
+ newest_hist = ++curr_hist;
+ if ( newest_hist >= HIST_SIZE )
+ {
+ // bump oldest off the list
+ hist_list.erase(hist_list.begin());
+ hist_list.push_back("");
+
+ oldest_hist++;
+ }
+}
+
+/**************************** GLUI_CommandLine::reset_history() ********/
+
+void GLUI_CommandLine::reset_history( void )
+{
+ oldest_hist = newest_hist = curr_hist = 0;
+}
+
+
+
+/*************************************** GLUI_CommandLine::dump() **************/
+
+void GLUI_CommandLine::dump( FILE *out, const char *name )
+{
+ fprintf( out,
+ "%s (commandline@%p): ins_pt:%d subs:%d/%d sel:%d/%d len:%d\n",
+ name, this,
+ insertion_pt, substring_start, substring_end, sel_start, sel_end,
+ (int)text.length());
+}
+
+
diff --git a/tests/box2d/glui/glui_control.cpp b/tests/box2d/glui/glui_control.cpp new file mode 100755 index 00000000..056916f3 --- /dev/null +++ b/tests/box2d/glui/glui_control.cpp @@ -0,0 +1,1203 @@ +/****************************************************************************
+
+ GLUI User Interface Toolkit
+ ---------------------------
+
+ glui_control.cpp - top-level GLUI_Control class
+
+
+ --------------------------------------------------
+
+ Copyright (c) 1998 Paul Rademacher
+
+ WWW: http://sourceforge.net/projects/glui/
+ Forums: http://sourceforge.net/forum/?group_id=92496
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+#include "glui_internal_control.h"
+
+int _glui_draw_border_only = 0;
+
+/*************************** Drawing Utility routines *********************/
+
+/* Redraw this control. */
+void GLUI_Control::redraw(void) {
+ if (glui==NULL || hidden) return;
+ if (glui->should_redraw_now(this))
+ translate_and_draw_front();
+}
+
+/** Redraw everybody in our window. */
+void GLUI_Control::redraw_window(void) {
+ if (glui==NULL || hidden) return;
+ if ( glui->get_glut_window_id() == -1 ) return;
+ int orig = set_to_glut_window();
+ glutPostRedisplay();
+ restore_window(orig);
+}
+
+
+
+/* GLUI_Control::translate_and_draw_front() ********/
+
+void GLUI_Control::translate_and_draw_front()
+{
+ GLUI_DRAWINGSENTINAL_IDIOM
+
+ glMatrixMode( GL_MODELVIEW );
+ glPushMatrix();
+ translate_to_origin();
+ draw(0,0);
+ glPopMatrix();
+}
+
+
+/********** GLUI_Control::set_to_bkgd_color() ********/
+
+void GLUI_Control::set_to_bkgd_color( void )
+{
+ if ( NOT glui )
+ return;
+
+ glColor3ub( glui->bkgd_color.r, glui->bkgd_color.g, glui->bkgd_color.b );
+}
+
+/******** GLUI_Control::draw_box_inwards_outline() ********/
+
+void GLUI_Control::draw_box_inwards_outline( int x_min, int x_max, int y_min, int y_max )
+{
+ glBegin( GL_LINES );
+ glColor3f( .5, .5, .5 );
+ glVertex2i( x_min, y_min ); glVertex2i( x_max, y_min );
+ glVertex2i( x_min, y_min ); glVertex2i( x_min, y_max );
+
+ glColor3f( 1., 1., 1. );
+ glVertex2i( x_min, y_max ); glVertex2i( x_max, y_max );
+ glVertex2i( x_max, y_max ); glVertex2i( x_max, y_min );
+
+ if ( enabled )
+ glColor3f( 0., 0., 0. );
+ else
+ glColor3f( .25, .25, .25 );
+
+ glVertex2i( x_min+1, y_min+1 ); glVertex2i( x_max-1, y_min+1 );
+ glVertex2i( x_min+1, y_min+1 ); glVertex2i( x_min+1, y_max-1 );
+
+ glColor3f( .75, .75, .75 );
+ glVertex2i( x_min+1, y_max-1 ); glVertex2i( x_max-1, y_max-1 );
+ glVertex2i( x_max-1, y_max-1 ); glVertex2i( x_max-1, y_min+1 );
+ glEnd();
+}
+
+
+/******* GLUI_Control::draw_box() **********/
+
+void GLUI_Control::draw_box( int x_min, int x_max, int y_min, int y_max, float r, float g, float b)
+{
+ if ( r == 1.0 AND g == 1.0 AND b == 1.0 AND NOT enabled AND glui ) {
+ draw_bkgd_box( x_min, x_max, y_min, y_max );
+ return;
+ }
+
+ glColor3f( r, g, b );
+ glBegin( GL_QUADS );
+ glVertex2i( x_min, y_min ); glVertex2i( x_max, y_min );
+ glVertex2i( x_max, y_max ); glVertex2i( x_min, y_max );
+ glEnd();
+}
+
+
+/******* GLUI_Control::draw_bkgd_box() **********/
+
+void GLUI_Control::draw_bkgd_box( int x_min, int x_max, int y_min, int y_max )
+{
+ set_to_bkgd_color();
+
+ glBegin( GL_QUADS );
+ glVertex2i( x_min, y_min ); glVertex2i( x_max, y_min );
+ glVertex2i( x_max, y_max ); glVertex2i( x_min, y_max );
+ glEnd();
+}
+
+
+/**** GLUI_Control::draw_active_area() ********/
+
+void GLUI_Control::draw_active_box( int x_min, int x_max, int y_min, int y_max )
+{
+ GLUI_DRAWINGSENTINAL_IDIOM
+
+ if ( active ) {
+ glEnable( GL_LINE_STIPPLE );
+ glLineStipple( 1, 0x5555 );
+ glColor3f( 0., 0., 0. );
+ } else {
+ set_to_bkgd_color();
+ }
+
+ glBegin( GL_LINE_LOOP );
+ glVertex2i(x_min, y_min); glVertex2i( x_max, y_min );
+ glVertex2i(x_max, y_max); glVertex2i( x_min, y_max );
+ glEnd();
+
+ glDisable( GL_LINE_STIPPLE );
+}
+
+
+/**** GLUI_Control::draw_emboss_box() ********/
+
+void GLUI_Control::draw_emboss_box(int x_min,int x_max,int y_min,int y_max)
+{
+ glLineWidth( 1.0 );
+ glColor3f( 1.0, 1.0, 1.0 );
+
+ glBegin( GL_LINE_LOOP );
+ glVertex2i( x_min, y_min ); glVertex2i( x_max, y_min );
+ glVertex2i( x_max, y_max ); glVertex2i( x_min, y_max );
+ glEnd();
+
+ glBegin( GL_LINE_LOOP );
+ glVertex2i( x_min+1, y_min+1 ); glVertex2i( x_max-1, y_min+1 );
+ glVertex2i( x_max-1, y_max-1 ); glVertex2i( x_min+1, y_max-1 );
+ glEnd();
+
+ glColor3f( .5, .5, .5 );
+ glBegin( GL_LINE_LOOP );
+ glVertex2i( x_min, y_min );
+ glVertex2i( x_max-1, y_min );
+ glVertex2i( x_max-1, y_max-1 );
+ glVertex2i( x_min, y_max-1 );
+ glEnd();
+}
+
+
+
+/******* GLUT_Control::draw_recursive() **********/
+
+void GLUI_Control::draw_recursive( int x, int y )
+{
+ GLUI_Control *node;
+
+ /* printf( "%s %d\n", this->name.c_str(), this->hidden );*/
+ if ( NOT can_draw() )
+ return;
+
+ /*if ( 1 ) { -- Debugging to check control width
+ glColor3f( 1.0, 0.0, 0.0 );
+ glBegin( GL_LINES );
+ glVertex2i( x_abs, y_abs );00
+ glVertex2i( x_abs+w, y_abs );
+
+ glEnd();
+ }*/
+
+ glMatrixMode( GL_MODELVIEW );
+ glPushMatrix();
+
+ glTranslatef( (float) this->x_abs + .5,
+ (float) this->y_abs + .5,
+ 0.0 );
+
+ if ( NOT _glui_draw_border_only ) {
+ if ( NOT strcmp( name.c_str(), "Rollout" ) ) {
+ }
+
+ this->draw( this->x_off, this->y_off_top );
+ }
+ else
+ {
+ if ( dynamic_cast<GLUI_Column*>(this) ) {
+ /* printf( "%s w/h: %d/%d\n", (char*) name, w, h ); */
+ /*w = 2; */
+ }
+
+ /* The following draws the area of each control */
+ glColor3f( 1.0, 0.0, 0.0 );
+ glBegin( GL_LINE_LOOP );
+ glVertex2i( 0, 0 ); glVertex2i( w, 0 );
+ glVertex2i( w, h ); glVertex2i( 0, h );
+ glEnd();
+ }
+ glPopMatrix();
+
+ node = (GLUI_Control*) first_child();
+ while( node ) {
+ node->draw_recursive( node->x_abs, node->y_abs );
+ node = (GLUI_Control*) node->next();
+ }
+}
+
+
+/****** GLUI_Control::set_to_glut_window() *********/
+/* Sets the current window to the glut window associated with this control */
+
+int GLUI_Control::set_to_glut_window()
+{
+ int orig_window;
+
+ if ( NOT glui)
+ return 1;
+
+ orig_window = glutGetWindow();
+
+ glutSetWindow( glui->get_glut_window_id());
+
+ return orig_window;
+}
+
+
+/********** GLUI_Control::restore_window() *********/
+
+void GLUI_Control::restore_window(int orig)
+{
+ if ( orig > 0 )
+ glutSetWindow( orig );
+}
+
+
+
+/****************************** Text ***************************/
+
+/*************** GLUI_Control::set_font() **********/
+
+void GLUI_Control::set_font(void *new_font)
+{
+ font = new_font;
+ redraw();
+}
+
+
+/********** GLUI_Control::draw_string() ************/
+
+void GLUI_Control::draw_string( const char *text )
+{
+ _glutBitmapString( get_font(), text );
+}
+
+
+/**************** GLUI_Control::draw_char() ********/
+
+void GLUI_Control::draw_char(char c)
+{
+ glutBitmapCharacter( get_font(), c );
+}
+
+
+/*********** GLUI_Control::string_width() **********/
+
+int GLUI_Control::string_width(const char *text)
+{
+ return _glutBitmapWidthString( get_font(), text );
+}
+
+
+/************* GLUI_Control::char_width() **********/
+
+int GLUI_Control::char_width(char c)
+{ /* Hash table for faster character width lookups - JVK
+ Speeds up the textbox a little bit.
+ */
+ int hash_index = c % CHAR_WIDTH_HASH_SIZE;
+ if (char_widths[hash_index][0] != c) {
+ char_widths[hash_index][0] = c;
+ char_widths[hash_index][1] = glutBitmapWidth( get_font(), c );
+ }
+ return char_widths[hash_index][1];
+}
+
+
+/*************** GLUI_Control::get_font() **********/
+
+void *GLUI_Control::get_font( void )
+{
+ /*** Does this control have its own font? ***/
+ if ( this->font != NULL )
+ return this->font;
+
+ /*** Does the parent glui have a font? ***/
+ if ( glui )
+ return glui->font;
+
+ /*** Return the default font ***/
+ return GLUT_BITMAP_HELVETICA_12;
+}
+
+
+/************* GLUI_Control::draw_name() ***********/
+/* This draws the name of the control as either black (if enabled), or */
+/* embossed if disabled. */
+
+void GLUI_Control::draw_name(int x, int y)
+{
+ if ( NOT can_draw() )
+ return;
+
+ if ( enabled )
+ {
+ set_to_bkgd_color();
+ glRasterPos2i(x+1, y+1);
+ draw_string(name);
+ glColor3b( 0, 0, 0 );
+ glRasterPos2i(x, y);
+ draw_string(name);
+ }
+ else
+ { /* Control is disabled - emboss the string */
+ glColor3f( 1.0f, 1.0f, 1.0f );
+ glRasterPos2i(x+1, y+1);
+ draw_string(name);
+ glColor3f( .4f, .4f, .4f );
+ glRasterPos2i(x, y);
+ draw_string(name);
+ }
+}
+
+
+/**************************** Layout and Packing *********************/
+
+/****** GLUI_Control::align() **************/
+
+void GLUI_Control::align()
+{
+ int col_x, col_y, col_w, col_h, col_x_off, col_y_off;
+ int orig_x_abs;
+
+ orig_x_abs = x_abs;
+
+ /* Fix alignment bug relating to columns */
+ /*return; */
+
+ if ( NOT parent() )
+ return; /* Clearly this shouldn't happen, though */
+
+ get_this_column_dims(&col_x, &col_y, &col_w, &col_h,
+ &col_x_off, &col_y_off);
+
+ if ( dynamic_cast<GLUI_Column*>(this) ) {
+ /* if ( this->prev() != NULL ) {
+ ((GLUI_Control*)prev())->get_this_column_dims(&col_x, &col_y, &col_w, &col_h,
+ &col_x_off, &col_y_off);
+
+ x_abs = col_x + col_w;
+ }
+ else {
+ x_abs = ((GLUI_Control*)parent())->x_abs;
+ }
+ */
+ return;
+ }
+
+ if ( alignment == GLUI_ALIGN_LEFT ) {
+ x_abs = col_x + col_x_off;
+ }
+ else if ( alignment == GLUI_ALIGN_RIGHT ) {
+ x_abs = col_x + col_w - col_x_off - this->w;
+ }
+ else if ( alignment == GLUI_ALIGN_CENTER ) {
+ x_abs = col_x + (col_w - this->w) / 2;
+ }
+
+ if ( this->is_container ) {
+ /*** Shift all child columns ***/
+ int delta = x_abs - orig_x_abs;
+
+ GLUI_Control *node;
+
+ node = (GLUI_Control*) this->first_child();
+ while( node != NULL ) {
+ if ( dynamic_cast<GLUI_Column*>(node) ) {
+ node->x_abs += delta;
+ }
+
+ node = (GLUI_Control*) node->next();
+ }
+ }
+
+}
+
+
+/************** GLUI_Control::pack() ************/
+/* Recalculate positions and offsets */
+
+void GLUI_Control::pack_old(int x, int y)
+{
+ GLUI_Control *node;
+ int max_w, curr_y, curr_x, max_y;
+ int x_in = x, y_in =y;
+ int x_margin, y_margin_top, y_margin_bot;
+ int y_top_column;
+ int column_x;
+ GLUI_Column *curr_column = NULL;
+ this->update_size();
+ x_margin = this->x_off;
+ y_margin_top = this->y_off_top;
+ y_margin_bot = this->y_off_bot;
+ this->x_abs = x_in;
+ this->y_abs = y_in;
+ max_w = -1;
+ max_y = -1;
+ curr_x = this->x_abs + x_margin;
+ curr_y = this->y_abs + y_margin_top;
+ /*** Record start of this set of columns ***/
+ y_top_column = curr_y;
+ column_x = 0;
+ if ( this == glui->main_panel ) {
+ x=x;
+ }
+ /*** Iterate over children, packing them first ***/
+ node = (GLUI_Control*) this->first_child();
+ while( node != NULL ) {
+ if ( dynamic_cast<GLUI_Panel*>(node) && !node->collapsible) {
+ /* Pad some space above fixed size panels */
+ curr_y += GLUI_ITEMSPACING;
+ }
+ else if ( dynamic_cast<GLUI_Column*>(node)) {
+ curr_column = (GLUI_Column*) node;
+ if ( 1 ) {
+ column_x += max_w + 2 * x_margin;
+ curr_x += max_w + 2 * x_margin;
+ }
+ else {
+ column_x += max_w + 0 * x_margin;
+ curr_x += max_w + 0 * x_margin;
+ }
+ /*node->pack( curr_x, curr_y ); */
+ node->x_abs = curr_x;
+ node->y_abs = y_top_column;
+ node->w = 2;
+ node->h = curr_y - y_top_column;
+ curr_x += x_margin * 3 + 40;
+ curr_y = y_top_column;
+ max_w = 0;
+ node = (GLUI_Control*) node->next();
+ continue;
+ }
+ node->pack( curr_x, curr_y );
+ if ( dynamic_cast<GLUI_Panel*>(node) && !node->collapsible)
+ /* Pad some space below fixed size panels */
+ curr_y += GLUI_ITEMSPACING;
+ curr_y += node->h;
+ if ( node->w > max_w ) {
+ max_w = node->w;
+ if ( curr_column != NULL )
+ curr_column->w = max_w;
+ }
+ node = (GLUI_Control*) node->next();
+ if ( node ) {
+ curr_y += GLUI_ITEMSPACING;
+ }
+ if ( curr_y > max_y )
+ max_y = curr_y;
+ }
+ if ( this->is_container ) {
+ max_y += y_margin_bot; /*** Add bottom border inside box */
+ if ( this->first_child() ) {
+ if ( dynamic_cast<GLUI_Rollout*>(this) ) {
+ /** We don't want the rollout to shrink in width when it's
+ closed **/
+ this->w = MAX(this->w, column_x + max_w + 2 * x_margin );
+ }
+ else {
+ this->w = column_x + max_w + 2 * x_margin;
+ }
+ this->h = (max_y - y_in);
+ }
+ else { /* An empty container, so just assign default w & h */
+ this->w = GLUI_DEFAULT_CONTROL_WIDTH;
+ this->h = GLUI_DEFAULT_CONTROL_HEIGHT;
+ }
+ /** Expand panel if necessary (e.g., to include all the text in
+ a panel label) **/
+ this->update_size();
+ }
+}
+
+/*** GLUI_Control::get_this_column_dims() **********/
+/* Gets the x,y,w,h,and x/y offsets of the column to which a control belongs */
+
+void GLUI_Control::get_this_column_dims( int *col_x, int *col_y,
+ int *col_w, int *col_h,
+ int *col_x_off, int *col_y_off )
+{
+ GLUI_Control *node, *parent_ptr;
+ int parent_h, parent_y_abs;
+
+ parent_ptr = (GLUI_Control*) parent();
+
+ if ( parent_ptr==NULL )
+ return;
+
+ parent_h = parent_ptr->h;
+ parent_y_abs = parent_ptr->y_abs;
+
+ if ( dynamic_cast<GLUI_Panel*>(parent_ptr) AND
+ parent_ptr->int_val == GLUI_PANEL_EMBOSSED AND
+ parent_ptr->name != "" ) {
+ parent_h -= GLUI_PANEL_EMBOSS_TOP;
+ parent_y_abs += GLUI_PANEL_EMBOSS_TOP;
+ }
+
+ if ( 0 ) {
+ GLUI_Node *first, *last, *curr;
+
+ /** Look for first control in this column **/
+ first = this;
+ while (first->prev() AND !dynamic_cast<GLUI_Column*>(first->prev()) )
+ first = first->prev();
+
+ /** Look for last control in this column **/
+ last = this;
+ while ( last->next() AND !dynamic_cast<GLUI_Column*>(first->next()) )
+ last = last->next();
+
+ curr = first;
+ int max_w = -1;
+ do {
+ if ( ((GLUI_Control*)curr)->w > max_w )
+ max_w = ((GLUI_Control*)curr)->w;
+
+ if ( curr == last )
+ break;
+
+ curr = curr->next();
+ } while( curr != NULL );
+
+ *col_x = ((GLUI_Control*)first)->x_abs;
+ *col_y = ((GLUI_Control*)first)->y_abs;
+ *col_w = max_w;
+ if ( parent() ) {
+ *col_h = ((GLUI_Control*)parent())->h;
+ *col_x_off = ((GLUI_Control*)parent())->x_off;
+ }
+ else {
+ *col_h = 10;
+ *col_x_off = 0;
+ }
+ *col_y_off = 0;
+
+ return;
+ }
+
+ if ( 1 ) { /* IS THIS WRONG? */
+ /*** Look for preceding column ***/
+ node = (GLUI_Control*) this->prev();
+ while( node ) {
+ if ( dynamic_cast<GLUI_Column*>(node) ) {
+ *col_x = node->x_abs;
+ *col_y = parent_y_abs;
+ *col_w = node->w;
+ *col_h = parent_h;
+ *col_x_off = node->x_off;
+ *col_y_off = 0;
+
+ return;
+ }
+
+ node = (GLUI_Control*) node->prev();
+ }
+
+ /*** Nope, Look for next column ***/
+ node = (GLUI_Control*) this->next();
+ while( node ) {
+ if ( dynamic_cast<GLUI_Column*>(node) ) {
+ *col_x = parent_ptr->x_abs;
+ *col_y = parent_y_abs;
+ *col_w = node->x_abs - parent_ptr->x_abs;
+ *col_h = parent_h;
+ *col_x_off = node->x_off;
+ *col_y_off = 0;
+
+ return;
+ }
+
+ node = (GLUI_Control*) node->next();
+ }
+
+ /*** This is single-column panel, so return panel dims ***/
+ *col_x = parent_ptr->x_abs;
+ *col_y = parent_y_abs;
+ *col_w = parent_ptr->w;
+ *col_h = parent_h;
+ *col_x_off = parent_ptr->x_off;
+ *col_y_off = 0;
+ }
+}
+
+
+void GLUI_Control::pack( int x, int y )
+{
+ GLUI_Control *node;
+ int max_w, curr_y, curr_x, max_y;
+ int x_in = x, y_in =y;
+ int x_margin, y_margin_top, y_margin_bot;
+ int y_top_column;
+ int column_x;
+ GLUI_Column *curr_column = NULL;
+
+ this->update_size();
+
+ x_margin = this->x_off;
+ y_margin_top = this->y_off_top;
+ y_margin_bot = this->y_off_bot;
+
+ this->x_abs = x_in;
+ this->y_abs = y_in;
+
+ max_w = 0;
+ max_y = 0;
+ curr_x = this->x_abs + x_margin;
+ curr_y = this->y_abs + y_margin_top;
+
+ /*** Record start of this set of columns ***/
+
+ y_top_column = curr_y;
+ column_x = curr_x;
+
+ /*** Iterate over children, packing them first ***/
+
+ node = (GLUI_Control*) this->first_child();
+ while( node != NULL ) {
+ if ( dynamic_cast<GLUI_Panel*>(node) && !node->collapsible) {
+ /* Pad some space above fixed-size panels */
+ curr_y += GLUI_ITEMSPACING;
+ }
+ else if ( dynamic_cast<GLUI_Column*>(node) ) {
+ curr_column = (GLUI_Column*) node;
+ curr_x += max_w + 1 * x_margin;
+ column_x = curr_x;
+
+ node->x_abs = curr_x;
+ node->y_abs = y_top_column;
+ node->w = 2;
+ node->h = curr_y - y_top_column;
+
+ curr_x += x_margin * 1;
+ curr_y = y_top_column;
+ max_w = 0;
+
+ node = (GLUI_Control*) node->next();
+ continue;
+ }
+
+ node->pack( curr_x, curr_y );
+
+ if ( dynamic_cast<GLUI_Panel*>(node) && !node->collapsible)
+ /* Pad some space below fixed-size panels */
+ curr_y += GLUI_ITEMSPACING;
+
+ curr_y += node->h;
+
+ if ( node->w > max_w ) {
+ max_w = node->w;
+ if ( curr_column != NULL )
+ curr_column->w = max_w + x_margin;
+ }
+
+ if ( curr_y > max_y ) {
+ max_y = curr_y;
+ if ( curr_column != NULL )
+ curr_column->h = max_y - y_top_column;
+ }
+
+ node = (GLUI_Control*) node->next();
+
+ if ( node ) {
+ curr_y += GLUI_ITEMSPACING;
+ }
+
+ }
+
+ if ( this->is_container ) {
+ max_y += y_margin_bot; /*** Add bottom border inside box */
+
+ if ( this->first_child() ) {
+ this->w = column_x + max_w + 2 * x_margin - x_in;
+ this->h = (max_y - y_in);
+ }
+ else { /* An empty container, so just assign default w & h */
+ if ( !dynamic_cast<GLUI_Rollout*>(this) &&
+ !dynamic_cast<GLUI_Tree*>(this) ) {
+ this->w = GLUI_DEFAULT_CONTROL_WIDTH;
+ this->h = GLUI_DEFAULT_CONTROL_HEIGHT;
+ }
+ }
+
+ /** Expand panel if necessary (e.g., to include all the text in
+ a panel label) **/
+ this->update_size();
+
+
+ /*** Now we step through the GLUI_Columns, setting the 'h' ***/
+ node = (GLUI_Control*) this->first_child();
+ while( node != NULL ) {
+ if ( dynamic_cast<GLUI_Column*>(node) ) {
+ node->h = this->h - y_margin_bot - y_margin_top;
+ }
+
+ node = (GLUI_Control*) node->next();
+ }
+ }
+}
+
+
+
+/******************************** Live Variables **************************/
+/*********** GLUI_Control::sync_live() ************/
+/* Reads live variable and sets control to its current value */
+/* This function is recursive, and operates on control's children */
+
+void GLUI_Control::sync_live(int recurse, int draw_it)
+{
+ GLUI_Node *node;
+ int sync_it=true;
+ int i;
+ float *fp;
+ bool changed = false;
+
+ /*** If this is currently active control, and mouse button is down,
+ don't sync ***/
+ if ( glui )
+ {
+ if ( this == glui->active_control AND glui->mouse_button_down )
+ sync_it = false;
+
+ /*** Actually, just disable syncing if button is down ***/
+ /*** Nope, go ahead and sync if mouse is down - this allows syncing in
+ callbacks ***/
+ if ( 0 ) { /* THIS CODE BELOW SHOULD NOT BE EXECUTED */
+ if ( glui->mouse_button_down ) {
+ /* printf( "Can't sync\n" ); */
+ return;
+ }
+ }
+ }
+
+ /*** If this control has a live variable, we check its current value
+ against the stored value in the control ***/
+
+ if ( ptr_val != NULL ) {
+ if ( live_type == GLUI_LIVE_NONE OR NOT sync_it ) {
+ }
+ else if ( live_type == GLUI_LIVE_INT ) {
+ if ( *((int*)ptr_val) != last_live_int ) {
+ set_int_val( *((int*)ptr_val) );
+ last_live_int = *((int*)ptr_val);
+ changed = true;
+ }
+ }
+ else if ( live_type == GLUI_LIVE_FLOAT ) {
+ if ( *((float*)ptr_val) != last_live_float ) {
+ set_float_val( *((float*)ptr_val) );
+ last_live_float = *((float*)ptr_val);
+ changed = true;
+ }
+ }
+ else if ( live_type == GLUI_LIVE_TEXT ) {
+ if ( last_live_text.compare((const char*)ptr_val) != 0 ) {
+ set_text( (char*) ptr_val );
+ last_live_text = (const char*)ptr_val;
+ changed = true;
+ }
+ }
+ else if ( live_type == GLUI_LIVE_STRING ) {
+ if ( last_live_text.compare(((std::string*) ptr_val)->c_str()) != 0 ) {
+ set_text( ((std::string*) ptr_val)->c_str());
+ last_live_text = *((std::string*) ptr_val);
+ changed = true;
+ }
+ }
+ else if ( live_type == GLUI_LIVE_FLOAT_ARRAY ) {
+ /*** Step through the arrays, and see if they're the same ***/
+
+ fp = (float*) ptr_val;
+ for ( i=0; i<float_array_size; i++ ) {
+ if ( *fp != last_live_float_array[i] ) {
+ changed = true;
+ break;
+ }
+
+ fp++;
+ }
+
+ if ( changed == true) {
+ fp = (float*) ptr_val;
+ set_float_array_val( fp );
+ for ( i=0; i<float_array_size; i++ ) {
+ last_live_float_array[i] = *fp;
+ fp++;
+ }
+ }
+ }
+ else if ( live_type == GLUI_LIVE_DOUBLE ) {
+ }
+ }
+
+ /*** If this control is changed and we're supposed to be drawing, then
+ draw it now ***/
+ if ( changed == true AND draw_it ) {
+ redraw();
+ }
+
+ if ( recurse ) {
+ /*** Now recursively output live vars for all children ***/
+ node = this->first_child();
+ while( node ) {
+ ((GLUI_Control*) node)->sync_live(true, true);
+ node = node->next();
+ }
+
+ if ( collapsible == true AND is_open == false ) {
+ /** Here we have a collapsed control (e.g., a rollout that is closed **/
+ /** We need to go in and sync all the collapsed controls inside **/
+
+ node = this->collapsed_node.first_child();
+ while( node ) {
+ ((GLUI_Control*) node)->sync_live(true, false);
+ node = node->next();
+ }
+ }
+ }
+}
+
+
+/********** GLUI_Control::output_live() ************/
+/* Writes current value of control to live variable. */
+
+void GLUI_Control::output_live(int update_main_gfx)
+{
+ int i;
+ float *fp;
+
+ if ( ptr_val == NULL )
+ return;
+
+ if ( NOT live_inited )
+ return;
+
+ if ( live_type == GLUI_LIVE_NONE ) {
+ }
+ else if ( live_type == GLUI_LIVE_INT ) {
+ *((int*)ptr_val) = int_val;
+ last_live_int = int_val;
+ }
+ else if ( live_type == GLUI_LIVE_FLOAT ) {
+ *((float*)ptr_val) = float_val;
+ last_live_float = float_val;
+ }
+ else if ( live_type == GLUI_LIVE_TEXT ) {
+ strncpy( (char*) ptr_val, text.c_str(), text.length()+1);
+ last_live_text = text;
+ }
+ else if ( live_type == GLUI_LIVE_STRING ) {
+ (*(std::string*)ptr_val)= text.c_str();
+ last_live_text = text;
+ }
+ else if ( live_type == GLUI_LIVE_FLOAT_ARRAY ) {
+ fp = (float*) ptr_val;
+
+ for( i=0; i<float_array_size; i++ ) {
+ *fp = float_array_val[i];
+ last_live_float_array[i] = float_array_val[i];
+ fp++;
+ }
+ }
+ else if ( live_type == GLUI_LIVE_DOUBLE ) {
+ }
+
+ /** Update the main gfx window? **/
+ if ( update_main_gfx AND this->glui != NULL ) {
+ this->glui->post_update_main_gfx();
+ }
+}
+
+
+/****** GLUI_Control::execute_callback() **********/
+
+void GLUI_Control::execute_callback()
+{
+ int old_window;
+
+ old_window = glutGetWindow();
+
+ if ( glui AND glui->main_gfx_window_id != -1 )
+ glutSetWindow( glui->main_gfx_window_id );
+
+ this->callback( this );
+// if ( this->callback )
+// this->callback( this->user_id );
+
+ glutSetWindow( old_window );
+}
+
+
+/************** GLUI_Control::init_live() **********/
+/* Reads in value of a live variable. Called once, when ctrl is created */
+
+void GLUI_Control::init_live()
+{
+ int i;
+ float *fp;
+
+ if ( ptr_val == NULL )
+ return;
+
+ if ( live_type == GLUI_LIVE_NONE ) {
+ }
+ else if ( live_type == GLUI_LIVE_INT ) {
+ set_int_val( *((int*)ptr_val) );
+ last_live_int = *((int*)ptr_val);
+ }
+ else if ( live_type == GLUI_LIVE_FLOAT ) {
+ set_float_val( *((float*)ptr_val) );
+ last_live_float = *((float*)ptr_val);
+ }
+ else if ( live_type == GLUI_LIVE_TEXT ) {
+ set_text( (const char*) ptr_val );
+ last_live_text = (const char*) ptr_val;
+ }
+ else if ( live_type == GLUI_LIVE_STRING ) {
+ set_text( ((std::string*) ptr_val)->c_str() );
+ last_live_text = ((std::string*) ptr_val)->c_str();
+ }
+ else if ( live_type == GLUI_LIVE_FLOAT_ARRAY ) {
+ set_float_array_val( (float*) ptr_val );
+
+ fp = (float*) ptr_val;
+
+ for( i=0; i<float_array_size; i++ ) {
+ last_live_float_array[i] = *fp;
+ fp++;
+ }
+
+ }
+ else if ( live_type == GLUI_LIVE_DOUBLE ) {
+ }
+
+ live_inited = true;
+}
+
+/***** GLUI_Control::set_float_array_val() ********/
+
+void GLUI_Control::set_float_array_val( float *array_ptr )
+{
+ int i;
+
+ if ( array_ptr == NULL )
+ return;
+
+ for( i=0; i<float_array_size; i++ ) {
+ float_array_val[i] = array_ptr[i];
+ }
+
+ /*** Output the live var, without updating the main gfx window ***/
+ output_live(false);
+}
+
+
+/***** GLUI_Control::get_float_array_val() ********/
+
+void GLUI_Control::get_float_array_val( float *array_ptr )
+{
+ int i;
+
+ if ( array_ptr == NULL )
+ return;
+
+ for( i=0; i<float_array_size; i++ ) {
+ array_ptr[i] = float_array_val[i];
+ }
+}
+
+
+
+/**************************** Little Utility Routines ********************/
+
+/**** GLUI_Control::set_name() ********************/
+
+void GLUI_Control::set_name( const char *str )
+{
+ name = str;
+ redraw();
+}
+
+/**** GLUI_Control::enable() ****************/
+
+void GLUI_Control::enable()
+{
+ GLUI_Control *node;
+
+ enabled = true;
+
+ if ( NOT glui )
+ return;
+
+ redraw();
+
+ /*** Now recursively enable all buttons below it ***/
+ node = (GLUI_Control*) first_child();
+ while(node)
+ {
+ node->enable();
+ node = (GLUI_Control*) node->next();
+ }
+}
+
+
+/***** GLUI_Control::disable() ****************/
+
+void GLUI_Control::disable()
+{
+ GLUI_Control *node;
+
+ enabled = false;
+
+ if ( NOT glui )
+ return;
+
+ if ( glui->active_control == this )
+ glui->deactivate_current_control();
+ redraw();
+
+ /*** Now recursively disable all buttons below it ***/
+ node = (GLUI_Control*) first_child();
+ while(node) {
+ node->disable();
+ node = (GLUI_Control*) node->next();
+ }
+}
+
+/******* GLUI_Control::set_w() **************/
+
+void GLUI_Control::set_w(int new_w)
+{
+ w = new_w;
+ update_size(); /* Make sure control is big enough to fit text */
+ if (glui) glui->refresh();
+}
+
+
+/**** GLUI_Control::set_h() **************/
+
+void GLUI_Control::set_h(int new_h)
+{
+ h = new_h;
+ update_size(); /* Make sure control is big enough to fit text */
+ if (glui) glui->refresh();
+}
+
+
+/***** GLUI_Control::set_alignment() ******/
+
+void GLUI_Control::set_alignment(int new_align)
+{
+ alignment = new_align;
+
+ if ( glui )
+ {
+ glui->align_controls(this);
+ redraw_window();
+ }
+}
+
+
+/***** GLUI_Control::needs_idle() *********/
+/* This method gets overloaded by specific classes, e.g. Spinner. */
+/* It returns whether or not a control needs to receive an idle event or not */
+/* For example, a spinner only needs idle events when the user is holding */
+/* the mouse down in one of the arrows. Otherwise, don't waste cycles */
+/* and OpenGL context switching by calling its idle. */
+
+bool GLUI_Control::needs_idle() const
+{
+ return false;
+}
+
+
+/********* GLUI_Control::~GLUI_Control() **********/
+
+GLUI_Control::~GLUI_Control()
+{
+ GLUI_Control *item = (GLUI_Control*) this->first_child();
+
+ while (item)
+ {
+ GLUI_Control *tmp = item;
+ item = (GLUI_Control*) item->next();
+ delete tmp;
+ }
+}
+
+/********* GLUI_Control::hide_internal() ********/
+/** Sets hidden==true for this control and all its siblings. */
+/** If recurse is true, we go to children as well */
+
+void GLUI_Control::hide_internal( int recurse )
+{
+ GLUI_Node *node;
+
+ node = (GLUI_Node *) this;
+ while( node != NULL ) {
+ ((GLUI_Control*)node)->hidden = true;
+
+ if ( recurse AND node->first_child() != NULL )
+ ((GLUI_Control*) node->first_child())->hide_internal(true);
+
+ node = node->next();
+ }
+
+ node = this->collapsed_node.first_child();
+ while( node != NULL ) {
+ ((GLUI_Control*)node)->hidden = true;
+
+ if ( recurse AND node->first_child() != NULL )
+ ((GLUI_Control*) node->first_child())->hide_internal(true);
+
+ node = node->next();
+ }
+}
+
+
+/********* GLUI_Control::unhide_internal() ********/
+/** Sets hidden==false for this control and all its siblings. */
+/** If recurse is true, we go to children as well */
+
+void GLUI_Control::unhide_internal( int recurse )
+{
+ GLUI_Node *node;
+
+ node = (GLUI_Node *) this;
+ while( node != NULL ) {
+ /* printf( "unhide: %s [%d]\n", ((GLUI_Control*)node)->name.c_str(),
+ ((GLUI_Control*)node)->hidden );*/
+ ((GLUI_Control*)node)->hidden = false;
+
+ if ( recurse AND node->first_child() != NULL )
+ ((GLUI_Control*) node->first_child())->unhide_internal(true);
+
+ node = node->next();
+ }
+
+ node = this->collapsed_node.first_child();
+ while( node != NULL ) {
+ ((GLUI_Control*)node)->hidden = false;
+
+ if ( recurse AND node->first_child() != NULL )
+ ((GLUI_Control*) node->first_child())->unhide_internal(true);
+
+ node = node->next();
+ }
+}
diff --git a/tests/box2d/glui/glui_edittext.cpp b/tests/box2d/glui/glui_edittext.cpp new file mode 100755 index 00000000..5f2a1d84 --- /dev/null +++ b/tests/box2d/glui/glui_edittext.cpp @@ -0,0 +1,1198 @@ +/****************************************************************************
+
+ GLUI User Interface Toolkit
+ ---------------------------
+
+ glui_edittext.cpp - GLUI_EditText control class
+
+
+ --------------------------------------------------
+
+ Copyright (c) 1998 Paul Rademacher
+
+ WWW: http://sourceforge.net/projects/glui/
+ Forums: http://sourceforge.net/forum/?group_id=92496
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+#include "glui_internal_control.h"
+#include <cassert>
+
+/****************************** GLUI_EditText::GLUI_EditText() **********/
+
+GLUI_EditText::GLUI_EditText( GLUI_Node *parent, const char *name,
+ int data_type, void *live_var,
+ int id, GLUI_CB callback )
+{
+ if (data_type == GLUI_EDITTEXT_TEXT) {
+ live_type = GLUI_LIVE_TEXT;
+ }
+ else if (data_type == GLUI_EDITTEXT_STRING) {
+ data_type = GLUI_EDITTEXT_TEXT; // EDITTEXT_STRING doesn't really exist.
+ // Except as a signal to make a string.
+ // It's a backwards-compat hack.
+ live_type = GLUI_LIVE_STRING;
+ }
+ else if (data_type == GLUI_EDITTEXT_INT) {
+ live_type = GLUI_LIVE_INT;
+ }
+ else if (data_type == GLUI_EDITTEXT_FLOAT) {
+ live_type = GLUI_LIVE_FLOAT;
+ }
+ common_construct( parent, name, data_type, live_type, live_var, id, callback );
+}
+
+/****************************** GLUI_EditText::GLUI_EditText() **********/
+
+GLUI_EditText::GLUI_EditText( GLUI_Node *parent, const char *name,
+ int text_type, int id, GLUI_CB callback )
+{
+ common_construct( parent, name, text_type, GLUI_LIVE_NONE, 0, id, callback);
+}
+
+/****************************** GLUI_EditText::GLUI_EditText() **********/
+
+GLUI_EditText::GLUI_EditText( GLUI_Node *parent, const char *name,
+ int *live_var,
+ int id, GLUI_CB callback )
+{
+ common_construct( parent, name, GLUI_EDITTEXT_INT, GLUI_LIVE_INT, live_var, id, callback);
+}
+
+/****************************** GLUI_EditText::GLUI_EditText() **********/
+
+GLUI_EditText::GLUI_EditText( GLUI_Node *parent, const char *name,
+ float *live_var,
+ int id, GLUI_CB callback )
+{
+ common_construct( parent, name, GLUI_EDITTEXT_FLOAT, GLUI_LIVE_FLOAT, live_var, id, callback);
+}
+
+/****************************** GLUI_EditText::GLUI_EditText() **********/
+
+GLUI_EditText::GLUI_EditText( GLUI_Node *parent, const char *name,
+ char *live_var,
+ int id, GLUI_CB callback )
+{
+ common_construct( parent, name, GLUI_EDITTEXT_TEXT, GLUI_LIVE_TEXT, live_var, id, callback);
+}
+
+/****************************** GLUI_EditText::GLUI_EditText() **********/
+
+GLUI_EditText::GLUI_EditText( GLUI_Node *parent, const char *name,
+ std::string &live_var,
+ int id, GLUI_CB callback )
+{
+ common_construct( parent, name, GLUI_EDITTEXT_TEXT, GLUI_LIVE_STRING, &live_var, id, callback);
+}
+
+/****************************** GLUI_EditText::common_construct() **********/
+
+void GLUI_EditText::common_construct( GLUI_Node *parent, const char *name,
+ int data_t, int live_t, void *data, int id,
+ GLUI_CB cb )
+{
+ common_init();
+ set_name( name );
+
+ live_type = live_t;
+ data_type = data_t;
+ ptr_val = data;
+ user_id = id;
+ callback = cb;
+
+
+ if ( live_type == GLUI_LIVE_INT) {
+ if ( data == NULL )
+ set_int_val(int_val); /** Set to some default, in case of no live var **/
+ }
+ else if ( live_type == GLUI_LIVE_FLOAT ) {
+ num_periods = 1;
+ if ( data == NULL )
+ set_float_val(float_val); /** Set to some default, in case of no live var **/
+ }
+
+ parent->add_control( this );
+
+ init_live();
+}
+
+/****************************** GLUI_EditText::mouse_down_handler() **********/
+
+int GLUI_EditText::mouse_down_handler( int local_x, int local_y )
+{
+ int tmp_insertion_pt;
+
+ if ( debug ) dump( stdout, "-> MOUSE DOWN" );
+
+ tmp_insertion_pt = find_insertion_pt( local_x, local_y );
+ if ( tmp_insertion_pt == -1 ) {
+ if ( glui )
+ glui->deactivate_current_control( );
+ return false;
+ }
+
+ insertion_pt = tmp_insertion_pt;
+
+ sel_start = sel_end = insertion_pt;
+
+ if ( can_draw())
+ update_and_draw_text();
+
+ if ( debug ) dump( stdout, "<- MOUSE UP" );
+
+ return true;
+}
+
+
+/******************************** GLUI_EditText::mouse_up_handler() **********/
+
+int GLUI_EditText::mouse_up_handler( int local_x, int local_y, bool inside )
+{
+ return false;
+}
+
+
+/***************************** GLUI_EditText::mouse_held_down_handler() ******/
+
+int GLUI_EditText::mouse_held_down_handler( int local_x, int local_y,
+ bool new_inside)
+{
+ int tmp_pt;
+
+ if ( NOT new_inside )
+ return false;
+
+ if ( debug ) dump( stdout, "-> HELD DOWN" );
+
+ tmp_pt = find_insertion_pt( local_x, local_y );
+
+ if ( tmp_pt == -1 AND sel_end != 0 ) { /* moved mouse past left edge */
+ special_handler( GLUT_KEY_LEFT, GLUT_ACTIVE_SHIFT );
+ }
+ else if ( tmp_pt == substring_end+1 AND sel_end != (int) text.length()) {
+ /* moved mouse past right edge */
+ special_handler( GLUT_KEY_RIGHT, GLUT_ACTIVE_SHIFT );
+ }
+ else if ( tmp_pt != -1 AND tmp_pt != sel_end ) {
+ sel_end = insertion_pt = tmp_pt;
+
+ update_and_draw_text();
+ }
+
+ if ( debug )
+ dump( stdout, "<- HELD DOWN" );
+
+ return false;
+}
+
+
+/****************************** GLUI_EditText::key_handler() **********/
+
+int GLUI_EditText::key_handler( unsigned char key,int modifiers )
+{
+ int i, regular_key;
+ /* int has_selection; */
+
+ if ( NOT glui )
+ return false;
+
+ if ( debug )
+ dump( stdout, "-> KEY HANDLER" );
+
+ regular_key = false;
+ bool ctrl_down = (modifiers & GLUT_ACTIVE_CTRL)!=0;
+ /* has_selection = (sel_start != sel_end); */
+
+ if ( key == CTRL('m') ) { /* RETURN */
+ /* glui->deactivate_current_control(); */
+ deactivate(); /** Force callbacks, etc **/
+ activate(GLUI_ACTIVATE_TAB); /** Reselect all text **/
+ redraw();
+ return true;
+ }
+ else if ( key == CTRL('[')) { /* ESCAPE */
+ glui->deactivate_current_control();
+ return true;
+ }
+ else if ( (key == 127 AND !ctrl_down) OR /* FORWARD DELETE */
+ ( key == CTRL('d') AND modifiers == GLUT_ACTIVE_CTRL) )
+ {
+ if ( sel_start == sel_end ) { /* no selection */
+ if ( insertion_pt < (int)text.length() ) {
+ /*** See if we're deleting a period in a float data-type box ***/
+ if ( data_type == GLUI_EDITTEXT_FLOAT AND text[insertion_pt]=='.' )
+ num_periods--;
+
+ /*** Shift over string first ***/
+ text.erase(insertion_pt,1);
+ }
+ }
+ else { /* There is a selection */
+ clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end ));
+ insertion_pt = MIN(sel_start,sel_end);
+ sel_start = sel_end = insertion_pt;
+ }
+ }
+ else if ( ((key == 127) AND ctrl_down) OR // Delete word forward
+ ((key == 'd') AND (modifiers == GLUT_ACTIVE_ALT)) )
+ {
+ if ( sel_start == sel_end ) { /* no selection */
+ sel_start = insertion_pt;
+ sel_end = find_word_break( insertion_pt, +1 );
+ }
+
+ clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end ));
+ insertion_pt = MIN(sel_start,sel_end);
+ sel_start = sel_end = insertion_pt;
+ }
+ else if ( key == CTRL('h') ) { /* BACKSPACE */
+ if ( sel_start == sel_end ) { /* no selection */
+ if ( insertion_pt > 0 ) {
+ /*** See if we're deleting a period in a float data-type box ***/
+ if ( data_type == GLUI_EDITTEXT_FLOAT AND text[insertion_pt-1]=='.' )
+ num_periods--;
+
+ /*** Shift over string first ***/
+ insertion_pt--;
+ text.erase(insertion_pt,1);
+ }
+ }
+ else { /* There is a selection */
+ clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end ));
+ insertion_pt = MIN(sel_start,sel_end);
+ sel_start = sel_end = insertion_pt;
+ }
+ }
+ else if ( modifiers == GLUT_ACTIVE_CTRL ) /* CTRL ONLY */
+ {
+ /* Ctrl-key bindings */
+ if ( key == CTRL('a') ) {
+ return special_handler( GLUT_KEY_HOME, 0 );
+ }
+ else if ( key == CTRL('e') ) {
+ return special_handler( GLUT_KEY_END, 0 );
+ }
+ else if ( key == CTRL('b') ) {
+ return special_handler( GLUT_KEY_LEFT, 0 );
+ }
+ else if ( key == CTRL('f') ) {
+ return special_handler( GLUT_KEY_RIGHT, 0 );
+ }
+ else if ( key == CTRL('p') ) {
+ return special_handler( GLUT_KEY_UP, 0 );
+ }
+ else if ( key == CTRL('n') ) {
+ return special_handler( GLUT_KEY_DOWN, 0 );
+ }
+ else if ( key == CTRL('u') ) { /* ERASE LINE */
+ insertion_pt = 0;
+ text.erase(0,text.length());
+ sel_start = sel_end = 0;
+ }
+ else if ( key == CTRL('k') ) { /* KILL TO END OF LINE */
+ sel_start = sel_end = insertion_pt;
+ text.erase(insertion_pt,GLUI_String::npos);
+ }
+ }
+ else if ( modifiers == GLUT_ACTIVE_ALT ) /* ALT ONLY */
+ {
+ if ( key == 'b' ) { // Backward word
+ return special_handler ( GLUT_KEY_LEFT, GLUT_ACTIVE_CTRL );
+ }
+ if ( key == 'f' ) { // Forward word
+ return special_handler ( GLUT_KEY_RIGHT, GLUT_ACTIVE_CTRL );
+ }
+ }
+ else if ( (modifiers & GLUT_ACTIVE_CTRL) OR
+ (modifiers & GLUT_ACTIVE_ALT) )
+ {
+ /** ignore other keys with modifiers */
+ return true;
+ }
+ else { /* Regular key */
+ regular_key = true;
+
+ /** Check if we only accept numbers **/
+ if (data_type == GLUI_EDITTEXT_FLOAT ) {
+ if ( (key < '0' OR key > '9') AND key != '.' AND key != '-' )
+ return true;
+
+ if ( key == '-' ) { /* User typed a '-' */
+
+ /* If user has first character selected, then '-' is allowed */
+ if ( NOT ( MIN(sel_start,sel_end) == 0 AND
+ MAX(sel_start,sel_end) > 0 ) ) {
+
+ /* User does not have 1st char selected */
+ if (insertion_pt != 0 OR text[0] == '-' ) {
+ return true; /* Can only place negative at beginning of text,
+ and only one of them */
+ }
+ }
+ }
+
+ if ( key == '.' ) {
+ /*printf( "PERIOD: %d\n", num_periods ); */
+
+ if ( num_periods > 0 ) {
+ /** We're trying to type a period, but the text already contains
+ a period. Check whether the period is contained within
+ is current selection (thus it will be safely replaced) **/
+
+ int period_found = false;
+ if ( sel_start != sel_end ) {
+ for( i=MIN(sel_end,sel_start); i<MAX(sel_start,sel_end); i++ ) {
+ /* printf( "%c ", text[i] ); */
+ if ( text[i] == '.' ) {
+ period_found = true;
+ break;
+ }
+ }
+ }
+
+ /* printf( "found: %d num: %d\n", period_found, num_periods ); */
+
+ if ( NOT period_found )
+ return true;
+ }
+ }
+ }
+ else if (data_type == GLUI_EDITTEXT_INT)
+ {
+ if ( (key < '0' OR key > '9') AND key != '-' )
+ return true;
+
+ if ( key == '-' ) { /* User typed a '-' */
+
+ /* If user has first character selected, then '-' is allowed */
+ if ( NOT ( MIN(sel_start,sel_end) == 0 AND
+ MAX(sel_start,sel_end) > 0 ) ) {
+
+ /* User does not have 1st char selected */
+ if (insertion_pt != 0 OR text[0] == '-' ) {
+ return true; /* Can only place negative at beginning of text,
+ and only one of them */
+ }
+ }
+ }
+ }
+
+ /** This is just to get rid of warnings - the flag regular_key is
+ set if the key was not a backspace, return, whatever. But I
+ believe if we're here, we know it was a regular key anyway */
+ if ( regular_key ) {
+ }
+
+ /**** If there's a current selection, erase it ******/
+ if ( sel_start != sel_end ) {
+ clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end ));
+ insertion_pt = MIN(sel_start,sel_end);
+ sel_start = sel_end = insertion_pt;
+ }
+
+ /******** We insert the character into the string ***/
+
+ text.insert(insertion_pt,1,key);
+
+ /******** Move the insertion point and substring_end one over ******/
+ insertion_pt++;
+ substring_end++;
+
+ sel_start = sel_end = insertion_pt;
+ }
+
+ /******** Now redraw text ***********/
+ /* Hack to prevent text box from being cleared first **/
+ /** int substring_change = update_substring_bounds();
+ draw_text_only =
+ (NOT substring_change AND NOT has_selection AND regular_key );
+ */
+
+ draw_text_only = false; /** Well, hack is not yet working **/
+ update_and_draw_text();
+ draw_text_only = false;
+
+
+ if ( debug )
+ dump( stdout, "<- KEY HANDLER" );
+
+ /*** Now look to see if this string has a period ***/
+ num_periods = 0;
+ for( i=0; i<(int)text.length(); i++ )
+ if ( text[i] == '.' )
+ num_periods++;
+
+ return true;
+}
+
+
+/****************************** GLUI_EditText::activate() **********/
+
+void GLUI_EditText::activate( int how )
+{
+ if ( debug )
+ dump( stdout, "-> ACTIVATE" );
+
+ active = true;
+
+ if ( how == GLUI_ACTIVATE_MOUSE )
+ return; /* Don't select everything if activated with mouse */
+
+ orig_text = text;
+
+ sel_start = 0;
+ sel_end = (int)text.length();
+ insertion_pt = 0;
+
+ if ( debug )
+ dump( stdout, "<- ACTIVATE" );
+}
+
+
+/****************************** GLUI_EditText::deactivate() **********/
+
+void GLUI_EditText::deactivate( void )
+{
+ int new_int_val;
+ float new_float_val;
+
+ active = false;
+
+ if ( NOT glui )
+ return;
+
+ if ( debug )
+ dump( stdout, "-> DISACTIVATE" );
+
+ sel_start = sel_end = insertion_pt = -1;
+
+ /***** Retrieve the current value from the text *****/
+ /***** The live variable will be updated by set_text() ****/
+ if ( data_type == GLUI_EDITTEXT_FLOAT ) {
+ if ( text.length() == 0 ) /* zero-length string - make it "0.0" */
+ text = "0.0";
+
+ new_float_val = atof( text.c_str() );
+
+ set_float_val( new_float_val );
+ }
+ else if ( data_type == GLUI_EDITTEXT_INT ) {
+ if ( text.length() == 0 ) /* zero-length string - make it "0" */
+ text = "0";
+
+ new_int_val = atoi( text.c_str() );
+
+ set_int_val( new_int_val );
+ }
+ else
+ if ( data_type == GLUI_EDITTEXT_TEXT ) {
+ set_text(text); /* This will force callbacks and gfx refresh */
+ }
+
+ update_substring_bounds();
+
+ /******** redraw text without insertion point ***********/
+ redraw();
+
+ /***** Now do callbacks if value changed ******/
+ if ( orig_text != text ) {
+ this->execute_callback();
+
+ if ( 0 ) {
+ /* THE CODE BELOW IS FROM WHEN SPINNER ALSO MAINTAINED CALLBACKS */
+ if ( spinner == NULL ) { /** Are we independent of a spinner? **/
+ if ( callback ) {
+ callback( this );
+ }
+ }
+ else { /* We're attached to a spinner */
+ spinner->do_callbacks(); /* Let the spinner do the callback stuff */
+ }
+ }
+ }
+
+ if ( debug )
+ dump( stdout, "<- DISACTIVATE" );
+}
+
+/****************************** GLUI_EditText::draw() **********/
+
+void GLUI_EditText::draw( int x, int y )
+{
+ GLUI_DRAWINGSENTINAL_IDIOM
+ int name_x;
+
+ name_x = MAX(text_x_offset - string_width(this->name) - 3,0);
+ draw_name( name_x , 13);
+
+ glBegin( GL_LINES );
+ glColor3f( .5, .5, .5 );
+ glVertex2i( text_x_offset, 0 ); glVertex2i( w, 0 );
+ glVertex2i( text_x_offset, 0 ); glVertex2i( text_x_offset, h );
+
+ glColor3f( 1., 1., 1. );
+ glVertex2i( text_x_offset, h ); glVertex2i( w, h );
+ glVertex2i( w, h ); glVertex2i( w, 0 );
+
+ if ( enabled )
+ glColor3f( 0., 0., 0. );
+ else
+ glColor3f( .25, .25, .25 );
+ glVertex2i( text_x_offset+1, 1 ); glVertex2i( w-1, 1 );
+ glVertex2i( text_x_offset+1, 1 ); glVertex2i( text_x_offset+1, h-1 );
+
+ glColor3f( .75, .75, .75 );
+ glVertex2i( text_x_offset+1, h-1 ); glVertex2i( w-1, h-1 );
+ glVertex2i( w-1, h-1 ); glVertex2i( w-1, 1 );
+ glEnd();
+
+ /** Find where to draw the text **/
+ update_substring_bounds();
+ draw_text(0,0);
+
+ draw_insertion_pt();
+}
+
+
+
+/************************** GLUI_EditText::update_substring_bounds() *********/
+
+int GLUI_EditText::update_substring_bounds( void )
+{
+ int box_width;
+ int text_len = (int)text.length();
+ int old_start, old_end;
+
+ old_start = substring_start;
+ old_end = substring_end;
+
+ /*** Calculate the width of the usable area of the edit box ***/
+ box_width = MAX( this->w - this->text_x_offset
+ - 4 /* 2 * the two-line box border */
+ - 2 * GLUI_EDITTEXT_BOXINNERMARGINX, 0 );
+
+ CLAMP( substring_end, 0, MAX(text_len-1,0) );
+ CLAMP( substring_start, 0, MAX(text_len-1,0) );
+
+ if ( debug ) dump( stdout, "-> UPDATE SS" );
+
+ if ( insertion_pt >= 0 AND
+ insertion_pt < substring_start ) { /* cursor moved left */
+ substring_start = insertion_pt;
+
+ while ( substring_width( substring_start, substring_end ) > box_width )
+ substring_end--;
+ }
+ else if ( insertion_pt > substring_end ) { /* cursor moved right */
+ substring_end = insertion_pt-1;
+
+ while ( substring_width( substring_start, substring_end ) > box_width )
+ substring_start++;
+ }
+ else { /* cursor is within old substring bounds */
+ if ( last_insertion_pt > insertion_pt ) { /* cursor moved left */
+ }
+ else {
+ while ( substring_width( substring_start, substring_end ) > box_width )
+ substring_end--;
+
+ while(substring_end < text_len-1
+ AND substring_width( substring_start, substring_end ) <= box_width)
+ substring_end++;
+ }
+ }
+
+ while ( substring_width( substring_start, substring_end ) > box_width )
+ substring_end--;
+
+ last_insertion_pt = insertion_pt;
+
+ /*** No selection if not enabled ***/
+ if ( NOT enabled ) {
+ sel_start = sel_end = 0;
+ }
+
+ if ( debug ) dump( stdout, "<- UPDATE SS" );
+
+ if ( substring_start == old_start AND substring_end == old_end )
+ return false; /*** bounds did not change ***/
+ else
+ return true; /*** bounds did change ***/
+}
+
+
+/********************************* GLUI_EditText::update_x_offsets() *********/
+
+void GLUI_EditText::update_x_offsets( void )
+{
+}
+
+
+/********************************* GLUI_EditText::draw_text() ****************/
+
+void GLUI_EditText::draw_text( int x, int y )
+{
+ GLUI_DRAWINGSENTINAL_IDIOM
+ int text_x, i, sel_lo, sel_hi;
+
+ if ( debug ) dump( stdout, "-> DRAW_TEXT" );
+
+ if ( NOT draw_text_only ) {
+ if ( enabled )
+ glColor3f( 1., 1., 1. );
+ else
+ set_to_bkgd_color();
+ glDisable( GL_CULL_FACE );
+ glBegin( GL_QUADS );
+ glVertex2i( text_x_offset+2, 2 ); glVertex2i( w-2, 2 );
+ glVertex2i( w-2, h-2 ); glVertex2i( text_x_offset+2, h-2 );
+ glEnd();
+ }
+
+ /** Find where to draw the text **/
+
+ text_x = text_x_offset + 2 + GLUI_EDITTEXT_BOXINNERMARGINX;
+
+ /*printf( "text_x: %d substr_width: %d start/end: %d/%d\n",
+ text_x, substring_width( substring_start, substring_end ),
+ substring_start, substring_end );
+ */
+ /** Find lower and upper selection bounds **/
+ sel_lo = MIN(sel_start, sel_end );
+ sel_hi = MAX(sel_start, sel_end );
+
+ int sel_x_start, sel_x_end, delta;
+
+ /** Draw selection area dark **/
+ if ( sel_start != sel_end ) {
+ sel_x_start = text_x;
+ sel_x_end = text_x;
+ for( i=substring_start; i<=substring_end; i++ ) {
+ delta = char_width( text[i] );
+
+ if ( i < sel_lo ) {
+ sel_x_start += delta;
+ sel_x_end += delta;
+ }
+ else if ( i < sel_hi ) {
+ sel_x_end += delta;
+ }
+ }
+
+ glColor3f( 0.0f, 0.0f, .6f );
+ glBegin( GL_QUADS );
+ glVertex2i( sel_x_start, 2 ); glVertex2i( sel_x_end, 2 );
+ glVertex2i( sel_x_end, h-2 ); glVertex2i( sel_x_start, h-2 );
+ glEnd();
+ }
+
+
+ if ( sel_start == sel_end ) { /* No current selection */
+ if ( enabled )
+ glColor3b( 0, 0, 0 );
+ else
+ glColor3b( 32, 32, 32 );
+
+ glRasterPos2i( text_x, 13);
+ for( i=substring_start; i<=substring_end; i++ ) {
+ glutBitmapCharacter( get_font(), this->text[i] );
+ }
+ }
+ else { /* There is a selection */
+ int x = text_x;
+ for( i=substring_start; i<=substring_end; i++ ) {
+ if ( IN_BOUNDS( i, sel_lo, sel_hi-1)) { /* This character is selected */
+ glColor3f( 1., 1., 1. );
+ glRasterPos2i( x, 13);
+ glutBitmapCharacter( get_font(), this->text[i] );
+ }
+ else {
+ glColor3f( 0., 0., 0. );
+ glRasterPos2i( x, 13);
+ glutBitmapCharacter( get_font(), this->text[i] );
+ }
+
+ x += char_width( text[i] );
+ }
+ }
+
+ if ( debug ) dump( stdout, "<- DRAW_TEXT" );
+}
+
+
+/******************************** GLUI_EditText::find_insertion_pt() *********/
+/* This function returns the character numer *before which* the insertion */
+/* point goes */
+
+int GLUI_EditText::find_insertion_pt( int x, int y )
+{
+ int curr_x, i;
+
+ /*** See if we clicked outside box ***/
+ if ( x < this->x_abs + text_x_offset )
+ return -1;
+
+ /* We move from right to left, looking to see if the mouse was clicked
+ to the right of the ith character */
+
+ curr_x = this->x_abs + text_x_offset
+ + substring_width( substring_start, substring_end )
+ + 2 /* The edittext box has a 2-pixel margin */
+ + GLUI_EDITTEXT_BOXINNERMARGINX; /** plus this many pixels blank space
+ between the text and the box **/
+
+ /*** See if we clicked in an empty box ***/
+ if ( (int) text.length() == 0 )
+ return 0;
+
+ /** find mouse click in text **/
+ for( i=substring_end; i>=substring_start; i-- ) {
+ curr_x -= char_width( text[i] );
+
+ if ( x > curr_x ) {
+ /* printf( "-> %d\n", i ); */
+
+ return i+1;
+ }
+ }
+
+ return 0;
+
+ /* Well, the mouse wasn't after any of the characters...see if it's
+ before the beginning of the substring */
+ if ( 0 ) {
+ if ( x > (x_abs + text_x_offset + 2 ) )
+ return substring_start;
+
+ return -1; /* Nothing found */
+ }
+}
+
+
+/******************************** GLUI_EditText::draw_insertion_pt() *********/
+
+void GLUI_EditText::draw_insertion_pt( void )
+{
+ int curr_x, i;
+
+ if ( NOT can_draw() )
+ return;
+
+ /*** Don't draw insertion pt if control is disabled ***/
+ if ( NOT enabled )
+ return;
+
+ if ( debug ) dump( stdout, "-> DRAW_INS_PT" );
+
+ if ( sel_start != sel_end OR insertion_pt < 0 ) {
+ return; /* Don't draw insertion point if there is a current selection */
+ }
+
+ /* printf( "insertion pt: %d\n", insertion_pt ); */
+
+ curr_x = this->x_abs + text_x_offset
+ + substring_width( substring_start, substring_end )
+ + 2 /* The edittext box has a 2-pixel margin */
+ + GLUI_EDITTEXT_BOXINNERMARGINX; /** plus this many pixels blank space
+ between the text and the box **/
+
+ for( i=substring_end; i>=insertion_pt; i-- ) {
+ curr_x -= char_width( text[i] );
+ }
+
+ glColor3f( 0.0, 0.0, 0.0 );
+ glBegin( GL_LINE_LOOP );
+ /***
+ glVertex2i( curr_x, y_abs + 4 );
+ glVertex2i( curr_x, y_abs + 4 );
+ glVertex2i( curr_x, y_abs + h - 3 );
+ glVertex2i( curr_x, y_abs + h - 3 );
+ ***/
+ curr_x -= x_abs;
+ glVertex2i( curr_x, 0 + 4 );
+ glVertex2i( curr_x, 0 + 4 );
+ glVertex2i( curr_x, 0 + h - 3 );
+ glVertex2i( curr_x, 0 + h - 3 );
+ glEnd();
+
+ if ( debug ) dump( stdout, "-> DRAW_INS_PT" );
+}
+
+
+
+/******************************** GLUI_EditText::substring_width() *********/
+
+int GLUI_EditText::substring_width( int start, int end )
+{
+ int i, width;
+
+ width = 0;
+
+ for( i=start; i<=end; i++ )
+ width += char_width( text[i] );
+
+ return width;
+}
+
+
+/***************************** GLUI_EditText::update_and_draw_text() ********/
+
+void GLUI_EditText::update_and_draw_text( void )
+{
+ if ( NOT can_draw() )
+ return;
+
+ update_substring_bounds();
+ /* printf( "ss: %d/%d\n", substring_start, substring_end ); */
+
+ redraw();
+}
+
+
+/********************************* GLUI_EditText::special_handler() **********/
+
+int GLUI_EditText::special_handler( int key,int modifiers )
+{
+ if ( NOT glui )
+ return false;
+
+ if ( debug )
+ printf( "SPECIAL:%d - mod:%d subs:%d/%d ins:%d sel:%d/%d\n",
+ key, modifiers, substring_start, substring_end,insertion_pt,
+ sel_start, sel_end );
+
+ if ( key == GLUT_KEY_LEFT ) {
+ if ( (modifiers & GLUT_ACTIVE_CTRL) != 0 ) {
+ insertion_pt = find_word_break( insertion_pt, -1 );
+ }
+ else {
+ insertion_pt--;
+ }
+ }
+ else if ( key == GLUT_KEY_RIGHT ) {
+ if ( (modifiers & GLUT_ACTIVE_CTRL) != 0 ) {
+ insertion_pt = find_word_break( insertion_pt, +1 );
+ }
+ else {
+ insertion_pt++;
+ }
+ }
+ else if ( key == GLUT_KEY_HOME ) {
+ insertion_pt = 0;
+ }
+ else if ( key == GLUT_KEY_END ) {
+ insertion_pt = (int) text.length();
+ }
+
+ /*** Update selection if shift key is down ***/
+ if ( (modifiers & GLUT_ACTIVE_SHIFT ) != 0 )
+ sel_end = insertion_pt;
+ else
+ sel_start = sel_end = insertion_pt;
+
+
+ CLAMP( insertion_pt, 0, (int) text.length()); /* Make sure insertion_pt
+ is in bounds */
+ CLAMP( sel_start, 0, (int) text.length()); /* Make sure insertion_pt
+ is in bounds */
+ CLAMP( sel_end, 0, (int) text.length()); /* Make sure insertion_pt
+ is in bounds */
+
+ /******** Now redraw text ***********/
+ if ( can_draw())
+ update_and_draw_text();
+
+ return true;
+}
+
+
+/****************************** GLUI_EditText::find_word_break() **********/
+/* It looks either left or right (depending on value of 'direction' */
+/* for the beginning of the next 'word', where word are characters */
+/* separated by one of the following tokens: " :-.," */
+/* If there is no next word in the specified direction, this returns */
+/* the beginning of 'text', or the very end. */
+
+int GLUI_EditText::find_word_break( int start, int direction )
+{
+ int i, j;
+ char *breaks = " :-.,";
+ int num_break_chars = (int)strlen(breaks), text_len = (int)text.length();
+ int new_pt;
+
+ /** If we're moving left, we have to start two back, in case we're either
+ already at the beginning of a word, or on a separating token.
+ Otherwise, this function would just return the word we're already at **/
+ if ( direction == -1 ) {
+ start -= 2;
+ }
+
+ /***** Iterate over text in the specified direction *****/
+ for ( i=start; i >= 0 AND i < text_len; i += direction ) {
+
+ /** For each character in text, iterate over list of separating tokens **/
+ for( j=0; j<num_break_chars; j++ ) {
+ if ( text[i] == breaks[j] ) {
+
+ /** character 'i' is a separating token, so we return i+1 **/
+ new_pt = i + 1;
+
+ CLAMP( new_pt, 0, text_len );
+
+ return new_pt;
+ }
+ }
+ }
+
+ if ( direction > 0 ) /* Return the end of string */
+ return text_len;
+ else /* Return the beginning of the text */
+ return 0;
+}
+
+
+/********************************** GLUI_EditText::clear_substring() ********/
+
+void GLUI_EditText::clear_substring( int start, int end )
+{
+ int i;
+
+ /*
+ printf( "clearing: %d-%d '", start,end);
+ for(i=start;i<end;i++ )
+ putchar(text[i]);
+ printf( "'\n" ); flushout;
+ */
+ /*** See if we're deleting a period in a float data-type box ***/
+ if ( data_type == GLUI_EDITTEXT_FLOAT ) {
+ for( i=start; i<end; i++ )
+ if ( text[i] == '.' )
+ num_periods = 0;
+ }
+
+ text.erase(start,end-start);
+}
+
+
+
+/************************************ GLUI_EditText::update_size() **********/
+
+void GLUI_EditText::update_size( void )
+{
+ int text_size, delta;
+
+ if ( NOT glui )
+ return;
+
+ text_size = string_width( name );
+
+ delta = 0;
+ if ( text_x_offset < text_size +2 )
+ delta = text_size+2-text_x_offset;
+
+ text_x_offset += delta;
+ /* w += delta; */
+
+ if ( data_type == GLUI_EDITTEXT_TEXT OR
+ data_type == GLUI_EDITTEXT_FLOAT) {
+ if ( w < text_x_offset + GLUI_EDITTEXT_MIN_TEXT_WIDTH )
+ w = text_x_offset + GLUI_EDITTEXT_MIN_TEXT_WIDTH;
+ }
+ else if ( data_type == GLUI_EDITTEXT_INT ) {
+ if ( w < text_x_offset + GLUI_EDITTEXT_MIN_INT_WIDTH )
+ w = text_x_offset + GLUI_EDITTEXT_MIN_INT_WIDTH;
+ }
+}
+
+
+/****************************** GLUI_EditText::set_text() **********/
+
+void GLUI_EditText::set_text( const char *new_text )
+{
+ text=new_text;
+ substring_start = 0;
+ substring_end = (int) text.length() - 1;
+ insertion_pt = -1;
+ sel_start = 0;
+ sel_end = 0;
+
+ if ( can_draw() )
+ update_and_draw_text();
+
+ /** Update the spinner, if we have one **/
+ if ( spinner ) {
+ spinner->float_val = this->float_val;
+ spinner->int_val = this->int_val;
+ }
+
+ /*** Now update the live variable ***/
+ output_live(true);
+}
+
+
+/******************************* GLUI_EditText::set_float_val() ************/
+
+void GLUI_EditText::set_float_val( float new_val )
+{
+ if ( has_limits == GLUI_LIMIT_CLAMP ) {
+ /*** Clamp the new value to the existing limits ***/
+
+ CLAMP( new_val, float_low, float_high );
+ }
+ else if ( has_limits == GLUI_LIMIT_WRAP ) {
+ /*** Clamp the value cyclically to the limits - that is, if the
+ value exceeds the max, set it the the minimum, and conversely ***/
+
+ if ( new_val < float_low )
+ new_val = float_high;
+ if ( new_val > float_high )
+ new_val = float_low;
+ }
+
+ float_val = new_val;
+ int_val = (int) new_val; /* Mirror the value as an int, too */
+
+ set_numeric_text();
+}
+
+
+/********************************** GLUI_EditText::set_int_val() ************/
+
+void GLUI_EditText::set_int_val( int new_val )
+{
+ if ( has_limits == GLUI_LIMIT_CLAMP ) {
+ /*** Clamp the new value to the existing limits ***/
+
+ CLAMP( new_val, int_low, int_high );
+ }
+ else if ( has_limits == GLUI_LIMIT_WRAP ) {
+ /*** Clamp the value cyclically to the limits - that is, if the
+ value exceeds the max, set it the the minimum, and conversely ***/
+
+ if ( new_val < int_low )
+ new_val = int_high;
+ if ( new_val > int_high )
+ new_val = int_low;
+ }
+
+ int_val = new_val;
+ float_val = (float) new_val; /* We mirror the value as a float, too */
+
+ set_numeric_text();
+}
+
+
+/********************************* GLUI_EditText::set_float_limits() *********/
+
+void GLUI_EditText::set_float_limits( float low, float high, int limit_type )
+{
+ has_limits = limit_type;
+ float_low = low;
+ float_high = high;
+
+ if ( NOT IN_BOUNDS( float_val, float_low, float_high ))
+ set_float_val( float_low );
+
+ int_low = (int) float_low;
+ int_high = (int) float_high;
+}
+
+
+/*********************************** GLUI_EditText::set_int_limits() *********/
+
+void GLUI_EditText::set_int_limits( int low, int high, int limit_type )
+{
+ has_limits = limit_type;
+ int_low = low;
+ int_high = high;
+
+ if ( NOT IN_BOUNDS( int_val, int_low, int_high ))
+ set_int_val( int_low );
+
+ float_low = (float) int_low;
+ float_high = (float) int_high;
+}
+
+
+/************************************ GLUI_EditText::set_numeric_text() ******/
+
+void GLUI_EditText::set_numeric_text( void )
+{
+ char buf_num[200];
+ int i, text_len;
+
+ if ( data_type == GLUI_EDITTEXT_FLOAT ) {
+ sprintf( buf_num, "%#g", float_val );
+
+ num_periods = 0;
+ text_len = (int) strlen(buf_num);
+ for ( i=0; i<text_len; i++ )
+ if ( buf_num[i] == '.' )
+ num_periods++;
+
+ /* Now remove trailing zeros */
+ if ( num_periods > 0 ) {
+ text_len = (int) strlen(buf_num);
+ for ( i=text_len-1; i>0; i-- ) {
+ if ( buf_num[i] == '0' AND buf_num[i-1] != '.' )
+ buf_num[i] = '\0';
+ else
+ break;
+ }
+ }
+ set_text( buf_num );
+ }
+ else {
+ sprintf( buf_num, "%d", int_val );
+ set_text( buf_num );
+ }
+
+}
+
+
+/*************************************** GLUI_EditText::dump() **************/
+
+void GLUI_EditText::dump( FILE *out, const char *name )
+{
+ fprintf( out,
+ "%s (edittext@%p): ins_pt:%d subs:%d/%d sel:%d/%d len:%d\n",
+ name, this,
+ insertion_pt,
+ substring_start,
+ substring_end,
+ sel_start,
+ sel_end,
+ (int) text.length());
+}
+
+
+/**************************************** GLUI_EditText::mouse_over() ********/
+
+int GLUI_EditText::mouse_over( int state, int x, int y )
+{
+ if ( state ) {
+ /* curr_cursor = GLUT_CURSOR_TEXT; */
+ glutSetCursor( GLUT_CURSOR_TEXT );
+ }
+ else {
+ /* printf( "OUT\n" ); */
+ glutSetCursor( GLUT_CURSOR_LEFT_ARROW );
+ }
+
+ return true;
+}
diff --git a/tests/box2d/glui/glui_filebrowser.cpp b/tests/box2d/glui/glui_filebrowser.cpp new file mode 100755 index 00000000..13171fbf --- /dev/null +++ b/tests/box2d/glui/glui_filebrowser.cpp @@ -0,0 +1,165 @@ +/****************************************************************************
+
+ GLUI User Interface Toolkit
+ ---------------------------
+
+ glui_filebrowser.cpp - GLUI_FileBrowser control class
+
+
+ --------------------------------------------------
+
+ Copyright (c) 1998 Paul Rademacher
+
+ This program is freely distributable without licensing fees and is
+ provided without guarantee or warrantee expressed or implied. This
+ program is -not- in the public domain.
+
+*****************************************************************************/
+
+#include "glui.h"
+#include "glui_internal.h"
+#include <sys/types.h>
+
+#ifdef __GNUC__
+#include <dirent.h>
+#include <unistd.h>
+#endif
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#include <sys/stat.h>
+
+GLUI_FileBrowser::GLUI_FileBrowser( GLUI_Node *parent,
+ const char *name,
+ int type,
+ int id,
+ GLUI_CB cb)
+{
+ common_init();
+
+ set_name( name );
+ user_id = id;
+ int_val = type;
+ callback = cb;
+
+ parent->add_control( this );
+ list = new GLUI_List(this, true, 1);
+ list->set_object_callback( GLUI_FileBrowser::dir_list_callback, this );
+ list->set_click_type(GLUI_DOUBLE_CLICK);
+ this->fbreaddir(this->current_dir.c_str());
+}
+
+/****************************** GLUI_FileBrowser::draw() **********/
+
+void GLUI_FileBrowser::dir_list_callback(GLUI_Control *glui_object) {
+ GLUI_List *list = dynamic_cast<GLUI_List*>(glui_object);
+ if (!list)
+ return;
+ GLUI_FileBrowser* me = dynamic_cast<GLUI_FileBrowser*>(list->associated_object);
+ if (!me)
+ return;
+ int this_item;
+ const char *selected;
+ this_item = list->get_current_item();
+ if (this_item > 0) { /* file or directory selected */
+ selected = list->get_item_ptr( this_item )->text.c_str();
+ if (selected[0] == '/' || selected[0] == '\\') {
+ if (me->allow_change_dir) {
+#ifdef __GNUC__
+ chdir(selected+1);
+#endif
+#ifdef _WIN32
+ SetCurrentDirectory(selected+1);
+#endif
+ me->fbreaddir(".");
+ }
+ } else {
+ me->file = selected;
+ me->execute_callback();
+ }
+ }
+}
+
+
+
+void GLUI_FileBrowser::fbreaddir(const char *d) {
+ GLUI_String item;
+ int i = 0;
+
+ if (!d)
+ return;
+
+#ifdef _WIN32
+
+ WIN32_FIND_DATA FN;
+ HANDLE hFind;
+ //char search_arg[MAX_PATH], new_file_path[MAX_PATH];
+ //sprintf(search_arg, "%s\\*.*", path_name);
+
+ hFind = FindFirstFile("*.*", &FN);
+ if (list) {
+ list->delete_all();
+ if (hFind != INVALID_HANDLE_VALUE) {
+ do {
+ int len = strlen(FN.cFileName);
+ if (FN.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ item = '\\';
+ item += FN.cFileName;
+ } else {
+ item = FN.cFileName;
+ }
+ list->add_item(i,item.c_str());
+ i++;
+ } while (FindNextFile(hFind, &FN) != 0);
+
+ if (GetLastError() == ERROR_NO_MORE_FILES)
+ FindClose(&FN);
+ else
+ perror("fbreaddir");
+ }
+ }
+
+#elif defined(__GNUC__)
+
+ DIR *dir;
+ struct dirent *dirp;
+ struct stat dr;
+
+ if (list) {
+ list->delete_all();
+ if ((dir = opendir(d)) == NULL)
+ perror("fbreaddir:");
+ else {
+ while ((dirp = readdir(dir)) != NULL) /* open directory */
+ {
+ if (!lstat(dirp->d_name,&dr) && S_ISDIR(dr.st_mode)) /* dir is directory */
+ item = dirp->d_name + GLUI_String("/");
+ else
+ item = dirp->d_name;
+
+ list->add_item(i,item.c_str());
+ i++;
+ }
+ closedir(dir);
+ }
+ }
+#endif
+}
+
+void ProcessFiles(const char *path_name)
+{
+
+}
+
+
+void GLUI_FileBrowser::set_w(int w)
+{
+ if (list) list->set_w(w);
+}
+
+void GLUI_FileBrowser::set_h(int h)
+{
+ if (list) list->set_h(h);
+}
diff --git a/tests/box2d/glui/glui_internal.h b/tests/box2d/glui/glui_internal.h new file mode 100755 index 00000000..20efc6f9 --- /dev/null +++ b/tests/box2d/glui/glui_internal.h @@ -0,0 +1,105 @@ +#ifndef GLUI_INTERNAL_H
+#define GLUI_INTERNAL_H
+
+#include <cstdio>
+#include <cmath>
+
+#ifndef AND
+#define AND &&
+#define OR ||
+#define NOT !
+#endif
+
+#ifndef MAX
+#define MAX(a,b) ((a)>(b) ? (a) : (b))
+#define MIN(a,b) ((a)<(b) ? (a) : (b))
+#endif
+
+#ifndef ABS
+#define ABS(a) ((a)>=0 ? (a) : (-(a)))
+#endif
+
+/******************** bit comparisons and operations ***************/
+#ifndef TEST_BIT
+#define TEST_BIT( x, b ) (((x) & (1<<(b))) != 0 )
+#define SET_BIT( x, b ) ((x) |= (1 << (b)))
+#define CLEAR_BIT( x, b ) ((x) &= ~(1 << (b)))
+#define TOGGLE_BIT( x, b ) ((TEST_BIT(x,b)) ?(CLEAR_BIT(x,b)):(SET_BIT(x,b)))
+#endif
+
+#ifndef TEST_AND
+#define TEST_AND( a, b ) ((a&b)==b)
+#endif
+
+
+#ifndef M_PI
+#define M_PI 3.141592654
+#endif
+
+/*********** flush the stdout and stderr output streams *************/
+#ifndef flushout
+#define flushout fflush(stdout)
+#define flusherr fflush(stderr)
+#endif
+
+/********** Debugging functions *************************************/
+#ifndef error_return
+#define error_return( c ); {fprintf(stderr,c);return;}
+#endif
+
+/************************* floating-point random ********************/
+#ifndef randf
+#define randf() ((float) rand() / (float)RAND_MAX )
+#endif
+
+#ifndef SIGN
+#define SIGN(x) ((x)>=0 ? 1 : -1)
+#endif
+
+/****************** conversion between degrees and radians **********/
+#ifndef DEG2RAD
+#define DEG2RAD(x) ((x)/180.0*M_PI)
+#define RAD2DEG(x) ((x)/M_PI*180.0)
+#endif
+
+/***************** clamp a value to some fixed interval *************/
+#ifndef CLAMP
+#define CLAMP(x,lo,hi) {if ((x) < (lo)) {(x)=(lo);} else if((x) > (hi)) {(x)=(hi);}}
+#endif
+
+/************ check if a value lies within a closed interval *********/
+#ifndef IN_BOUNDS
+#define IN_BOUNDS( x, lo, hi ) ( (x) >= (lo) AND (x) <= (hi) )
+#endif
+
+/************ check if a 2D point lies within a 2D box ***************/
+#ifndef PT_IN_BOX
+#define PT_IN_BOX( x, y, lo_x, hi_x, lo_y, hi_y ) \
+( IN_BOUNDS(x,lo_x,hi_x) AND IN_BOUNDS(y,lo_y,hi_y) )
+#endif
+
+/****** check if value lies on proper side of another value *****/
+/*** if side is positive => proper side is positive, else negative **/
+#ifndef CHECK_PROPER_SIDE
+#define CHECK_PROPER_SIDE(x,val,side) ((side) > 0 ? (x) > (val) : (x) < (val))
+#endif
+
+
+/***** Small value when we want to do a comparison to 'close to zero' *****/
+#ifndef FUDGE
+#define FUDGE .00001
+#endif
+
+
+/******************* swap two values, using a temp variable *********/
+#ifndef SWAP2
+#define SWAP2(a,b,t) {t=a;a=b;b=t;}
+#endif
+
+#define VEC3_TO_ARRAY(v,a) a[0]=v[0], a[1]=v[1], a[2]=v[2]
+
+/**** Return the ASCII control code given the non-control ASCII character */
+#define CTRL(c) ( (c>=('a'-1)) ? (c-'a'+1) : (c-'A'+1) )
+
+
+#endif /* GLUI_INTERNAL_H */
diff --git a/tests/box2d/glui/glui_internal_control.h b/tests/box2d/glui/glui_internal_control.h new file mode 100755 index 00000000..ef0db159 --- /dev/null +++ b/tests/box2d/glui/glui_internal_control.h @@ -0,0 +1,45 @@ +/*
+ Header file for use by GLUI controls.
+ Everything you need is right here.
+
+
+*/
+#ifndef __GLUI_INTERNAL_CONTROL_H
+#define __GLUI_INTERNAL_CONTROL_H
+
+/* This is the main GLUI external header */
+#include "glui.h"
+
+/* Here's some utility routines */
+#include "glui_internal.h"
+
+
+/**
+ A GLUI_Control-drawing sentinal object.
+ On creation, saves the current draw buffer and window.
+ On destruction, restores draw buffer and window.
+ This is way nicer than calling save/restore manually.
+*/
+class GLUI_DrawingSentinal {
+ int orig_buf, orig_win;
+ GLUI_Control *c;
+public:
+ /** The constructor sets up the drawing system */
+ GLUI_DrawingSentinal(GLUI_Control *c_);
+ /** The destructor cleans up drawing back how it was */
+ ~GLUI_DrawingSentinal();
+
+ // Do-nothing routine to avoid compiler warning about unused variable
+ inline void avoid_warning(void) {}
+};
+/** Just drop a GLUI_DRAWINGSENTINAL_IDIOM at the start of your draw methods,
+and they'll return if we can't be drawn, and
+automatically save and restore all needed state.
+*/
+#define GLUI_DRAWINGSENTINAL_IDIOM if (NOT can_draw()) return; GLUI_DrawingSentinal drawSentinal(this); drawSentinal.avoid_warning();
+
+
+/** Return the time, in seconds. */
+inline double GLUI_Time(void) {return 0.001*glutGet(GLUT_ELAPSED_TIME);}
+
+#endif
diff --git a/tests/box2d/glui/glui_list.cpp b/tests/box2d/glui/glui_list.cpp new file mode 100755 index 00000000..a5b09393 --- /dev/null +++ b/tests/box2d/glui/glui_list.cpp @@ -0,0 +1,540 @@ +/****************************************************************************
+
+ GLUI User Interface Toolkit
+ ---------------------------
+
+ glui_list.cpp - GLUI_List control class
+
+
+ --------------------------------------------------
+
+ Copyright (c) 2004 John Kew
+
+ This program is freely distributable without licensing fees and is
+ provided without guarantee or warrantee expressed or implied. This
+ program is -not- in the public domain.
+
+*****************************************************************************/
+
+#include "glui_internal_control.h"
+#include <cmath>
+#include <sys/timeb.h>
+
+/****************************** GLUI_List::GLUI_List() **********/
+
+GLUI_List::GLUI_List( GLUI_Node *parent, bool scroll,
+ int id, GLUI_CB callback
+ /*,GLUI_Control *object
+ GLUI_InterObject_CB obj_cb*/)
+{
+ common_construct(parent, NULL, scroll, id, callback/*, object, obj_cb*/);
+}
+
+/****************************** GLUI_List::GLUI_List() **********/
+
+GLUI_List::GLUI_List( GLUI_Node *parent,
+ GLUI_String& live_var, bool scroll,
+ int id,
+ GLUI_CB callback
+ /* ,GLUI_Control *object
+ ,GLUI_InterObject_CB obj_cb*/ )
+{
+ common_construct(parent, &live_var, scroll, id, callback/*, object, obj_cb*/);
+}
+
+/****************************** GLUI_List::common_construct() **********/
+
+void GLUI_List::common_construct(
+ GLUI_Node *parent,
+ GLUI_String* data, bool scroll,
+ int id,
+ GLUI_CB callback
+ /*,GLUI_Control *object
+ , GLUI_InterObject_CB obj_cb*/)
+{
+ common_init();
+ GLUI_Node *list_panel = parent;
+
+ if (scroll) {
+ GLUI_Panel *p = new GLUI_Panel(parent,"",GLUI_PANEL_NONE);
+ p->x_off = 1;
+ list_panel = p;
+ }
+ this->ptr_val = data;
+ if (data) {
+ this->live_type = GLUI_LIVE_STRING;
+ }
+ this->user_id = id;
+ this->callback = callback;
+ this->name = "list";
+ list_panel->add_control( this );
+ if (scroll)
+ {
+ new GLUI_Column(list_panel, false);
+ scrollbar =
+ new GLUI_Scrollbar(list_panel,
+ "scrollbar",
+ GLUI_SCROLL_VERTICAL,
+ GLUI_SCROLL_INT);
+ scrollbar->set_object_callback(GLUI_List::scrollbar_callback, this);
+ scrollbar->set_alignment(GLUI_ALIGN_LEFT);
+ // scrollbar->can_activate = false; //kills ability to mouse drag too
+ }
+ init_live();
+}
+
+/****************************** GLUI_List::mouse_down_handler() **********/
+int GLUI_List::mouse_down_handler( int local_x, int local_y )
+{
+ int tmp_line;
+ unsigned long int ms;
+ timeb time;
+ ftime(&time);
+ ms = time.millitm + (time.time)*1000;
+
+ tmp_line = find_line( local_x-x_abs, local_y-y_abs-5 );
+ if ( tmp_line == -1 ) {
+ if ( glui )
+ glui->deactivate_current_control( );
+ return false;
+ }
+
+ if (tmp_line < num_lines) {
+ curr_line = tmp_line;
+ if (scrollbar)
+ scrollbar->set_int_val(curr_line);
+ this->execute_callback();
+ if (associated_object != NULL)
+ if (cb_click_type == GLUI_SINGLE_CLICK) {
+ if (obj_cb) {
+ // obj_cb(associated_object, user_id);
+ obj_cb(this);
+ }
+ } else {
+ if (last_line == curr_line && (ms - last_click_time) < 300) {
+ //obj_cb(associated_object, user_id);
+ obj_cb(this);
+ } else {
+ last_click_time = ms;
+ last_line = curr_line;
+ }
+ }
+ if ( can_draw())
+ update_and_draw_text();
+ }
+
+ return true;
+}
+
+
+
+
+/******************************** GLUI_List::mouse_up_handler() **********/
+
+int GLUI_List::mouse_up_handler( int local_x, int local_y, bool inside )
+{
+ return false;
+}
+
+
+/***************************** GLUI_List::mouse_held_down_handler() ******/
+
+int GLUI_List::mouse_held_down_handler( int local_x, int local_y,
+ bool new_inside)
+{
+ return false;
+}
+
+
+/****************************** GLUI_List::key_handler() **********/
+
+int GLUI_List::key_handler( unsigned char key,int modifiers )
+{
+
+
+ draw_text_only = false; /** Well, hack is not yet working **/
+ update_and_draw_text();
+ draw_text_only = false;
+
+ return true;
+}
+
+
+/****************************** GLUI_List::activate() **********/
+
+void GLUI_List::activate( int how )
+{
+// if ( debug )
+// dump( stdout, "-> ACTIVATE" );
+ active = true;
+
+ if ( how == GLUI_ACTIVATE_MOUSE )
+ return; /* Don't select everything if activated with mouse */
+
+}
+
+
+/****************************** GLUI_List::deactivate() **********/
+
+void GLUI_List::deactivate( void )
+{
+ active = false;
+ redraw();
+}
+
+/****************************** GLUI_List::draw() **********/
+
+void GLUI_List::draw( int x, int y )
+{
+ int line = 0;
+ int box_width;
+ GLUI_List_Item *item;
+
+ GLUI_DRAWINGSENTINAL_IDIOM
+
+ /* Bevelled Border */
+ glBegin( GL_LINES );
+ glColor3f( .5, .5, .5 );
+ glVertex2i( 0, 0 ); glVertex2i( w, 0 );
+ glVertex2i( 0, 0 ); glVertex2i( 0, h );
+
+ glColor3f( 1., 1., 1. );
+ glVertex2i( 0, h ); glVertex2i( w, h );
+ glVertex2i( w, h ); glVertex2i( w, 0 );
+
+ if ( enabled )
+ glColor3f( 0., 0., 0. );
+ else
+ glColor3f( .25, .25, .25 );
+ glVertex2i( 1, 1 ); glVertex2i( w-1, 1 );
+ glVertex2i( 1, 1 ); glVertex2i( 1, h-1 );
+
+ glColor3f( .75, .75, .75 );
+ glVertex2i( 1, h-1 ); glVertex2i( w-1, h-1 );
+ glVertex2i( w-1, h-1 ); glVertex2i( w-1, 1 );
+ glEnd();
+
+ /* Draw Background if enabled*/
+ if (enabled) {
+ glColor3f( 1., 1., 1. );
+ glDisable( GL_CULL_FACE );
+ glBegin( GL_QUADS );
+ glVertex2i( 2, 2 ); glVertex2i( w-2, 2 );
+ glVertex2i( w-2, h-2 ); glVertex2i(2, h-2 );
+ glEnd();
+ } else {
+ glColor3f( .8, .8, .8 );
+ glDisable( GL_CULL_FACE );
+ glBegin( GL_QUADS );
+ glVertex2i( 2, 2 ); glVertex2i( w-2, 2 );
+ glVertex2i( w-2, h-2 ); glVertex2i(2, h-2 );
+ glEnd();
+ }
+
+ /* Figure out how wide the box is */
+ box_width = get_box_width();
+
+ /* Figure out which lines are visible*/
+
+ visible_lines = (int)(h-20)/15;
+
+ item = (GLUI_List_Item *) items_list.first_child();
+
+ line = 0;
+ while (item) {
+ if (line < start_line) {
+ line++;
+ item = (GLUI_List_Item *) item->next();
+ continue;
+ }
+ if (line >= start_line && line <= (start_line+visible_lines)) {
+ if (curr_line == line)
+ draw_text(item->text.c_str(),1,0,(line - start_line)*15);
+ else
+ draw_text(item->text.c_str(),0,0,(line - start_line)*15);
+ }
+ line++;
+ item = (GLUI_List_Item *) item->next();
+ }
+
+ if (scrollbar) {
+ scrollbar->set_int_limits(MAX(0,num_lines-visible_lines), 0);
+ glPushMatrix();
+ glTranslatef(scrollbar->x_abs-x_abs, scrollbar->y_abs-y_abs,0.0);
+ scrollbar->draw_scroll();
+ glPopMatrix();
+ }
+}
+
+/********************************* GLUI_List::draw_text() ****************/
+
+void GLUI_List::draw_text(const char *t, int selected, int x, int y )
+{
+ int text_x, i, x_pos;
+ int box_width;
+
+ GLUI_DRAWINGSENTINAL_IDIOM
+
+ /** Find where to draw the text **/
+
+ text_x = 2 + GLUI_LIST_BOXINNERMARGINX;
+
+ /** Draw selection area dark **/
+ if ( enabled && selected ) {
+ glColor3f( 0.0f, 0.0f, .6f );
+ glBegin( GL_QUADS );
+ glVertex2i(text_x, y+5 ); glVertex2i( w-text_x, y+5 );
+ glVertex2i(w-text_x, y+19 ); glVertex2i(text_x, y+19 );
+ glEnd();
+ }
+ box_width = get_box_width();
+
+ if ( !selected || !enabled ) { /* No current selection */
+ x_pos = text_x; /* or control disabled */
+ if ( enabled )
+ glColor3b( 0, 0, 0 );
+ else
+ glColor3b( 32, 32, 32 );
+
+ glRasterPos2i( text_x, y+15);
+ i = 0;
+ while( t[i] != '\0' && substring_width(t,0,i) < box_width) {
+ glutBitmapCharacter( get_font(), t[i] );
+ x_pos += char_width( t[i] );
+ i++;
+ }
+ }
+ else { /* There is a selection */
+ i = 0;
+ x_pos = text_x;
+ glColor3f( 1., 1., 1. );
+ glRasterPos2i( text_x, y+15);
+ while( t[i] != '\0' && substring_width(t,0,i) < box_width) {
+ glutBitmapCharacter( get_font(), t[i] );
+ x_pos += char_width( t[i] );
+ i++;
+ }
+ }
+}
+
+
+int GLUI_List::find_line(int x, int y) {
+ return start_line + ((int)(y/15));
+}
+
+int GLUI_List::get_box_width() {
+ return MAX( this->w
+ - 6 /* 2 * the two-line box border */
+ - 2 * GLUI_LIST_BOXINNERMARGINX, 0 );
+
+}
+
+/******************************** GLUI_List::substring_width() *********/
+int GLUI_List::substring_width( const char *t, int start, int end )
+{
+ int i, width;
+
+ width = 0;
+
+ for( i=start; i<=end; i++ )
+ width += char_width( t[i] );
+
+ return width;
+}
+
+
+/***************************** GLUI_List::update_and_draw_text() ********/
+
+void GLUI_List::update_and_draw_text( void )
+{
+ if ( NOT can_draw() )
+ return;
+
+ //update_substring_bounds();
+ /* printf( "ss: %d/%d\n", substring_start, substring_end ); */
+
+ redraw();
+}
+
+
+/********************************* GLUI_List::special_handler() **********/
+
+int GLUI_List::special_handler( int key,int modifiers )
+{
+ if ( NOT glui )
+ return false;
+
+ if ( key == GLUT_KEY_DOWN ) {
+ if (curr_line < num_lines) {
+ curr_line++;
+ if (curr_line > start_line+visible_lines)
+ start_line++;
+ }
+ } else if ( key == GLUT_KEY_UP ) {
+ if (curr_line > 0) {
+ curr_line--;
+ if (curr_line < start_line)
+ start_line--;
+ }
+ }
+
+ if (scrollbar)
+ scrollbar->set_int_val(curr_line);
+ redraw();
+ return true;
+}
+
+
+/************************************ GLUI_List::update_size() **********/
+
+void GLUI_List::update_size( void )
+{
+ if ( NOT glui )
+ return;
+
+ if ( w < GLUI_LIST_MIN_TEXT_WIDTH )
+ w = GLUI_LIST_MIN_TEXT_WIDTH;
+}
+
+/**************************************** GLUI_Listbox::add_item() **********/
+
+int GLUI_List::add_item( int id, const char *new_text )
+{
+ GLUI_List_Item *new_node = new GLUI_List_Item;
+ GLUI_List_Item *head;
+
+ new_node->text = new_text;
+ new_node->id = id;
+
+ head = (GLUI_List_Item*) items_list.first_child();
+ new_node->link_this_to_parent_last( &items_list );
+
+ if ( head == NULL ) {
+ /*** This is first item added ***/
+
+ int_val = id+1; /** Different than id **/
+ // do_selection( id );
+ last_live_int = id;
+
+ if( glui )
+ glui->post_update_main_gfx();
+ }
+ num_lines++;
+ if (scrollbar)
+ scrollbar->set_int_limits(MAX(num_lines-visible_lines,0), 0);
+
+ return true;
+}
+
+/************************************** GLUI_Listbox::delete_() **********/
+
+int GLUI_List::delete_all()
+{
+ GLUI_List_Item *item;
+
+ item = (GLUI_List_Item *) items_list.first_child();
+ while( item ) {
+ item->unlink();
+ delete item;
+ item = (GLUI_List_Item *) items_list.first_child();
+ }
+
+ num_lines = 0;
+ curr_line = 0;
+
+ return true;
+}
+
+
+/************************************** GLUI_Listbox::delete_item() **********/
+
+int GLUI_List::delete_item( const char *text )
+{
+ GLUI_List_Item *node = get_item_ptr( text );
+
+ if ( node ) {
+ node->unlink();
+ delete node;
+ num_lines--;
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+
+/************************************** GLUI_Listbox::delete_item() **********/
+
+int GLUI_List::delete_item( int id )
+{
+ GLUI_List_Item *node = get_item_ptr( id );
+
+ if ( node ) {
+ node->unlink();
+ delete node;
+ num_lines--;
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+
+/************************************ GLUI_Listbox::get_item_ptr() **********/
+
+GLUI_List_Item *GLUI_List::get_item_ptr( const char *text )
+{
+ GLUI_List_Item *item;
+
+ item = (GLUI_List_Item *) items_list.first_child();
+ while( item ) {
+ if ( item->text == text )
+ return item;
+
+ item = (GLUI_List_Item *) item->next();
+ }
+
+ return NULL;
+}
+
+
+/************************************ GLUI_Listbox::get_item_ptr() **********/
+
+GLUI_List_Item *GLUI_List::get_item_ptr( int id )
+{
+ GLUI_List_Item *item;
+
+ item = (GLUI_List_Item *) items_list.first_child();
+ while( item ) {
+ if ( item->id == id )
+ return item;
+
+ item = (GLUI_List_Item *) item->next();
+ }
+
+ return NULL;
+}
+
+/**************************************** GLUI_List::mouse_over() ********/
+
+int GLUI_List::mouse_over( int state, int x, int y )
+{
+ glutSetCursor( GLUT_CURSOR_LEFT_ARROW );
+
+ return true;
+}
+
+void GLUI_List::scrollbar_callback(GLUI_Control *my_scrollbar) {
+ GLUI_Scrollbar *sb = dynamic_cast<GLUI_Scrollbar*>(my_scrollbar);
+ if (!sb) return;
+ GLUI_List* me = (GLUI_List*) sb->associated_object;
+ if (me->scrollbar == NULL)
+ return;
+ int new_start_line = sb->get_int_val(); // TODO!!
+ me->start_line = new_start_line;
+
+ if ( me->can_draw() )
+ me->update_and_draw_text();
+}
diff --git a/tests/box2d/glui/glui_listbox.cpp b/tests/box2d/glui/glui_listbox.cpp new file mode 100755 index 00000000..3eda3107 --- /dev/null +++ b/tests/box2d/glui/glui_listbox.cpp @@ -0,0 +1,448 @@ +/****************************************************************************
+
+ GLUI User Interface Toolkit
+ ---------------------------
+
+ glui_listbox - GLUI_ListBox control class
+
+
+ --------------------------------------------------
+
+ Copyright (c) 1998 Paul Rademacher
+
+ WWW: http://sourceforge.net/projects/glui/
+ Forums: http://sourceforge.net/forum/?group_id=92496
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+#include "glui_internal_control.h"
+
+/****************************** GLUI_Listbox::GLUI_Listbox() **********/
+GLUI_Listbox::GLUI_Listbox( GLUI_Node *parent,
+ const char *name, int *value_ptr,
+ int id,
+ GLUI_CB cb)
+{
+ common_init();
+ set_ptr_val( value_ptr );
+ user_id = id;
+ set_name( name );
+ callback = cb;
+
+ parent->add_control( this );
+
+ init_live();
+}
+
+
+/****************************** GLUI_Listbox::mouse_down_handler() **********/
+
+int GLUI_Listbox::mouse_down_handler( int local_x, int local_y )
+{
+ return false;
+}
+
+
+/****************************** GLUI_Listbox::mouse_up_handler() **********/
+
+int GLUI_Listbox::mouse_up_handler( int local_x, int local_y, bool inside )
+{
+
+ return false;
+}
+
+
+/****************************** GLUI_Listbox::mouse_held_down_handler() ******/
+
+int GLUI_Listbox::mouse_held_down_handler( int local_x, int local_y,
+ bool inside)
+{
+
+ return false;
+}
+
+
+/****************************** GLUI_Listbox::key_handler() **********/
+
+int GLUI_Listbox::key_handler( unsigned char key,int modifiers )
+{
+ return false;
+}
+
+
+/****************************** GLUI_Listbox::draw() **********/
+
+void GLUI_Listbox::draw( int x, int y )
+{
+ GLUI_DRAWINGSENTINAL_IDIOM
+ int name_x;
+
+ /* draw_active_area(); */
+
+ name_x = MAX(text_x_offset - string_width(this->name) - 3,0);
+ draw_name( name_x , 13);
+ draw_box_inwards_outline( text_x_offset, w,
+ 0, h );
+
+ if ( NOT active ) {
+ draw_box( text_x_offset+3, w-2, 2, h-2, 1.0, 1.0, 1.0 );
+ if ( NOT enabled )
+ glColor3b( 32, 32, 32 );
+ else
+ glColor3f( 0.0, 0.0, 0.0 );
+ glRasterPos2i( text_x_offset+5, 13 );
+ draw_string( curr_text );
+ }
+ else {
+ draw_box( text_x_offset+3, w-2, 2, h-2, .0, .0, .6 );
+ glColor3f( 1.0, 1.0, 1.0 );
+ glRasterPos2i( text_x_offset+5, 13 );
+ draw_string( curr_text );
+ }
+
+
+ if ( enabled ) {
+ glui->std_bitmaps.
+ draw(GLUI_STDBITMAP_LISTBOX_UP,
+ w-glui->std_bitmaps.width(GLUI_STDBITMAP_LISTBOX_UP)-1,
+ 2 );
+ }
+ else {
+ glui->std_bitmaps.
+ draw(GLUI_STDBITMAP_LISTBOX_UP_DIS,
+ w-glui->std_bitmaps.width(GLUI_STDBITMAP_LISTBOX_UP)-1,
+ 2 );
+ }
+}
+
+
+/************************************ GLUI_Listbox::update_si() **********/
+void GLUI_Listbox::update_size( void )
+{
+ recalculate_item_width();
+}
+
+/********************************* GLUI_Listbox::set_int_val() **************/
+
+void GLUI_Listbox::set_int_val( int new_val )
+{
+ /* int_val = new_val; */
+
+ do_selection( new_val );
+
+ /*** Update the variable we're (possibly) pointing to, and update the main gfx ***/
+ output_live(true);
+}
+
+/**************************************** GLUI_Listbox::add_item() **********/
+
+int GLUI_Listbox::add_item( int id, const char *new_text )
+{
+ GLUI_Listbox_Item *new_node = new GLUI_Listbox_Item;
+ GLUI_Listbox_Item *head;
+
+ new_node->text = new_text;
+ new_node->id = id;
+
+ head = (GLUI_Listbox_Item*) items_list.first_child();
+ new_node->link_this_to_parent_last( &items_list );
+
+ if ( head == NULL ) {
+ /*** This is first item added ***/
+
+ int_val = id+1; /** Different than id **/
+ do_selection( id );
+ last_live_int = id;
+
+ if( glui )
+ glui->post_update_main_gfx();
+ }
+ if (recalculate_item_width()) glui->refresh();
+
+ return true;
+}
+
+
+/************************************** GLUI_Listbox::delete_item() **********/
+
+int GLUI_Listbox::delete_item( const char *text )
+{
+ GLUI_Listbox_Item *node = get_item_ptr(text);
+
+ if (node)
+ {
+ node->unlink();
+ delete node;
+ return true;
+ }
+ if (recalculate_item_width()) glui->refresh();
+
+ return false;
+}
+
+
+/************************************** GLUI_Listbox::delete_item() **********/
+
+int GLUI_Listbox::delete_item(int id)
+{
+ GLUI_Listbox_Item *node = get_item_ptr(id);
+
+ if (node)
+ {
+ node->unlink();
+ delete node;
+ return true;
+ }
+ if (recalculate_item_width()) glui->refresh();
+
+ return false;
+}
+
+
+/************************************** GLUI_Listbox::sort_items() **********/
+
+int GLUI_Listbox::sort_items( void )
+{
+ return false;
+}
+
+
+/********************************************* GLUI_Listbox::dump() **********/
+
+void GLUI_Listbox::dump( FILE *output )
+{
+ GLUI_Listbox_Item *item;
+
+ /* printf( "%p\n", (char*) name ); */
+
+ fprintf( output, "Listbox: %s\n", name.c_str() );
+
+ item = (GLUI_Listbox_Item *) items_list.first_child();
+ while( item ) {
+ fprintf( output, " %3d : %s\n", item->id, item->text.c_str() );
+
+ item = (GLUI_Listbox_Item *) item->next();
+ }
+}
+
+
+/************************************ GLUI_Listbox::get_item_ptr() **********/
+
+GLUI_Listbox_Item *GLUI_Listbox::get_item_ptr( const char *text )
+{
+ GLUI_Listbox_Item *item;
+
+ item = (GLUI_Listbox_Item *) items_list.first_child();
+ while( item ) {
+ if ( item->text == text )
+ return item;
+
+ item = (GLUI_Listbox_Item *) item->next();
+ }
+
+ return NULL;
+}
+
+
+/************************************ GLUI_Listbox::get_item_ptr() **********/
+
+GLUI_Listbox_Item *GLUI_Listbox::get_item_ptr( int id )
+{
+ GLUI_Listbox_Item *item;
+
+ item = (GLUI_Listbox_Item *) items_list.first_child();
+ while( item ) {
+ if ( item->id == id )
+ return item;
+
+ item = (GLUI_Listbox_Item *) item->next();
+ }
+
+ return NULL;
+}
+
+
+/************************************ GLUI_Listbox::mouse_over() **********/
+
+static void listbox_callback( int i )
+{
+ int old_val;
+
+ if ( NOT GLUI_Master.curr_left_button_glut_menu OR
+ !dynamic_cast<GLUI_Listbox*>(GLUI_Master.curr_left_button_glut_menu) )
+ return;
+
+ old_val = ((GLUI_Listbox*)GLUI_Master.curr_left_button_glut_menu)->int_val;
+ ((GLUI_Listbox*)GLUI_Master.curr_left_button_glut_menu)->set_int_val(i);
+
+ /**** If value changed, execute callback ****/
+ if ( old_val !=
+ ((GLUI_Listbox*)GLUI_Master.curr_left_button_glut_menu)->int_val ) {
+ ((GLUI_Listbox*)GLUI_Master.curr_left_button_glut_menu)->execute_callback();
+ }
+}
+
+
+/*************************************** GLUI_Listbox::mouse_over() **********/
+
+int GLUI_Listbox::mouse_over( int state, int x, int y )
+{
+ GLUI_Listbox_Item *item;
+
+ /* printf( "x/y: %d/%d\n", x, y ); */
+
+ if ( state AND enabled AND x > x_abs + text_x_offset) {
+ /**** Build a GLUT menu for this listbox ***/
+
+ /* printf( "%d %d\n", x, y ); */
+
+ glut_menu_id = glutCreateMenu(listbox_callback);
+
+ item = (GLUI_Listbox_Item *) items_list.first_child();
+ while( item ) {
+ glutAddMenuEntry( item->text.c_str(), item->id );
+ item = (GLUI_Listbox_Item *) item->next();
+ }
+
+ glutAttachMenu( GLUT_LEFT_BUTTON);
+
+ GLUI_Master.set_left_button_glut_menu_control( this );
+ }
+ else if ( glut_menu_id != -1 ) {
+ /* printf( "OUT\n" ); */
+ glutDetachMenu( GLUT_LEFT_BUTTON );
+ glutDestroyMenu( glut_menu_id );
+ glut_menu_id = -1;
+ }
+
+ return true;
+}
+
+
+/************************************ GLUI_Listbox::do_selection() **********/
+
+int GLUI_Listbox::do_selection( int item_num )
+{
+ GLUI_Listbox_Item *item, *sel_item;
+
+ /*** Is this item already selected? ***/
+ if ( item_num == int_val )
+ return false;
+
+ sel_item = NULL;
+ item = (GLUI_Listbox_Item *) items_list.first_child();
+ while( item ) {
+ if ( item->id == item_num ) {
+ sel_item = item;
+ break;
+ }
+
+ item = (GLUI_Listbox_Item *) item->next();
+ }
+
+ if ( NOT sel_item )
+ return false;
+
+ /* printf( "-> %s\n", (char*) sel_item->text ); */
+
+ int_val = item_num;
+ curr_text = sel_item->text;
+ redraw();
+
+ return true;
+}
+
+
+/*********************************** GLUI_Listbox::~GLUI_Listbox() **********/
+
+GLUI_Listbox::~GLUI_Listbox()
+{
+ GLUI_Listbox_Item *item = (GLUI_Listbox_Item *) items_list.first_child();
+
+ while (item)
+ {
+ GLUI_Listbox_Item *tmp = item;
+ item = (GLUI_Listbox_Item *) item->next();
+ delete tmp;
+ }
+}
+
+/****************************** GLUI_Listbox::special_handler() **********/
+
+int GLUI_Listbox::special_handler( int key,int modifiers )
+{
+ GLUI_Listbox_Item *node, *new_node;
+
+ node = get_item_ptr( int_val );
+ new_node = NULL;
+
+ if ( key == GLUT_KEY_DOWN ) {
+ new_node = (GLUI_Listbox_Item*) node->next();
+ }
+ else if ( key == GLUT_KEY_UP ) {
+ new_node = (GLUI_Listbox_Item*) node->prev();
+ }
+ else if ( key == GLUT_KEY_HOME ) {
+ new_node = (GLUI_Listbox_Item*) items_list.first_child();
+ }
+ else if ( key == GLUT_KEY_END ) {
+ new_node = (GLUI_Listbox_Item*) items_list.last_child();
+ }
+
+ if ( new_node != NULL AND new_node != node ) {
+ node = new_node;
+ set_int_val( node->id );
+ execute_callback();
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+
+/************************* GLUI_Listbox::recalculate_item_width( void ) ***********/
+/** Change w and return true if we need to be widened to fit the current items. */
+bool GLUI_Listbox::recalculate_item_width( void )
+{
+ int item_text_size;
+
+ if ( NOT glui )
+ return false;
+
+ /* Find the title size */
+ text_x_offset = string_width( name );
+
+ /* Find the longest item string ***/
+ item_text_size = 0;
+
+ GLUI_Listbox_Item *item = (GLUI_Listbox_Item *) items_list.first_child();
+ while( item ) {
+ item_text_size = MAX(item_text_size,string_width(item->text));
+ item = (GLUI_Listbox_Item *) item->next();
+ }
+
+ /* Sum up our layout: name, item, and drop-down marker */
+ int new_wid=text_x_offset+MAX(GLUI_EDITTEXT_MIN_TEXT_WIDTH,item_text_size)+20;
+ if ( w != new_wid) {
+ w = new_wid;
+ return true; /* we gotta be shortened or widened */
+ }
+ else {
+ return false; /* our current width is OK */
+ }
+}
diff --git a/tests/box2d/glui/glui_mouse_iaction.cpp b/tests/box2d/glui/glui_mouse_iaction.cpp new file mode 100755 index 00000000..bc9f0610 --- /dev/null +++ b/tests/box2d/glui/glui_mouse_iaction.cpp @@ -0,0 +1,210 @@ +/****************************************************************************
+
+ GLUI User Interface Toolkit
+ ---------------------------
+
+ glui_mouse_iaction - GLUI Mouse Interaction control class
+
+
+ --------------------------------------------------
+
+ Copyright (c) 1998 Paul Rademacher
+
+ WWW: http://sourceforge.net/projects/glui/
+ Forums: http://sourceforge.net/forum/?group_id=92496
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+#include "glui_internal_control.h"
+
+/********************** GLUI_Mouse_Interaction::mouse_down_handler() ******/
+
+int GLUI_Mouse_Interaction::mouse_down_handler( int local_x, int local_y )
+{
+ /* int win_h = glutGet( GLUT_WINDOW_HEIGHT ); */
+
+ /* iaction_mouse_down_handler( local_x, local_y ); */
+ iaction_mouse_down_handler( local_x-x_abs, local_y-y_abs );
+ /*local_x-x_abs, ((glui->h-local_y)-y_abs) ); */
+ redraw();
+
+ return false;
+}
+
+
+/**************************** GLUI_Mouse_Interaction::mouse_up_handler() */
+
+int GLUI_Mouse_Interaction::mouse_up_handler( int local_x, int local_y, bool inside )
+{
+ iaction_mouse_up_handler( local_x-x_abs, local_y-y_abs, inside );
+ return false;
+}
+
+
+/****************************** GLUI_Mouse_Interaction::mouse_held_down_handler() ******/
+
+int GLUI_Mouse_Interaction::mouse_held_down_handler( int local_x, int local_y,
+ bool inside)
+{
+ iaction_mouse_held_down_handler( local_x-x_abs, local_y-y_abs , inside );
+
+ redraw();
+
+ /** Tell the main graphics window to update iteself **/
+ if( glui )
+ glui->post_update_main_gfx();
+
+ execute_callback();
+
+ return false;
+}
+
+
+
+/****************************** GLUI_Mouse_Interaction::draw() **********/
+
+void GLUI_Mouse_Interaction::draw( int x, int y )
+{
+ GLUI_DRAWINGSENTINAL_IDIOM
+ int text_width = string_width( this->name );
+ int x_left = this->w/2 - text_width/2;
+
+ if ( NOT draw_active_area_only ) {
+ draw_name( x_left, h-4 );
+ draw_active_box( x_left-4, x_left+string_width( name )+4,
+ h, h-14 );
+ }
+
+ draw_active_area();
+}
+
+
+/************************************ GLUI_Mouse_Interaction::update_size() **********/
+
+void GLUI_Mouse_Interaction::update_size( void )
+{
+ if ( NOT glui )
+ return;
+
+ int text_width = string_width( this->name );
+
+ if ( w < text_width+6 )
+ w = text_width+6;
+
+ if ( h - 18 > w )
+ w = h - 18;
+
+ iaction_init();
+}
+
+
+/****************************** GLUI_Mouse_Interaction::special_handler() **********/
+
+int GLUI_Mouse_Interaction::special_handler( int key,int modifiers )
+{
+ int center_x, center_y;
+ int drag_x, drag_y;
+
+ center_x = w/2;
+ center_y = (h-18)/2;
+ drag_x = 0;
+ drag_y = 0;
+
+ if ( key == GLUT_KEY_LEFT )
+ drag_x = -6;
+ else if ( key == GLUT_KEY_RIGHT )
+ drag_x = 6;
+ else if ( key == GLUT_KEY_UP )
+ drag_y = -6;
+ else if ( key == GLUT_KEY_DOWN )
+ drag_y = 6;
+
+ if ( drag_x != 0 OR drag_y != 0 ) {
+ mouse_down_handler( center_x, center_y );
+ mouse_held_down_handler( center_x + drag_x, center_y + drag_y,true );
+ mouse_up_handler( center_x + drag_x, center_y + drag_y, true );
+ }
+
+ return false;
+}
+
+
+/****************************** GLUI_Mouse_Interaction::draw_active_area() **********/
+
+void GLUI_Mouse_Interaction::draw_active_area( void )
+{
+ int win_h = glutGet( GLUT_WINDOW_HEIGHT ), win_w = glutGet(GLUT_WINDOW_WIDTH);
+
+ int text_height = 18; /* what a kludge */
+
+ int viewport_size = h-text_height; /*MIN(w,h); */
+
+ glMatrixMode( GL_MODELVIEW );
+ glPushMatrix();
+ glLoadIdentity();
+ glTranslatef( (float) win_w/2.0, (float) win_h/2.0, 0.0 );
+ glRotatef( 180.0, 0.0, 1.0, 0.0 );
+ glRotatef( 180.0, 0.0, 0.0, 1.0 );
+ glTranslatef( (float) -win_w/2.0, (float) -win_h/2.0, 0.0 );
+
+ glTranslatef( (float) this->x_abs + .5, (float) this->y_abs + .5, 0.0 );
+
+ glTranslatef( (float)this->w/2.0, (float)viewport_size/2.0 + 2.0 , 0.0 );
+
+ /*** Draw the interaction control's orthographic elements ***/
+ iaction_draw_active_area_ortho();
+
+ /*** Setup and draw the interaction control's perspective elements ***/
+
+ /*** Set the viewport to just the square of the drawing area ***/
+ /* glViewport( this->x_abs , glui->main_panel->h - this->y_abs - this->h,*/
+ /*glViewport( this->x_abs+1+(this->w/2-viewport_size/2),
+ this->h-this->y_abs-viewport_size-1,
+ viewport_size, viewport_size );*/
+
+ viewport_size -= 4;
+ int offset = 0;
+ if ( ((this->w-viewport_size) % 2) == 1 )
+ offset = 1;
+
+ glViewport( this->x_abs + (this->w-viewport_size)/2 + offset,
+ win_h - this->y_abs - this->h + text_height,
+ viewport_size, viewport_size );
+
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ double xy=1.00,zc=50.0; /* X-Y size, and Z origin */
+ glFrustum( -1.0*xy, 1.0*xy, -xy, xy, zc*0.7, zc*1.3 );
+ glMatrixMode( GL_MODELVIEW );
+ glPushMatrix();
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -zc );
+ glScalef(xy,xy,1.0); // xy);
+
+ /* glutSolidTeapot( 1.0 ); */
+ iaction_draw_active_area_persp();
+
+ glMatrixMode( GL_MODELVIEW );
+ glPopMatrix();
+
+ glui->set_viewport();
+ glui->set_ortho_projection();
+
+ glMatrixMode( GL_MODELVIEW );
+ glPopMatrix();
+}
+
diff --git a/tests/box2d/glui/glui_node.cpp b/tests/box2d/glui/glui_node.cpp new file mode 100755 index 00000000..96aa1dd9 --- /dev/null +++ b/tests/box2d/glui/glui_node.cpp @@ -0,0 +1,212 @@ +/****************************************************************************
+
+ GLUI User Interface Toolkit
+ ---------------------------
+
+ glui_node.cpp - linked-list tree structure
+
+
+ --------------------------------------------------
+
+ Copyright (c) 1998 Paul Rademacher
+
+ WWW: http://sourceforge.net/projects/glui/
+ Forums: http://sourceforge.net/forum/?group_id=92496
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+#include "glui.h"
+#include "glui_internal.h"
+
+/********************************************* GLUI_Node::GLUI_Node() *******/
+
+GLUI_Node::GLUI_Node()
+:
+ parent_node(NULL),
+ child_head(NULL),
+ child_tail(NULL),
+ next_sibling(NULL),
+ prev_sibling(NULL)
+{
+}
+
+/********************************************* GLUI_Node::first() *******/
+/* Returns first sibling in 'this' node's sibling list */
+
+GLUI_Node *GLUI_Node::first_sibling( void )
+{
+ if ( parent_node == NULL )
+ return this; /* root node has no siblings */
+ else
+ return parent_node->child_head;
+}
+
+
+/******************************************** GLUI_Node::next() ********/
+/* Returns next sibling in 'this' node's sibling list */
+
+GLUI_Node *GLUI_Node::next( void )
+{
+ return next_sibling;
+}
+
+
+/******************************************** GLUI_Node::prev() ********/
+/* Returns prev sibling in 'this' node's sibling list */
+
+GLUI_Node *GLUI_Node::prev( void )
+{
+ return prev_sibling;
+}
+
+
+/********************************************* GLUI_Node::last() *******/
+/* Returns last sibling in 'this' node's sibling list */
+
+GLUI_Node *GLUI_Node::last_sibling( void )
+{
+ if ( parent_node == NULL )
+ return this; /* root node has no siblings */
+ else
+ return parent_node->child_tail;
+}
+
+
+/*************************** GLUI_Node::link_this_to_parent_last() *******/
+/* Links as last child of parent */
+
+void GLUI_Node::link_this_to_parent_last( GLUI_Node *new_parent )
+{
+ if ( new_parent->child_tail == NULL ) { /* parent has no children */
+ new_parent->child_head = this;
+ new_parent->child_tail = this;
+ this->parent_node = new_parent;
+ }
+ else { /* parent has children */
+ new_parent->child_tail->next_sibling = this;
+ this->prev_sibling = new_parent->child_tail;
+ new_parent->child_tail = this;
+ this->parent_node = new_parent;
+ }
+}
+
+
+/*************************** GLUI_Node::link_this_to_parent_first() *******/
+/* Links as first child of parent */
+
+void GLUI_Node::link_this_to_parent_first( GLUI_Node *new_parent )
+{
+ if ( new_parent->child_head == NULL ) { /* parent has no children */
+ new_parent->child_head = this;
+ new_parent->child_tail = this;
+ this->parent_node = new_parent;
+ }
+ else { /* parent has children */
+ new_parent->child_head->prev_sibling = this;
+ this->next_sibling = new_parent->child_head;
+ new_parent->child_head = this;
+ this->parent_node = new_parent;
+ }
+}
+
+/**************************** GLUI_Node::link_this_to_sibling_next() *****/
+
+void GLUI_Node::link_this_to_sibling_next( GLUI_Node *sibling )
+{
+ if ( sibling->next_sibling == NULL ) { /* node has no next sibling */
+ sibling->next_sibling = this;
+ this->prev_sibling = sibling;
+
+ /* This was the parent's last child, so update that as well */
+ if ( sibling->parent_node != NULL ) {
+ sibling->parent_node->child_tail = this;
+ }
+ }
+ else { /* node already has a next sibling */
+ sibling->next_sibling->prev_sibling = this;
+ this->next_sibling = sibling->next_sibling;
+ sibling->next_sibling = this;
+ this->prev_sibling = sibling;
+ }
+
+ this->parent_node = sibling->parent_node;
+}
+
+
+/**************************** GLUI_Node::link_this_to_sibling_prev() *****/
+
+void GLUI_Node::link_this_to_sibling_prev( GLUI_Node *sibling )
+{
+ if ( sibling->prev_sibling == NULL ) { /* node has no prev sibling */
+ sibling->prev_sibling = this;
+ this->next_sibling = sibling;
+
+ /* This was the parent's first child, so update that as well */
+ if ( sibling->parent_node != NULL ) {
+ sibling->parent_node->child_head = this;
+ }
+ }
+ else { /* node already has a prev sibling */
+ sibling->prev_sibling->next_sibling = this;
+ this->prev_sibling = sibling->prev_sibling;
+ sibling->prev_sibling = this;
+ this->next_sibling = sibling;
+ }
+
+ this->parent_node = sibling->parent_node;
+}
+
+/**************************************** GLUI_Node::unlink() **************/
+
+void GLUI_Node::unlink( void )
+{
+ /* Unlink from prev sibling */
+ if ( this->prev_sibling != NULL ) {
+ this->prev_sibling->next_sibling = this->next_sibling;
+ }
+ else { /* No prev sibling: this was parent's first child */
+ this->parent_node->child_head = this->next_sibling;
+ }
+
+ /* Unlink from next sibling */
+ if ( this->next_sibling != NULL ) {
+ this->next_sibling->prev_sibling = this->prev_sibling;
+ }
+ else { /* No next sibling: this was parent's last child */
+ this->parent_node->child_tail = this->prev_sibling;
+ }
+
+ this->parent_node = NULL;
+ this->next_sibling = NULL;
+ this->prev_sibling = NULL;
+ this->child_head = NULL;
+ this->child_tail = NULL;
+}
+
+/**************************************** GLUI_Node::dump() **************/
+
+void GLUI_Node::dump( FILE *out, const char *name )
+{
+ fprintf( out, "GLUI_node: %s\n", name );
+ fprintf( out, " parent: %p child_head: %p child_tail: %p\n",
+ (void *) parent_node,
+ (void *) child_head,
+ (void *) child_tail );
+ fprintf( out, " next: %p prev: %p\n",
+ (void *) next_sibling,
+ (void *) prev_sibling );
+}
diff --git a/tests/box2d/glui/glui_panel.cpp b/tests/box2d/glui/glui_panel.cpp new file mode 100755 index 00000000..687b7797 --- /dev/null +++ b/tests/box2d/glui/glui_panel.cpp @@ -0,0 +1,186 @@ +/****************************************************************************
+
+ GLUI User Interface Toolkit
+ ---------------------------
+
+ glui_panel.cpp - GLUI_Panel control class
+
+
+ --------------------------------------------------
+
+ Copyright (c) 1998 Paul Rademacher
+
+ WWW: http://sourceforge.net/projects/glui/
+ Forums: http://sourceforge.net/forum/?group_id=92496
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+#include "glui_internal_control.h"
+
+GLUI_Panel::GLUI_Panel( GLUI_Node *parent, const char *name, int type )
+{
+ common_init();
+ set_name( name );
+ user_id = -1;
+ int_val = type;
+
+ parent->add_control( this );
+}
+
+/****************************** GLUI_Panel::draw() **********/
+
+void GLUI_Panel::draw( int x, int y )
+{
+ int top;
+ GLUI_DRAWINGSENTINAL_IDIOM
+
+ if ( int_val == GLUI_PANEL_RAISED ) {
+ top = 0;
+ glLineWidth( 1.0 );
+ glColor3f( 1.0, 1.0, 1.0 );
+ glBegin( GL_LINE_LOOP );
+ glVertex2i( 0, top ); glVertex2i( w, top );
+ glVertex2i( 0, top ); glVertex2i( 0, h );
+ glEnd();
+
+ glColor3f( .5, .5, .5 );
+ glBegin( GL_LINE_LOOP );
+ glVertex2i( w, top );
+ glVertex2i( w, h );
+ glVertex2i( 0, h );
+ glVertex2i( w, h );
+ glEnd();
+
+ /** ORIGINAL RAISED PANEL METHOD - A LITTLE TOO HIGH **
+ glLineWidth(1.0);
+ glBegin( GL_LINES );
+ glColor3f( 1.0, 1.0, 1.0 );
+ glVertex2i( 1, 1 ); glVertex2i( w-2, 1 );
+ glVertex2i( 1, 1 ); glVertex2i( 1, h-2 );
+
+ glColor3f( .5, .5, .5 );
+ glVertex2i( w-1, 1 ); glVertex2i( w-1, h-1 );
+ glVertex2i( 1, h-1 ); glVertex2i( w-1, h-1 );
+
+ glColor3f( 0.0, 0.0, 0.0 );
+ glVertex2i( 0, h ); glVertex2i( w, h );
+ glVertex2i( w, 0 ); glVertex2i( w, h );
+ glEnd();
+
+ -- Touch up the lines a bit (needed in some opengl implementations
+ glBegin( GL_POINTS );
+ glColor3f( .5, .5, .5 );
+ glVertex2i( w-1, h-1 );
+ glColor3f( 0.0, 0.0, 0.0 );
+ glVertex2i( w, h );
+ glEnd();
+ **/
+ }
+ else if ( int_val == GLUI_PANEL_EMBOSSED ) {
+ if ( parent_node == NULL || name == "" ) {
+ top = 0;
+ }
+ else {
+ top = GLUI_PANEL_EMBOSS_TOP;
+ }
+
+ glLineWidth( 1.0 );
+ glColor3f( 1.0, 1.0, 1.0 );
+ glBegin( GL_LINE_LOOP );
+ glVertex2i( 0, top ); glVertex2i( w, top );
+ glVertex2i( w, h ); glVertex2i( 0, h );
+
+ glVertex2i( 1, top+1 ); glVertex2i( w-1, top+1 );
+ glVertex2i( w-1, h-1 ); glVertex2i( 1, h-1 );
+ glEnd();
+
+ glColor3f( .5, .5, .5 );
+ glBegin( GL_LINE_LOOP );
+ glVertex2i( 0, top );
+ glVertex2i( w-1, top );
+ glVertex2i( w-1, h-1 );
+ glVertex2i( 0, h-1 );
+ glEnd();
+
+ /**** Only display text in embossed panel ****/
+ if ( parent_node != NULL && name != "" ) { /* Only draw non-null strings */
+ int left = 7, height=GLUI_PANEL_NAME_DROP+1;
+ int str_width;
+
+ str_width = string_width(name);
+
+ if ( glui )
+ glColor3ub(glui->bkgd_color.r,glui->bkgd_color.g,glui->bkgd_color.b);
+ glDisable( GL_CULL_FACE );
+ glBegin( GL_QUADS );
+ glVertex2i( left-3, 0 ); glVertex2i( left+str_width+3, 0 );
+ glVertex2i( left+str_width+3, height ); glVertex2i( left-3, height );
+ glEnd();
+
+ draw_name( left, GLUI_PANEL_NAME_DROP );
+ }
+ }
+
+ glLineWidth( 1.0 );
+}
+
+/****************************** GLUI_Panel::set_name() **********/
+
+void GLUI_Panel::set_name( const char *new_name )
+{
+ name = new_name ? new_name : "";
+
+ update_size();
+
+ if ( glui )
+ glui->refresh();
+}
+
+
+/****************************** GLUI_Panel::set_type() **********/
+
+void GLUI_Panel::set_type( int new_type )
+{
+ if ( new_type != int_val ) {
+ int_val = new_type;
+ update_size();
+ redraw();
+ }
+}
+
+
+/************************************** GLUI_Panel::update_size() **********/
+
+void GLUI_Panel::update_size( void )
+{
+ int text_size;
+
+ if ( NOT glui )
+ return;
+
+ text_size = string_width(name);
+
+ if ( w < text_size + 16 )
+ w = text_size + 16 ;
+
+ if ( name != "" AND int_val == GLUI_PANEL_EMBOSSED ) {
+ this->y_off_top = GLUI_YOFF + 8;
+ }
+ else {
+ this->y_off_top = GLUI_YOFF;
+ }
+}
diff --git a/tests/box2d/glui/glui_radio.cpp b/tests/box2d/glui/glui_radio.cpp new file mode 100755 index 00000000..157d18e8 --- /dev/null +++ b/tests/box2d/glui/glui_radio.cpp @@ -0,0 +1,362 @@ +/****************************************************************************
+
+ GLUI User Interface Toolkit
+ ---------------------------
+
+ glui_radio.cpp - GLUI_RadioGroup and GLUI_RadioButton control classes
+
+
+ --------------------------------------------------
+
+ Copyright (c) 1998 Paul Rademacher
+
+ WWW: http://sourceforge.net/projects/glui/
+ Forums: http://sourceforge.net/forum/?group_id=92496
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+#include "glui_internal_control.h"
+#include <cassert>
+
+/****************************** GLUI_RadioGroup::GLUI_RadioGroup() **********/
+
+GLUI_RadioGroup::GLUI_RadioGroup(GLUI_Node *parent,
+ int *value_ptr,
+ int id, GLUI_CB cb)
+{
+ common_init();
+ GLUI_String buf;
+
+ set_ptr_val( value_ptr );
+ if ( value_ptr ) {
+ int_val = *value_ptr; /** Can't call set_int_val(), b/c that
+ function will try to call the
+ callback, etc */
+ /** Actually, maybe not **/
+ last_live_int = *value_ptr;
+ }
+
+ user_id = id;
+ glui_format_str( buf, "RadioGroup: %p", this );
+ set_name( buf.c_str() );
+ callback = cb;
+
+ parent->add_control( this );
+
+ init_live();
+}
+
+
+/****************************** GLUI_RadioGroup::draw() **********/
+
+void GLUI_RadioGroup::draw( int x, int y )
+{
+ if ( NOT can_draw() )
+ return;
+
+ draw_group(false);
+}
+
+
+/********************* GLUI_RadioGroup::draw_group(int translate) **********/
+
+void GLUI_RadioGroup::draw_group( int translate )
+{
+ GLUI_DRAWINGSENTINAL_IDIOM
+ GLUI_RadioButton *button;
+ this->int_val = int_val;
+
+ glMatrixMode(GL_MODELVIEW );
+
+ button = (GLUI_RadioButton*) first_child();
+ while( button != NULL ) {
+ glPushMatrix();
+ if (translate) {
+ button->translate_to_origin();
+ }
+ else {
+ glTranslatef(button->x_abs-x_abs,
+ button->y_abs-y_abs,0.0);
+ }
+
+ if ( button->int_val )
+ button->draw_checked();
+ else
+ button->draw_unchecked();
+
+ glPopMatrix();
+
+ button = (GLUI_RadioButton*) button->next();
+ }
+}
+
+
+/****************************** GLUI_RadioGroup::set_name() **********/
+
+void GLUI_RadioGroup::set_name( const char *text )
+{
+ name = text;
+
+ if ( glui )
+ glui->refresh();
+}
+
+
+/********************************* GLUI_RadioGroup::set_selected() **********/
+
+void GLUI_RadioGroup::set_selected( int int_val )
+{
+ GLUI_RadioButton *button;
+
+ this->int_val = int_val;
+
+ button = (GLUI_RadioButton*) first_child();
+ while( button != NULL ) {
+ if ( int_val == -1 ) { /*** All buttons in group are deselected ***/
+ button->set_int_val(0);
+ }
+ else if ( int_val == button->user_id ) { /*** This is selected button ***/
+ button->set_int_val(1);
+ }
+ else { /*** This is NOT selected button ***/
+ button->set_int_val(0);
+
+ }
+ button = (GLUI_RadioButton*) button->next();
+ }
+ redraw();
+}
+
+
+/************************ GLUI_RadioButton::GLUI_RadioButton() **********/
+
+GLUI_RadioButton::GLUI_RadioButton( GLUI_RadioGroup *grp, const char *name )
+{
+ common_init();
+
+ set_int_val( 0 );
+
+ /** A radio button's user id is always its ordinal number (zero-indexed)
+ within the group */
+ user_id = grp->num_buttons;
+ set_name( name );
+ group = grp;
+
+ group->num_buttons++; /* Increments radiogroup's button count */
+ group->add_control( this );
+
+ /*** Now update button states ***/
+ group->set_int_val( group->int_val ); /* This tells the group to
+ reset itself to its
+ current value, thereby
+ updating all its buttons */
+}
+
+
+/************************ GLUI_RadioButton::mouse_down_handler() **********/
+
+int GLUI_RadioButton::mouse_down_handler( int local_x, int local_y )
+{
+ if ( NOT group )
+ return false;
+
+ orig_value = group->int_val;
+
+ currently_inside = true;
+
+ group->set_selected( this->user_id );
+ redraw();
+
+ return false;
+}
+
+/********************** GLUI_RadioButton::mouse_held_down_handler() ******/
+
+int GLUI_RadioButton::mouse_held_down_handler( int local_x, int local_y,
+ bool inside)
+{
+ if (inside != currently_inside) {
+ if (inside) group->set_selected( this->user_id );
+ else group->set_selected( orig_value );
+ currently_inside = inside;
+ redraw();
+ }
+
+ return false;
+}
+
+
+/*************************** GLUI_RadioButton::mouse_up_handler() **********/
+
+int GLUI_RadioButton::mouse_up_handler( int local_x, int local_y,
+ bool inside )
+{
+ if ( NOT group )
+ return false;
+
+ if ( NOT inside ) {
+ group->set_selected( orig_value );
+ redraw();
+ }
+ else {
+ /** Now we update the radio button group. We tell the group
+ handler to set the currently-selected item to this button, which
+ is reference by its user_id/ordinal number within group **/
+
+ group->set_selected( this->user_id );
+ redraw();
+
+ /*** Now update the linked variable, and call the callback,
+ but ONLY if the value of the radio group actually changed ***/
+ if ( group->int_val != orig_value ) {
+ group->output_live(true); /** Output live and update gfx ***/
+
+ group->execute_callback();
+ }
+ }
+
+ return false;
+}
+
+/****************************** GLUI_RadioButton::draw() **********/
+
+void GLUI_RadioButton::draw( int x, int y )
+{
+ GLUI_DRAWINGSENTINAL_IDIOM
+
+ if ( NOT group OR NOT can_draw() )
+ return;
+
+ /*** See if we're the currently-selected button. If so, draw ***/
+ if ( group->int_val == this->user_id ) {
+ if ( enabled )
+ glui->std_bitmaps.draw( GLUI_STDBITMAP_RADIOBUTTON_ON, 0, 0 );
+ else
+ glui->std_bitmaps.draw( GLUI_STDBITMAP_RADIOBUTTON_ON_DIS, 0, 0 );
+ }
+ else {
+ if ( enabled )
+ glui->std_bitmaps.draw( GLUI_STDBITMAP_RADIOBUTTON_OFF, 0, 0 );
+ else
+ glui->std_bitmaps.draw( GLUI_STDBITMAP_RADIOBUTTON_OFF_DIS, 0, 0 );
+ }
+
+ draw_active_area();
+
+ draw_name( text_x_offset, 10 );
+}
+
+
+/************************************ GLUI_RadioButton::draw_checked() ******/
+
+void GLUI_RadioButton::draw_checked( void )
+{
+ GLUI_DRAWINGSENTINAL_IDIOM
+ if ( enabled )
+ glui->std_bitmaps.draw( GLUI_STDBITMAP_RADIOBUTTON_ON, 0, 0 );
+ else
+ glui->std_bitmaps.draw( GLUI_STDBITMAP_RADIOBUTTON_ON_DIS, 0, 0 );
+ draw_active_area();
+}
+
+
+/*********************************** GLUI_RadioButton::draw_unchecked() ******/
+
+void GLUI_RadioButton::draw_unchecked( void )
+{
+ GLUI_DRAWINGSENTINAL_IDIOM
+
+ if ( enabled )
+ glui->std_bitmaps.draw( GLUI_STDBITMAP_RADIOBUTTON_OFF, 0, 0 );
+ else
+ glui->std_bitmaps.draw( GLUI_STDBITMAP_RADIOBUTTON_OFF_DIS, 0, 0 );
+ draw_active_area();
+}
+
+
+/**************************************** GLUI_RadioButton::draw_O() ********/
+
+void GLUI_RadioButton::draw_O( void )
+{
+ GLUI_DRAWINGSENTINAL_IDIOM
+ int i, j;
+
+ glBegin( GL_POINTS );
+ for(i=3; i<=GLUI_RADIOBUTTON_SIZE-3; i++ )
+ for(j=3; j<=GLUI_RADIOBUTTON_SIZE-3; j++ )
+ glVertex2i(i,j);
+ glEnd();
+}
+
+
+/******************************** GLUI_RadioButton::update_size() **********/
+
+void GLUI_RadioButton::update_size( void )
+{
+ int text_size;
+
+ if ( NOT glui )
+ return;
+
+ text_size = _glutBitmapWidthString( glui->font, name.c_str() );
+
+ /* if ( w < text_x_offset + text_size + 6 ) */
+ w = text_x_offset + text_size + 6 ;
+}
+
+
+/************************* GLUI_RadioButton::draw_active_area() **************/
+
+void GLUI_RadioButton::draw_active_area( void )
+{
+ GLUI_DRAWINGSENTINAL_IDIOM
+ int text_width, left, right;
+
+ text_width = _glutBitmapWidthString( glui->font, name.c_str() );
+ left = text_x_offset-3;
+ right = left + 7 + text_width;
+
+ if ( active ) {
+ glEnable( GL_LINE_STIPPLE );
+ glLineStipple( 1, 0x5555 );
+ glColor3f( 0., 0., 0. );
+ } else {
+ glColor3ub( glui->bkgd_color.r, glui->bkgd_color.g, glui->bkgd_color.b );
+ }
+
+ glBegin( GL_LINE_LOOP );
+ glVertex2i(left,0); glVertex2i( right,0);
+ glVertex2i(right,h+1); glVertex2i( left,h+1);
+ glEnd();
+
+ glDisable( GL_LINE_STIPPLE );
+}
+
+
+/********************************* GLUI_RadioGroup::set_int_val() **********/
+
+void GLUI_RadioGroup::set_int_val( int new_val )
+{
+ if ( new_val == int_val )
+ return;
+
+ set_selected( new_val );
+ redraw();
+
+ output_live(true);
+
+}
diff --git a/tests/box2d/glui/glui_rollout.cpp b/tests/box2d/glui/glui_rollout.cpp new file mode 100755 index 00000000..f0aa7fc4 --- /dev/null +++ b/tests/box2d/glui/glui_rollout.cpp @@ -0,0 +1,275 @@ +/****************************************************************************
+
+ GLUI User Interface Toolkit
+ ---------------------------
+
+ glui_panel.cpp - GLUI_Panel control class
+
+
+ --------------------------------------------------
+
+ Copyright (c) 1998 Paul Rademacher
+
+ WWW: http://sourceforge.net/projects/glui/
+ Forums: http://sourceforge.net/forum/?group_id=92496
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+#include "glui_internal_control.h"
+
+enum {rollout_height_pixels=GLUI_DEFAULT_CONTROL_HEIGHT + 7};
+
+/****************************** GLUI_Rollout::GLUI_Rollout() **********/
+
+GLUI_Rollout::GLUI_Rollout( GLUI_Node *parent, const char *name,
+ int open, int type )
+{
+ common_init();
+ set_name( name );
+ user_id = -1;
+ int_val = type;
+
+ if ( NOT open ) {
+ is_open = false;
+ h = rollout_height_pixels;
+ }
+
+ parent->add_control( this );
+}
+
+/****************************** GLUI_Rollout::open() **********/
+
+void GLUI_Rollout::open( void )
+{
+ if ( NOT glui )
+ return;
+
+ if ( is_open )
+ return;
+ is_open = true;
+
+ GLUI_DRAWINGSENTINAL_IDIOM
+
+ /* Copy hidden children into our private list "collapsed_node" */
+ child_head = collapsed_node.child_head;
+ child_tail = collapsed_node.child_tail;
+ collapsed_node.child_head = NULL;
+ collapsed_node.child_tail = NULL;
+
+ if ( child_head != NULL ) {
+ ((GLUI_Control*) child_head)->unhide_internal( true );
+ }
+
+ glui->refresh();
+}
+
+
+/****************************** GLUI_Rollout::close() **********/
+
+void GLUI_Rollout::close( void )
+{
+ if ( NOT glui )
+ return;
+
+ if ( NOT is_open )
+ return;
+ is_open = false;
+
+ GLUI_DRAWINGSENTINAL_IDIOM
+
+ if ( child_head != NULL ) {
+ ((GLUI_Control*) child_head)->hide_internal( true );
+ }
+
+ /* Move all children into a private list of hidden children */
+ collapsed_node.child_head = first_child();
+ collapsed_node.child_tail = last_child();
+ child_head = NULL;
+ child_tail = NULL;
+
+ this->h = rollout_height_pixels;
+
+ glui->refresh();
+}
+
+
+/**************************** GLUI_Rollout::mouse_down_handler() **********/
+
+
+int GLUI_Rollout::mouse_down_handler( int local_x, int local_y )
+{
+ if ( local_y - y_abs > rollout_height_pixels ) {
+ initially_inside = currently_inside = false;
+ return false;
+ }
+
+ currently_inside = true;
+ initially_inside = true;
+ redraw();
+
+ return false;
+}
+
+
+/**************************** GLUI_Rollout::mouse_held_down_handler() ****/
+
+int GLUI_Rollout::mouse_held_down_handler(
+ int local_x, int local_y,
+ bool new_inside )
+{
+ if ( NOT initially_inside )
+ return false;
+
+ if ( local_y - y_abs> rollout_height_pixels )
+ new_inside = false;
+
+ if (new_inside != currently_inside) {
+ currently_inside = new_inside;
+ redraw();
+ }
+
+ return false;
+}
+
+
+/**************************** GLUI_Rollout::mouse_down_handler() **********/
+
+int GLUI_Rollout::mouse_up_handler( int local_x, int local_y, bool inside )
+{
+ if ( currently_inside ) {
+ if ( is_open )
+ close();
+ else
+ open();
+ }
+
+ currently_inside = false;
+ initially_inside = false;
+ redraw();
+
+ return false;
+}
+
+
+/********************************* GLUI_Rollout::draw() ***********/
+
+void GLUI_Rollout::draw( int x, int y )
+{
+ GLUI_DRAWINGSENTINAL_IDIOM
+
+ int left, right, top, bottom;
+
+ left = 5;
+ right = w-left;
+ top = 3;
+ bottom = 3+16;
+
+ if ( is_open )
+ draw_emboss_box( 0, w, top+3, h );
+ else
+ draw_emboss_box( 0, w, top+3, h-7 );
+
+ glui->draw_raised_box( left, top, w-left*2, 16 );
+
+ if ( glui )
+ glColor3ub(glui->bkgd_color.r,glui->bkgd_color.g,glui->bkgd_color.b);
+ glDisable( GL_CULL_FACE );
+ glBegin( GL_QUADS );
+ glVertex2i( left+1, top+1 ); glVertex2i( right-1, top+1 );
+ glVertex2i( right-1, bottom-1 ); glVertex2i( left+1, bottom-1 );
+ glEnd();
+
+ draw_name( left+8, top+11 );
+
+ if ( active )
+ /*draw_active_box( left+4, left+string_width( name.c_str() )+12, */
+ draw_active_box( left+4, right-17,
+ top+2, bottom-2 );
+
+
+ /** Draw '+' or '-' **/
+
+ glBegin( GL_LINES );
+ if ( is_open ) {
+ if ( enabled ) glColor3f( 0.0, 0.0, 0.0 );
+ else glColor3f( 0.5, 0.5, 0.5 );
+ glVertex2i(right-14,(top+bottom)/2); glVertex2i(right-5,(top+bottom)/2);
+
+ glColor3f( 1.0, 1.0, 1.0 );
+ glVertex2i(right-14,1+(top+bottom)/2);glVertex2i(right-5,1+(top+bottom)/2);
+ }
+ else
+ {
+ glColor3f( 1.0, 1.0, 1.0 );
+ glVertex2i(right-9,top+3); glVertex2i(right-9,bottom-4);
+ glVertex2i(right-14,(top+bottom)/2); glVertex2i(right-5,(top+bottom)/2);
+
+ if ( enabled ) glColor3f( 0.0, 0.0, 0.0 );
+ else glColor3f( 0.5, 0.5, 0.5 );
+ glVertex2i(right-14,-1+(top+bottom)/2);
+ glVertex2i(right-5,-1+(top+bottom)/2);
+ glVertex2i(right-10,top+3);
+ glVertex2i(right-10,bottom-4);
+ }
+ glEnd();
+
+ glLineWidth( 1.0 );
+
+ if (currently_inside) {draw_pressed(); /* heavy black outline when pressed */ }
+}
+
+
+/***************************** GLUI_Rollout::update_size() **********/
+
+void GLUI_Rollout::update_size( void )
+{
+ int text_size;
+
+ if ( NOT glui )
+ return;
+
+ text_size = string_width(name);
+
+ if ( w < text_size + 36 )
+ w = text_size + 36;
+}
+
+
+/**************************** GLUI_Rollout::draw_pressed() ***********/
+
+void GLUI_Rollout::draw_pressed( void )
+{
+ int left, right, top, bottom;
+
+ left = 5;
+ right = w-left;
+ top = 3;
+ bottom = 3+16;
+
+
+ glColor3f( 0.0, 0.0, 0.0 );
+
+ glBegin( GL_LINE_LOOP );
+ glVertex2i( left, top ); glVertex2i( right, top );
+ glVertex2i( right, bottom ); glVertex2i( left,bottom );
+ glEnd();
+
+ glBegin( GL_LINE_LOOP );
+ glVertex2i( left+1, top+1 ); glVertex2i( right-1, top+1 );
+ glVertex2i( right-1, bottom-1 ); glVertex2i( left+1,bottom-1 );
+ glEnd();
+}
diff --git a/tests/box2d/glui/glui_rotation.cpp b/tests/box2d/glui/glui_rotation.cpp new file mode 100755 index 00000000..e3e84bed --- /dev/null +++ b/tests/box2d/glui/glui_rotation.cpp @@ -0,0 +1,473 @@ +/****************************************************************************
+
+ GLUI User Interface Toolkit
+ ---------------------------
+
+ glui_rotation - GLUI_Rotation control class
+
+
+ --------------------------------------------------
+
+ Copyright (c) 1998 Paul Rademacher
+
+ WWW: http://sourceforge.net/projects/glui/
+ Forums: http://sourceforge.net/forum/?group_id=92496
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+#include "glui.h"
+#include "arcball.h"
+#include "algebra3.h"
+
+/*************************** GLUI_Rotation::iaction_mouse_down_handler() ***/
+
+int GLUI_Rotation::iaction_mouse_down_handler( int local_x, int local_y )
+{
+ copy_float_array_to_ball();
+
+ init_ball();
+
+ local_y = (int) floor(2.0 * ball->center[1] - local_y);
+
+ ball->mouse_down( local_x, local_y );
+
+ /* printf( "%d %d - %f %f\n", local_x, local_y, ball->center[0], ball->center[1] ); */
+
+ copy_ball_to_float_array();
+
+ spinning = false;
+
+ return false;
+}
+
+
+/*********************** GLUI_Rotation::iaction_mouse_up_handler() **********/
+
+int GLUI_Rotation::iaction_mouse_up_handler( int local_x, int local_y,
+ bool inside )
+{
+ copy_float_array_to_ball();
+
+ ball->mouse_up();
+
+ return false;
+}
+
+
+/******************* GLUI_Rotation::iaction_mouse_held_down_handler() ******/
+
+int GLUI_Rotation::iaction_mouse_held_down_handler( int local_x, int local_y,
+ bool inside)
+{
+ if ( NOT glui )
+ return 0;
+
+ copy_float_array_to_ball();
+
+ local_y = (int) floor(2.0 * ball->center[1] - local_y);
+
+ /* printf( "%d %d\n", local_x, local_y ); */
+
+ ball->mouse_motion( local_x, local_y, 0,
+ (glui->curr_modifiers & GLUT_ACTIVE_ALT) != 0,
+ (glui->curr_modifiers & GLUT_ACTIVE_CTRL) != 0 );
+
+ copy_ball_to_float_array();
+
+ if ( can_spin )
+ spinning = true;
+
+ return false;
+}
+
+
+/******************** GLUI_Rotation::iaction_draw_active_area_persp() **************/
+
+void GLUI_Rotation::iaction_draw_active_area_persp( void )
+{
+ /********** arcball *******/
+ copy_float_array_to_ball();
+
+ setup_texture();
+ setup_lights();
+
+ glEnable(GL_CULL_FACE );
+
+ glMatrixMode( GL_MODELVIEW );
+ glPushMatrix();
+
+ mat4 tmp_rot = *ball->rot_ptr;
+ glMultMatrixf( (float*) &tmp_rot[0][0] );
+
+ /*** Draw the checkered box ***/
+ /*glDisable( GL_TEXTURE_2D ); */
+ draw_ball(1.35); // 1.96 );
+
+ glPopMatrix();
+
+ glBindTexture(GL_TEXTURE_2D,0); /* unhook our checkerboard texture */
+ glDisable( GL_TEXTURE_2D );
+ glDisable( GL_LIGHTING );
+ glDisable( GL_CULL_FACE );
+}
+
+
+/******************** GLUI_Rotation::iaction_draw_active_area_ortho() **********/
+
+void GLUI_Rotation::iaction_draw_active_area_ortho( void )
+{
+ float radius;
+ radius = (float)(h-22)/2.0; /*MIN((float)w/2.0, (float)h/2.0); */
+
+ /********* Draw emboss circles around arcball control *********/
+ int k;
+ glLineWidth( 1.0 );
+ glBegin( GL_LINE_LOOP);
+ for( k=0; k<60; k++ ) {
+ float phi = 2*M_PI*(float)k/60.0;
+ vec2 p( cos(phi) * (2.0 + radius), sin(phi) * (2.0 + radius));
+ if ( p[1] < -p[0] ) glColor3ub( 128,128,128 );
+ else glColor3ub( 255,255,255 );
+ glVertex2fv((float*)&p[0]);
+ }
+ glEnd();
+
+ glBegin( GL_LINE_LOOP);
+ for( k=0; k<60; k++ ) {
+ float phi = 2*M_PI*(float)k/60.0;
+ vec2 p( cos(phi) * (1.0 + radius), sin(phi) * (1.0 + radius));
+ if ( enabled ) {
+ if ( p[1] < -p[0] ) glColor3ub( 0,0,0);
+ else glColor3ub( 192,192,192);
+ }
+ else
+ {
+ if ( p[1] < -p[0] ) glColor3ub( 180,180,180);
+ else glColor3ub( 192,192,192);
+ }
+ glVertex2fv((float*)&p[0]);
+ }
+ glEnd();
+}
+
+
+/******************************** GLUI_Rotation::iaction_dump() **********/
+
+void GLUI_Rotation::iaction_dump( FILE *output )
+{
+}
+
+
+/******************** GLUI_Rotation::iaction_special_handler() **********/
+
+int GLUI_Rotation::iaction_special_handler( int key,int modifiers )
+{
+
+ return false;
+}
+
+/********************************** GLUI_Rotation::init_ball() **********/
+
+void GLUI_Rotation::init_ball( void )
+{
+ /*printf( "%f %f %f", float( MIN(w/2,h/2)), (float) w/2, (float) h/2 ); */
+
+ ball->set_params( vec2( (float)(w/2), (float)((h-18)/2)),
+ (float) 2.0*(h-18) );
+ /*ball->set_damping( .05 ); */
+ /*float( MIN(w/2,h/2))*2.0 ); */
+ /* ball->reset_mouse(); */
+}
+
+
+/****************************** GLUI_Rotation::setup_texture() *********/
+
+void GLUI_Rotation::setup_texture( void )
+{
+ static GLuint tex=0u;
+ GLenum t=GL_TEXTURE_2D;
+ glEnable(t);
+ glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+ glColor3f( 1.0, 1.0, 1.0 );
+ if (tex!=0u) {
+ /* (OSL 2006/06) Just use glBindTexture to avoid having to re-upload the whole checkerboard every frame. */
+ glBindTexture(t,tex);
+ return;
+ } /* Else need to make a new checkerboard texture */
+ glGenTextures(1,&tex);
+ glBindTexture(t,tex);
+ glEnable(t);
+
+ unsigned int i, j;
+ int dark, light; /*** Dark and light colors for ball checkerboard ***/
+
+/* Note: you can change the number of checkers across there sphere in draw_ball */
+#define CHECKBOARD_SIZE 64 /* pixels across whole texture */
+#define CHECKBOARD_REPEAT 32u /* pixels across one black/white sector */
+ unsigned char texture_image[CHECKBOARD_SIZE] [CHECKBOARD_SIZE] [3];
+ unsigned char c;
+ for( i=0; i<CHECKBOARD_SIZE; i++ )
+ {
+ for( j=0; j<CHECKBOARD_SIZE; j++ )
+ {
+ dark = 110;
+ light = 220;
+
+ if ((((i/CHECKBOARD_REPEAT)&0x1)==0) ^ (((j/CHECKBOARD_REPEAT)&0x1)==0))
+ c = light;
+ else
+ c = dark;
+
+ texture_image[i][j][0] = c;
+ texture_image[i][j][1] = c;
+ texture_image[i][j][2] = c;
+ }
+ }
+
+ glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
+ glTexParameteri( t, GL_TEXTURE_WRAP_S, GL_REPEAT );
+ glTexParameteri( t, GL_TEXTURE_WRAP_T, GL_REPEAT );
+ glTexParameteri( t, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ glTexParameteri( t, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
+ gluBuild2DMipmaps(t, GL_RGB, CHECKBOARD_SIZE, CHECKBOARD_SIZE,
+ GL_RGB, GL_UNSIGNED_BYTE, texture_image);
+
+/* Add some mipmapping LOD bias, to keep sphere texture sharp */
+ float bias=-0.5;
+ /* glTexEnvf(TEXTURE_FILTER_CONTROL_EXT,TEXTURE_LOD_BIAS_EXT,bias); */
+ /* glTexParameteri( t, GL_TEXTURE_MAX_LEVEL,1);*/
+ glTexEnvf(0x8500,0x8501,bias); /* <- numeric version for older OpenGL headers */
+ /* Cap out the mipmap level, to prevent blurring on horizon */
+ glTexParameteri(t, 0x813D, 1);
+ if (glGetError()) {
+ /* Ignore errors in setting funky texture state-- go with defaults.
+ If somebody knows how to check OpenGL 1.2 before doing this, please do!
+ */
+ }
+}
+
+/****************************** GLUI_Rotation::setup_lights() ***********/
+
+void GLUI_Rotation::setup_lights( void )
+{
+ glEnable( GL_LIGHTING );
+ /* if ( enabled )
+ glEnable( GL_LIGHTING );
+ else
+ glDisable( GL_LIGHTING );*/
+ glEnable(GL_LIGHT0);
+ glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE );
+ glEnable(GL_COLOR_MATERIAL);
+ GLfloat light0_position[] = {-1.f, 1.f, 1.0f, 0.0f};
+ glLightfv(GL_LIGHT0, GL_POSITION, light0_position);
+ if (enabled) { /* enabled colors */
+ GLfloat light0_ambient[] = {0.2f, 0.2f, 0.2f, 1.0f};
+ GLfloat light0_diffuse[] = {1.f, 1.f, 1.0f, 1.0f};
+ glLightfv(GL_LIGHT0, GL_AMBIENT, light0_ambient);
+ glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
+ }
+ else { /* disabled colors */
+ GLfloat light0_ambient[] = {0.6f, 0.6f, 0.6f, 1.0f};
+ GLfloat light0_diffuse[] = {0.2f, 0.2f, 0.2f, 1.0f};
+ glLightfv(GL_LIGHT0, GL_AMBIENT, light0_ambient);
+ glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
+ }
+
+}
+
+
+/****************************** GLUI_Rotation::draw_ball() **************/
+
+void GLUI_Rotation::draw_ball( float radius )
+{
+ if ( NOT can_draw() )
+ return;
+
+ if (quadObj == NULL) quadObj = gluNewQuadric();
+ if (quadObj) {
+ gluQuadricDrawStyle(quadObj, GLU_FILL);
+ gluQuadricNormals(quadObj, GLU_SMOOTH);
+ gluQuadricTexture(quadObj, true );
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+ double checkerTiles=2.0; /* black-white checker tiles across whole sphere */
+ glScalef(checkerTiles,checkerTiles,1.0);
+ gluSphere(quadObj, radius, 32, 16);
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
+ }
+}
+
+
+/****************************** GLUI_Rotation::reset() **********/
+
+void GLUI_Rotation::reset( void )
+{
+ ball->init(); /** reset quaternion, etc. **/
+ ball->set_params( vec2( (float)(w/2), (float)((h-18)/2)),
+ (float) 2.0*(h-18) );
+
+ set_spin( this->damping );
+
+ copy_ball_to_float_array();
+
+ translate_and_draw_front();
+
+ output_live(true); /*** Output live and draw main grx window ***/
+}
+
+
+/****************************** GLUI_Rotation::needs_idle() *********/
+
+bool GLUI_Rotation::needs_idle( void ) const
+{
+ return can_spin;
+}
+
+
+/****************************** GLUI_Rotation::idle() ***************/
+
+void GLUI_Rotation::idle( void )
+{
+ spinning = ball->is_spinning?true:false;
+
+ if ( can_spin AND spinning ) {
+ copy_float_array_to_ball();
+ ball->idle();
+
+ *ball->rot_ptr = *ball->rot_ptr * ball->rot_increment;
+
+ mat4 tmp_rot;
+ tmp_rot = *ball->rot_ptr;
+
+ copy_ball_to_float_array();
+
+ draw_active_area_only = true;
+ translate_and_draw_front();
+ draw_active_area_only = false;
+
+ output_live(true); /** output live and update gfx **/
+ }
+ else {
+ }
+}
+
+
+/********************** GLUI_Rotation::copy_float_array_to_ball() *********/
+
+void GLUI_Rotation::copy_float_array_to_ball( void )
+{
+ int i;
+ float *fp_src, *fp_dst;
+
+ fp_src = &float_array_val[0];
+ fp_dst = &((*ball->rot_ptr)[0][0]);
+
+ for( i=0; i<16; i++ ) {
+ *fp_dst = *fp_src;
+
+ fp_src++;
+ fp_dst++;
+ }
+}
+
+
+/********************** GLUI_Rotation::copy_ball_to_float_array() *********/
+
+void GLUI_Rotation::copy_ball_to_float_array( void )
+{
+ mat4 tmp_rot;
+ tmp_rot = *ball->rot_ptr;
+
+ set_float_array_val( (float*) &tmp_rot[0][0] );
+}
+
+
+/************************ GLUI_Rotation::set_spin() **********************/
+
+void GLUI_Rotation::set_spin( float damp_factor )
+{
+ if ( damp_factor == 0.0 )
+ can_spin = false;
+ else
+ can_spin = true;
+
+ ball->set_damping( 1.0 - damp_factor );
+
+ this->damping = damp_factor;
+}
+
+
+/************** GLUI_Rotation::GLUI_Rotation() ********************/
+
+GLUI_Rotation::GLUI_Rotation( GLUI_Node *parent,
+ const char *name, float *value_ptr,
+ int id,
+ GLUI_CB cb )
+{
+ common_init();
+ set_ptr_val( value_ptr );
+ user_id = id;
+ set_name( name );
+ callback = cb;
+ parent->add_control( this );
+ init_live();
+
+ /*** Init the live 4x4 matrix. This is different than the standard
+ live variable behavior, since the original value of the 4x4 matrix
+ is ignored and reset to Identity ***/
+/*
+NO! WVB
+ if ( value_ptr != NULL ) {
+ int i, j, index;
+ for( i=0; i<4; i++ ) {
+ for( j=0; j<4; j++ ) {
+ index = i*4+j;
+ if ( i==j )
+ value_ptr[index] = 1.0;
+ else
+ value_ptr[index] = 0.0;
+ }
+ }
+ }
+*/
+ /*init_ball(); */
+
+
+}
+
+
+/************** GLUI_Rotation::common_init() ********************/
+
+void GLUI_Rotation::common_init( void )
+{
+ glui_format_str( name, "Rotation: %p", this );
+// type = GLUI_CONTROL_ROTATION;
+ w = GLUI_ROTATION_WIDTH;
+ h = GLUI_ROTATION_HEIGHT;
+ can_activate = true;
+ live_type = GLUI_LIVE_FLOAT_ARRAY;
+ float_array_size = 16;
+ quadObj = NULL;
+ alignment = GLUI_ALIGN_CENTER;
+ can_spin = false;
+ spinning = false;
+ damping = 0.0;
+ ball = new Arcball;
+
+ reset();
+}
diff --git a/tests/box2d/glui/glui_scrollbar.cpp b/tests/box2d/glui/glui_scrollbar.cpp new file mode 100755 index 00000000..9540d407 --- /dev/null +++ b/tests/box2d/glui/glui_scrollbar.cpp @@ -0,0 +1,832 @@ +/****************************************************************************
+
+ GLUI User Interface Toolkit
+ ---------------------------
+
+ glui_scrollbar.cpp - GLUI_Scrollbar class
+
+ --------------------------------------------------
+
+ Copyright (c) 2004 John Kew, 1998 Paul Rademacher
+
+ This program is freely distributable without licensing fees and is
+ provided without guarantee or warrantee expressed or implied. This
+ program is -not- in the public domain.
+
+*****************************************************************************/
+
+#include "glui_internal_control.h"
+#include <cmath>
+#include <cassert>
+
+/*static int __debug=0; */
+
+#define GLUI_SCROLL_GROWTH_STEPS 800
+#define GLUI_SCROLL_MIN_GROWTH_STEPS 100
+#define GLUI_SCROLL_CALLBACK_INTERVAL 1 /* Execute the user's callback every this many clicks */
+
+enum {
+ GLUI_SCROLL_ARROW_UP,
+ GLUI_SCROLL_ARROW_DOWN,
+ GLUI_SCROLL_ARROW_LEFT,
+ GLUI_SCROLL_ARROW_RIGHT
+};
+
+
+/****************************** GLUI_Scrollbar::GLUI_Scrollbar() **********/
+// Constructor, no live var
+GLUI_Scrollbar::GLUI_Scrollbar( GLUI_Node *parent,
+ const char *name,
+ int horz_vert,
+ int data_type,
+ int id, GLUI_CB callback
+ /*,GLUI_Control *object
+ ,GLUI_InterObject_CB obj_cb*/
+ )
+{
+ common_construct(parent, name, horz_vert, data_type, NULL, id, callback/*, object, obj_cb*/);
+}
+
+/****************************** GLUI_Scrollbar::GLUI_Scrollbar() **********/
+// Constructor, int live var
+GLUI_Scrollbar::GLUI_Scrollbar( GLUI_Node *parent, const char *name,
+ int horz_vert,
+ int *live_var,
+ int id, GLUI_CB callback
+ /*,GLUI_Control *object
+ ,GLUI_InterObject_CB obj_cb*/
+ )
+{
+ common_construct(parent, name, horz_vert, GLUI_SCROLL_INT, live_var, id, callback/*, object, obj_cb*/);
+}
+
+/****************************** GLUI_Scrollbar::GLUI_Scrollbar() **********/
+// Constructor, float live var
+GLUI_Scrollbar::GLUI_Scrollbar( GLUI_Node *parent, const char *name,
+ int horz_vert,
+ float *live_var,
+ int id, GLUI_CB callback
+ /*,GLUI_Control *object
+ ,GLUI_InterObject_CB obj_cb*/
+ )
+{
+ common_construct(parent, name, horz_vert, GLUI_SCROLL_FLOAT, live_var, id, callback/*, object, obj_cb*/);
+}
+
+/****************************** GLUI_Scrollbar::common_init() **********/
+void GLUI_Scrollbar::common_init(void)
+{
+ horizontal = true;
+ h = GLUI_SCROLL_ARROW_HEIGHT;
+ w = GLUI_TEXTBOX_WIDTH;
+ alignment = GLUI_ALIGN_CENTER;
+ x_off = 0;
+ y_off_top = 0;
+ y_off_bot = 0;
+ can_activate = true;
+ state = GLUI_SCROLL_STATE_NONE;
+ growth_exp = GLUI_SCROLL_DEFAULT_GROWTH_EXP;
+ callback_count = 0;
+ first_callback = true;
+ user_speed = 1.0;
+ float_min = 0.0;
+ float_max = 0.0;
+ int_min = 0;
+ int_max = 0;
+ associated_object = NULL;
+ last_update_time=0;
+ velocity_limit=50.0; /* Change value by at most 50 per second */
+ box_length = 0;
+ box_start_position = 0;
+ box_end_position = 0;
+ track_length = 0;
+}
+
+/****************************** GLUI_Scrollbar::common_construct() **********/
+void GLUI_Scrollbar::common_construct(
+ GLUI_Node *parent,
+ const char *name,
+ int horz_vert,
+ int data_type,
+ void *data,
+ int id, GLUI_CB callback
+ /*,GLUI_Control *object,
+ GLUI_InterObject_CB obj_cb*/
+ )
+{
+ common_init();
+
+ // make sure limits are wide enough to hold live value
+ if (data_type==GLUI_SCROLL_FLOAT) {
+ float lo = 0.0f, hi=1.0f;
+ if (data) {
+ float d = *(float*)(data);
+ lo = MIN(lo, d);
+ hi = MAX(hi, d);
+ }
+ this->set_float_limits(lo,hi);
+ this->set_float_val(lo);
+ this->live_type = GLUI_LIVE_FLOAT;
+ } else {
+ int lo = 0, hi=100;
+ if (data) {
+ int d = *(int*)(data);
+ lo = MIN(lo, d);
+ hi = MAX(hi, d);
+ }
+ this->set_int_limits(lo,hi);
+ this->set_int_val(0);
+ this->live_type = GLUI_LIVE_INT;
+ }
+ this->data_type = data_type;
+ this->set_ptr_val( data );
+ this->set_name(name);
+ this->user_id = id;
+ this->callback = callback;
+ //this->associated_object = object;
+ //this->object_cb = obj_cb;
+ this->horizontal=(horz_vert==GLUI_SCROLL_HORIZONTAL);
+ if (this->horizontal) {
+ this->h = GLUI_SCROLL_ARROW_HEIGHT;
+ this->w = GLUI_TEXTBOX_WIDTH;
+ } else {
+ this->h = GLUI_TEXTBOX_HEIGHT;
+ this->w = GLUI_SCROLL_ARROW_WIDTH;
+ }
+ parent->add_control( this );
+ this->init_live();
+}
+
+/****************************** GLUI_Scrollbar::mouse_down_handler() **********/
+
+int GLUI_Scrollbar::mouse_down_handler( int local_x, int local_y )
+{
+ last_update_time=GLUI_Time()-1.0;
+ this->state = find_arrow( local_x, local_y );
+ GLUI_Master.glui_setIdleFuncIfNecessary();
+
+ /* printf( "spinner: mouse down : %d/%d arrow:%d\n", local_x, local_y,
+ find_arrow( local_x, local_y ));
+ */
+
+ if ( state != GLUI_SCROLL_STATE_UP AND state != GLUI_SCROLL_STATE_DOWN)
+ return true;
+
+ reset_growth();
+
+ /*** ints and floats behave a bit differently. When you click on
+ an int spinner, you expect the value to immediately go up by 1, whereas
+ for a float it'll go up only by a fractional amount. Therefore, we
+ go ahead and increment by one for int spinners ***/
+#if 1
+ if ( data_type == GLUI_SCROLL_INT ) {
+ // Allow for possibility of reversed limits
+ int lo = MIN(int_min,int_max);
+ int hi = MAX(int_min,int_max);
+ int increase = int_min < int_max ? 1 : -1;
+ int new_val = int_val;
+ if ( state == GLUI_SCROLL_STATE_UP ) {
+ new_val += increase;
+ } else if ( state == GLUI_SCROLL_STATE_DOWN ) {
+ new_val -= increase;
+ }
+ if (new_val >= lo && new_val <= hi && new_val!=int_val) {
+ set_int_val(new_val);
+ do_callbacks();
+ }
+ }
+#endif
+ do_click();
+ redraw();
+
+ return false;
+}
+
+
+/******************************** GLUI_Scrollbar::mouse_up_handler() **********/
+
+int GLUI_Scrollbar::mouse_up_handler( int local_x, int local_y, bool inside )
+{
+ state = GLUI_SCROLL_STATE_NONE;
+ GLUI_Master.glui_setIdleFuncIfNecessary();
+
+ /* printf("spinner: mouse up : %d/%d inside: %d\n",local_x,local_y,inside); */
+
+ /*glutSetCursor( GLUT_CURSOR_INHERIT ); */
+ glutSetCursor( GLUT_CURSOR_LEFT_ARROW );
+
+ redraw();
+
+ /* do_callbacks(); --- stub */
+ /* if ( callback ) */
+ /* callback( this->user_id ); */
+
+ return false;
+}
+
+
+/***************************** GLUI_Scrollbar::mouse_held_down_handler() ******/
+
+int GLUI_Scrollbar::mouse_held_down_handler( int local_x, int local_y,
+ bool new_inside)
+{
+ int new_state;
+ if ( state == GLUI_SCROLL_STATE_NONE )
+ return false;
+
+ /* printf("spinner: mouse held: %d/%d inside: %d\n",local_x,local_y,
+ new_inside);
+ */
+
+ if ( state == GLUI_SCROLL_STATE_SCROLL) { /* dragging? */
+ do_drag( local_x-x_abs, local_y-y_abs );
+ }
+ else { /* not dragging */
+ new_state = find_arrow( local_x, local_y );
+
+ if ( new_state == state ) {
+ /** Still in same arrow **/
+ do_click();
+ }
+ }
+ redraw();
+
+ return false;
+}
+
+
+/****************************** GLUI_Scrollbar::key_handler() **********/
+
+int GLUI_Scrollbar::key_handler( unsigned char key,int modifiers )
+{
+ return true;
+}
+
+
+/****************************** GLUI_Scrollbar::draw() **********/
+
+void GLUI_Scrollbar::draw( int x, int y )
+{
+ GLUI_DRAWINGSENTINAL_IDIOM
+
+ if ( horizontal ) {
+ draw_scroll_arrow(GLUI_SCROLL_ARROW_LEFT, 0, 0);
+ draw_scroll_arrow(GLUI_SCROLL_ARROW_RIGHT, w-GLUI_SCROLL_ARROW_WIDTH, 0);
+ } else {
+ draw_scroll_arrow(GLUI_SCROLL_ARROW_UP, 0, 0);
+ draw_scroll_arrow(GLUI_SCROLL_ARROW_DOWN, 0, h-GLUI_SCROLL_ARROW_HEIGHT);
+ }
+ draw_scroll();
+}
+
+
+/****************************** GLUI_Scrollbar::draw_scroll_arrow() **********/
+
+void GLUI_Scrollbar::draw_scroll_arrow(int arrowtype, int x, int y)
+{
+ float offset=0;
+ float L=3.5f,HC=7.f,R=10.5f;
+ float T=4.5f,VC=8.f,B=11.5;
+ const float verts[][6]={
+ { L,10.5f, R, 10.5f, HC, 6.5f }, // up arrow
+ { L,6.5f, R, 6.5f, HC,10.5f }, // down arrow
+ { R-2,T, R-2, B, L+1, VC }, // left arrow
+ { L+2,T, L+2, B, R-1, VC } // right arrow
+ };
+
+ const float *tri = NULL;
+
+ switch (arrowtype)
+ {
+ case GLUI_SCROLL_ARROW_UP:
+ tri = verts[0];
+ if (state & GLUI_SCROLL_STATE_UP) offset = 1;
+ break;
+
+ case GLUI_SCROLL_ARROW_DOWN:
+ tri = verts[1];
+ if (state & GLUI_SCROLL_STATE_DOWN) offset = 1;
+ break;
+
+ case GLUI_SCROLL_ARROW_LEFT:
+ tri = verts[2];
+ if (state & GLUI_SCROLL_STATE_DOWN) offset = 1;
+ break;
+
+ case GLUI_SCROLL_ARROW_RIGHT:
+ tri = verts[3];
+ if (state & GLUI_SCROLL_STATE_UP) offset = 1;
+ break;
+
+ default:
+ return; /* tri is NULL */
+ }
+
+ glColor3ubv(&glui->bkgd_color.r);
+ glRecti(x,y,x+GLUI_SCROLL_ARROW_WIDTH,y+GLUI_SCROLL_ARROW_HEIGHT);
+ if (!offset) {
+ glui->draw_raised_box(x,y+1,GLUI_SCROLL_ARROW_WIDTH-1,GLUI_SCROLL_ARROW_HEIGHT-1);
+ } else {
+ glColor3ub(128,128,128);
+ glBegin(GL_LINE_LOOP);
+ int x2=x+GLUI_SCROLL_ARROW_WIDTH, y2=y+GLUI_SCROLL_ARROW_HEIGHT;
+ glVertex2i(x ,y);
+ glVertex2i(x2,y);
+ glVertex2i(x2,y2);
+ glVertex2i(x ,y2);
+ glEnd();
+ }
+
+ GLubyte black[]={0,0,0};
+ GLubyte white[]={255,255,255};
+ GLubyte gray[]={128,128,128};
+ GLubyte *color=black;
+ if (!enabled) {
+ offset = 1;
+ color = white;
+ }
+ glTranslatef(x+offset,y+offset,0);
+ glColor3ubv(color);
+ glBegin(GL_TRIANGLES);
+ glVertex2fv(tri); glVertex2fv(tri+2), glVertex2fv(tri+4);
+ glEnd();
+ glTranslatef(-(x+offset),-(y+offset),0);
+
+ if (!enabled) { // once more!
+ glTranslatef(x,y,0);
+ glColor3ubv(gray);
+ glBegin(GL_TRIANGLES);
+ glVertex2fv(tri); glVertex2fv(tri+2), glVertex2fv(tri+4);
+ glEnd();
+ glTranslatef(-x,-y,0);
+ }
+}
+
+
+void GLUI_Scrollbar::draw_scroll() {
+ update_scroll_parameters();
+
+ // Draw track using a checkerboard background
+ const unsigned char scroll_bg[] = {
+ 0xD4, 0xD0, 0xC8, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xD4, 0xD0, 0xC8
+ };
+ glColor3f( 1.0, 1.0, 1.0 );
+ glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
+ glEnable( GL_TEXTURE_2D);
+ glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+ glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, GL_RGB, GL_UNSIGNED_BYTE,
+ scroll_bg);
+
+ float y0 = horizontal? 0 : GLUI_SCROLL_ARROW_HEIGHT;
+ float y1 = horizontal? h : h-GLUI_SCROLL_ARROW_HEIGHT;
+ float x0 = horizontal? GLUI_SCROLL_ARROW_WIDTH : 0;
+ float x1 = horizontal? w-GLUI_SCROLL_ARROW_WIDTH : w;
+ x0-=0.5; y0+=0.5;
+ x1-=0.5; y1+=0.5;
+ float dy = y1-y0;
+ float dx = x1-x0;
+ glBegin(GL_QUADS);
+ glTexCoord2f(0, 0); glVertex2f(x0,y0);
+ glTexCoord2f(dx*0.5f,0); glVertex2f(x1,y0);
+ glTexCoord2f(dx*0.5f,dy*0.5f); glVertex2f(x1,y1);
+ glTexCoord2f(0, dy*0.5f); glVertex2f(x0,y1);
+ glEnd();
+ glDisable(GL_TEXTURE_2D);
+
+ // Draw scroll box
+ int box = box_start_position;
+ if (horizontal) {
+ box += GLUI_SCROLL_ARROW_WIDTH;
+ draw_scroll_box(box,1,box_length,h);
+ } else {
+ box += GLUI_SCROLL_ARROW_HEIGHT+1;
+ draw_scroll_box(0,box,w,box_length);
+ }
+}
+
+/****************************** GLUI_Scrollbar::draw_scroll_box() **********/
+
+void GLUI_Scrollbar::draw_scroll_box(int x, int y, int w, int h)
+{
+ if (!enabled) return;
+ glColor3ubv(&glui->bkgd_color.r);
+ glRecti(x,y,x+w,y+h);
+ glui->draw_raised_box(x,y, w-1, h-1);
+
+ if (active) {
+ glEnable( GL_LINE_STIPPLE );
+ glLineStipple( 1, 0x5555 );
+ glColor3f( 0., 0., 0. );
+ glBegin(GL_LINE_LOOP);
+ int x1 = x+2, y1 = y+2, x2 = x+w-4, y2 = y+h-4;
+ glVertex2i(x1,y1);
+ glVertex2i(x2,y1);
+ glVertex2i(x2,y2);
+ glVertex2i(x1,y2);
+ glEnd();
+ glDisable( GL_LINE_STIPPLE );
+ }
+}
+
+
+
+/**************************** update_scroll_parameters ***********/
+
+void GLUI_Scrollbar::update_scroll_parameters() {
+ track_length = horizontal?
+ this->w-GLUI_SCROLL_ARROW_WIDTH*2 :
+ this->h-GLUI_SCROLL_ARROW_HEIGHT*2;
+ if (data_type==GLUI_SCROLL_INT)
+ {
+ if (int_max==int_min)
+ box_length=track_length;
+ else {
+ const int MIN_TAB = GLUI_SCROLL_BOX_STD_HEIGHT;
+ //box_length = int(track_length/float(visible_range));
+ //if (box_length < MIN_TAB)
+ box_length = MIN_TAB;
+ }
+ float pixels_per_unit = (track_length-box_length)/float(int_max-int_min);
+ if (horizontal)
+ box_start_position = int((int_val-int_min)*pixels_per_unit);
+ else
+ box_start_position = int((int_max-int_val)*pixels_per_unit);
+ box_end_position = box_start_position+box_length;
+ }
+ else if (data_type==GLUI_SCROLL_FLOAT)
+ {
+ if (float_max==float_min)
+ box_length=track_length;
+ else {
+ box_length = GLUI_SCROLL_BOX_STD_HEIGHT;
+ }
+ float pixels_per_unit = (track_length-box_length)/float(float_max-float_min);
+ if (horizontal)
+ box_start_position = int((float_val-float_min)*pixels_per_unit);
+ else
+ box_start_position = int((float_max-float_val)*pixels_per_unit);
+ box_end_position = box_start_position+box_length;
+ }
+}
+
+
+/********************************* GLUI_Scrollbar::special_handler() **********/
+
+int GLUI_Scrollbar::special_handler( int key,int modifiers )
+{
+ if ( !horizontal && key == GLUT_KEY_UP ) {
+ mouse_down_handler( x_abs + w - GLUI_SCROLL_ARROW_WIDTH + 1,
+ y_abs + 1 );
+ mouse_up_handler( x_abs + w - GLUI_SCROLL_ARROW_WIDTH + 1,
+ y_abs + 1, true );
+ }
+ else if ( !horizontal && key == GLUT_KEY_DOWN ) {
+ mouse_down_handler(x_abs + w - GLUI_SCROLL_ARROW_WIDTH + 1,
+ y_abs+1+GLUI_SCROLL_ARROW_HEIGHT);
+ mouse_up_handler( x_abs + w - GLUI_SCROLL_ARROW_WIDTH + 1,
+ y_abs+1 +GLUI_SCROLL_ARROW_HEIGHT,
+ true );
+ }
+ if ( horizontal && key == GLUT_KEY_LEFT ) {
+ mouse_down_handler( x_abs + 1,y_abs + 1 );
+ mouse_up_handler( x_abs + 1, y_abs + 1, true );
+ }
+ else if ( horizontal && key == GLUT_KEY_RIGHT ) {
+ mouse_down_handler(x_abs + w - GLUI_SCROLL_ARROW_WIDTH + 1,
+ y_abs+1);
+ mouse_up_handler( x_abs + w - GLUI_SCROLL_ARROW_WIDTH + 1,
+ y_abs+1,
+ true );
+ }
+ else if ( key == GLUT_KEY_HOME ) { /** Set value to limit top -
+ or increment by 10 **/
+ }
+ else if ( key == GLUT_KEY_END ) {
+ }
+
+ return true;
+}
+
+
+/************************************ GLUI_Scrollbar::update_size() **********/
+
+void GLUI_Scrollbar::update_size( void )
+{
+ if (horizontal) {
+ h = GLUI_SCROLL_ARROW_HEIGHT;
+ if (associated_object) {
+ this->w = ((GLUI_Control *)associated_object)->w;
+ }
+ }
+ else {
+ w = GLUI_SCROLL_ARROW_WIDTH;
+ if (associated_object) {
+ this->h = ((GLUI_Control *)associated_object)->h;
+ }
+ }
+}
+
+
+/************************************ GLUI_Scrollbar::find_arrow() ************/
+
+int GLUI_Scrollbar::find_arrow( int local_x, int local_y )
+{
+
+ local_x = local_x-x_abs;
+ local_y = local_y-y_abs;
+
+ if (horizontal)
+ {
+ if ( local_y >= h-GLUI_SCROLL_ARROW_HEIGHT-3 && local_y <= h)
+ {
+ update_scroll_parameters();
+ if ( local_x >= 0 AND local_x <= (GLUI_SCROLL_ARROW_WIDTH+box_start_position) )
+ {
+ return GLUI_SCROLL_STATE_DOWN;
+ }
+ if ( local_x >= (GLUI_SCROLL_ARROW_WIDTH+box_end_position)
+ AND local_x <= (w+GLUI_SCROLL_ARROW_WIDTH) )
+ {
+ return GLUI_SCROLL_STATE_UP;
+ }
+ return GLUI_SCROLL_STATE_SCROLL;
+ }
+ }
+ else
+ {
+ if ( local_x >= w-GLUI_SCROLL_ARROW_WIDTH-3 && local_x <= w)
+ {
+ update_scroll_parameters();
+ if ( local_y >= 0 AND local_y <= (GLUI_SCROLL_ARROW_HEIGHT+box_start_position) )
+ {
+ return GLUI_SCROLL_STATE_UP;
+ }
+ if ( local_y >= (GLUI_SCROLL_ARROW_HEIGHT+box_end_position)
+ AND local_y <= (h+GLUI_SCROLL_ARROW_HEIGHT) )
+ {
+ return GLUI_SCROLL_STATE_DOWN;
+ }
+ return GLUI_SCROLL_STATE_SCROLL;
+ }
+ }
+
+ return GLUI_SCROLL_STATE_NONE;
+}
+
+/***************************************** GLUI_Scrollbar::do_click() **********/
+
+void GLUI_Scrollbar::do_click( void )
+{
+ int direction = 0;
+
+ if ( state == GLUI_SCROLL_STATE_UP )
+ direction = +1;
+ else if ( state == GLUI_SCROLL_STATE_DOWN )
+ direction = -1;
+
+ if (data_type==GLUI_SCROLL_INT&&int_min>int_max) direction*=-1;
+ if (data_type==GLUI_SCROLL_FLOAT&&float_min>float_max) direction*=-1;
+
+ increase_growth();
+
+ float modifier_factor = 1.0;
+ float incr = growth * modifier_factor * user_speed ;
+
+ double frame_time=GLUI_Time()-last_update_time;
+ double frame_limit=velocity_limit*frame_time;
+ if (incr>frame_limit) incr=frame_limit; /* don't scroll faster than limit */
+ last_update_time=GLUI_Time();
+
+ float new_val = float_val;
+
+ new_val += direction * incr;
+ if (1 || data_type==GLUI_SCROLL_FLOAT) set_float_val(new_val);
+ if (0 && data_type==GLUI_SCROLL_INT) set_int_val((int)new_val);
+ //printf("do_click: incr %f val=%f float_val=%f\n",incr,new_val,float_val);
+
+ /*** Now update live variable and do callback. We don't want
+ to do the callback on each iteration of this function, just on every
+ i^th iteration, where i is given by GLUI_SCROLL_CALLBACK_INTERVAL ****/
+ callback_count++;
+ if ( (callback_count % GLUI_SCROLL_CALLBACK_INTERVAL ) == 0 )
+ do_callbacks();
+
+}
+
+
+/***************************************** GLUI_Scrollbar::do_drag() **********/
+
+void GLUI_Scrollbar::do_drag( int x, int y )
+{
+ int direction = 0;
+ float incr, modifier_factor;
+ /* int delta_x; */
+ int new_int_val = int_val;
+ float new_float_val = float_val;
+
+ int free_len = track_length-box_length;
+ if (free_len == 0) return;
+
+ modifier_factor = 1.0;
+ if ( state == GLUI_SCROLL_STATE_SCROLL) {
+ update_scroll_parameters();
+
+ int hbox = box_length/2;
+ if (horizontal) {
+ int track_v = x-GLUI_SCROLL_ARROW_WIDTH;
+ new_int_val = int_min + (track_v-hbox)*(int_max-int_min)/free_len;
+ new_float_val = float_min + (track_v-hbox)*(float_max-float_min)/float(free_len);
+ } else {
+ int track_v = y-GLUI_SCROLL_ARROW_HEIGHT;
+ new_int_val = int_max - (track_v-hbox)*(int_max-int_min)/free_len;
+ new_float_val = float_max - (track_v-hbox)*(float_max-float_min)/float(free_len);
+ }
+ }
+ else {
+ if ( state == GLUI_SCROLL_STATE_UP )
+ direction = +1;
+ else if ( state == GLUI_SCROLL_STATE_DOWN )
+ direction = -1;
+ incr = growth * direction * modifier_factor * user_speed;
+ new_int_val += direction;
+ new_float_val += direction * (float_max-float_min)/free_len;
+ }
+ last_y = y;
+ last_x = x;
+
+ /*** Now update live variable and do callback. We don't want
+ to do the callback on each iteration of this function, just on every
+ i^th iteration, where i is given by GLUI_SCROLL_CALLBACK_INTERVAL ****/
+ if(data_type==GLUI_SCROLL_INT)
+ set_int_val(new_int_val);
+ else if (data_type==GLUI_SCROLL_FLOAT)
+ set_float_val(new_float_val);
+
+ callback_count++;
+ if ( (callback_count % GLUI_SCROLL_CALLBACK_INTERVAL ) == 0 )
+ do_callbacks();
+}
+
+
+/***************************************** GLUI_Scrollbar::needs_idle() ******/
+
+bool GLUI_Scrollbar::needs_idle( void ) const
+{
+ if (state == GLUI_SCROLL_STATE_UP OR state == GLUI_SCROLL_STATE_DOWN ) {
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+/***************************************** GLUI_Scrollbar::idle() **********/
+
+void GLUI_Scrollbar::idle( void )
+{
+ if ( NOT needs_idle() )
+ return;
+ else
+ do_click();
+}
+
+
+/************************************ GLUI_Scrollbar::do_callbacks() **********/
+
+void GLUI_Scrollbar::do_callbacks( void )
+{
+
+ /* *******************************************/
+
+ if ( NOT first_callback ) {
+ if ( data_type == GLUI_SCROLL_INT AND int_val == last_int_val ) {
+ return;
+ }
+ if ( data_type == GLUI_SPINNER_FLOAT AND float_val == last_float_val ) {
+ return;
+ }
+ }
+
+ if (associated_object == NULL) {
+ this->execute_callback();
+ }
+ else { // Use internal Callbacks
+ if (object_cb) {
+ //object_cb(associated_object, int_val);
+ object_cb(this);
+ }
+ }
+ last_int_val = int_val;
+ last_float_val = float_val;
+ first_callback = false;
+}
+
+
+/********************************** GLUI_Scrollbar::set_float_val() ************/
+
+void GLUI_Scrollbar::set_float_val( float new_val )
+{
+ // Allow for the possibility that the limits are reversed
+ float hi = MAX(float_min,float_max);
+ float lo = MIN(float_min,float_max);
+ if (new_val > hi)
+ new_val = hi;
+ if (new_val < lo)
+ new_val = lo;
+ last_float_val = float_val;
+ float_val = new_val;
+ int_val = (int)new_val;
+
+ redraw();
+
+ /*** Now update the live variable ***/
+ output_live(true);
+}
+
+
+/********************************** GLUI_Scrollbar::set_int_val() ************/
+
+void GLUI_Scrollbar::set_int_val( int new_val )
+{
+ // Allow for the possibility that the limits are reversed
+ int hi = MAX(int_min,int_max);
+ int lo = MIN(int_min,int_max);
+ if (new_val > hi)
+ new_val = hi;
+ if (new_val < lo)
+ new_val = lo;
+ last_int_val = int_val;
+ float_val = int_val = new_val;
+
+ redraw();
+
+ /*** Now update the live variable ***/
+ output_live(true);
+}
+
+/*********************************** GLUI_Scrollbar::set_float_limits() *********/
+
+void GLUI_Scrollbar::set_float_limits( float low, float high, int limit_type )
+{
+ if (limit_type != GLUI_LIMIT_CLAMP) {
+ // error!
+ }
+ float_min = low;
+ float_max = high;
+ // Allow for possiblitly of reversed limits
+ float lo = MIN(low,high);
+ float hi = MAX(low,high);
+ if (float_val<lo) set_float_val(lo);
+ if (float_val>hi) set_float_val(hi);
+}
+
+
+/*********************************** GLUI_Scrollbar::set_int_limits() *********/
+
+void GLUI_Scrollbar::set_int_limits( int low, int high, int limit_type )
+{
+ if (limit_type != GLUI_LIMIT_CLAMP) {
+ // error!
+ }
+ int_min = low;
+ int_max = high;
+ // Allow for possiblitly of reversed limits
+ int lo = MIN(low,high);
+ int hi = MAX(low,high);
+ if (int_val<lo) set_int_val(lo);
+ if (int_val>hi) set_int_val(hi);
+ float_min = low;
+ float_max = high;
+}
+
+
+/*********************************** GLUI_Scrollbar::reset_growth() *************/
+
+void GLUI_Scrollbar::reset_growth( void )
+{
+ growth = fabs(float_max - float_min) / float(GLUI_SCROLL_GROWTH_STEPS);
+ if (data_type == GLUI_SCROLL_INT && growth<1) growth=1;
+}
+
+
+/******************************* GLUI_Scrollbar::increase_growth() *************/
+
+void GLUI_Scrollbar::increase_growth( void )
+{
+ float range=0;
+ if (data_type==GLUI_SCROLL_FLOAT)
+ range = fabs(float_max-float_min);
+ else
+ range = fabs(float(int_max-int_min));
+ if ( growth < (range / float(GLUI_SCROLL_MIN_GROWTH_STEPS)) )
+ growth *= growth_exp;
+ return;
+}
+
+
+
diff --git a/tests/box2d/glui/glui_separator.cpp b/tests/box2d/glui/glui_separator.cpp new file mode 100755 index 00000000..b10cf361 --- /dev/null +++ b/tests/box2d/glui/glui_separator.cpp @@ -0,0 +1,75 @@ +/****************************************************************************
+
+ GLUI User Interface Toolkit
+ ---------------------------
+
+ glui_separator.cpp - GLUI_Separator control class
+
+
+ --------------------------------------------------
+
+ Copyright (c) 1998 Paul Rademacher
+
+ WWW: http://sourceforge.net/projects/glui/
+ Forums: http://sourceforge.net/forum/?group_id=92496
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+#include "glui_internal_control.h"
+
+/****************************** GLUI_Separator::GLUI_Separator() **********/
+
+GLUI_Separator::GLUI_Separator( GLUI_Node *parent )
+{
+ common_init();
+ parent->add_control( this );
+}
+
+/****************************** GLUI_Separator::draw() **********/
+
+void GLUI_Separator::draw( int x, int y )
+{
+ GLUI_DRAWINGSENTINAL_IDIOM
+
+ int width, indent;
+ int cont_x, cont_y, cont_w, cont_h, cont_x_off, cont_y_off;
+
+ if ( parent() != NULL ) {
+ get_this_column_dims(&cont_x, &cont_y, &cont_w, &cont_h,
+ &cont_x_off, &cont_y_off);
+
+ width = cont_w - cont_x_off*2;
+ }
+ else {
+ width = this->w;
+ }
+
+ indent = (int) floor(width * .05);
+
+ glLineWidth( 1.0 );
+ glBegin( GL_LINES );
+ glColor3f( .5, .5, .5 );
+ glVertex2i( indent, GLUI_SEPARATOR_HEIGHT/2-1 );
+ glVertex2i( width-indent, GLUI_SEPARATOR_HEIGHT/2-1 );
+
+ glColor3f( 1., 1., 1. );
+ glVertex2i( indent, GLUI_SEPARATOR_HEIGHT/2 );
+ glVertex2i( width-indent, GLUI_SEPARATOR_HEIGHT/2 );
+ glEnd();
+}
+
+
diff --git a/tests/box2d/glui/glui_spinner.cpp b/tests/box2d/glui/glui_spinner.cpp new file mode 100755 index 00000000..85e7e3e0 --- /dev/null +++ b/tests/box2d/glui/glui_spinner.cpp @@ -0,0 +1,647 @@ +/****************************************************************************
+
+ GLUI User Interface Toolkit
+ ---------------------------
+
+ glui_spinner.cpp - GLUI_Spinner class
+
+
+ notes:
+ spinner does not explicitly keep track of the current value - this is all
+ handled by the underlying edittext control
+ -> thus, spinner->sync_live() has no meaning, nor spinner->output_live
+ -> BUT, edittext will alter this spinner's float_val and int_val,
+ so that spinner->get/set will work
+
+
+FIXME: there's a heck of a lot of duplication between this and glui_scrollbar.cpp.
+ (OSL, 2006/06)
+
+
+ --------------------------------------------------
+
+ Copyright (c) 1998 Paul Rademacher
+
+ WWW: http://sourceforge.net/projects/glui/
+ Forums: http://sourceforge.net/forum/?group_id=92496
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+#include "glui_internal_control.h"
+#include <cmath>
+#include <cassert>
+
+/*static int __debug=0; */
+
+#define GLUI_SPINNER_GROWTH_STEPS 800
+#define GLUI_SPINNER_MIN_GROWTH_STEPS 100
+#define GLUI_SPINNER_CALLBACK_INTERVAL 1
+
+
+/****************************** spinner_edittext_callback() ******************/
+/* This function is not used anymore. It has been replaced by directly */
+/* Including an optional pointer to a spinner from an edittext box */
+
+void spinner_edittext_callback( int id )
+{
+ GLUI_Spinner *spinner;
+
+ putchar( '.' ); flushout;
+
+ spinner = (GLUI_Spinner*) id;
+
+ if ( NOT spinner )
+ return;
+
+ spinner->do_callbacks();
+}
+
+
+/****************************** GLUI_Spinner::GLUI_Spinner() ****************/
+
+GLUI_Spinner::GLUI_Spinner( GLUI_Node* parent, const char *name,
+ int data_type, int id, GLUI_CB callback )
+{
+ common_construct(parent, name, data_type, NULL, id, callback);
+}
+
+/****************************** GLUI_Spinner::GLUI_Spinner() ****************/
+
+GLUI_Spinner::GLUI_Spinner( GLUI_Node* parent, const char *name,
+ int *live_var, int id, GLUI_CB callback )
+{
+ common_construct(parent, name, GLUI_SPINNER_INT, live_var, id, callback);
+}
+
+/****************************** GLUI_Spinner::GLUI_Spinner() ****************/
+
+GLUI_Spinner::GLUI_Spinner( GLUI_Node* parent, const char *name,
+ float *live_var, int id, GLUI_CB callback )
+{
+ common_construct(parent, name, GLUI_SPINNER_FLOAT, live_var, id, callback);
+}
+
+/****************************** GLUI_Spinner::GLUI_Spinner() ****************/
+
+GLUI_Spinner::GLUI_Spinner( GLUI_Node *parent, const char *name,
+ int data_t, void *live_var,
+ int id, GLUI_CB callback )
+{
+ common_construct(parent, name, data_t, live_var, id, callback);
+}
+
+/****************************** GLUI_Spinner::common_construct() ************/
+
+void GLUI_Spinner::common_construct( GLUI_Node* parent, const char *name,
+ int data_t, void *data,
+ int id, GLUI_CB cb )
+{
+ common_init();
+
+ if ( NOT strcmp( name, "Spinner Test" ))
+ id=id;
+
+ int text_type;
+ if ( data_t == GLUI_SPINNER_INT ) {
+ text_type = GLUI_EDITTEXT_INT;
+ }
+ else if ( data_t == GLUI_SPINNER_FLOAT ) {
+ text_type = GLUI_EDITTEXT_FLOAT;
+ }
+ else {
+ assert(0); /* Did not pass in a valid data type */
+ }
+
+ user_id = id;
+ data_type = data_t;
+ callback = cb;
+ set_name( name );
+ //glui = parent->get_glui();
+
+ parent->add_control( this );
+
+ GLUI_EditText *txt =
+ new GLUI_EditText( this, name, text_type, data, id, cb);
+
+ edittext = txt; /* Link the edittext to the spinner */
+ /* control->ptr_val = data; */
+
+ edittext->spinner = this; /* Link the spinner to the edittext */
+
+}
+
+/****************************** GLUI_Spinner::mouse_down_handler() **********/
+
+int GLUI_Spinner::mouse_down_handler( int local_x, int local_y )
+{
+ this->state = find_arrow( local_x, local_y );
+ GLUI_Master.glui_setIdleFuncIfNecessary();
+
+ /* printf( "spinner: mouse down : %d/%d arrow:%d\n", local_x, local_y,
+ find_arrow( local_x, local_y ));
+ */
+
+ if ( state != GLUI_SPINNER_STATE_UP AND state != GLUI_SPINNER_STATE_DOWN )
+ return true;
+
+ reset_growth();
+ redraw();
+
+ /*** ints and floats behave a bit differently. When you click on
+ an int spinner, you expect the value to immediately go up by 1, whereas
+ for a float it'll go up only by a fractional amount. Therefore, we
+ go ahead and increment by one for int spinners ***/
+ if ( data_type == GLUI_SPINNER_INT ) {
+ if ( state == GLUI_SPINNER_STATE_UP )
+ edittext->set_float_val( edittext->float_val + 1.0 );
+ else if ( state == GLUI_SPINNER_STATE_DOWN )
+ edittext->set_float_val( edittext->float_val - .9 );
+ }
+
+ do_click();
+
+ return false;
+}
+
+
+/******************************** GLUI_Spinner::mouse_up_handler() **********/
+
+int GLUI_Spinner::mouse_up_handler( int local_x, int local_y, bool inside )
+{
+ state = GLUI_SPINNER_STATE_NONE;
+ GLUI_Master.glui_setIdleFuncIfNecessary();
+
+ /* printf("spinner: mouse up : %d/%d inside: %d\n",local_x,local_y,inside); */
+
+ /*glutSetCursor( GLUT_CURSOR_INHERIT ); */
+ glutSetCursor( GLUT_CURSOR_LEFT_ARROW );
+ redraw();
+
+ /* do_callbacks(); --- stub */
+ /* if ( callback ) */
+ /* callback( this->user_id ); */
+
+ return false;
+}
+
+
+/***************************** GLUI_Spinner::mouse_held_down_handler() ******/
+
+int GLUI_Spinner::mouse_held_down_handler( int local_x, int local_y,
+ bool new_inside)
+{
+ int new_state;
+
+ if ( state == GLUI_SPINNER_STATE_NONE )
+ return false;
+
+ /* printf("spinner: mouse held: %d/%d inside: %d\n",local_x,local_y,
+ new_inside);
+ */
+
+ if ( state == GLUI_SPINNER_STATE_BOTH ) { /* dragging? */
+ do_drag( local_x, local_y );
+ }
+ else { /* not dragging */
+ new_state = find_arrow( local_x, local_y );
+
+ if ( new_state == state ) {
+ /** Still in same arrow **/
+ do_click();
+ }
+ else {
+ if ( new_inside OR 1) {
+ /** The state changed, but we're still inside - that
+ means we moved off the arrow: begin dragging **/
+ state = GLUI_SPINNER_STATE_BOTH;
+ }
+ else {
+ /*** Here check y of mouse position to determine whether to
+ drag ***/
+
+ /* ... */
+ }
+ }
+
+ /*** We switched to up/down dragging ***/
+ if ( state == GLUI_SPINNER_STATE_BOTH ) {
+ glutSetCursor( GLUT_CURSOR_UP_DOWN );
+ last_x = local_x;
+ last_y = local_y;
+
+ /** If the spinner has limits, we reset the growth value, since
+ reset_growth() will compute a new growth value for dragging
+ vs. clicking. If the spinner has no limits, then we just let the
+ growth remain at whatever the user has incremented it up to **/
+ if ( edittext->has_limits != GLUI_LIMIT_NONE )
+ reset_growth();
+ }
+
+ redraw();
+ }
+
+ return false;
+}
+
+
+/****************************** GLUI_Spinner::key_handler() **********/
+
+int GLUI_Spinner::key_handler( unsigned char key,int modifiers )
+{
+
+
+ return true;
+}
+
+
+/****************************** GLUI_Spinner::draw() **********/
+
+void GLUI_Spinner::draw( int x, int y )
+{
+ GLUI_DRAWINGSENTINAL_IDIOM
+
+ if ( enabled ) {
+ /*** Draw the up arrow either pressed or unrpessed ***/
+ if ( state == GLUI_SPINNER_STATE_UP OR state == GLUI_SPINNER_STATE_BOTH )
+ glui->std_bitmaps.draw( GLUI_STDBITMAP_SPINNER_UP_ON,
+ w-GLUI_SPINNER_ARROW_WIDTH-1,
+ GLUI_SPINNER_ARROW_Y);
+ else
+ glui->std_bitmaps.draw( GLUI_STDBITMAP_SPINNER_UP_OFF,
+ w-GLUI_SPINNER_ARROW_WIDTH-1,
+ GLUI_SPINNER_ARROW_Y);
+
+ /*** Draw the down arrow either pressed or unrpessed ***/
+ if (state == GLUI_SPINNER_STATE_DOWN OR state == GLUI_SPINNER_STATE_BOTH)
+ glui->std_bitmaps.draw( GLUI_STDBITMAP_SPINNER_DOWN_ON,
+ w-GLUI_SPINNER_ARROW_WIDTH-1,
+ GLUI_SPINNER_ARROW_HEIGHT+GLUI_SPINNER_ARROW_Y);
+ else
+ glui->std_bitmaps.draw( GLUI_STDBITMAP_SPINNER_DOWN_OFF,
+ w-GLUI_SPINNER_ARROW_WIDTH-1,
+ GLUI_SPINNER_ARROW_HEIGHT+GLUI_SPINNER_ARROW_Y);
+ }
+ else { /**** The spinner is disabled ****/
+ glui->std_bitmaps.draw( GLUI_STDBITMAP_SPINNER_UP_DIS,
+ w-GLUI_SPINNER_ARROW_WIDTH-1,
+ GLUI_SPINNER_ARROW_Y);
+ glui->std_bitmaps.draw( GLUI_STDBITMAP_SPINNER_DOWN_DIS,
+ w-GLUI_SPINNER_ARROW_WIDTH-1,
+ GLUI_SPINNER_ARROW_HEIGHT+GLUI_SPINNER_ARROW_Y);
+ }
+
+ if ( active ) {
+ glColor3ub( 0, 0, 0 );
+ glEnable( GL_LINE_STIPPLE );
+ glLineStipple( 1, 0x5555 );
+ }
+ else {
+ glColor3ub( glui->bkgd_color.r,glui->bkgd_color.g,glui->bkgd_color.b );
+ }
+
+ glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
+ glDisable( GL_CULL_FACE );
+ glBegin( GL_QUADS );
+ glVertex2i( w-GLUI_SPINNER_ARROW_WIDTH-2, 0 );
+ glVertex2i( w, 0 );
+ glVertex2i( w, h );
+ glVertex2i( w-GLUI_SPINNER_ARROW_WIDTH-2, h );
+ glEnd();
+ glDisable( GL_LINE_STIPPLE );
+ glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
+}
+
+
+/********************************* GLUI_Spinner::special_handler() **********/
+
+int GLUI_Spinner::special_handler( int key,int modifiers )
+{
+ if ( key == GLUT_KEY_UP ) { /** Simulate a click in the up arrow **/
+ mouse_down_handler( x_abs + w - GLUI_SPINNER_ARROW_WIDTH + 1,
+ y_abs + GLUI_SPINNER_ARROW_Y+1 );
+ mouse_up_handler( x_abs + w - GLUI_SPINNER_ARROW_WIDTH + 1,
+ y_abs + GLUI_SPINNER_ARROW_Y+1, true );
+ }
+ else if ( key == GLUT_KEY_DOWN ) { /** Simulate a click in the up arrow **/
+ mouse_down_handler(x_abs + w - GLUI_SPINNER_ARROW_WIDTH + 1,
+ y_abs+GLUI_SPINNER_ARROW_Y+1+GLUI_SPINNER_ARROW_HEIGHT);
+ mouse_up_handler( x_abs + w - GLUI_SPINNER_ARROW_WIDTH + 1,
+ y_abs+GLUI_SPINNER_ARROW_Y+1 +GLUI_SPINNER_ARROW_HEIGHT,
+ true );
+ }
+ else if ( key == GLUT_KEY_HOME ) { /** Set value to limit top -
+ or increment by 10 **/
+ }
+ else if ( key == GLUT_KEY_END ) {
+ }
+
+ return true;
+}
+
+
+/******************************* GLUI_Spinner::set_float_val() ************/
+
+void GLUI_Spinner::set_float_val( float new_val )
+{
+ if ( NOT edittext )
+ return;
+
+ edittext->set_float_val( new_val );
+}
+
+
+/********************************** GLUI_Spinner::set_int_val() ************/
+
+void GLUI_Spinner::set_int_val( int new_val )
+{
+ if ( NOT edittext )
+ return;
+
+ edittext->set_int_val( new_val );
+}
+
+
+/************************************ GLUI_Spinner::update_size() **********/
+
+void GLUI_Spinner::update_size( void )
+{
+ if (!edittext) return;
+ /*edittext->w = this->w - GLUI_SPINNER_ARROW_WIDTH-3; */
+ this->w = edittext->w + GLUI_SPINNER_ARROW_WIDTH + 3;
+}
+
+
+/************************************ GLUI_Spinner::find_arrow() ************/
+
+int GLUI_Spinner::find_arrow( int local_x, int local_y )
+{
+ local_x -= x_abs;
+ local_y -= y_abs;
+
+ if ( local_x >= (w - GLUI_SPINNER_ARROW_WIDTH) AND
+ local_x <= w ) {
+
+ if ( local_y >= GLUI_SPINNER_ARROW_Y AND
+ local_y <= (GLUI_SPINNER_ARROW_Y+GLUI_SPINNER_ARROW_HEIGHT) )
+ return GLUI_SPINNER_STATE_UP;
+
+ if ( local_y >= GLUI_SPINNER_ARROW_Y+GLUI_SPINNER_ARROW_HEIGHT AND
+ local_y <= (GLUI_SPINNER_ARROW_Y+GLUI_SPINNER_ARROW_HEIGHT*2) )
+ return GLUI_SPINNER_STATE_DOWN;
+
+ }
+
+ return GLUI_SPINNER_STATE_NONE;
+}
+
+
+/***************************************** GLUI_Spinner::do_click() **********/
+
+void GLUI_Spinner::do_click( void )
+{
+ int direction = 0;
+ float incr;
+ float modifier_factor;
+
+ if ( state == GLUI_SPINNER_STATE_UP )
+ direction = +1;
+ else if ( state == GLUI_SPINNER_STATE_DOWN )
+ direction = -1;
+
+ increase_growth();
+
+ modifier_factor = 1.0;
+ if ( glui ) {
+ if ( glui->curr_modifiers & GLUT_ACTIVE_SHIFT )
+ modifier_factor = 100.0f;
+ else if ( glui->curr_modifiers & GLUT_ACTIVE_CTRL )
+ modifier_factor = .01f;
+ }
+
+ if ( this->data_type == GLUI_SPINNER_FLOAT OR 1) {
+ incr = growth * direction * modifier_factor * user_speed;
+ edittext->set_float_val( edittext->float_val + incr );
+ /** Remember, edittext mirrors the float and int values ***/
+ }
+
+ /*** Now update live variable and do callback. We don't want
+ to do the callback on each iteration of this function, just on every
+ i^th iteration, where i is given by GLUI_SPINNER_CALLBACK_INTERVAL ****/
+ callback_count++;
+ if ( (callback_count % GLUI_SPINNER_CALLBACK_INTERVAL ) == 0 )
+ do_callbacks();
+}
+
+
+/***************************************** GLUI_Spinner::do_drag() **********/
+
+void GLUI_Spinner::do_drag( int x, int y )
+{
+ int delta_y;
+ float incr, modifier_factor;
+ /* int delta_x; */
+
+ modifier_factor = 1.0f;
+ if ( glui ) {
+ if ( glui->curr_modifiers & GLUT_ACTIVE_SHIFT )
+ modifier_factor = 100.0f;
+ else if ( glui->curr_modifiers & GLUT_ACTIVE_CTRL )
+ modifier_factor = .01f;
+ }
+
+ /* delta_x = x - last_x; */
+ delta_y = -(y - last_y);
+
+ if ( this->data_type == GLUI_SPINNER_FLOAT OR 1 ) {
+ incr = growth * delta_y * modifier_factor * user_speed;
+ edittext->set_float_val( edittext->float_val + incr );
+ /** Remember, edittext mirrors the float and int values ***/
+ }
+
+ last_x = x;
+ last_y = y;
+
+ /*** Now update live variable and do callback. We don't want
+ to do the callback on each iteration of this function, just on every
+ i^th iteration, where i is given by GLUI_SPINNER_CALLBACK_INTERVAL ****/
+
+ callback_count++;
+ if ( (callback_count % GLUI_SPINNER_CALLBACK_INTERVAL ) == 0 )
+ do_callbacks();
+}
+
+
+/***************************************** GLUI_Spinner::needs_idle() ******/
+
+bool GLUI_Spinner::needs_idle( void ) const
+{
+ if (state == GLUI_SPINNER_STATE_UP OR state == GLUI_SPINNER_STATE_DOWN ) {
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+/***************************************** GLUI_Spinner::idle() **********/
+
+void GLUI_Spinner::idle( void )
+{
+ if ( NOT needs_idle() )
+ return;
+ else
+ do_click();
+}
+
+
+/************************************ GLUI_Spinner::do_callbacks() **********/
+
+void GLUI_Spinner::do_callbacks( void )
+{
+ /*** This is not necessary, b/c edittext automatically updates us ***/
+ if ( NOT edittext )
+ return;
+ this->float_val = edittext->float_val;
+ this->int_val = edittext->int_val;
+ /* *******************************************/
+
+ if ( NOT first_callback ) {
+ if ( data_type == GLUI_SPINNER_INT AND int_val == last_int_val ) {
+ return;
+ }
+
+ if ( data_type == GLUI_SPINNER_FLOAT AND float_val == last_float_val ) {
+ return;
+ }
+ }
+
+ this->execute_callback();
+
+ last_int_val = int_val;
+ last_float_val = float_val;
+ first_callback = false;
+}
+
+
+/********************************* GLUI_Spinner::set_float_limits() *********/
+
+void GLUI_Spinner::set_float_limits( float low, float high, int limit_type )
+{
+ if ( NOT edittext )
+ return;
+
+ edittext->set_float_limits( low, high, limit_type );
+}
+
+
+/*********************************** GLUI_Spinner::set_int_limits() *********/
+
+void GLUI_Spinner::set_int_limits( int low, int high, int limit_type )
+{
+ if ( NOT edittext )
+ return;
+
+ edittext->set_int_limits( low, high, limit_type );
+}
+
+
+/*********************************** GLUI_Spinner:reset_growth() *************/
+
+void GLUI_Spinner::reset_growth( void )
+{
+ float lo, hi;
+
+ if ( edittext->has_limits == GLUI_LIMIT_NONE ) {
+ if ( data_type == GLUI_SPINNER_FLOAT )
+ growth = sqrt(ABS(edittext->float_val)) * .05f;
+ else if ( data_type == GLUI_SPINNER_INT )
+ growth = .4f;
+ }
+ else {
+ if ( data_type == GLUI_SPINNER_FLOAT ) {
+ lo = edittext->float_low;
+ hi = edittext->float_high;
+ growth = (hi-lo) / GLUI_SPINNER_GROWTH_STEPS;
+ }
+ else if ( data_type == GLUI_SPINNER_INT ) {
+ lo = (float) edittext->int_low;
+ hi = (float) edittext->int_high;
+
+ growth = (hi-lo) / GLUI_SPINNER_GROWTH_STEPS;
+ }
+ }
+
+ if ( growth == 0.0f )
+ growth = .001f;
+}
+
+
+/******************************* GLUI_Spinner:increase_growth() *************/
+
+void GLUI_Spinner::increase_growth( void )
+{
+ float hi = 0.0,lo = 0.0;
+
+ if ( data_type == GLUI_SPINNER_FLOAT ) {
+ lo = edittext->float_low;
+ hi = edittext->float_high;
+ }
+ else if ( data_type == GLUI_SPINNER_INT ) {
+ lo = (float) edittext->int_low;
+ hi = (float) edittext->int_high;
+ }
+
+ if ( growth < (hi-lo) / GLUI_SPINNER_MIN_GROWTH_STEPS )
+ growth *= growth_exp;
+
+ /* printf( "growth: %f\n", growth ); */
+}
+
+
+/*************************************** GLUI_Spinner:get_text() *************/
+
+const char *GLUI_Spinner::get_text( void )
+{
+ if (edittext)
+ return edittext->text.c_str();
+ else
+ return "";
+}
+
+
+/********************************** GLUI_Spinner:get_float_val() *************/
+
+float GLUI_Spinner::get_float_val( void )
+{
+ if (edittext)
+ return edittext->float_val;
+ else
+ return 0.0f;
+}
+
+
+/********************************** GLUI_Spinner:get_int_val() *************/
+
+int GLUI_Spinner::get_int_val( void )
+{
+ if (edittext)
+ return edittext->int_val;
+ else
+ return 0;
+}
+
+
diff --git a/tests/box2d/glui/glui_statictext.cpp b/tests/box2d/glui/glui_statictext.cpp new file mode 100755 index 00000000..b0db4b94 --- /dev/null +++ b/tests/box2d/glui/glui_statictext.cpp @@ -0,0 +1,105 @@ +/****************************************************************************
+
+ GLUI User Interface Toolkit
+ ---------------------------
+
+ glui_statictext.cpp - GLUI_StaticText Control
+
+
+ --------------------------------------------------
+
+ Copyright (c) 1998 Paul Rademacher
+
+ WWW: http://sourceforge.net/projects/glui/
+ Forums: http://sourceforge.net/forum/?group_id=92496
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+#include "glui_internal_control.h"
+
+/****************************** GLUI_StaticText::GLUI_StaticText() **********/
+GLUI_StaticText::GLUI_StaticText( GLUI_Node *parent, const char *name )
+{
+ common_init();
+ set_name( name );
+ parent->add_control( this );
+}
+
+/****************************** GLUI_StaticText::draw() **********/
+
+void GLUI_StaticText::draw( int x, int y )
+{
+ GLUI_DRAWINGSENTINAL_IDIOM
+
+ draw_text();
+}
+
+
+/****************************** GLUI_StaticText::set_text() **********/
+
+void GLUI_StaticText::set_text( const char *text )
+{
+ set_name( text );
+ redraw();
+}
+
+
+/************************************ GLUI_StaticText::update_size() **********/
+
+void GLUI_StaticText::update_size( void )
+{
+ int text_size;
+
+ if ( NOT glui )
+ return;
+
+ text_size = string_width( name );
+
+ if ( w < text_size )
+ w = text_size;
+}
+
+
+/****************************** GLUI_StaticText::draw_text() **********/
+
+void GLUI_StaticText::draw_text( void )
+{
+ if ( NOT can_draw() )
+ return;
+
+ erase_text();
+ draw_name( 0, 9 );
+}
+
+
+/****************************** GLUI_StaticText::erase_text() **********/
+
+void GLUI_StaticText::erase_text( void )
+{
+ if ( NOT can_draw() )
+ return;
+
+ set_to_bkgd_color();
+ glDisable( GL_CULL_FACE );
+ glBegin( GL_TRIANGLES );
+ glVertex2i( 0,0 ); glVertex2i( w, 0 ); glVertex2i( w, h );
+ glVertex2i( 0, 0 ); glVertex2i( w, h ); glVertex2i( 0, h );
+ glEnd();
+}
+
+
+
diff --git a/tests/box2d/glui/glui_string.cpp b/tests/box2d/glui/glui_string.cpp new file mode 100755 index 00000000..910e6eb8 --- /dev/null +++ b/tests/box2d/glui/glui_string.cpp @@ -0,0 +1,62 @@ +/****************************************************************************
+
+ GLUI User Interface Toolkit
+ ---------------------------
+
+ glui.cpp
+
+
+ --------------------------------------------------
+
+ Copyright (c) 1998 Paul Rademacher (this file, Bill Baxter 2005)
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA
+
+ This program is -not- in the public domain.
+
+*****************************************************************************/
+
+#include "glui.h"
+#include <stdarg.h>
+
+#ifdef _MSC_VER
+#define vsnprintf _vsnprintf
+#endif
+
+GLUI_String& glui_format_str(GLUI_String& str, const char* fmt, ...)
+{
+ const size_t ISIZE = 128;
+ char stackbuf[ISIZE];
+ size_t bufsz = ISIZE;
+ char *buf = stackbuf;
+ str = "";
+ va_list arg;
+ while (1) {
+ va_start(arg, fmt);
+ int ret = vsnprintf(buf,299,fmt,arg);
+ va_end(arg);
+ if (ret>=0) {
+ break;
+ }
+ // else make a bigger buf, try again
+ bufsz <<= 1;
+ if (buf==stackbuf) buf = (char*)malloc(sizeof(char)*bufsz);
+ else buf = (char*)realloc(buf, sizeof(char)*bufsz);
+ }
+ if (buf!=stackbuf) free(buf);
+ str=buf;
+ return str;
+}
diff --git a/tests/box2d/glui/glui_textbox.cpp b/tests/box2d/glui/glui_textbox.cpp new file mode 100755 index 00000000..56fc0158 --- /dev/null +++ b/tests/box2d/glui/glui_textbox.cpp @@ -0,0 +1,1108 @@ +/****************************************************************************
+
+ GLUI User Interface Toolkit
+ ---------------------------
+
+ glui_textbox.cpp - GLUI_TextBox control class
+
+
+ --------------------------------------------------
+
+ Copyright (c) 1998 Paul Rademacher, 2004 John Kew
+
+ WWW: http://sourceforge.net/projects/glui/
+ Forums: http://sourceforge.net/forum/?group_id=92496
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+#include "glui_internal_control.h"
+#include <cmath>
+
+
+static const int LINE_HEIGHT = 15;
+
+/****************************** GLUI_TextBox::GLUI_TextBox() **********/
+
+GLUI_TextBox::GLUI_TextBox(GLUI_Node *parent, GLUI_String &live_var,
+ bool scroll, int id, GLUI_CB callback )
+{
+ common_construct(parent, &live_var, scroll, id, callback);
+}
+
+/****************************** GLUI_TextBox::GLUI_TextBox() **********/
+
+GLUI_TextBox::GLUI_TextBox( GLUI_Node *parent, bool scroll, int id,
+ GLUI_CB callback )
+{
+ common_construct(parent, NULL, scroll, id, callback);
+}
+
+/****************************** GLUI_TextBox::common_construct() **********/
+void GLUI_TextBox::common_construct(
+ GLUI_Node *parent, GLUI_String *data,
+ bool scroll, int id, GLUI_CB callback)
+{
+ common_init();
+
+ GLUI_Node *tb_panel = parent;
+
+ if (scroll) {
+ GLUI_Panel *p = new GLUI_Panel(parent,"",GLUI_PANEL_NONE);
+ p->x_off = 1;
+ tb_panel = p;
+ }
+ this->ptr_val = data;
+ if (data) {
+ this->live_type = GLUI_LIVE_STRING;
+ } else {
+ this->live_type = GLUI_LIVE_NONE;
+ }
+ this->user_id = id;
+ this->callback = callback;
+ this->name = "textbox";
+ tb_panel->add_control( this );
+ if (scroll) {
+ new GLUI_Column(tb_panel, false);
+ scrollbar =
+ new GLUI_Scrollbar(tb_panel,
+ "scrollbar",
+ GLUI_SCROLL_VERTICAL,
+ GLUI_SCROLL_INT);
+ scrollbar->set_object_callback(GLUI_TextBox::scrollbar_callback, this);
+ scrollbar->set_alignment(GLUI_ALIGN_LEFT);
+ // scrollbar->can_activate = false; //kills ability to mouse drag too
+ }
+ init_live();
+}
+
+/****************************** GLUI_TextBox::mouse_down_handler() **********/
+
+int GLUI_TextBox::mouse_down_handler( int local_x, int local_y )
+{
+ int tmp_insertion_pt;
+
+ if ( debug ) dump( stdout, "-> MOUSE DOWN" );
+
+ tmp_insertion_pt = find_insertion_pt( local_x, local_y );
+ if ( tmp_insertion_pt == -1 ) {
+ if ( glui )
+ glui->deactivate_current_control( );
+ return false;
+ }
+
+ insertion_pt = tmp_insertion_pt;
+
+ sel_start = sel_end = insertion_pt;
+
+ keygoal_x = insert_x;
+
+ if ( can_draw())
+ update_and_draw_text();
+
+ if ( debug ) dump( stdout, "<- MOUSE UP" );
+
+ return true;
+}
+
+
+/******************************** GLUI_TextBox::mouse_up_handler() **********/
+
+int GLUI_TextBox::mouse_up_handler( int local_x, int local_y, bool inside )
+{
+ return false;
+}
+
+
+/***************************** GLUI_TextBox::mouse_held_down_handler() ******/
+
+int GLUI_TextBox::mouse_held_down_handler( int local_x, int local_y,
+ bool new_inside)
+{
+ int tmp_pt;
+
+ if ( NOT new_inside ) return false;
+
+ if ( debug ) dump( stdout, "-> HELD DOWN" );
+
+ tmp_pt = find_insertion_pt( local_x, local_y );
+ keygoal_x = insert_x;
+
+ if ( tmp_pt == -1 AND sel_end != 0 ) { /* moved mouse past left edge */
+ special_handler( GLUT_KEY_LEFT, GLUT_ACTIVE_SHIFT );
+ }
+ else if ( tmp_pt == substring_end+1 AND sel_end != (int) text.length()) {
+ /* moved mouse past right edge */
+ special_handler( GLUT_KEY_RIGHT, GLUT_ACTIVE_SHIFT );
+ }
+ else if ( tmp_pt != -1 AND tmp_pt != sel_end ) {
+ sel_end = insertion_pt = tmp_pt;
+
+ update_and_draw_text();
+ }
+
+ if ( debug )
+ dump( stdout, "<- HELD DOWN" );
+
+ return false;
+}
+
+
+/****************************** GLUI_TextBox::key_handler() **********/
+int GLUI_TextBox::key_handler( unsigned char key,int modifiers )
+{
+ int regular_key;
+ /* int has_selection; */
+
+ if ( NOT glui )
+ return false;
+
+ if ( debug )
+ dump( stdout, "-> KEY HANDLER" );
+
+ regular_key = false;
+ bool ctrl_down = (modifiers & GLUT_ACTIVE_CTRL)!=0;
+ /* has_selection = (sel_start != sel_end); */
+
+ if ( key == CTRL('[')) { /* ESCAPE */
+ glui->deactivate_current_control();
+ return true;
+ }
+ else if ( (key == 127 AND !ctrl_down) OR /* FORWARD DELETE */
+ ( key == CTRL('d') AND modifiers == GLUT_ACTIVE_CTRL) )
+ {
+ if ( sel_start == sel_end ) { /* no selection */
+ if ( insertion_pt < (int)text.length() ) {
+ text.erase(insertion_pt,1);
+ }
+ }
+ else { /* There is a selection */
+ clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end ));
+ insertion_pt = MIN(sel_start,sel_end);
+ sel_start = sel_end = insertion_pt;
+ }
+ }
+ else if ( ((key == 127) AND ctrl_down) OR // Delete word forward
+ ((key == 'd') AND (modifiers == GLUT_ACTIVE_ALT)) )
+ {
+ if ( sel_start == sel_end ) { /* no selection */
+ sel_start = insertion_pt;
+ sel_end = find_word_break( insertion_pt, +1 );
+ }
+
+ clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end ));
+ insertion_pt = MIN(sel_start,sel_end);
+ sel_start = sel_end = insertion_pt;
+ }
+ else if ( key == CTRL('h') ) { /* BACKSPACE */
+ if ( sel_start == sel_end ) { /* no selection */
+ if ( insertion_pt > 0 ) {
+ insertion_pt--;
+ text.erase(insertion_pt,1);
+ }
+ }
+ else { /* There is a selection */
+ clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end ));
+ insertion_pt = MIN(sel_start,sel_end);
+ sel_start = sel_end = insertion_pt;
+ }
+ }
+ else if ( modifiers == GLUT_ACTIVE_CTRL ) /* CTRL ONLY */
+ {
+ /* Ctrl-key bindings */
+ if ( key == CTRL('a') ) {
+ return special_handler( GLUT_KEY_HOME, 0 );
+ }
+ else if ( key == CTRL('e') ) {
+ return special_handler( GLUT_KEY_END, 0 );
+ }
+ else if ( key == CTRL('b') ) {
+ return special_handler( GLUT_KEY_LEFT, 0 );
+ }
+ else if ( key == CTRL('f') ) {
+ return special_handler( GLUT_KEY_RIGHT, 0 );
+ }
+ else if ( key == CTRL('p') ) {
+ return special_handler( GLUT_KEY_UP, 0 );
+ }
+ else if ( key == CTRL('n') ) {
+ return special_handler( GLUT_KEY_DOWN, 0 );
+ }
+ else if ( key == CTRL('u') ) { /* ERASE LINE */
+ insertion_pt = 0;
+ text.erase(0,text.length());
+ sel_start = sel_end = 0;
+ }
+ else if ( key == CTRL('k') ) { /* KILL TO END OF LINE */
+ sel_start = sel_end = insertion_pt;
+ text.erase(insertion_pt,GLUI_String::npos);
+ }
+ }
+ else if ( modifiers == GLUT_ACTIVE_ALT ) /* ALT ONLY */
+ {
+ if ( key == 'b' ) { // Backward word
+ return special_handler ( GLUT_KEY_LEFT, GLUT_ACTIVE_CTRL );
+ }
+ if ( key == 'f' ) { // Forward word
+ return special_handler ( GLUT_KEY_RIGHT, GLUT_ACTIVE_CTRL );
+ }
+ }
+ else if ( (modifiers & GLUT_ACTIVE_CTRL) OR
+ (modifiers & GLUT_ACTIVE_ALT) )
+ {
+ /** ignore other keys with modifiers */
+ return true;
+ }
+ else { /* Regular key */
+ if ( key == 13 ) /* RETURNS are written as newlines*/
+ key = '\n';
+
+ regular_key = true;
+
+ /** This is just to get rid of warnings - the flag regular_key is
+ set if the key was not a backspace, return, whatever. But I
+ believe if we're here, we know it was a regular key anyway */
+ if ( regular_key ) {
+ }
+
+ /**** If there's a current selection, erase it ******/
+ if ( sel_start != sel_end ) {
+ clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end ));
+ insertion_pt = MIN(sel_start,sel_end);
+ sel_start = sel_end = insertion_pt;
+ }
+
+ /******** We insert the character into the string ***/
+
+ text.insert(insertion_pt,1,key);
+
+ /******** Move the insertion point and substring_end one over ******/
+ insertion_pt++;
+ substring_end++;
+
+ sel_start = sel_end = insertion_pt;
+ }
+
+ /******** Now redraw text ***********/
+ /* Hack to prevent text box from being cleared first **/
+ /** int substring_change = update_substring_bounds();
+ draw_text_only =
+ (NOT substring_change AND NOT has_selection AND regular_key );
+ */
+
+ draw_text_only = false; /** Well, hack is not yet working **/
+ update_and_draw_text();
+ draw_text_only = false;
+
+
+ if ( debug )
+ dump( stdout, "<- KEY HANDLER" );
+
+ return true;
+}
+
+/****************************** GLUI_TextBox::enable() **********/
+
+void GLUI_TextBox::enable( void )
+{
+ GLUI_Control::enable();
+ scrollbar->enable();
+}
+
+/****************************** GLUI_TextBox::disable() **********/
+
+void GLUI_TextBox::disable( void )
+{
+ GLUI_Control::disable();
+ scrollbar->disable();
+}
+
+/****************************** GLUI_TextBox::activate() **********/
+
+void GLUI_TextBox::activate( int how )
+{
+ if ( debug )
+ dump( stdout, "-> ACTIVATE" );
+ active = true;
+
+ if ( how == GLUI_ACTIVATE_MOUSE )
+ return; /* Don't select everything if activated with mouse */
+
+ orig_text = text;
+
+ sel_start = 0;
+ sel_end = text.length();
+ insertion_pt = 0;
+ if ( debug )
+ dump( stdout, "<- ACTIVATE" );
+}
+
+
+/****************************** GLUI_TextBox::deactivate() **********/
+
+void GLUI_TextBox::deactivate( void )
+{
+ active = false;
+
+ if ( NOT glui )
+ return;
+
+ if ( debug )
+ dump( stdout, "-> DISACTIVATE" );
+
+ sel_start = sel_end = insertion_pt = -1;
+
+ /***** Retrieve the current value from the text *****/
+ /***** The live variable will be updated by set_text() ****/
+ set_text(text.c_str()); /* This will force callbacks and gfx refresh */
+
+ update_substring_bounds();
+
+ /******** redraw text without insertion point ***********/
+ redraw();
+
+ /***** Now do callbacks if value changed ******/
+ if ( orig_text != text ) {
+ this->execute_callback();
+
+
+ }
+
+
+ if ( debug )
+ dump( stdout, "<- DISACTIVATE" );
+}
+
+/****************************** GLUI_TextBox::draw() **********/
+
+void GLUI_TextBox::draw( int x, int y )
+{
+ GLUI_DRAWINGSENTINAL_IDIOM
+ int line = 0;
+ int text_length;
+ int box_width;
+ int i;
+
+ /* Bevelled Border */
+ glBegin( GL_LINES );
+ glColor3f( .5, .5, .5 );
+ glVertex2i( 0, 0 ); glVertex2i( w, 0 );
+ glVertex2i( 0, 0 ); glVertex2i( 0, h );
+
+ glColor3f( 1., 1., 1. );
+ glVertex2i( 0, h ); glVertex2i( w, h );
+ glVertex2i( w, h ); glVertex2i( w, 0 );
+
+ if ( enabled )
+ glColor3f( 0., 0., 0. );
+ else
+ glColor3f( .25, .25, .25 );
+ glVertex2i( 1, 1 ); glVertex2i( w-1, 1 );
+ glVertex2i( 1, 1 ); glVertex2i( 1, h-1 );
+
+ glColor3f( .75, .75, .75 );
+ glVertex2i( 1, h-1 ); glVertex2i( w-1, h-1 );
+ glVertex2i( w-1, h-1 ); glVertex2i( w-1, 1 );
+ glEnd();
+
+ /* Draw Background if enabled*/
+ if (enabled) {
+ glColor3f( 1., 1., 1. );
+ glDisable( GL_CULL_FACE );
+ glBegin( GL_QUADS );
+ glVertex2i( 2, 2 ); glVertex2i( w-2, 2 );
+ glVertex2i( w-2, h-2 ); glVertex2i(2, h-2 );
+ glEnd();
+ } else {
+ glColor3f( .8, .8, .8 );
+ glDisable( GL_CULL_FACE );
+ glBegin( GL_QUADS );
+ glVertex2i( 2, 2 ); glVertex2i( w-2, 2 );
+ glVertex2i( w-2, h-2 ); glVertex2i(2, h-2 );
+ glEnd();
+ }
+
+ /* Begin Drawing Lines of Text */
+ substring_start = 0;
+ substring_end = 0;
+ text_length = text.length()-1;
+
+ /* Figure out how wide the box is */
+ box_width = get_box_width();
+
+ /* Get the first line substring */
+ while (substring_width(substring_start, substring_end+1 ) < box_width &&
+ substring_end < text_length && text[substring_end+1] != '\n')
+ substring_end++;
+
+ /* Figure out which lines are visible*/
+
+ visible_lines = (int)(h-20)/LINE_HEIGHT;
+ if (start_line < (curr_line-visible_lines)) {
+ for (i = 0; ((curr_line-i)*LINE_HEIGHT+20) > h; i++);
+ start_line = i;
+ } else if ( start_line > curr_line) {
+ start_line = curr_line;
+ }
+ line = 0;
+ do {
+ if (line && substring_end < text_length) {
+ substring_start = substring_end+1;
+ while (substring_width(substring_start, substring_end+1 ) < box_width &&
+ substring_end < text_length && text[substring_end+1] != '\n')
+ substring_end++;
+ }
+ if (text[substring_end+1] == '\n') { /* Skip newline */
+ substring_end++;
+ }
+ if (line < start_line || (line > curr_line && curr_line > (start_line + visible_lines))) {
+ line++;
+ continue;
+ }
+ if ((line - start_line) <= visible_lines)
+ draw_text(0,(line - start_line)*LINE_HEIGHT); /* tabs and other nasties are handled by substring_width */
+ line++;
+ } while (substring_end < text_length);
+
+ num_lines = line;
+
+ draw_insertion_pt();
+ if (scrollbar) {
+ scrollbar->set_int_limits(MAX(0,num_lines/*-1*/-visible_lines),0);
+ glPushMatrix();
+ glTranslatef(scrollbar->x_abs-x_abs, scrollbar->y_abs-y_abs,0.0);
+ scrollbar->draw_scroll();
+ glPopMatrix();
+ }
+}
+
+
+
+/************************** GLUI_TextBox::update_substring_bounds() *********/
+
+int GLUI_TextBox::update_substring_bounds( void )
+{
+ int box_width;
+ int text_len = text.length();
+ int old_start, old_end;
+
+ old_start = substring_start;
+ old_end = substring_end;
+
+ /*** Calculate the width of the usable area of the edit box ***/
+ box_width = get_box_width();
+
+ CLAMP( substring_end, 0, MAX(text_len-1,0) );
+ CLAMP( substring_start, 0, MAX(text_len-1,0) );
+
+ if ( debug ) dump( stdout, "-> UPDATE SS" );
+
+ if ( insertion_pt >= 0 AND
+ insertion_pt < substring_start ) { /* cursor moved left */
+ substring_start = insertion_pt;
+
+ while ( substring_width( substring_start, substring_end ) > box_width )
+ substring_end--;
+ }
+ else if ( insertion_pt > substring_end ) { /* cursor moved right */
+ substring_end = insertion_pt-1;
+
+ while ( substring_width( substring_start, substring_end ) > box_width )
+ substring_start++;
+ }
+ else { /* cursor is within old substring bounds */
+ if ( last_insertion_pt > insertion_pt ) { /* cursor moved left */
+ }
+ else {
+ while ( substring_width( substring_start, substring_end ) > box_width )
+ substring_end--;
+
+ while(substring_width( substring_start, substring_end+1 ) <= box_width
+ AND substring_end < text_len-1 )
+ substring_end++;
+ }
+ }
+
+ while ( substring_width( substring_start, substring_end ) > box_width )
+ substring_end--;
+
+ last_insertion_pt = insertion_pt;
+
+ /*** No selection if not enabled ***/
+ if ( NOT enabled ) {
+ sel_start = sel_end = 0;
+ }
+
+ if ( debug ) dump( stdout, "<- UPDATE SS" );
+
+ if ( substring_start == old_start AND substring_end == old_end )
+ return false; /*** bounds did not change ***/
+ else
+ return true; /*** bounds did change ***/
+
+}
+
+
+/********************************* GLUI_TextBox::update_x_offsets() *********/
+
+void GLUI_TextBox::update_x_offsets( void )
+{
+}
+
+
+/********************************* GLUI_TextBox::draw_text() ****************/
+
+void GLUI_TextBox::draw_text( int x, int y )
+{
+ GLUI_DRAWINGSENTINAL_IDIOM
+ int text_x, i, sel_lo, sel_hi, x_pos;
+
+ if ( debug ) dump( stdout, "-> DRAW_TEXT" );
+
+ /** Find where to draw the text **/
+
+ text_x = 2 + GLUI_TEXTBOX_BOXINNERMARGINX;
+
+ /** Find lower and upper selection bounds **/
+ sel_lo = MIN(sel_start, sel_end );
+ sel_hi = MAX(sel_start, sel_end );
+
+ int sel_x_start, sel_x_end, delta;
+
+ /** Draw selection area dark **/
+ if ( sel_start != sel_end ) {
+ sel_x_start = text_x;
+ sel_x_end = text_x;
+ delta = 0;
+ for( i=substring_start; sel_x_end < (w - text_x) && i<=substring_end; i++ ) {
+ delta = 0;
+ if (text[i] == '\t') // Character is a tab, go to next tab stop
+ while (((delta + sel_x_end) < (w - text_x)) &&
+ (delta == 0 || delta % tab_width))
+ delta++;
+ else
+ delta = char_width( text[i] );
+
+ if ( i < sel_lo ) {
+ sel_x_start += delta;
+ sel_x_end += delta;
+ }
+ else if ( i < sel_hi ) {
+ sel_x_end += delta;
+ }
+ }
+
+ glColor3f( 0.0f, 0.0f, .6f );
+ glRecti(sel_x_start, y+5, sel_x_end, y+20);
+ }
+
+
+ if ( sel_start == sel_end ) { // No current selection
+ x_pos = text_x;
+ if ( enabled )
+ glColor3b( 0, 0, 0 );
+ else
+ glColor3b( 32, 32, 32 );
+
+ glRasterPos2i( text_x, y+LINE_HEIGHT);
+ for( i=substring_start; i<=substring_end; i++ ) {
+ if (this->text[i] == '\t') { // Character is a tab, go to next tab stop
+ x_pos = ((x_pos-text_x)/tab_width)*tab_width+tab_width+text_x;
+ glRasterPos2i( x_pos, y+LINE_HEIGHT); // Reposition pen after tab
+ } else {
+ glutBitmapCharacter( get_font(), this->text[i] );
+ x_pos += char_width( this->text[i] );
+ }
+ }
+ }
+ else { // There is a selection
+ x_pos = text_x;
+ for( i=substring_start; i<=substring_end; i++ ) {
+ if ( IN_BOUNDS( i, sel_lo, sel_hi-1)) { // This character is selected
+ glColor3f( 1., 1., 1. );
+ glRasterPos2i( x_pos, y+LINE_HEIGHT);
+ if (this->text[i] == '\t') { // Character is a tab, go to next tab stop
+ x_pos = ((x_pos-text_x)/tab_width)*tab_width+tab_width+text_x;
+ }
+ else
+ glutBitmapCharacter( get_font(), this->text[i] );
+ }
+ else {
+ glColor3f( 0., 0., 0. );
+ glRasterPos2i( x_pos, y+LINE_HEIGHT);
+ if (this->text[i] == '\t') { // Character is a tab, go to next tab stop
+ x_pos = ((x_pos-text_x)/tab_width)*tab_width+tab_width+text_x;
+ glRasterPos2i( x_pos, y+LINE_HEIGHT); // Reposition pen after tab
+ } else
+ glutBitmapCharacter( get_font(), this->text[i] );
+ }
+
+ x_pos += char_width( text[i] );
+ }
+ }
+
+ if ( debug ) dump( stdout, "<- DRAW_TEXT" );
+}
+
+
+/******************************** GLUI_TextBox::find_insertion_pt() *********/
+/* This function returns the character number *before which* the insertion */
+/* point goes */
+
+int GLUI_TextBox::find_insertion_pt( int x, int y )
+{
+ /*** See if we clicked outside box ***/
+ if ( x < this->x_abs || y < this->y_abs)
+ return -1;
+
+ /*** See if we clicked in an empty box ***/
+ if ( text.empty() )
+ return 0;
+
+ /* update insert variables */
+ insert_x = x;
+ insert_y = y;
+
+ int text_length = text.length()-1;
+ int box_width = get_box_width();
+
+ int sol = 0;
+ int eol = 0;
+ int line = 0;
+
+ int y_off = y - (y_abs + 2 + GLUI_TEXTBOX_BOXINNERMARGINX);
+ int x_off = x - (x_abs + 2 + GLUI_TEXTBOX_BOXINNERMARGINX);
+
+ /* Find the line clicked,
+ The possibility of long lines getting wrapped complicates this. */
+ while ((line-start_line+1)*LINE_HEIGHT < y_off && eol < text_length)
+ {
+ while (eol < text_length && text[eol] != '\n' &&
+ substring_width(sol, eol+1) <= box_width)
+ {
+ eol++;
+ }
+ if (text[eol]=='\n' && eol<text_length) { eol++; }
+ line++;
+ sol = eol;
+ }
+ curr_line = line;
+ // Now search to the end of this line for the closest insertion point
+ int prev_w=0,total_w=0,prev_eol=eol;
+ while (eol <= text_length
+ && (total_w=substring_width(prev_eol,eol,prev_w))< x_off
+ && (eol==text_length||text[eol]!='\n'))
+ {
+ prev_w=total_w;
+ eol++;
+ prev_eol=eol;
+ }
+ if (total_w>=x_off) {
+ // did we go far enough? (see if click was >1/2 width of last char)
+ int decision_pt = prev_w+(total_w-prev_w)/2;
+ if (x_off>decision_pt) eol++;
+ }
+ return eol;
+
+#if 0
+ while (eol < text_length && text[eol] != '\n' &&
+ substring_width(sol, eol+1) < box_width )
+ {
+ eol++;
+ }
+
+
+ /* We move from right to left, looking to see if the mouse was clicked
+ to the right of the ith character */
+#if 0
+ int curr_x = this->x_abs
+ + substring_width( sol, eol )
+ + 2 /* The edittext box has a 2-pixel margin */
+ + GLUI_TEXTBOX_BOXINNERMARGINX; /** plus this many pixels blank space
+ between the text and the box **/
+#endif
+
+ /** find mouse click in text **/
+
+ if (x_off > substring_width(sol, eol))
+ return eol;
+
+ for(i = sol; i <= eol+1; i++) {
+ if (x_off <= substring_width(sol, i))
+ return i+1;
+ }
+ return 0;
+#endif
+}
+
+
+int GLUI_TextBox::get_box_width()
+{
+ return MAX( this->w
+ - 4 /* 2 * the two-line box border */
+ - 2 * GLUI_TEXTBOX_BOXINNERMARGINX, 0 );
+
+}
+
+/******************************** GLUI_TextBox::draw_insertion_pt() *********/
+
+void GLUI_TextBox::draw_insertion_pt( void )
+{
+ int curr_x, box_width, text_length, eol, sol, line;
+
+ if ( NOT can_draw() )
+ return;
+
+ /*** Don't draw insertion pt if control is disabled ***/
+ if ( NOT enabled )
+ return;
+
+ if ( sel_start != sel_end OR insertion_pt < 0 ) {
+ return; /* Don't draw insertion point if there is a current selection */
+ }
+
+ if ( debug ) dump( stdout, "-> DRAW_INS_PT" );
+
+ /* printf( "insertion pt: %d\n", insertion_pt ); */
+
+ box_width = get_box_width();
+
+ // This function is unable to distinguish whether an insertion
+ // point on a line break should be drawn on the line before or the line after.
+ // This depends on the sequence of operations used to get there, and this
+ // function just doesn't have that information. If curr_line were kept up
+ // to date elsewhere that could be used here to disambiguate, but arrow keys
+ // and such do not update it.
+
+ sol = 0;
+ eol = 0;
+ text_length = text.length()-1;
+
+ //while (eol < text_length && text[eol] != '\n'
+ // && substring_width(sol, eol + 1) < box_width )
+ // eol++;
+ line = 0;
+ while (eol < insertion_pt && eol <= text_length)
+ {
+ if (text[eol] == '\n' || substring_width(sol, eol + 1) >= box_width)
+ {
+ eol++;
+ if (text[eol]=='\n'||eol!=insertion_pt
+ ||(eol==insertion_pt && eol>0 && text[eol-1]=='\n')) {
+ sol = eol;
+ line++;
+ }
+ }
+ else {
+ eol++;
+ }
+ }
+
+ //glColor3f(1,0,0);
+ //glRecti(0, curr_line*LINE_HEIGHT, 3, (curr_line+1)*LINE_HEIGHT);
+
+ curr_line = line;
+
+ if (scrollbar)
+ scrollbar->set_int_val(start_line);
+ if (curr_line < start_line || curr_line > (start_line + visible_lines)) /* Insertion pt out of draw area */
+ return;
+
+ curr_x = this->x_abs
+ + 2 /* The edittext box has a 2-pixel margin */
+ + GLUI_TEXTBOX_BOXINNERMARGINX; /** plus this many pixels blank space
+ between the text and the box **/
+
+ curr_x += substring_width(sol,insertion_pt-1);
+ if (insertion_pt == text.length() && text[text.length()-1] == '\n'
+ || curr_x-this->x_abs > (w - 2 - GLUI_TEXTBOX_BOXINNERMARGINX)) { // Insert on the next line
+ curr_x = this->x_abs + GLUI_TEXTBOX_BOXINNERMARGINX;
+ line++;
+ }
+ /* update insertion coordinates */
+ insert_x = curr_x+5; /* I hate magic numbers too, these offset the imagined insertion point */
+ insert_y = (curr_line-start_line+2)*LINE_HEIGHT;
+
+
+ glColor3f( 0.0, 0.0, 0.0 );
+ glBegin( GL_LINE_LOOP );
+
+ curr_x -= x_abs;
+ glVertex2i( curr_x+1, (curr_line-start_line)*LINE_HEIGHT + 4 );
+ glVertex2i( curr_x, (curr_line-start_line)*LINE_HEIGHT + 4 );
+ glVertex2i( curr_x+1, (curr_line-start_line)*LINE_HEIGHT + 16 );
+ glVertex2i( curr_x, (curr_line-start_line)*LINE_HEIGHT + 16 );
+ glEnd();
+
+
+ if ( debug ) dump( stdout, "-> DRAW_INS_PT" );
+}
+
+
+
+
+/******************************** GLUI_TextBox::substring_width() *********/
+int GLUI_TextBox::substring_width( int start, int end, int initial_width )
+{
+ // This function only works properly if start is really the start of a line.
+ // Otherwise tabs will be messed up.
+ int i, width = initial_width;
+
+ for( i=start; i<=end; i++ )
+ if (text[i] == '\t') { // Character is a tab, jump to next tab stop
+ width += tab_width-(width%tab_width);
+ //while (width == 0 || width % tab_width)
+ // width++;
+ }
+ else
+ width += char_width( text[i] );
+
+ return width;
+}
+
+
+/***************************** GLUI_TextBox::update_and_draw_text() ********/
+
+void GLUI_TextBox::update_and_draw_text( void )
+{
+ //update_substring_bounds();
+ /* printf( "ss: %d/%d\n", substring_start, substring_end ); */
+
+ redraw();
+}
+
+
+/********************************* GLUI_TextBox::special_handler() **********/
+
+int GLUI_TextBox::special_handler( int key,int modifiers )
+{
+ int tmp_insertion_pt;
+ if ( NOT glui )
+ return false;
+
+ if ( debug )
+ printf( "SPECIAL:%d - mod:%d subs:%d/%d ins:%d sel:%d/%d\n",
+ key, modifiers, substring_start, substring_end,insertion_pt,
+ sel_start, sel_end );
+
+ if ( key == GLUT_KEY_DOWN ) {
+ if (insert_x == -1 || insert_y == -1)
+ return false;
+ tmp_insertion_pt = find_insertion_pt( keygoal_x, insert_y+LINE_HEIGHT);
+ if (tmp_insertion_pt < 0)
+ return false;
+ insertion_pt = tmp_insertion_pt;
+ sel_end = insertion_pt;
+ if (!(modifiers & GLUT_ACTIVE_SHIFT)) {
+ sel_start = sel_end;
+ }
+ if ( can_draw())
+ update_and_draw_text();
+ } else if ( key == GLUT_KEY_UP ) {
+ if (insert_x == -1 || insert_y == -1)
+ return false;
+ tmp_insertion_pt = find_insertion_pt( keygoal_x, insert_y-LINE_HEIGHT);
+ if (tmp_insertion_pt < 0)
+ return false;
+ insertion_pt = tmp_insertion_pt;
+ sel_end = insertion_pt;
+ if (!(modifiers & GLUT_ACTIVE_SHIFT)) {
+ sel_start = sel_end;
+ }
+ if ( can_draw())
+ update_and_draw_text();
+ } else if ( key == GLUT_KEY_LEFT ) {
+ if ( (modifiers & GLUT_ACTIVE_CTRL) != 0 ) {
+ insertion_pt = find_word_break( insertion_pt, -1 );
+ }
+ else {
+ insertion_pt--;
+ }
+ // update keygoal_x!
+ }
+ else if ( key == GLUT_KEY_RIGHT ) {
+ if ( (modifiers & GLUT_ACTIVE_CTRL) != 0 ) {
+ insertion_pt = find_word_break( insertion_pt, +1 );
+ }
+ else {
+ insertion_pt++;
+ }
+ // update keygoal_x!
+ }
+ else if ( key == GLUT_KEY_HOME ) {
+ insertion_pt = 0;
+ // update keygoal_x!
+ }
+ else if ( key == GLUT_KEY_END ) {
+ insertion_pt = text.length();
+ // update keygoal_x!
+ }
+
+ /*** Update selection if shift key is down ***/
+ if ( (modifiers & GLUT_ACTIVE_SHIFT ) != 0 )
+ sel_end = insertion_pt;
+ else
+ sel_start = sel_end = insertion_pt;
+
+
+ CLAMP( insertion_pt, 0, (int)text.length()); /* Make sure insertion_pt
+ is in bounds */
+ CLAMP( sel_start, 0, (int)text.length()); /* Make sure insertion_pt
+ is in bounds */
+ CLAMP( sel_end, 0, (int)text.length()); /* Make sure insertion_pt
+ is in bounds */
+
+ /******** Now redraw text ***********/
+ if ( can_draw())
+ update_and_draw_text();
+
+ return true;
+}
+
+
+/****************************** GLUI_TextBox::find_word_break() **********/
+/* It looks either left or right (depending on value of 'direction' */
+/* for the beginning of the next 'word', where word are characters */
+/* separated by one of the following tokens: " :-.," */
+/* If there is no next word in the specified direction, this returns */
+/* the beginning of 'text', or the very end. */
+
+int GLUI_TextBox::find_word_break( int start, int direction )
+{
+ int i, j;
+ char breaks[] = " \n\t:-.,";
+ int num_break_chars = (int)strlen(breaks), text_len = text.length();
+ int new_pt;
+
+ /** If we're moving left, we have to start two back, in case we're either
+ already at the beginning of a word, or on a separating token.
+ Otherwise, this function would just return the word we're already at **/
+ if ( direction == -1 ) {
+ start -= 2;
+ }
+
+ /***** Iterate over text in the specified direction *****/
+ for ( i=start; i >= 0 AND i < text_len; i += direction ) {
+
+ /** For each character in text, iterate over list of separating tokens **/
+ for( j=0; j<num_break_chars; j++ ) {
+ if ( text[i] == breaks[j] ) {
+
+ /** character 'i' is a separating token, so we return i+1 **/
+ new_pt = i + 1;
+
+ CLAMP( new_pt, 0, text_len );
+
+ return new_pt;
+ }
+ }
+ }
+
+ if ( direction > 0 ) /* Return the end of string */
+ return text_len;
+ else /* Return the beginning of the text */
+ return 0;
+}
+
+
+/********************************** GLUI_TextBox::clear_substring() ********/
+
+void GLUI_TextBox::clear_substring( int start, int end )
+{
+ text.erase(start,end-start);
+}
+
+
+
+/************************************ GLUI_TextBox::update_size() **********/
+
+void GLUI_TextBox::update_size( void )
+{
+ if ( NOT glui )
+ return;
+
+ if ( w < GLUI_TEXTBOX_MIN_TEXT_WIDTH )
+ w = GLUI_TEXTBOX_MIN_TEXT_WIDTH;
+}
+
+
+/****************************** GLUI_TextBox::set_text() **********/
+
+void GLUI_TextBox::set_text( const char *new_text )
+{
+ text = new_text;
+
+ substring_start = 0;
+ substring_end = text.length() - 1;
+ insertion_pt = -1;
+ sel_start = 0;
+ sel_end = 0;
+ visible_lines = 0;
+ start_line = 0;
+ curr_line = 0;
+ num_lines = 0;
+
+ if ( can_draw() )
+ update_and_draw_text();
+
+ /*** Now update the live variable ***/
+ output_live(true);
+}
+
+
+/*************************************** GLUI_TextBox::dump() **************/
+
+void GLUI_TextBox::dump( FILE *out, char *name )
+{
+ fprintf( out,
+ "%s (edittext@%p): line:%d ins_pt:%d subs:%d/%d sel:%d/%d len:%d\n",
+ name, this, curr_line,
+ insertion_pt, substring_start, substring_end, sel_start, sel_end,
+ text.length());
+}
+
+
+/**************************************** GLUI_TextBox::mouse_over() ********/
+
+int GLUI_TextBox::mouse_over( int state, int x, int y )
+{
+ if ( state && enabled) {
+ /* curr_cursor = GLUT_CURSOR_TEXT; */
+ glutSetCursor( GLUT_CURSOR_TEXT );
+ }
+ else {
+ /* printf( "OUT\n" ); */
+ glutSetCursor( GLUT_CURSOR_LEFT_ARROW );
+ }
+
+ return true;
+}
+
+void GLUI_TextBox::scrollbar_callback(GLUI_Control *my_scrollbar) {
+ GLUI_Scrollbar *sb = dynamic_cast<GLUI_Scrollbar*>(my_scrollbar);
+ if (!sb) return;
+ GLUI_TextBox* me = (GLUI_TextBox*) sb->associated_object;
+ if (me->scrollbar == NULL)
+ return;
+ int new_start_line = sb->get_int_val(); // ??
+ me->start_line = new_start_line;
+ if (new_start_line < (me->curr_line - me->visible_lines))
+ me->curr_line = new_start_line + me->visible_lines;
+ if (new_start_line > me->curr_line)
+ me->curr_line = new_start_line;
+ if ( me->can_draw() )
+ me->update_and_draw_text();
+}
diff --git a/tests/box2d/glui/glui_translation.cpp b/tests/box2d/glui/glui_translation.cpp new file mode 100755 index 00000000..73b1fa32 --- /dev/null +++ b/tests/box2d/glui/glui_translation.cpp @@ -0,0 +1,559 @@ +/****************************************************************************
+
+ GLUI User Interface Toolkit
+ ---------------------------
+
+ glui_translation - GLUI_Translation control class
+
+
+ --------------------------------------------------
+
+ Copyright (c) 1998 Paul Rademacher
+
+ WWW: http://sourceforge.net/projects/glui/
+ Forums: http://sourceforge.net/forum/?group_id=92496
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+#include "glui.h"
+#include "glui_internal.h"
+#include "algebra3.h"
+
+/********************** GLUI_Translation::GLUI_Translation() ***/
+
+GLUI_Translation::GLUI_Translation(
+ GLUI_Node *parent, const char *name,
+ int trans_t, float *value_ptr,
+ int id, GLUI_CB cb )
+{
+ common_init();
+
+ set_ptr_val( value_ptr );
+ user_id = id;
+ set_name( name );
+ callback = cb;
+ parent->add_control( this );
+ //init_live();
+
+ trans_type = trans_t;
+
+ if ( trans_type == GLUI_TRANSLATION_XY ) {
+ float_array_size = 2;
+ }
+ else if ( trans_type == GLUI_TRANSLATION_X ) {
+ float_array_size = 1;
+ }
+ else if ( trans_type == GLUI_TRANSLATION_Y ) {
+ float_array_size = 1;
+ }
+ else if ( trans_type == GLUI_TRANSLATION_Z ) {
+ float_array_size = 1;
+ }
+ init_live();
+}
+
+/********************** GLUI_Translation::iaction_mouse_down_handler() ***/
+/* These are really in local coords (5/10/99) */
+
+int GLUI_Translation::iaction_mouse_down_handler( int local_x,
+ int local_y )
+{
+ int center_x, center_y;
+
+ down_x = local_x;
+ down_y = local_y;
+
+ if ( trans_type == GLUI_TRANSLATION_XY ) {
+ orig_x = float_array_val[0];
+ orig_y = float_array_val[1];
+
+ /** Check if the Alt key is down, which means lock to an axis **/
+
+ center_x = w/2;
+ center_y = (h-18)/2;
+
+ if ( glui->curr_modifiers & GLUT_ACTIVE_ALT ) {
+ if ( ABS(local_y-center_y) > ABS(local_x-center_x) ) {
+ locked = GLUI_TRANSLATION_LOCK_Y;
+ glutSetCursor( GLUT_CURSOR_UP_DOWN );
+ }
+ else {
+ locked = GLUI_TRANSLATION_LOCK_X;
+ glutSetCursor( GLUT_CURSOR_LEFT_RIGHT );
+ }
+ }
+ else {
+ locked = GLUI_TRANSLATION_LOCK_NONE;
+ glutSetCursor( GLUT_CURSOR_SPRAY );
+ }
+ }
+ else if ( trans_type == GLUI_TRANSLATION_X ) {
+ glutSetCursor( GLUT_CURSOR_LEFT_RIGHT );
+ orig_x = float_array_val[0];
+ }
+ else if ( trans_type == GLUI_TRANSLATION_Y ) {
+ glutSetCursor( GLUT_CURSOR_UP_DOWN );
+ orig_y = float_array_val[0];
+ }
+ else if ( trans_type == GLUI_TRANSLATION_Z ) {
+ glutSetCursor( GLUT_CURSOR_UP_DOWN );
+ orig_z = float_array_val[0];
+ }
+
+ trans_mouse_code = 1;
+ redraw();
+
+ return false;
+}
+
+
+/*********************** GLUI_Translation::iaction_mouse_up_handler() **********/
+
+int GLUI_Translation::iaction_mouse_up_handler( int local_x, int local_y,
+ bool inside )
+{
+ trans_mouse_code = GLUI_TRANSLATION_MOUSE_NONE;
+ locked = GLUI_TRANSLATION_LOCK_NONE;
+
+ redraw();
+
+ return false;
+}
+
+
+/******************* GLUI_Translation::iaction_mouse_held_down_handler() ******/
+
+int GLUI_Translation::iaction_mouse_held_down_handler( int local_x, int local_y,
+ bool inside)
+{
+ float x_off, y_off;
+ float off_array[2];
+
+ x_off = scale_factor * (float)(local_x - down_x);
+ y_off = -scale_factor * (float)(local_y - down_y);
+
+ if ( glui->curr_modifiers & GLUT_ACTIVE_SHIFT ) {
+ x_off *= 100.0f;
+ y_off *= 100.0f;
+ }
+ else if ( glui->curr_modifiers & GLUT_ACTIVE_CTRL ) {
+ x_off *= .01f;
+ y_off *= .01f;
+ }
+
+
+ if ( trans_type == GLUI_TRANSLATION_XY ) {
+
+ if ( locked == GLUI_TRANSLATION_LOCK_X )
+ y_off = 0.0;
+ else if ( locked == GLUI_TRANSLATION_LOCK_Y )
+ x_off = 0.0;
+
+ off_array[0] = x_off + orig_x;
+ off_array[1] = y_off + orig_y;
+ }
+ else if ( trans_type == GLUI_TRANSLATION_X ) {
+ off_array[0] = x_off + orig_x;
+ }
+ else if ( trans_type == GLUI_TRANSLATION_Y ) {
+ off_array[0] = y_off + orig_y;
+ }
+ else if ( trans_type == GLUI_TRANSLATION_Z ) {
+ off_array[0] = y_off + orig_z;
+ }
+
+ set_float_array_val( (float*) &off_array[0] );
+
+ return false;
+}
+
+
+/******************** GLUI_Translation::iaction_draw_active_area_persp() **************/
+
+void GLUI_Translation::iaction_draw_active_area_persp( void )
+{
+}
+
+
+/******************** GLUI_Translation::iaction_draw_active_area_ortho() **********/
+
+void GLUI_Translation::iaction_draw_active_area_ortho( void )
+{
+ /********* Draw emboss circles around arcball control *********/
+ float radius;
+ radius = (float)(h-22)/2.0; /* MIN((float)w/2.0, (float)h/2.0); */
+ glLineWidth( 1.0 );
+
+ draw_emboss_box( (int) -radius-2, (int)radius+2,
+ (int)-radius-2, (int)radius+2 );
+
+ glMatrixMode( GL_MODELVIEW );
+ glPushMatrix();
+ glTranslatef( .5, .5, .5 );
+ /* glScalef( radius-1.0, radius-1.0, radius-1.0 ); */
+ if ( trans_type == GLUI_TRANSLATION_Z )
+ draw_2d_z_arrows((int)radius-1);
+ else if ( trans_type == GLUI_TRANSLATION_XY )
+ draw_2d_xy_arrows((int)radius-1);
+ else if ( trans_type == GLUI_TRANSLATION_X )
+ draw_2d_x_arrows((int)radius-1);
+ else if ( trans_type == GLUI_TRANSLATION_Y )
+ draw_2d_y_arrows((int)radius-1);
+
+ glPopMatrix();
+}
+
+
+/******************************** GLUI_Translation::iaction_dump() **********/
+
+void GLUI_Translation::iaction_dump( FILE *output )
+{
+}
+
+
+/******************** GLUI_Translation::iaction_special_handler() **********/
+
+int GLUI_Translation::iaction_special_handler( int key,int modifiers )
+{
+
+ return false;
+}
+
+
+
+/*************************** GLUI_Translation::draw_2d_z_arrows() **************/
+
+void GLUI_Translation::draw_2d_z_arrows( int radius )
+{
+ if ( trans_mouse_code != GLUI_TRANSLATION_MOUSE_NONE ) {
+ draw_2d_arrow(radius, true, 2);
+ draw_2d_arrow(radius, true, 0);
+ }
+ else {
+ draw_2d_arrow(radius, false, 2);
+ draw_2d_arrow(radius, false, 0);
+ }
+}
+
+
+/*************************** GLUI_Translation::draw_2d_x_arrows() **************/
+
+void GLUI_Translation::draw_2d_x_arrows( int radius )
+{
+ if ( trans_mouse_code != GLUI_TRANSLATION_MOUSE_NONE ) {
+ draw_2d_arrow(radius, true, 1);
+ draw_2d_arrow(radius, true, 3);
+ }
+ else {
+ draw_2d_arrow(radius, false, 1);
+ draw_2d_arrow(radius, false, 3);
+ }
+}
+
+
+/*************************** GLUI_Translation::draw_2d_y_arrows() **************/
+
+void GLUI_Translation::draw_2d_y_arrows( int radius )
+{
+ if ( trans_mouse_code != GLUI_TRANSLATION_MOUSE_NONE ) {
+ draw_2d_arrow(radius, true, 0);
+ draw_2d_arrow(radius, true, 2);
+ }
+ else {
+ draw_2d_arrow(radius, false, 0);
+ draw_2d_arrow(radius, false, 2);
+ }
+}
+
+
+/************************** GLUI_Translation::draw_2d_xy_arrows() **************/
+
+void GLUI_Translation::draw_2d_xy_arrows( int radius)
+{
+ if ( trans_mouse_code != GLUI_TRANSLATION_MOUSE_NONE ) {
+ if ( locked == GLUI_TRANSLATION_LOCK_X ) {
+ draw_2d_arrow(radius, false, 0);
+ draw_2d_arrow(radius, false, 2);
+ draw_2d_arrow(radius, true, 1);
+ draw_2d_arrow(radius, true, 3);
+ }
+ else if ( locked == GLUI_TRANSLATION_LOCK_Y ) {
+ draw_2d_arrow(radius, false, 1);
+ draw_2d_arrow(radius, false, 3);
+ draw_2d_arrow(radius, true, 0);
+ draw_2d_arrow(radius, true, 2);
+ }
+ else {
+ draw_2d_arrow(radius, true, 0);
+ draw_2d_arrow(radius, true, 1);
+ draw_2d_arrow(radius, true, 2);
+ draw_2d_arrow(radius, true, 3);
+ }
+ }
+ else {
+ draw_2d_arrow(radius, false, 0);
+ draw_2d_arrow(radius, false, 1);
+ draw_2d_arrow(radius, false, 2);
+ draw_2d_arrow(radius, false, 3);
+ }
+
+ return;
+}
+
+
+/*************************** GLUI_Translation::draw_2d_arrow() **************/
+/* ori: 0=up, 1=left, 2=down, 3=right */
+/* */
+/* */
+/* 0, y2 */
+/* / \ */
+/* / \ */
+/* / \ */
+/* / \ */
+/* / \ */
+/* / \ */
+/* / \ */
+/* / \ */
+/* -x2,y1 -x1b,y1 x1b,y1 x2,y1 */
+/* | | */
+/* | | */
+/* | | */
+/* | | */
+/* | | */
+/* -x1a,y0 x1a,y0 */
+/* */
+
+
+void GLUI_Translation::draw_2d_arrow( int radius, int filled, int orientation )
+{
+ float x1 = .2, x2 = .4, y1 = .54, y2 = .94, y0;
+ float x1a, x1b;
+/*
+ vec3 col1( 0.0, 0.0, 0.0 ), col2( .45, .45, .45 ),
+ col3( .7, .7, .7 ), col4( 1.0, 1.0, 1.0 );
+ vec3 c1, c2, c3, c4, c5, c6;
+*/
+ vec3 white(1.0,1.0,1.0), black(0.0,0.0,0.0), gray(.45,.45,.45),
+ bkgd(.7,.7,.7);
+ int c_off=0; /* color index offset */
+
+ if ( glui )
+ bkgd.set(glui->bkgd_color_f[0],
+ glui->bkgd_color_f[1],
+ glui->bkgd_color_f[2]);
+
+ /* bkgd[0] = 255.0; bkgd[1] = 0; */
+
+ /** The following 8 colors define the shading of an octagon, in
+ clockwise order, starting from the upstroke on the left **/
+ /** This is for an outside and inside octagons **/
+ vec3 colors_out[]={white, white, white, gray, black, black, black, gray};
+ vec3 colors_in[] ={bkgd,white,bkgd,gray,gray,gray,gray,gray};
+
+#define SET_COL_OUT(i) glColor3fv((float*) &colors_out[(i)%8][0]);
+#define SET_COL_IN(i) glColor3fv((float*) &colors_in[(i)%8][0]);
+
+ x1 = (float)radius * .2;
+ x2 = x1 * 2;
+ y1 = (float)radius * .54;
+ y2 = y1 + x2;
+ x1a = x1;
+ x1b = x1;
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+
+#define DRAW_SEG( xa,ya,xb,yb ) glVertex2f(xa,ya); glVertex2f(xb,yb);
+
+ glScalef( -1.0, 1.0, 1.0 );
+
+ if ( orientation == 2 ) {
+ c_off = 4;
+ }
+ else if ( orientation == 0 ) {
+ c_off = 0;
+ glRotatef( 180.0, 0.0, 0.0, 1.0 );
+ }
+ else if ( orientation == 1 ) {
+ c_off = 2;
+ glRotatef( 90.0, 0.0, 0.0, 1.0 );
+ }
+ else if ( orientation == 3 ) {
+ c_off = 6;
+ glRotatef( -90.0, 0.0, 0.0, 1.0 );
+ }
+
+ if ( trans_type == GLUI_TRANSLATION_Z )
+ y0 = 0.0;
+ else if ( trans_type == GLUI_TRANSLATION_XY )
+ y0 = x1;
+ else
+ y0 = 0.0;
+
+
+ if ( trans_type == GLUI_TRANSLATION_Z ) {
+ if ( orientation == 0 ) {
+ y1 += 2.0;
+ y2 += 0.0;
+
+ x1b -= 2.0;
+ x2 -= 2.0;
+ x1a += 2.0;
+ }
+ else if ( orientation == 2 ) {
+ y1 -= 6.0;
+ x1a += 2.0;
+ x1b += 4.0;
+ x2 += 6.0;
+ }
+ }
+
+ /*** Fill in inside of arrow ***/
+ if ( NOT filled ) { /*** Means button is up - control is not clicked ***/
+ /*glColor3f( .8, .8, .8 ); */
+ set_to_bkgd_color();
+ glColor3f( bkgd[0]+.07, bkgd[1]+.07, bkgd[2]+.07 );
+ }
+ else { /*** Button is down on control ***/
+ glColor3f( .6, .6, .6 );
+ c_off += 4; /* Indents the shadows - goes from a raised look to embossed */
+ }
+
+ /*** Check if control is enabled or not ***/
+ if ( NOT enabled ) {
+ set_to_bkgd_color();
+ /*c_off += 4; -- Indents the shadows - goes from a raised look to embossed */
+ colors_out[0] = colors_out[1] = colors_out[2] = colors_out[7] = gray;
+ colors_out[3] = colors_out[4] = colors_out[5] = colors_out[6] = white;
+ colors_in[0] = colors_in[1] = colors_in[2] = colors_in[7] = white;
+ colors_in[3] = colors_in[4] = colors_in[5] = colors_in[6] = gray;
+
+ }
+
+ glBegin( GL_POLYGON );
+ glVertex2f( 0.0, 0.0 ); glVertex2f( -x1a, 0.0 );
+ glVertex2f( -x1a, 0.0 ); glVertex2f( -x1b, y1 );
+ glVertex2f( x1b, y1); glVertex2f( x1a, 0.0 );
+ glVertex2f( x1a, 0.0 ); glVertex2f( 0.0, 0.0 );
+ glEnd();
+ glBegin( GL_TRIANGLES );
+ glVertex2f( -x2, y1 ); glVertex2f( 0.0, y2 ); glVertex2f( x2, y1 );
+ glEnd();
+
+ glLineWidth( 1.0 );
+ /*** Draw arrow outline ***/
+ glBegin( GL_LINES );
+
+ SET_COL_IN(1+c_off); DRAW_SEG( 0.0, y2-1.0, -x2, y1-1.0 );
+ SET_COL_IN(6+c_off); DRAW_SEG( -x2+2.0, y1+1.0, -x1b+1.0, y1+1.0 );
+ SET_COL_IN(0+c_off); DRAW_SEG( -x1b+1.0, y1+1.0, -x1a+1.0, y0 );
+ SET_COL_IN(3+c_off); DRAW_SEG( 0.0, y2-1.0, x2, y1-1.0 );
+ SET_COL_IN(6+c_off); DRAW_SEG( x2-1.0, y1+1.0, x1b-1.0, y1+1.0 );
+ SET_COL_IN(4+c_off); DRAW_SEG( x1b-1.0, y1+1.0, x1a-1.0, y0 );
+
+ SET_COL_OUT(0+c_off); DRAW_SEG( -x1a, y0, -x1b, y1 );
+ SET_COL_OUT(6+c_off); DRAW_SEG( -x1b, y1, -x2, y1 );
+ SET_COL_OUT(1+c_off); DRAW_SEG( -x2, y1, 0.0, y2 );
+ SET_COL_OUT(3+c_off); DRAW_SEG( 0.0, y2, x2, y1 );
+ SET_COL_OUT(6+c_off); DRAW_SEG( x2, y1, x1b, y1 );
+ SET_COL_OUT(4+c_off); DRAW_SEG( x1b, y1, x1a, y0 );
+
+ glEnd();
+
+#undef DRAW_SEG
+
+ glPopMatrix();
+}
+
+
+/*************************** GLUI_Translation::get_mouse_code() *************/
+
+int GLUI_Translation::get_mouse_code( int x, int y )
+{
+ if ( x == 0 AND y < 0 )
+ return GLUI_TRANSLATION_MOUSE_DOWN;
+ else if ( x == 0 AND y > 0 )
+ return GLUI_TRANSLATION_MOUSE_UP;
+ else if ( x > 0 AND y == 0 )
+ return GLUI_TRANSLATION_MOUSE_LEFT;
+ else if ( x < 0 AND y == 0 )
+ return GLUI_TRANSLATION_MOUSE_RIGHT;
+ else if ( x < 0 AND y < 0 )
+ return GLUI_TRANSLATION_MOUSE_DOWN_LEFT;
+ else if ( x < 0 AND y > 0 )
+ return GLUI_TRANSLATION_MOUSE_DOWN_RIGHT;
+ else if ( x > 0 AND y < 0 )
+ return GLUI_TRANSLATION_MOUSE_UP_LEFT;
+ else if ( x > 0 AND y > 0 )
+ return GLUI_TRANSLATION_MOUSE_UP_RIGHT;
+
+
+ return GLUI_TRANSLATION_MOUSE_NONE;
+}
+
+
+/*********************************** GLUI_Translation::set_x() ******/
+
+void GLUI_Translation::set_x( float val )
+{
+ set_one_val( val, 0 );
+}
+
+
+/*********************************** GLUI_Translation::set_y() ******/
+
+void GLUI_Translation::set_y( float val )
+{
+ if ( trans_type == GLUI_TRANSLATION_XY )
+ set_one_val( val, 1 );
+ else
+ set_one_val( val, 0 );
+}
+
+
+/*********************************** GLUI_Translation::set_z() ******/
+
+void GLUI_Translation::set_z( float val )
+{
+ set_one_val( val, 0 );
+}
+
+
+/******************************* GLUI_Translation::set_one_val() ****/
+
+void GLUI_Translation::set_one_val( float val, int index )
+{
+ float *fp;
+
+ float_array_val[index] = val; /* set value in array */
+
+ /*** The code below is like output_live, except it only operates on
+ a single member of the float array (given by 'index') instead of
+ outputting the entire array ****/
+
+ if ( ptr_val == NULL OR NOT live_inited )
+ return;
+
+ fp = (float*) ptr_val;
+ fp[index] = float_array_val[index];
+ last_live_float_array[index] = float_array_val[index];
+
+ /** Update the main gfx window? **/
+ if ( this->glui != NULL ) {
+ this->glui->post_update_main_gfx();
+ }
+}
diff --git a/tests/box2d/glui/glui_tree.cpp b/tests/box2d/glui/glui_tree.cpp new file mode 100755 index 00000000..1ed456d5 --- /dev/null +++ b/tests/box2d/glui/glui_tree.cpp @@ -0,0 +1,278 @@ +/****************************************************************************
+
+ GLUI User Interface Toolkit
+ ---------------------------
+
+ glui_panel.cpp - GLUI_Panel control class
+
+
+ --------------------------------------------------
+
+ Copyright (c) 1998 Paul Rademacher
+
+ This program is freely distributable without licensing fees and is
+ provided without guarantee or warrantee expressed or implied. This
+ program is -not- in the public domain.
+
+*****************************************************************************/
+
+#include "glui_internal_control.h"
+
+
+/****************************** GLUI_Tree::GLUI_Tree() **********/
+GLUI_Tree::GLUI_Tree(GLUI_Node *parent, const char *name,
+ int open, int inset)
+{
+ common_init();
+ GLUI_StaticText *inset_label;
+ GLUI_Column *col;
+
+ this->set_name( name );
+ this->user_id = -1;
+
+ if ( NOT open ) {
+ this->is_open = false;
+ this->h = GLUI_DEFAULT_CONTROL_HEIGHT + 7;
+ }
+
+ parent->add_control( this );
+ inset_label = new GLUI_StaticText(this,"");
+ inset_label->set_w(inset);
+ col = new GLUI_Column(this,true);
+ this->set_column(col);
+ this->set_alignment(GLUI_ALIGN_LEFT);
+}
+
+
+/****************************** GLUI_Tree::open() **********/
+
+void GLUI_Tree::open( void )
+{
+ if ( is_open )
+ return;
+ is_open = true;
+
+ GLUI_DRAWINGSENTINAL_IDIOM
+
+ child_head = collapsed_node.child_head;
+ child_tail = collapsed_node.child_tail;
+
+ collapsed_node.child_head = NULL;
+ collapsed_node.child_tail = NULL;
+
+ if ( child_head != NULL ) {
+ ((GLUI_Control*) child_head)->unhide_internal( true );
+ }
+
+ glui->refresh();
+}
+
+
+/****************************** GLUI_Tree::close() **********/
+
+void GLUI_Tree::close( void )
+{
+ if ( NOT glui )
+ return;
+
+ if ( NOT is_open )
+ return;
+ is_open = false;
+
+ GLUI_DRAWINGSENTINAL_IDIOM
+
+ if ( child_head != NULL ) {
+ ((GLUI_Control*) child_head)->hide_internal( true );
+ }
+
+ collapsed_node.child_head = first_child();
+ collapsed_node.child_tail = last_child();
+
+ child_head = NULL;
+ child_tail = NULL;
+
+ this->h = GLUI_DEFAULT_CONTROL_HEIGHT + 7;
+
+ glui->refresh();
+}
+
+
+/**************************** GLUI_Tree::mouse_down_handler() **********/
+
+
+int GLUI_Tree::mouse_down_handler( int local_x, int local_y )
+{
+ if ( local_y - y_abs > 18 ) {
+ initially_inside = currently_inside = false;
+ return false;
+ }
+
+ currently_inside = true;
+ initially_inside = true;
+ redraw();
+
+ return false;
+}
+
+/**************************** GLUI_Tree::mouse_held_down_handler() ****/
+
+int GLUI_Tree::mouse_held_down_handler(
+ int local_x, int local_y,
+ bool new_inside )
+{
+ if ( NOT initially_inside )
+ return false;
+
+ if ( local_y - y_abs> 18 )
+ new_inside = false;
+
+ if (currently_inside != new_inside)
+ redraw();
+
+ return false;
+}
+
+
+/**************************** GLUI_Tree::mouse_down_handler() **********/
+
+int GLUI_Tree::mouse_up_handler( int local_x, int local_y, bool inside )
+{
+ if ( currently_inside ) {
+ if ( is_open )
+ close();
+ else
+ open();
+ }
+
+ currently_inside = false;
+ initially_inside = false;
+ redraw();
+
+ return false;
+}
+
+
+/********************************* GLUI_Tree::draw() ***********/
+
+void GLUI_Tree::draw( int x, int y )
+{
+ GLUI_DRAWINGSENTINAL_IDIOM
+ int left, right, top, bottom, delta_x;
+
+ left = 5;
+ right = w-left;
+ top = 3;
+ bottom = 3+16;
+ delta_x = 0;
+
+ glui->draw_raised_box( left, top, 16, 16 );
+
+ if ( glui )
+ glColor3ub(glui->bkgd_color.r,glui->bkgd_color.g,glui->bkgd_color.b);
+ glDisable( GL_CULL_FACE );
+ glBegin( GL_QUADS );
+ glVertex2i( left+17, top+1 ); glVertex2i( right-1, top+1 );
+ glVertex2i( right-1, bottom-1 ); glVertex2i( left+17, bottom-1 );
+ glEnd();
+
+ if (format & GLUI_TREEPANEL_DISPLAY_HIERARCHY) {
+ delta_x = string_width( level_name ) + char_width(' ');
+ glColor3f( lred, lgreen, lblue); /* The hierarchy is drawn in bold */
+ glRasterPos2i(left + 25, top + 11);
+ draw_string(level_name);
+ glRasterPos2i(left + 24, top + 11);
+ draw_string(level_name);
+ }
+
+ draw_name( delta_x+left+24, top+11 );
+
+ if ( active )
+ draw_active_box( left+22, delta_x+left+string_width( name )+32,
+ top, bottom-2 );
+
+
+ /** Draw '+' or '-' **/
+
+ glBegin( GL_LINES );
+ if ( is_open ) {
+ if ( enabled )
+ if (is_current)
+ glColor3f( 0, 0, 1 );
+ else
+ glColor3f( 0.0, 0.0, 0.0 );
+ else
+ glColor3f( 0.5, 0.5, 0.5 );
+ glVertex2i(left+4,(top+bottom)/2); glVertex2i(left+13,(top+bottom)/2);
+
+ glColor3f( 1.0, 1.0, 1.0 );
+ glVertex2i(left+4,1+(top+bottom)/2);glVertex2i(left+13,1+(top+bottom)/2);
+ }
+ else
+ {
+ glColor3f( 1.0, 1.0, 1.0 );
+ glVertex2i(left+9,top+3); glVertex2i(left+9,bottom-4);
+ glVertex2i(left+4,(top+bottom)/2); glVertex2i(left+13,(top+bottom)/2);
+
+ if ( enabled )
+ if (is_current)
+ glColor3f( 0, 0, 1 );
+ else
+ glColor3f( 0.0, 0.0, 0.0 );
+ else
+ glColor3f( 0.5, 0.5, 0.5 );
+ glVertex2i(left+4,-1+(top+bottom)/2);
+ glVertex2i(left+13,-1+(top+bottom)/2);
+ glVertex2i(left+8,top+3);
+ glVertex2i(left+8,bottom-4);
+ }
+ glEnd();
+
+ glLineWidth( 1.0 );
+
+ if (currently_inside) draw_pressed();
+}
+
+
+/***************************** GLUI_Tree::update_size() **********/
+
+void GLUI_Tree::update_size( void )
+{
+ int text_size = 0, delta_x = 0;
+
+ if ( NOT glui )
+ return;
+
+ text_size = string_width(name);
+
+ if (format & GLUI_TREEPANEL_DISPLAY_HIERARCHY) {
+ delta_x = string_width( level_name );
+ }
+
+ if ( w < text_size + 36 + delta_x)
+ w = text_size + 36 + delta_x;
+}
+
+
+/**************************** GLUI_Tree::draw_pressed() ***********/
+
+void GLUI_Tree::draw_pressed( void )
+{
+ int left, right, top, bottom;
+
+ left = 5;
+ right = w-left;
+ top = 3;
+ bottom = 3+16;
+
+ glColor3f( 0.0, 0.0, 0.0 );
+
+ glBegin( GL_LINE_LOOP );
+ glVertex2i( left, top ); glVertex2i( right, top );
+ glVertex2i( right, bottom ); glVertex2i( left,bottom );
+ glEnd();
+
+ glBegin( GL_LINE_LOOP );
+ glVertex2i( left+1, top+1 ); glVertex2i( right-1, top+1 );
+ glVertex2i( right-1, bottom-1 ); glVertex2i( left+1,bottom-1 );
+ glEnd();
+}
diff --git a/tests/box2d/glui/glui_treepanel.cpp b/tests/box2d/glui/glui_treepanel.cpp new file mode 100755 index 00000000..4849aed4 --- /dev/null +++ b/tests/box2d/glui/glui_treepanel.cpp @@ -0,0 +1,387 @@ +#include "glui.h"
+
+
+/****************************** GLUI_TreePanel::GLUI_TreePanel() *********/
+
+GLUI_TreePanel::GLUI_TreePanel(GLUI_Node *parent, const char *name,
+ bool open, int inset)
+{
+ common_init();
+
+ set_name( name );
+ user_id = -1;
+
+ if ( !open ) {
+ is_open = false;
+ h = GLUI_DEFAULT_CONTROL_HEIGHT + 7;
+ }
+
+ parent->add_control( this );
+}
+
+/****************************** GLUI_TreePanel::set_color() *********/
+
+void GLUI_TreePanel::set_color(float r, float g, float b)
+{
+ red = r;
+ green = g;
+ blue = b;
+ redraw();
+}
+
+/************************ GLUI_TreePanel::set_level_color() *********/
+
+void GLUI_TreePanel::set_level_color(float r, float g, float b)
+{
+ lred = r;
+ lgreen = g;
+ lblue = b;
+ redraw();
+}
+
+/****************************** GLUI_TreePanel::ab() *********/
+
+/* Adds branch to curr_root */
+GLUI_Tree *GLUI_TreePanel::ab(const char *name, GLUI_Tree *root)
+{
+ GLUI_Tree *temp;
+
+
+ if (root != NULL) {
+ resetToRoot(root);
+ }
+
+ temp = new GLUI_Tree(curr_root, name);
+ initNode(temp);
+ formatNode(temp);
+
+ curr_root = temp;
+ curr_branch = NULL; /* Currently at leaf */
+
+ if (dynamic_cast<GLUI_Tree*>(temp))
+ ((GLUI_Tree *)temp)->set_current(true);
+ //refresh();
+ // glui->deactivate_current_control();
+ //glui->activate_control( temp, GLUI_ACTIVATE_TAB );
+ return temp;
+
+}
+
+/****************************** GLUI_TreePanel::fb() *********/
+
+/* Goes up one level, resets curr_root and curr_branch to parents*/
+void GLUI_TreePanel::fb(GLUI_Tree *branch)
+{
+ if (((GLUI_Panel *)branch) == ((GLUI_Panel *)this))
+ return;
+
+ if (((GLUI_Panel *)curr_branch) == ((GLUI_Panel *)this)) {
+ resetToRoot();
+ return;
+ }
+ if (((GLUI_Panel *)curr_root) == ((GLUI_Panel *)this)) {
+ resetToRoot();
+ return;
+ }
+
+ if (branch != NULL) {
+
+ if ( dynamic_cast<GLUI_Tree*>(branch) )
+ ((GLUI_Tree *)branch)->set_current(false);
+
+ curr_branch = (GLUI_Tree *)branch->next();
+ curr_root = (GLUI_Panel *)branch->parent();
+
+ if (curr_branch == NULL && (curr_root->collapsed_node).first_child() != NULL)
+ curr_branch = (GLUI_Tree *)(curr_root->collapsed_node).first_child();
+
+ if ( dynamic_cast<GLUI_Tree*>(curr_root) )
+ ((GLUI_Tree *)curr_root)->set_current(true);
+
+ } else {
+ if (curr_root != NULL) { /* up one parent */
+
+ if (dynamic_cast<GLUI_Tree*>(curr_root))
+ ((GLUI_Tree *)curr_root)->set_current(false);
+
+ curr_branch = (GLUI_Tree *) curr_root->next();
+ curr_root = (GLUI_Panel *) curr_root->parent();
+
+ if (curr_branch == NULL && (curr_root->collapsed_node).first_child() != NULL)
+ curr_branch = (GLUI_Tree *)(curr_root->collapsed_node).first_child();
+
+ if (dynamic_cast<GLUI_Tree*>(curr_root))
+ ((GLUI_Tree *)curr_root)->set_current(true);
+
+ }
+
+ }
+ //refresh();
+}
+
+
+/****************************** GLUI_TreePanel::refresh() *********/
+
+void GLUI_TreePanel::refresh()
+{
+ glui->deactivate_current_control();
+ glui->activate_control( curr_root, GLUI_ACTIVATE_TAB );
+
+ redraw();
+}
+
+/****************************** GLUI_TreePanel::initNode() *********/
+
+void GLUI_TreePanel::initNode(GLUI_Tree *temp)
+{
+ if (temp == NULL)
+ return;
+ int level = temp->get_level();
+ int child_number = 1;
+
+ GLUI_Tree *ptree = dynamic_cast<GLUI_Tree*>(temp->parent());
+ if (ptree) {
+ level = ptree->get_level() + 1;
+ GLUI_Tree *prevTree = dynamic_cast<GLUI_Tree*>(temp->prev());
+ if (prevTree) {
+ child_number = prevTree->get_child_number() + 1;
+ }
+ } else if (dynamic_cast<GLUI_Tree*>(temp) &&
+ dynamic_cast<GLUI_TreePanel*>(temp->parent())) {
+ child_number = ++root_children;
+ }
+ temp->set_id(uniqueID()); // -1 if unset
+ temp->set_level(level);
+ temp->set_child_number(child_number);
+}
+
+/****************************** GLUI_TreePanel::formatNode() *********/
+
+void GLUI_TreePanel::formatNode(GLUI_Tree *temp)
+{
+ if (temp == NULL)
+ return;
+ int level = temp->get_level();
+ int child_number = temp->get_child_number();
+ GLUI_String level_name="";
+ GLUI_String full_name="";
+
+ temp->level_name == "";
+
+ if (format & GLUI_TREEPANEL_DISPLAY_HIERARCHY) {
+ if (format & GLUI_TREEPANEL_HIERARCHY_LEVEL_ONLY) {
+ glui_format_str(level_name, "%d", level);
+ }
+ if (format & GLUI_TREEPANEL_HIERARCHY_NUMERICDOT) {
+ if ( dynamic_cast<GLUI_Tree*>(temp->parent()) )
+ glui_format_str(level_name, "%s.%d",
+ ((GLUI_Tree *)(temp->parent()))->level_name.c_str(),
+ child_number);
+ else
+ glui_format_str(level_name, "%d", child_number);
+ }
+ }
+
+ temp->set_level_color(lred, lgreen, lblue);
+ temp->set_format(format);
+ temp->level_name = level_name;
+
+ if (format & GLUI_TREEPANEL_ALTERNATE_COLOR) {
+ switch (level%8) {
+ case (7): temp->set_color(.5,.5,.5); break;
+ case (6): temp->set_color(.3,.5,.5); break;
+ case (5): temp->set_color(.5,.3,.5); break;
+ case (4): temp->set_color(.3,.3,.5); break;
+ case (3): temp->set_color(.5,.5,.3); break;
+ case (2): temp->set_color(.3,.5,.3); break;
+ case (1): temp->set_color(.5,.3,.3); break;
+ default: temp->set_color(.3,.3,.3);
+ }
+ } else {
+ temp->set_color(red,green,blue);
+ }
+
+ if (format & GLUI_TREEPANEL_DISABLE_BAR) {
+ temp->disable_bar();
+ } else {
+ if (format & GLUI_TREEPANEL_DISABLE_DEEPEST_BAR) {
+ temp->disable_bar();
+ if ( dynamic_cast<GLUI_Tree*>(curr_root) )
+ ((GLUI_Tree *)curr_root)->enable_bar();
+ } else
+ if (format & GLUI_TREEPANEL_CONNECT_CHILDREN_ONLY) {
+ temp->disable_bar();
+ if (temp->prev() && dynamic_cast<GLUI_Tree*>(temp->prev()) )
+ {
+ ((GLUI_Tree *)temp->prev())->enable_bar();
+ }
+ }
+ }
+}
+
+/****************************** GLUI_TreePanel::update_all() *********/
+
+void GLUI_TreePanel::update_all()
+{
+ printf("GLUI_TreePanel::update_all() doesn't work yet. - JVK\n");
+ return;
+ GLUI_Panel *saved_root = curr_root;
+ GLUI_Tree *saved_branch = curr_branch;
+ root_children = 0;
+ resetToRoot(this);
+ if (curr_branch && dynamic_cast<GLUI_Tree*>(curr_branch))
+ formatNode((GLUI_Tree *)curr_branch);
+ next();
+ while (curr_root && curr_branch != this->first_child()) {
+ if (curr_branch && dynamic_cast<GLUI_Tree*>(curr_branch)) {
+ formatNode((GLUI_Tree *)curr_branch);
+ }
+ next();
+ }
+ curr_root = saved_root;
+ curr_branch = saved_branch;
+}
+
+/****************************** GLUI_TreePanel::expand_all() *********/
+
+void GLUI_TreePanel::expand_all()
+{
+ GLUI_Panel *saved_root = curr_root;
+ GLUI_Tree *saved_branch = curr_branch;
+
+ resetToRoot(this);
+ if (dynamic_cast<GLUI_Tree*>(curr_root))
+ ((GLUI_Tree*)curr_root)->open();
+ next();
+ while (curr_root != NULL && curr_branch != this->first_child()) {
+ if (dynamic_cast<GLUI_Tree*>(curr_root))
+ ((GLUI_Tree*)curr_root)->open();
+ next();
+ }
+
+ curr_root = saved_root;
+ curr_branch = saved_branch;
+}
+
+/****************************** GLUI_TreePanel::collapse_all() *********/
+
+void GLUI_TreePanel::collapse_all()
+{
+ GLUI_Panel *saved_root = curr_root;
+ GLUI_Tree *saved_branch = curr_branch;
+
+ resetToRoot(this);
+ next();
+ while (curr_root != NULL && curr_branch != this->first_child()) {
+ if (dynamic_cast<GLUI_Tree*>(curr_root) &&
+ curr_branch == NULL) { /* we want to close everything leaf-first */
+ ((GLUI_Tree*)curr_root)->close();
+ /* Rather than simply next(), we need to manually move the
+ curr_root because this node has been moved to the
+ collapsed_node list */
+ curr_branch = (GLUI_Tree *)curr_root->next();
+ curr_root = (GLUI_Panel *)curr_root->parent();
+ } else
+ next();
+ }
+
+ curr_root = saved_root;
+ curr_branch = saved_branch;
+
+}
+
+/****************************** GLUI_TreePanel::db() *********/
+
+/* Deletes the curr_root */
+void GLUI_TreePanel::db(GLUI_Tree *root)
+{
+ GLUI_Tree *temp_branch;
+ GLUI_Panel *temp_root;
+
+ if (((GLUI_Control *)root) == ((GLUI_Control *)this))
+ return;
+
+ if (root != NULL) {
+ curr_root = (GLUI_Tree *)root;
+ curr_branch = NULL;
+ }
+
+ if (curr_root == NULL || ((GLUI_Panel *)curr_root) == ((GLUI_Panel *)this)) {
+ resetToRoot();
+ return;
+ }
+
+
+ temp_branch = (GLUI_Tree *)curr_root->next(); /* Next branch, if any */
+ temp_root = (GLUI_Panel *)curr_root->parent(); /* new root */
+ curr_root->unlink();
+ delete curr_root;
+ curr_branch = (GLUI_Tree *) temp_branch;
+ curr_root = (GLUI_Panel *) temp_root;
+ if (dynamic_cast<GLUI_Tree*>(curr_root))
+ ((GLUI_Tree *)curr_root)->open();
+
+ if ((format & GLUI_TREEPANEL_DISABLE_DEEPEST_BAR) == GLUI_TREEPANEL_DISABLE_DEEPEST_BAR) {
+ if (dynamic_cast<GLUI_Tree*>(curr_root) && ((GLUI_Tree *)curr_root->next()) == NULL)
+ ((GLUI_Tree *)curr_root)->disable_bar();
+ }
+ //refresh();
+}
+
+/****************************** GLUI_TreePanel::descendBranch() *********/
+
+/* Finds the very last branch of curr_root, resets vars */
+void GLUI_TreePanel::descendBranch(GLUI_Panel *root) {
+ if (root)
+ resetToRoot(root);
+ else
+ resetToRoot(curr_root);
+ if (curr_branch != NULL && curr_branch != ((GLUI_Panel *)this)) {
+ if (dynamic_cast<GLUI_Tree*>(curr_root))
+ ((GLUI_Tree *)curr_root)->set_current(false);
+ descendBranch(curr_branch);
+ }
+}
+
+/****************************** GLUI_TreePanel::next() *********/
+
+void GLUI_TreePanel::next()
+{
+ if (curr_root == NULL)
+ resetToRoot(this);
+
+ if (curr_branch == NULL && (curr_root->collapsed_node).first_child() != NULL)
+ curr_branch = (GLUI_Tree *)(curr_root->collapsed_node).first_child();
+
+
+ if (curr_branch != NULL && curr_branch != ((GLUI_Panel *)this)) { /* Descend into branch */
+ if (dynamic_cast<GLUI_Tree*>(curr_root))
+ ((GLUI_Tree *)curr_root)->set_current(false);
+ resetToRoot(curr_branch);
+ } else if (curr_branch == NULL) {
+ fb(NULL); /* Backup and move on */
+ }
+}
+
+/****************************** GLUI_TreePanel::resetToRoot() *********/
+
+/* Resets curr_root and curr branch to TreePanel and lastChild */
+void GLUI_TreePanel::resetToRoot(GLUI_Panel *new_root)
+{
+ GLUI_Panel *root = this;
+ if (new_root != NULL)
+ root = new_root;
+ curr_root = root;
+ if (dynamic_cast<GLUI_Tree*>(curr_root))
+ ((GLUI_Tree *)curr_root)->set_current(true);
+ curr_branch = (GLUI_Tree *)root->first_child();
+
+ /* since Trees are collapsable, we need to check the collapsed nodes
+ in case the curr_root is collapsed */
+ if (curr_branch == NULL && (root->collapsed_node).first_child() != NULL) {
+ curr_branch = (GLUI_Tree *)(root->collapsed_node).first_child();
+ }
+ while (curr_branch && dynamic_cast<GLUI_Tree*>(curr_branch)) {
+ curr_branch=(GLUI_Tree *)curr_branch->next();
+ }
+}
diff --git a/tests/box2d/glui/glui_window.cpp b/tests/box2d/glui/glui_window.cpp new file mode 100755 index 00000000..83559782 --- /dev/null +++ b/tests/box2d/glui/glui_window.cpp @@ -0,0 +1,44 @@ +/*
+
+ glui_window.cpp - GLUI_Button control class
+
+ GLUI User Interface Toolkit (LGPL)
+ Copyright (c) 1998 Paul Rademacher
+
+ WWW: http://sourceforge.net/projects/glui/
+ Forums: http://sourceforge.net/forum/?group_id=92496
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+
+#include "glui.h"
+#include "glui_internal.h"
+
+GLUI_Glut_Window::GLUI_Glut_Window()
+: GLUI_Node(),
+
+ glut_window_id(0),
+ glut_keyboard_CB(NULL),
+ glut_special_CB(NULL),
+ glut_reshape_CB(NULL),
+ glut_passive_motion_CB(NULL),
+ glut_mouse_CB(NULL),
+ glut_visibility_CB(NULL),
+ glut_motion_CB(NULL),
+ glut_display_CB(NULL),
+ glut_entry_CB(NULL)
+{
+}
diff --git a/tests/box2d/glui/quaternion.cpp b/tests/box2d/glui/quaternion.cpp new file mode 100755 index 00000000..3e80242a --- /dev/null +++ b/tests/box2d/glui/quaternion.cpp @@ -0,0 +1,243 @@ +/***********************************************************************
+
+ quaternion.cpp - A quaternion class
+
+ -------------------------------------------------------------------
+
+ GLUI User Interface Toolkit (LGPL)
+ Copyright (c) 1998 Paul Rademacher
+
+ WWW: http://sourceforge.net/projects/glui/
+ Forums: http://sourceforge.net/forum/?group_id=92496
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+************************************************************************
+
+ Feb 1998, Paul Rademacher (rademach@cs.unc.edu)
+ Oct 2003, Nigel Stewart - GLUI Code Cleaning
+
+************************************************************************/
+
+#include "quaternion.h"
+#include <cmath>
+#include "glui_internal.h"
+
+/******************************************* constructors **************/
+
+quat::quat()
+{
+ *this = quat_identity();
+}
+
+quat::quat(const float x, const float y, const float z, const float w)
+{
+ v.set( x, y, z );
+ s = w;
+}
+
+quat::quat(const vec3 &_v, const float _s)
+{
+ set( _v, _s );
+}
+
+quat::quat(const float _s, const vec3 &_v)
+{
+ set( _v, _s );
+}
+
+quat::quat(const float *d)
+{
+ v[0] = d[0];
+ v[1] = d[1];
+ v[2] = d[2];
+ s = d[3];
+}
+
+quat::quat(const double *d)
+{
+ v[0] = (float) d[0];
+ v[1] = (float) d[1];
+ v[2] = (float) d[2];
+ s = (float) d[3];
+}
+
+quat::quat(const quat &q)
+{
+ v = q.v;
+ s = q.s;
+}
+
+void quat::set(const vec3 &_v, const float _s)
+{
+ v = _v;
+ s = _s;
+}
+
+quat &quat::operator=(const quat &q)
+{
+ v = q.v;
+ s = q.s;
+ return *this;
+}
+
+/******** quat friends ************/
+
+quat operator + (const quat &a, const quat &b)
+{
+ return quat( a.s+b.s, a.v+b.v );
+}
+
+quat operator - (const quat &a, const quat &b)
+{
+ return quat( a.s-b.s, a.v-b.v );
+}
+
+quat operator - (const quat &a )
+{
+ return quat( -a.s, -a.v );
+}
+
+quat operator * ( const quat &a, const quat &b)
+{
+ return quat( a.s*b.s - a.v*b.v, a.s*b.v + b.s*a.v + a.v^b.v );
+}
+
+quat operator * ( const quat &a, const float t)
+{
+ return quat( a.v * t, a.s * t );
+}
+
+quat operator * ( const float t, const quat &a )
+{
+ return quat( a.v * t, a.s * t );
+}
+
+mat4 quat::to_mat4() const
+{
+ float xs, ys, zs, wx, wy, wz, xx, xy, xz, yy, yz, zz;
+
+ float t = 2.0f / (v*v + s*s);
+
+ xs = v[VX]*t; ys = v[VY]*t; zs = v[VZ]*t;
+ wx = s*xs; wy = s*ys; wz = s*zs;
+ xx = v[VX]*xs; xy = v[VX]*ys; xz = v[VX]*zs;
+ yy = v[VY]*ys; yz = v[VY]*zs; zz = v[VZ]*zs;
+
+ mat4 matrix(
+ 1.0f-(yy+zz), xy+wz, xz-wy, 0.0f,
+ xy-wz, 1.0f-(xx+zz), yz+wx, 0.0f,
+ xz+wy, yz-wx, 1.0f-(xx+yy), 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f );
+
+ return matrix;
+}
+
+/************************************************* quat_identity() *****/
+/* Returns quaternion identity element */
+
+quat quat_identity()
+{
+ return quat( vec3( 0.0, 0.0, 0.0 ), 1.0 );
+}
+
+/************************************************ quat_slerp() ********/
+/* Quaternion spherical interpolation */
+
+quat quat_slerp(const quat &from, const quat &to, float t)
+{
+ quat to1;
+ float omega, cosom, sinom, scale0, scale1;
+
+ /* calculate cosine */
+ cosom = from.v * to.v + from.s + to.s;
+
+ /* Adjust signs (if necessary) */
+ if ( cosom < 0.0 )
+ {
+ cosom = -cosom;
+ to1 = -to;
+ }
+ else
+ {
+ to1 = to;
+ }
+
+ /* Calculate coefficients */
+ if ((1.0 - cosom) > FUDGE )
+ {
+ /* standard case (slerp) */
+ omega = (float) acos( cosom );
+ sinom = (float) sin( omega );
+ scale0 = (float) sin((1.0 - t) * omega) / sinom;
+ scale1 = (float) sin(t * omega) / sinom;
+ }
+ else
+ {
+ /* 'from' and 'to' are very close - just do linear interpolation */
+ scale0 = 1.0f - t;
+ scale1 = t;
+ }
+
+ return scale0 * from + scale1 * to1;
+}
+
+/********************************************** set_angle() ************/
+/* set rot angle (degrees) */
+
+void quat::set_angle(float f)
+{
+ vec3 axis = get_axis();
+
+ s = (float) cos( DEG2RAD( f ) / 2.0 );
+
+ v = axis * (float) sin(DEG2RAD(f) / 2.0);
+}
+
+/********************************************** scale_angle() ************/
+/* scale rot angle (degrees) */
+
+void quat::scale_angle(float f)
+{
+ set_angle( f * get_angle() );
+}
+
+/********************************************** get_angle() ************/
+/* get rot angle (degrees). Assumes s is between -1 and 1 */
+
+float quat::get_angle() const
+{
+ return (float) RAD2DEG( 2.0 * acos( s ) );
+}
+
+/********************************************* get_axis() **************/
+
+vec3 quat::get_axis() const
+{
+ float scale = (float) sin( acos( s ) );
+
+ if ( scale < FUDGE AND scale > -FUDGE )
+ return vec3( 0.0, 0.0, 0.0 );
+ else
+ return v / scale;
+}
+
+/******************************************* quat::print() ************/
+
+void quat::print(FILE *dest, const char *name) const
+{
+ fprintf( dest, "%s: v:<%3.2f %3.2f %3.2f> s:%3.2f\n",
+ name, v[0], v[1], v[2], s );
+}
diff --git a/tests/box2d/glui/quaternion.h b/tests/box2d/glui/quaternion.h new file mode 100755 index 00000000..8bd45823 --- /dev/null +++ b/tests/box2d/glui/quaternion.h @@ -0,0 +1,114 @@ +/****************************************************************************
+
+ quaternion.h - A quaternion class
+
+ GLUI User Interface Toolkit (LGPL)
+ Copyright (c) 1998 Paul Rademacher
+
+ ---------------------------------------------------------------------
+
+ WWW: http://sourceforge.net/projects/glui/
+ Forums: http://sourceforge.net/forum/?group_id=92496
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+#ifndef GLUI_QUATERNION_H
+#define GLUI_QUATERNION_H
+
+#include "algebra3.h"
+#include <cstdio>
+
+/* this line defines a new type: pointer to a function which returns a */
+/* float and takes as argument a float */
+typedef float (*V_FCT_PTR)(float);
+
+/****************************************************************
+ * Quaternion *
+ ****************************************************************/
+
+class quat
+{
+ /*protected: */
+public:
+
+ vec3 v; /* vector component */
+ float s; /* scalar component */
+
+ /*public: */
+
+ /* Constructors */
+
+ quat();
+ quat(float x, float y, float z, float w);
+ quat(const vec3 &v, float s);
+ quat(float s, const vec3 &v);
+ quat(const float *d); /* copy from four-element float array */
+ quat(const double *f); /* copy from four-element double array */
+ quat(const quat &q); /* copy from other quat */
+
+ /* Assignment operators */
+
+ quat &operator = (const quat &v); /* assignment of a quat */
+ quat &operator += (const quat &v); /* incrementation by a quat */
+ quat &operator -= (const quat &v); /* decrementation by a quat */
+ quat &operator *= (float d); /* multiplication by a constant */
+ quat &operator /= (float d); /* division by a constant */
+
+ /* special functions */
+
+ float length() const; /* length of a quat */
+ float length2() const; /* squared length of a quat */
+ quat &normalize(); /* normalize a quat */
+ quat &apply(V_FCT_PTR fct); /* apply a func. to each component */
+ vec3 xform(const vec3 &v ); /* q*v*q-1 */
+ mat4 to_mat4() const;
+ void set_angle(float f); /* set rot angle (degrees) */
+ void scale_angle(float f); /* scale rot angle (degrees) */
+ float get_angle() const; /* set rot angle (degrees) */
+ vec3 get_axis() const; /* get axis */
+
+ void print( FILE *file, const char *name ) const; /* print to a file */
+
+ float &operator [] (int i); /* indexing */
+ const float &operator [] (int i) const; /* indexing */
+
+ void set(float x, float y, float z); /* set quat */
+ void set(const vec3 &v, float s); /* set quat */
+
+ /* friends */
+
+ friend quat operator - (const quat &v); /* -q1 */
+ friend quat operator + (const quat &a, const quat &b); /* q1 + q2 */
+ friend quat operator - (const quat &a, const quat &b); /* q1 - q2 */
+ friend quat operator * (const quat &a, float d); /* q1 * 3.0 */
+ friend quat operator * (float d, const quat &a); /* 3.0 * q1 */
+ friend quat operator * (const quat &a, const quat &b); /* q1 * q2 */
+ friend quat operator / (const quat &a, float d); /* q1 / 3.0 */
+ friend int operator == (const quat &a, const quat &b); /* q1 == q2 ? */
+ friend int operator != (const quat &a, const quat &b); /* q1 != q2 ? */
+ friend void swap(quat &a, quat &b); /* swap q1 &q2 */
+ /*friend quat min(const quat &a, const quat &b); -- min(q1, q2) */
+ /*friend quat max(const quat &a, const quat &b); -- max(q1, q2) */
+ friend quat prod(const quat &a, const quat &b); /* term by term mult*/
+};
+
+/* Utility functions */
+
+quat quat_identity(); /* Returns quaternion identity element */
+quat quat_slerp(const quat &from, const quat &to, float t);
+
+#endif
diff --git a/tests/box2d/glui/readme.txt b/tests/box2d/glui/readme.txt new file mode 100755 index 00000000..43ba3ed5 --- /dev/null +++ b/tests/box2d/glui/readme.txt @@ -0,0 +1,228 @@ +Welcome to the GLUI User Interface Library, v2.3!
+March 22, 2005
+-------------------------------------------------
+
+This distribution contains the latest community-maintained fork of the
+GLUI Library. It is based on the GLUI v2.1 beta version from Paul
+Rademacher (http://www.cs.unc.edu/~rademach/glui/) plus the
+compatibility changes made by Nigel Stewart in his "GLUI v2.2"
+(http://www.nigels.com/glt/glui) In accordance with the LGPL under
+which the library is released (according to Paul's web page at least),
+these changes are available to everyone in the community.
+
+WARNING: This version (2.3) introduces some incompatible changes with
+previous versions!!
+
+CHANGES:
+
+----------------------------------
+- GLUI_String is now a std::string
+ This is the main source of most incopatibilities, but I felt it was
+ a necessary change, because the previous usage of a fixed-sized
+ buffer was just too unsafe. I myself was bitten a few times passing
+ a char* buffer of insufficient size into GLUI as a live variable.
+ It is still possible to use a char buffer, but it is not recommended.
+
+ If you used GLUI_String before as a live var type, the easiest way
+ to get your code compiling again is to change those to "char
+ buf[300]". The better way, though, is to update your code to treat
+ it as a std::string.
+
+ For instance, if you used to pass mystr to functions that take
+ 'const char*', now use mystr.c_str() method, instead.
+ If you used strcpy(mystr, b) to set the value, now just do mystr=b.
+ If you used sprintf(mystr,...) to set the value, now do
+ glui_format_string(mystr,...).
+ If you used to clear the string with mystr[0]='\0', now just clear
+ it with mystr="".
+
+----------------------------------
+- Enhanced GLUI_EditText
+ Control keys can be used for navigation and control. The bindings
+ are bash-like: Ctrl-B for previous char, Ctrl-F for forward char, etc.
+ bindings. Also control keys that aren't bound to commands are
+ simply ignored, whereas before they would be inserted as invisible
+ characters.
+
+----------------------------------
+- Added GLUI_CommandLine class
+ This is a GLUI_EditText with a history mechanism.
+
+----------------------------------
+- New, more object oriented construction API.
+ Now instead of calling
+
+ glui->add_button_to_panel( panel, "my button", myid, mycallback );
+
+ you should just call the button constructor:
+
+ new GLUI_Button( panel, "my button", myid, mycallback );
+
+ And similarly to add it to a GLUI instead of a panel, rather than:
+
+ glui->add_button( glui, "my button", myid, mycallback );
+
+ just call the constructor with the GLUI as the first argument:
+
+ new GLUI_Button( glui, "my button", myid, mycallback );
+
+ The old scheme is now deprecated, but still works. The benefit of
+ this new scheme is that now the GLUI class doesn't have to know
+ about all the different types of GLUI_Controls that exist.
+ Previously GLUI had to both know about all the controls, and know
+ how to initialize them. Now the responsibility for initialization
+ belongs to the GLUI_Control subclasses themselves, where it
+ belongs. Additionally it means that you can create your own
+ GLUI_Control subclasses which will be on equal footing with the
+ built-in controls, whereas before any user-created controls would
+ always be "second-class citizens" since they would have to be
+ constructed differently from the built-ins.
+
+
+----------------------------------
+- Removed need for type-declaring arguments when argment type suffices.
+ This effects GLUI_Spinner and GLUI_EditText (and GLUI_CommandLine?).
+
+ For example, instead of calling
+
+ new GLUI_Spinner( glui, "myspin", GLUI_SPINNER_INT, &live_int_var );
+
+ you can just omit the GLUI_SPINNER_INT part, because the type of the
+ live_int_var tells the compiler which type you want.
+
+ new GLUI_Spinner( glui, "myspin", &live_int_var );
+
+ If you're not using a live, var, you can still use the
+ GLUI_SPINNER_INT type argument. See glui.h for all the new
+ constructor signatures. Note this only works with the new
+ construction API, not with the old "add_blah_to_panel" style of
+ API.
+
+----------------------------------
+- GLUI_Rotation uses your matrix live-variable now.
+ GLUI used to ignore the matrix in your live variable. This version
+ doesn't ignore it, so you'll need to set it to the identity matrix
+ yourself if that's what you want it to start as. There could
+ probably be some improvements to this API, though.
+
+----------------------------------
+- Improvements to 'const' usage.
+ Most char*'s in GLUI functions used to be non-const even when the
+ functions did not modify the string. I changed everywhere
+ appropriate to use const char* instead.
+
+----------------------------------
+- Updated license info in the headers
+ Paul's web page says that GLUI is LGPL, but that wasn't declared in
+ the code itself. I've modified all the headers with the standard
+ LGPL notice.
+
+----------------------------------
+- Updated examples for the API changes
+
+----------------------------------
+- Created project files for Visual Studio .NET (MSVC7.1)
+
+
+That's about it. Enjoy!
+
+
+If you find yourself with too much time on your hands, the things I
+think would be most useful for future improvements to GLUI would be:
+
+1. The GLUI_TextBox and GLUI_Tree definitely need some work, still.
+2. Clipboard integration under Windows/X-Win. I have some code that
+ works on Win32 that I once integrated with GLUI, but I lost that
+ version somewhere. I still have the Win32 clipboard code, though
+ if anyone wants to work on integrating it. I have some X-Win
+ clipboard code, too, but I never got it working quite right.
+3. Remove the dependency on GLUT, making the connection with window
+ system APIs into a more plug-in/adapter modular design.
+ So e.g. if you want to use GLUT, you'd link with the GLUI lib and a
+ GLUI_GLUT lib, and call one extra GLUI_glut_init() function or
+ something.
+
+
+Definitly consider submitting a patch if you've made some nice improvements
+to GLUI. Hopefully being an LGPL sourceforge project will attract some new
+interest to the GLUI project.
+
+Bill Baxter
+baxter
+at
+cs unc edu
+
+=================================================
+JOHN KEW'S ADDITIONS (March 2005)
+=================================================
+
+Thanks to John Kew of Natural Solutions Inc.,
+there are some new widgets. These are demonstrated in example6.cpp.
+
+The new widgets are:
+
+* GLUI_Scrollbar - A scrollbar slider widget
+* GLUI_TextBox - A multi-line text widget
+* GLUI_List - A static choice list
+* GLUI_FileBrowser - A simple filebrowser based on GLUI_List
+* GLUI_Tree - Hierarchical tree widget
+* GLUI_TreePanel - Manager for the tree widget
+
+And one other change:
+
+* GLUI_Rollout has optional embossed border
+
+=================================================
+PAUL'S ORIGINAL GLUI 2.0/2.1 README
+=================================================
+
+Welcome to the GLUI User Interface Library, v2.0 beta!
+-------------------------------------------------
+
+This distribution contains the full GLUI sources, as well as 5 example
+programs. You'll find the full manual under "glui_manual.pdf". The
+GLUI web page is at
+
+ http://www.cs.unc.edu/~rademach/glui
+
+
+ ---------- Windows ----------
+
+The directory 'msvc' contains a Visual C++ workspace entitled
+'glui.dsw'. To recompile the library and examples, open this
+workspace and run the menu command "Build:Batch Build:Build". The 3
+executables will be in the 'bin' directory, and the library in the
+'lib' directory.
+
+To create a new Windows executable using GLUI, create a "Win32 Console
+Application" in VC++, add the GLUI library (in 'msvc/lib/glui32.lib'),
+and add the OpenGL libs:
+
+ glui32.lib glut32.lib glu32.lib opengl32.lib (Microsoft OpenGL)
+
+Include the file "glui.h" in any file that uses the GLUI library.
+
+
+ ---------- Unix ----------
+
+An SGI/HP makefile is found in the file 'makefile' (certain lines may need
+to be commented/uncommented).
+
+To include GLUI in your own apps, add the glui library to your
+makefile (before the glut library 'libglut.a'), and include "glui.h"
+in your sources.
+
+
+
+----------------------------------------------------------------------
+
+Please let me know what you think, what you'd like to change or add,
+and especially what bugs you encounter. Also, please send me your
+e-mail so I can add you to a mailing list for updates.
+
+Good luck, and thanks for trying this out!
+
+Paul Rademacher
+rademach
+at
+cs unc edu
\ No newline at end of file diff --git a/tests/box2d/premake4.lua b/tests/box2d/premake4.lua new file mode 100755 index 00000000..dec685c3 --- /dev/null +++ b/tests/box2d/premake4.lua @@ -0,0 +1,67 @@ +-- Box2D premake script. +-- http://industriousone.com/premake + +local action = _ACTION or "" + +solution "Box2D" + location ( "Build/" .. action ) + configurations { "Debug", "Release" } + + configuration "vs*" + defines { "_CRT_SECURE_NO_WARNINGS" } + + configuration "Debug" + targetdir ( "Build/" .. action .. "/bin/Debug" ) + flags { "Symbols" } + + configuration "Release" + targetdir ( "Build/" .. action .. "/bin/Release" ) + defines { "NDEBUG" } + flags { "Optimize" } + + project "Box2D" + kind "StaticLib" + language "C++" + files { "Box2D/**.h", "Box2D/**.cpp" } + vpaths { [""] = "Box2D" } + includedirs { "." } + + if os.get == "windows" then + project "FreeGLUT" + kind "StaticLib" + language "C" + files { "freeglut/*.h", "freeglut/*.c" } + vpaths { ["Headers"] = "**.h", ["Sources"] = "**.c" } + end + + project "GLUI" + kind "StaticLib" + language "C++" + files { "glui/*.h", "glui/*.cpp" } + vpaths { ["Headers"] = "**.h", ["Sources"] = "**.cpp" } + includedirs { "." } + configuration { "windows" } + buildoptions { "/W1" } + + project "HelloWorld" + kind "ConsoleApp" + language "C++" + files { "HelloWorld/Helloworld.cpp" } + vpaths { [""] = "HelloWorld" } + includedirs { "." } + links { "Box2D" } + + project "Testbed" + kind "ConsoleApp" + language "C++" + files { "Testbed/**.h", "Testbed/**.cpp" } + vpaths { [""] = "Testbed" } + includedirs { "." } + links { "Box2D", "GLUI" } + configuration { "windows" } + links { "FreeGLUT", "glu32", "opengl32", "winmm" } + configuration { "macosx" } + linkoptions { "-framework OpenGL -framework GLUT" } + configuration { "not windows", "not macosx" } + links { "X11", "GL", "GLU", "GLUT" } + |