Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

508 lines
18 KiB

  1. page ,132
  2. ;------------------------------Module-Header-------------------------------;
  3. ; Module Name: xline.asm ;
  4. ; ;
  5. ; Contains the line intersection routine. ;
  6. ; ;
  7. ; Created: 26-Apr-1991 10:49:53 ;
  8. ; Author: Charles Whitmer [chuckwh] ;
  9. ; ;
  10. ; Copyright (c) 1991-1999 Microsoft Corporation ;
  11. ;--------------------------------------------------------------------------;
  12. .386
  13. .model small,c
  14. assume cs:FLAT,ds:FLAT,es:FLAT,ss:FLAT
  15. assume fs:nothing,gs:nothing
  16. .xlist
  17. include stdcall.inc
  18. include gdii386.inc
  19. .list
  20. .code
  21. QUAD struc
  22. lo dd 0
  23. hi dd 0
  24. QUAD ends
  25. extrn cmp_table_1:dword
  26. extrn cmp_table_2:dword
  27. extrn cmp_table_3:dword
  28. extrn cmp_table_4:dword
  29. ;------------------------------Public-Routine------------------------------;
  30. ; LONG fxYIntersect (pptlAB,pptlCD) ;
  31. ; POINTL *pptlAB; // First line segment. ;
  32. ; POINTL *pptlCD; // Second line segment. ;
  33. ; ;
  34. ; Computes the y coordinate of the intersection of the two line segments. ;
  35. ; The returned value is the ceiling of the exact geometric intersection. ;
  36. ; ;
  37. ; The intersection is computed by: ;
  38. ; ;
  39. ; (Cx - Ax)(Cy - Dy) + (Cy - Ay)(Dx - Cx) ;
  40. ; lamda = --------------------------------------- ;
  41. ; (Bx - Ax)(Cy - Dy) + (By - Ay)(Dx - Cx) ;
  42. ; ;
  43. ; If (lamda < 0) or (lamda > 1) then there is no intersection, and we ;
  44. ; return 0x80000000. ;
  45. ; ;
  46. ; Y = Ay + lamda * (By - Ay) ;
  47. ; ;
  48. ; We assume on entry to this routine that all coordinates are limited to ;
  49. ; 31 bits of significance. Because of this we know that quantities like ;
  50. ; (Cx - Ax) will fit in 32 bits. Also, products like (Cx - Ax)(Cy - Dy) ;
  51. ; will fit in 63 bits, and sums as in the numerator of lamda will fit in ;
  52. ; 64 bits. ;
  53. ; ;
  54. ; Note that if you call this routine with POINTFX's instead of POINTL's ;
  55. ; you'll get answers that are correct down to 1/16th pel. If you only ;
  56. ; want the integer part, just shift the answer right by 4 bits. ;
  57. ; ;
  58. ; History: ;
  59. ; Wed 25-Sep-1991 16:52:20 -by- Wendy Wu [wendywu] ;
  60. ; 1) Changed to return the ceiling of the geometric intersection rather ;
  61. ; than the floor. ;
  62. ; 2) When the given two line segments are actually the same line, we used ;
  63. ; to return 0x80000000, now return the y at which they last "intersect".;
  64. ; 3) If Y is bigger or smaller than both Cy and Dy, return 0x80000000. ;
  65. ; ;
  66. ; Fri 26-Apr-1991 10:52:28 -by- Charles Whitmer [chuckwh] ;
  67. ; Wrote it. ;
  68. ;--------------------------------------------------------------------------;
  69. SEGAB struc
  70. AB_xA dd 0
  71. AB_yA dd 0
  72. AB_xB dd 0
  73. AB_yB dd 0
  74. SEGAB ends
  75. SEGCD struc
  76. CD_xC dd 0
  77. CD_yC dd 0
  78. CD_xD dd 0
  79. CD_yD dd 0
  80. SEGCD ends
  81. cProc fxYIntersect,8,< \
  82. uses ebx esi edi, \
  83. pptlAB: ptr SEGAB, \
  84. pptlCD: ptr SEGCD >
  85. local xA: dword
  86. local yA: dword
  87. local yByA: dword
  88. local qDenom: qword
  89. ; Load AB into registers.
  90. mov esi,pptlAB
  91. mov ebx,[esi].AB_yA
  92. mov edx,[esi].AB_yB
  93. mov eax,[esi].AB_xA
  94. mov ecx,[esi].AB_xB
  95. ; Reorder AB so that By >= Ay. This will guarantee that (By - Ay)*lamda is a
  96. ; positive number so that it's easier to compute the ceiling. (This lets us
  97. ; complete the division earlier than a normal extended precision one.)
  98. cmp edx,ebx
  99. jg @F
  100. xchg eax,ecx
  101. xchg ebx,edx
  102. @@:
  103. ; Save A locally.
  104. mov xA,eax
  105. mov yA,ebx
  106. ; Compute qDenom = (Bx - Ax)(Cy - Dy) + (By - Ay)(Dx - Cx).
  107. sub edx,ebx ; EDX = (By - Ay)
  108. mov esi,pptlCD
  109. sub ecx,eax ; ECX = (Bx - Ax)
  110. mov eax,[esi].CD_xD
  111. mov yByA,edx
  112. sub eax,[esi].CD_xC ; EAX = (Dx - Cx)
  113. imul edx ; EDX:EAX = (By - Ay)(Dx - Cx)
  114. xchg ecx,edx ; EDX = (Bx - Ax)
  115. mov ebx,eax ; ECX:EBX = (By - Ay)(Dx - Cx)
  116. mov eax,[esi].CD_yC
  117. sub eax,[esi].CD_yD ; EAX = (Cy - Dy)
  118. imul edx ; EDX:EAX = (Bx - Ax)(Cy - Dy)
  119. add ebx,eax
  120. jz qDenom_maybe_zero
  121. adc ecx,edx ; ECX:EBX = qDenom
  122. qDenom_not_zero:
  123. mov qDenom.lo,ebx
  124. mov qDenom.hi,ecx
  125. ; Compute qNum = (Cx - Ax)(Cy - Dy) + (Cy - Ay)(Dx - Cx).
  126. mov edx,[esi].CD_yC
  127. sub edx,yA ; EDX = (Cy - Ay)
  128. mov eax,[esi].CD_xD
  129. sub eax,[esi].CD_xC ; EAX = (Dx - Cx)
  130. imul edx ; EDX:EAX = (Cy - Ay)(Dx - Cx)
  131. mov ecx,edx
  132. mov ebx,eax ; ECX:EBX = (Cy - Ay)(Dx - Cx)
  133. mov edx,[esi].CD_xC
  134. sub edx,xA ; EDX = (Cx - Ax)
  135. mov eax,[esi].CD_yC
  136. sub eax,[esi].CD_yD ; EAX = (Cy - Dy)
  137. imul edx ; EDX:EAX = (Cx - Ax)(Cy - Dy)
  138. add eax,ebx
  139. adc edx,ecx ; EDX:EAX = qNum
  140. ; Force the denominator to be positive.
  141. mov ebx,qDenom.lo
  142. mov ecx,qDenom.hi ; ECX:EBX = qDenom
  143. or ecx,ecx
  144. jns @F
  145. neg ebx ; Negate qDenom.
  146. adc ecx,0
  147. neg ecx
  148. neg eax ; Negate qNum.
  149. adc edx,0
  150. neg edx
  151. js no_intersection ; (qNum < 0) => (lamda < 0)
  152. @@:
  153. ; See if (lamda > 1).
  154. cmp edx,ecx
  155. ja no_intersection ; (uqNum > uqDenom) => (lamda > 1)
  156. jb no_problem
  157. cmp eax,ebx
  158. jbe no_problem
  159. no_intersection:
  160. mov eax,80000000h
  161. cRet fxYIntersect
  162. no_problem:
  163. ; See if we can do a short form calculation.
  164. ; (99% of all cases get handled here.)
  165. or ecx,ecx
  166. jnz long_form
  167. mul yByA ; EDX:EAX = (By - Ay) uqNum
  168. div ebx ; EAX = (By - Ay) uqNum / uqDenom
  169. ; Get the ceiling of the intersection by incrementing the quotient
  170. ; by 1 if the remainder is bigger than zero.
  171. cmp ecx,edx ; CF = 1 if (edx > 0)
  172. adc eax,0
  173. add eax,yA ; EAX = CEILING((By - Ay) uqNum /
  174. ; uqDenom) + Ay
  175. ; Compare the intersection y with Cy and Dy.
  176. ; Return 0x80000000 if the intersection y is not between Cy and Dy.
  177. cmp_with_cy_dy:
  178. cmp eax,[esi].CD_yC
  179. jg @F
  180. jz done
  181. cmp eax,[esi].CD_yD
  182. jl no_intersection
  183. cRet fxYIntersect
  184. @@:
  185. cmp eax,[esi].CD_yD
  186. jg no_intersection
  187. done:
  188. cRet fxYIntersect
  189. long_form:
  190. ; Do the extended precision calculation.
  191. ; Count the bits needed to normalize the denominator.
  192. mov esi,ecx
  193. mov edi,ebx ; ESI:EDI = uqDenom.
  194. xor ecx,ecx
  195. cmp esi,10000h ; This binary search scheme is a lot
  196. adc ecx,ecx ; faster than BSR.
  197. cmp esi,cmp_table_1[4*ecx]
  198. adc ecx,ecx
  199. cmp esi,cmp_table_2[4*ecx]
  200. adc ecx,ecx
  201. cmp esi,cmp_table_3[4*ecx]
  202. adc ecx,ecx
  203. cmp esi,cmp_table_4[4*ecx]
  204. adc ecx,ecx ; CL = number of bits to shift left!
  205. ; Normalize the denominator and numerator.
  206. shld esi,edi,cl
  207. shl edi,cl
  208. shld edx,eax,cl ; EDX:EAX = uqNum.
  209. shl eax,cl
  210. ; Compute uqNum * (By - Ay), a 95 bit result.
  211. mov ebx,edx
  212. mul yByA
  213. xchg eax,ebx
  214. mov ecx,edx
  215. mul yByA
  216. add eax,ecx
  217. adc edx,0 ; EDX:EAX:EBX = (By - Ay) * uqNum
  218. ; Divide by the 64 bit uqDenom, we're only interested in the integer part!
  219. ; (We would have to worry about overflow in the general case, but we know the
  220. ; answer cannot be 0FFFFFFFFh in this case, since (By - Ay) is bounded below
  221. ; that.)
  222. div esi
  223. mov ecx,edx ; ECX:EBX = remainder, so far.
  224. ; We want to increment the quotient if the remainder is positive. In this
  225. ; case, we want the carry flag set to avoid jumps. In order to do this,
  226. ; instead of calculating the remainder, we calculate the minus remainder.
  227. mov esi,eax ; Hold quotient temporarily.
  228. mul edi
  229. sub eax,ebx
  230. sbb edx,ecx ; EDX:EAX = -remainder
  231. ; We don't have enough bits here, since the remainder is unsigned. We
  232. ; therefore use the carry bit instead of a sign bit. If the carry
  233. ; is set, we have a positive remainder. We'll increment the quotient
  234. ; in this case.
  235. ; (We have bounded (By - Ay) to be less than 2^31, so we also know that
  236. ; the quotient is less than 2^31. This guarantees that we only have to
  237. ; adjust for the quotient once.)
  238. adc esi,0
  239. mov eax,esi
  240. ; Add Ay to the result then compare it with Cy and Dy.
  241. add eax,yA
  242. mov esi,pptlCD
  243. jmp cmp_with_cy_dy
  244. qDenom_maybe_zero:
  245. adc ecx,edx ; ECX:EBX = qDenom
  246. jnz qDenom_not_zero
  247. ; These two lines are parallel since qDenom is zero, we have to find out if
  248. ; they are actually the same line.
  249. ; !!! We may want to change the interface for ulPtOnWhichSide so we call
  250. ; !!! it in a more efficient way. However, this is not a critical path
  251. ; !!! so lets wait until performance tuning time. [wendywu]
  252. mov esi,pptlAB
  253. mov edi,pptlCD
  254. cCall ulPtOnWhichSide,<edi,esi> ; See if C is on SEGAB
  255. cmp eax,POINT_ON_LINE
  256. jnz no_intersection
  257. ; They are indeed the same line, return the last point they meet.
  258. ; MIN(MAX(AB_yA, AB_yB), MAX(CD_yC, CD_yD))
  259. mov eax,[esi].AB_yA
  260. cmp eax,[esi].AB_yB
  261. jg @F
  262. mov eax,[esi].AB_yB ; EAX = MAX((AB_yA, AB_yB)
  263. @@:
  264. mov ebx,[edi].CD_yC
  265. cmp ebx,[edi].CD_yD
  266. jg @F
  267. mov ebx,[edi].CD_yD ; EBX = MAX(CD_yC, CD_yD)
  268. @@:
  269. cmp eax,ebx
  270. jl @F
  271. mov eax,ebx
  272. @@:
  273. cRet fxYIntersect
  274. endProc fxYIntersect
  275. ;------------------------------Public-Routine------------------------------;
  276. ; ULONG ulPtOnWhichSide(pptl,pptlAB) ;
  277. ; POINTL *pptl; // Point in question. ;
  278. ; POINTL *pptlAB; // Line segment. ;
  279. ; ;
  280. ; Compute on which side of the line a given point lies. This is ;
  281. ; determined by the sign of the z component of the cross product of ;
  282. ; the two vectors (pptlB - pptlA) x (pptl - pptlA). i.e. the sign of ;
  283. ; ;
  284. ; (Bx - Ax) * (y - Ay) - (By - Ay) * (x - Ax) ;
  285. ; ;
  286. ; We make sure By >= Ay so the first vector is in the 1st or 2nd quadrant. ;
  287. ; If the above product is ;
  288. ; 1) positive -> the given point is on the left side of the line ;
  289. ; 2) negative -> the given point is on the right side of the line ;
  290. ; 3) zero -> the given point is on the given line ;
  291. ; ;
  292. ; History: ;
  293. ; Wed 25-Sep-1991 16:52:20 -by- Wendy Wu [wendywu] ;
  294. ; Wrote it. ;
  295. ;--------------------------------------------------------------------------;
  296. cProc ulPtOnWhichSide,8,< \
  297. uses ebx esi, \
  298. pptl: ptr POINTL, \
  299. pptlAB: ptr SEGAB >
  300. local yByA: dword
  301. local xBxA: dword
  302. ; Load AB into registers.
  303. mov esi,pptlAB
  304. mov ebx,[esi].AB_yA
  305. mov edx,[esi].AB_yB
  306. mov ecx,[esi].AB_xA
  307. mov eax,[esi].AB_xB
  308. ; Reorder AB so that By >= Ay.
  309. cmp edx,ebx
  310. jg @F
  311. xchg eax,ecx
  312. xchg ebx,edx
  313. @@:
  314. sub eax,ecx ; Compute (Bx - Ax)
  315. mov xBxA,eax
  316. sub edx,ebx ; Compute (By - Ay)
  317. mov yByA,edx
  318. mov esi,pptl
  319. mov eax,[esi].ptl_y ; Compute (y - Ay)
  320. sub eax,ebx
  321. imul xBxA
  322. mov ebx,eax
  323. mov eax,[esi].ptl_x ; Compute (x - Ax)
  324. sub eax,ecx
  325. mov ecx,edx ; ECX:EBX = (Bx - Ax) * (y - Ay)
  326. imul yByA ; EDX:EAX = (By - Ay) * (x - Ax)
  327. sub ebx,eax
  328. sbb ecx,edx ; ECX:EBX = (Bx - Ax) * (y - Ay) -
  329. jns @F ; (By - Ay) * (x - Ax)
  330. mov eax,POINT_ON_RIGHT_SIDE ; on the right if negative
  331. cRet ulPtOnWhichSide
  332. @@:
  333. jnz @F ; on the line if zero
  334. or ebx,ebx
  335. jnz @F
  336. mov eax,POINT_ON_LINE
  337. cRet ulPtOnWhichSide
  338. @@:
  339. mov eax,POINT_ON_LEFT_SIDE ; on the left if positive
  340. cRet ulPtOnWhichSide
  341. endProc ulPtOnWhichSide
  342. ;------------------------------Public-Routine------------------------------;
  343. ; ULONG yGetLtoR/yGetRtoL
  344. ;
  345. ; Compute the ceiling of the y coordinate in integer of a line given the
  346. ; x coordinate in FIX. yB must be bigger than yA.
  347. ; plnfx points to a line which must satisfy ptfxLo.y < ptfxHi.y.
  348. ; Lines that start from left and end at right, i.e. ptfxLo.x <= ptfxHi.x,
  349. ; should use yGetLtoR.
  350. ; Lines that start from right and end at left, i.e. ptfxLo.x > ptfxHi.x,
  351. ; should use yGetRtoL.
  352. ;
  353. ; History:
  354. ; 02-Dec-1992 -by- Wendy Wu [wendywu]
  355. ; Wrote it.
  356. ;--------------------------------------------------------------------------;
  357. cProc yGetLtoR,8,< \
  358. uses ebx, \
  359. plnfx: ptr SEGAB, \
  360. x: dword >
  361. ; Calculate DN = yB - yA
  362. mov ebx,plnfx
  363. mov eax,[ebx].AB_yB
  364. sub eax,[ebx].AB_yA ; EAX = yB - yA
  365. ; Calculate x - xA
  366. mov edx,x
  367. mov ecx,[ebx].AB_xA
  368. sub edx,ecx ; EDX = x - xA
  369. mul edx ; EDX:EAX = (yB - yA) * (x - xA)
  370. ; Calculate DM = xB - xA
  371. sub ecx,[ebx].AB_xB
  372. neg ecx ; ECX = xB - xA
  373. ; FXTOLONGCEILING(DN * (x - xA) / DM + yA)
  374. div ecx
  375. xor ecx,ecx ; increment by 1 if remainder not 0
  376. cmp ecx,edx
  377. adc eax,[ebx].AB_yA
  378. add eax,15
  379. sar eax,4
  380. cRet yGetLtoR
  381. endProc yGetLtoR
  382. cProc yGetRtoL,8,< \
  383. uses ebx, \
  384. plnfx: ptr SEGAB, \
  385. x: dword >
  386. ; Calculate DN = yB - yA
  387. mov ebx,plnfx
  388. mov eax,[ebx].AB_yB
  389. sub eax,[ebx].AB_yA ; EAX = yB - yA
  390. ; Calculate xA - x
  391. mov ecx,[ebx].AB_xA
  392. mov edx,ecx
  393. sub edx,x ; EDX = xA - x
  394. mul edx ; EDX:EAX = (yB - yA) * (xA - x)
  395. ; Calculate DM = xA - xB
  396. sub ecx,[ebx].AB_xB ; ECX = xA - xB
  397. ; FXTOLONGCEILING(DN * (xA - x) / DM + yA)
  398. div ecx
  399. xor ecx,ecx ; increment by 1 if remainder not 0
  400. cmp ecx,edx
  401. adc eax,[ebx].AB_yA
  402. add eax,15
  403. sar eax,4
  404. cRet yGetRtoL
  405. endProc yGetRtoL
  406. end