Added Box2D

This commit is contained in:
Julian Nießner
2018-05-06 12:43:20 +02:00
parent cb5469bb89
commit d175d433a8
351 changed files with 123545 additions and 1 deletions

View File

@@ -0,0 +1,24 @@
//
// Box2DAppDelegate.h
// Box2D
//
// Box2D iPhone port by Simon Oliver - http://www.simonoliver.com - http://www.handcircus.com
//
#import <UIKit/UIKit.h>
#import "TestEntriesViewController.h"
#import "Delegates.h"
@class Box2DView;
@interface Box2DAppDelegate : NSObject <UIApplicationDelegate,TestSelectDelegate> {
UIWindow *window;
Box2DView *glView;
TestEntriesViewController *testEntriesView;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet Box2DView *glView;
@end

View File

@@ -0,0 +1,62 @@
//
// Box2DAppDelegate.m
// Box2D
//
// Box2D iPhone port by Simon Oliver - http://www.simonoliver.com - http://www.handcircus.com
//
#import <UIKit/UIKit.h>
#import "Box2DAppDelegate.h"
#import "Box2DView.h"
@implementation Box2DAppDelegate
@synthesize window;
@synthesize glView;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
[application setStatusBarHidden:true];
[glView removeFromSuperview];
glView.animationInterval = 1.0 / 60.0;
testEntriesView=[[TestEntriesViewController alloc] initWithStyle:UITableViewStylePlain];
[testEntriesView setDelegate:self];
[glView setDelegate:self];
[window addSubview:[testEntriesView view]];
}
-(void) selectTest:(int) testIndex
{
[[testEntriesView view] removeFromSuperview];
[window addSubview:glView];
[glView startAnimation];
[glView selectTestEntry:testIndex];
}
-(void) leaveTest
{
[glView stopAnimation];
[glView removeFromSuperview];
[window addSubview:[testEntriesView view]];
}
- (void)applicationWillResignActive:(UIApplication *)application {
glView.animationInterval = 1.0 / 5.0;
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
glView.animationInterval = 1.0 / 60.0;
}
- (void)dealloc {
[window release];
[glView release];
[super dealloc];
}
@end

View File

@@ -0,0 +1,63 @@
//
// Box2DView.h
// Box2D OpenGL View
//
// Box2D iPhone port by Simon Oliver - http://www.simonoliver.com - http://www.handcircus.com
//
#import <UIKit/UIKit.h>
#import <OpenGLES/EAGL.h>
#import <OpenGLES/ES1/gl.h>
#import <OpenGLES/ES1/glext.h>
#import "iPhoneTest.h"
#import "Delegates.h"
/*
This class wraps the CAEAGLLayer from CoreAnimation into a convenient UIView subclass.
The view content is basically an EAGL surface you render your OpenGL scene into.
Note that setting the view non-opaque will only work if the EAGL surface has an alpha channel.
*/
@interface Box2DView : UIView <UIAccelerometerDelegate> {
@private
/* The pixel dimensions of the backbuffer */
GLint backingWidth;
GLint backingHeight;
EAGLContext *context;
/* OpenGL names for the renderbuffer and framebuffers used to render to this view */
GLuint viewRenderbuffer, viewFramebuffer;
/* OpenGL name for the depth buffer that is attached to viewFramebuffer, if it exists (0 if it does not exist) */
GLuint depthRenderbuffer;
NSTimer *animationTimer;
NSTimeInterval animationInterval;
TestEntry* entry;
Test* test;
// Position offset and scale
float sceneScale;
CGPoint positionOffset;
CGPoint lastWorldTouch;
CGPoint lastScreenTouch;
bool panning;
int doubleClickValidCountdown;
id<TestSelectDelegate> _delegate;
}
@property(assign) id<TestSelectDelegate> delegate;
@property NSTimeInterval animationInterval;
- (void)startAnimation;
- (void)stopAnimation;
- (void)drawView;
-(void) selectTestEntry:(int) testIndex;
@end

View File

