| @@ -0,0 +1,94 @@ | |||||
| apply plugin: 'com.android.application' | |||||
| android { | |||||
| compileSdkVersion 23 | |||||
| buildToolsVersion "27.0.0" | |||||
| externalNativeBuild { | |||||
| cmake { | |||||
| path "CMakeLists.txt" | |||||
| } | |||||
| } | |||||
| signingConfigs { | |||||
| juceSigning { | |||||
| storeFile file("${System.properties['user.home']}${File.separator}.android${File.separator}debug.keystore") | |||||
| storePassword "android" | |||||
| keyAlias "androiddebugkey" | |||||
| keyPassword "android" | |||||
| storeType "jks" | |||||
| } | |||||
| } | |||||
| defaultConfig { | |||||
| applicationId "com.roli.juce.demorunner" | |||||
| minSdkVersion 23 | |||||
| targetSdkVersion 23 | |||||
| externalNativeBuild { | |||||
| cmake { | |||||
| arguments "-DANDROID_TOOLCHAIN=clang", "-DANDROID_PLATFORM=android-23", "-DANDROID_STL=c++_static", "-DANDROID_CPP_FEATURES=exceptions rtti", "-DANDROID_ARM_MODE=arm", "-DANDROID_ARM_NEON=TRUE" | |||||
| cFlags "-fsigned-char" | |||||
| cppFlags "-fsigned-char", "-std=c++14" | |||||
| } | |||||
| } | |||||
| } | |||||
| buildTypes { | |||||
| debug { | |||||
| initWith debug | |||||
| debuggable true | |||||
| jniDebuggable true | |||||
| signingConfig signingConfigs.juceSigning | |||||
| } | |||||
| release { | |||||
| initWith release | |||||
| debuggable false | |||||
| jniDebuggable false | |||||
| signingConfig signingConfigs.juceSigning | |||||
| } | |||||
| } | |||||
| flavorDimensions "default" | |||||
| productFlavors { | |||||
| debug_ { | |||||
| ndk { | |||||
| abiFilters "armeabi", "x86" | |||||
| } | |||||
| externalNativeBuild { | |||||
| cmake { | |||||
| arguments "-DJUCE_BUILD_CONFIGURATION=DEBUG", "-DCMAKE_CXX_FLAGS_DEBUG=-O0", "-DCMAKE_C_FLAGS_DEBUG=-O0" | |||||
| } | |||||
| } | |||||
| dimension "default" | |||||
| } | |||||
| release_ { | |||||
| externalNativeBuild { | |||||
| cmake { | |||||
| arguments "-DJUCE_BUILD_CONFIGURATION=RELEASE", "-DCMAKE_CXX_FLAGS_RELEASE=-O3", "-DCMAKE_C_FLAGS_RELEASE=-O3" | |||||
| } | |||||
| } | |||||
| dimension "default" | |||||
| } | |||||
| } | |||||
| variantFilter { variant -> | |||||
| def names = variant.flavors*.name | |||||
| if (names.contains ("debug_") | |||||
| && variant.buildType.name != "debug") { | |||||
| setIgnore(true) | |||||
| } | |||||
| if (names.contains ("release_") | |||||
| && variant.buildType.name != "release") { | |||||
| setIgnore(true) | |||||
| } | |||||
| } | |||||
| repositories { | |||||
| } | |||||
| dependencies { | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,5 @@ | |||||
| <?xml version="1.0" encoding="utf-8"?> | |||||
| <resources> | |||||
| <string name="app_name">DemoRunner</string> | |||||
| </resources> | |||||
| @@ -0,0 +1,26 @@ | |||||
| <?xml version="1.0" encoding="utf-8"?> | |||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="5.2.1" | |||||
| package="com.roli.juce.demorunner"> | |||||
| <supports-screens android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:anyDensity="true"/> | |||||
| <uses-sdk android:minSdkVersion="23" android:targetSdkVersion="23"/> | |||||
| <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> | |||||
| <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> | |||||
| <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> | |||||
| <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> | |||||
| <uses-permission android:name="android.permission.BLUETOOTH"/> | |||||
| <uses-permission android:name="android.permission.RECORD_AUDIO"/> | |||||
| <uses-permission android:name="android.permission.INTERNET"/> | |||||
| <uses-feature android:glEsVersion="0x00030000" android:required="true"/> | |||||
| <application android:label="@string/app_name" android:icon="@drawable/icon" android:hardwareAccelerated="false"> | |||||
| <activity android:name="DemoRunner" android:label="@string/app_name" android:configChanges="keyboardHidden|orientation|screenSize" | |||||
| android:screenOrientation="userLandscape" android:launchMode="singleTask" android:hardwareAccelerated="true"> | |||||
| <intent-filter> | |||||
| <action android:name="android.intent.action.MAIN"/> | |||||
| <category android:name="android.intent.category.LAUNCHER"/> | |||||
| </intent-filter> | |||||
| </activity> | |||||
| <provider android:name="com.roli.juce.demorunner.SharingContentProvider" android:authorities="com.roli.juce.demorunner.sharingcontentprovider" | |||||
| android:grantUriPermissions="true" android:exported="false"/> | |||||
| </application> | |||||
| </manifest> | |||||
| @@ -0,0 +1,72 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE examples. | |||||
| Copyright (c) 2017 - ROLI Ltd. | |||||
| The code included in this file is provided under the terms of the ISC license | |||||
| http://www.isc.org/downloads/software-support-policy/isc-license. Permission | |||||
| To use, copy, modify, and/or distribute this software for any purpose with or | |||||
| without fee is hereby granted provided that the above copyright notice and | |||||
| this permission notice appear in all copies. | |||||
| THE SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, | |||||
| WHETHER EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR | |||||
| PURPOSE, ARE DISCLAIMED. | |||||
| ============================================================================== | |||||
| */ | |||||
| #pragma once | |||||
| //============================================================================== | |||||
| /* This component scrolls a continuous waveform showing the audio that's | |||||
| coming into whatever audio inputs this object is connected to. | |||||
| */ | |||||
| class LiveScrollingAudioDisplay : public AudioVisualiserComponent, | |||||
| public AudioIODeviceCallback | |||||
| { | |||||
| public: | |||||
| LiveScrollingAudioDisplay() : AudioVisualiserComponent (1) | |||||
| { | |||||
| setSamplesPerBlock (256); | |||||
| setBufferSize (1024); | |||||
| } | |||||
| //============================================================================== | |||||
| void audioDeviceAboutToStart (AudioIODevice*) override | |||||
| { | |||||
| clear(); | |||||
| } | |||||
| void audioDeviceStopped() override | |||||
| { | |||||
| clear(); | |||||
| } | |||||
| void audioDeviceIOCallback (const float** inputChannelData, int numInputChannels, | |||||
| float** outputChannelData, int numOutputChannels, | |||||
| int numberOfSamples) override | |||||
| { | |||||
| for (int i = 0; i < numberOfSamples; ++i) | |||||
| { | |||||
| float inputSample = 0; | |||||
| for (int chan = 0; chan < numInputChannels; ++chan) | |||||
| if (const float* inputChannel = inputChannelData[chan]) | |||||
| inputSample += inputChannel[i]; // find the sum of all the channels | |||||
| inputSample *= 10.0f; // boost the level to make it more easily visible. | |||||
| pushSample (&inputSample, 1); | |||||
| } | |||||
| // We need to clear the output buffers before returning, in case they're full of junk.. | |||||
| for (int j = 0; j < numOutputChannels; ++j) | |||||
| if (float* outputChannel = outputChannelData[j]) | |||||
| zeromem (outputChannel, sizeof (float) * (size_t) numberOfSamples); | |||||
| } | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LiveScrollingAudioDisplay) | |||||
| }; | |||||
| @@ -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 (int 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 | |||||
| @@ -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.0f); | |||||
| 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 | |||||
| @@ -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 | |||||
| @@ -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 | |||||
| @@ -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 | |||||
| @@ -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 | |||||
| @@ -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 | |||||
| @@ -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 | |||||
| @@ -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 (int 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 | |||||
| @@ -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 | |||||
| @@ -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 | |||||
| @@ -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 | |||||
| @@ -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 | |||||
| @@ -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 | |||||
| @@ -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 | |||||
| @@ -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 | |||||
| @@ -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 (int 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 | |||||
| @@ -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 | |||||
| @@ -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 | |||||
| @@ -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 | |||||
| @@ -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 | |||||
| @@ -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 | |||||
| @@ -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 | |||||
| @@ -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() | |||||
| { | |||||
| 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 | |||||
| @@ -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 | |||||
| @@ -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 | |||||
| @@ -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 | |||||
| @@ -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 | |||||
| @@ -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 | |||||
| @@ -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 | |||||
| @@ -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 | |||||
| @@ -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 | |||||
| @@ -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 | |||||
| @@ -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 | |||||
| @@ -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 | |||||
| @@ -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 | |||||
| @@ -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 | |||||
| @@ -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} | |||||
| }; | |||||
| @@ -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 | |||||
| @@ -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 | |||||
| @@ -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 | |||||
| @@ -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 | |||||
| @@ -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 | |||||
| @@ -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 | |||||
| @@ -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 | |||||
| @@ -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 | |||||
| @@ -0,0 +1,686 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE examples. | |||||
| Copyright (c) 2017 - ROLI Ltd. | |||||
| The code included in this file is provided under the terms of the ISC license | |||||
| http://www.isc.org/downloads/software-support-policy/isc-license. Permission | |||||
| To use, copy, modify, and/or distribute this software for any purpose with or | |||||
| without fee is hereby granted provided that the above copyright notice and | |||||
| this permission notice appear in all copies. | |||||
| THE SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, | |||||
| WHETHER EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR | |||||
| PURPOSE, ARE DISCLAIMED. | |||||
| ============================================================================== | |||||
| */ | |||||
| #pragma once | |||||
| using namespace dsp; | |||||
| //============================================================================== | |||||
| struct DSPDemoParameterBase : public ChangeBroadcaster | |||||
| { | |||||
| DSPDemoParameterBase (const String& labelName) : name (labelName) {} | |||||
| virtual ~DSPDemoParameterBase() {} | |||||
| virtual Component* getComponent() = 0; | |||||
| virtual int getPreferredHeight() = 0; | |||||
| virtual int getPreferredWidth() = 0; | |||||
| String name; | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DSPDemoParameterBase) | |||||
| }; | |||||
| //============================================================================== | |||||
| struct SliderParameter : public DSPDemoParameterBase | |||||
| { | |||||
| SliderParameter (Range<double> range, double skew, double initialValue, | |||||
| const String& labelName, const String& suffix = {}) | |||||
| : DSPDemoParameterBase (labelName) | |||||
| { | |||||
| slider.setRange (range.getStart(), range.getEnd(), 0.01); | |||||
| slider.setSkewFactor (skew); | |||||
| slider.setValue (initialValue); | |||||
| if (suffix.isNotEmpty()) | |||||
| slider.setTextValueSuffix (suffix); | |||||
| slider.onValueChange = [this] { sendChangeMessage(); }; | |||||
| } | |||||
| Component* getComponent() override { return &slider; } | |||||
| int getPreferredHeight() override { return 40; } | |||||
| int getPreferredWidth() override { return 500; } | |||||
| double getCurrentValue() const { return slider.getValue(); } | |||||
| private: | |||||
| Slider slider; | |||||
| }; | |||||
| //============================================================================== | |||||
| struct ChoiceParameter : public DSPDemoParameterBase | |||||
| { | |||||
| ChoiceParameter (const StringArray& options, int initialId, const String& labelName) | |||||
| : DSPDemoParameterBase (labelName) | |||||
| { | |||||
| parameterBox.addItemList (options, 1); | |||||
| parameterBox.onChange = [this] { sendChangeMessage(); }; | |||||
| parameterBox.setSelectedId (initialId); | |||||
| } | |||||
| Component* getComponent() override { return ¶meterBox; } | |||||
| int getPreferredHeight() override { return 25; } | |||||
| int getPreferredWidth() override { return 250; } | |||||
| int getCurrentSelectedID() const { return parameterBox.getSelectedId(); } | |||||
| private: | |||||
| ComboBox parameterBox; | |||||
| }; | |||||
| //============================================================================== | |||||
| class AudioThumbnailComponent : public Component, | |||||
| public FileDragAndDropTarget, | |||||
| public ChangeBroadcaster, | |||||
| private ChangeListener, | |||||
| private Timer | |||||
| { | |||||
| public: | |||||
| AudioThumbnailComponent (AudioDeviceManager& adm, AudioFormatManager& afm) | |||||
| : audioDeviceManager (adm), | |||||
| thumbnailCache (5), | |||||
| thumbnail (128, afm, thumbnailCache) | |||||
| { | |||||
| thumbnail.addChangeListener (this); | |||||
| } | |||||
| ~AudioThumbnailComponent() | |||||
| { | |||||
| thumbnail.removeChangeListener (this); | |||||
| } | |||||
| void paint (Graphics& g) override | |||||
| { | |||||
| g.fillAll (Colour (0xff495358)); | |||||
| g.setColour (Colours::white); | |||||
| if (thumbnail.getTotalLength() > 0.0) | |||||
| { | |||||
| thumbnail.drawChannels (g, getLocalBounds().reduced (2), | |||||
| 0.0, thumbnail.getTotalLength(), 1.0f); | |||||
| g.setColour (Colours::black); | |||||
| g.fillRect (static_cast<float> (currentPosition * getWidth()), 0.0f, | |||||
| 1.0f, static_cast<float> (getHeight())); | |||||
| } | |||||
| else | |||||
| { | |||||
| g.drawFittedText ("No audio file loaded.\nDrop a file here or click the \"Load File...\" button.", getLocalBounds(), | |||||
| Justification::centred, 2); | |||||
| } | |||||
| } | |||||
| bool isInterestedInFileDrag (const StringArray&) override { return true; } | |||||
| void filesDropped (const StringArray& files, int, int) override { loadURL (URL (File (files[0])), true); } | |||||
| void setCurrentURL (const URL& u) | |||||
| { | |||||
| if (currentURL == u) | |||||
| return; | |||||
| loadURL (u); | |||||
| } | |||||
| URL getCurrentURL() { return currentURL; } | |||||
| void setTransportSource (AudioTransportSource* newSource) | |||||
| { | |||||
| transportSource = newSource; | |||||
| struct ResetCallback : public CallbackMessage | |||||
| { | |||||
| ResetCallback (AudioThumbnailComponent& o) : owner (o) {} | |||||
| void messageCallback() override { owner.reset(); } | |||||
| AudioThumbnailComponent& owner; | |||||
| }; | |||||
| (new ResetCallback (*this))->post(); | |||||
| } | |||||
| private: | |||||
| AudioDeviceManager& audioDeviceManager; | |||||
| AudioThumbnailCache thumbnailCache; | |||||
| AudioThumbnail thumbnail; | |||||
| AudioTransportSource* transportSource = nullptr; | |||||
| URL currentURL; | |||||
| double currentPosition = 0.0; | |||||
| //============================================================================== | |||||
| void changeListenerCallback (ChangeBroadcaster*) override { repaint(); } | |||||
| void reset() | |||||
| { | |||||
| currentPosition = 0.0; | |||||
| repaint(); | |||||
| if (transportSource == nullptr) | |||||
| stopTimer(); | |||||
| else | |||||
| startTimerHz (25); | |||||
| } | |||||
| void loadURL (const URL& u, bool notify = false) | |||||
| { | |||||
| if (currentURL == u) | |||||
| return; | |||||
| currentURL = u; | |||||
| InputSource* inputSource = nullptr; | |||||
| #if ! JUCE_IOS | |||||
| if (u.isLocalFile()) | |||||
| { | |||||
| inputSource = new FileInputSource (u.getLocalFile()); | |||||
| } | |||||
| else | |||||
| #endif | |||||
| { | |||||
| if (inputSource == nullptr) | |||||
| inputSource = new URLInputSource (u); | |||||
| } | |||||
| thumbnail.setSource (inputSource); | |||||
| if (notify) | |||||
| sendChangeMessage(); | |||||
| } | |||||
| void timerCallback() override | |||||
| { | |||||
| if (transportSource != nullptr) | |||||
| { | |||||
| currentPosition = transportSource->getCurrentPosition() / thumbnail.getTotalLength(); | |||||
| repaint(); | |||||
| } | |||||
| } | |||||
| void mouseDrag (const MouseEvent& e) override | |||||
| { | |||||
| if (transportSource != nullptr) | |||||
| { | |||||
| const ScopedLock sl (audioDeviceManager.getAudioCallbackLock()); | |||||
| transportSource->setPosition ((jmax (static_cast<double> (e.x), 0.0) / getWidth()) | |||||
| * thumbnail.getTotalLength()); | |||||
| } | |||||
| } | |||||
| }; | |||||
| //============================================================================== | |||||
| class DemoParametersComponent : public Component | |||||
| { | |||||
| public: | |||||
| DemoParametersComponent (const std::vector<DSPDemoParameterBase*>& demoParams) | |||||
| { | |||||
| parameters = demoParams; | |||||
| for (auto demoParameter : parameters) | |||||
| { | |||||
| addAndMakeVisible (demoParameter->getComponent()); | |||||
| auto* paramLabel = new Label ({}, demoParameter->name); | |||||
| paramLabel->attachToComponent (demoParameter->getComponent(), true); | |||||
| paramLabel->setJustificationType (Justification::centredLeft); | |||||
| addAndMakeVisible (paramLabel); | |||||
| labels.add (paramLabel); | |||||
| } | |||||
| } | |||||
| void resized() override | |||||
| { | |||||
| auto bounds = getLocalBounds(); | |||||
| bounds.removeFromLeft (100); | |||||
| for (auto* p : parameters) | |||||
| { | |||||
| auto* comp = p->getComponent(); | |||||
| comp->setSize (jmin (bounds.getWidth(), p->getPreferredWidth()), p->getPreferredHeight()); | |||||
| auto compBounds = bounds.removeFromTop (p->getPreferredHeight()); | |||||
| comp->setCentrePosition (compBounds.getCentre()); | |||||
| } | |||||
| } | |||||
| int getHeightNeeded() | |||||
| { | |||||
| auto height = 0; | |||||
| for (auto* p : parameters) | |||||
| height += p->getPreferredHeight(); | |||||
| return height + 10; | |||||
| } | |||||
| private: | |||||
| std::vector<DSPDemoParameterBase*> parameters; | |||||
| OwnedArray<Label> labels; | |||||
| }; | |||||
| //============================================================================== | |||||
| template <class DemoType> | |||||
| struct DSPDemo : public AudioSource, | |||||
| public ProcessorWrapper<DemoType>, | |||||
| private ChangeListener | |||||
| { | |||||
| DSPDemo (AudioSource& input) | |||||
| : inputSource (&input) | |||||
| { | |||||
| for (auto* p : getParameters()) | |||||
| p->addChangeListener (this); | |||||
| } | |||||
| void prepareToPlay (int blockSize, double sampleRate) override | |||||
| { | |||||
| inputSource->prepareToPlay (blockSize, sampleRate); | |||||
| this->prepare ({ sampleRate, (uint32) blockSize, 2 }); | |||||
| } | |||||
| void releaseResources() override | |||||
| { | |||||
| inputSource->releaseResources(); | |||||
| } | |||||
| void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill) override | |||||
| { | |||||
| jassert (bufferToFill.buffer != nullptr); | |||||
| inputSource->getNextAudioBlock (bufferToFill); | |||||
| dsp::AudioBlock<float> block (*bufferToFill.buffer, | |||||
| (size_t) bufferToFill.startSample); | |||||
| ScopedLock audioLock (audioCallbackLock); | |||||
| this->process (ProcessContextReplacing<float> (block)); | |||||
| } | |||||
| const std::vector<DSPDemoParameterBase*>& getParameters() | |||||
| { | |||||
| return this->processor.parameters; | |||||
| } | |||||
| void changeListenerCallback (ChangeBroadcaster*) override | |||||
| { | |||||
| ScopedLock audioLock (audioCallbackLock); | |||||
| static_cast<DemoType&> (this->processor).updateParameters(); | |||||
| } | |||||
| CriticalSection audioCallbackLock; | |||||
| AudioSource* inputSource; | |||||
| }; | |||||
| //============================================================================== | |||||
| template <class DemoType> | |||||
| class AudioFileReaderComponent : public Component, | |||||
| private TimeSliceThread, | |||||
| private Value::Listener, | |||||
| private ChangeListener | |||||
| { | |||||
| public: | |||||
| //============================================================================== | |||||
| AudioFileReaderComponent() | |||||
| : TimeSliceThread ("Audio File Reader Thread"), | |||||
| header (audioDeviceManager, formatManager, *this) | |||||
| { | |||||
| loopState.addListener (this); | |||||
| formatManager.registerBasicFormats(); | |||||
| audioDeviceManager.addAudioCallback (&audioSourcePlayer); | |||||
| #ifndef JUCE_DEMO_RUNNER | |||||
| audioDeviceManager.initialiseWithDefaultDevices (0, 2); | |||||
| #endif | |||||
| init(); | |||||
| startThread(); | |||||
| setOpaque (true); | |||||
| addAndMakeVisible (header); | |||||
| setSize (800, 250); | |||||
| } | |||||
| ~AudioFileReaderComponent() | |||||
| { | |||||
| signalThreadShouldExit(); | |||||
| stop(); | |||||
| audioDeviceManager.removeAudioCallback (&audioSourcePlayer); | |||||
| waitForThreadToExit (10000); | |||||
| } | |||||
| void paint (Graphics& g) override | |||||
| { | |||||
| g.setColour (getLookAndFeel().findColour (ResizableWindow::backgroundColourId)); | |||||
| g.fillRect (getLocalBounds()); | |||||
| } | |||||
| void resized() override | |||||
| { | |||||
| auto r = getLocalBounds(); | |||||
| header.setBounds (r.removeFromTop (120)); | |||||
| r.removeFromTop (20); | |||||
| if (parametersComponent.get() != nullptr) | |||||
| parametersComponent->setBounds (r.removeFromTop (parametersComponent->getHeightNeeded()).reduced (20, 0)); | |||||
| } | |||||
| //============================================================================== | |||||
| bool loadURL (const URL& fileToPlay) | |||||
| { | |||||
| stop(); | |||||
| audioSourcePlayer.setSource (nullptr); | |||||
| getThumbnailComponent().setTransportSource (nullptr); | |||||
| transportSource.reset(); | |||||
| readerSource.reset(); | |||||
| AudioFormatReader* newReader = nullptr; | |||||
| #if ! JUCE_IOS | |||||
| if (fileToPlay.isLocalFile()) | |||||
| { | |||||
| newReader = formatManager.createReaderFor (fileToPlay.getLocalFile()); | |||||
| } | |||||
| else | |||||
| #endif | |||||
| { | |||||
| if (newReader == nullptr) | |||||
| newReader = formatManager.createReaderFor (fileToPlay.createInputStream (false)); | |||||
| } | |||||
| reader.reset (newReader); | |||||
| if (reader.get() != nullptr) | |||||
| { | |||||
| readerSource.reset (new AudioFormatReaderSource (reader.get(), false)); | |||||
| readerSource->setLooping (loopState.getValue()); | |||||
| init(); | |||||
| return true; | |||||
| } | |||||
| return false; | |||||
| } | |||||
| void togglePlay() | |||||
| { | |||||
| if (playState.getValue()) | |||||
| stop(); | |||||
| else | |||||
| play(); | |||||
| } | |||||
| void stop() | |||||
| { | |||||
| playState = false; | |||||
| if (transportSource.get() != nullptr) | |||||
| { | |||||
| transportSource->stop(); | |||||
| transportSource->setPosition (0); | |||||
| } | |||||
| } | |||||
| void init() | |||||
| { | |||||
| if (transportSource.get() == nullptr) | |||||
| { | |||||
| transportSource.reset (new AudioTransportSource()); | |||||
| transportSource->addChangeListener (this); | |||||
| if (readerSource.get() != nullptr) | |||||
| { | |||||
| if (auto* device = audioDeviceManager.getCurrentAudioDevice()) | |||||
| { | |||||
| transportSource->setSource (readerSource.get(), roundToInt (device->getCurrentSampleRate()), this, reader->sampleRate); | |||||
| getThumbnailComponent().setTransportSource (transportSource.get()); | |||||
| } | |||||
| } | |||||
| } | |||||
| audioSourcePlayer.setSource (nullptr); | |||||
| currentDemo.reset(); | |||||
| if (currentDemo.get() == nullptr) | |||||
| currentDemo.reset (new DSPDemo<DemoType> (*transportSource)); | |||||
| audioSourcePlayer.setSource (currentDemo.get()); | |||||
| initParameters(); | |||||
| } | |||||
| void play() | |||||
| { | |||||
| if (readerSource.get() == nullptr) | |||||
| return; | |||||
| if (transportSource->getCurrentPosition() >= transportSource->getLengthInSeconds() | |||||
| || transportSource->getCurrentPosition() < 0) | |||||
| transportSource->setPosition (0); | |||||
| transportSource->start(); | |||||
| playState = true; | |||||
| } | |||||
| void setLooping (bool shouldLoop) | |||||
| { | |||||
| if (readerSource.get() != nullptr) | |||||
| readerSource->setLooping (shouldLoop); | |||||
| } | |||||
| AudioThumbnailComponent& getThumbnailComponent() { return header.thumbnailComp; } | |||||
| void initParameters() | |||||
| { | |||||
| auto& parameters = currentDemo->getParameters(); | |||||
| parametersComponent.reset(); | |||||
| if (parameters.size() > 0) | |||||
| { | |||||
| parametersComponent.reset (new DemoParametersComponent (parameters)); | |||||
| addAndMakeVisible (parametersComponent.get()); | |||||
| } | |||||
| resized(); | |||||
| } | |||||
| private: | |||||
| //============================================================================== | |||||
| class AudioPlayerHeader : public Component, | |||||
| private ChangeListener, | |||||
| private Value::Listener | |||||
| { | |||||
| public: | |||||
| AudioPlayerHeader (AudioDeviceManager& adm, | |||||
| AudioFormatManager& afm, | |||||
| AudioFileReaderComponent& afr) | |||||
| : thumbnailComp (adm, afm), | |||||
| audioFileReader (afr) | |||||
| { | |||||
| setOpaque (true); | |||||
| addAndMakeVisible (loadButton); | |||||
| addAndMakeVisible (playButton); | |||||
| addAndMakeVisible (loopButton); | |||||
| playButton.setColour (TextButton::buttonColourId, Colour (0xff79ed7f)); | |||||
| playButton.setColour (TextButton::textColourOffId, Colours::black); | |||||
| loadButton.setColour (TextButton::buttonColourId, Colour (0xff797fed)); | |||||
| loadButton.setColour (TextButton::textColourOffId, Colours::black); | |||||
| loadButton.onClick = [this] { openFile(); }; | |||||
| playButton.onClick = [this] { audioFileReader.togglePlay(); }; | |||||
| addAndMakeVisible (thumbnailComp); | |||||
| thumbnailComp.addChangeListener (this); | |||||
| audioFileReader.playState.addListener (this); | |||||
| loopButton.getToggleStateValue().referTo (audioFileReader.loopState); | |||||
| } | |||||
| ~AudioPlayerHeader() | |||||
| { | |||||
| audioFileReader.playState.removeListener (this); | |||||
| } | |||||
| void paint (Graphics& g) override | |||||
| { | |||||
| g.setColour (getLookAndFeel().findColour (ResizableWindow::backgroundColourId).darker()); | |||||
| g.fillRect (getLocalBounds()); | |||||
| } | |||||
| void resized() override | |||||
| { | |||||
| auto bounds = getLocalBounds(); | |||||
| auto buttonBounds = bounds.removeFromLeft (jmin (250, bounds.getWidth() / 4)); | |||||
| auto loopBounds = buttonBounds.removeFromBottom (30); | |||||
| loadButton.setBounds (buttonBounds.removeFromTop (buttonBounds.getHeight() / 2)); | |||||
| playButton.setBounds (buttonBounds); | |||||
| loopButton.setSize (0, 25); | |||||
| loopButton.changeWidthToFitText(); | |||||
| loopButton.setCentrePosition (loopBounds.getCentre()); | |||||
| thumbnailComp.setBounds (bounds); | |||||
| } | |||||
| AudioThumbnailComponent thumbnailComp; | |||||
| private: | |||||
| //============================================================================== | |||||
| void openFile() | |||||
| { | |||||
| audioFileReader.stop(); | |||||
| if (fileChooser == nullptr) | |||||
| { | |||||
| SafePointer<AudioPlayerHeader> safeThis (this); | |||||
| if (! RuntimePermissions::isGranted (RuntimePermissions::readExternalStorage)) | |||||
| { | |||||
| RuntimePermissions::request (RuntimePermissions::readExternalStorage, | |||||
| [safeThis] (bool granted) mutable | |||||
| { | |||||
| if (granted) | |||||
| safeThis->openFile(); | |||||
| }); | |||||
| return; | |||||
| } | |||||
| fileChooser = new FileChooser ("Select an audio file...", File(), "*.wav;*.mp3;*.aif"); | |||||
| fileChooser->launchAsync (FileBrowserComponent::openMode | FileBrowserComponent::canSelectFiles, | |||||
| [safeThis] (const FileChooser& fc) mutable | |||||
| { | |||||
| if (safeThis != nullptr && fc.getURLResults().size() > 0) | |||||
| { | |||||
| auto u = fc.getURLResult(); | |||||
| if (! safeThis->audioFileReader.loadURL (u)) | |||||
| NativeMessageBox::showOkCancelBox (AlertWindow::WarningIcon, "Error loading file", "Unable to load audio file", nullptr, nullptr); | |||||
| else | |||||
| safeThis->thumbnailComp.setCurrentURL (u); | |||||
| } | |||||
| }, nullptr); | |||||
| } | |||||
| } | |||||
| void changeListenerCallback (ChangeBroadcaster*) override | |||||
| { | |||||
| if (audioFileReader.playState.getValue()) | |||||
| audioFileReader.stop(); | |||||
| audioFileReader.loadURL (thumbnailComp.getCurrentURL()); | |||||
| } | |||||
| void valueChanged (Value& v) override | |||||
| { | |||||
| playButton.setButtonText (v.getValue() ? "Stop" : "Play"); | |||||
| playButton.setColour (TextButton::buttonColourId, v.getValue() ? Colour (0xffed797f) : Colour (0xff79ed7f)); | |||||
| } | |||||
| //============================================================================== | |||||
| TextButton loadButton { "Load File..." }, playButton { "Play" }; | |||||
| ToggleButton loopButton { "Loop File" }; | |||||
| AudioFileReaderComponent& audioFileReader; | |||||
| ScopedPointer<FileChooser> fileChooser; | |||||
| }; | |||||
| //============================================================================== | |||||
| void valueChanged (Value& v) override | |||||
| { | |||||
| if (readerSource.get() != nullptr) | |||||
| readerSource->setLooping (v.getValue()); | |||||
| } | |||||
| void changeListenerCallback (ChangeBroadcaster*) override | |||||
| { | |||||
| if (playState.getValue() && ! transportSource->isPlaying()) | |||||
| stop(); | |||||
| } | |||||
| //============================================================================== | |||||
| // if this PIP is running inside the demo runner, we'll use the shared device manager instead | |||||
| #ifndef JUCE_DEMO_RUNNER | |||||
| AudioDeviceManager audioDeviceManager; | |||||
| #else | |||||
| AudioDeviceManager& audioDeviceManager { getSharedAudioDeviceManager (0, 2) }; | |||||
| #endif | |||||
| AudioFormatManager formatManager; | |||||
| Value playState { var (false) }; | |||||
| Value loopState { var (false) }; | |||||
| double currentSampleRate = 44100.0; | |||||
| uint32 currentBlockSize = 512; | |||||
| uint32 currentNumChannels = 2; | |||||
| ScopedPointer<AudioFormatReader> reader; | |||||
| ScopedPointer<AudioFormatReaderSource> readerSource; | |||||
| ScopedPointer<AudioTransportSource> transportSource; | |||||
| ScopedPointer<DSPDemo<DemoType>> currentDemo; | |||||
| AudioSourcePlayer audioSourcePlayer; | |||||
| AudioPlayerHeader header; | |||||
| AudioBuffer<float> fileReadBuffer; | |||||
| ScopedPointer<DemoParametersComponent> parametersComponent; | |||||
| }; | |||||
| @@ -0,0 +1,233 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE examples. | |||||
| Copyright (c) 2017 - ROLI Ltd. | |||||
| The code included in this file is provided under the terms of the ISC license | |||||
| http://www.isc.org/downloads/software-support-policy/isc-license. Permission | |||||
| To use, copy, modify, and/or distribute this software for any purpose with or | |||||
| without fee is hereby granted provided that the above copyright notice and | |||||
| this permission notice appear in all copies. | |||||
| THE SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, | |||||
| WHETHER EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR | |||||
| PURPOSE, ARE DISCLAIMED. | |||||
| ============================================================================== | |||||
| */ | |||||
| #pragma once | |||||
| #include "../JuceLibraryCode/JuceHeader.h" | |||||
| #ifndef PIP_DEMO_UTILITIES_INCLUDED | |||||
| #define PIP_DEMO_UTILITIES_INCLUDED 1 | |||||
| #endif | |||||
| //============================================================================== | |||||
| /* | |||||
| This file contains a bunch of miscellaneous utilities that are | |||||
| used by the various demos. | |||||
| */ | |||||
| //============================================================================== | |||||
| inline Colour getRandomColour (float brightness) noexcept | |||||
| { | |||||
| return Colour::fromHSV (Random::getSystemRandom().nextFloat(), 0.5f, brightness, 1.0f); | |||||
| } | |||||
| inline Colour getRandomBrightColour() noexcept { return getRandomColour (0.8f); } | |||||
| inline Colour getRandomDarkColour() noexcept { return getRandomColour (0.3f); } | |||||
| inline Colour getUIColourIfAvailable (LookAndFeel_V4::ColourScheme::UIColour uiColour, Colour fallback = Colour (0xff4d4d4d)) noexcept | |||||
| { | |||||
| if (auto* v4 = dynamic_cast<LookAndFeel_V4*> (&LookAndFeel::getDefaultLookAndFeel())) | |||||
| return v4->getCurrentColourScheme().getUIColour (uiColour); | |||||
| return fallback; | |||||
| } | |||||
| inline File getExamplesDirectory() noexcept | |||||
| { | |||||
| #ifdef PIP_JUCE_EXAMPLES_DIRECTORY | |||||
| MemoryOutputStream mo; | |||||
| auto success = Base64::convertFromBase64 (mo, JUCE_STRINGIFY (PIP_JUCE_EXAMPLES_DIRECTORY)); | |||||
| jassert (success); | |||||
| return mo.toString(); | |||||
| #else | |||||
| auto currentFile = File::getSpecialLocation (File::SpecialLocationType::currentExecutableFile); | |||||
| int numTries = 0; // keep track of the number of parent directories so we don't go on endlessly | |||||
| while (currentFile.getFileName() != "examples" && numTries++ < 15) | |||||
| currentFile = currentFile.getParentDirectory(); | |||||
| return currentFile; | |||||
| #endif | |||||
| } | |||||
| inline InputStream* createAssetInputStream (const char* resourcePath) | |||||
| { | |||||
| #if JUCE_ANDROID | |||||
| ZipFile apkZip (File::getSpecialLocation (File::invokedExecutableFile)); | |||||
| return apkZip.createStreamForEntry (apkZip.getIndexOfFileName ("assets/" + String (resourcePath))); | |||||
| #else | |||||
| #if JUCE_IOS | |||||
| auto assetsDir = File::getSpecialLocation (File::currentExecutableFile) | |||||
| .getParentDirectory().getChildFile ("Assets"); | |||||
| #else | |||||
| auto assetsDir = getExamplesDirectory().getChildFile ("Assets"); | |||||
| #endif | |||||
| auto resourceFile = assetsDir.getChildFile (resourcePath); | |||||
| jassert (resourceFile.existsAsFile()); | |||||
| return resourceFile.createInputStream(); | |||||
| #endif | |||||
| } | |||||
| inline Image getImageFromAssets (const char* assetName) | |||||
| { | |||||
| auto hashCode = (String (assetName) + "@juce_demo_assets").hashCode64(); | |||||
| auto img = ImageCache::getFromHashCode (hashCode); | |||||
| if (img.isNull()) | |||||
| { | |||||
| ScopedPointer<InputStream> juceIconStream (createAssetInputStream (assetName)); | |||||
| if (juceIconStream == nullptr) | |||||
| return {}; | |||||
| img = ImageFileFormat::loadFrom (*juceIconStream); | |||||
| ImageCache::addImageToCache (img, hashCode); | |||||
| } | |||||
| return img; | |||||
| } | |||||
| inline String loadEntireAssetIntoString (const char* assetName) | |||||
| { | |||||
| ScopedPointer<InputStream> input (createAssetInputStream (assetName)); | |||||
| if (input == nullptr) | |||||
| return {}; | |||||
| return input->readString(); | |||||
| } | |||||
| //============================================================================== | |||||
| inline Path getJUCELogoPath() | |||||
| { | |||||
| return Drawable::parseSVGPath ( | |||||
| "M250,301.3c-37.2,0-67.5-30.3-67.5-67.5s30.3-67.5,67.5-67.5s67.5,30.3,67.5,67.5S287.2,301.3,250,301.3zM250,170.8c-34.7,0-63,28.3-63,63s28.3,63,63,63s63-28.3,63-63S284.7,170.8,250,170.8z" | |||||
| "M247.8,180.4c0-2.3-1.8-4.1-4.1-4.1c-0.2,0-0.3,0-0.5,0c-10.6,1.2-20.6,5.4-29,12c-1,0.8-1.5,1.8-1.6,2.9c-0.1,1.2,0.4,2.3,1.3,3.2l32.5,32.5c0.5,0.5,1.4,0.1,1.4-0.6V180.4z" | |||||
| "M303.2,231.6c1.2,0,2.3-0.4,3.1-1.2c0.9-0.9,1.3-2.1,1.1-3.3c-1.2-10.6-5.4-20.6-12-29c-0.8-1-1.9-1.6-3.2-1.6c-1.1,0-2.1,0.5-3,1.3l-32.5,32.5c-0.5,0.5-0.1,1.4,0.6,1.4L303.2,231.6z" | |||||
| "M287.4,191.3c-0.1-1.1-0.6-2.2-1.6-2.9c-8.4-6.6-18.4-10.8-29-12c-0.2,0-0.3,0-0.5,0c-2.3,0-4.1,1.9-4.1,4.1v46c0,0.7,0.9,1.1,1.4,0.6l32.5-32.5C287,193.6,287.5,192.5,287.4,191.3z" | |||||
| "M252.2,287.2c0,2.3,1.8,4.1,4.1,4.1c0.2,0,0.3,0,0.5,0c10.6-1.2,20.6-5.4,29-12c1-0.8,1.5-1.8,1.6-2.9c0.1-1.2-0.4-2.3-1.3-3.2l-32.5-32.5c-0.5-0.5-1.4-0.1-1.4,0.6V287.2z" | |||||
| "M292.3,271.2L292.3,271.2c1.2,0,2.4-0.6,3.2-1.6c6.6-8.4,10.8-18.4,12-29c0.1-1.2-0.3-2.4-1.1-3.3c-0.8-0.8-1.9-1.2-3.1-1.2l-45.9,0c-0.7,0-1.1,0.9-0.6,1.4l32.5,32.5C290.2,270.8,291.2,271.2,292.3,271.2z" | |||||
| "M207.7,196.4c-1.2,0-2.4,0.6-3.2,1.6c-6.6,8.4-10.8,18.4-12,29c-0.1,1.2,0.3,2.4,1.1,3.3c0.8,0.8,1.9,1.2,3.1,1.2l45.9,0c0.7,0,1.1-0.9,0.6-1.4l-32.5-32.5C209.8,196.8,208.8,196.4,207.7,196.4z" | |||||
| "M242.6,236.1l-45.9,0c-1.2,0-2.3,0.4-3.1,1.2c-0.9,0.9-1.3,2.1-1.1,3.3c1.2,10.6,5.4,20.6,12,29c0.8,1,1.9,1.6,3.2,1.6c1.1,0,2.1-0.5,3-1.3c0,0,0,0,0,0l32.5-32.5C243.7,236.9,243.4,236.1,242.6,236.1z" | |||||
| "M213.8,273.1L213.8,273.1c-0.9,0.9-1.3,2-1.3,3.2c0.1,1.1,0.6,2.2,1.6,2.9c8.4,6.6,18.4,10.8,29,12c0.2,0,0.3,0,0.5,0h0c1.2,0,2.3-0.5,3.1-1.4c0.7-0.8,1-1.8,1-2.9v-45.9c0-0.7-0.9-1.1-1.4-0.6l-13.9,13.9L213.8,273.1z" | |||||
| "M197.2,353c-4.1,0-7.4-1.5-10.4-5.4l4-3.5c2,2.6,3.9,3.6,6.4,3.6c4.4,0,7.4-3.3,7.4-8.3v-24.7h5.6v24.7C210.2,347.5,204.8,353,197.2,353z" | |||||
| "M232.4,353c-8.1,0-15-6-15-15.8v-22.5h5.6v22.2c0,6.6,3.9,10.8,9.5,10.8c5.6,0,9.5-4.3,9.5-10.8v-22.2h5.6v22.5C247.5,347,240.5,353,232.4,353z" | |||||
| "M272,353c-10.8,0-19.5-8.6-19.5-19.3c0-10.8,8.8-19.3,19.5-19.3c4.8,0,9,1.6,12.3,4.4l-3.3,4.1c-3.4-2.4-5.7-3.2-8.9-3.2c-7.7,0-13.8,6.2-13.8,14.1c0,7.9,6.1,14.1,13.8,14.1c3.1,0,5.6-1,8.8-3.2l3.3,4.1C280.1,351.9,276.4,353,272,353z" | |||||
| "M290.4,352.5v-37.8h22.7v5H296v11.2h16.5v5H296v11.6h17.2v5H290.4z"); | |||||
| } | |||||
| //============================================================================== | |||||
| #if JUCE_MODULE_AVAILABLE_juce_gui_extra | |||||
| inline CodeEditorComponent::ColourScheme getDarkCodeEditorColourScheme() | |||||
| { | |||||
| struct Type | |||||
| { | |||||
| const char* name; | |||||
| juce::uint32 colour; | |||||
| }; | |||||
| const Type types[] = | |||||
| { | |||||
| { "Error", 0xffe60000 }, | |||||
| { "Comment", 0xff72d20c }, | |||||
| { "Keyword", 0xffee6f6f }, | |||||
| { "Operator", 0xffc4eb19 }, | |||||
| { "Identifier", 0xffcfcfcf }, | |||||
| { "Integer", 0xff42c8c4 }, | |||||
| { "Float", 0xff885500 }, | |||||
| { "String", 0xffbc45dd }, | |||||
| { "Bracket", 0xff058202 }, | |||||
| { "Punctuation", 0xffcfbeff }, | |||||
| { "Preprocessor Text", 0xfff8f631 } | |||||
| }; | |||||
| CodeEditorComponent::ColourScheme cs; | |||||
| for (auto& t : types) | |||||
| cs.set (t.name, Colour (t.colour)); | |||||
| return cs; | |||||
| } | |||||
| inline CodeEditorComponent::ColourScheme getLightCodeEditorColourScheme() | |||||
| { | |||||
| struct Type | |||||
| { | |||||
| const char* name; | |||||
| juce::uint32 colour; | |||||
| }; | |||||
| const Type types[] = | |||||
| { | |||||
| { "Error", 0xffcc0000 }, | |||||
| { "Comment", 0xff00aa00 }, | |||||
| { "Keyword", 0xff0000cc }, | |||||
| { "Operator", 0xff225500 }, | |||||
| { "Identifier", 0xff000000 }, | |||||
| { "Integer", 0xff880000 }, | |||||
| { "Float", 0xff885500 }, | |||||
| { "String", 0xff990099 }, | |||||
| { "Bracket", 0xff000055 }, | |||||
| { "Punctuation", 0xff004400 }, | |||||
| { "Preprocessor Text", 0xff660000 } | |||||
| }; | |||||
| CodeEditorComponent::ColourScheme cs; | |||||
| for (auto& t : types) | |||||
| cs.set (t.name, Colour (t.colour)); | |||||
| return cs; | |||||
| } | |||||
| #endif | |||||
| //============================================================================== | |||||
| // This is basically a sawtooth wave generator - maps a value that bounces between | |||||
| // 0.0 and 1.0 at a random speed | |||||
| struct BouncingNumber | |||||
| { | |||||
| BouncingNumber() | |||||
| : speed (0.0004 + 0.0007 * Random::getSystemRandom().nextDouble()), | |||||
| phase (Random::getSystemRandom().nextDouble()) | |||||
| { | |||||
| } | |||||
| float getValue() const | |||||
| { | |||||
| double v = fmod (phase + speed * Time::getMillisecondCounterHiRes(), 2.0); | |||||
| return (float) (v >= 1.0 ? (2.0 - v) : v); | |||||
| } | |||||
| protected: | |||||
| double speed, phase; | |||||
| }; | |||||
| struct SlowerBouncingNumber : public BouncingNumber | |||||
| { | |||||
| SlowerBouncingNumber() | |||||
| { | |||||
| speed *= 0.3; | |||||
| } | |||||
| }; | |||||