source: OniSplit/Akira/RoomGridBuilder.cs

Last change on this file was 1114, checked in by iritscen, 5 years ago

Adding OniSplit source code (v0.9.99.0). Many thanks to Neo for all his work over the years.

File size: 8.3 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.IO;
4using Oni.Collections;
5using Oni.Imaging;
6
7namespace Oni.Akira
8{
9 internal class RoomGridBuilder
10 {
11 private readonly Dae.Scene roomsScene;
12 private readonly PolygonMesh geometryMesh;
13 private PolygonMesh roomsMesh;
14 private OctreeNode geometryOcttree;
15 private OctreeNode dangerOcttree;
16
17 public RoomGridBuilder(Dae.Scene roomsScene, PolygonMesh geometryMesh)
18 {
19 this.roomsScene = roomsScene;
20 this.geometryMesh = geometryMesh;
21 }
22
23 public PolygonMesh Mesh => roomsMesh;
24
25 public void Build()
26 {
27 roomsMesh = RoomDaeReader.Read(roomsScene);
28
29 RoomBuilder.BuildRooms(roomsMesh);
30
31 Console.Error.WriteLine("Read {0} rooms", roomsMesh.Rooms.Count);
32
33 geometryOcttree = OctreeBuilder.Build(geometryMesh, GunkFlags.NoCollision | GunkFlags.NoCharacterCollision);
34 dangerOcttree = OctreeBuilder.Build(geometryMesh, p => (p.Flags & GunkFlags.Danger) != 0);
35
36 ProcessStairsCollision();
37
38 Parallel.ForEach(roomsMesh.Rooms, room =>
39 {
40 BuildGrid(room);
41 });
42 }
43
44 private void ProcessStairsCollision()
45 {
46 var verticalTolerance1 = new Vector3(0.0f, 0.1f, 0.0f);
47 var verticalTolerance2 = new Vector3(0.0f, 7.5f, 0.0f);
48
49 foreach (var stairs in geometryMesh.Polygons.Where(p => p.IsStairs && p.VertexCount == 4))
50 {
51 var floorPoints = stairs.Points.Select(v => v + verticalTolerance1).ToArray();
52 var ceilPoints = stairs.Points.Select(v => v + verticalTolerance2).ToArray();
53 var bbox = BoundingBox.CreateFromPoints(floorPoints.Concatenate(ceilPoints));
54
55 var floorPlane = new Plane(floorPoints[0], floorPoints[1], floorPoints[2]);
56 var ceilingPlane = new Plane(ceilPoints[0], ceilPoints[1], ceilPoints[2]);
57
58 foreach (var node in geometryOcttree.FindLeafs(bbox))
59 {
60 foreach (var poly in node.Polygons)
61 {
62 if ((poly.Flags & (GunkFlags.NoCollision | GunkFlags.NoCharacterCollision)) != 0)
63 {
64 //
65 // already a no collision polygon, skip it
66 //
67
68 continue;
69 }
70
71 if (!poly.BoundingBox.Intersects(bbox))
72 continue;
73
74 var points = poly.Points.ToList();
75
76 points = PolygonUtils.ClipToPlane(points, floorPlane);
77
78 if (points == null)
79 {
80 //
81 // this polygon is below stairs, skip it
82 //
83
84 continue;
85 }
86
87 points = PolygonUtils.ClipToPlane(points, ceilingPlane);
88
89 if (points != null)
90 {
91 //
92 // this polygon is too high above the stairs, skip it
93 //
94
95 continue;
96 }
97
98 poly.Flags |= GunkFlags.NoCharacterCollision;
99 }
100 }
101 }
102 }
103
104 private void BuildGrid(Room room)
105 {
106 var floor = room.FloorPolygon;
107 var bbox = room.BoundingBox;
108
109 //
110 // Create an empty grid and mark all tiles as 'danger'
111 //
112
113 var rasterizer = new RoomGridRasterizer(bbox);
114 rasterizer.Clear(RoomGridWeight.Danger);
115
116 //
117 // Collect all polygons that intersect the room
118 //
119
120 bbox.Inflate(2.0f * new Vector3(rasterizer.TileSize, 0.0f, rasterizer.TileSize));
121
122 var testbox = bbox;
123 testbox.Min.X -= 1.0f;
124 testbox.Min.Y = bbox.Min.Y - 6.0f;
125 testbox.Min.Z -= 1.0f;
126 testbox.Max.X += 1.0f;
127 testbox.Max.Y = bbox.Max.Y - 6.0f;
128 testbox.Max.Z += 1.0f;
129
130 var polygons = new Set<Polygon>();
131 var dangerPolygons = new Set<Polygon>();
132
133 foreach (var node in geometryOcttree.FindLeafs(testbox))
134 {
135 polygons.UnionWith(node.Polygons);
136 }
137
138 foreach (var node in dangerOcttree.FindLeafs(testbox))
139 {
140 dangerPolygons.UnionWith(node.Polygons);
141 }
142
143 //
144 // Draw all the floors on the grid. This will overwrite the 'danger'
145 // areas with 'clear' areas. This means danger area will remain
146 // where there isn't any floor.
147 //
148
149 foreach (var polygon in polygons)
150 {
151 if (polygon.Plane.Normal.Y > 0.5f)
152 rasterizer.DrawFloor(polygon.Points);
153 }
154
155 if (room.FloorPlane.Normal.Y >= 0.999f)
156 {
157 //
158 // Draw the walls.
159 //
160
161 float floorMaxY = floor.BoundingBox.Max.Y;
162 var floorPlane = new Plane(floor.Plane.Normal, floor.Plane.D - 4.0f);
163 var ceilingPlane = new Plane(-floor.Plane.Normal, -(floor.Plane.D - 20.0f));
164
165 foreach (var polygon in polygons)
166 {
167 if ((polygon.Flags & (GunkFlags.Stairs | GunkFlags.NoCharacterCollision | GunkFlags.Impassable)) == 0)
168 {
169 //
170 // Remove curbs from character collision.
171 //
172
173 var polyBox = polygon.BoundingBox;
174
175 if (Math.Abs(polygon.Plane.Normal.Y) < MathHelper.Eps
176 && polyBox.Height <= 4.0f
177 && Math.Abs(polyBox.Max.Y - floorMaxY) <= 4.0f)
178 {
179 polygon.Flags |= GunkFlags.NoCharacterCollision;
180 continue;
181 }
182 }
183
184 if ((polygon.Flags & (GunkFlags.Stairs | GunkFlags.GridIgnore | GunkFlags.NoCollision | GunkFlags.NoCharacterCollision)) != 0)
185 continue;
186
187 var points = polygon.Points.ToList();
188
189 points = PolygonUtils.ClipToPlane(points, floorPlane);
190
191 if (points == null)
192 continue;
193
194 points = PolygonUtils.ClipToPlane(points, ceilingPlane);
195
196 if (points == null)
197 continue;
198
199 if (Math.Abs(polygon.Plane.Normal.Y) <= 0.1f)
200 rasterizer.DrawWall(points);
201 else
202 rasterizer.DrawImpassable(points);
203 }
204
205 //
206 // Draw ramp entry/exit lines. Hmm, this seems useless.
207 //
208
209 //if (room.FloorPlane.Normal.Y >= 0.98f)
210 //{
211 // foreach (RoomAdjacency adj in room.Ajacencies)
212 // {
213 // if (Math.Abs(room.FloorPlane.Normal.Y - adj.AdjacentRoom.FloorPlane.Normal.Y) > 0.001f)
214 // rasterizer.DrawStairsEntry(adj.Ghost.Points);
215 // }
216 //}
217
218 //
219 // Draw 'danger' quads.
220 //
221
222 foreach (var polygon in dangerPolygons)
223 {
224 rasterizer.DrawDanger(polygon.Points);
225 }
226
227 //
228 // Draw 'near wall' borders.
229 //
230
231 rasterizer.AddBorders();
232 }
233
234 //
235 // Finally, get the rasterized pathfinding grid.
236 //
237
238 room.Grid = rasterizer.GetGrid();
239
240 if (room.Grid.XTiles * room.Grid.ZTiles > 256 * 256)
241 Console.Error.WriteLine("Warning: pathfinding grid too large");
242 }
243 }
244}
Note: See TracBrowser for help on using the repository browser.