.data ;If penetration depth is less than this, ;we consider the penetration as 'trivial' fEpsilon_Penetration real4 0.01f .code ;Enumeration of 3D Geometric Shapes SHAPEID_UNDEFINED equ -1 SHAPEID_PLANE equ 0 ;derived from CollisionShape SHAPEID_TRIANGLE equ 1 ;derived from CollisionPlane SHAPEID_SPHERE equ 2 ;derived from CollisionBody ;Types of Physical Material supported by the physics engine: MATERIALID_UNDEFINED equ -1 MATERIALID_WOOD equ 0 MATERIALID_STONE equ 1 MATERIALID_ICE equ 2 MATERIALID_GLASS equ 3 MATERIALID_METAL equ 4 MATERIALID_RUBBER equ 5 MATERIALID_VELCRO equ 6 MATERIALID_MEAT equ 7 ;Enumeration of Collision result Penetrating equ -1 Clear equ 0 Colliding equ 1 ;This struct describes the minimal physical State for collision checking. ;Note that this describes a physical body 'without mass', ;although 'CM' refers to the Center of Mass of the object, which is ASSUMED to be its Origin. state struct CMPosition Vec3 <> ;Position in world space CMVelocity Vec3 <> ;Rate of change of Position CMForce Vec3 <> ;Linear force at center of mass Orientation Mat33 <> ;rotation matrix, bodyspace to worldspace AngularVelocity Vec3 <> ;Rate of change of orientation AngularMomentum Vec3 <> ; CMTorque Vec3 <> ;Angular force at center of mass dCollisionState dword Clear ;Clear, Colliding, or Penetrating state ends ; 覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧 ;The CollisionShape class is our baseclass for collidable entities. Object CollisionShape, 345343, Primer RedefineMethod Init, Pointer, dword DefineVariable dShapeID, dword, SHAPEID_UNDEFINED ;describes the shape of the 3D geometry DefineVariable dMaterialID, dword, MATERIALID_UNDEFINED ;describes the physical material properties ObjectEnd Method CollisionShape.Init,uses esi, pOwner, dShapeID SetObject esi ACall Init, pOwner m2m [esi].dShapeID, dShapeID, edx MethodEnd ; 覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧 ;The CollisionPlane class is our most primitive CollisionShape. Object CollisionPlane, 234234, CollisionShape RedefineMethod Init, Pointer, dword, Pointer DefineVariable plane, Vec4, {<>} ObjectEnd Method CollisionPlane.Init,uses esi,pOwner,dShapeID,pplane SetObject esi ACall Init, pOwner, dShapeID mov edx,pplane m2m [esi].plane.x,[edx].Vec4.x,eax m2m [esi].plane.y,[edx].Vec4.y,eax m2m [esi].plane.z,[edx].Vec4.z,eax m2m [esi].plane.w,[edx].Vec4.w,eax MethodEnd ; 覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧 ;The CollisionTriangle class is derived from CollisionPlane. Object CollisionTriangle,234232,CollisionPlane RedefineMethod Init,Pointer,dword,Pointer,Pointer,Pointer RedefineMethod Done VirtualMethod versus_Point, Pointer DefineVariable pPoints,Pointer,NULL ObjectEnd Method CollisionTriangle.Init,uses esi,pOwner,dShapeID,pvA,pvB,pvC LOCAL Plane:Vec4 LOCAL EdgeAB:Vec3 LOCAL EdgeAC:Vec3 SetObject esi ;Keep a local record of the triangle vertices mov [esi].pPoints,$MemAlloc(3*sizeof Vec3) mov edx,eax mov eax,pvA mov ebx,pvB mov ecx,pvC Vec3_Load [eax].Vec3 Vec3_Stow [edx].Vec3 Vec3_Load [ebx].Vec3 Vec3_Stow [edx+1*sizeof Vec3].Vec3 Vec3_Load [ecx].Vec3 Vec3_Stow [edx+2*sizeof Vec3].Vec3 ;Calculate the Plane of the triangle Vec3_Sub [ebx].Vec3, [eax].Vec3 ;Calculating Normal Vec3_Stow EdgeAB ;its the crossproduct Vec3_Sub [ecx].Vec3, [eax].Vec3 ;of any two Edges Vec3_Stow EdgeAC Vec3_Cross EdgeAB,EdgeAC Vec3_Stow Plane Vec3_Normalize Plane ;Normalize the normal Vec3_Dot Plane,Plane ;Calculating the PlaneD fchs ;= -dot (normal, normal) fstp Plane.w DbgVec4 Plane ;Initialize the ancestor CollisionPlane ACall Init,pOwner,dShapeID,addr Plane MethodEnd Method CollisionTriangle.Done,uses esi SetObject esi MemFree [esi].pPoints ACall Done MethodEnd ;This procedure uses the Barycentric technique ;to determine whether the given Point ;is located within the given 3D Triangle ;Returns TRUE/FALSE ;pvPoint = Point to be tested ; ;NOTES : The Barycentric coordinates (u,v) can be ;thought of as 'weights' for linear interpolation along ;the triangle edges AB and AC. ;It is therefore possible to convert these coordinates ;into TEXTURE COORDINATES via linear interpolation ;of the texcoords at the three points of the triangle Method CollisionTriangle.versus_Point, uses esi, pvPoint LOCAL v0:Vec3 LOCAL v1:Vec3 LOCAL v2:Vec3 LOCAL dot00:real8 LOCAL dot01:real8 LOCAL dot02:real8 LOCAL dot11:real8 LOCAL dot12:real8 LOCAL invDenom:real8 LOCAL u:real8 LOCAL v:real8 SetObject esi ; Compute vectors ;v0 = C - A ;v1 = B - A ;v2 = P - A mov eax,[esi].pPoints mov ebx,eax mov ecx,eax add ebx,1*sizeof Vec3 add ecx,2*sizeof Vec3 mov edx,pvPoint Vec3_Sub [ecx].Vec3, [eax].Vec3 Vec3_Stow v0 Vec3_Sub [ebx].Vec3, [eax].Vec3 Vec3_Stow v1 Vec3_Sub [edx].Vec3, [eax].Vec3 Vec3_Stow v2 ; Compute dot products ;dot00 = dot(v0, v0) ;dot01 = dot(v0, v1) ;dot02 = dot(v0, v2) ;dot11 = dot(v1, v1) ;dot12 = dot(v1, v2) Vec3_Dot v0,v0 fstp dot00 Vec3_Dot v0,v1 fstp dot01 Vec3_Dot v0,v2 fstp dot02 Vec3_Dot v1,v1 fstp dot11 Vec3_Dot v1,v2 fstp dot12 ; Compute barycentric coordinates: ;invDenom = 1 / (dot00 * dot11 - dot01 * dot01) ;u = (dot11 * dot02 - dot01 * dot12) * invDenom ;v = (dot00 * dot12 - dot01 * dot02) * invDenom fld1 fld dot00 fmul dot11 fld dot01 fmul st(0),st(0) fsub fdiv fst invDenom fld dot11 fmul dot02 fld dot01 fmul dot12 fsub fmul ;invDenom fstp u fld dot00 fmul dot12 fld dot01 fmul dot02 fsub fmul invDenom fstp v ; Check if point is in triangle ;return (u > 0) && (v > 0) && (u + v < 1) fld u fldz fcompp fjle @F fld v fldz fcompp fjle @F fld u fadd v fld1 fjge @F return TRUE @@: mov eax, FALSE MethodEnd ; 覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧覧 ;The CollisionBody class describes a collidable object. ;It has linear and angular velocity (3D speed and spin), but has NO Mass-related properties, ;and cannot RESOLVE collisions, only DETECT them. Object CollisionBody, 82124, CollisionShape ;Constructor/Destructor methods RedefineMethod Init, Pointer, dword ;Get/Set methods VirtualMethod SetMass, real4, real8 VirtualMethod SetVelocity, Pointer VirtualMethod Get_Closing_And_Relative_Velocities, Pointer VirtualMethod Get_Local_Velocity,Pointer,Pointer ;pm33_ContactToWorld, pvrelativeContactPosition VirtualMethod Get_Linear_Momentum_Due_To_Rotation,Pointer,Pointer ;Collision Detection / Resolution methods VirtualMethod Body_Sweep_Body, Pointer VirtualMethod Body_Sweep_Plane, Pointer, Pointer ;pContactOut VirtualMethod Sphere_Sweep_Plane, Pointer, Pointer ;pContactOut, pPlaneIn VirtualMethod Apply_Correction, Pointer,Pointer ;Physics Integration VirtualMethod Integrate, real8 ;Constants DefineVariable CoefficientOfRestitution,real4,0.8 ;'bouncyness' DefineVariable Density, real4, 1.0 ;Density of Material - in case we need to calculate Mass from Volume DefineVariable Mass, real4, 1.0 ;Mass of Object - should be either calculated or explicitly set DefineVariable OneOverMass, real4, 1.0 ;Inverse of Mass, used to avoid some divisions, speeds up some maths DefineVariable fRadius, real4, 0.0 ;BoundingSphere Radius DefineVariable InverseBodyInertiaTensor, Mat33, {<>} ;Physical States DefineVariable OldState, state, {<>} ;state at the start of the timestep DefineVariable NewState, state, {<>} ;state at the end of the timestep ;Variables ;This is the velocity-delta which was caused only by acceleration in this frame DefineVariable VelocityChange, Vec3, {<>} ;This is the accumulator of velocity-deltas resulting from collision impulses DefineVariable Velocity_Delta, Vec3,{<>} DefineVariable AngMomentum_Delta, Vec3,{<>} ;This is the number N of Impulses which have been applied to this Body ;due to collisions with N other bodies (usually ONE) DefineVariable dNumContacts,dword,NULL ;DefineVariable AngMomentumChange,Vec3, {<>} ;angular momentum delta for this frame DefineVariable InverseWorldInertiaTensor, Mat33, {<>} DefineVariable m44_BodyToWorld, Mat44, {<>} ;rotation & translation (no scaling or shear) ;Switches DefineVariable IsAwake, BOOL,TRUE ;Sleeping objects cannot 'cause' a collision DefineVariable IsHollow,BOOL,FALSE ;TRUE if object is a hollow shell ObjectEnd Method CollisionBody.Init,uses esi, pOwner, dShapeID SetObject esi ACall Init, pOwner, dShapeID invoke RtlZeroMemory,addr [esi].OldState,sizeof state*2 Mat33_Identity [esi].OldState.Orientation MethodEnd Method CollisionBody.SetOrientation, uses esi, pMat44 SetObject esi mov eax,pMat44 m2m [esi].OldState.Orientation.m00, [eax].Mat44.m00,edx m2m [esi].OldState.Orientation.m01, [eax].Mat44.m01,edx m2m [esi].OldState.Orientation.m02, [eax].Mat44.m02,edx m2m [esi].OldState.Orientation.m10, [eax].Mat44.m10,edx m2m [esi].OldState.Orientation.m11, [eax].Mat44.m11,edx m2m [esi].OldState.Orientation.m12, [eax].Mat44.m12,edx m2m [esi].OldState.Orientation.m20, [eax].Mat44.m20,edx m2m [esi].OldState.Orientation.m21, [eax].Mat44.m21,edx m2m [esi].OldState.Orientation.m22, [eax].Mat44.m22,edx MethodEnd Method CollisionBody.SetVelocity, uses esi, pVec3 SetObject esi mov eax,pVec3 m2m [esi].OldState.CMVelocity.x, [eax].Vec3.x,edx m2m [esi].OldState.CMVelocity.y, [eax].Vec3.y,edx m2m [esi].OldState.CMVelocity.z, [eax].Vec3.z,edx MethodEnd Method CollisionBody.SetPosition, uses esi, pVec3 SetObject esi mov eax,pVec3 m2m [esi].OldState.CMPosition.x, [eax].Vec3.x,edx m2m [esi].OldState.CMPosition.y, [eax].Vec3.y,edx m2m [esi].OldState.CMPosition.z, [eax].Vec3.z,edx MethodEnd Method CollisionBody.SetSpin, uses esi, pVec3 SetObject esi mov eax,pVec3 m2m [esi].OldState.AngularVelocity.x, [eax].Vec3.x,edx m2m [esi].OldState.AngularVelocity.y, [eax].Vec3.y,edx m2m [esi].OldState.AngularVelocity.z, [eax].Vec3.z,edx MethodEnd Method CollisionBody.SetMass, uses esi, fDensity:real4, fVolume:real8 SetObject esi fld1 fld fDensity fmul fVolume fst [esi].Mass fdiv fstp [esi].OneOverMass MethodEnd QuadraticFormula macro ; q = b*b - 4*a*c fld _b fmul st(0),st(0) fld _a fmul _c fadd st(0),st(0) fadd st(0),st(0) fsub fstReg eax ;if q >= 0 .ifBitSet eax, BIT31 fUnload mov eax, FALSE ;complex root .else ; sq = sqrt(q) fsqrt fstp sq ;d = 1 / (2*a) fld1 fld _a fadd st(0),st(0) fdiv fstp _d ;u0 = ( -b + sq ) * d fld _b ; fchs fadd sq fmul _d fstp u0 ;u1 = ( -b - sq ) * d fld _b ; fchs fsub sq fmul _d fstp u1 ;load fpu with T = smaller of two impact times fMin u0, u1 mov eax,TRUE .endif endm ;Sweep for collision of moving sphere and fixed plane ;Possible return values are: ;eax=Penetrating - Body was penetrating in previous frame (pSource) ;eax=Colliding - Body will collide with Plane at point pCi, the Time scalar is on the fpu stack ;eax=Clear - Body does not collide with Plane during this frame Method CollisionBody.Sphere_Sweep_Plane,uses esi,pContact,pPlane local u:real8 ;normalized time of collision LOCAL d0, d1 LOCAL vab LOCAL ftemp:real8 SetObject esi mov eax,pPlane ;Calculate distance from starting position to plane Vec3_PlaneDotCoord [esi].OldState.CMPosition, [eax].CollisionPlane.plane fst d0 ;Calculate distance from end position to plane Vec3_PlaneDotCoord [esi].NewState.CMPosition, [eax].CollisionPlane.plane fst d1 ;If d0=d1 , the sphere is not moving ;If d0