|
17 | 17 | #include "mdfour.h" |
18 | 18 |
|
19 | 19 | extern cvar_t prvm_backtraceforwarnings; |
| 20 | +extern cvar_t prvm_gameplayfix_rintisround; |
20 | 21 | #ifdef USEODE |
21 | 22 | extern dllhandle_t ode_dll; |
22 | 23 | #endif |
@@ -1511,10 +1512,48 @@ void VM_rint(prvm_prog_t *prog) |
1511 | 1512 | VM_SAFEPARMCOUNT(1,VM_rint); |
1512 | 1513 |
|
1513 | 1514 | f = PRVM_G_FLOAT(OFS_PARM0); |
1514 | | - if (f > 0) |
1515 | | - PRVM_G_FLOAT(OFS_RETURN) = floor(f + 0.5); |
| 1515 | + |
| 1516 | + if (prvm_gameplayfix_rintisround.integer) |
| 1517 | + { |
| 1518 | + // Guarantee that integers (including negative zeroes) and |
| 1519 | + // infinities remain as is. This also guarantees the following |
| 1520 | + // code doesn't run for zeroes. |
| 1521 | + if (f == floor(f)) |
| 1522 | + PRVM_G_FLOAT(OFS_RETURN) = f; |
| 1523 | + // The copysign ensures that output negative zeroes always have |
| 1524 | + // the same sign as the input. This likely is already the case |
| 1525 | + // anyway, but I honestly can't find anywhere in the C |
| 1526 | + // standards which kind of zero floor(0.8) and ceil(-0.8) are |
| 1527 | + // supposed to be. |
| 1528 | + else if (f > 0) |
| 1529 | + PRVM_G_FLOAT(OFS_RETURN) = copysign(floor(f + 0.5), f); |
| 1530 | + else |
| 1531 | + PRVM_G_FLOAT(OFS_RETURN) = copysign(ceil(f - 0.5), f); |
| 1532 | + // NOTE: Technically rint() when rounding to nearest should |
| 1533 | + // round towards even. Leaving things as is for now, though, as |
| 1534 | + // it matches Quake. |
| 1535 | + } |
1516 | 1536 | else |
1517 | | - PRVM_G_FLOAT(OFS_RETURN) = ceil(f - 0.5); |
| 1537 | + { |
| 1538 | + // Known broken implementation of Quake, except with well |
| 1539 | + // defined overflow behavior. |
| 1540 | + if (f >= 2147483647.5 || f <= -2147483648.5) |
| 1541 | + { |
| 1542 | + // Intel 8087 and SSE2 overflow behavior. |
| 1543 | + PRVM_G_FLOAT(OFS_RETURN) = -2147483648.0; |
| 1544 | + } |
| 1545 | + else |
| 1546 | + { |
| 1547 | + // Original code from Quake. |
| 1548 | + // |
| 1549 | + // Uses cast to int, and thus truncates and never |
| 1550 | + // produces negative zeroes. |
| 1551 | + if (f > 0) |
| 1552 | + PRVM_G_FLOAT(OFS_RETURN) = (int)(f + 0.5); |
| 1553 | + else |
| 1554 | + PRVM_G_FLOAT(OFS_RETURN) = (int)(f - 0.5); |
| 1555 | + } |
| 1556 | + } |
1518 | 1557 | } |
1519 | 1558 |
|
1520 | 1559 | /* |
|
0 commit comments