software renderer: handle some float type related issues with slope drawers
there were a bunch of cases where inf and nan float results were casted and used with integer things, which is undefined in c yes i did use ceepeepee for that crap, cause this wouldve been really annoying without templating if someone really wants that crap to use outside ceepeepee, feel free to make a bunch of wrappers cause im too lazy for that stuff
This commit is contained in:
parent
d7ed03fab9
commit
88c0fc51d8
3 changed files with 97 additions and 33 deletions
|
|
@ -147,6 +147,73 @@ public:
|
|||
template <class T>
|
||||
NotNull(T) -> NotNull<T>;
|
||||
|
||||
// does a super safe cast from floating point to interger types
|
||||
// this prob could be better since i suck at ceepeepee
|
||||
// but atleast we can just template shit to our desired types
|
||||
template <typename FloatT, typename IntT>
|
||||
static inline IntT floattoint(FloatT val)
|
||||
{
|
||||
// :chaosleep:
|
||||
static_assert(std::is_floating_point_v<FloatT>, "Input must be a floating-point type");
|
||||
static_assert(std::is_integral_v<IntT>, "Output must be a integer type");
|
||||
|
||||
if (std::fpclassify(val) == FP_NAN)
|
||||
return 0; // if stuffs not a number we sure screwed up lmao
|
||||
|
||||
// treat inifinity as "int min/max"
|
||||
if (std::fpclassify(val) == FP_INFINITE)
|
||||
{
|
||||
// yes infinity can be signed kek
|
||||
if (std::signbit(val))
|
||||
return std::numeric_limits<IntT>::min(); // negative infinity, so return min
|
||||
else
|
||||
return std::numeric_limits<IntT>::max();
|
||||
}
|
||||
|
||||
// make sure we fit into our targettype uwu
|
||||
if (val > static_cast<FloatT>(std::numeric_limits<IntT>::max()))
|
||||
return std::numeric_limits<IntT>::max();
|
||||
else if (val < static_cast<FloatT>(std::numeric_limits<IntT>::min()))
|
||||
return std::numeric_limits<IntT>::min();
|
||||
|
||||
return static_cast<IntT>(val);
|
||||
}
|
||||
|
||||
// safe float to fixed
|
||||
// which handles nan and inf
|
||||
// pretty much the same stuff as the above, but uh, idk how id use the above with this
|
||||
template <typename FloatT> // can use both float and doubles yay
|
||||
static inline int32_t floattofixed(FloatT val)
|
||||
{
|
||||
// :chaosleep:
|
||||
static_assert(std::is_floating_point_v<FloatT>, "Input must be a floating-point type");
|
||||
|
||||
// fixed_t is just an int32_t, i dont wanna include doomtype here if it can be avoided
|
||||
|
||||
if (std::fpclassify(val) == FP_NAN)
|
||||
return 0; // if stuffs not a number we sure screwed up lmao
|
||||
|
||||
// treat inifinity as "int min/max"
|
||||
if (std::fpclassify(val) == FP_INFINITE)
|
||||
{
|
||||
// yes infinity can be signed kek
|
||||
if (std::signbit(val))
|
||||
return std::numeric_limits<int32_t>::min(); // negative infinity, so return min
|
||||
else
|
||||
return std::numeric_limits<int32_t>::max();
|
||||
}
|
||||
|
||||
const FloatT ret = (val * 65536.0);
|
||||
|
||||
// make sure we fit into our targettype uwu
|
||||
if (ret > static_cast<FloatT>(std::numeric_limits<int32_t>::max()))
|
||||
return std::numeric_limits<int32_t>::max();
|
||||
else if (ret < static_cast<FloatT>(std::numeric_limits<int32_t>::min()))
|
||||
return std::numeric_limits<int32_t>::min();
|
||||
|
||||
return static_cast<int32_t>(ret);
|
||||
}
|
||||
|
||||
} // namespace srb2
|
||||
|
||||
#endif // __SRB2_CXXUTIL_HPP__
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
using namespace libdivide;
|
||||
|
||||
#include "cxxutil.hpp"
|
||||
|
||||
// ==========================================================================
|
||||
// SPANS
|
||||
// ==========================================================================
|
||||
|
|
@ -358,10 +360,10 @@ static void R_DrawTiltedSpanTemplate(drawspandata_t* ds)
|
|||
endz = 1.f/iz;
|
||||
endu = uz*endz;
|
||||
endv = vz*endz;
|
||||
stepu = (INT64)((endu - startu) * INVSPAN);
|
||||
stepv = (INT64)((endv - startv) * INVSPAN);
|
||||
u = (INT64)(startu);
|
||||
v = (INT64)(startv);
|
||||
stepu = srb2::floattoint<float, INT64>((endu - startu) * INVSPAN);
|
||||
stepv = srb2::floattoint<float, INT64>((endv - startv) * INVSPAN);
|
||||
u = srb2::floattoint<float, INT64>(startu);
|
||||
v = srb2::floattoint<float, INT64>(startv);
|
||||
|
||||
x1 = ds->x1;
|
||||
|
||||
|
|
@ -393,8 +395,8 @@ static void R_DrawTiltedSpanTemplate(drawspandata_t* ds)
|
|||
{
|
||||
if (width == 1)
|
||||
{
|
||||
u = (INT64)(startu);
|
||||
v = (INT64)(startv);
|
||||
u = srb2::floattoint<float, INT64>(startu);
|
||||
v = srb2::floattoint<float, INT64>(startv);
|
||||
bit = ((v >> nflatyshift) & nflatmask) | (u >> nflatxshift);
|
||||
if constexpr (!(Type & DS_SPRITE))
|
||||
{
|
||||
|
|
@ -418,10 +420,10 @@ static void R_DrawTiltedSpanTemplate(drawspandata_t* ds)
|
|||
endu = uz*endz;
|
||||
endv = vz*endz;
|
||||
left = 1.f/left;
|
||||
stepu = (INT64)((endu - startu) * left);
|
||||
stepv = (INT64)((endv - startv) * left);
|
||||
u = (INT64)(startu);
|
||||
v = (INT64)(startv);
|
||||
stepu = srb2::floattoint<float, INT64>((endu - startu) * left);
|
||||
stepv = srb2::floattoint<float, INT64>((endv - startv) * left);
|
||||
u = srb2::floattoint<float, INT64>(startu);
|
||||
v = srb2::floattoint<float, INT64>(startv);
|
||||
|
||||
for (; width != 0; width--)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@
|
|||
|
||||
extern "C" consvar_t cv_debugfinishline;
|
||||
|
||||
#include "cxxutil.hpp"
|
||||
|
||||
#define HEIGHTBITS 12
|
||||
#define HEIGHTUNIT (1<<HEIGHTBITS)
|
||||
|
||||
|
|
@ -1938,26 +1940,23 @@ void R_StoreWallRange(INT32 start, INT32 stop)
|
|||
// left
|
||||
temp = xtoviewangle[viewssnum][start]+viewangle;
|
||||
|
||||
#define FIXED_TO_DOUBLE(x) (((double)(x)) / ((double)FRACUNIT))
|
||||
#define DOUBLE_TO_FIXED(x) (fixed_t)((x) * ((double)FRACUNIT))
|
||||
|
||||
{
|
||||
// Both lines can be written in slope-intercept form, so figure out line intersection
|
||||
double a1, b1, c1, a2, b2, c2, det; // 1 is the seg, 2 is the view angle vector...
|
||||
///TODO: convert to fixed point
|
||||
|
||||
a1 = FIXED_TO_DOUBLE(curline->v2->y-curline->v1->y);
|
||||
b1 = FIXED_TO_DOUBLE(curline->v1->x-curline->v2->x);
|
||||
c1 = a1*FIXED_TO_DOUBLE(curline->v1->x) + b1*FIXED_TO_DOUBLE(curline->v1->y);
|
||||
a1 = FixedToDouble(curline->v2->y-curline->v1->y);
|
||||
b1 = FixedToDouble(curline->v1->x-curline->v2->x);
|
||||
c1 = a1*FixedToDouble(curline->v1->x) + b1*FixedToDouble(curline->v1->y);
|
||||
|
||||
a2 = -FIXED_TO_DOUBLE(FINESINE(temp>>ANGLETOFINESHIFT));
|
||||
b2 = FIXED_TO_DOUBLE(FINECOSINE(temp>>ANGLETOFINESHIFT));
|
||||
c2 = a2*FIXED_TO_DOUBLE(viewx) + b2*FIXED_TO_DOUBLE(viewy);
|
||||
a2 = -FixedToDouble(FINESINE(temp>>ANGLETOFINESHIFT));
|
||||
b2 = FixedToDouble(FINECOSINE(temp>>ANGLETOFINESHIFT));
|
||||
c2 = a2*FixedToDouble(viewx) + b2*FixedToDouble(viewy);
|
||||
|
||||
det = a1*b2 - a2*b1;
|
||||
|
||||
ds_p->leftpos.x = segleft.x = DOUBLE_TO_FIXED((b2*c1 - b1*c2)/det);
|
||||
ds_p->leftpos.y = segleft.y = DOUBLE_TO_FIXED((a1*c2 - a2*c1)/det);
|
||||
ds_p->leftpos.x = segleft.x = srb2::floattofixed<double>((b2*c1 - b1*c2)/det);
|
||||
ds_p->leftpos.y = segleft.y = srb2::floattofixed<double>((a1*c2 - a2*c1)/det);
|
||||
}
|
||||
|
||||
// right
|
||||
|
|
@ -1968,23 +1967,19 @@ void R_StoreWallRange(INT32 start, INT32 stop)
|
|||
double a1, b1, c1, a2, b2, c2, det; // 1 is the seg, 2 is the view angle vector...
|
||||
///TODO: convert to fixed point
|
||||
|
||||
a1 = FIXED_TO_DOUBLE(curline->v2->y-curline->v1->y);
|
||||
b1 = FIXED_TO_DOUBLE(curline->v1->x-curline->v2->x);
|
||||
c1 = a1*FIXED_TO_DOUBLE(curline->v1->x) + b1*FIXED_TO_DOUBLE(curline->v1->y);
|
||||
a1 = FixedToDouble(curline->v2->y-curline->v1->y);
|
||||
b1 = FixedToDouble(curline->v1->x-curline->v2->x);
|
||||
c1 = a1*FixedToDouble(curline->v1->x) + b1*FixedToDouble(curline->v1->y);
|
||||
|
||||
a2 = -FIXED_TO_DOUBLE(FINESINE(temp>>ANGLETOFINESHIFT));
|
||||
b2 = FIXED_TO_DOUBLE(FINECOSINE(temp>>ANGLETOFINESHIFT));
|
||||
c2 = a2*FIXED_TO_DOUBLE(viewx) + b2*FIXED_TO_DOUBLE(viewy);
|
||||
a2 = -FixedToDouble(FINESINE(temp>>ANGLETOFINESHIFT));
|
||||
b2 = FixedToDouble(FINECOSINE(temp>>ANGLETOFINESHIFT));
|
||||
c2 = a2*FixedToDouble(viewx) + b2*FixedToDouble(viewy);
|
||||
|
||||
det = a1*b2 - a2*b1;
|
||||
|
||||
ds_p->rightpos.x = segright.x = DOUBLE_TO_FIXED((b2*c1 - b1*c2)/det);
|
||||
ds_p->rightpos.y = segright.y = DOUBLE_TO_FIXED((a1*c2 - a2*c1)/det);
|
||||
ds_p->rightpos.x = segright.x = srb2::floattofixed<double>((b2*c1 - b1*c2)/det);
|
||||
ds_p->rightpos.y = segright.y = srb2::floattofixed<double>((a1*c2 - a2*c1)/det);
|
||||
}
|
||||
|
||||
#undef FIXED_TO_DOUBLE
|
||||
#undef DOUBLE_TO_FIXED
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue