.386P .MODEL FLAT, C .STACK 1000h ; EXTRN TREE_DistancePixelCornersToPoint : NEAR ;.DATA ; LEFT_LONGITUDE REAL4 -180.0 ; RIGHT_LONGITUDE REAL4 180.0 ; ZERO REAL4 0.0 .CODE ; Array length must be 4 ; Must be room in the stack for 2 values ; [esp + 0] holds first value ; [esp + 12] holds last value ; result distance is put in st(0) (with stack push down) ; result index is put into ecx TREE_ASM_FindShortestValueInArray_FLOAT PROC NEAR ; Load the first values into the results push eax mov ecx, 0 fld DWORD PTR [esp + 8] ; Load the second value fld DWORD PTR [esp + 12] fcom st(1) fnstsw ax and eax, 100h jne TREE_ASM_FindShortestValueInArray_FLOAT_2ND_IS_SMALLER ; The second point is larger, so skip it fstp st(0) jmp TREE_ASM_FindShortestValueInArray_FLOAT_3RD TREE_ASM_FindShortestValueInArray_FLOAT_2ND_IS_SMALLER: ; The second point is smaller, so load it into the results fxch st(1) mov ecx, 4 fstp st(0) TREE_ASM_FindShortestValueInArray_FLOAT_3RD: ; Load the third value fld DWORD PTR [esp + 16] fcom st(1) fnstsw ax and eax, 100h jne TREE_ASM_FindShortestValueInArray_FLOAT_3RD_IS_SMALLER ; The third point is larger, so skip it fstp st(0) jmp TREE_ASM_FindShortestValueInArray_FLOAT_4TH TREE_ASM_FindShortestValueInArray_FLOAT_3RD_IS_SMALLER: ; The third point is smaller, so load it into the results fxch st(1) mov ecx, 8 fstp st(0) TREE_ASM_FindShortestValueInArray_FLOAT_4TH: ; Load the fourth value fld DWORD PTR [esp + 20] fcom st(1) fnstsw ax and eax, 100h jne TREE_ASM_FindShortestValueInArray_FLOAT_4TH_IS_SMALLER ; The fourth point is larger, so pop it off the stack fstp st(0) pop eax ret TREE_ASM_FindShortestValueInArray_FLOAT_4TH_IS_SMALLER: ; The fourth point is smaller, so load it into the results fxch st(1) mov ecx, 12 fstp st(0) pop eax ret TREE_ASM_FindShortestValueInArray_FLOAT ENDP ; st(0),st(1) = point ; st(2) = 180.0 ; ecx = corners float array reference ; result is stored in st(0) (with the stack pushed down) ; eax is saved first TREE_ASM_DistanceCornersToPoint PROC NEAR push eax ; Load the left longitude fld DWORD PTR [ecx] ; See if the point is less than the left longitude fcom st(1) fnstsw ax and eax, 100h jne TREE_ASM_DistanceCornersToPoint_X_ABOVE_LEFT ; The x dimension is less than the left longitude, so subtract the point from the left longitude ; Get the wrap difference fld st(1) ; load the x dimension fadd st(0), st(4) ; add 180.0 to x fld st(4) ; load 180.0 into st(0) fsub DWORD PTR [ecx + 4] ; subtract the right longitude faddp st(1), st(0) ; Get the no-wrap difference fxch st(1) fsub st(0), st(2) ; Compare the wrap and no-wrap differences and keep the smaller one (put in st(0)) fcom st(1) fnstsw ax test ah, 5h jp TREE_ASM_DistanceCornersToPoint_X_NOWRAP_GREATER ; The no-wrap is smaller, so get rid of the wrap (wrap is in st(1)) fxch st(1) fstp st(0) fmul st(0), st(0) jmp TREE_ASM_DistanceCornersToPoint_Y TREE_ASM_DistanceCornersToPoint_X_NOWRAP_GREATER: ; The wrap is smaller, so get rid of the no-wrap (no-wrap is in st(0)) fstp st(0) fmul st(0), st(0) jmp TREE_ASM_DistanceCornersToPoint_Y TREE_ASM_DistanceCornersToPoint_X_ABOVE_LEFT: ; The x dimension is greater than the left longitude, so see if it is also greater than the right longitude fld DWORD PTR [ecx + 4] ; right longitude fcom st(2) fnstsw ax test ah, 41h jp TREE_ASM_DistanceCornersToPoint_X_INSIDE ; The x dimension is greater than the right longitude, so subtract the right longitude from the point ; Get the no-wrap difference fld st(2) ; load x fxch st(1) ; swap x and right longitude fsubp st(1), st(0) ; subtract right longitude from x ; Get the wrap difference fxch st(1) ; swap no-wrap with left longitude fadd st(0), st(4) ; add 180 to left longitude fld st(4) ; load 180 fsub st(0), st(3) ; subtract x from 180 faddp st(1), st(0) ; add to get the wrap difference ; Compare the wrap and no-wrap differences and keep the smaller one (put in st(0)) fcom st(1) fnstsw ax and eax, 4100h jne TREE_ASM_DistanceCornersToPoint_X_WRAP_GREATER ; The no-wrap is smaller, so get rid of the wrap (wrap is in st(0)) fstp st(0) fmul st(0), st(0) jmp TREE_ASM_DistanceCornersToPoint_Y TREE_ASM_DistanceCornersToPoint_X_WRAP_GREATER: ; The wrap is smaller, so get rid of the no-wrap (no-wrap is in st(1)) fxch st(1) fstp st(0) fmul st(0), st(0) jmp TREE_ASM_DistanceCornersToPoint_Y TREE_ASM_DistanceCornersToPoint_X_INSIDE: fstp st(0) fstp st(0) fldz ; load zero (since point is in between left and right longitudes ; By here, the result from the x dimension is in st(0) (whether the point was inside the area or not) TREE_ASM_DistanceCornersToPoint_Y: ; Load the bottom latitude fld DWORD PTR [ecx + 8] ; See if the point is less than the bottom latitude fcom st(3) fnstsw ax and eax, 100h jne TREE_ASM_DistanceCornersToPoint_Y_ABOVE_BOTTOM ; The point is less than the bottom latitude, so subtract the point from the bottom latitude fsub st(0), st(3) fmul st(0), st(0) ; Add to the results from the x dimension, and store in [eax] faddp st(1), st(0) pop eax ret TREE_ASM_DistanceCornersToPoint_Y_ABOVE_BOTTOM: ; Get rid of the bottom latitude and load the top latitude fstp st(0) fld DWORD PTR [ecx + 12] ; See if the point is greater than the top latitude fcom st(3) fnstsw ax test ah, 5h jp TREE_ASM_DistanceCornersToPoint_Y_INSIDE ; The point is greater than the top latitude, so subtract the top latitude from the point fld st(3) fxch st(1) fsubp st(1), st(0) fmul st(0), st(0) ; Add to the results from the x dimension, and store in [eax] faddp st(1), st(0) pop eax ret TREE_ASM_DistanceCornersToPoint_Y_INSIDE: fstp st(0) pop eax ret TREE_ASM_DistanceCornersToPoint ENDP ;*********************************************************************************************** ;*********************************************************************************************** ;*********************************************************************************************** ; st(0),st(1) = point ; st(2) = 180.0 ; edi = point reference ; result is stored in st(0) (with the stack pushed down) TREE_ASM_DistancePointToPoint PROC NEAR ; Load the x coordinate fld DWORD PTR [edi] ; See which x value is greater fcom st(1) fnstsw ax and eax, 100h jne TREE_ASM_DistancePointToPoint_NEW_X_LESSER ; The point on the coprocessor stack is less than or equal to the point in memory (in x dimension) ; Get the wrap and no-wrap differences fld st(1) ; load x1 fadd st(0), st(4) ; add 180 to x1 fld st(4) ; load 180 fsub st(0), st(2) ; subtract x2 from 180 fxch st(2) ; swap result with x2 fsub st(0), st(3) ; get the no-wrap difference fxch st(2) faddp st(1), st(0) ; get the wrap difference ; Take the lesser of the wrap and no-wrap differences fcom st(1) fnstsw ax and eax, 100h jne TREE_ASM_DistancePointToPoint_WRAP_IS_SMALLER1 ; The no-wrap value is smaller; get rid of the wrap value fstp st(0) fmul st(0), st(0) jmp TREE_ASM_DistancePointToPoint_Y TREE_ASM_DistancePointToPoint_WRAP_IS_SMALLER1: ; The wrap value is smaller; get rid of the no-wrap value fxch st(1) fstp st(0) fmul st(0), st(0) jmp TREE_ASM_DistancePointToPoint_Y TREE_ASM_DistancePointToPoint_NEW_X_LESSER: ; The point on the stack is greater than the point in memory (in x dimension) ; Get the no-wrap difference fld st(1) ; load x1 fsub st(0), st(1) ; subtract x2 from x1 ; Get the wrap difference fxch st(1) ; swap the no-wrap difference and x2 fadd st(0), st(4) ; add 180 to x2 fld st(4) ; load 180 fsub st(0), st(3) ; subtract 180 from x1 faddp st(1), st(0) ; add the two values to get the wrap difference ; Take the lesser of the wrap and no-wrap differences fcom st(1) fnstsw ax and eax, 100h jne TREE_ASM_DistancePointToPoint_WRAP_IS_SMALLER2 ; The no-wrap value is smaller, get rid of the wrap value fstp st(0) fmul st(0), st(0) jmp TREE_ASM_DistancePointToPoint_Y TREE_ASM_DistancePointToPoint_WRAP_IS_SMALLER2: ; The wrap value is smaller; get rid of the no-wrap value fxch st(1) fstp st(0) fmul st(0), st(0) TREE_ASM_DistancePointToPoint_Y: ; Load the y coorindate fld DWORD PTR [edi + 4] ; Subtract from y1 from y2 and square the result fsub st(0), st(3) fmul st(0), st(0) ; Add to the x difference to get the result faddp st(1), st(0) ret TREE_ASM_DistancePointToPoint ENDP ; ... ; [ebx + ? + 4] = 2nd value ; [ebx + ?] = 1st value ; ... ; [ebx + 8] = 2nd distance ; [ebx + 4] = 1st distance ; [ebx + 0] = (# of averaging points - 1)(x4) ; ebx = stack reference ; edx = node pointer ; st(0) holds x value of point ; st(1) holds y value of point ; st(2) holds 180.0 ; st(3) holds largest allowable distance TREE_ASM_Point2fFindClosestPoints PROC NEAR push ecx push edi mov ecx, DWORD PTR [edx] ; number of points jecxz TREE_ASM_Point2fFindClosestPoints_PARENT_NODE ; ; This is a leaf node, so we must compare all points to the target point ; ; edi points to the first point mov edi, DWORD PTR [edx + 4] ; Compute the address of the last point mov eax, 12 mul ecx ; esi points to just beyond last point (loop will continue as long as edi < esi) mov esi, eax add esi, edi ; Set ecx to the # of average points mov ecx, DWORD PTR [ebx] ; (# of points * 4) TREE_ASM_Point2fFindClosestPoints_LEAF_LOOP_1_START: call TREE_ASM_DistancePointToPoint ; Skip this point if the distance is larger than the current largest distance fcom st(4) fnstsw ax test ah, 5h jp TREE_ASM_Point2fFindClosestPoints_LEAF_LOOP_1_END ; ; The point is smaller than the largest distance, so loop through until we have found a smaller distance (start at the end) ; mov ebp, ebx add ebp, ecx TREE_ASM_Point2fFindClosestPoints_LEAF_LOOP_2_START: ; Compare the point's distance with the distance in the array fcom DWORD PTR [ebp] fnstsw ax test ah, 5h jp TREE_ASM_Point2fFindClosestPoints_LEAF_LOOP_2_END ; Shift distance array mov eax, DWORD PTR [ebp] mov DWORD PTR [ebp + 4], eax ; Shift value array mov eax, DWORD PTR [ebp + ecx + 4] mov DWORD PTR [ebp + ecx + 8], eax sub ebp, 4 cmp ebp, ebx ja TREE_ASM_Point2fFindClosestPoints_LEAF_LOOP_2_START TREE_ASM_Point2fFindClosestPoints_LEAF_LOOP_2_END: mov eax, DWORD PTR [edi + 8] ; get point data fstp DWORD PTR [ebp + 4] ; store point distance mov DWORD PTR [ebp + ecx + 8], eax ; store point data ; Replace the current largest distance with the one from the end of the distance array fld DWORD PTR [ebx + ecx] fxch st(4) TREE_ASM_Point2fFindClosestPoints_LEAF_LOOP_1_END: ; Get rid of the current points distance fstp st(0) ; Add to the point reference add edi, 12 cmp edi, esi jb TREE_ASM_Point2fFindClosestPoints_LEAF_LOOP_1_START pop edi pop ecx ret; TREE_ASM_Point2fFindClosestPoints_PARENT_NODE: ; ; This is a parent node, so we must compare all child node distances to the target point ; sub esp, 16 mov eax, esp ; Set edi to the start of the node pointer array, esi to the end mov edi, edx add edi, 8 mov esi, edi add esi, 16 push edi TREE_ASM_Point2fFindClosestPoints_PARENT_LOOP_1_START: ; See if the child is NULL mov ecx, DWORD PTR [edi]; jecxz TREE_ASM_Point2fFindClosestPoints_PARENT_LOOP_1_NULL ; Set ecx to the child's corners; DistanceCornersToPoint will put the result in st(0) add ecx, 24 call TREE_ASM_DistanceCornersToPoint jmp TREE_ASM_Point2fFindClosestPoints_PARENT_LOOP_1_MID TREE_ASM_Point2fFindClosestPoints_PARENT_LOOP_1_NULL: ; The child is NULL, so load the maximum distance (so the child won't get calculated) fld st(3) TREE_ASM_Point2fFindClosestPoints_PARENT_LOOP_1_MID: ; Store the result in the distance array fstp DWORD PTR [eax] add eax, 4 add edi, 4 cmp edi, esi jb TREE_ASM_Point2fFindClosestPoints_PARENT_LOOP_1_START ; Again, set edi to the start of the child node pointer array pop edi TREE_ASM_Point2fFindClosestPoints_PARENT_LOOP_2_START: ; FindShortestValueInArray_FLOAT will find the closest node call TREE_ASM_FindShortestValueInArray_FLOAT ; See if the closest child node is farther than the current largest distance (in which case we are done with this node) fcomp st(4) fnstsw ax test ah, 5h jp TREE_ASM_Point2fFindClosestPoints_PARENT_END ; Set edx to the child node mov edx, DWORD PTR [edi + ecx] call TREE_ASM_Point2fFindClosestPoints ; Set this child's distance to the largest distance, so the same node won't get calculated again fld st(3) fstp DWORD PTR [esp + ecx] jmp TREE_ASM_Point2fFindClosestPoints_PARENT_LOOP_2_START TREE_ASM_Point2fFindClosestPoints_PARENT_END: add esp, 16 pop edi pop ecx ret TREE_ASM_Point2fFindClosestPoints ENDP END