-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathobj2json.hs
158 lines (124 loc) · 4.85 KB
/
obj2json.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
147
148
149
150
151
152
153
154
155
156
157
-- TODO: Currently only supports one object per file.
import Data.Char
import Data.Maybe
import Data.List
import Control.Monad
import Text.Printf
-- raw types
data RawType =
O String |
V Double Double Double |
VN Double Double Double |
F [Int] |
USEMTL String |
S String |
MTLLIB String |
Unknown String
deriving (Read)
instance Show RawType where
show (O s) = s
show (V x y z) = printf "[%f,%f,%f]" x y z
show (VN x y z) = printf "[%f,%f,%f]" x y z
show (F fs) = show fs
show (USEMTL s) = ""
show (S s) = ""
show (MTLLIB s) = ""
show (Unknown s) = ""
-- maybe I'm missing a haskell-ism here
isObj :: RawType -> Bool
isObj (O xs) = True
isObj _ = False
isVert :: RawType -> Bool
isVert (V x y z) = True
isVert _ = False
isVertNorm :: RawType -> Bool
isVertNorm (VN x y z) = True
isVertNorm _ = False
isFace :: RawType -> Bool
isFace (F xs) = True
isFace _ = False
firstToken :: String -> Maybe String
firstToken [] = Nothing
firstToken l = Just h
where h = head $ words l
isCommentLine :: Maybe String -> Bool
isCommentLine Nothing = True
isCommentLine (Just l) = c == '#'
where c = head l
getDataLines :: String -> [String]
getDataLines contents = filter (not . isCommentLine . firstToken) $ lines contents
getStringData :: String -> String
getStringData s = (words s) !! 1
-- abust of pattern matching? you decide :-)
getData :: String -> String -> RawType
getData "V" line = V (nums !! 0) (nums !! 1) (nums !! 2)
where
numStrings = tail $ words line
nums = map (\x -> read x :: Double) numStrings
-- warning: repeated code!
getData "VN" line = VN (nums !! 0) (nums !! 1) (nums !! 2)
where
numStrings = tail $ words line
nums = map (\x -> read x :: Double) numStrings
-- renumber Face vert references starting at 0
getData "F" line = F adjustedNumData
where
strData = words $ tail line
numData = map (\n -> read n :: Int) strData
adjustedNumData = map (\n -> n - 1) numData
getData "O" line = O objname
where objname = getStringData line
getData "USEMTL" line = USEMTL matlName
where matlName = getStringData line
getData "S" line = S s
where s = getStringData line
getData "MTLLIB" line = MTLLIB m
where m = getStringData line
getData _ line = Unknown line
-- produces "\"Foo\"" from "Foo"
jsonStr :: String -> String
jsonStr s = "\"" ++ s ++ "\""
jsonKeyValQuote :: String -> String -> String
jsonKeyValQuote k v = jsonStr k ++ ":" ++ jsonStr v
jsonKeyVal :: String -> String -> String
jsonKeyVal k v = jsonStr k ++ ":" ++ v
outputObject :: [RawType] -> IO ()
outputObject objData = do
let nameNode = jsonKeyValQuote "name" $ show obj
let vertsNode = jsonKeyVal "verts" $ show verts
let vertNormsNode = jsonKeyVal "vert_norms" $ show vertNorms
let facesNode = jsonKeyVal "faces" $ show faces
let odata = [nameNode, vertsNode, vertNormsNode, facesNode]
putStr "{"
mapM_ putStr $ intersperse "," odata
putStrLn "}"
where
verts = filter isVert objData
vertNorms = filter isVertNorm objData
faces = filter isFace objData
obj = head $ filter isObj objData
outputObjects :: [RawType] -> IO ()
outputObjects o = do
putStr "{"
putStr $ jsonStr "objects"
putStr ": ["
-- TODO, not correct for more than one object
outputObject o
putStrLn "]}"
processLine :: String -> RawType
processLine l = getData ft l
where
ft = map toUpper $ (fromJust $ firstToken l)
processData :: String -> IO ()
processData contents =
--mapM_ putStrLn mappedStrs >>
outputObjects mapped
where
ls = getDataLines contents
mapped = map processLine ls
--mappedStrs = map show mapped
main :: IO ()
main = do
contents <- getContents
processData contents
return ()