1 /* Copyright (c) 2013 Scott Lembcke and Howling Moon Software
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to deal
5 * in the Software without restriction, including without limitation the rights
6 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 * copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 #import "ObjectiveChipmunk/ObjectiveChipmunk.h"
24 @interface ChipmunkSpace(DoubleDispatch)
26 - (ChipmunkShape *)addShape:(ChipmunkShape *)obj;
27 - (ChipmunkShape *)removeShape:(ChipmunkShape *)obj;
31 @implementation ChipmunkShape
33 @synthesize userData = _userData;
35 +(ChipmunkShape *)shapeFromCPShape:(cpShape *)shape
37 ChipmunkShape *obj = shape->userData;
38 cpAssertHard([obj isKindOfClass:[ChipmunkShape class]], "'shape->data' is not a pointer to a ChipmunkShape object.");
45 cpShapeDestroy(self.shape);
51 [self doesNotRecognizeSelector:_cmd];
55 - (ChipmunkBody *)body {
56 cpBody *body = cpShapeGetBody(self.shape);
57 return (body ? cpBodyGetUserData(body) : nil);
60 - (void)setBody:(ChipmunkBody *)body {
61 if(self.body != body){
63 cpShapeSetBody(self.shape, [body retain].body);
67 -(cpFloat)mass {return cpShapeGetMass(self.shape);}
68 -(void)setMass:(cpFloat)mass {cpShapeSetMass(self.shape, mass);}
70 -(cpFloat)density {return cpShapeGetDensity(self.shape);}
71 -(void)setDensity:(cpFloat)density {cpShapeSetDensity(self.shape, density);}
73 -(cpFloat)moment {return cpShapeGetMoment(self.shape);}
74 -(cpFloat)area {return cpShapeGetArea(self.shape);}
75 -(cpVect)centerOfGravity {return cpShapeGetCenterOfGravity(self.shape);}
78 #define getter(type, lower, upper) \
79 - (type)lower {return cpShapeGet##upper(self.shape);}
80 #define setter(type, lower, upper) \
81 - (void)set##upper:(type)value {cpShapeSet##upper(self.shape, value);};
82 #define both(type, lower, upper) \
83 getter(type, lower, upper) \
84 setter(type, lower, upper)
87 both(BOOL, sensor, Sensor)
88 both(cpFloat, elasticity, Elasticity)
89 both(cpFloat, friction, Friction)
90 both(cpVect, surfaceVelocity, SurfaceVelocity)
91 both(cpCollisionType, collisionType, CollisionType)
92 both(cpShapeFilter, filter, Filter)
94 -(ChipmunkSpace *)space {
95 cpSpace *space = cpShapeGetSpace(self.shape);
96 return (ChipmunkSpace *)(space ? cpSpaceGetUserData(space) : nil);
99 - (cpBB)cacheBB {return cpShapeCacheBB(self.shape);}
101 - (ChipmunkPointQueryInfo *)pointQuery:(cpVect)point
103 cpPointQueryInfo info;
104 cpShapePointQuery(self.shape, point, &info);
105 return (info.shape ? [[[ChipmunkPointQueryInfo alloc] initWithInfo:&info] autorelease] : nil);
108 - (ChipmunkSegmentQueryInfo *)segmentQueryFrom:(cpVect)start to:(cpVect)end radius:(cpFloat)radius
110 cpSegmentQueryInfo info;
111 if(cpShapeSegmentQuery(self.shape, start, end, radius, &info)){
112 return [[[ChipmunkSegmentQueryInfo alloc] initWithInfo:&info start:start end:end] autorelease];
119 - (NSArray *)chipmunkObjects {return [NSArray arrayWithObject:self];}
120 - (void)addToSpace:(ChipmunkSpace *)space {[space addShape:self];}
121 - (void)removeFromSpace:(ChipmunkSpace *)space {[space removeShape:self];}
126 @implementation ChipmunkPointQueryInfo
128 - (id)initWithInfo:(cpPointQueryInfo *)info
130 if((self = [super init])){
138 - (cpPointQueryInfo *)info {return &_info;}
139 - (ChipmunkShape *)shape {return (_info.shape ? _info.shape->userData : nil);}
140 - (cpVect)point {return _info.point;}
141 - (cpFloat)distance {return _info.distance;}
142 - (cpVect)gradient {return _info.gradient;}
146 [self.shape release];
154 @implementation ChipmunkSegmentQueryInfo
156 - (id)initWithInfo:(cpSegmentQueryInfo *)info start:(cpVect)start end:(cpVect)end
158 if((self = [super init])){
169 - (cpSegmentQueryInfo *)info {return &_info;}
170 - (ChipmunkShape *)shape {return (_info.shape ? _info.shape->userData : nil);}
171 - (cpFloat)t {return _info.alpha;}
172 - (cpVect)normal {return _info.normal;}
173 - (cpVect)point {return _info.point;}
174 - (cpFloat)dist {return cpvdist(_start, _end)*_info.alpha;}
175 - (cpVect)start {return _start;}
176 - (cpVect)end {return _end;}
180 [self.shape release];
188 @implementation ChipmunkShapeQueryInfo
190 @synthesize shape = _shape;
191 - (cpContactPointSet *)contactPoints {return &_contactPoints;}
193 - (id)initWithShape:(ChipmunkShape *)shape andPoints:(cpContactPointSet *)set
195 if((self = [super init])){
196 _shape = [shape retain];
197 _contactPoints = *set;
210 @implementation ChipmunkCircleShape {
211 cpCircleShape _shape;
215 + (ChipmunkCircleShape *)circleWithBody:(ChipmunkBody *)body radius:(cpFloat)radius offset:(cpVect)offset
217 return [[[self alloc] initWithBody:body radius:radius offset:offset] autorelease];
220 - (cpShape *)shape {return (cpShape *)&_shape;}
222 - (id)initWithBody:(ChipmunkBody *)body radius:(cpFloat)radius offset:(cpVect)offset {
223 if((self = [super init])){
225 cpCircleShapeInit(&_shape, body.body, radius, offset);
226 self.shape->userData = self;
232 - (cpFloat)radius {return cpCircleShapeGetRadius((cpShape *)&_shape);}
233 - (cpVect)offset {return cpCircleShapeGetOffset((cpShape *)&_shape);}
238 @implementation ChipmunkSegmentShape {
239 cpSegmentShape _shape;
242 + (ChipmunkSegmentShape *)segmentWithBody:(ChipmunkBody *)body from:(cpVect)a to:(cpVect)b radius:(cpFloat)radius
244 return [[[self alloc] initWithBody:body from:a to:b radius:radius] autorelease];
247 - (cpShape *)shape {return (cpShape *)&_shape;}
249 - (id)initWithBody:(ChipmunkBody *)body from:(cpVect)a to:(cpVect)b radius:(cpFloat)radius {
250 if((self = [super init])){
252 cpSegmentShapeInit(&_shape, body.body, a, b, radius);
253 self.shape->userData = self;
259 - (void)setPrevNeighbor:(cpVect)prev nextNeighbor:(cpVect)next
261 cpSegmentShapeSetNeighbors((cpShape *)&_shape, prev, next);
264 - (cpVect)a {return cpSegmentShapeGetA((cpShape *)&_shape);}
265 - (cpVect)b {return cpSegmentShapeGetB((cpShape *)&_shape);}
266 - (cpVect)normal {return cpSegmentShapeGetNormal((cpShape *)&_shape);}
267 - (cpFloat)radius {return cpSegmentShapeGetRadius((cpShape *)&_shape);}
272 @implementation ChipmunkPolyShape {
276 + (id)polyWithBody:(ChipmunkBody *)body count:(int)count verts:(const cpVect *)verts transform:(cpTransform)transform radius:(cpFloat)radius
278 return [[[self alloc] initWithBody:body count:count verts:verts transform:transform radius:radius] autorelease];
281 + (id)boxWithBody:(ChipmunkBody *)body width:(cpFloat)width height:(cpFloat)height radius:(cpFloat)radius
283 return [[[self alloc] initBoxWithBody:body width:width height:height radius:radius] autorelease];
286 + (id)boxWithBody:(ChipmunkBody *)body bb:(cpBB)bb radius:(cpFloat)radius
288 return [[[self alloc] initBoxWithBody:body bb:bb radius:radius] autorelease];
291 - (cpShape *)shape {return (cpShape *)&_shape;}
293 - (id)initWithBody:(ChipmunkBody *)body count:(int)count verts:(const cpVect *)verts transform:(cpTransform)transform radius:(cpFloat)radius
295 if((self = [super init])){
297 cpPolyShapeInit(&_shape, body.body, count, verts, transform, radius);
298 self.shape->userData = self;
304 - (id)initBoxWithBody:(ChipmunkBody *)body width:(cpFloat)width height:(cpFloat)height radius:(cpFloat)radius
306 if((self = [super init])){
308 cpBoxShapeInit(&_shape, body.body, width, height, radius);
309 self.shape->userData = self;
315 - (id)initBoxWithBody:(ChipmunkBody *)body bb:(cpBB)bb radius:(cpFloat)radius
317 if((self = [super init])){
319 cpBoxShapeInit2(&_shape, body.body, bb, radius);
320 self.shape->userData = self;
326 - (int)count {return cpPolyShapeGetCount((cpShape *)&_shape);}
327 - (cpFloat)radius {return cpPolyShapeGetRadius((cpShape *)&_shape);}
328 - (cpVect)getVertex:(int)index {return cpPolyShapeGetVert((cpShape *)&_shape, index);}