1 |
using System; |
2 |
using System.Collections.Generic; |
3 |
using Oni.Imaging; |
4 |
|
5 |
namespace Oni.Akira |
6 |
{ |
7 |
internal class MaterialLibrary |
8 |
{ |
9 |
private readonly MarkerMaterials markers = new MarkerMaterials(); |
10 |
private readonly Dictionary<string, Material> materials = new Dictionary<string, Material>(StringComparer.OrdinalIgnoreCase); |
11 |
private Material notFound; |
12 |
|
13 |
#region internal class MarkerMaterials |
14 |
|
15 |
internal class MarkerMaterials |
16 |
{ |
17 |
private Material ghost; |
18 |
private Material stairs; |
19 |
private Material door; |
20 |
private Material danger; |
21 |
private Material barrier; |
22 |
private Material impassable; |
23 |
private Material blackness; |
24 |
private Material floor; |
25 |
|
26 |
public Material GetMarker(string name) |
27 |
{ |
28 |
EnsureMaterials(); |
29 |
|
30 |
switch (name) |
31 |
{ |
32 |
case "_marker_door": |
33 |
return door; |
34 |
case "_marker_ghost": |
35 |
return ghost; |
36 |
case "_marker_stairs": |
37 |
return stairs; |
38 |
case "_marker_danger": |
39 |
return danger; |
40 |
case "_marker_barrier": |
41 |
return barrier; |
42 |
case "_marker_impassable": |
43 |
return impassable; |
44 |
case "_marker_blackness": |
45 |
return blackness; |
46 |
case "_marker_floor": |
47 |
return floor; |
48 |
default: |
49 |
return null; |
50 |
} |
51 |
} |
52 |
|
53 |
public Material GetMarker(Polygon polygon) |
54 |
{ |
55 |
EnsureMaterials(); |
56 |
|
57 |
var flags = polygon.Flags & ~(GunkFlags.ProjectionBit0 | GunkFlags.ProjectionBit1 | GunkFlags.Horizontal | GunkFlags.Vertical); |
58 |
var adjacencyFlags = GunkFlags.Ghost | GunkFlags.StairsUp | GunkFlags.StairsDown; |
59 |
|
60 |
if ((flags & (GunkFlags.DoorFrame | adjacencyFlags)) == GunkFlags.DoorFrame) |
61 |
return door; |
62 |
|
63 |
if ((flags & adjacencyFlags) != 0) |
64 |
return ghost; |
65 |
|
66 |
if ((flags & GunkFlags.Invisible) != 0) |
67 |
{ |
68 |
flags &= ~GunkFlags.Invisible; |
69 |
|
70 |
if ((flags & GunkFlags.Danger) != 0) |
71 |
return danger; |
72 |
|
73 |
if ((flags & GunkFlags.Stairs) != 0) |
74 |
return stairs; |
75 |
|
76 |
if ((flags & (GunkFlags.NoObjectCollision | GunkFlags.NoCharacterCollision)) == GunkFlags.NoObjectCollision) |
77 |
return barrier; |
78 |
|
79 |
if ((flags & (GunkFlags.NoObjectCollision | GunkFlags.NoCharacterCollision | GunkFlags.NoCollision)) == 0) |
80 |
return impassable; |
81 |
|
82 |
// |
83 |
// What's the point of a invisible and no collision polygon?! |
84 |
// |
85 |
|
86 |
if ((flags & GunkFlags.NoCollision) != 0) |
87 |
return null; |
88 |
|
89 |
Console.Error.WriteLine("Unknown invisible material, fix tool: {0}", flags); |
90 |
} |
91 |
else |
92 |
{ |
93 |
if ((flags & (GunkFlags.TwoSided | GunkFlags.NoCollision)) == (GunkFlags.TwoSided | GunkFlags.NoCollision) |
94 |
&& polygon.Material != null |
95 |
&& polygon.Material.Name == "BLACKNESS") |
96 |
{ |
97 |
return blackness; |
98 |
} |
99 |
} |
100 |
|
101 |
return null; |
102 |
} |
103 |
|
104 |
private void EnsureMaterials() |
105 |
{ |
106 |
if (ghost != null) |
107 |
return; |
108 |
|
109 |
CreateGhost(); |
110 |
CreateBarrier(); |
111 |
CreateDanger(); |
112 |
CreateDoor(); |
113 |
CreateStairs(); |
114 |
CreateImpassable(); |
115 |
CreateBlackness(); |
116 |
CreateFloor(); |
117 |
} |
118 |
|
119 |
private void CreateBarrier() |
120 |
{ |
121 |
var surface = new Surface(128, 128); |
122 |
|
123 |
var fill = new Color(0, 240, 20, 180); |
124 |
var sign = new Color(240, 20, 0, 255); |
125 |
|
126 |
surface.Fill(0, 0, 128, 128, fill); |
127 |
|
128 |
surface.Fill(0, 0, 128, 1, sign); |
129 |
surface.Fill(0, 127, 128, 1, sign); |
130 |
surface.Fill(0, 1, 1, 126, sign); |
131 |
surface.Fill(127, 1, 1, 126, sign); |
132 |
surface.Fill(64, 1, 1, 126, sign); |
133 |
surface.Fill(1, 64, 126, 1, sign); |
134 |
|
135 |
barrier = new Material("_marker_barrier", true) |
136 |
{ |
137 |
Flags = GunkFlags.NoObjectCollision | GunkFlags.Invisible, |
138 |
Image = surface |
139 |
}; |
140 |
} |
141 |
|
142 |
private void CreateImpassable() |
143 |
{ |
144 |
var surface = new Surface(128, 128); |
145 |
|
146 |
var fill = new Color(240, 0, 20, 180); |
147 |
var sign = new Color(240, 20, 0, 255); |
148 |
|
149 |
surface.Fill(0, 0, 128, 128, fill); |
150 |
|
151 |
surface.Fill(0, 0, 128, 1, sign); |
152 |
surface.Fill(0, 127, 128, 1, sign); |
153 |
surface.Fill(0, 1, 1, 126, sign); |
154 |
surface.Fill(127, 1, 1, 126, sign); |
155 |
surface.Fill(64, 1, 1, 126, sign); |
156 |
surface.Fill(1, 64, 126, 1, sign); |
157 |
|
158 |
impassable = new Material("_marker_impassable", true) |
159 |
{ |
160 |
Flags = GunkFlags.Invisible, |
161 |
Image = surface |
162 |
}; |
163 |
} |
164 |
|
165 |
private void CreateGhost() |
166 |
{ |
167 |
var surface = new Surface(128, 128); |
168 |
|
169 |
var border = new Color(16, 48, 240, 240); |
170 |
var fill = new Color(208, 240, 240, 80); |
171 |
|
172 |
surface.Fill(0, 0, 128, 128, fill); |
173 |
|
174 |
surface.Fill(0, 0, 128, 1, border); |
175 |
surface.Fill(0, 127, 128, 1, border); |
176 |
surface.Fill(0, 1, 1, 126, border); |
177 |
surface.Fill(127, 1, 1, 126, border); |
178 |
surface.Fill(64, 1, 1, 126, border); |
179 |
surface.Fill(1, 64, 126, 1, border); |
180 |
|
181 |
ghost = new Material("_marker_ghost", true); |
182 |
ghost.Flags = GunkFlags.Ghost | GunkFlags.TwoSided | GunkFlags.Transparent | GunkFlags.NoCollision; |
183 |
ghost.Image = surface; |
184 |
} |
185 |
|
186 |
private void CreateDoor() |
187 |
{ |
188 |
var surface = new Surface(128, 128); |
189 |
|
190 |
var fill = new Color(240, 240, 0, 208); |
191 |
var line = new Color(0, 0, 240); |
192 |
|
193 |
surface.Fill(0, 0, 128, 128, fill); |
194 |
|
195 |
surface.Fill(1, 1, 126, 1, line); |
196 |
surface.Fill(1, 1, 1, 126, line); |
197 |
surface.Fill(1, 126, 126, 1, line); |
198 |
surface.Fill(126, 1, 1, 126, line); |
199 |
|
200 |
door = new Material("_marker_door", true) |
201 |
{ |
202 |
Flags = GunkFlags.DoorFrame | GunkFlags.TwoSided | GunkFlags.Transparent | GunkFlags.NoCollision, |
203 |
Image = surface |
204 |
}; |
205 |
} |
206 |
|
207 |
private void CreateDanger() |
208 |
{ |
209 |
var surface = new Surface(128, 128); |
210 |
|
211 |
var fill = new Color(255, 10, 0, 208); |
212 |
var sign = new Color(255, 255, 255, 255); |
213 |
|
214 |
surface.Fill(0, 0, 128, 128, fill); |
215 |
surface.Fill(52, 16, 24, 64, sign); |
216 |
surface.Fill(52, 96, 24, 16, sign); |
217 |
|
218 |
danger = new Material("_marker_danger", true) |
219 |
{ |
220 |
Flags = GunkFlags.Danger | GunkFlags.Invisible | GunkFlags.NoCollision | GunkFlags.NoOcclusion, |
221 |
Image = surface |
222 |
}; |
223 |
} |
224 |
|
225 |
private void CreateStairs() |
226 |
{ |
227 |
var surface = new Surface(128, 128); |
228 |
|
229 |
var fill = new Color(40, 240, 0, 180); |
230 |
var step = new Color(40, 0, 240, 180); |
231 |
|
232 |
surface.Fill(0, 0, 128, 128, fill); |
233 |
|
234 |
for (int y = 0; y < surface.Height; y += 32) |
235 |
surface.Fill(0, y, surface.Width, 16, step); |
236 |
|
237 |
stairs = new Material("_marker_stairs", true) |
238 |
{ |
239 |
Flags = GunkFlags.Stairs | GunkFlags.Invisible | GunkFlags.NoObjectCollision | GunkFlags.TwoSided, |
240 |
Image = surface |
241 |
}; |
242 |
} |
243 |
|
244 |
private void CreateBlackness() |
245 |
{ |
246 |
var surface = new Surface(16, 16, SurfaceFormat.BGRX); |
247 |
|
248 |
surface.Fill(0, 0, 16, 16, Color.Black); |
249 |
|
250 |
blackness = new Material("_marker_blackness", true) |
251 |
{ |
252 |
Flags = GunkFlags.TwoSided | GunkFlags.NoCollision, |
253 |
Image = surface |
254 |
}; |
255 |
} |
256 |
|
257 |
private void CreateFloor() |
258 |
{ |
259 |
var surface = new Surface(256, 256); |
260 |
|
261 |
surface.Fill(0, 0, 16, 16, Color.White); |
262 |
|
263 |
for (int x = 0; x < 256; x += 4) |
264 |
{ |
265 |
surface.Fill(x, 0, 1, 256, Color.Black); |
266 |
surface.Fill(0, x, 256, 1, Color.Black); |
267 |
} |
268 |
|
269 |
floor = new Material("_marker_floor", true) |
270 |
{ |
271 |
Flags = GunkFlags.NoCollision, |
272 |
Image = surface |
273 |
}; |
274 |
} |
275 |
|
276 |
public Material Barrier |
277 |
{ |
278 |
get |
279 |
{ |
280 |
EnsureMaterials(); |
281 |
return barrier; |
282 |
} |
283 |
} |
284 |
|
285 |
public Material Ghost |
286 |
{ |
287 |
get |
288 |
{ |
289 |
EnsureMaterials(); |
290 |
return ghost; |
291 |
} |
292 |
} |
293 |
|
294 |
public Material Danger |
295 |
{ |
296 |
get |
297 |
{ |
298 |
EnsureMaterials(); |
299 |
return danger; |
300 |
} |
301 |
} |
302 |
|
303 |
public Material DoorFrame |
304 |
{ |
305 |
get |
306 |
{ |
307 |
EnsureMaterials(); |
308 |
return door; |
309 |
} |
310 |
} |
311 |
|
312 |
public Material Stairs |
313 |
{ |
314 |
get |
315 |
{ |
316 |
EnsureMaterials(); |
317 |
return stairs; |
318 |
} |
319 |
} |
320 |
|
321 |
public Material Floor |
322 |
{ |
323 |
get |
324 |
{ |
325 |
EnsureMaterials(); |
326 |
return floor; |
327 |
} |
328 |
} |
329 |
|
330 |
public Material Blackness |
331 |
{ |
332 |
get |
333 |
{ |
334 |
EnsureMaterials(); |
335 |
return blackness; |
336 |
} |
337 |
} |
338 |
} |
339 |
|
340 |
#endregion |
341 |
|
342 |
public MarkerMaterials Markers => markers; |
343 |
|
344 |
public Material NotFound |
345 |
{ |
346 |
get |
347 |
{ |
348 |
if (notFound == null) |
349 |
notFound = GetMaterial("notfoundtex"); |
350 |
|
351 |
return notFound; |
352 |
} |
353 |
} |
354 |
|
355 |
public IEnumerable<Material> All => materials.Values; |
356 |
|
357 |
public Material GetMaterial(string name) |
358 |
{ |
359 |
Material material; |
360 |
|
361 |
if (!materials.TryGetValue(name, out material)) |
362 |
{ |
363 |
material = markers.GetMarker(name); |
364 |
|
365 |
if (material == null) |
366 |
material = new Material(name); |
367 |
|
368 |
materials.Add(name, material); |
369 |
} |
370 |
|
371 |
if (name.StartsWith("lmap_", StringComparison.OrdinalIgnoreCase)) |
372 |
{ |
373 |
material.Flags |= GunkFlags.NoCollision | GunkFlags.NoOcclusion | GunkFlags.SoundTransparent; |
374 |
} |
375 |
|
376 |
return material; |
377 |
} |
378 |
} |
379 |
} |