diff --git a/src/game/Global.cpp b/src/game/Global.cpp index 747a26c..a99ab72 100644 --- a/src/game/Global.cpp +++ b/src/game/Global.cpp @@ -127,7 +127,7 @@ Vec3 Transform::GlobalToLocalDirection(Vec3 global) bx::vec4MulMtx(out, in, MI.Transpose().M); return {out[0], out[1], out[2]}; } -bx::Vec3 Transform::GlobalToLocalPoint(Vec3 global) +Vec3 Transform::GlobalToLocalPoint(Vec3 global) { UpdateMatrix(); float in[4]{global.x, global.y, global.z, 1.0f}; @@ -143,7 +143,7 @@ Vec3 Transform::LocalToGlobalDirection(Vec3 local) bx::vec4MulMtx(out, in, M.Transpose().M); return {out[0], out[1], out[2]}; } -bx::Vec3 Transform::LocalToGlobalPoint(Vec3 local) +Vec3 Transform::LocalToGlobalPoint(Vec3 local) { UpdateMatrix(); float in[4]{local.x, local.y, local.z, 1.0f}; @@ -177,3 +177,38 @@ Vec4 Mat4::Mul(const Vec4& vec) bx::vec4MulMtx(&out.x, &vec.x, &M[0]); return out; } +float DotProduct(Vec3 a, Vec3 b) +{ + return a.x * b.x + a.y * b.y + a.z * b.z; +} +Vec3 CrossProduct(Vec3 a, Vec3 b) +{ + float x = a.y * b.z - a.z * b.y; + float y = a.z * b.x - a.x * b.z; + float z = a.x * b.y - a.y * b.x; + return {x, y, z}; +} +Vec3 CrossProductFromPlane(Vec3 a, Vec3 b, Vec3 c) +{ + // TODO: normalize might not be necessary + Vec3 lineA = (b - a).Normalize(); + Vec3 lineB = (c - a).Normalize(); + return CrossProduct(lineA, lineB); +} +bool RayPlaneIntersect(Vec3 l1, Vec3 l2, Vec3 p1, Vec3 p2, Vec3 p3, Vec3& out) +{ + // thanks to Paul Bourke and Bryan Hanson + // l1,l2 constitute the line. P1,P2,P3 constitute the plane + out = {}; + Vec3 N = CrossProductFromPlane(p1, p2, p3); // N is the normal of the plane + float n = DotProduct(N, Vec3{p3.x - l1.x, p3.y - l1.y, p3.z - l1.z}); + Vec3 LbMinusLa = Vec3{l2.x - l1.x, l2.y - l1.y, l2.z - l1.z}; + float d = DotProduct(N, LbMinusLa); + if (d == 0) return false; // Line is parallel to or in the plane + float u = n / d; + if ((u >= 0.0) && (u <= 1.0)) + { // Plane is between the two points + } // can be used for checking but does not influence the outcome + out = Vec3{l1.x + u * LbMinusLa.x, l1.y + u * LbMinusLa.y, l1.z + u * LbMinusLa.z}; + return true; +} diff --git a/src/game/Global.h b/src/game/Global.h index 47370bc..6619eca 100644 --- a/src/game/Global.h +++ b/src/game/Global.h @@ -243,9 +243,9 @@ struct Transform void TranslateLocal(Vec3 offset); void Rotate(Vec3 rotation); void RotateLocal(Vec3 rotation); - bx::Vec3 LocalToGlobalPoint(Vec3 local); + Vec3 LocalToGlobalPoint(Vec3 local); Vec3 LocalToGlobalDirection(Vec3 local); - bx::Vec3 GlobalToLocalPoint(Vec3 global); + Vec3 GlobalToLocalPoint(Vec3 global); Vec3 GlobalToLocalDirection(Vec3 global); Vec3 Right() const; Vec3 Up() const; @@ -257,6 +257,10 @@ struct Transform void UpdateMatrixForCam(); }; +Vec3 CrossProduct(Vec3 a, Vec3 b); +Vec3 CrossProductFromPlane(Vec3 a, Vec3 b, Vec3 c); +bool RayPlaneIntersect(Vec3 l1, Vec3 l2, Vec3 p1, Vec3 p2, Vec3 p3, Vec3& out); + struct SharedData; namespace Game diff --git a/src/game/Level.cpp b/src/game/Level.cpp index ea08d10..d5b93b4 100644 --- a/src/game/Level.cpp +++ b/src/game/Level.cpp @@ -344,17 +344,14 @@ namespace Game mousePos *= 2.0f; mousePos -= 1.0f; Vec4 mousePosView = {mousePos.x, -mousePos.y, 0.0f, 1.0f}; - Vec4 mousePosCam = GetInstance().Player.ProjectionInverse.Mul(mousePosView); - mousePosCam.x /= mousePosCam.w; - mousePosCam.y /= mousePosCam.w; - mousePosCam.z /= mousePosCam.w; - mousePosCam.w = 1.0f; - Vec4 mousePosWorld = camTransform.M.Mul(mousePosCam); + Vec4 mousePosCam4 = GetInstance().Player.ProjectionInverse.Mul(mousePosView); + Vec3 mousePosCam = Vec3{ + mousePosCam4.x /= mousePosCam4.w, + mousePosCam4.y /= mousePosCam4.w, + mousePosCam4.z /= mousePosCam4.w, + }; - auto& t = level.Tests.Get({0}); - t.EData.ModelH = GameRendering::Get().GetModelHandleFromPath("models/cube.gltf"); - t.EData.Transform.Position = {mousePosWorld.x, mousePosWorld.y, mousePosWorld.z}; - t.EData.Transform.Scale = {0.01f, 0.01f, 0.01f}; + Vec3 mousePosWorld = camTransform.LocalToGlobalPoint(mousePosCam); for (int8_t y = 0; y < Data.HeightTiles / Puzzle::Config::CardSize; ++y) { @@ -392,33 +389,41 @@ namespace Game // quad.EData.Transform.Scale = {0.1f, 0.1f, 0.1f}; quad.EData.Transform.Rotate(Vec3{bx::kPi * 0.5f, 0.0f, bx::kPi}); - if (clicked && IsValid && x == 1 && y == 1) + if (clicked && IsValid) { - quad.EData.Transform.UpdateMatrix(); - // boardTransform.UpdateMatrix(); - Vec4 posInQuad = quad.EData.Transform.MI.Mul(mousePosWorld); - // Vec4 posInQuad = boardTransform.MI.Mul(mousePosWorld); - // if (posInQuad.x >= -1.0f && posInQuad.x <= 1.0f && posInQuad.z >= -1.0f && posInQuad.z <= 1.0f) + Vec3 quadPosWorld = quad.EData.Transform.GetPosition(); + Vec3 quadXWorld = quad.EData.Transform.LocalToGlobalPoint({1, 0, 0}); + Vec3 quadYWorld = quad.EData.Transform.LocalToGlobalPoint({0, 0, 1}); + Vec3 intersectPos; + if (RayPlaneIntersect(camTransform.GetPosition(), + mousePosWorld, + quadPosWorld, + quadXWorld, + quadYWorld, + intersectPos)) { - LOG("---"); - LOG("%.03f %.03f: Click", mousePos.x, mousePos.y); - LOG("%.03f %.03f %.03f %.03f: Cam", mousePosCam.x, mousePosCam.y, mousePosCam.z, mousePosCam.w); - LOG("%.03f %.03f %.03f %.03f: World", - mousePosWorld.x, - mousePosWorld.y, - mousePosWorld.z, - mousePosWorld.w); - LOG("%.03f %.03f %.03f %.03f: Card (%u %u)", - posInQuad.x, - posInQuad.y, - posInQuad.z, - posInQuad.w, - x, - y); - LOG("%.03f %.03f %.03f: Player", - camTransform.Position.x, - camTransform.Position.y, - camTransform.Position.z); + Vec3 quadSpaceIntersect = quad.EData.Transform.GlobalToLocalPoint(intersectPos); + if (quadSpaceIntersect.x >= -1.0f && quadSpaceIntersect.x <= 1.0f && + quadSpaceIntersect.z >= -1.0f && quadSpaceIntersect.z <= 1.0f) + { + // LOG("---"); + // LOG("%.03f %.03f: Click", mousePos.x, mousePos.y); + // LOG("%.03f %.03f %.03f: MouseCam", mousePosCam.x, mousePosCam.y, mousePosCam.z); + // LOG("%.03f %.03f %.03f: MouseWorld", mousePosWorld.x, mousePosWorld.y, mousePosWorld.z); + // LOG("%.03f %.03f %.03f: Player", + // camTransform.Position.x, + // camTransform.Position.y, + // camTransform.Position.z); + // LOG("%.03f %.03f %.03f: QuadWorld", quadPosWorld.x, quadPosWorld.y, quadPosWorld.z); + // LOG("%.03f %.03f %.03f: QuadX", quadXWorld.x, quadXWorld.y, quadXWorld.z); + // LOG("%.03f %.03f %.03f: QuadY", quadYWorld.x, quadYWorld.y, quadYWorld.z); + // LOG("%.03f %.03f %.03f: Intersect", intersectPos.x, intersectPos.y, intersectPos.z); + // LOG("%.03f %.03f %.03f: IntersectQ", + // quadSpaceIntersect.x, + // quadSpaceIntersect.y, + // quadSpaceIntersect.z); + LOG("Clicked %u %u", x, y); + } } } }