// Copyright 2013 Howling Moon Software. All rights reserved. // See http://chipmunk2d.net/legal.php for more information. #include #include #include #include "chipmunk/chipmunk.h" #include "chipmunk/cpMarch.h" typedef void (*cpMarchCellFunc)( cpFloat t, cpFloat a, cpFloat b, cpFloat c, cpFloat d, cpFloat x0, cpFloat x1, cpFloat y0, cpFloat y1, cpMarchSegmentFunc segment, void *segment_data ); // The looping and sample caching code is shared between cpMarchHard() and cpMarchSoft(). static void cpMarchCells( cpBB bb, unsigned long x_samples, unsigned long y_samples, cpFloat t, cpMarchSegmentFunc segment, void *segment_data, cpMarchSampleFunc sample, void *sample_data, cpMarchCellFunc cell ){ cpFloat x_denom = 1.0/(cpFloat)(x_samples - 1); cpFloat y_denom = 1.0/(cpFloat)(y_samples - 1); // TODO range assertions and short circuit for 0 sized windows. // Keep a copy of the previous row to avoid double lookups. cpFloat *buffer = (cpFloat *)cpcalloc(x_samples, sizeof(cpFloat)); for(unsigned long i=0; it)<<0 | (b>t)<<1 | (c>t)<<2 | (d>t)<<3){ case 0x1: seg(cpv(x0, midlerp(y0,y1,a,c,t)), cpv(midlerp(x0,x1,a,b,t), y0), segment, segment_data); break; case 0x2: seg(cpv(midlerp(x0,x1,a,b,t), y0), cpv(x1, midlerp(y0,y1,b,d,t)), segment, segment_data); break; case 0x3: seg(cpv(x0, midlerp(y0,y1,a,c,t)), cpv(x1, midlerp(y0,y1,b,d,t)), segment, segment_data); break; case 0x4: seg(cpv(midlerp(x0,x1,c,d,t), y1), cpv(x0, midlerp(y0,y1,a,c,t)), segment, segment_data); break; case 0x5: seg(cpv(midlerp(x0,x1,c,d,t), y1), cpv(midlerp(x0,x1,a,b,t), y0), segment, segment_data); break; case 0x6: seg(cpv(midlerp(x0,x1,a,b,t), y0), cpv(x1, midlerp(y0,y1,b,d,t)), segment, segment_data); seg(cpv(midlerp(x0,x1,c,d,t), y1), cpv(x0, midlerp(y0,y1,a,c,t)), segment, segment_data); break; case 0x7: seg(cpv(midlerp(x0,x1,c,d,t), y1), cpv(x1, midlerp(y0,y1,b,d,t)), segment, segment_data); break; case 0x8: seg(cpv(x1, midlerp(y0,y1,b,d,t)), cpv(midlerp(x0,x1,c,d,t), y1), segment, segment_data); break; case 0x9: seg(cpv(x0, midlerp(y0,y1,a,c,t)), cpv(midlerp(x0,x1,a,b,t), y0), segment, segment_data); seg(cpv(x1, midlerp(y0,y1,b,d,t)), cpv(midlerp(x0,x1,c,d,t), y1), segment, segment_data); break; case 0xA: seg(cpv(midlerp(x0,x1,a,b,t), y0), cpv(midlerp(x0,x1,c,d,t), y1), segment, segment_data); break; case 0xB: seg(cpv(x0, midlerp(y0,y1,a,c,t)), cpv(midlerp(x0,x1,c,d,t), y1), segment, segment_data); break; case 0xC: seg(cpv(x1, midlerp(y0,y1,b,d,t)), cpv(x0, midlerp(y0,y1,a,c,t)), segment, segment_data); break; case 0xD: seg(cpv(x1, midlerp(y0,y1,b,d,t)), cpv(midlerp(x0,x1,a,b,t), y0), segment, segment_data); break; case 0xE: seg(cpv(midlerp(x0,x1,a,b,t), y0), cpv(x0, midlerp(y0,y1,a,c,t)), segment, segment_data); break; default: break; // 0x0 and 0xF } } void cpMarchSoft( cpBB bb, unsigned long x_samples, unsigned long y_samples, cpFloat t, cpMarchSegmentFunc segment, void *segment_data, cpMarchSampleFunc sample, void *sample_data ){ cpMarchCells(bb, x_samples, y_samples, t, segment, segment_data, sample, sample_data, cpMarchCellSoft); } // TODO should flip this around eventually. static inline void segs(cpVect a, cpVect b, cpVect c, cpMarchSegmentFunc f, void *data) { seg(b, c, f, data); seg(a, b, f, data); } static void cpMarchCellHard( cpFloat t, cpFloat a, cpFloat b, cpFloat c, cpFloat d, cpFloat x0, cpFloat x1, cpFloat y0, cpFloat y1, cpMarchSegmentFunc segment, void *segment_data ){ // midpoints cpFloat xm = cpflerp(x0, x1, 0.5f); cpFloat ym = cpflerp(y0, y1, 0.5f); switch((a>t)<<0 | (b>t)<<1 | (c>t)<<2 | (d>t)<<3){ case 0x1: segs(cpv(x0, ym), cpv(xm, ym), cpv(xm, y0), segment, segment_data); break; case 0x2: segs(cpv(xm, y0), cpv(xm, ym), cpv(x1, ym), segment, segment_data); break; case 0x3: seg(cpv(x0, ym), cpv(x1, ym), segment, segment_data); break; case 0x4: segs(cpv(xm, y1), cpv(xm, ym), cpv(x0, ym), segment, segment_data); break; case 0x5: seg(cpv(xm, y1), cpv(xm, y0), segment, segment_data); break; case 0x6: segs(cpv(xm, y0), cpv(xm, ym), cpv(x0, ym), segment, segment_data); segs(cpv(xm, y1), cpv(xm, ym), cpv(x1, ym), segment, segment_data); break; case 0x7: segs(cpv(xm, y1), cpv(xm, ym), cpv(x1, ym), segment, segment_data); break; case 0x8: segs(cpv(x1, ym), cpv(xm, ym), cpv(xm, y1), segment, segment_data); break; case 0x9: segs(cpv(x1, ym), cpv(xm, ym), cpv(xm, y0), segment, segment_data); segs(cpv(x0, ym), cpv(xm, ym), cpv(xm, y1), segment, segment_data); break; case 0xA: seg(cpv(xm, y0), cpv(xm, y1), segment, segment_data); break; case 0xB: segs(cpv(x0, ym), cpv(xm, ym), cpv(xm, y1), segment, segment_data); break; case 0xC: seg(cpv(x1, ym), cpv(x0, ym), segment, segment_data); break; case 0xD: segs(cpv(x1, ym), cpv(xm, ym), cpv(xm, y0), segment, segment_data); break; case 0xE: segs(cpv(xm, y0), cpv(xm, ym), cpv(x0, ym), segment, segment_data); break; default: break; // 0x0 and 0xF } } void cpMarchHard( cpBB bb, unsigned long x_samples, unsigned long y_samples, cpFloat t, cpMarchSegmentFunc segment, void *segment_data, cpMarchSampleFunc sample, void *sample_data ){ cpMarchCells(bb, x_samples, y_samples, t, segment, segment_data, sample, sample_data, cpMarchCellHard); }