News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

FPU causing crashes

Started by Brett Kuntz, April 03, 2005, 09:14:32 AM

Previous topic - Next topic

Brett Kuntz

Ya so since it's my first stab at FPU it comes as no surprise it doesn't work.


IsCircleColl proc x1:REAL4, y1:REAL4, x2:REAL4, y2:REAL4, r:REAL4

    LOCAL dist:REAL4

    fld x1           ;ST0 = x1
    fsub x2          ;ST0 = x1-x2
    fabs             ;ST0 = abs(x1-x2)
    fld y1           ;ST0 = y1
                     ;ST1 = abs(x1-x2)
    fsub y2          ;ST0 = y1-y2
    fabs             ;ST0 = abs(y1-y2)
    fmul st, st      ;ST0 = abs(x1-x2)^2
    fld st(1)        ;ST0 = abs(y1-y2)
                     ;ST1 = abs(x1-x2)^2
                     ;ST2 = abs(y1-y2)
    fmulp st(2), st  ;ST0 = abs(x1-x2)^2
                     ;ST1 = abs(y1-y2)^2
    faddp st(1), st  ;ST0 = abs(x1-x2)^2 + abs(y1-y2)^2
    fsqrt            ;ST0 = sqrt(abs(x1-x2)^2 + abs(y1-y2)^2)
    fcom r           ;if (r < ST0) return 0
                     ;else return dist
    jl @F
        fstp dist    ;ST0 popped into dist - stack balanced
        mov eax, dist
        ret
    @@:
    mov eax, 0
    ret

IsCircleColl endp


It first checks the distance between two circles (of varying size), then checks that against the sum of both circle's radii to see if they're touching/colliding or not. Any idea whats wrong?

Tedd

You are calling FINIT somewhere, aren't you? :wink
No snowflake in an avalanche feels responsible.

Brett Kuntz

Alright adding fninit seems to have gotten rid of the random crashing. Good 'ol initializing saves the day. Now onto the good stuff, the anglo in asm is giving strange results to my ball collisions. Here's the pseuseudoe code for it:


float IsCircleColl (float x1, float x2, float y1, float y2, float rad)
{
    float X = abs(x1 - x2);
    float Y = abs(y1 - y2);
    X = X * X;
    Y = Y * Y;
    float dist = sqrt(X + Y);
    if (dist <= r) return dist;
    return 0;
}


Any ideas where I went wrong?

doomsday

Are all balls the same size?
Do the (x:y) coords refer to the center of the ball?
Is "r" just a typo in your post where you meant to write "rad" ?

If all of the above are true, then you'll be wanting to do "if (dist <= 2 * rad) ...."  (the distance between the center of ball1 and the center of ball2 is less than twice the radius of the balls) right?

BTW it's probaby faster to return a BOOL for (collision/no collision) unless the return value is used by the calling code.

regards,
-Brent

Brett Kuntz

Quote from: doomsday on April 03, 2005, 06:05:59 PM
Are all balls the same size?
Do the (x:y) coords refer to the center of the ball?
Is "r" just a typo in your post where you meant to write "rad" ?

If all of the above are true, then you'll be wanting to do "if (dist <= 2 * rad) ...."  (the distance between the center of ball1 and the center of ball2 is less than twice the radius of the balls) right?

BTW it's probaby faster to return a BOOL for (collision/no collision) unless the return value is used by the calling code.

regards,
-Brent


For testing the balls are the same radius, XY in this case refers to the top-left corner, r is a typo, and rad is (rad1 + rad2) before the function is called, so no math has to be done on that inside this function. I need to return the distance between them so I can calculate the angle between the balls if there is a collision and bounce them away properly.

Brett Kuntz

Updated it to remove the abs's, don't need them since a negative squared equals a positive anyways. It's still miscalculating collisions though, and runs 1-2 fps slower then the c++ version =[


    ; r = radius of the two circles added together
    LOCAL dist:REAL4

    fninit
    fld x1           ;ST0 = x1
    fsub x2          ;ST0 = x1-x2
    fld y1           ;ST0 = y1
                     ;ST1 = x1-x2
    fsub y2          ;ST0 = y1-y2
                     ;ST1 = x1-x2
    fmul st, st      ;ST0 = (y1-y2)^2
                     ;ST1 = x1-x2
    fld st(1)        ;ST0 = x1-x2
                     ;ST1 = (y1-y2)^2
                     ;ST2 = x1-x2
    fmulp st(2), st  ;ST0 = (x1-x2)^2
                     ;ST1 = (y1-y2)^2
    faddp st(1), st  ;ST0 = (x1-x2)^2 + (y1-y2)^2
    fsqrt            ;ST0 = sqrt((x1-x2)^2 + (y1-y2)^2)
    fcom r           ;if (r < ST0) return 0
                     ;else return dist
    jl down
        fstp dist
        mov eax, dist
        ret
    down:
    mov eax, 0
    ret

raymond

The first detail to clear up is if the "r" (sum of the 2 radii) is in the REAL4 format or not. If not, you could never get a proper comparison.

The second detail is a wrong assumption on your part. The "fcom" instruction DOES NOT CHANGE CPU FLAGS. It only changes some of the bits in the Status Word. Look at the following for a description of that instruction:

http://www.ray.masmcode.com/tutorial/fpuchap7.htm#fcom

If you want the CPU flags modified based on the result of a comparison on the FPU, you will have to use the "fcomi" (or fcomip) instruction. Look at the following to understand the requirements.

http://www.ray.masmcode.com/tutorial/fpuchap7.htm#fcomi

Raymond
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

Brett Kuntz

Thanks a lot, that would be the reason I'm getting weird results.