@@ -0,0 +1,299 @@
//
// Box2DView.mm
// Box2D OpenGL View
//
// Box2D iPhone port by Simon Oliver - http://www.simonoliver.com - http://www.handcircus.com
//
#import <QuartzCore/QuartzCore.h>
#import <OpenGLES/EAGLDrawable.h>
#import "Box2DView.h"
#define USE_DEPTH_BUFFER 0
#define kAccelerometerFrequency 30
#define FRAMES_BETWEEN_PRESSES_FOR_DOUBLE_CLICK 10
Settings settings;
// A class extension to declare private methods
@interface Box2DView ()
@property (nonatomic, retain) EAGLContext *context;
@property (nonatomic, assign) NSTimer *animationTimer;
- (BOOL) createFramebuffer;
- (void) destroyFramebuffer;
@end
@implementation Box2DView
@synthesize context;
@synthesize animationTimer;
@synthesize animationInterval;
@synthesize delegate=_delegate;
// You must implement this method
+ (Class)layerClass {
return [CAEAGLLayer class];
}
//The GL view is stored in the nib file. When it's unarchived it's sent -initWithCoder:
- (id)initWithCoder:(NSCoder*)coder {
if ((self = [super initWithCoder:coder])) {
// Get the layer
CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
eaglLayer.opaque = YES;
eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
if (!context || ![EAGLContext setCurrentContext:context]) {
[self release];
return nil;
}
animationInterval = 1.0 / 60.0;
sceneScale=10.0f;
positionOffset=CGPointMake(0, 0);
lastWorldTouch=CGPointMake(0, 0);
[[UIAccelerometer sharedAccelerometer] setUpdateInterval:(1.0 / kAccelerometerFrequency)];
[[UIAccelerometer sharedAccelerometer] setDelegate:self];
//[self setMultipleTouchEnabled:YES];
}
return self;
}
-(void) selectTestEntry:(int) testIndex
{
// Destroy existing scene
delete test;
entry = g_testEntries + testIndex;
test = entry->createFcn();
doubleClickValidCountdown=0;
sceneScale=10.0f;
positionOffset=CGPointMake(0, 0);
lastWorldTouch=CGPointMake(0, 0);
}
- (void)drawView {
if (doubleClickValidCountdown>0) doubleClickValidCountdown--;
[EAGLContext setCurrentContext:context];
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
glViewport(0, 0, backingWidth, backingHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrthof(-sceneScale, sceneScale, -sceneScale*1.5f, sceneScale*1.5f, -1.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(positionOffset.x, positionOffset.y,0);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnableClientState(GL_VERTEX_ARRAY);
test->Step(&settings);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
}
- (void)layoutSubviews {
[EAGLContext setCurrentContext:context];
[self destroyFramebuffer];
[self createFramebuffer];
[self drawView];
}
- (BOOL)createFramebuffer {
glGenFramebuffersOES(1, &viewFramebuffer);
glGenRenderbuffersOES(1, &viewRenderbuffer);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
[context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
if (USE_DEPTH_BUFFER) {
glGenRenderbuffersOES(1, &depthRenderbuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, backingWidth, backingHeight);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
}
if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) {
NSLog(@"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
return NO;
}
return YES;
}
- (void)destroyFramebuffer {
glDeleteFramebuffersOES(1, &viewFramebuffer);
viewFramebuffer = 0;
glDeleteRenderbuffersOES(1, &viewRenderbuffer);
viewRenderbuffer = 0;
if(depthRenderbuffer) {
glDeleteRenderbuffersOES(1, &depthRenderbuffer);
depthRenderbuffer = 0;
}
}
- (void)startAnimation {
self.animationTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval target:self selector:@selector(drawView) userInfo:nil repeats:YES];
}
- (void)stopAnimation {
self.animationTimer = nil;
}
- (void)setAnimationTimer:(NSTimer *)newTimer {
[animationTimer invalidate];
animationTimer = newTimer;
}
- (void)setAnimationInterval:(NSTimeInterval)interval {
animationInterval = interval;
if (animationTimer) {
[self stopAnimation];
[self startAnimation];
}
}
- (void)dealloc {
[self stopAnimation];
if ([EAGLContext currentContext] == context) {
[EAGLContext setCurrentContext:nil];
}
[context release];
[super dealloc];
}
-(CGPoint) screenSpaceToWorldSpace:(CGPoint) screenLocation
{
screenLocation.x-=160;
screenLocation.y-=240;
screenLocation.x/=160;
screenLocation.y/=160;
screenLocation.x*=sceneScale;
screenLocation.y*=-sceneScale;
screenLocation.x-=positionOffset.x;
screenLocation.y-=positionOffset.y;
return screenLocation;
}
- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
{
if (doubleClickValidCountdown>0)
{
[_delegate leaveTest];
return;
}
doubleClickValidCountdown=FRAMES_BETWEEN_PRESSES_FOR_DOUBLE_CLICK;
panning=false;
for (UITouch *touch in touches)
{
CGPoint touchLocation=[touch locationInView:self];
CGPoint worldPosition=[self screenSpaceToWorldSpace:touchLocation];
//printf("Screen touched %f,%f -> %f,%f\n",touchLocation.x,touchLocation.y,worldPosition.x,worldPosition.y);
lastScreenTouch=touchLocation;
lastWorldTouch=worldPosition;
b2Vec2 p = b2Vec2(lastWorldTouch.x,lastWorldTouch.y);
test->MouseDown(p);
//test->ShiftMouseDown(p);
if (!test->m_mouseJoint) panning=true;
}
}
- (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
for (UITouch *touch in touches)
{
CGPoint touchLocation=[touch locationInView:self];
CGPoint worldPosition=[self screenSpaceToWorldSpace:touchLocation];
//printf("Screen touched %f,%f -> %f,%f\n",touchLocation.x,touchLocation.y,worldPosition.x,worldPosition.y);
CGPoint screenDistanceMoved=CGPointMake(touchLocation.x-lastScreenTouch.x,touchLocation.y-lastScreenTouch.y);
if (panning)
{
screenDistanceMoved.x/=160;
screenDistanceMoved.y/=160;
screenDistanceMoved.x*=sceneScale;
screenDistanceMoved.y*=-sceneScale;
positionOffset.x+=screenDistanceMoved.x;
positionOffset.y+=screenDistanceMoved.y;
}
lastScreenTouch=touchLocation;
lastWorldTouch=worldPosition;
test->MouseMove(b2Vec2(lastWorldTouch.x,lastWorldTouch.y));
}
}
- (void) touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event
{
test->MouseUp(b2Vec2(lastWorldTouch.x,lastWorldTouch.y));
}
- (void) accelerometer:(UIAccelerometer*)accelerometer didAccelerate:(UIAcceleration*)acceleration
{
// Only run for valid values
if (acceleration.y!=0 && acceleration.x!=0)
{
if (test) test->SetGravity(acceleration.x,acceleration.y);
}
}
@end

View File

@@ -0,0 +1,14 @@
/*
* Delegates.h
* Box2D
*
* Box2D iPhone port by Simon Oliver - http://www.simonoliver.com - http://www.handcircus.com
*
*
*/
@protocol TestSelectDelegate <NSObject>
-(void) selectTest:(int) testIndex;
-(void) leaveTest;
@end

View File

@@ -0,0 +1,58 @@
/*
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
*
* iPhone port by Simon Oliver - http://www.simonoliver.com - http://www.handcircus.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef RENDER_H
#define RENDER_H
#import <UIKit/UIKit.h>
#import <OpenGLES/EAGL.h>
#import <OpenGLES/ES1/gl.h>
#import <OpenGLES/ES1/glext.h>
#include <Box2D/Box2D.h>
struct b2AABB;
// This class implements debug drawing callbacks that are invoked
// inside b2World::Step.
class GLESDebugDraw : public b2Draw
{
public:
void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color);
void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color);
void DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color);
void DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color);
void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color);
void DrawTransform(const b2Transform& xf);
void DrawPoint(const b2Vec2& p, float32 size, const b2Color& color);
void DrawString(int x, int y, const char* string, ...);
void DrawAABB(b2AABB* aabb, const b2Color& color);
};
#endif

View File

@@ -0,0 +1,149 @@
/*
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
*
* iPhone port by Simon Oliver - http://www.simonoliver.com - http://www.handcircus.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include "GLES-Render.h"
#include <cstdio>
#include <cstdarg>
#include <cstring>
void GLESDebugDraw::DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color)
{
glColor4f(color.r, color.g, color.b,1);
glVertexPointer(2, GL_FLOAT, 0, vertices);
glDrawArrays(GL_LINE_LOOP, 0, vertexCount);
}
void GLESDebugDraw::DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color)
{
glVertexPointer(2, GL_FLOAT, 0, vertices);
glColor4f(color.r, color.g, color.b,0.5f);
glDrawArrays(GL_TRIANGLE_FAN, 0, vertexCount);
glColor4f(color.r, color.g, color.b,1);
glDrawArrays(GL_LINE_LOOP, 0, vertexCount);
}
void GLESDebugDraw::DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color)
{
const float32 k_segments = 16.0f;
int vertexCount=16;
const float32 k_increment = 2.0f * b2_pi / k_segments;
float32 theta = 0.0f;
GLfloat glVertices[vertexCount*2];
for (int32 i = 0; i < k_segments; ++i)
{
b2Vec2 v = center + radius * b2Vec2(cosf(theta), sinf(theta));
glVertices[i*2]=v.x;
glVertices[i*2+1]=v.y;
theta += k_increment;
}
glColor4f(color.r, color.g, color.b,1);
glVertexPointer(2, GL_FLOAT, 0, glVertices);
glDrawArrays(GL_TRIANGLE_FAN, 0, vertexCount);
}
void GLESDebugDraw::DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color)
{
const float32 k_segments = 16.0f;
int vertexCount=16;
const float32 k_increment = 2.0f * b2_pi / k_segments;
float32 theta = 0.0f;
GLfloat glVertices[vertexCount*2];
for (int32 i = 0; i < k_segments; ++i)
{
b2Vec2 v = center + radius * b2Vec2(cosf(theta), sinf(theta));
glVertices[i*2]=v.x;
glVertices[i*2+1]=v.y;
theta += k_increment;
}
glColor4f(color.r, color.g, color.b,0.5f);
glVertexPointer(2, GL_FLOAT, 0, glVertices);
glDrawArrays(GL_TRIANGLE_FAN, 0, vertexCount);
glColor4f(color.r, color.g, color.b,1);
glDrawArrays(GL_LINE_LOOP, 0, vertexCount);
// Draw the axis line
DrawSegment(center,center+radius*axis,color);
}
void GLESDebugDraw::DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color)
{
glColor4f(color.r, color.g, color.b,1);
GLfloat glVertices[] = {
p1.x,p1.y,p2.x,p2.y
};
glVertexPointer(2, GL_FLOAT, 0, glVertices);
glDrawArrays(GL_LINES, 0, 2);
}
void GLESDebugDraw::DrawTransform(const b2Transform& xf)
{
b2Vec2 p1 = xf.position, p2;
const float32 k_axisScale = 0.4f;
p2 = p1 + k_axisScale * xf.R.col1;
DrawSegment(p1,p2,b2Color(1,0,0));
p2 = p1 + k_axisScale * xf.R.col2;
DrawSegment(p1,p2,b2Color(0,1,0));
}
void GLESDebugDraw::DrawPoint(const b2Vec2& p, float32 size, const b2Color& color)
{
glColor4f(color.r, color.g, color.b,1);
glPointSize(size);
GLfloat glVertices[] = {
p.x,p.y
};
glVertexPointer(2, GL_FLOAT, 0, glVertices);
glDrawArrays(GL_POINTS, 0, 1);
glPointSize(1.0f);
}
void GLESDebugDraw::DrawString(int x, int y, const char *string, ...)
{
/* Unsupported as yet. Could replace with bitmap font renderer at a later date */
}
void GLESDebugDraw::DrawAABB(b2AABB* aabb, const b2Color& c)
{
glColor4f(c.r, c.g, c.b,1);
GLfloat glVertices[] = {
aabb->lowerBound.x, aabb->lowerBound.y,
aabb->upperBound.x, aabb->lowerBound.y,
aabb->upperBound.x, aabb->upperBound.y,
aabb->lowerBound.x, aabb->upperBound.y
};
glVertexPointer(2, GL_FLOAT, 0, glVertices);
glDrawArrays(GL_LINE_LOOP, 0, 8);
}

View File

@@ -0,0 +1,19 @@
//
// TestEntriesViewController.h
// Box2D
//
// Box2D iPhone port by Simon Oliver - http://www.simonoliver.com - http://www.handcircus.com
//
#import <UIKit/UIKit.h>
#import "iPhoneTest.h"
#import "Delegates.h"
@interface TestEntriesViewController : UITableViewController {
int32 testCount;
id<TestSelectDelegate> _delegate;
}
@property(assign) id<TestSelectDelegate> delegate;
@end

View File

@@ -0,0 +1,75 @@
//
// TestEntriesViewController.m
// Box2D
//
// Box2D iPhone port by Simon Oliver - http://www.simonoliver.com - http://www.handcircus.com
//
#import "TestEntriesViewController.h"
@implementation TestEntriesViewController
@synthesize delegate=_delegate;
- (id)initWithStyle:(UITableViewStyle)style {
if (self = [super initWithStyle:style]) {
testCount = 0;
TestEntry* e = g_testEntries;
while (e->createFcn)
{
++testCount;
++e;
}
}
return self;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
// Release anything that's not essential, such as cached data
}
#pragma mark Table view methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return testCount;
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
// Set up the cell...
TestEntry* e = g_testEntries;
e+=indexPath.row;
cell.textLabel.text = [NSString stringWithUTF8String:e->name];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[_delegate selectTest:indexPath.row];
}
- (void)dealloc {
[super dealloc];
}
@end

