| 1 | using System; | 
 
 
 
 
 | 2 | using System.Collections.Generic; | 
 
 
 
 
 | 3 | using Oni.Imaging; | 
 
 
 
 
 | 4 |  | 
 
 
 
 
 | 5 | namespace Oni.Akira | 
 
 
 
 
 | 6 | { | 
 
 
 
 
 | 7 | internal class Polygon | 
 
 
 
 
 | 8 | { | 
 
 
 
 
 | 9 | #region Private data | 
 
 
 
 
 | 10 | private PolygonMesh mesh; | 
 
 
 
 
 | 11 | private GunkFlags flags; | 
 
 
 
 
 | 12 | private int[] pointIndices; | 
 
 
 
 
 | 13 | private int[] texCoordIndices; | 
 
 
 
 
 | 14 | private int[] normalIndices; | 
 
 
 
 
 | 15 | private Color[] colors; | 
 
 
 
 
 | 16 | private Material material; | 
 
 
 
 
 | 17 | private Plane plane; | 
 
 
 
 
 | 18 | private int objectType = -1; | 
 
 
 
 
 | 19 | private int objectId = -1; | 
 
 
 
 
 | 20 | private int scriptId; | 
 
 
 
 
 | 21 | private string fileName; | 
 
 
 
 
 | 22 | private string objectName; | 
 
 
 
 
 | 23 | private PolygonEdge[] edges; | 
 
 
 
 
 | 24 | private BoundingBox bbox; | 
 
 
 
 
 | 25 | #endregion | 
 
 
 
 
 | 26 |  | 
 
 
 
 
 | 27 | public Polygon(PolygonMesh mesh, int[] pointIndices) | 
 
 
 
 
 | 28 | { | 
 
 
 
 
 | 29 | this.mesh = mesh; | 
 
 
 
 
 | 30 | this.pointIndices = pointIndices; | 
 
 
 
 
 | 31 | this.plane = GetPlane(); | 
 
 
 
 
 | 32 | this.bbox = GetBoundingBox(); | 
 
 
 
 
 | 33 |  | 
 
 
 
 
 | 34 | BuildFlags(); | 
 
 
 
 
 | 35 | } | 
 
 
 
 
 | 36 |  | 
 
 
 
 
 | 37 | public Polygon(PolygonMesh mesh, int[] pointIndices, GunkFlags flags) | 
 
 
 
 
 | 38 | : this(mesh, pointIndices) | 
 
 
 
 
 | 39 | { | 
 
 
 
 
 | 40 | this.flags |= flags; | 
 
 
 
 
 | 41 | } | 
 
 
 
 
 | 42 |  | 
 
 
 
 
 | 43 | public Polygon(PolygonMesh mesh, int[] pointIndices, Plane plane) | 
 
 
 
 
 | 44 | { | 
 
 
 
 
 | 45 | this.mesh = mesh; | 
 
 
 
 
 | 46 | this.pointIndices = pointIndices; | 
 
 
 
 
 | 47 | this.plane = plane; | 
 
 
 
 
 | 48 |  | 
 
 
 
 
 | 49 | BuildFlags(); | 
 
 
 
 
 | 50 | } | 
 
 
 
 
 | 51 |  | 
 
 
 
 
 | 52 | public PolygonMesh Mesh => mesh; | 
 
 
 
 
 | 53 |  | 
 
 
 
 
 | 54 | public GunkFlags Flags | 
 
 
 
 
 | 55 | { | 
 
 
 
 
 | 56 | get | 
 
 
 
 
 | 57 | { | 
 
 
 
 
 | 58 | if (material == null) | 
 
 
 
 
 | 59 | return flags; | 
 
 
 
 
 | 60 |  | 
 
 
 
 
 | 61 | return flags | material.Flags; | 
 
 
 
 
 | 62 | } | 
 
 
 
 
 | 63 | set | 
 
 
 
 
 | 64 | { | 
 
 
 
 
 | 65 | flags = value; | 
 
 
 
 
 | 66 | } | 
 
 
 
 
 | 67 | } | 
 
 
 
 
 | 68 |  | 
 
 
 
 
 | 69 | public bool IsTransparent => (Flags & GunkFlags.Transparent) != 0; | 
 
 
 
 
 | 70 | public bool IsStairs=>(Flags & GunkFlags.Stairs) != 0; | 
 
 
 
 
 | 71 |  | 
 
 
 
 
 | 72 | public Material Material | 
 
 
 
 
 | 73 | { | 
 
 
 
 
 | 74 | get { return material; } | 
 
 
 
 
 | 75 | set { material = value; } | 
 
 
 
 
 | 76 | } | 
 
 
 
 
 | 77 |  | 
 
 
 
 
 | 78 | public int VertexCount => pointIndices.Length; | 
 
 
 
 
 | 79 |  | 
 
 
 
 
 | 80 | public int[] PointIndices => pointIndices; | 
 
 
 
 
 | 81 |  | 
 
 
 
 
 | 82 | public IEnumerable<Vector3> Points | 
 
 
 
 
 | 83 | { | 
 
 
 
 
 | 84 | get | 
 
 
 
 
 | 85 | { | 
 
 
 
 
 | 86 | foreach (int i in pointIndices) | 
 
 
 
 
 | 87 | yield return mesh.Points[i]; | 
 
 
 
 
 | 88 | } | 
 
 
 
 
 | 89 | } | 
 
 
 
 
 | 90 |  | 
 
 
 
 
 | 91 | public int[] TexCoordIndices | 
 
 
 
 
 | 92 | { | 
 
 
 
 
 | 93 | get { return texCoordIndices; } | 
 
 
 
 
 | 94 | set { texCoordIndices = value; } | 
 
 
 
 
 | 95 | } | 
 
 
 
 
 | 96 |  | 
 
 
 
 
 | 97 | public int[] NormalIndices | 
 
 
 
 
 | 98 | { | 
 
 
 
 
 | 99 | get { return normalIndices; } | 
 
 
 
 
 | 100 | set { normalIndices = value; } | 
 
 
 
 
 | 101 | } | 
 
 
 
 
 | 102 |  | 
 
 
 
 
 | 103 | public Color[] Colors | 
 
 
 
 
 | 104 | { | 
 
 
 
 
 | 105 | get { return colors; } | 
 
 
 
 
 | 106 | set { colors = value; } | 
 
 
 
 
 | 107 | } | 
 
 
 
 
 | 108 |  | 
 
 
 
 
 | 109 | public Plane Plane => plane; | 
 
 
 
 
 | 110 |  | 
 
 
 
 
 | 111 | public int ObjectType | 
 
 
 
 
 | 112 | { | 
 
 
 
 
 | 113 | get { return objectType; } | 
 
 
 
 
 | 114 | set { objectType = value; } | 
 
 
 
 
 | 115 | } | 
 
 
 
 
 | 116 |  | 
 
 
 
 
 | 117 | public int ObjectId | 
 
 
 
 
 | 118 | { | 
 
 
 
 
 | 119 | get { return objectId; } | 
 
 
 
 
 | 120 | set { objectId = value; } | 
 
 
 
 
 | 121 | } | 
 
 
 
 
 | 122 |  | 
 
 
 
 
 | 123 | public int ScriptId | 
 
 
 
 
 | 124 | { | 
 
 
 
 
 | 125 | get { return scriptId; } | 
 
 
 
 
 | 126 | set { scriptId = value; } | 
 
 
 
 
 | 127 | } | 
 
 
 
 
 | 128 |  | 
 
 
 
 
 | 129 | public string FileName | 
 
 
 
 
 | 130 | { | 
 
 
 
 
 | 131 | get { return fileName; } | 
 
 
 
 
 | 132 | set { fileName = value; } | 
 
 
 
 
 | 133 | } | 
 
 
 
 
 | 134 |  | 
 
 
 
 
 | 135 | public string ObjectName | 
 
 
 
 
 | 136 | { | 
 
 
 
 
 | 137 | get { return objectName; } | 
 
 
 
 
 | 138 | set { objectName = value; } | 
 
 
 
 
 | 139 | } | 
 
 
 
 
 | 140 |  | 
 
 
 
 
 | 141 | private Plane GetPlane() | 
 
 
 
 
 | 142 | { | 
 
 
 
 
 | 143 | var plane = new Plane( | 
 
 
 
 
 | 144 | mesh.Points[pointIndices[0]], | 
 
 
 
 
 | 145 | mesh.Points[pointIndices[1]], | 
 
 
 
 
 | 146 | mesh.Points[pointIndices[2]]); | 
 
 
 
 
 | 147 |  | 
 
 
 
 
 | 148 | var bbox = GetBoundingBox(); | 
 
 
 
 
 | 149 | var bboxSize = bbox.Max - bbox.Min; | 
 
 
 
 
 | 150 |  | 
 
 
 
 
 | 151 | if (Math.Abs(bboxSize.X) < 0.0001f) | 
 
 
 
 
 | 152 | { | 
 
 
 
 
 | 153 | if (plane.Normal.X < 0.0f) | 
 
 
 
 
 | 154 | plane = new Plane(Vector3.Left, bbox.Min.X); | 
 
 
 
 
 | 155 | else | 
 
 
 
 
 | 156 | plane = new Plane(Vector3.Right, -bbox.Max.X); | 
 
 
 
 
 | 157 | } | 
 
 
 
 
 | 158 | else if (Math.Abs(bboxSize.Y) < 0.0001f) | 
 
 
 
 
 | 159 | { | 
 
 
 
 
 | 160 | if (plane.Normal.Y < 0.0f) | 
 
 
 
 
 | 161 | plane = new Plane(Vector3.Down, bbox.Min.Y); | 
 
 
 
 
 | 162 | else | 
 
 
 
 
 | 163 | plane = new Plane(Vector3.Up, -bbox.Max.Y); | 
 
 
 
 
 | 164 | } | 
 
 
 
 
 | 165 | else if (Math.Abs(bboxSize.Z) < 0.0001f) | 
 
 
 
 
 | 166 | { | 
 
 
 
 
 | 167 | if (plane.Normal.Z < 0.0f) | 
 
 
 
 
 | 168 | plane = new Plane(Vector3.Forward, bbox.Min.Z); | 
 
 
 
 
 | 169 | else | 
 
 
 
 
 | 170 | plane = new Plane(Vector3.Backward, -bbox.Max.Z); | 
 
 
 
 
 | 171 | } | 
 
 
 
 
 | 172 | else | 
 
 
 
 
 | 173 | { | 
 
 
 
 
 | 174 | plane.Normal.X = FMath.Round(plane.Normal.X, 4); | 
 
 
 
 
 | 175 | plane.Normal.Y = FMath.Round(plane.Normal.Y, 4); | 
 
 
 
 
 | 176 | plane.Normal.Z = FMath.Round(plane.Normal.Z, 4); | 
 
 
 
 
 | 177 | } | 
 
 
 
 
 | 178 |  | 
 
 
 
 
 | 179 | return plane; | 
 
 
 
 
 | 180 | } | 
 
 
 
 
 | 181 |  | 
 
 
 
 
 | 182 | public BoundingBox BoundingBox => bbox; | 
 
 
 
 
 | 183 |  | 
 
 
 
 
 | 184 | private BoundingBox GetBoundingBox() | 
 
 
 
 
 | 185 | { | 
 
 
 
 
 | 186 | var point = mesh.Points[pointIndices[0]]; | 
 
 
 
 
 | 187 | var bbox = new BoundingBox(point, point); | 
 
 
 
 
 | 188 |  | 
 
 
 
 
 | 189 | for (int i = 1; i < pointIndices.Length; i++) | 
 
 
 
 
 | 190 | { | 
 
 
 
 
 | 191 | point = mesh.Points[pointIndices[i]]; | 
 
 
 
 
 | 192 |  | 
 
 
 
 
 | 193 | Vector3.Min(ref bbox.Min, ref point, out bbox.Min); | 
 
 
 
 
 | 194 | Vector3.Max(ref bbox.Max, ref point, out bbox.Max); | 
 
 
 
 
 | 195 | } | 
 
 
 
 
 | 196 |  | 
 
 
 
 
 | 197 | return bbox; | 
 
 
 
 
 | 198 | } | 
 
 
 
 
 | 199 |  | 
 
 
 
 
 | 200 | private void BuildFlags() | 
 
 
 
 
 | 201 | { | 
 
 
 
 
 | 202 | SetProjectionPlane(); | 
 
 
 
 
 | 203 | SetHorizontalVertical(); | 
 
 
 
 
 | 204 | } | 
 
 
 
 
 | 205 |  | 
 
 
 
 
 | 206 | private void SetHorizontalVertical() | 
 
 
 
 
 | 207 | { | 
 
 
 
 
 | 208 | if (Math.Abs(Vector3.Dot(plane.Normal, Vector3.UnitY)) < 0.3420201f) | 
 
 
 
 
 | 209 | flags |= GunkFlags.Vertical; | 
 
 
 
 
 | 210 | else | 
 
 
 
 
 | 211 | flags |= GunkFlags.Horizontal; | 
 
 
 
 
 | 212 | } | 
 
 
 
 
 | 213 |  | 
 
 
 
 
 | 214 | private void SetProjectionPlane() | 
 
 
 
 
 | 215 | { | 
 
 
 
 
 | 216 | var points = new Vector3[pointIndices.Length]; | 
 
 
 
 
 | 217 |  | 
 
 
 
 
 | 218 | for (int i = 0; i < pointIndices.Length; i++) | 
 
 
 
 
 | 219 | points[i] = mesh.Points[pointIndices[i]]; | 
 
 
 
 
 | 220 |  | 
 
 
 
 
 | 221 | float xyArea = MathHelper.Area(Project(points, PolygonProjectionPlane.XY)); | 
 
 
 
 
 | 222 | float yzArea = MathHelper.Area(Project(points, PolygonProjectionPlane.YZ)); | 
 
 
 
 
 | 223 | float xzArea = MathHelper.Area(Project(points, PolygonProjectionPlane.XZ)); | 
 
 
 
 
 | 224 |  | 
 
 
 
 
 | 225 | var plane = PolygonProjectionPlane.None; | 
 
 
 
 
 | 226 |  | 
 
 
 
 
 | 227 | if (xyArea > yzArea) | 
 
 
 
 
 | 228 | { | 
 
 
 
 
 | 229 | if (xyArea > xzArea) | 
 
 
 
 
 | 230 | plane = PolygonProjectionPlane.XY; | 
 
 
 
 
 | 231 | else | 
 
 
 
 
 | 232 | plane = PolygonProjectionPlane.XZ; | 
 
 
 
 
 | 233 | } | 
 
 
 
 
 | 234 | else | 
 
 
 
 
 | 235 | { | 
 
 
 
 
 | 236 | if (yzArea > xzArea) | 
 
 
 
 
 | 237 | plane = PolygonProjectionPlane.YZ; | 
 
 
 
 
 | 238 | else | 
 
 
 
 
 | 239 | plane = PolygonProjectionPlane.XZ; | 
 
 
 
 
 | 240 | } | 
 
 
 
 
 | 241 |  | 
 
 
 
 
 | 242 | flags |= (GunkFlags)((int)plane << 25); | 
 
 
 
 
 | 243 | } | 
 
 
 
 
 | 244 |  | 
 
 
 
 
 | 245 | private static Vector2[] Project(Vector3[] points, PolygonProjectionPlane plane) | 
 
 
 
 
 | 246 | { | 
 
 
 
 
 | 247 | var result = new Vector2[points.Length]; | 
 
 
 
 
 | 248 |  | 
 
 
 
 
 | 249 | switch (plane) | 
 
 
 
 
 | 250 | { | 
 
 
 
 
 | 251 | case PolygonProjectionPlane.XY: | 
 
 
 
 
 | 252 | for (int i = 0; i < points.Length; i++) | 
 
 
 
 
 | 253 | { | 
 
 
 
 
 | 254 | result[i].X = points[i].X; | 
 
 
 
 
 | 255 | result[i].Y = points[i].Y; | 
 
 
 
 
 | 256 | } | 
 
 
 
 
 | 257 | break; | 
 
 
 
 
 | 258 | case PolygonProjectionPlane.XZ: | 
 
 
 
 
 | 259 | for (int i = 0; i < points.Length; i++) | 
 
 
 
 
 | 260 | { | 
 
 
 
 
 | 261 | result[i].X = points[i].X; | 
 
 
 
 
 | 262 | result[i].Y = points[i].Z; | 
 
 
 
 
 | 263 | } | 
 
 
 
 
 | 264 | break; | 
 
 
 
 
 | 265 | case PolygonProjectionPlane.YZ: | 
 
 
 
 
 | 266 | for (int i = 0; i < points.Length; i++) | 
 
 
 
 
 | 267 | { | 
 
 
 
 
 | 268 | result[i].X = points[i].Z; | 
 
 
 
 
 | 269 | result[i].Y = points[i].Y; | 
 
 
 
 
 | 270 | } | 
 
 
 
 
 | 271 | break; | 
 
 
 
 
 | 272 | } | 
 
 
 
 
 | 273 |  | 
 
 
 
 
 | 274 | return result; | 
 
 
 
 
 | 275 | } | 
 
 
 
 
 | 276 |  | 
 
 
 
 
 | 277 | public PolygonEdge[] Edges | 
 
 
 
 
 | 278 | { | 
 
 
 
 
 | 279 | get | 
 
 
 
 
 | 280 | { | 
 
 
 
 
 | 281 | if (edges == null) | 
 
 
 
 
 | 282 | { | 
 
 
 
 
 | 283 | edges = new PolygonEdge[pointIndices.Length]; | 
 
 
 
 
 | 284 |  | 
 
 
 
 
 | 285 | for (int i = 0; i < edges.Length; i++) | 
 
 
 
 
 | 286 | edges[i] = new PolygonEdge(this, i); | 
 
 
 
 
 | 287 | } | 
 
 
 
 
 | 288 |  | 
 
 
 
 
 | 289 | return edges; | 
 
 
 
 
 | 290 | } | 
 
 
 
 
 | 291 | } | 
 
 
 
 
 | 292 | } | 
 
 
 
 
 | 293 | } |