; Q16.16 simulation, velocities in cloth pixels per 2 ms fixed step. PoolSqrt3D PROC squared:DWORD local result:DWORD fild squared fsqrt fistp result mov eax, result ret PoolSqrt3D ENDP InitPool3D PROC uses ebx esi edi lea edi, poolVX3D xor eax, eax mov ecx, 32 rep stosd xor esi, esi pool_init_balls: mov poolActive3D[esi*4], 1 mov poolPocket3D[esi*4], -1 mov poolSinkTime3D[esi*4], 0 inc esi cmp esi, 16 jb pool_init_balls mov poolX3D, 82*FP_1 mov poolY3D, 115*FP_1 xor esi, esi xor ebx, ebx pool_rack_row: xor edi, edi pool_rack_ball: mov ecx, poolRackOrder3D[esi*4] imul eax, ebx, FP_1*43302/10000 add eax, 225*FP_1 mov poolX3D[ecx*4], eax imul eax, edi, 5*FP_1 imul edx, ebx, FP_1*5/2 sub eax, edx add eax, 115*FP_1 mov poolY3D[ecx*4], eax inc esi inc edi cmp edi, ebx jbe pool_rack_ball inc ebx cmp ebx, 5 jb pool_rack_row mov poolState3D, POOL_AIM mov poolPlayer3D, 0 mov poolGroups3D, 0 mov poolGroups3D[4], 0 mov poolAngle3D, 0 mov poolPower3D, 80000 mov poolBreak3D, 1 mov poolAccumulator3D, 0 mov poolCharge3D, 0 mov poolTime3D, 0 mov poolFoul3D, 0 mov poolPotted3D, 0 mov poolStill3D, 1 mov poolCalled3D, 1 mov poolCalledPocket3D, 0 call InitPyramidState3D ret InitPool3D ENDP ; Symmetric equal-mass impulse plus separation; opening contacts never gain energy. PoolCollide3D PROC uses ebx esi edi a:DWORD,b:DWORD local deltaX:DWORD,deltaY:DWORD,length8:DWORD,nx:DWORD,ny:DWORD,impulse:DWORD,correction:DWORD mov esi, a mov edi, b cmp poolActive3D[esi*4], 0 je pool_pair_done cmp poolActive3D[edi*4], 0 je pool_pair_done mov eax, poolX3D[edi*4] sub eax, poolX3D[esi*4] cmp eax, POOL_DIAMETER jg pool_pair_done cmp eax, -POOL_DIAMETER jl pool_pair_done mov deltaX, eax mov eax, poolY3D[edi*4] sub eax, poolY3D[esi*4] cmp eax, POOL_DIAMETER jg pool_pair_done cmp eax, -POOL_DIAMETER jl pool_pair_done mov deltaY, eax sar eax, 8 imul eax, eax mov ebx, deltaX sar ebx, 8 imul ebx, ebx add eax, ebx cmp eax, 25*256*256 jg pool_pair_done test eax, eax jnz @F mov deltaX, 256 mov eax, 1 @@: invoke PoolSqrt3D, eax cmp eax, 1 jge @F mov eax, 1 @@: mov length8, eax mov eax, deltaX imul eax, 256 cdq idiv length8 mov nx, eax mov eax, deltaY imul eax, 256 cdq idiv length8 mov ny, eax mov eax, poolVX3D[edi*4] sub eax, poolVX3D[esi*4] imul nx shrd eax, edx, 16 mov ebx, eax mov eax, poolVY3D[edi*4] sub eax, poolVY3D[esi*4] imul ny shrd eax, edx, 16 add eax, ebx test eax, eax jns pool_pair_separate imul eax, 99 cdq mov ecx, 100 idiv ecx mov impulse, eax imul nx shrd eax, edx, 16 add poolVX3D[esi*4], eax sub poolVX3D[edi*4], eax mov eax, impulse imul ny shrd eax, edx, 16 add poolVY3D[esi*4], eax sub poolVY3D[edi*4], eax invoke PyramidContact3D,esi,edi cmp esi,pyrCue3D je @F cmp edi,pyrCue3D jne pool_pair_separate cmp poolFirst3D,-1 jne pool_pair_separate mov poolFirst3D,esi jmp pool_pair_separate @@: cmp poolFirst3D, -1 jne pool_pair_separate mov poolFirst3D, edi pool_pair_separate: mov eax, length8 shl eax, 8 neg eax add eax, POOL_DIAMETER sar eax, 1 mov correction, eax imul nx shrd eax, edx, 16 sub poolX3D[esi*4], eax add poolX3D[edi*4], eax mov eax, correction imul ny shrd eax, edx, 16 sub poolY3D[esi*4], eax add poolY3D[edi*4], eax pool_pair_done: ret PoolCollide3D ENDP PoolPocketBall3D PROC uses ebx esi ball:DWORD mov esi, ball cmp poolActive3D[esi*4],0 je pool_pocket_done xor ebx, ebx pool_pocket_test: mov eax, poolX3D[esi*4] sub eax, poolPocketX3D[ebx*4] cmp eax,2*FP_1 jg pool_pocket_next cmp eax,-2*FP_1 jl pool_pocket_next sar eax, 8 imul eax, eax mov ecx, eax mov eax, poolY3D[esi*4] sub eax, poolPocketY3D[ebx*4] cmp eax,2*FP_1 jg pool_pocket_next cmp eax,-2*FP_1 jl pool_pocket_next sar eax, 8 imul eax, eax add eax, ecx ; Capture is deep inside the narrow mouth; jaws are separate colliders. cmp eax, 480*480 ja pool_pocket_next pool_pocket_capture: mov poolActive3D[esi*4], 0 mov poolVX3D[esi*4], 0 mov poolVY3D[esi*4], 0 mov poolPocket3D[esi*4], ebx mov poolSinkTime3D[esi*4], 220 bts poolPotted3D, esi ret pool_pocket_next: inc ebx cmp ebx, 6 jb pool_pocket_test pool_pocket_done: ret PoolPocketBall3D ENDP PoolRailContact3D PROC ball:DWORD mov ecx, ball bts poolBreakRails3D, ecx cmp poolFirst3D, -1 je @F mov poolRail3D, 1 invoke PyramidRail3D,ball,pyrRailSide3D @@: ret PoolRailContact3D ENDP PoolJawContact3D PROC uses ebx esi edi ball:DWORD local deltaX:DWORD,deltaY:DWORD,distance:DWORD,normX:DWORD,normY:DWORD,impulse:DWORD mov esi, ball xor edi, edi pool_jaw_test: mov eax, poolX3D[esi*4] sub eax, poolJawX3D[edi*4] cmp eax, 3*FP_1 jg pool_jaw_next cmp eax, -3*FP_1 jl pool_jaw_next mov deltaX, eax mov eax, poolY3D[esi*4] sub eax, poolJawY3D[edi*4] cmp eax, 3*FP_1 jg pool_jaw_next cmp eax, -3*FP_1 jl pool_jaw_next mov deltaY, eax sar eax, 8 imul eax, eax mov ebx, deltaX sar ebx, 8 imul ebx, ebx add eax, ebx cmp eax, 704*704 ja pool_jaw_next test eax, eax jnz @F mov deltaX, 256 mov eax, 1 @@: invoke PoolSqrt3D,eax cmp eax, 1 jge @F mov eax, 1 @@: mov distance, eax mov eax, deltaX imul eax, 256 cdq idiv distance mov normX, eax mov eax, deltaY imul eax, 256 cdq idiv distance mov normY, eax mov eax, poolVX3D[esi*4] imul normX shrd eax, edx, 16 mov ebx, eax mov eax, poolVY3D[esi*4] imul normY shrd eax, edx, 16 add eax, ebx test eax, eax jns pool_jaw_separate imul eax, 187 cdq mov ecx, 100 idiv ecx mov impulse, eax imul normX shrd eax, edx, 16 sub poolVX3D[esi*4], eax mov eax, impulse imul normY shrd eax, edx, 16 sub poolVY3D[esi*4], eax mov pyrRailSide3D,0 cmp edi,6 jb @F mov pyrRailSide3D,1 @@: cmp edi,1 je pyr_jaw_left_side cmp edi,7 jne @F pyr_jaw_left_side: mov pyrRailSide3D,2 @@: cmp edi,4 je pyr_jaw_right_side cmp edi,10 jne @F pyr_jaw_right_side: mov pyrRailSide3D,3 @@: invoke PoolRailContact3D,esi pool_jaw_separate: mov eax, distance shl eax, 8 neg eax add eax, FP_1*11/4 mov impulse, eax imul normX shrd eax, edx, 16 add poolX3D[esi*4], eax mov eax, impulse imul normY shrd eax, edx, 16 add poolY3D[esi*4], eax pool_jaw_next: inc edi cmp edi, 12 jb pool_jaw_test ret PoolJawContact3D ENDP PoolStep3D PROC uses ebx esi edi xor esi, esi pool_step_ball: cmp poolActive3D[esi*4], 0 je pool_step_next mov eax,poolX3D[esi*4] mov pyrPreviousX3D[esi*4],eax mov eax, poolVX3D[esi*4] add poolX3D[esi*4], eax mov eax, poolVY3D[esi*4] add poolY3D[esi*4], eax invoke PyramidCross3D,esi invoke PoolPocketBall3D, esi cmp poolActive3D[esi*4], 0 je pool_step_next invoke PoolJawContact3D,esi ; Leave the corner throats open. Solid cushions stop at their jaws. mov ebx, 30*FP_1+POOL_RADIUS mov edi, 290*FP_1-POOL_RADIUS cmp poolY3D[esi*4], 57*FP_1 jle pool_rail_corner_x cmp poolY3D[esi*4], 173*FP_1 jl pool_rail_test_x pool_rail_corner_x: mov ebx, 31*FP_1 mov edi, 289*FP_1 pool_rail_test_x: cmp poolX3D[esi*4], ebx jge pool_rail_right mov poolX3D[esi*4], ebx mov eax, poolVX3D[esi*4] test eax, eax jns pool_rail_y jmp pool_rail_bounce_x pool_rail_right: cmp poolX3D[esi*4], edi jle pool_rail_y mov poolX3D[esi*4], edi mov eax, poolVX3D[esi*4] test eax, eax jle pool_rail_y pool_rail_bounce_x: imul eax, -87 cdq mov ecx, 100 idiv ecx mov poolVX3D[esi*4], eax mov pyrRailSide3D,2 cmp poolX3D[esi*4],160*FP_1 jl @F mov pyrRailSide3D,3 @@: invoke PoolRailContact3D, esi pool_rail_y: mov ebx, 50*FP_1+POOL_RADIUS mov edi, 180*FP_1-POOL_RADIUS cmp poolX3D[esi*4], 37*FP_1 jle pool_rail_throat_y cmp poolX3D[esi*4], 283*FP_1 jge pool_rail_throat_y cmp poolX3D[esi*4], 157*FP_1 jl pool_rail_test_y cmp poolX3D[esi*4], 163*FP_1 jg pool_rail_test_y pool_rail_throat_y: mov ebx, 51*FP_1 mov edi, 179*FP_1 pool_rail_test_y: cmp poolY3D[esi*4], ebx jge pool_rail_bottom mov poolY3D[esi*4], ebx mov eax, poolVY3D[esi*4] test eax, eax jns pool_step_next jmp pool_rail_bounce_y pool_rail_bottom: cmp poolY3D[esi*4], edi jle pool_step_next mov poolY3D[esi*4], edi mov eax, poolVY3D[esi*4] test eax, eax jle pool_step_next pool_rail_bounce_y: imul eax, -87 cdq mov ecx, 100 idiv ecx mov poolVY3D[esi*4], eax mov pyrRailSide3D,0 cmp poolY3D[esi*4],115*FP_1 jl @F mov pyrRailSide3D,1 @@: invoke PoolRailContact3D, esi pool_step_next: inc esi cmp esi, 16 jb pool_step_ball ; Two contact passes stabilize the triangular break rack. mov ebx, 2 pool_contact_pass: xor esi, esi pool_contact_outer: lea edi, [esi+1] pool_contact_inner: invoke PoolCollide3D, esi,edi inc edi cmp edi, 16 jb pool_contact_inner inc esi cmp esi, 15 jb pool_contact_outer dec ebx jnz pool_contact_pass xor esi, esi mov poolStill3D, 1 pool_friction_ball: cmp poolActive3D[esi*4],0 je pool_sleep_ball mov eax,poolVX3D[esi*4] test eax,eax jns @F neg eax @@: add pyrRoll3D[esi*4],eax mov eax, poolVX3D[esi*4] sar eax, 4 imul eax, eax mov ecx, poolVY3D[esi*4] sar ecx, 4 imul ecx, ecx add eax, ecx cmp eax, 64 jbe pool_sleep_ball invoke PoolSqrt3D, eax shl eax, 4 cmp eax, 128 jbe pool_sleep_ball mov ecx, eax sub eax, 16 xor edx, edx shld edx, eax, 16 shl eax, 16 div ecx mov ecx, eax mov eax, poolVX3D[esi*4] imul ecx shrd eax, edx, 16 mov poolVX3D[esi*4], eax mov eax, poolVY3D[esi*4] imul ecx shrd eax, edx, 16 mov poolVY3D[esi*4], eax mov poolStill3D, 0 jmp pool_friction_next pool_sleep_ball: mov poolVX3D[esi*4], 0 mov poolVY3D[esi*4], 0 pool_friction_next: inc esi cmp esi, 16 jb pool_friction_ball ret PoolStep3D ENDP include src_graphics\pyramid_rules.inc include src_graphics\pyramid_play.inc include src_graphics\pyramid_render.inc