View File

@@ -0,0 +1,189 @@
/*
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
*
* iPhone port by Simon Oliver - http://www.simonoliver.com - http://www.handcircus.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef TEST_H
#define TEST_H
#import <UIKit/UIKit.h>
#include <Box2D/Box2D.h>
#include "GLES-Render.h"
#include <cstdlib>
class Test;
struct Settings;
typedef Test* TestCreateFcn();
#define RAND_LIMIT 32767
/// Random number in range [-1,1]
inline float32 RandomFloat()
{
float32 r = (float32)(rand() & (RAND_LIMIT));
r /= RAND_LIMIT;
r = 2.0f * r - 1.0f;
return r;
}
/// Random floating point number in range [lo, hi]
inline float32 RandomFloat(float32 lo, float32 hi)
{
float32 r = (float32)(rand() & (RAND_LIMIT));
r /= RAND_LIMIT;
r = (hi - lo) * r + lo;
return r;
}
/// Test settings. Some can be controlled in the GUI.
struct Settings
{
Settings() :
viewCenter(0.0f, 20.0f),
hz(60.0f),
velocityIterations(8),
positionIterations(3),
drawShapes(1),
drawJoints(1),
drawAABBs(0),
drawPairs(0),
drawContactPoints(0),
drawContactNormals(0),
drawContactForces(0),
drawFrictionForces(0),
drawCOMs(0),
drawStats(0),
enableWarmStarting(1),
enableContinuous(1),
enableSubStepping(0),
pause(0),
singleStep(0)
{}
b2Vec2 viewCenter;
float32 hz;
int32 velocityIterations;
int32 positionIterations;
int32 drawShapes;
int32 drawJoints;
int32 drawAABBs;
int32 drawPairs;
int32 drawContactPoints;
int32 drawContactNormals;
int32 drawContactForces;
int32 drawFrictionForces;
int32 drawCOMs;
int32 drawStats;
int32 enableWarmStarting;
int32 enableContinuous;
int32 enableSubStepping;
int32 pause;
int32 singleStep;
};
struct TestEntry
{
const char *name;
TestCreateFcn *createFcn;
};
extern TestEntry g_testEntries[];
// This is called when a joint in the world is implicitly destroyed
// because an attached body is destroyed. This gives us a chance to
// nullify the mouse joint.
class DestructionListener : public b2DestructionListener
{
public:
void SayGoodbye(b2Fixture* fixture) { B2_NOT_USED(fixture); }
void SayGoodbye(b2Joint* joint);
Test* test;
};
const int32 k_maxContactPoints = 2048;
struct ContactPoint
{
b2Fixture* fixtureA;
b2Fixture* fixtureB;
b2Vec2 normal;
b2Vec2 position;
b2PointState state;
};
class Test : public b2ContactListener
{
public:
Test();
virtual ~Test();
void SetGravity(float x,float y);
void SetTextLine(int32 line) { m_textLine = line; }
void DrawTitle(int x, int y, const char *string);
virtual void Step(Settings* settings);
virtual void Keyboard(unsigned char key) { B2_NOT_USED(key); }
void ShiftMouseDown(const b2Vec2& p);
virtual void MouseDown(const b2Vec2& p);
virtual void MouseUp(const b2Vec2& p);
void MouseMove(const b2Vec2& p);
void LaunchBomb();
void LaunchBomb(const b2Vec2& position, const b2Vec2& velocity);
void SpawnBomb(const b2Vec2& worldPt);
void CompleteBombSpawn(const b2Vec2& p);
// Let derived tests know that a joint was destroyed.
virtual void JointDestroyed(b2Joint* joint) { B2_NOT_USED(joint); }
// Callbacks for derived classes.
virtual void BeginContact(b2Contact* contact) { B2_NOT_USED(contact); }
virtual void EndContact(b2Contact* contact) { B2_NOT_USED(contact); }
virtual void PreSolve(b2Contact* contact, const b2Manifold* oldManifold);
virtual void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse)
{
B2_NOT_USED(contact);
B2_NOT_USED(impulse);
}
protected:
friend class DestructionListener;
friend class BoundaryListener;
friend class ContactListener;
b2Body* m_groundBody;
b2AABB m_worldAABB;
ContactPoint m_points[k_maxContactPoints];
int32 m_pointCount;
DestructionListener m_destructionListener;
GLESDebugDraw m_debugDraw;
int32 m_textLine;
b2World* m_world;
b2Body* m_bomb;
b2MouseJoint* m_mouseJoint;
b2Vec2 m_bombSpawnPoint;
bool m_bombSpawning;
b2Vec2 m_mouseWorld;
int32 m_stepCount;
};
#endif

View File

@@ -0,0 +1,415 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* iPhone port by Simon Oliver - http://www.simonoliver.com - http://www.handcircus.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include "iPhoneTest.h"
#include "GLES-Render.h"
#include <cstdio>
void DestructionListener::SayGoodbye(b2Joint* joint)
{
if (test->m_mouseJoint == joint)
{
test->m_mouseJoint = NULL;
}
else
{
test->JointDestroyed(joint);
}
}
Test::Test()
: m_debugDraw()
{
b2Vec2 gravity;
gravity.Set(0.0f, -10.0f);
bool doSleep = true;
m_world = new b2World(gravity, doSleep);
m_bomb = NULL;
m_textLine = 30;
m_mouseJoint = NULL;
m_pointCount = 0;
m_destructionListener.test = this;
m_world->SetDestructionListener(&m_destructionListener);
m_world->SetContactListener(this);
m_world->SetDebugDraw(&m_debugDraw);
m_bombSpawning = false;
m_stepCount = 0;
b2BodyDef bodyDef;
m_groundBody = m_world->CreateBody(&bodyDef);
}
Test::~Test()
{
// By deleting the world, we delete the bomb, mouse joint, etc.
delete m_world;
m_world = NULL;
}
void Test::SetGravity( float x, float y)
{
float tVectorLength=sqrt(x*x+y*y);
float newGravityX=9.81f*x/tVectorLength;
float newGravityY=9.81f*y/tVectorLength;
m_world->SetGravity(b2Vec2(newGravityX,newGravityY));
}
void Test::PreSolve(b2Contact* contact, const b2Manifold* oldManifold)
{
const b2Manifold* manifold = contact->GetManifold();
if (manifold->pointCount == 0)
{
return;
}
b2Fixture* fixtureA = contact->GetFixtureA();
b2Fixture* fixtureB = contact->GetFixtureB();
b2PointState state1[b2_maxManifoldPoints], state2[b2_maxManifoldPoints];
b2GetPointStates(state1, state2, oldManifold, manifold);
b2WorldManifold worldManifold;
contact->GetWorldManifold(&worldManifold);
for (int32 i = 0; i < manifold->pointCount && m_pointCount < k_maxContactPoints; ++i)
{
ContactPoint* cp = m_points + m_pointCount;
cp->fixtureA = fixtureA;
cp->fixtureB = fixtureB;
cp->position = worldManifold.points[i];
cp->normal = worldManifold.normal;
cp->state = state2[i];
++m_pointCount;
}
}
void Test::DrawTitle(int x, int y, const char *string)
{
m_debugDraw.DrawString(x, y, string);
}
class QueryCallback : public b2QueryCallback
{
public:
QueryCallback(const b2Vec2& point)
{
m_point = point;
m_fixture = NULL;
}
bool ReportFixture(b2Fixture* fixture)
{
b2Body* body = fixture->GetBody();
if (body->GetType() == b2_dynamicBody)
{
bool inside = fixture->TestPoint(m_point);
if (inside)
{
m_fixture = fixture;
// We are done, terminate the query.
return false;
}
}
// Continue the query.
return true;
}
b2Vec2 m_point;
b2Fixture* m_fixture;
};
void Test::MouseDown(const b2Vec2& p)
{
m_mouseWorld = p;
if (m_mouseJoint != NULL)
{
return;
}
// Make a small box.
b2AABB aabb;
b2Vec2 d;
d.Set(0.001f, 0.001f);
aabb.lowerBound = p - d;
aabb.upperBound = p + d;
// Query the world for overlapping shapes.
QueryCallback callback(p);
m_world->QueryAABB(&callback, aabb);
if (callback.m_fixture)
{
b2Body* body = callback.m_fixture->GetBody();
b2MouseJointDef md;
md.bodyA = m_groundBody;
md.bodyB = body;
md.target = p;
#ifdef TARGET_FLOAT32_IS_FIXED
md.maxForce = (body->GetMass() < 16.0)?
(1000.0f * body->GetMass()) : float32(16000.0);
#else
md.maxForce = 1000.0f * body->GetMass();
#endif
m_mouseJoint = (b2MouseJoint*)m_world->CreateJoint(&md);
body->SetAwake(true);
}
}
void Test::SpawnBomb(const b2Vec2& worldPt)
{
m_bombSpawnPoint = worldPt;
m_bombSpawning = true;
}
void Test::CompleteBombSpawn(const b2Vec2& p)
{
if (m_bombSpawning == false)
{
return;
}
const float multiplier = 30.0f;
b2Vec2 vel = m_bombSpawnPoint - p;
vel *= multiplier;
LaunchBomb(m_bombSpawnPoint,vel);
m_bombSpawning = false;
}
void Test::ShiftMouseDown(const b2Vec2& p)
{
m_mouseWorld = p;
if (m_mouseJoint != NULL)
{
return;
}
SpawnBomb(p);
}
void Test::MouseUp(const b2Vec2& p)
{
if (m_mouseJoint)
{
m_world->DestroyJoint(m_mouseJoint);
m_mouseJoint = NULL;
}
if (m_bombSpawning)
{
CompleteBombSpawn(p);
}
}
void Test::MouseMove(const b2Vec2& p)
{
m_mouseWorld = p;
if (m_mouseJoint)
{
m_mouseJoint->SetTarget(p);
}
}
void Test::LaunchBomb()
{
b2Vec2 p(RandomFloat(-15.0f, 15.0f), 30.0f);
b2Vec2 v = -5.0f * p;
LaunchBomb(p, v);
}
void Test::LaunchBomb(const b2Vec2& position, const b2Vec2& velocity)
{
if (m_bomb)
{
m_world->DestroyBody(m_bomb);
m_bomb = NULL;
}
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position = position;
bd.bullet = true;
m_bomb = m_world->CreateBody(&bd);
m_bomb->SetLinearVelocity(velocity);
b2CircleShape circle;
circle.m_radius = 0.3f;
b2FixtureDef fd;
fd.shape = &circle;
fd.density = 20.0f;
fd.restitution = 0.0f;
b2Vec2 minV = position - b2Vec2(0.3f,0.3f);
b2Vec2 maxV = position + b2Vec2(0.3f,0.3f);
b2AABB aabb;
aabb.lowerBound = minV;
aabb.upperBound = maxV;
m_bomb->CreateFixture(&fd);
}
void Test::Step(Settings* settings)
{
float32 timeStep = settings->hz > 0.0f ? 1.0f / settings->hz : float32(0.0f);
if (settings->pause)
{
if (settings->singleStep)
{
settings->singleStep = 0;
}
else
{
timeStep = 0.0f;
}
m_debugDraw.DrawString(5, m_textLine, "****PAUSED****");
m_textLine += 15;
}
uint32 flags = 0;
flags += settings->drawShapes * b2Draw::e_shapeBit;
flags += settings->drawJoints * b2Draw::e_jointBit;
flags += settings->drawAABBs * b2Draw::e_aabbBit;
flags += settings->drawPairs * b2Draw::e_pairBit;
flags += settings->drawCOMs * b2Draw::e_centerOfMassBit;
m_debugDraw.SetFlags(flags);
m_world->SetWarmStarting(settings->enableWarmStarting > 0);
m_world->SetContinuousPhysics(settings->enableContinuous > 0);
m_world->SetSubStepping(settings->enableSubStepping > 0);
m_pointCount = 0;
m_world->Step(timeStep, settings->velocityIterations, settings->positionIterations);
m_world->DrawDebugData();
if (timeStep > 0.0f)
{
++m_stepCount;
}
if (settings->drawStats)
{
m_debugDraw.DrawString(5, m_textLine, "bodies/contacts/joints/proxies = %d/%d/%d",
m_world->GetBodyCount(), m_world->GetContactCount(), m_world->GetJointCount(), m_world->GetProxyCount());
m_textLine += 15;
}
if (m_mouseJoint)
{
b2Vec2 p1 = m_mouseJoint->GetAnchorB();
b2Vec2 p2 = m_mouseJoint->GetTarget();
glPointSize(4.0f);
glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
GLbyte verts1[2 * 3] = {
p1.x, p1.y, 0.0f,
p2.x, p2.y, 0.0f
};
glVertexPointer(3, GL_BYTE, 0, verts1);
glDrawArrays(GL_POINTS, 0, 2);
glPointSize(1.0f);
glColor4f(0.8f, 0.8f, 0.8f, 1.0f);
GLbyte verts2[2 * 3] = {
p1.x, p1.y, 0.0f,
p2.x, p2.y, 0.0f
};
glVertexPointer(3, GL_BYTE, 0, verts2);
glDrawArrays(GL_LINES, 0, 2);
}
if (m_bombSpawning)
{
glPointSize(4.0f);
glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
GLbyte verts1[1 * 3] = {
m_bombSpawnPoint.x, m_bombSpawnPoint.y, 0.0f
};
glVertexPointer(3, GL_BYTE, 0, verts1);
glDrawArrays(GL_POINTS, 0, 1);
glColor4f(0.8f, 0.8f, 0.8f, 1.0f);
GLbyte verts2[2 * 3] = {
m_mouseWorld.x, m_mouseWorld.y, 0.0f,
m_bombSpawnPoint.x, m_bombSpawnPoint.y, 0.0f
};
glVertexPointer(3, GL_BYTE, 0, verts2);
glDrawArrays(GL_LINES, 0, 2);
}
if (settings->drawContactPoints)
{
//const float32 k_impulseScale = 0.1f;
const float32 k_axisScale = 0.3f;
for (int32 i = 0; i < m_pointCount; ++i)
{
ContactPoint* point = m_points + i;
if (point->state == b2_addState)
{
// Add
m_debugDraw.DrawPoint(point->position, 10.0f, b2Color(0.3f, 0.95f, 0.3f));
}
else if (point->state == b2_persistState)
{
// Persist
m_debugDraw.DrawPoint(point->position, 5.0f, b2Color(0.3f, 0.3f, 0.95f));
}
if (settings->drawContactNormals == 1)
{
b2Vec2 p1 = point->position;
b2Vec2 p2 = p1 + k_axisScale * point->normal;
m_debugDraw.DrawSegment(p1, p2, b2Color(0.9f, 0.9f, 0.9f));
}
else if (settings->drawContactForces == 1)
{
//b2Vec2 p1 = point->position;
//b2Vec2 p2 = p1 + k_forceScale * point->normalForce * point->normal;
//DrawSegment(p1, p2, b2Color(0.9f, 0.9f, 0.3f));
}
if (settings->drawFrictionForces == 1)
{
//b2Vec2 tangent = b2Cross(point->normal, 1.0f);
//b2Vec2 p1 = point->position;
//b2Vec2 p2 = p1 + k_forceScale * point->tangentForce * tangent;
//DrawSegment(p1, p2, b2Color(0.9f, 0.9f, 0.3f));
}
}
}
}

View File

@@ -0,0 +1,111 @@
/*
* 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 "iPhoneTest.h"
#include <cstring>
using namespace std;
#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 "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 "VaryingFriction.h"
#include "VaryingRestitution.h"
#include "VerticalStack.h"
#include "Web.h"
TestEntry g_testEntries[] =
{
{"Pulleys", Pulleys::Create},
{"SphereStack", SphereStack::Create},
{"Tiles", Tiles::Create},
{"Polygon Shapes", PolyShapes::Create},
{"Rope", Rope::Create},
{"Web", Web::Create},
{"Car", Car::Create},
{"Vertical Stack", VerticalStack::Create},
{"RopeJoint", RopeJoint::Create},
{"Character Collision", CharacterCollision::Create},
{"Edge Test", EdgeTest::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},
{"Varying Restitution", VaryingRestitution::Create},
{"Theo Jansen's Walker", TheoJansen::Create},
{"Body Types", BodyTypes::Create},
{"Prismatic", Prismatic::Create},
{"Edge Shapes", EdgeShapes::Create},
{"PolyCollision", PolyCollision::Create},
{"Apply Force", ApplyForce::Create},
{"Cantilever", Cantilever::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},
{"Gears", Gears::Create},
{"Revolute", Revolute::Create},
{"Sensor Test", SensorTest::Create},
{"Shape Editing", ShapeEditing::Create},
{"Slider Crank", SliderCrank::Create},
{"Varying Friction", VaryingFriction::Create},
{NULL, NULL}
};