1#include "Bullet3Collision/NarrowPhaseCollision/shared/b3Contact4Data.h"
2
3#define SHAPE_CONVEX_HULL 3
4#define SHAPE_PLANE 4
5#define SHAPE_CONCAVE_TRIMESH 5
6#define SHAPE_COMPOUND_OF_CONVEX_HULLS 6
7#define SHAPE_SPHERE 7
8
9
10#pragma OPENCL EXTENSION cl_amd_printf : enable
11#pragma OPENCL EXTENSION cl_khr_local_int32_base_atomics : enable
12#pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable
13#pragma OPENCL EXTENSION cl_khr_local_int32_extended_atomics : enable
14#pragma OPENCL EXTENSION cl_khr_global_int32_extended_atomics : enable
15
16#ifdef cl_ext_atomic_counters_32
17#pragma OPENCL EXTENSION cl_ext_atomic_counters_32 : enable
18#else
19#define counter32_t volatile __global int*
20#endif
21
22#define GET_GROUP_IDX get_group_id(0)
23#define GET_LOCAL_IDX get_local_id(0)
24#define GET_GLOBAL_IDX get_global_id(0)
25#define GET_GROUP_SIZE get_local_size(0)
26#define GET_NUM_GROUPS get_num_groups(0)
27#define GROUP_LDS_BARRIER barrier(CLK_LOCAL_MEM_FENCE)
28#define GROUP_MEM_FENCE mem_fence(CLK_LOCAL_MEM_FENCE)
29#define AtomInc(x) atom_inc(&(x))
30#define AtomInc1(x, out) out = atom_inc(&(x))
31#define AppendInc(x, out) out = atomic_inc(x)
32#define AtomAdd(x, value) atom_add(&(x), value)
33#define AtomCmpxhg(x, cmp, value) atom_cmpxchg( &(x), cmp, value )
34#define AtomXhg(x, value) atom_xchg ( &(x), value )
35
36#define max2 max
37#define min2 min
38
39typedef unsigned int u32;
40
41
42
43
44typedef struct
45{
46	union
47	{
48		float4	m_min;
49		float   m_minElems[4];
50		int			m_minIndices[4];
51	};
52	union
53	{
54		float4	m_max;
55		float   m_maxElems[4];
56		int			m_maxIndices[4];
57	};
58} btAabbCL;
59
60///keep this in sync with btCollidable.h
61typedef struct
62{
63	int m_numChildShapes;
64	float m_radius;
65	int m_shapeType;
66	int m_shapeIndex;
67
68} btCollidableGpu;
69
70typedef struct
71{
72	float4	m_childPosition;
73	float4	m_childOrientation;
74	int m_shapeIndex;
75	int m_unused0;
76	int m_unused1;
77	int m_unused2;
78} btGpuChildShape;
79
80#define GET_NPOINTS(x) (x).m_worldNormalOnB.w
81
82typedef struct
83{
84	float4 m_pos;
85	float4 m_quat;
86	float4 m_linVel;
87	float4 m_angVel;
88
89	u32 m_collidableIdx;
90	float m_invMass;
91	float m_restituitionCoeff;
92	float m_frictionCoeff;
93} BodyData;
94
95
96typedef struct
97{
98	float4		m_localCenter;
99	float4		m_extents;
100	float4		mC;
101	float4		mE;
102
103	float			m_radius;
104	int	m_faceOffset;
105	int m_numFaces;
106	int	m_numVertices;
107
108	int m_vertexOffset;
109	int	m_uniqueEdgesOffset;
110	int	m_numUniqueEdges;
111	int m_unused;
112
113} ConvexPolyhedronCL;
114
115typedef struct
116{
117	float4 m_plane;
118	int m_indexOffset;
119	int m_numIndices;
120} btGpuFace;
121
122#define SELECT_UINT4( b, a, condition ) select( b,a,condition )
123
124#define make_float4 (float4)
125#define make_float2 (float2)
126#define make_uint4 (uint4)
127#define make_int4 (int4)
128#define make_uint2 (uint2)
129#define make_int2 (int2)
130
131
132__inline
133float fastDiv(float numerator, float denominator)
134{
135	return native_divide(numerator, denominator);
136//	return numerator/denominator;
137}
138
139__inline
140float4 fastDiv4(float4 numerator, float4 denominator)
141{
142	return native_divide(numerator, denominator);
143}
144
145
146__inline
147float4 cross3(float4 a, float4 b)
148{
149	return cross(a,b);
150}
151
152//#define dot3F4 dot
153
154__inline
155float dot3F4(float4 a, float4 b)
156{
157	float4 a1 = make_float4(a.xyz,0.f);
158	float4 b1 = make_float4(b.xyz,0.f);
159	return dot(a1, b1);
160}
161
162__inline
163float4 fastNormalize4(float4 v)
164{
165	return fast_normalize(v);
166}
167
168
169///////////////////////////////////////
170//	Quaternion
171///////////////////////////////////////
172
173typedef float4 Quaternion;
174
175__inline
176Quaternion qtMul(Quaternion a, Quaternion b);
177
178__inline
179Quaternion qtNormalize(Quaternion in);
180
181__inline
182float4 qtRotate(Quaternion q, float4 vec);
183
184__inline
185Quaternion qtInvert(Quaternion q);
186
187
188
189
190__inline
191Quaternion qtMul(Quaternion a, Quaternion b)
192{
193	Quaternion ans;
194	ans = cross3( a, b );
195	ans += a.w*b+b.w*a;
196//	ans.w = a.w*b.w - (a.x*b.x+a.y*b.y+a.z*b.z);
197	ans.w = a.w*b.w - dot3F4(a, b);
198	return ans;
199}
200
201__inline
202Quaternion qtNormalize(Quaternion in)
203{
204	return fastNormalize4(in);
205//	in /= length( in );
206//	return in;
207}
208__inline
209float4 qtRotate(Quaternion q, float4 vec)
210{
211	Quaternion qInv = qtInvert( q );
212	float4 vcpy = vec;
213	vcpy.w = 0.f;
214	float4 out = qtMul(qtMul(q,vcpy),qInv);
215	return out;
216}
217
218__inline
219Quaternion qtInvert(Quaternion q)
220{
221	return (Quaternion)(-q.xyz, q.w);
222}
223
224__inline
225float4 qtInvRotate(const Quaternion q, float4 vec)
226{
227	return qtRotate( qtInvert( q ), vec );
228}
229
230__inline
231float4 transform(const float4* p, const float4* translation, const Quaternion* orientation)
232{
233	return qtRotate( *orientation, *p ) + (*translation);
234}
235
236void	trInverse(float4 translationIn, Quaternion orientationIn,
237		float4* translationOut, Quaternion* orientationOut)
238{
239	*orientationOut = qtInvert(orientationIn);
240	*translationOut = qtRotate(*orientationOut, -translationIn);
241}
242
243void	trMul(float4 translationA, Quaternion orientationA,
244						float4 translationB, Quaternion orientationB,
245		float4* translationOut, Quaternion* orientationOut)
246{
247	*orientationOut = qtMul(orientationA,orientationB);
248	*translationOut = transform(&translationB,&translationA,&orientationA);
249}
250
251
252
253__inline
254float4 normalize3(const float4 a)
255{
256	float4 n = make_float4(a.x, a.y, a.z, 0.f);
257	return fastNormalize4( n );
258}
259
260
261__inline float4 lerp3(const float4 a,const float4 b, float  t)
262{
263	return make_float4(	a.x + (b.x - a.x) * t,
264						a.y + (b.y - a.y) * t,
265						a.z + (b.z - a.z) * t,
266						0.f);
267}
268
269
270float signedDistanceFromPointToPlane(float4 point, float4 planeEqn, float4* closestPointOnFace)
271{
272	float4 n = (float4)(planeEqn.x, planeEqn.y, planeEqn.z, 0);
273	float dist = dot3F4(n, point) + planeEqn.w;
274	*closestPointOnFace = point - dist * n;
275	return dist;
276}
277
278
279
280inline bool IsPointInPolygon(float4 p,
281							const btGpuFace* face,
282							__global const float4* baseVertex,
283							__global const  int* convexIndices,
284							float4* out)
285{
286    float4 a;
287    float4 b;
288    float4 ab;
289    float4 ap;
290    float4 v;
291
292	float4 plane = make_float4(face->m_plane.x,face->m_plane.y,face->m_plane.z,0.f);
293
294	if (face->m_numIndices<2)
295		return false;
296
297
298	float4 v0 = baseVertex[convexIndices[face->m_indexOffset + face->m_numIndices-1]];
299
300	b = v0;
301
302    for(unsigned i=0; i != face->m_numIndices; ++i)
303    {
304		a = b;
305		float4 vi = baseVertex[convexIndices[face->m_indexOffset + i]];
306		b = vi;
307        ab = b-a;
308        ap = p-a;
309        v = cross3(ab,plane);
310
311        if (dot(ap, v) > 0.f)
312        {
313            float ab_m2 = dot(ab, ab);
314            float rt = ab_m2 != 0.f ? dot(ab, ap) / ab_m2 : 0.f;
315            if (rt <= 0.f)
316            {
317                *out = a;
318            }
319            else if (rt >= 1.f)
320            {
321                *out = b;
322            }
323            else
324            {
325            	float s = 1.f - rt;
326				out[0].x = s * a.x + rt * b.x;
327				out[0].y = s * a.y + rt * b.y;
328				out[0].z = s * a.z + rt * b.z;
329            }
330            return false;
331        }
332    }
333    return true;
334}
335
336
337
338
339void	computeContactSphereConvex(int pairIndex,
340																int bodyIndexA, int bodyIndexB,
341																int collidableIndexA, int collidableIndexB,
342																__global const BodyData* rigidBodies,
343																__global const btCollidableGpu* collidables,
344																__global const ConvexPolyhedronCL* convexShapes,
345																__global const float4* convexVertices,
346																__global const int* convexIndices,
347																__global const btGpuFace* faces,
348																__global struct b3Contact4Data* restrict globalContactsOut,
349																counter32_t nGlobalContactsOut,
350																int maxContactCapacity,
351																float4 spherePos2,
352																float radius,
353																float4 pos,
354																float4 quat
355																)
356{
357
358	float4 invPos;
359	float4 invOrn;
360
361	trInverse(pos,quat, &invPos,&invOrn);
362
363	float4 spherePos = transform(&spherePos2,&invPos,&invOrn);
364
365	int shapeIndex = collidables[collidableIndexB].m_shapeIndex;
366	int numFaces = convexShapes[shapeIndex].m_numFaces;
367	float4 closestPnt = (float4)(0, 0, 0, 0);
368	float4 hitNormalWorld = (float4)(0, 0, 0, 0);
369	float minDist = -1000000.f;
370	bool bCollide = true;
371
372	for ( int f = 0; f < numFaces; f++ )
373	{
374		btGpuFace face = faces[convexShapes[shapeIndex].m_faceOffset+f];
375
376		// set up a plane equation
377		float4 planeEqn;
378		float4 n1 = face.m_plane;
379		n1.w = 0.f;
380		planeEqn = n1;
381		planeEqn.w = face.m_plane.w;
382
383
384		// compute a signed distance from the vertex in cloth to the face of rigidbody.
385		float4 pntReturn;
386		float dist = signedDistanceFromPointToPlane(spherePos, planeEqn, &pntReturn);
387
388		// If the distance is positive, the plane is a separating plane.
389		if ( dist > radius )
390		{
391			bCollide = false;
392			break;
393		}
394
395
396		if (dist>0)
397		{
398			//might hit an edge or vertex
399			float4 out;
400			float4 zeroPos = make_float4(0,0,0,0);
401
402			bool isInPoly = IsPointInPolygon(spherePos,
403					&face,
404					&convexVertices[convexShapes[shapeIndex].m_vertexOffset],
405					convexIndices,
406           &out);
407			if (isInPoly)
408			{
409				if (dist>minDist)
410				{
411					minDist = dist;
412					closestPnt = pntReturn;
413					hitNormalWorld = planeEqn;
414
415				}
416			} else
417			{
418				float4 tmp = spherePos-out;
419				float l2 = dot(tmp,tmp);
420				if (l2<radius*radius)
421				{
422					dist  = sqrt(l2);
423					if (dist>minDist)
424					{
425						minDist = dist;
426						closestPnt = out;
427						hitNormalWorld = tmp/dist;
428
429					}
430
431				} else
432				{
433					bCollide = false;
434					break;
435				}
436			}
437		} else
438		{
439			if ( dist > minDist )
440			{
441				minDist = dist;
442				closestPnt = pntReturn;
443				hitNormalWorld.xyz = planeEqn.xyz;
444			}
445		}
446
447	}
448
449
450
451	if (bCollide && minDist > -10000)
452	{
453		float4 normalOnSurfaceB1 = qtRotate(quat,-hitNormalWorld);
454		float4 pOnB1 = transform(&closestPnt,&pos,&quat);
455
456		float actualDepth = minDist-radius;
457		if (actualDepth<=0.f)
458		{
459
460
461			pOnB1.w = actualDepth;
462
463			int dstIdx;
464			AppendInc( nGlobalContactsOut, dstIdx );
465
466
467			if (1)//dstIdx < maxContactCapacity)
468			{
469				__global struct b3Contact4Data* c = &globalContactsOut[dstIdx];
470				c->m_worldNormalOnB = -normalOnSurfaceB1;
471				c->m_restituitionCoeffCmp = (0.f*0xffff);c->m_frictionCoeffCmp = (0.7f*0xffff);
472				c->m_batchIdx = pairIndex;
473				c->m_bodyAPtrAndSignBit = rigidBodies[bodyIndexA].m_invMass==0?-bodyIndexA:bodyIndexA;
474				c->m_bodyBPtrAndSignBit = rigidBodies[bodyIndexB].m_invMass==0?-bodyIndexB:bodyIndexB;
475				c->m_worldPosB[0] = pOnB1;
476				c->m_childIndexA = -1;
477				c->m_childIndexB = -1;
478
479				GET_NPOINTS(*c) = 1;
480			}
481
482		}
483	}//if (hasCollision)
484
485}
486
487
488
489int extractManifoldSequential(const float4* p, int nPoints, float4 nearNormal, int4* contactIdx)
490{
491	if( nPoints == 0 )
492        return 0;
493
494    if (nPoints <=4)
495        return nPoints;
496
497
498    if (nPoints >64)
499        nPoints = 64;
500
501	float4 center = make_float4(0.f);
502	{
503
504		for (int i=0;i<nPoints;i++)
505			center += p[i];
506		center /= (float)nPoints;
507	}
508
509
510
511	//	sample 4 directions
512
513    float4 aVector = p[0] - center;
514    float4 u = cross3( nearNormal, aVector );
515    float4 v = cross3( nearNormal, u );
516    u = normalize3( u );
517    v = normalize3( v );
518
519
520    //keep point with deepest penetration
521    float minW= FLT_MAX;
522
523    int minIndex=-1;
524
525    float4 maxDots;
526    maxDots.x = FLT_MIN;
527    maxDots.y = FLT_MIN;
528    maxDots.z = FLT_MIN;
529    maxDots.w = FLT_MIN;
530
531    //	idx, distance
532    for(int ie = 0; ie<nPoints; ie++ )
533    {
534        if (p[ie].w<minW)
535        {
536            minW = p[ie].w;
537            minIndex=ie;
538        }
539        float f;
540        float4 r = p[ie]-center;
541        f = dot3F4( u, r );
542        if (f<maxDots.x)
543        {
544            maxDots.x = f;
545            contactIdx[0].x = ie;
546        }
547
548        f = dot3F4( -u, r );
549        if (f<maxDots.y)
550        {
551            maxDots.y = f;
552            contactIdx[0].y = ie;
553        }
554
555
556        f = dot3F4( v, r );
557        if (f<maxDots.z)
558        {
559            maxDots.z = f;
560            contactIdx[0].z = ie;
561        }
562
563        f = dot3F4( -v, r );
564        if (f<maxDots.w)
565        {
566            maxDots.w = f;
567            contactIdx[0].w = ie;
568        }
569
570    }
571
572    if (contactIdx[0].x != minIndex && contactIdx[0].y != minIndex && contactIdx[0].z != minIndex && contactIdx[0].w != minIndex)
573    {
574        //replace the first contact with minimum (todo: replace contact with least penetration)
575        contactIdx[0].x = minIndex;
576    }
577
578    return 4;
579
580}
581
582#define MAX_PLANE_CONVEX_POINTS 64
583
584int computeContactPlaneConvex(int pairIndex,
585								int bodyIndexA, int bodyIndexB,
586								int collidableIndexA, int collidableIndexB,
587								__global const BodyData* rigidBodies,
588								__global const btCollidableGpu*collidables,
589								__global const ConvexPolyhedronCL* convexShapes,
590								__global const float4* convexVertices,
591								__global const int* convexIndices,
592								__global const btGpuFace* faces,
593								__global struct b3Contact4Data* restrict globalContactsOut,
594								counter32_t nGlobalContactsOut,
595								int maxContactCapacity,
596								float4 posB,
597								Quaternion ornB
598								)
599{
600	int resultIndex=-1;
601
602		int shapeIndex = collidables[collidableIndexB].m_shapeIndex;
603	__global const ConvexPolyhedronCL* hullB = &convexShapes[shapeIndex];
604
605	float4 posA;
606	posA = rigidBodies[bodyIndexA].m_pos;
607	Quaternion ornA;
608	ornA = rigidBodies[bodyIndexA].m_quat;
609
610	int numContactsOut = 0;
611	int numWorldVertsB1= 0;
612
613	float4 planeEq;
614	 planeEq = faces[collidables[collidableIndexA].m_shapeIndex].m_plane;
615	float4 planeNormal = make_float4(planeEq.x,planeEq.y,planeEq.z,0.f);
616	float4 planeNormalWorld;
617	planeNormalWorld = qtRotate(ornA,planeNormal);
618	float planeConstant = planeEq.w;
619
620	float4 invPosA;Quaternion invOrnA;
621	float4 convexInPlaneTransPos1; Quaternion convexInPlaneTransOrn1;
622	{
623
624		trInverse(posA,ornA,&invPosA,&invOrnA);
625		trMul(invPosA,invOrnA,posB,ornB,&convexInPlaneTransPos1,&convexInPlaneTransOrn1);
626	}
627	float4 invPosB;Quaternion invOrnB;
628	float4 planeInConvexPos1;	Quaternion planeInConvexOrn1;
629	{
630
631		trInverse(posB,ornB,&invPosB,&invOrnB);
632		trMul(invPosB,invOrnB,posA,ornA,&planeInConvexPos1,&planeInConvexOrn1);
633	}
634
635
636	float4 planeNormalInConvex = qtRotate(planeInConvexOrn1,-planeNormal);
637	float maxDot = -1e30;
638	int hitVertex=-1;
639	float4 hitVtx;
640
641
642
643	float4 contactPoints[MAX_PLANE_CONVEX_POINTS];
644	int numPoints = 0;
645
646	int4 contactIdx;
647	contactIdx=make_int4(0,1,2,3);
648
649
650	for (int i=0;i<hullB->m_numVertices;i++)
651	{
652		float4 vtx = convexVertices[hullB->m_vertexOffset+i];
653		float curDot = dot(vtx,planeNormalInConvex);
654
655
656		if (curDot>maxDot)
657		{
658			hitVertex=i;
659			maxDot=curDot;
660			hitVtx = vtx;
661			//make sure the deepest points is always included
662			if (numPoints==MAX_PLANE_CONVEX_POINTS)
663				numPoints--;
664		}
665
666		if (numPoints<MAX_PLANE_CONVEX_POINTS)
667		{
668			float4 vtxWorld = transform(&vtx, &posB, &ornB);
669			float4 vtxInPlane = transform(&vtxWorld, &invPosA, &invOrnA);//oplaneTransform.inverse()*vtxWorld;
670			float dist = dot(planeNormal,vtxInPlane)-planeConstant;
671			if (dist<0.f)
672			{
673				vtxWorld.w = dist;
674				contactPoints[numPoints] = vtxWorld;
675				numPoints++;
676			}
677		}
678
679	}
680
681	int numReducedPoints  = numPoints;
682	if (numPoints>4)
683	{
684		numReducedPoints = extractManifoldSequential( contactPoints, numPoints, planeNormalInConvex, &contactIdx);
685	}
686
687	if (numReducedPoints>0)
688	{
689		int dstIdx;
690	    AppendInc( nGlobalContactsOut, dstIdx );
691
692		if (dstIdx < maxContactCapacity)
693		{
694			resultIndex = dstIdx;
695			__global struct b3Contact4Data* c = &globalContactsOut[dstIdx];
696			c->m_worldNormalOnB = -planeNormalWorld;
697			//c->setFrictionCoeff(0.7);
698			//c->setRestituitionCoeff(0.f);
699			c->m_restituitionCoeffCmp = (0.f*0xffff);c->m_frictionCoeffCmp = (0.7f*0xffff);
700			c->m_batchIdx = pairIndex;
701			c->m_bodyAPtrAndSignBit = rigidBodies[bodyIndexA].m_invMass==0?-bodyIndexA:bodyIndexA;
702			c->m_bodyBPtrAndSignBit = rigidBodies[bodyIndexB].m_invMass==0?-bodyIndexB:bodyIndexB;
703			c->m_childIndexA = -1;
704			c->m_childIndexB = -1;
705
706			switch (numReducedPoints)
707            {
708                case 4:
709                    c->m_worldPosB[3] = contactPoints[contactIdx.w];
710                case 3:
711                    c->m_worldPosB[2] = contactPoints[contactIdx.z];
712                case 2:
713                    c->m_worldPosB[1] = contactPoints[contactIdx.y];
714                case 1:
715                    c->m_worldPosB[0] = contactPoints[contactIdx.x];
716                default:
717                {
718                }
719            };
720
721			GET_NPOINTS(*c) = numReducedPoints;
722		}//if (dstIdx < numPairs)
723	}
724
725	return resultIndex;
726}
727
728
729void	computeContactPlaneSphere(int pairIndex,
730																int bodyIndexA, int bodyIndexB,
731																int collidableIndexA, int collidableIndexB,
732																__global const BodyData* rigidBodies,
733																__global const btCollidableGpu* collidables,
734																__global const btGpuFace* faces,
735																__global struct b3Contact4Data* restrict globalContactsOut,
736																counter32_t nGlobalContactsOut,
737																int maxContactCapacity)
738{
739	float4 planeEq = faces[collidables[collidableIndexA].m_shapeIndex].m_plane;
740	float radius = collidables[collidableIndexB].m_radius;
741	float4 posA1 = rigidBodies[bodyIndexA].m_pos;
742	float4 ornA1 = rigidBodies[bodyIndexA].m_quat;
743	float4 posB1 = rigidBodies[bodyIndexB].m_pos;
744	float4 ornB1 = rigidBodies[bodyIndexB].m_quat;
745
746	bool hasCollision = false;
747	float4 planeNormal1 = make_float4(planeEq.x,planeEq.y,planeEq.z,0.f);
748	float planeConstant = planeEq.w;
749	float4 convexInPlaneTransPos1; Quaternion convexInPlaneTransOrn1;
750	{
751		float4 invPosA;Quaternion invOrnA;
752		trInverse(posA1,ornA1,&invPosA,&invOrnA);
753		trMul(invPosA,invOrnA,posB1,ornB1,&convexInPlaneTransPos1,&convexInPlaneTransOrn1);
754	}
755	float4 planeInConvexPos1;	Quaternion planeInConvexOrn1;
756	{
757		float4 invPosB;Quaternion invOrnB;
758		trInverse(posB1,ornB1,&invPosB,&invOrnB);
759		trMul(invPosB,invOrnB,posA1,ornA1,&planeInConvexPos1,&planeInConvexOrn1);
760	}
761	float4 vtx1 = qtRotate(planeInConvexOrn1,-planeNormal1)*radius;
762	float4 vtxInPlane1 = transform(&vtx1,&convexInPlaneTransPos1,&convexInPlaneTransOrn1);
763	float distance = dot3F4(planeNormal1,vtxInPlane1) - planeConstant;
764	hasCollision = distance < 0.f;//m_manifoldPtr->getContactBreakingThreshold();
765	if (hasCollision)
766	{
767		float4 vtxInPlaneProjected1 = vtxInPlane1 -   distance*planeNormal1;
768		float4 vtxInPlaneWorld1 = transform(&vtxInPlaneProjected1,&posA1,&ornA1);
769		float4 normalOnSurfaceB1 = qtRotate(ornA1,planeNormal1);
770		float4 pOnB1 = vtxInPlaneWorld1+normalOnSurfaceB1*distance;
771		pOnB1.w = distance;
772
773		int dstIdx;
774    AppendInc( nGlobalContactsOut, dstIdx );
775
776		if (dstIdx < maxContactCapacity)
777		{
778			__global struct b3Contact4Data* c = &globalContactsOut[dstIdx];
779			c->m_worldNormalOnB = -normalOnSurfaceB1;
780			c->m_restituitionCoeffCmp = (0.f*0xffff);c->m_frictionCoeffCmp = (0.7f*0xffff);
781			c->m_batchIdx = pairIndex;
782			c->m_bodyAPtrAndSignBit = rigidBodies[bodyIndexA].m_invMass==0?-bodyIndexA:bodyIndexA;
783			c->m_bodyBPtrAndSignBit = rigidBodies[bodyIndexB].m_invMass==0?-bodyIndexB:bodyIndexB;
784			c->m_worldPosB[0] = pOnB1;
785			c->m_childIndexA = -1;
786			c->m_childIndexB = -1;
787			GET_NPOINTS(*c) = 1;
788		}//if (dstIdx < numPairs)
789	}//if (hasCollision)
790}
791
792
793__kernel void   primitiveContactsKernel( __global int4* pairs,
794																					__global const BodyData* rigidBodies,
795																					__global const btCollidableGpu* collidables,
796																					__global const ConvexPolyhedronCL* convexShapes,
797																					__global const float4* vertices,
798																					__global const float4* uniqueEdges,
799																					__global const btGpuFace* faces,
800																					__global const int* indices,
801																					__global struct b3Contact4Data* restrict globalContactsOut,
802																					counter32_t nGlobalContactsOut,
803																					int numPairs, int maxContactCapacity)
804{
805
806	int i = get_global_id(0);
807	int pairIndex = i;
808
809	float4 worldVertsB1[64];
810	float4 worldVertsB2[64];
811	int capacityWorldVerts = 64;
812
813	float4 localContactsOut[64];
814	int localContactCapacity=64;
815
816	float minDist = -1e30f;
817	float maxDist = 0.02f;
818
819	if (i<numPairs)
820	{
821
822		int bodyIndexA = pairs[i].x;
823		int bodyIndexB = pairs[i].y;
824
825		int collidableIndexA = rigidBodies[bodyIndexA].m_collidableIdx;
826		int collidableIndexB = rigidBodies[bodyIndexB].m_collidableIdx;
827
828		if (collidables[collidableIndexA].m_shapeType == SHAPE_PLANE &&
829			collidables[collidableIndexB].m_shapeType == SHAPE_CONVEX_HULL)
830		{
831
832			float4 posB;
833			posB = rigidBodies[bodyIndexB].m_pos;
834			Quaternion ornB;
835			ornB = rigidBodies[bodyIndexB].m_quat;
836			int contactIndex = computeContactPlaneConvex(pairIndex, bodyIndexA, bodyIndexB, collidableIndexA, collidableIndexB,
837																rigidBodies,collidables,convexShapes,vertices,indices,
838																faces,	globalContactsOut, nGlobalContactsOut,maxContactCapacity, posB,ornB);
839			if (contactIndex>=0)
840				pairs[pairIndex].z = contactIndex;
841
842			return;
843		}
844
845
846		if (collidables[collidableIndexA].m_shapeType == SHAPE_CONVEX_HULL &&
847			collidables[collidableIndexB].m_shapeType == SHAPE_PLANE)
848		{
849
850			float4 posA;
851			posA = rigidBodies[bodyIndexA].m_pos;
852			Quaternion ornA;
853			ornA = rigidBodies[bodyIndexA].m_quat;
854
855
856			int contactIndex = computeContactPlaneConvex( pairIndex, bodyIndexB,bodyIndexA,  collidableIndexB,collidableIndexA,
857																rigidBodies,collidables,convexShapes,vertices,indices,
858																faces,	globalContactsOut, nGlobalContactsOut,maxContactCapacity,posA,ornA);
859
860			if (contactIndex>=0)
861				pairs[pairIndex].z = contactIndex;
862
863			return;
864		}
865
866		if (collidables[collidableIndexA].m_shapeType == SHAPE_PLANE &&
867			collidables[collidableIndexB].m_shapeType == SHAPE_SPHERE)
868		{
869			computeContactPlaneSphere(pairIndex, bodyIndexA, bodyIndexB, collidableIndexA, collidableIndexB,
870																rigidBodies,collidables,faces,	globalContactsOut, nGlobalContactsOut,maxContactCapacity);
871			return;
872		}
873
874
875		if (collidables[collidableIndexA].m_shapeType == SHAPE_SPHERE &&
876			collidables[collidableIndexB].m_shapeType == SHAPE_PLANE)
877		{
878
879
880			computeContactPlaneSphere( pairIndex, bodyIndexB,bodyIndexA,  collidableIndexB,collidableIndexA,
881																rigidBodies,collidables,
882																faces,	globalContactsOut, nGlobalContactsOut,maxContactCapacity);
883
884			return;
885		}
886
887
888
889
890		if (collidables[collidableIndexA].m_shapeType == SHAPE_SPHERE &&
891			collidables[collidableIndexB].m_shapeType == SHAPE_CONVEX_HULL)
892		{
893
894			float4 spherePos = rigidBodies[bodyIndexA].m_pos;
895			float sphereRadius = collidables[collidableIndexA].m_radius;
896			float4 convexPos = rigidBodies[bodyIndexB].m_pos;
897			float4 convexOrn = rigidBodies[bodyIndexB].m_quat;
898
899			computeContactSphereConvex(pairIndex, bodyIndexA, bodyIndexB, collidableIndexA, collidableIndexB,
900																rigidBodies,collidables,convexShapes,vertices,indices,faces, globalContactsOut, nGlobalContactsOut,maxContactCapacity,
901																spherePos,sphereRadius,convexPos,convexOrn);
902
903			return;
904		}
905
906		if (collidables[collidableIndexA].m_shapeType == SHAPE_CONVEX_HULL &&
907			collidables[collidableIndexB].m_shapeType == SHAPE_SPHERE)
908		{
909
910			float4 spherePos = rigidBodies[bodyIndexB].m_pos;
911			float sphereRadius = collidables[collidableIndexB].m_radius;
912			float4 convexPos = rigidBodies[bodyIndexA].m_pos;
913			float4 convexOrn = rigidBodies[bodyIndexA].m_quat;
914
915			computeContactSphereConvex(pairIndex, bodyIndexB, bodyIndexA, collidableIndexB, collidableIndexA,
916																rigidBodies,collidables,convexShapes,vertices,indices,faces, globalContactsOut, nGlobalContactsOut,maxContactCapacity,
917																spherePos,sphereRadius,convexPos,convexOrn);
918			return;
919		}
920
921
922
923
924
925
926		if (collidables[collidableIndexA].m_shapeType == SHAPE_SPHERE &&
927			collidables[collidableIndexB].m_shapeType == SHAPE_SPHERE)
928		{
929			//sphere-sphere
930			float radiusA = collidables[collidableIndexA].m_radius;
931			float radiusB = collidables[collidableIndexB].m_radius;
932			float4 posA = rigidBodies[bodyIndexA].m_pos;
933			float4 posB = rigidBodies[bodyIndexB].m_pos;
934
935			float4 diff = posA-posB;
936			float len = length(diff);
937
938			///iff distance positive, don't generate a new contact
939			if ( len <= (radiusA+radiusB))
940			{
941				///distance (negative means penetration)
942				float dist = len - (radiusA+radiusB);
943				float4 normalOnSurfaceB = make_float4(1.f,0.f,0.f,0.f);
944				if (len > 0.00001)
945				{
946					normalOnSurfaceB = diff / len;
947				}
948				float4 contactPosB = posB + normalOnSurfaceB*radiusB;
949				contactPosB.w = dist;
950
951				int dstIdx;
952				 AppendInc( nGlobalContactsOut, dstIdx );
953
954				if (dstIdx < maxContactCapacity)
955				{
956					__global struct b3Contact4Data* c = &globalContactsOut[dstIdx];
957					c->m_worldNormalOnB = normalOnSurfaceB;
958					c->m_restituitionCoeffCmp = (0.f*0xffff);c->m_frictionCoeffCmp = (0.7f*0xffff);
959					c->m_batchIdx = pairIndex;
960					int bodyA = pairs[pairIndex].x;
961					int bodyB = pairs[pairIndex].y;
962					c->m_bodyAPtrAndSignBit = rigidBodies[bodyA].m_invMass==0?-bodyA:bodyA;
963					c->m_bodyBPtrAndSignBit = rigidBodies[bodyB].m_invMass==0?-bodyB:bodyB;
964					c->m_worldPosB[0] = contactPosB;
965					c->m_childIndexA = -1;
966					c->m_childIndexB = -1;
967					GET_NPOINTS(*c) = 1;
968				}//if (dstIdx < numPairs)
969			}//if ( len <= (radiusA+radiusB))
970
971			return;
972		}//SHAPE_SPHERE SHAPE_SPHERE
973
974	}//	if (i<numPairs)
975
976}
977
978
979// work-in-progress
980__kernel void   processCompoundPairsPrimitivesKernel( __global const int4* gpuCompoundPairs,
981													__global const BodyData* rigidBodies,
982													__global const btCollidableGpu* collidables,
983													__global const ConvexPolyhedronCL* convexShapes,
984													__global const float4* vertices,
985													__global const float4* uniqueEdges,
986													__global const btGpuFace* faces,
987													__global const int* indices,
988													__global btAabbCL* aabbs,
989													__global const btGpuChildShape* gpuChildShapes,
990													__global struct b3Contact4Data* restrict globalContactsOut,
991													counter32_t nGlobalContactsOut,
992													int numCompoundPairs, int maxContactCapacity
993													)
994{
995
996	int i = get_global_id(0);
997	if (i<numCompoundPairs)
998	{
999		int bodyIndexA = gpuCompoundPairs[i].x;
1000		int bodyIndexB = gpuCompoundPairs[i].y;
1001
1002		int childShapeIndexA = gpuCompoundPairs[i].z;
1003		int childShapeIndexB = gpuCompoundPairs[i].w;
1004
1005		int collidableIndexA = -1;
1006		int collidableIndexB = -1;
1007
1008		float4 ornA = rigidBodies[bodyIndexA].m_quat;
1009		float4 posA = rigidBodies[bodyIndexA].m_pos;
1010
1011		float4 ornB = rigidBodies[bodyIndexB].m_quat;
1012		float4 posB = rigidBodies[bodyIndexB].m_pos;
1013
1014		if (childShapeIndexA >= 0)
1015		{
1016			collidableIndexA = gpuChildShapes[childShapeIndexA].m_shapeIndex;
1017			float4 childPosA = gpuChildShapes[childShapeIndexA].m_childPosition;
1018			float4 childOrnA = gpuChildShapes[childShapeIndexA].m_childOrientation;
1019			float4 newPosA = qtRotate(ornA,childPosA)+posA;
1020			float4 newOrnA = qtMul(ornA,childOrnA);
1021			posA = newPosA;
1022			ornA = newOrnA;
1023		} else
1024		{
1025			collidableIndexA = rigidBodies[bodyIndexA].m_collidableIdx;
1026		}
1027
1028		if (childShapeIndexB>=0)
1029		{
1030			collidableIndexB = gpuChildShapes[childShapeIndexB].m_shapeIndex;
1031			float4 childPosB = gpuChildShapes[childShapeIndexB].m_childPosition;
1032			float4 childOrnB = gpuChildShapes[childShapeIndexB].m_childOrientation;
1033			float4 newPosB = transform(&childPosB,&posB,&ornB);
1034			float4 newOrnB = qtMul(ornB,childOrnB);
1035			posB = newPosB;
1036			ornB = newOrnB;
1037		} else
1038		{
1039			collidableIndexB = rigidBodies[bodyIndexB].m_collidableIdx;
1040		}
1041
1042		int shapeIndexA = collidables[collidableIndexA].m_shapeIndex;
1043		int shapeIndexB = collidables[collidableIndexB].m_shapeIndex;
1044
1045		int shapeTypeA = collidables[collidableIndexA].m_shapeType;
1046		int shapeTypeB = collidables[collidableIndexB].m_shapeType;
1047
1048		int pairIndex = i;
1049		if ((shapeTypeA == SHAPE_PLANE) && (shapeTypeB==SHAPE_CONVEX_HULL))
1050		{
1051
1052			computeContactPlaneConvex( pairIndex, bodyIndexA,bodyIndexB,  collidableIndexA,collidableIndexB,
1053																rigidBodies,collidables,convexShapes,vertices,indices,
1054																faces,	globalContactsOut, nGlobalContactsOut,maxContactCapacity,posB,ornB);
1055			return;
1056		}
1057
1058		if ((shapeTypeA == SHAPE_CONVEX_HULL) && (shapeTypeB==SHAPE_PLANE))
1059		{
1060
1061			computeContactPlaneConvex( pairIndex, bodyIndexB,bodyIndexA,  collidableIndexB,collidableIndexA,
1062																rigidBodies,collidables,convexShapes,vertices,indices,
1063																faces,	globalContactsOut, nGlobalContactsOut,maxContactCapacity,posA,ornA);
1064			return;
1065		}
1066
1067		if ((shapeTypeA == SHAPE_CONVEX_HULL) && (shapeTypeB == SHAPE_SPHERE))
1068		{
1069			float4 spherePos = rigidBodies[bodyIndexB].m_pos;
1070			float sphereRadius = collidables[collidableIndexB].m_radius;
1071			float4 convexPos = posA;
1072			float4 convexOrn = ornA;
1073
1074			computeContactSphereConvex(pairIndex, bodyIndexB, bodyIndexA , collidableIndexB,collidableIndexA,
1075										rigidBodies,collidables,convexShapes,vertices,indices,faces, globalContactsOut, nGlobalContactsOut,maxContactCapacity,
1076										spherePos,sphereRadius,convexPos,convexOrn);
1077
1078			return;
1079		}
1080
1081		if ((shapeTypeA == SHAPE_SPHERE) && (shapeTypeB == SHAPE_CONVEX_HULL))
1082		{
1083
1084			float4 spherePos = rigidBodies[bodyIndexA].m_pos;
1085			float sphereRadius = collidables[collidableIndexA].m_radius;
1086			float4 convexPos = posB;
1087			float4 convexOrn = ornB;
1088
1089
1090			computeContactSphereConvex(pairIndex, bodyIndexA, bodyIndexB, collidableIndexA, collidableIndexB,
1091										rigidBodies,collidables,convexShapes,vertices,indices,faces, globalContactsOut, nGlobalContactsOut,maxContactCapacity,
1092										spherePos,sphereRadius,convexPos,convexOrn);
1093
1094			return;
1095		}
1096	}//	if (i<numCompoundPairs)
1097}
1098
1099
1100bool pointInTriangle(const float4* vertices, const float4* normal, float4 *p )
1101{
1102
1103	const float4* p1 = &vertices[0];
1104	const float4* p2 = &vertices[1];
1105	const float4* p3 = &vertices[2];
1106
1107	float4 edge1;	edge1 = (*p2 - *p1);
1108	float4 edge2;	edge2 = ( *p3 - *p2 );
1109	float4 edge3;	edge3 = ( *p1 - *p3 );
1110
1111
1112	float4 p1_to_p; p1_to_p = ( *p - *p1 );
1113	float4 p2_to_p; p2_to_p = ( *p - *p2 );
1114	float4 p3_to_p; p3_to_p = ( *p - *p3 );
1115
1116	float4 edge1_normal; edge1_normal = ( cross(edge1,*normal));
1117	float4 edge2_normal; edge2_normal = ( cross(edge2,*normal));
1118	float4 edge3_normal; edge3_normal = ( cross(edge3,*normal));
1119
1120
1121
1122	float r1, r2, r3;
1123	r1 = dot(edge1_normal,p1_to_p );
1124	r2 = dot(edge2_normal,p2_to_p );
1125	r3 = dot(edge3_normal,p3_to_p );
1126
1127	if ( r1 > 0 && r2 > 0 && r3 > 0 )
1128		return true;
1129    if ( r1 <= 0 && r2 <= 0 && r3 <= 0 )
1130		return true;
1131	return false;
1132
1133}
1134
1135
1136float segmentSqrDistance(float4 from, float4 to,float4 p, float4* nearest)
1137{
1138	float4 diff = p - from;
1139	float4 v = to - from;
1140	float t = dot(v,diff);
1141
1142	if (t > 0)
1143	{
1144		float dotVV = dot(v,v);
1145		if (t < dotVV)
1146		{
1147			t /= dotVV;
1148			diff -= t*v;
1149		} else
1150		{
1151			t = 1;
1152			diff -= v;
1153		}
1154	} else
1155	{
1156		t = 0;
1157	}
1158	*nearest = from + t*v;
1159	return dot(diff,diff);
1160}
1161
1162
1163void	computeContactSphereTriangle(int pairIndex,
1164									int bodyIndexA, int bodyIndexB,
1165									int collidableIndexA, int collidableIndexB,
1166									__global const BodyData* rigidBodies,
1167									__global const btCollidableGpu* collidables,
1168									const float4* triangleVertices,
1169									__global struct b3Contact4Data* restrict globalContactsOut,
1170									counter32_t nGlobalContactsOut,
1171									int maxContactCapacity,
1172									float4 spherePos2,
1173									float radius,
1174									float4 pos,
1175									float4 quat,
1176									int faceIndex
1177									)
1178{
1179
1180	float4 invPos;
1181	float4 invOrn;
1182
1183	trInverse(pos,quat, &invPos,&invOrn);
1184	float4 spherePos = transform(&spherePos2,&invPos,&invOrn);
1185	int numFaces = 3;
1186	float4 closestPnt = (float4)(0, 0, 0, 0);
1187	float4 hitNormalWorld = (float4)(0, 0, 0, 0);
1188	float minDist = -1000000.f;
1189	bool bCollide = false;
1190
1191
1192	//////////////////////////////////////
1193
1194	float4 sphereCenter;
1195	sphereCenter = spherePos;
1196
1197	const float4* vertices = triangleVertices;
1198	float contactBreakingThreshold = 0.f;//todo?
1199	float radiusWithThreshold = radius + contactBreakingThreshold;
1200	float4 edge10;
1201	edge10 = vertices[1]-vertices[0];
1202	edge10.w = 0.f;//is this needed?
1203	float4 edge20;
1204	edge20 = vertices[2]-vertices[0];
1205	edge20.w = 0.f;//is this needed?
1206	float4 normal = cross3(edge10,edge20);
1207	normal = normalize(normal);
1208	float4 p1ToCenter;
1209	p1ToCenter = sphereCenter - vertices[0];
1210
1211	float distanceFromPlane = dot(p1ToCenter,normal);
1212
1213	if (distanceFromPlane < 0.f)
1214	{
1215		//triangle facing the other way
1216		distanceFromPlane *= -1.f;
1217		normal *= -1.f;
1218	}
1219	hitNormalWorld = normal;
1220
1221	bool isInsideContactPlane = distanceFromPlane < radiusWithThreshold;
1222
1223	// Check for contact / intersection
1224	bool hasContact = false;
1225	float4 contactPoint;
1226	if (isInsideContactPlane)
1227	{
1228
1229		if (pointInTriangle(vertices,&normal, &sphereCenter))
1230		{
1231			// Inside the contact wedge - touches a point on the shell plane
1232			hasContact = true;
1233			contactPoint = sphereCenter - normal*distanceFromPlane;
1234
1235		} else {
1236			// Could be inside one of the contact capsules
1237			float contactCapsuleRadiusSqr = radiusWithThreshold*radiusWithThreshold;
1238			float4 nearestOnEdge;
1239			int numEdges = 3;
1240			for (int i = 0; i < numEdges; i++)
1241			{
1242				float4 pa =vertices[i];
1243				float4 pb = vertices[(i+1)%3];
1244
1245				float distanceSqr = segmentSqrDistance(pa,pb,sphereCenter, &nearestOnEdge);
1246				if (distanceSqr < contactCapsuleRadiusSqr)
1247				{
1248					// Yep, we're inside a capsule
1249					hasContact = true;
1250					contactPoint = nearestOnEdge;
1251
1252				}
1253
1254			}
1255		}
1256	}
1257
1258	if (hasContact)
1259	{
1260
1261		closestPnt = contactPoint;
1262		float4 contactToCenter = sphereCenter - contactPoint;
1263		minDist = length(contactToCenter);
1264		if (minDist>FLT_EPSILON)
1265		{
1266			hitNormalWorld = normalize(contactToCenter);//*(1./minDist);
1267			bCollide  = true;
1268		}
1269
1270	}
1271
1272
1273	/////////////////////////////////////
1274
1275	if (bCollide && minDist > -10000)
1276	{
1277
1278		float4 normalOnSurfaceB1 = qtRotate(quat,-hitNormalWorld);
1279		float4 pOnB1 = transform(&closestPnt,&pos,&quat);
1280		float actualDepth = minDist-radius;
1281
1282
1283		if (actualDepth<=0.f)
1284		{
1285			pOnB1.w = actualDepth;
1286			int dstIdx;
1287
1288
1289			float lenSqr = dot3F4(normalOnSurfaceB1,normalOnSurfaceB1);
1290			if (lenSqr>FLT_EPSILON)
1291			{
1292				AppendInc( nGlobalContactsOut, dstIdx );
1293
1294				if (dstIdx < maxContactCapacity)
1295				{
1296					__global struct b3Contact4Data* c = &globalContactsOut[dstIdx];
1297					c->m_worldNormalOnB = -normalOnSurfaceB1;
1298					c->m_restituitionCoeffCmp = (0.f*0xffff);c->m_frictionCoeffCmp = (0.7f*0xffff);
1299					c->m_batchIdx = pairIndex;
1300					c->m_bodyAPtrAndSignBit = rigidBodies[bodyIndexA].m_invMass==0?-bodyIndexA:bodyIndexA;
1301					c->m_bodyBPtrAndSignBit = rigidBodies[bodyIndexB].m_invMass==0?-bodyIndexB:bodyIndexB;
1302					c->m_worldPosB[0] = pOnB1;
1303
1304					c->m_childIndexA = -1;
1305					c->m_childIndexB = faceIndex;
1306
1307					GET_NPOINTS(*c) = 1;
1308				}
1309			}
1310
1311		}
1312	}//if (hasCollision)
1313
1314}
1315
1316
1317
1318// work-in-progress
1319__kernel void   findConcaveSphereContactsKernel( __global int4* concavePairs,
1320												__global const BodyData* rigidBodies,
1321												__global const btCollidableGpu* collidables,
1322												__global const ConvexPolyhedronCL* convexShapes,
1323												__global const float4* vertices,
1324												__global const float4* uniqueEdges,
1325												__global const btGpuFace* faces,
1326												__global const int* indices,
1327												__global btAabbCL* aabbs,
1328												__global struct b3Contact4Data* restrict globalContactsOut,
1329												counter32_t nGlobalContactsOut,
1330													int numConcavePairs, int maxContactCapacity
1331												)
1332{
1333
1334	int i = get_global_id(0);
1335	if (i>=numConcavePairs)
1336		return;
1337	int pairIdx = i;
1338
1339	int bodyIndexA = concavePairs[i].x;
1340	int bodyIndexB = concavePairs[i].y;
1341
1342	int collidableIndexA = rigidBodies[bodyIndexA].m_collidableIdx;
1343	int collidableIndexB = rigidBodies[bodyIndexB].m_collidableIdx;
1344
1345	int shapeIndexA = collidables[collidableIndexA].m_shapeIndex;
1346	int shapeIndexB = collidables[collidableIndexB].m_shapeIndex;
1347
1348	if (collidables[collidableIndexB].m_shapeType==SHAPE_SPHERE)
1349	{
1350		int f = concavePairs[i].z;
1351		btGpuFace face = faces[convexShapes[shapeIndexA].m_faceOffset+f];
1352
1353		float4 verticesA[3];
1354		for (int i=0;i<3;i++)
1355		{
1356			int index = indices[face.m_indexOffset+i];
1357			float4 vert = vertices[convexShapes[shapeIndexA].m_vertexOffset+index];
1358			verticesA[i] = vert;
1359		}
1360
1361		float4 spherePos = rigidBodies[bodyIndexB].m_pos;
1362		float sphereRadius = collidables[collidableIndexB].m_radius;
1363		float4 convexPos = rigidBodies[bodyIndexA].m_pos;
1364		float4 convexOrn = rigidBodies[bodyIndexA].m_quat;
1365
1366		computeContactSphereTriangle(i, bodyIndexB, bodyIndexA, collidableIndexB, collidableIndexA,
1367																rigidBodies,collidables,
1368																verticesA,
1369																globalContactsOut, nGlobalContactsOut,maxContactCapacity,
1370																spherePos,sphereRadius,convexPos,convexOrn, f);
1371
1372		return;
1373	}
1374}