-
Notifications
You must be signed in to change notification settings - Fork 1
/
Loader.fs
133 lines (114 loc) · 3.43 KB
/
Loader.fs
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
module Assets.Loader
open System
open FSharpDoom.OpenGl.Rgba
exception WadLoaderException of string
type LumpEntry =
{ Offset: int
Size: int
Name: string
}
type DoomImage =
{ Width: int
Height: int
Left: int
Top: int
Columns: int array array
}
type Palette =
{ Colors: Rgba array }
let getString offset maxLength (bytes:byte array) =
bytes
|> Array.skip(offset)
|> Array.take(maxLength)
|> Array.takeWhile(fun item -> item <> 0uy)
|> System.Text.Encoding.ASCII.GetString
let getInt32 offset bytes =
BitConverter.ToInt32(bytes, offset)
let getInt16 offset bytes =
BitConverter.ToInt16(bytes, offset)
let loadPalettes (wad:byte array) lump =
let paletteEntries = 256
let paletteSize = paletteEntries * 3
let numberOfPalettes = lump.Size / paletteSize
{0..numberOfPalettes-1}
|> Seq.map(fun paletteIndex ->
let offset = lump.Offset + (paletteIndex * paletteSize)
{ Colors =
{0..paletteEntries-1}
|> Seq.map(fun entryIndex ->
let entryOffset = offset + entryIndex * 3
{ R = wad[entryOffset] ; G = wad[entryOffset+1] ; B = wad[entryOffset+2] ; A = 0xFFuy }
)
|> Seq.toArray
}
)
|> Seq.toArray
let loadDoomImage wad lump =
let offset = lump.Offset
let width = wad |> getInt16 offset |> int
let height = wad |> getInt16 (offset+2) |> int
let left = wad |> getInt16 (offset+4) |> int
let top = wad |> getInt16 (offset+6) |> int
let columnIndexes =
{0..width-1}
|> Seq.map(fun ci ->
offset + (getInt32 (offset+8 + 4*ci) wad)
)
|> Seq.toArray
let columns =
columnIndexes
|> Array.map(fun columnOffset ->
// TODO: make this part of the fold - i.e. do not mutate the column array
let column = Array.create height -1
Seq.initInfinite id
|> Seq.scan(fun (postOffset,shouldContinue) _ ->
let row = wad[postOffset] |> int
if row = 0xFF then
(postOffset,false)
else
let postHeight = wad[postOffset+1] |> int
{0..postHeight-1}
|> Seq.iter(fun postIndex ->
column[row+postIndex] <- wad[postOffset+3+postIndex] |> int
)
// the offset moves on by the row byte, the height byte, a dummy byte before the pixels, a dummy byte after
// the pixels and the number of pixels in the post (postHeight)
(postOffset+4+postHeight,shouldContinue)
) (columnOffset,true)
|> Seq.takeWhile snd
|> Seq.toList
|> ignore
column
)
{ Width = width
Height = height
Left = left
Top = top
Columns = columns
}
let load () =
let lumpSize = 4 + 4 + 8
let wad = System.IO.File.ReadAllBytes("Assets/DOOM1.WAD")
let fileType = getString 0 4 wad
if fileType <> "IWAD" then raise (WadLoaderException "Only IWAD files are supported")
let numberOfLumps = getInt32 0x4 wad
let directoryOffset = getInt32 0x8 wad
let lumps =
{0..numberOfLumps-1}
|> Seq.map(fun index ->
let entryOffset = directoryOffset + index * lumpSize
{ Offset = getInt32 entryOffset wad
Size = getInt32 (entryOffset+0x4) wad
Name = getString (entryOffset+0x8) 0x8 wad
}
)
|> Seq.toArray
let titlePic =
lumps
|> Array.find(fun lump -> lump.Name = "TITLEPIC")
|> loadDoomImage wad
let palettes =
lumps
|> Array.find(fun lump -> lump.Name = "PLAYPAL")
|> loadPalettes wad
(titlePic,palettes[0])