@@ -4192,6 +4192,18 @@ vector_elementwise(pgVector *vec, PyObject *_null)
41924192 return (PyObject * )proxy ;
41934193}
41944194
4195+ inline double
4196+ lerp (double a , double b , double v )
4197+ {
4198+ return a + (b - a ) * v ;
4199+ }
4200+
4201+ inline double
4202+ invlerp (double a , double b , double v )
4203+ {
4204+ return (v - a ) / (b - a );
4205+ }
4206+
41954207static PyObject *
41964208math_clamp (PyObject * self , PyObject * const * args , Py_ssize_t nargs )
41974209{
@@ -4233,6 +4245,72 @@ math_clamp(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
42334245 return value ;
42344246}
42354247
4248+ #define RAISE_ARG_TYPE_ERROR (var ) \
4249+ if (PyErr_Occurred()) { \
4250+ return RAISE(PyExc_TypeError, \
4251+ "The argument '" var "' must be a real number"); \
4252+ }
4253+
4254+ static PyObject *
4255+ math_invlerp (PyObject * self , PyObject * const * args , Py_ssize_t nargs )
4256+ {
4257+ if (nargs != 3 )
4258+ return RAISE (PyExc_TypeError ,
4259+ "invlerp requires exactly 3 numeric arguments" );
4260+
4261+ double a = PyFloat_AsDouble (args [0 ]);
4262+ RAISE_ARG_TYPE_ERROR ("a" )
4263+ double b = PyFloat_AsDouble (args [1 ]);
4264+ RAISE_ARG_TYPE_ERROR ("b" )
4265+ double t = PyFloat_AsDouble (args [2 ]);
4266+ RAISE_ARG_TYPE_ERROR ("value" )
4267+
4268+ if (PyErr_Occurred ())
4269+ return RAISE (PyExc_ValueError ,
4270+ "invalid argument values passed to invlerp, numbers "
4271+ "might be too small or too big" );
4272+
4273+ if (b - a == 0 )
4274+ return RAISE (PyExc_ValueError ,
4275+ "the result of b - a needs to be different from zero" );
4276+
4277+ return PyFloat_FromDouble (invlerp (a , b , t ));
4278+ }
4279+
4280+ #
4281+
4282+ static PyObject *
4283+ math_remap (PyObject * self , PyObject * const * args , Py_ssize_t nargs )
4284+ {
4285+ if (nargs != 5 )
4286+ return RAISE (PyExc_TypeError ,
4287+ "remap requires exactly 5 numeric arguments" );
4288+
4289+ PyObject * i_min = args [0 ];
4290+ PyObject * i_max = args [1 ];
4291+ PyObject * o_min = args [2 ];
4292+ PyObject * o_max = args [3 ];
4293+ PyObject * value = args [4 ];
4294+
4295+ double v = PyFloat_AsDouble (value );
4296+ RAISE_ARG_TYPE_ERROR ("value" )
4297+ double a = PyFloat_AsDouble (i_min );
4298+ RAISE_ARG_TYPE_ERROR ("i_min" )
4299+ double b = PyFloat_AsDouble (i_max );
4300+ RAISE_ARG_TYPE_ERROR ("i_max" )
4301+ double c = PyFloat_AsDouble (o_min );
4302+ RAISE_ARG_TYPE_ERROR ("o_min" )
4303+ double d = PyFloat_AsDouble (o_max );
4304+ RAISE_ARG_TYPE_ERROR ("o_max" )
4305+
4306+ if (b - a == 0 )
4307+ return RAISE (
4308+ PyExc_ValueError ,
4309+ "the result of i_max - i_min needs to be different from zero" );
4310+
4311+ return PyFloat_FromDouble (lerp (c , d , invlerp (a , b , v )));
4312+ }
4313+
42364314static PyObject *
42374315math_lerp (PyObject * self , PyObject * const * args , Py_ssize_t nargs )
42384316{
@@ -4343,6 +4421,8 @@ math_disable_swizzling(pgVector *self, PyObject *_null)
43434421static PyMethodDef _math_methods [] = {
43444422 {"clamp" , (PyCFunction )math_clamp , METH_FASTCALL , DOC_MATH_CLAMP },
43454423 {"lerp" , (PyCFunction )math_lerp , METH_FASTCALL , DOC_MATH_LERP },
4424+ {"invlerp" , (PyCFunction )math_invlerp , METH_FASTCALL , DOC_MATH_INVLERP },
4425+ {"remap" , (PyCFunction )math_remap , METH_FASTCALL , DOC_MATH_REMAP },
43464426 {"smoothstep" , (PyCFunction )math_smoothstep , METH_FASTCALL ,
43474427 DOC_MATH_SMOOTHSTEP },
43484428 {"enable_swizzling" , (PyCFunction )math_enable_swizzling , METH_NOARGS ,
0 commit comments