From 56540ac3ca48cc77da0e86389fe550ede1c1081e Mon Sep 17 00:00:00 2001 From: Marc Sunet Date: Sat, 8 Sep 2012 12:39:14 +0200 Subject: Fixed 3d rotation; added rpgUnproject --- Spear.lkshs | 12 ++++---- Spear.lkshw | 4 +-- Spear/Math/MatrixUtils.hs | 48 +++++++++++++++++++++++++++++++- Spear/Scene/GameObject.hs | 70 +++++++++++++++++++++++++++++++++-------------- 4 files changed, 104 insertions(+), 30 deletions(-) diff --git a/Spear.lkshs b/Spear.lkshs index 3af403b..2c83290 100644 --- a/Spear.lkshs +++ b/Spear.lkshs @@ -1,18 +1,18 @@ Version of session file format: 1 Time of storage: - "Fri Sep 7 14:26:09 CEST 2012" -Layout: VerticalP (TerminalP {paneGroups = fromList [], paneTabs = Just TopP, currentPage = 6, detachedId = Nothing, detachedSize = Nothing}) (HorizontalP (TerminalP {paneGroups = fromList [("Browser",HorizontalP (TerminalP {paneGroups = fromList [], paneTabs = Nothing, currentPage = 0, detachedId = Nothing, detachedSize = Nothing}) (HorizontalP (TerminalP {paneGroups = fromList [], paneTabs = Nothing, currentPage = 0, detachedId = Nothing, detachedSize = Nothing}) (TerminalP {paneGroups = fromList [], paneTabs = Nothing, currentPage = 0, detachedId = Nothing, detachedSize = Nothing}) 350) 153),("Debug",HorizontalP (TerminalP {paneGroups = fromList [], paneTabs = Nothing, currentPage = 0, detachedId = Nothing, detachedSize = Nothing}) (TerminalP {paneGroups = fromList [], paneTabs = Just TopP, currentPage = 1, detachedId = Nothing, detachedSize = Nothing}) 239)], paneTabs = Just BottomP, currentPage = 0, detachedId = Nothing, detachedSize = Nothing}) (TerminalP {paneGroups = fromList [], paneTabs = Nothing, currentPage = 0, detachedId = Nothing, detachedSize = Nothing}) 640) 954 -Population: [(Just (BreakpointsSt BreakpointsState),[SplitP RightP,SplitP TopP,GroupP "Debug",SplitP BottomP]),(Just (ErrorsSt ErrorsState),[SplitP RightP,SplitP TopP]),(Just (BufferSt (BufferState "/home/jeanne/programming/haskell/Spear/demos/simple-scene/Game/GameObject/Factory.hs" 0)),[SplitP LeftP]),(Just (FilesSt FilesState),[SplitP RightP,SplitP TopP]),(Just (BufferSt (BufferState "/home/jeanne/programming/haskell/Spear/Spear/Scene/GameObject.hs" 46)),[SplitP LeftP]),(Just (BufferSt (BufferState "/home/jeanne/programming/haskell/Spear/demos/simple-scene/Game/GameObject.hs" 39)),[SplitP LeftP]),(Just (BufferSt (BufferState "/home/jeanne/programming/haskell/Spear/demos/simple-scene/Game/GameState.hs" 1011)),[SplitP LeftP]),(Just (InfoSt (InfoState Nothing)),[SplitP RightP,SplitP TopP,GroupP "Browser",SplitP BottomP,SplitP BottomP]),(Just (LogSt LogState),[SplitP RightP,SplitP BottomP]),(Just (BufferSt (BufferState "/home/jeanne/programming/haskell/Spear/Spear/Math/MatrixUtils.hs" 616)),[SplitP LeftP]),(Just (ModulesSt (ModulesState 328 (PackageScope False,False) (Nothing,Nothing) (ExpanderState {packageExp = ([],[]), packageExpNoBlack = ([],[]), packageDExp = ([],[]), packageDExpNoBlack = ([],[]), workspaceExp = ([],[]), workspaceExpNoBlack = ([],[]), workspaceDExp = ([],[]), workspaceDExpNoBlack = ([],[]), systemExp = ([],[]), systemExpNoBlack = ([],[])}))),[SplitP RightP,SplitP TopP,GroupP "Browser",SplitP BottomP,SplitP TopP]),(Just (BufferSt (BufferState "/home/jeanne/programming/haskell/Spear/demos/simple-scene/Game/GameObject/Player.hs" 611)),[SplitP LeftP]),(Just (SearchSt (SearchState {searchString = "putStrLn", searchScope = PackageScope False, searchMode = Prefix {caseSense = False}})),[SplitP RightP,SplitP TopP]),(Just (TraceSt TraceState),[SplitP RightP,SplitP TopP,GroupP "Debug",SplitP BottomP]),(Just (VariablesSt VariablesState),[SplitP RightP,SplitP TopP,GroupP "Debug",SplitP BottomP]),(Just (WorkspaceSt WorkspaceState),[SplitP RightP,SplitP TopP,GroupP "Browser",SplitP TopP]),(Just (BufferSt (BufferStateTrans "_Eval.hs" "\n" 0)),[SplitP RightP,SplitP TopP,GroupP "Debug",SplitP TopP]),(Just (BufferSt (BufferState "/home/jeanne/programming/haskell/Spear/demos/simple-scene/main.hs" 4966)),[SplitP LeftP])] + "Sat Sep 8 12:03:07 CEST 2012" +Layout: VerticalP (TerminalP {paneGroups = fromList [], paneTabs = Just TopP, currentPage = 0, detachedId = Nothing, detachedSize = Nothing}) (HorizontalP (TerminalP {paneGroups = fromList [("Browser",HorizontalP (TerminalP {paneGroups = fromList [], paneTabs = Nothing, currentPage = 0, detachedId = Nothing, detachedSize = Nothing}) (HorizontalP (TerminalP {paneGroups = fromList [], paneTabs = Nothing, currentPage = 0, detachedId = Nothing, detachedSize = Nothing}) (TerminalP {paneGroups = fromList [], paneTabs = Nothing, currentPage = 0, detachedId = Nothing, detachedSize = Nothing}) 335) 148),("Debug",HorizontalP (TerminalP {paneGroups = fromList [], paneTabs = Nothing, currentPage = 0, detachedId = Nothing, detachedSize = Nothing}) (TerminalP {paneGroups = fromList [], paneTabs = Just TopP, currentPage = 1, detachedId = Nothing, detachedSize = Nothing}) 234)], paneTabs = Just BottomP, currentPage = 0, detachedId = Nothing, detachedSize = Nothing}) (TerminalP {paneGroups = fromList [], paneTabs = Nothing, currentPage = 0, detachedId = Nothing, detachedSize = Nothing}) 621) 954 +Population: [(Just (BreakpointsSt BreakpointsState),[SplitP RightP,SplitP TopP,GroupP "Debug",SplitP BottomP]),(Just (ErrorsSt ErrorsState),[SplitP RightP,SplitP TopP]),(Just (BufferSt (BufferState "/home/jeanne/programming/haskell/Spear/demos/simple-scene/Game/GameObject/Factory.hs" 1138)),[SplitP LeftP]),(Just (FilesSt FilesState),[SplitP RightP,SplitP TopP]),(Just (BufferSt (BufferState "/home/jeanne/programming/haskell/Spear/Spear/Scene/GameObject.hs" 3926)),[SplitP LeftP]),(Just (BufferSt (BufferState "/home/jeanne/programming/haskell/Spear/demos/simple-scene/Game/GameObject.hs" 39)),[SplitP LeftP]),(Just (BufferSt (BufferState "/home/jeanne/programming/haskell/Spear/demos/simple-scene/Game/GameState.hs" 1011)),[SplitP LeftP]),(Just (InfoSt (InfoState Nothing)),[SplitP RightP,SplitP TopP,GroupP "Browser",SplitP BottomP,SplitP BottomP]),(Just (LogSt LogState),[SplitP RightP,SplitP BottomP]),(Just (BufferSt (BufferState "/home/jeanne/programming/haskell/Spear/Spear/Math/MatrixUtils.hs" 2151)),[SplitP LeftP]),(Just (ModulesSt (ModulesState 328 (PackageScope False,False) (Nothing,Nothing) (ExpanderState {packageExp = ([],[]), packageExpNoBlack = ([[0]],[]), packageDExp = ([],[]), packageDExpNoBlack = ([],[]), workspaceExp = ([],[]), workspaceExpNoBlack = ([],[]), workspaceDExp = ([],[]), workspaceDExpNoBlack = ([],[]), systemExp = ([],[]), systemExpNoBlack = ([],[])}))),[SplitP RightP,SplitP TopP,GroupP "Browser",SplitP BottomP,SplitP TopP]),(Just (BufferSt (BufferState "/home/jeanne/programming/haskell/Spear/demos/simple-scene/Game/GameObject/Player.hs" 2818)),[SplitP LeftP]),(Just (SearchSt (SearchState {searchString = "putStrLn", searchScope = PackageScope False, searchMode = Prefix {caseSense = False}})),[SplitP RightP,SplitP TopP]),(Just (TraceSt TraceState),[SplitP RightP,SplitP TopP,GroupP "Debug",SplitP BottomP]),(Just (VariablesSt VariablesState),[SplitP RightP,SplitP TopP,GroupP "Debug",SplitP BottomP]),(Just (WorkspaceSt WorkspaceState),[SplitP RightP,SplitP TopP,GroupP "Browser",SplitP TopP]),(Just (BufferSt (BufferStateTrans "_Eval.hs" "\n" 0)),[SplitP RightP,SplitP TopP,GroupP "Debug",SplitP TopP]),(Just (BufferSt (BufferState "/home/jeanne/programming/haskell/Spear/demos/simple-scene/main.hs" 4399)),[SplitP LeftP])] Window size: (1820,944) Completion size: (750,399) Workspace: Just "/home/jeanne/programming/haskell/Spear/Spear.lkshw" -Active pane: Just "main.hs" +Active pane: Just "Factory.hs" Toolbar visible: True -FindbarState: (False,FindState {entryStr = "Sphere", entryHist = ["Sphere","boxFrom","sphere","asdad","m[15]","m[14]","m[1]","m[13]","m[12]","m[11]","m[10]","m[9]"], replaceStr = "a01", replaceHist = [], caseSensitive = True, entireWord = False, wrapAround = False, regex = False, lineNr = 1}) +FindbarState: (False,FindState {entryStr = "asdads", entryHist = ["asdads","let scene","scene","Sphere","boxFrom","sphere","m[15]","m[14]","m[1]","m[13]","m[12]","m[11]"], replaceStr = "a01", replaceHist = [], caseSensitive = True, entireWord = False, wrapAround = False, regex = False, lineNr = 1}) Recently opened files: - ["/home/jeanne/programming/haskell/Spear/demos/simple-scene/Game/GameObject/AnimatedGO.hs","/home/jeanne/programming/haskell/Spear/demos/simple-scene/Game/GameObject/StaticGO.hs","/home/jeanne/programming/haskell/Spear/Spear/Math/Vector2.hs","/home/jeanne/programming/haskell/Spear/Spear/Render/StaticModel.hs","/home/jeanne/programming/haskell/Spear/Spear/Render/AnimatedModel.hs","/home/jeanne/programming/haskell/Spear/Spear/Collision.hs","/home/jeanne/programming/haskell/Spear/demos/simple-scene/main.hs","/home/jeanne/programming/haskell/Spear/Spear/Math/Camera.hs","/home/jeanne/programming/haskell/Spear/demos/simple-scene/Game/GameObject/Factory.hs","/home/jeanne/programming/haskell/Spear/Spear/Math/Matrix3.hs","/home/jeanne/programming/haskell/Spear/demos/simple-scene/Game/Program/Box.hs","/home/jeanne/programming/haskell/Spear/demos/simple-scene/Game/Program/Line.hs"] + ["/home/jeanne/programming/haskell/Spear/demos/simple-scene/Game/GameObject.hs","/home/jeanne/programming/haskell/Spear/Spear/Math/Matrix4.hs","/home/jeanne/programming/haskell/Spear/demos/simple-scene/Game/GameObject/AnimatedGO.hs","/home/jeanne/programming/haskell/Spear/demos/simple-scene/Game/GameObject/StaticGO.hs","/home/jeanne/programming/haskell/Spear/Spear/Math/Vector2.hs","/home/jeanne/programming/haskell/Spear/Spear/Render/StaticModel.hs","/home/jeanne/programming/haskell/Spear/Spear/Render/AnimatedModel.hs","/home/jeanne/programming/haskell/Spear/Spear/Collision.hs","/home/jeanne/programming/haskell/Spear/demos/simple-scene/main.hs","/home/jeanne/programming/haskell/Spear/Spear/Math/Camera.hs","/home/jeanne/programming/haskell/Spear/demos/simple-scene/Game/GameObject/Factory.hs","/home/jeanne/programming/haskell/Spear/Spear/Math/Matrix3.hs"] Recently opened workspaces: ["/home/jeanne/programming/haskell/hagen/hagen.lkshw","/home/jeanne/programming/haskell/foo/foo.lkshw","/home/jeanne/programming/haskell/Spear/Spear.lkshw","/home/jeanne/programming/haskell/nexus/nexus.lkshw","/home/jeanne/leksah.lkshw"] \ No newline at end of file diff --git a/Spear.lkshw b/Spear.lkshw index cc2deed..b2416a3 100644 --- a/Spear.lkshw +++ b/Spear.lkshw @@ -1,10 +1,10 @@ Version of workspace file format: 1 Time of storage: - "Fri Sep 7 17:11:58 CEST 2012" + "Sat Sep 8 12:34:51 CEST 2012" Name of the workspace: "Spear" File paths of contained packages: ["demos/simple-scene/simple-scene.cabal","Spear.cabal"] Maybe file path of an active package: - Just "demos/simple-scene/simple-scene.cabal" \ No newline at end of file + Just "Spear.cabal" \ No newline at end of file diff --git a/Spear/Math/MatrixUtils.hs b/Spear/Math/MatrixUtils.hs index 354c840..629b73c 100644 --- a/Spear/Math/MatrixUtils.hs +++ b/Spear/Math/MatrixUtils.hs @@ -1,6 +1,8 @@ module Spear.Math.MatrixUtils ( fastNormalMatrix +, unproject +, rpgUnproject , rpgTransform , pltTransform , rpgInverse @@ -27,6 +29,50 @@ fastNormalMatrix m = (M4.m02 m') (M4.m12 m') (M4.m22 m') +-- | Transform the given point in window coordinates to object coordinates. +unproject :: Matrix4 -- ^ Inverse projection matrix + -> Matrix4 -- ^ Inverse modelview matrix. + -> Float -- ^ Viewport x + -> Float -- ^ Viewport y + -> Float -- ^ Viewport width + -> Float -- ^ Viewport height + -> Float -- ^ Window x + -> Float -- ^ Window y + -> Float -- ^ Window z + -> V3.Vector3 +unproject projI modelviewI vpx vpy w h x y z = + let + xmouse = 2*(x-vpx)/w - 1 + ymouse = 2*(y-vpy)/h - 1 + zmouse = 2*z - 1 + in + (modelviewI * projI) `M4.mulp` V3.vec3 xmouse ymouse zmouse + + +-- | Transform the given point in window coordinates to 2d coordinates. +-- +-- The line defined by the given point in window space is intersected with +-- the XZ plane in world space to yield the resulting 2d point. +rpgUnproject + :: Matrix4 -- ^ Inverse projection matrix + -> Matrix4 -- ^ Inverse viewI matrix. + -> Float -- ^ Viewport x + -> Float -- ^ Viewport y + -> Float -- ^ Viewport width + -> Float -- ^ Viewport height + -> Float -- ^ Window x + -> Float -- ^ Window y + -> Vector2 +rpgUnproject projI viewI vpx vpy w h x y = + let + p1 = unproject projI viewI vpx vpy w h x y 0 + p2 = unproject projI viewI vpx vpy w h x y (-1) + lambda = (V3.y p1 / (V3.y p1 - V3.y p2)) + p' = p1 + V3.scale lambda (p2 - p1) + in + vec2 (V3.x p') (-V3.z p') + + -- | Map an object's transform in view space to world space. rpgTransform :: Float -- ^ The height above the ground @@ -37,7 +83,7 @@ rpgTransform -> Matrix4 rpgTransform h a axis pos viewI = let p1 = viewI `M4.mulp` (vec3 (V2.x pos) (V2.y pos) 0) - p2 = viewI `M4.mulp` (vec3 (V2.x pos) (V2.y pos) (-100)) + p2 = viewI `M4.mulp` (vec3 (V2.x pos) (V2.y pos) (-1)) lambda = (V3.y p1 / (V3.y p1 - V3.y p2)) p = p1 + V3.scale lambda (p2 - p1) mat' = axisAngle axis a diff --git a/Spear/Scene/GameObject.hs b/Spear/Scene/GameObject.hs index 53a03b5..a43a2a4 100644 --- a/Spear/Scene/GameObject.hs +++ b/Spear/Scene/GameObject.hs @@ -2,6 +2,7 @@ module Spear.Scene.GameObject ( GameObject , GameStyle(..) +, Window(..) , AM.AnimationSpeed -- * Construction , goNew @@ -13,6 +14,7 @@ module Spear.Scene.GameObject , goRPGtransform , numCollisioners , renderer +, window -- * Manipulation , goUpdate , setAnimation @@ -20,7 +22,7 @@ module Spear.Scene.GameObject , setAxis , withCollisioners , setCollisioners -, setViewInverse +, setWindow -- * Rendering , goRender -- * Collision @@ -53,15 +55,28 @@ data GameStyle | PLT -- ^ Platformer or space invaders style game. +data Window = Window + { projInv :: !M4.Matrix4 + , viewInv :: !M4.Matrix4 + , vpx :: !Float + , vpy :: !Float + , width :: !Float + , height :: !Float + } + + +dummyWindow = Window M4.id M4.id 0 0 640 480 + + -- | An object in the game scene. data GameObject = GameObject { gameStyle :: !GameStyle , renderer :: !(Either StaticModelRenderer AM.AnimatedModelRenderer) , collisioners :: ![Collisioner] , transform :: !M3.Matrix3 - , axis :: Vector3 - , angle :: Float - , viewInv :: !M4.Matrix4 + , axis :: !Vector3 + , angle :: !Float + , window :: !Window -- ^ Get the game object's window. } @@ -133,17 +148,28 @@ instance S2.Spatial2 GameObject where in go { transform = M3.transform (M3.right m) (M3.forward m) pos } lookAt p go = - let position = S2.pos go - fwd = V2.normalise $ p - position - r = perp fwd - toDeg = (*(180/pi)) + let position = S2.pos go + fwd = V2.normalise $ p - position + r = perp fwd + toDeg = (*(180/pi)) + wnd = window go + viewI = viewInv wnd + vpx' = vpx wnd + vpy' = vpy wnd + w = width wnd + h = height wnd + p1' = position + p2' = position + fwd + p1 = rpgUnproject M4.id viewI vpx' vpy' w h (V2.x p1') (V2.y p1') + p2 = rpgUnproject M4.id viewI vpx' vpy' w h (V2.x p2') (V2.y p2') + f = V2.normalise $ p2 - p1 in go { transform = M3.transform r fwd position - , angle = (-180) + - if V2.y r > 0 - then toDeg . acos $ r `V2.dot` V2.unitx - else (+180) . toDeg . acos $ r `V2.dot` (-V2.unitx) + , angle = 180 - + if V2.x f > 0 + then toDeg . acos $ f `V2.dot` V2.unity + else (+180) . toDeg . acos $ f `V2.dot` (-V2.unity) } @@ -155,11 +181,11 @@ goNew :: GameStyle -> Vector3 -- ^ Axis of rotation -> GameObject -goNew style (Left smr) cols transf axis = - GameObject style (Left $ SM.staticModelRenderer smr) cols transf axis 0 M4.id +goNew style (Left smr) cols transf axis = GameObject + style (Left $ SM.staticModelRenderer smr) cols transf axis 0 dummyWindow -goNew style (Right amr) cols transf axis = - GameObject style (Right $ AM.animatedModelRenderer 1 amr) cols transf axis 0 M4.id +goNew style (Right amr) cols transf axis = GameObject + style (Right $ AM.animatedModelRenderer 1 amr) cols transf axis 0 dummyWindow goUpdate :: Float -> GameObject -> GameObject @@ -185,7 +211,9 @@ goAABBs = fmap getAABB . collisioners -- | Get the game object's 3D transform. goRPGtransform :: GameObject -> M4.Matrix4 -goRPGtransform go = rpgTransform 0 (angle go) (axis go) (S2.pos go) (viewInv go) +goRPGtransform go = + let viewI = viewInv . window $ go + in rpgTransform 0 (angle go) (axis go) (S2.pos go) viewI -- | Get the game object's current animation. @@ -224,9 +252,9 @@ setCollisioners :: GameObject -> [Collisioner] -> GameObject setCollisioners go cols = go { collisioners = cols } --- | Set the game object's view inverse matrix. -setViewInverse :: M4.Matrix4 -> GameObject -> GameObject -setViewInverse mat go = go { viewInv = mat } +-- | Set the game object's window. +setWindow :: Window -> GameObject -> GameObject +setWindow wnd go = go { window = wnd } -- | Manipulate the game object's collisioners. @@ -242,7 +270,7 @@ goRender sprog aprog cam go = style = gameStyle go axis' = axis go a = angle go - viewI = viewInv go + viewI = viewInv . window $ go proj = Cam.projection cam view = M4.inverseTransform $ Cam.transform cam transf = S2.transform go -- cgit v1.2.3