This repository has been archived by the owner on Jul 11, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
skan.hs
executable file
·146 lines (121 loc) · 4.88 KB
/
skan.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
-- TODO:
-- . INPUT HANDLING
-- .. IMPROVE:
-- ... CHANGE SAVE/EXIT METHOD SO IT DOESN'T NEED UNSAFEPERFORMIO
-- .. IMPLEMENT:
-- ... RENAME ANIMATION (ask name) KEY = ???
-- ... UNDO (?) KEY = Z
-- ... REDO (?) KEY = X
-- ... HELP MENU (?) KEY = TAB
import Control.Lens
import Data.Foldable (toList)
import Data.Geometry
import Data.List.Util
import Data.Maybe
import Data.Skeleton
import Data.Skeleton.Gloss
import Data.Skeleton.Human
import Data.World
import Graphics.Gloss
import Graphics.Gloss.Interface.Pure.Game
import Linear hiding (trace)
import System.Directory
import System.IO.Unsafe
import qualified Data.Map as Map
import qualified Data.Set as Set
type View = Projection Float
-- INITIALIZATION
-- Initial world state
defaultWorld :: World
defaultWorld
= World
0
Set.empty
humanSkeletonCursor
[("UNNAMED", [humanSkeleton])]
"UNNAMED"
0
0
-- VIEWS
-- A view is just a projection from spatial (x,y,z) to screen (x,y,z)
-- On the screen, x goes right, y goes up
-- On the space, x goes right, y goes south, z goes up
-- The char is looking right with left arm pointing north
tibiaView, frontView, topView, sideView :: View
tibiaView (V3 x y z) = V3 ((x - z*0.707) * 0.8) ((y + z*0.707) * 0.8) 0
frontView (V3 x y z) = V3 y z 0
topView (V3 x y z) = V3 (-y) x 0
sideView (V3 x y z) = V3 x z 0
-- RENDERING
-- Renders a view
renderView :: World -> View -> Float -> Float -> Picture
renderView world view x y
= translate x y
$ renderSkeleton
view
(V3 0 0 0)
(V3 0 0 1)
(V3 1 0 0)
(world ^. bonePath)
(world ^. activeSkeleton)
-- DRAWING
-- Draws the world
draw :: World -> Picture
draw world = pictures [
renderView world topView (-100) (-100) ,
renderView world frontView (-100) ( 100) ,
renderView world sideView ( 100) (-100) ,
renderView world tibiaView ( 100) ( 100) ,
Translate 80 220 $ Scale 0.1 0.1 $ Text text] where
text = animationName ++ " (ANIMATION " ++ animationIndex ++ ") - FRAME " ++ frameIndex
animationName = world ^. activeAnimationName
animationIndex = show (world ^. activeAnimationIndex)
frameIndex = show (world ^. activeFrameIndex)
-- INPUT HANDLING
-- Updates the world after certain inputs
input :: Event -> World -> World
input (EventKey key Up _ _) = keyDown %~ Set.delete key
input (EventKey key Down _ _)
= (keyDown %~ Set.insert key)
. updateActiveAnimationName
. (Map.findWithDefault id key (Map.fromList [
(Char 'w' , moveCursorUp ),
(Char 'a' , moveCursorLeft ),
(Char 's' , moveCursorDown ),
(Char 'd' , moveCursorRight ),
(Char 'r' , resetActiveBone ),
(Char 'f' , createNewFrame ),
(Char 'q' , goToPreviousFrame ),
(Char 'e' , goToNextFrame ),
(Char 'g' , deleteActiveFrame ),
(Char 'v' , createNewAnimation ),
(Char '1' , goToPreviousAnimation ),
(Char '2' , goToNextAnimation ),
(Char 'b' , deleteActiveAnimation ),
(SpecialKey KeyEnter, \ w -> unsafePerformIO (saveAndExit w))]))
input _ = id
-- STATE HANDLING
-- Advances the world to the next state each frame
step :: Float -> World -> World
step dt world = (time +~ dt) . keyboardEffects $ world where
keyboardEffects = compose $ mapMaybe keyCommand pressedKeys
keyCommand key = Map.lookup key commandByKey
pressedKeys = Set.toList $ world ^. keyDown
inc = 0.02
commandByKey = Map.fromList [
-- Controls the active bone rotation
(Char 'u', activeBoneRotation *~ roll (-inc)),
(Char 'i', activeBoneRotation *~ roll ( inc)),
(Char 'j', activeBoneRotation *~ pitch (-inc)),
(Char 'k', activeBoneRotation *~ pitch ( inc)),
(Char 'm', activeBoneRotation *~ yaw (-inc)),
(Char ',', activeBoneRotation *~ yaw ( inc))]
-- MAIN MODULE
-- Where the magic happens
main = do
savedWorldExists <- doesFileExist "savedWorld"
if savedWorldExists
then do
savedWorld <- loadSavedWorld
play (InWindow "Skeleton_Draw_Test" (512, 512) (0, 0)) white 60 savedWorld draw input step
else play (InWindow "Skeleton_Draw_Test" (512, 512) (0, 0)) white 60 defaultWorld draw input step