diff --git a/src/api/l_math_vectors.c b/src/api/l_math_vectors.c index 4bc2edd7..f47dc8e9 100644 --- a/src/api/l_math_vectors.c +++ b/src/api/l_math_vectors.c @@ -253,7 +253,7 @@ static int l_lovrVec2Distance(lua_State* L) { uvec[1] = luax_checkfloat(L, 3); u = uvec; } else { - u = luax_checkvector(L, 2, V_VEC2, NULL); + u = luax_checkvector(L, 2, V_VEC2, "vec2 or number"); } float dx = v[0] - u[0]; float dy = v[1] - u[1]; @@ -270,7 +270,7 @@ static int l_lovrVec2Dot(lua_State* L) { uvec[1] = luax_checkfloat(L, 3); u = uvec; } else { - u = luax_checkvector(L, 2, V_VEC2, NULL); + u = luax_checkvector(L, 2, V_VEC2, "vec2 or number"); } lua_pushnumber(L, v[0] * u[0] + v[1] * u[1]); return 1; @@ -287,7 +287,7 @@ static int l_lovrVec2Lerp(lua_State* L) { u = uvec; t = luax_checkfloat(L, 4); } else { - u = luax_checkvector(L, 2, V_VEC2, NULL); + u = luax_checkvector(L, 2, V_VEC2, "vec2 or number"); t = luax_checkfloat(L, 3); } v[0] = v[0] + (u[0] - v[0]) * t; @@ -296,6 +296,29 @@ static int l_lovrVec2Lerp(lua_State* L) { return 1; } +static int l_lovrVec2Angle(lua_State* L) { + float* v = luax_checkvector(L, 1, V_VEC2, NULL); + float* u; + float uvec[2]; + float dot, length_v, length_u; + if (lua_type(L, 2) == LUA_TNUMBER) { + uvec[0] = lua_tonumber(L, 2); + uvec[1] = luax_checkfloat(L, 3); + u = uvec; + } else { + u = luax_checkvector(L, 2, V_VEC2, "vec2 or number"); + } + length_v = sqrtf(v[0] * v[0] + v[1] * v[1]); + length_u = sqrtf(u[0] * u[0] + u[1] * u[1]); + if ((length_v == 0.f) || (length_u == 0.f)) { + lua_pushnumber(L, (float) M_PI / 2); + } else { + dot = v[0] * u[0] + v[1] * u[1]; + lua_pushnumber(L, acosf(dot / (length_v * length_u))); + } + return 1; +} + static int l_lovrVec2__add(lua_State* L) { float* out = luax_newtempvector(L, V_VEC2); if (lua_type(L, 1) == LUA_TNUMBER) { @@ -497,6 +520,7 @@ const luaL_Reg lovrVec2[] = { { "distance", l_lovrVec2Distance }, { "dot", l_lovrVec2Dot }, { "lerp", l_lovrVec2Lerp }, + { "angle", l_lovrVec2Angle }, { "__add", l_lovrVec2__add }, { "__sub", l_lovrVec2__sub }, { "__mul", l_lovrVec2__mul }, @@ -687,6 +711,22 @@ static int l_lovrVec3Lerp(lua_State* L) { return 1; } +static int l_lovrVec3Angle(lua_State* L) { + vec3 v = luax_checkvector(L, 1, V_VEC3, NULL); + vec3 u; + float uvec[4]; + if (lua_type(L, 2) == LUA_TNUMBER) { + uvec[0] = lua_tonumber(L, 2); + uvec[1] = luax_checkfloat(L, 3); + uvec[2] = luax_checkfloat(L, 4); + u = uvec; + } else { + u = luax_checkvector(L, 2, V_VEC3, "vec3 or number"); + } + lua_pushnumber(L, vec3_angle(v, u)); + return 1; +} + static int l_lovrVec3__add(lua_State* L) { vec3 out = luax_newtempvector(L, V_VEC3); if (lua_type(L, 1) == LUA_TNUMBER) { @@ -891,6 +931,7 @@ const luaL_Reg lovrVec3[] = { { "dot", l_lovrVec3Dot }, { "cross", l_lovrVec3Cross }, { "lerp", l_lovrVec3Lerp }, + { "angle", l_lovrVec3Angle }, { "__add", l_lovrVec3__add }, { "__sub", l_lovrVec3__sub }, { "__mul", l_lovrVec3__mul }, @@ -1039,7 +1080,7 @@ static int l_lovrVec4Distance(lua_State* L) { uvec[3] = luax_checkfloat(L, 5); u = uvec; } else { - u = luax_checkvector(L, 2, V_VEC4, NULL); + u = luax_checkvector(L, 2, V_VEC4, "vec4 or number"); } float dx = v[0] - u[0]; float dy = v[1] - u[1]; @@ -1060,7 +1101,7 @@ static int l_lovrVec4Dot(lua_State* L) { uvec[3] = luax_checkfloat(L, 5); u = uvec; } else { - u = luax_checkvector(L, 2, V_VEC4, NULL); + u = luax_checkvector(L, 2, V_VEC4, "vec4 or number"); } lua_pushnumber(L, v[0] * u[0] + v[1] * u[1] + v[2] * u[2] + v[3] * u[3]); return 1; @@ -1079,7 +1120,7 @@ static int l_lovrVec4Lerp(lua_State* L) { u = uvec; t = luax_checkfloat(L, 6); } else { - u = luax_checkvector(L, 2, V_VEC4, NULL); + u = luax_checkvector(L, 2, V_VEC4, "vec4 or number"); t = luax_checkfloat(L, 3); } v[0] = v[0] + (u[0] - v[0]) * t; @@ -1090,6 +1131,31 @@ static int l_lovrVec4Lerp(lua_State* L) { return 1; } +static int l_lovrVec4Angle(lua_State* L) { + float* v = luax_checkvector(L, 1, V_VEC4, NULL); + float* u; + float uvec[4]; + float dot, length_v, length_u; + if (lua_type(L, 2) == LUA_TNUMBER) { + uvec[0] = lua_tonumber(L, 2); + uvec[1] = luax_checkfloat(L, 3); + uvec[2] = luax_checkfloat(L, 4); + uvec[3] = luax_checkfloat(L, 5); + u = uvec; + } else { + u = luax_checkvector(L, 2, V_VEC4, "vec4 or number"); + } + length_v = sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3]); + length_u = sqrtf(u[0] * u[0] + u[1] * u[1] + u[2] * u[2] + u[3] * u[3]); + if ((length_v == 0.f) || (length_u == 0.f)) { + lua_pushnumber(L, (float) M_PI / 2); + } else { + dot = v[0] * u[0] + v[1] * u[1] + v[2] * u[2] + v[3] * u[3]; + lua_pushnumber(L, acosf(dot / (length_v * length_u))); + } + return 1; +} + static int l_lovrVec4__add(lua_State* L) { float* out = luax_newtempvector(L, V_VEC4); if (lua_type(L, 1) == LUA_TNUMBER) { @@ -1329,6 +1395,7 @@ const luaL_Reg lovrVec4[] = { { "distance", l_lovrVec4Distance }, { "dot", l_lovrVec4Dot }, { "lerp", l_lovrVec4Lerp }, + { "angle", l_lovrVec4Angle }, { "__add", l_lovrVec4__add }, { "__sub", l_lovrVec4__sub }, { "__mul", l_lovrVec4__mul }, diff --git a/src/core/maf.h b/src/core/maf.h index d6d8e14e..d55a63d0 100644 --- a/src/core/maf.h +++ b/src/core/maf.h @@ -122,6 +122,15 @@ MAF vec3 vec3_max(vec3 v, const vec3 u) { return v; } +MAF float vec3_angle(const vec3 v, const vec3 u) { + float denom = vec3_length(v) * vec3_length(u); + if (denom == 0.f) { + return (float) M_PI / 2; + } else { + return acosf(vec3_dot(v, u) / denom); + } +} + // quat MAF quat quat_set(quat q, float x, float y, float z, float w) {