; 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 call ResetPool3D mov poolState3D,POOL_SELECT ret InitPool3D ENDP StartBilliards3D PROC variant:DWORD cmp variant,1 ja @F mov eax,variant mov poolVariant3D,eax call ResetPool3D call ClearKeys3D @@: ret StartBilliards3D ENDP ResetPool3D PROC uses ebx esi edi mov poolTraceValid3D,0 mov poolCapture2Q8,480*480 mov poolMiddleLeft3D,157*FP_1 mov poolMiddleRight3D,163*FP_1 lea esi,poolPyramidJawX3D lea edi,poolJawX3D mov ecx,24 rep movsd cmp poolVariant3D,0 je @F mov poolCapture2Q8,1024*1024 mov poolMiddleLeft3D,153*FP_1 mov poolMiddleRight3D,167*FP_1 lea esi,poolEightJawX3D lea edi,poolJawX3D mov ecx,24 rep movsd @@: 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 mov poolCallManual3D,0 call InitPyramidState3D ret ResetPool3D 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,5*FP_1 jg pool_pocket_next cmp eax,-5*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,5*FP_1 jg pool_pocket_next cmp eax,-5*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, poolCapture2Q8 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 mov eax,poolMiddleLeft3D cmp poolX3D[esi*4], eax jl pool_rail_test_y mov eax,poolMiddleRight3D cmp poolX3D[esi*4], eax 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,poolVY3D[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\eightball.inc include src_graphics\pyramid_play.inc include src_graphics\billiards_prediction.inc include src_graphics\pyramid_render.inc