Skip to content

Instantly share code, notes, and snippets.

@slembcke
Created September 12, 2011 21:38
Show Gist options
  • Save slembcke/1212534 to your computer and use it in GitHub Desktop.
Save slembcke/1212534 to your computer and use it in GitHub Desktop.
Chipmunk Pro deformable terrain: DeformableBitmapDemo.m
#import "DeformableBitmapDemo.h"
@implementation DeformableBitmapDemo
@synthesize space;
#define PIXEL_SIZE 4
#define TILE_SIZE 128
- (id) init
{
if((self = [super init])){
space = [[ChipmunkSpace alloc] init];
space.gravity = cpv(0, -500);
int width = 640;
int height = 480;
// Subsample the data from a small context for efficiency.
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
sampler = [[ChipmunkCGContextSampler alloc] initWithWidth:width/PIXEL_SIZE height:height/PIXEL_SIZE colorSpace:colorSpace bitmapInfo:kCGImageAlphaNone component:0];
CGColorSpaceRelease(colorSpace);
[sampler setBorderValue:1.0];
// The output rectangle should be inset slightly so that we sample pixel centers, not edges.
// This along with the tileOffset below will make sure the pixels line up with the geometry perfectly.
sampler.outputRect = cpBBNew(0.5*PIXEL_SIZE, 0.5*PIXEL_SIZE, width - 0.5*PIXEL_SIZE, height - 0.5*PIXEL_SIZE);
// Samples are spread out over the entire tile size starting at the edges.
// You must sample 1 point more than you'd think to line up with the pixels.
tiles = [[ChipmunkBasicTileCache alloc] initWithSampler:sampler space:space tileSize:TILE_SIZE samplesPerTile:TILE_SIZE/PIXEL_SIZE + 1];
tiles.tileOffset = cpv(-0.5*PIXEL_SIZE, -0.5*PIXEL_SIZE); // See above
tiles.segmentRadius = 1;
tiles.simplifyThreshold = 2;
// Set the CGContext's transform to match it's Chipmunk coords.
CGContextConcatCTM(sampler.context, CGAffineTransformMake(1.0/PIXEL_SIZE, 0.0, 0.0, 1.0/PIXEL_SIZE, 0.0, 0.0));
// Clear it to white.
CGContextSetGrayFillColor(sampler.context, 1.0, 1.0);
CGContextFillRect(sampler.context, CGRectMake(0, 0, width, height));
// Draw a block in the middle of the screen.
CGContextSetGrayFillColor(sampler.context, 0.0, 1.0);
CGContextFillRect(sampler.context, CGRectMake(100, 100, width - 200, height - 200));
}
return self;
}
-(void)dealloc
{
self.space = nil;
[sampler release];
[tiles release];
[super dealloc];
}
static cpBB
CGRect2cpBB(CGRect r)
{
cpFloat l = r.origin.x;
cpFloat b = r.origin.y;
return cpBBNew(l, b, l + r.size.width, b + r.size.height);
}
//static cpBB
//cpBBDilate(cpBB bb, cpFloat d)
//{
// return cpBBNew(bb.l - d, bb.b - d, bb.r + d, bb.t + d);
//}
-(void)drawEllipseAt:(cpVect)pos
{
cpFloat radius = 16;
CGRect rect = CGRectMake(pos.x - radius, pos.y - radius, radius*2.0, radius*2.0);
CGContextFillEllipseInRect(sampler.context, rect);
// CGContextFillRect(sampler.context, rect);
[tiles markDirtyRect:CGRect2cpBB(rect)];
}
-(void)leftMouse:(cpVect)pos;
{
CGContextSetGrayFillColor(sampler.context, 1.0, 1.0);
[self drawEllipseAt:pos];
}
-(void)drag:(cpVect)pos {
[self drawEllipseAt:pos];
}
-(void)rightMouse:(cpVect)pos;
{
CGContextSetGrayFillColor(sampler.context, 2.0, 1.0);
[self drawEllipseAt:pos];
}
-(void)step:(cpFloat)dt;
{
// Ensure that the geometry for the current screen rect is ready.
[tiles ensureRect:cpBBNew(0.0, 0.0, 640.0, 480.0)];
[space step:dt];
}
-(void)drawUnderlay
{
glPixelZoom(PIXEL_SIZE, -PIXEL_SIZE);
glWindowPos2f(0, 480);
glDrawPixels(sampler.width, sampler.height, GL_LUMINANCE, GL_UNSIGNED_BYTE, [sampler.pixelData bytes]);
}
extern void ChipmunkDemoDrawString(int x, int y, const char *str);
-(void)drawOverlay
{
ChipmunkDemoDrawString(20, 460,
"Controls:\n"
"Left click to cut holes in the block.\n"
"Right click to add to it.\n"
"Return to restart the demo.\n"
);
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment