aboutsummaryrefslogtreecommitdiff
path: root/tests/box2d
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2013-04-10 15:53:50 -0700
committerAlon Zakai <alonzakai@gmail.com>2013-04-10 15:53:50 -0700
commitf84537c333524d0841923eaec66604584bf77326 (patch)
tree6a43fab885a397a80de2cd8117b6ebafdb00cdf5 /tests/box2d
parenta4a20535e79f10c553b685b188fcfd6af12fac07 (diff)
more work towards box2d benchmark
Diffstat (limited to 'tests/box2d')
-rw-r--r--tests/box2d/Benchmark.cpp122
-rwxr-xr-xtests/box2d/Box2D/Box2D.h67
-rwxr-xr-xtests/box2d/Box2D/Box2DConfig.cmake3
-rwxr-xr-xtests/box2d/Box2D/CMakeLists.txt205
-rwxr-xr-xtests/box2d/Box2D/Collision/Shapes/b2ChainShape.cpp171
-rwxr-xr-xtests/box2d/Box2D/Collision/Shapes/b2ChainShape.h102
-rwxr-xr-xtests/box2d/Box2D/Collision/Shapes/b2CircleShape.cpp100
-rwxr-xr-xtests/box2d/Box2D/Collision/Shapes/b2CircleShape.h91
-rwxr-xr-xtests/box2d/Box2D/Collision/Shapes/b2EdgeShape.cpp139
-rwxr-xr-xtests/box2d/Box2D/Collision/Shapes/b2EdgeShape.h74
-rwxr-xr-xtests/box2d/Box2D/Collision/Shapes/b2PolygonShape.cpp361
-rwxr-xr-xtests/box2d/Box2D/Collision/Shapes/b2PolygonShape.h95
-rwxr-xr-xtests/box2d/Box2D/Collision/Shapes/b2Shape.h101
-rwxr-xr-xtests/box2d/Box2D/Collision/b2BroadPhase.cpp122
-rwxr-xr-xtests/box2d/Box2D/Collision/b2BroadPhase.h250
-rwxr-xr-xtests/box2d/Box2D/Collision/b2CollideCircle.cpp154
-rwxr-xr-xtests/box2d/Box2D/Collision/b2CollideEdge.cpp698
-rwxr-xr-xtests/box2d/Box2D/Collision/b2CollidePolygon.cpp317
-rwxr-xr-xtests/box2d/Box2D/Collision/b2Collision.cpp249
-rwxr-xr-xtests/box2d/Box2D/Collision/b2Collision.h281
-rwxr-xr-xtests/box2d/Box2D/Collision/b2Distance.cpp603
-rwxr-xr-xtests/box2d/Box2D/Collision/b2Distance.h141
-rwxr-xr-xtests/box2d/Box2D/Collision/b2DynamicTree.cpp771
-rwxr-xr-xtests/box2d/Box2D/Collision/b2DynamicTree.h284
-rwxr-xr-xtests/box2d/Box2D/Collision/b2TimeOfImpact.cpp483
-rwxr-xr-xtests/box2d/Box2D/Collision/b2TimeOfImpact.h58
-rwxr-xr-xtests/box2d/Box2D/Common/b2BlockAllocator.cpp217
-rwxr-xr-xtests/box2d/Box2D/Common/b2BlockAllocator.h62
-rwxr-xr-xtests/box2d/Box2D/Common/b2Draw.cpp44
-rwxr-xr-xtests/box2d/Box2D/Common/b2Draw.h85
-rwxr-xr-xtests/box2d/Box2D/Common/b2GrowableStack.h87
-rwxr-xr-xtests/box2d/Box2D/Common/b2Math.cpp94
-rwxr-xr-xtests/box2d/Box2D/Common/b2Math.h739
-rwxr-xr-xtests/box2d/Box2D/Common/b2Settings.cpp44
-rwxr-xr-xtests/box2d/Box2D/Common/b2Settings.h155
-rwxr-xr-xtests/box2d/Box2D/Common/b2StackAllocator.cpp83
-rwxr-xr-xtests/box2d/Box2D/Common/b2StackAllocator.h60
-rwxr-xr-xtests/box2d/Box2D/Common/b2Timer.cpp100
-rwxr-xr-xtests/box2d/Box2D/Common/b2Timer.h45
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.cpp54
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.h39
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.cpp54
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.h39
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Contacts/b2CircleContact.cpp53
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Contacts/b2CircleContact.h39
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Contacts/b2Contact.cpp240
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Contacts/b2Contact.h334
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Contacts/b2ContactSolver.cpp832
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Contacts/b2ContactSolver.h94
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.cpp50
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h39
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.cpp50
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.h39
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.cpp50
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.h38
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Contacts/b2PolygonContact.cpp53
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Contacts/b2PolygonContact.h39
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Joints/b2DistanceJoint.cpp260
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Joints/b2DistanceJoint.h180
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Joints/b2FrictionJoint.cpp251
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Joints/b2FrictionJoint.h129
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Joints/b2GearJoint.cpp423
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Joints/b2GearJoint.h136
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Joints/b2Joint.cpp199
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Joints/b2Joint.h222
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Joints/b2MouseJoint.cpp217
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Joints/b2MouseJoint.h136
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Joints/b2PrismaticJoint.cpp637
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Joints/b2PrismaticJoint.h207
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Joints/b2PulleyJoint.cpp332
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Joints/b2PulleyJoint.h154
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Joints/b2RevoluteJoint.cpp504
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Joints/b2RevoluteJoint.h214
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Joints/b2RopeJoint.cpp241
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Joints/b2RopeJoint.h125
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Joints/b2WeldJoint.cpp330
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Joints/b2WeldJoint.h136
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Joints/b2WheelJoint.cpp419
-rwxr-xr-xtests/box2d/Box2D/Dynamics/Joints/b2WheelJoint.h224
-rwxr-xr-xtests/box2d/Box2D/Dynamics/b2Body.cpp514
-rwxr-xr-xtests/box2d/Box2D/Dynamics/b2Body.h848
-rwxr-xr-xtests/box2d/Box2D/Dynamics/b2ContactManager.cpp293
-rwxr-xr-xtests/box2d/Box2D/Dynamics/b2ContactManager.h52
-rwxr-xr-xtests/box2d/Box2D/Dynamics/b2Fixture.cpp303
-rwxr-xr-xtests/box2d/Box2D/Dynamics/b2Fixture.h348
-rwxr-xr-xtests/box2d/Box2D/Dynamics/b2Island.cpp539
-rwxr-xr-xtests/box2d/Box2D/Dynamics/b2Island.h93
-rwxr-xr-xtests/box2d/Box2D/Dynamics/b2TimeStep.h70
-rwxr-xr-xtests/box2d/Box2D/Dynamics/b2World.cpp1316
-rwxr-xr-xtests/box2d/Box2D/Dynamics/b2World.h349
-rwxr-xr-xtests/box2d/Box2D/Dynamics/b2WorldCallbacks.cpp36
-rwxr-xr-xtests/box2d/Box2D/Dynamics/b2WorldCallbacks.h163
-rwxr-xr-xtests/box2d/Box2D/Rope/b2Rope.cpp259
-rwxr-xr-xtests/box2d/Box2D/Rope/b2Rope.h115
-rwxr-xr-xtests/box2d/Build/Readme.txt1
-rwxr-xr-xtests/box2d/Build/vs2010/Box2D.sln74
-rwxr-xr-xtests/box2d/Build/vs2010/Box2D.vcxproj340
-rwxr-xr-xtests/box2d/Build/vs2010/Box2D.vcxproj.filters301
-rwxr-xr-xtests/box2d/Build/vs2010/FreeGLUT.vcxproj250
-rwxr-xr-xtests/box2d/Build/vs2010/FreeGLUT.vcxproj.filters102
-rwxr-xr-xtests/box2d/Build/vs2010/GLUI.vcxproj275
-rwxr-xr-xtests/box2d/Build/vs2010/GLUI.vcxproj.filters129
-rwxr-xr-xtests/box2d/Build/vs2010/HelloWorld.vcxproj209
-rwxr-xr-xtests/box2d/Build/vs2010/HelloWorld.vcxproj.filters6
-rwxr-xr-xtests/box2d/Build/vs2010/Testbed.vcxproj265
-rwxr-xr-xtests/box2d/Build/vs2010/Testbed.vcxproj.filters171
-rwxr-xr-xtests/box2d/Build/xcode4/Box2D.xcodeproj/project.pbxproj1210
-rwxr-xr-xtests/box2d/Build/xcode4/Box2D.xcodeproj/project.xcworkspace/contents.xcworkspacedata7
-rwxr-xr-xtests/box2d/Building.txt37
-rwxr-xr-xtests/box2d/CMakeLists.txt35
-rwxr-xr-xtests/box2d/HelloWorld/CMakeLists.txt4
-rwxr-xr-xtests/box2d/HelloWorld/HelloWorld.cpp106
-rwxr-xr-xtests/box2d/License.txt18
-rw-r--r--tests/box2d/Makefile63
-rwxr-xr-xtests/box2d/Readme.txt19
-rwxr-xr-xtests/box2d/Testbed/CMakeLists.txt92
-rwxr-xr-xtests/box2d/Testbed/Framework/Main.cpp447
-rwxr-xr-xtests/box2d/Testbed/Framework/Render.cpp197
-rwxr-xr-xtests/box2d/Testbed/Framework/Render.h51
-rwxr-xr-xtests/box2d/Testbed/Framework/Test.cpp447
-rwxr-xr-xtests/box2d/Testbed/Framework/Test.h189
-rwxr-xr-xtests/box2d/Testbed/Tests/AddPair.h51
-rwxr-xr-xtests/box2d/Testbed/Tests/ApplyForce.h180
-rwxr-xr-xtests/box2d/Testbed/Tests/BodyTypes.h159
-rwxr-xr-xtests/box2d/Testbed/Tests/Breakable.h155
-rwxr-xr-xtests/box2d/Testbed/Tests/Bridge.h125
-rwxr-xr-xtests/box2d/Testbed/Tests/BulletTest.h136
-rwxr-xr-xtests/box2d/Testbed/Tests/Cantilever.h211
-rwxr-xr-xtests/box2d/Testbed/Tests/Car.h286
-rwxr-xr-xtests/box2d/Testbed/Tests/Chain.h74
-rwxr-xr-xtests/box2d/Testbed/Tests/CharacterCollision.h253
-rwxr-xr-xtests/box2d/Testbed/Tests/CollisionFiltering.h176
-rwxr-xr-xtests/box2d/Testbed/Tests/CollisionProcessing.h188
-rwxr-xr-xtests/box2d/Testbed/Tests/CompoundShapes.h143
-rwxr-xr-xtests/box2d/Testbed/Tests/Confined.h167
-rwxr-xr-xtests/box2d/Testbed/Tests/ContinuousTest.h137
-rwxr-xr-xtests/box2d/Testbed/Tests/DistanceTest.h135
-rwxr-xr-xtests/box2d/Testbed/Tests/Dominos.h215
-rwxr-xr-xtests/box2d/Testbed/Tests/DumpShell.h267
-rwxr-xr-xtests/box2d/Testbed/Tests/DynamicTreeTest.h357
-rwxr-xr-xtests/box2d/Testbed/Tests/EdgeShapes.h249
-rwxr-xr-xtests/box2d/Testbed/Tests/EdgeTest.h109
-rwxr-xr-xtests/box2d/Testbed/Tests/Gears.h187
-rwxr-xr-xtests/box2d/Testbed/Tests/OneSidedPlatform.h120
-rwxr-xr-xtests/box2d/Testbed/Tests/Pinball.h169
-rwxr-xr-xtests/box2d/Testbed/Tests/PolyCollision.h122
-rwxr-xr-xtests/box2d/Testbed/Tests/PolyShapes.h295
-rwxr-xr-xtests/box2d/Testbed/Tests/Prismatic.h107
-rwxr-xr-xtests/box2d/Testbed/Tests/Pulleys.h106
-rwxr-xr-xtests/box2d/Testbed/Tests/Pyramid.h89
-rwxr-xr-xtests/box2d/Testbed/Tests/RayCast.h440
-rwxr-xr-xtests/box2d/Testbed/Tests/Revolute.h166
-rwxr-xr-xtests/box2d/Testbed/Tests/Rope.h101
-rwxr-xr-xtests/box2d/Testbed/Tests/RopeJoint.h145
-rwxr-xr-xtests/box2d/Testbed/Tests/SensorTest.h181
-rwxr-xr-xtests/box2d/Testbed/Tests/ShapeEditing.h105
-rwxr-xr-xtests/box2d/Testbed/Tests/SliderCrank.h156
-rwxr-xr-xtests/box2d/Testbed/Tests/SphereStack.h86
-rwxr-xr-xtests/box2d/Testbed/Tests/TestEntries.cpp125
-rwxr-xr-xtests/box2d/Testbed/Tests/TheoJansen.h256
-rwxr-xr-xtests/box2d/Testbed/Tests/Tiles.h156
-rwxr-xr-xtests/box2d/Testbed/Tests/TimeOfImpact.h131
-rwxr-xr-xtests/box2d/Testbed/Tests/Tumbler.h99
-rwxr-xr-xtests/box2d/Testbed/Tests/VaryingFriction.h124
-rwxr-xr-xtests/box2d/Testbed/Tests/VaryingRestitution.h69
-rwxr-xr-xtests/box2d/Testbed/Tests/VerticalStack.h165
-rwxr-xr-xtests/box2d/Testbed/Tests/Web.h209
-rwxr-xr-xtests/box2d/freeglut/CMakeLists.txt51
-rwxr-xr-xtests/box2d/freeglut/COPYING27
-rwxr-xr-xtests/box2d/freeglut/freeglut.h22
-rwxr-xr-xtests/box2d/freeglut/freeglut_callbacks.c367
-rwxr-xr-xtests/box2d/freeglut/freeglut_cursor.c280
-rwxr-xr-xtests/box2d/freeglut/freeglut_display.c98
-rwxr-xr-xtests/box2d/freeglut/freeglut_ext.c226
-rwxr-xr-xtests/box2d/freeglut/freeglut_ext.h212
-rwxr-xr-xtests/box2d/freeglut/freeglut_font.c384
-rwxr-xr-xtests/box2d/freeglut/freeglut_font_data.c2020
-rwxr-xr-xtests/box2d/freeglut/freeglut_gamemode.c594
-rwxr-xr-xtests/box2d/freeglut/freeglut_geometry.c1215
-rwxr-xr-xtests/box2d/freeglut/freeglut_glutfont_definitions.c108
-rwxr-xr-xtests/box2d/freeglut/freeglut_init.c1166
-rwxr-xr-xtests/box2d/freeglut/freeglut_input_devices.c395
-rwxr-xr-xtests/box2d/freeglut/freeglut_internal.h960
-rwxr-xr-xtests/box2d/freeglut/freeglut_joystick.c1801
-rwxr-xr-xtests/box2d/freeglut/freeglut_main.c2296
-rwxr-xr-xtests/box2d/freeglut/freeglut_menu.c1002
-rwxr-xr-xtests/box2d/freeglut/freeglut_misc.c214
-rwxr-xr-xtests/box2d/freeglut/freeglut_overlay.c45
-rwxr-xr-xtests/box2d/freeglut/freeglut_spaceball.c454
-rwxr-xr-xtests/box2d/freeglut/freeglut_state.c895
-rwxr-xr-xtests/box2d/freeglut/freeglut_std.h583
-rwxr-xr-xtests/box2d/freeglut/freeglut_stroke_mono_roman.c2849
-rwxr-xr-xtests/box2d/freeglut/freeglut_stroke_roman.c2849
-rwxr-xr-xtests/box2d/freeglut/freeglut_structure.c596
-rwxr-xr-xtests/box2d/freeglut/freeglut_teapot.c200
-rwxr-xr-xtests/box2d/freeglut/freeglut_teapot_data.h2429
-rwxr-xr-xtests/box2d/freeglut/freeglut_videoresize.c50
-rwxr-xr-xtests/box2d/freeglut/freeglut_window.c1743
-rwxr-xr-xtests/box2d/glui/CMakeLists.txt49
-rwxr-xr-xtests/box2d/glui/algebra3.cpp1609
-rwxr-xr-xtests/box2d/glui/algebra3.h475
-rwxr-xr-xtests/box2d/glui/arcball.cpp237
-rwxr-xr-xtests/box2d/glui/arcball.h97
-rwxr-xr-xtests/box2d/glui/glui.cpp2105
-rwxr-xr-xtests/box2d/glui/glui.h2568
-rwxr-xr-xtests/box2d/glui/glui_add_controls.cpp319
-rwxr-xr-xtests/box2d/glui/glui_bitmap_img_data.cpp138
-rwxr-xr-xtests/box2d/glui/glui_bitmaps.cpp176
-rwxr-xr-xtests/box2d/glui/glui_button.cpp186
-rwxr-xr-xtests/box2d/glui/glui_checkbox.cpp188
-rwxr-xr-xtests/box2d/glui/glui_column.cpp89
-rwxr-xr-xtests/box2d/glui/glui_commandline.cpp197
-rwxr-xr-xtests/box2d/glui/glui_control.cpp1203
-rwxr-xr-xtests/box2d/glui/glui_edittext.cpp1198
-rwxr-xr-xtests/box2d/glui/glui_filebrowser.cpp165
-rwxr-xr-xtests/box2d/glui/glui_internal.h105
-rwxr-xr-xtests/box2d/glui/glui_internal_control.h45
-rwxr-xr-xtests/box2d/glui/glui_list.cpp540
-rwxr-xr-xtests/box2d/glui/glui_listbox.cpp448
-rwxr-xr-xtests/box2d/glui/glui_mouse_iaction.cpp210
-rwxr-xr-xtests/box2d/glui/glui_node.cpp212
-rwxr-xr-xtests/box2d/glui/glui_panel.cpp186
-rwxr-xr-xtests/box2d/glui/glui_radio.cpp362
-rwxr-xr-xtests/box2d/glui/glui_rollout.cpp275
-rwxr-xr-xtests/box2d/glui/glui_rotation.cpp473
-rwxr-xr-xtests/box2d/glui/glui_scrollbar.cpp832
-rwxr-xr-xtests/box2d/glui/glui_separator.cpp75
-rwxr-xr-xtests/box2d/glui/glui_spinner.cpp647
-rwxr-xr-xtests/box2d/glui/glui_statictext.cpp105
-rwxr-xr-xtests/box2d/glui/glui_string.cpp62
-rwxr-xr-xtests/box2d/glui/glui_textbox.cpp1108
-rwxr-xr-xtests/box2d/glui/glui_translation.cpp559
-rwxr-xr-xtests/box2d/glui/glui_tree.cpp278
-rwxr-xr-xtests/box2d/glui/glui_treepanel.cpp387
-rwxr-xr-xtests/box2d/glui/glui_window.cpp44
-rwxr-xr-xtests/box2d/glui/quaternion.cpp243
-rwxr-xr-xtests/box2d/glui/quaternion.h114
-rwxr-xr-xtests/box2d/glui/readme.txt228
-rwxr-xr-xtests/box2d/premake4.lua67
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 &center, 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 &center, 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" }
+