| 1 | using System; | 
 
 
 
 
 | 2 | using System.Collections.Generic; | 
 
 
 
 
 | 3 |  | 
 
 
 
 
 | 4 | namespace Oni.Motoko | 
 
 
 
 
 | 5 | { | 
 
 
 
 
 | 6 | internal class Stripify | 
 
 
 
 
 | 7 | { | 
 
 
 
 
 | 8 | private const int BeginStrip = int.MinValue; | 
 
 
 
 
 | 9 | private int[] tlist; | 
 
 
 
 
 | 10 | private int[] adjacency; | 
 
 
 
 
 | 11 | private int[] degree; | 
 
 
 
 
 | 12 | private List<int> strips; | 
 
 
 
 
 | 13 | private bool[] used; | 
 
 
 
 
 | 14 |  | 
 
 
 
 
 | 15 | public static int[] FromTriangleList(int[] triangleList) | 
 
 
 
 
 | 16 | { | 
 
 
 
 
 | 17 | var triStrips = new Stripify(triangleList); | 
 
 
 
 
 | 18 | return triStrips.Run(); | 
 
 
 
 
 | 19 | } | 
 
 
 
 
 | 20 |  | 
 
 
 
 
 | 21 | public static int[] ToTriangleList(int[] triangleStrips) | 
 
 
 
 
 | 22 | { | 
 
 
 
 
 | 23 | int triangleCount = 0; | 
 
 
 
 
 | 24 |  | 
 
 
 
 
 | 25 | for (int i = 0; i < triangleStrips.Length; i++) | 
 
 
 
 
 | 26 | { | 
 
 
 
 
 | 27 | triangleCount++; | 
 
 
 
 
 | 28 |  | 
 
 
 
 
 | 29 | if (triangleStrips[i] < 0) | 
 
 
 
 
 | 30 | triangleCount -= 2; | 
 
 
 
 
 | 31 | } | 
 
 
 
 
 | 32 |  | 
 
 
 
 
 | 33 | var triangles = new int[triangleCount * 3]; | 
 
 
 
 
 | 34 | int pos = 0; | 
 
 
 
 
 | 35 | var face = new int[3]; | 
 
 
 
 
 | 36 | int order = 0; | 
 
 
 
 
 | 37 |  | 
 
 
 
 
 | 38 | for (int i = 0; i < triangleStrips.Length; i++) | 
 
 
 
 
 | 39 | { | 
 
 
 
 
 | 40 | if (triangleStrips[i] < 0) | 
 
 
 
 
 | 41 | { | 
 
 
 
 
 | 42 | face[0] = triangleStrips[i] & int.MaxValue; | 
 
 
 
 
 | 43 | i++; | 
 
 
 
 
 | 44 | face[1] = triangleStrips[i]; | 
 
 
 
 
 | 45 | i++; | 
 
 
 
 
 | 46 | order = 0; | 
 
 
 
 
 | 47 | } | 
 
 
 
 
 | 48 | else | 
 
 
 
 
 | 49 | { | 
 
 
 
 
 | 50 | face[order] = face[2]; | 
 
 
 
 
 | 51 | order = (order + 1) % 2; | 
 
 
 
 
 | 52 | } | 
 
 
 
 
 | 53 |  | 
 
 
 
 
 | 54 | face[2] = triangleStrips[i]; | 
 
 
 
 
 | 55 |  | 
 
 
 
 
 | 56 | Array.Copy(face, 0, triangles, pos, 3); | 
 
 
 
 
 | 57 | pos += 3; | 
 
 
 
 
 | 58 | } | 
 
 
 
 
 | 59 |  | 
 
 
 
 
 | 60 | return triangles; | 
 
 
 
 
 | 61 | } | 
 
 
 
 
 | 62 |  | 
 
 
 
 
 | 63 | private Stripify(int[] triangleList) | 
 
 
 
 
 | 64 | { | 
 
 
 
 
 | 65 | tlist = triangleList; | 
 
 
 
 
 | 66 | } | 
 
 
 
 
 | 67 |  | 
 
 
 
 
 | 68 | private int[] Run() | 
 
 
 
 
 | 69 | { | 
 
 
 
 
 | 70 | strips = new List<int>(); | 
 
 
 
 
 | 71 |  | 
 
 
 
 
 | 72 | GenerateAdjacency(); | 
 
 
 
 
 | 73 |  | 
 
 
 
 
 | 74 | while (GenerateStrip()) | 
 
 
 
 
 | 75 | ; | 
 
 
 
 
 | 76 |  | 
 
 
 
 
 | 77 | // | 
 
 
 
 
 | 78 | // Generate 1 triangle long strips for all triangles that were not included | 
 
 
 
 
 | 79 | // in triangle strips | 
 
 
 
 
 | 80 | // | 
 
 
 
 
 | 81 |  | 
 
 
 
 
 | 82 | for (int i = 0; i < degree.Length; i++) | 
 
 
 
 
 | 83 | { | 
 
 
 
 
 | 84 | if (!used[i]) | 
 
 
 
 
 | 85 | { | 
 
 
 
 
 | 86 | int j = i * 3; | 
 
 
 
 
 | 87 |  | 
 
 
 
 
 | 88 | strips.Add(tlist[j + 0] | BeginStrip); | 
 
 
 
 
 | 89 | strips.Add(tlist[j + 1]); | 
 
 
 
 
 | 90 | strips.Add(tlist[j + 2]); | 
 
 
 
 
 | 91 |  | 
 
 
 
 
 | 92 | used[i] = true; | 
 
 
 
 
 | 93 | } | 
 
 
 
 
 | 94 | } | 
 
 
 
 
 | 95 |  | 
 
 
 
 
 | 96 | return strips.ToArray(); | 
 
 
 
 
 | 97 | } | 
 
 
 
 
 | 98 |  | 
 
 
 
 
 | 99 | private bool GenerateStrip() | 
 
 
 
 
 | 100 | { | 
 
 
 
 
 | 101 | int current = -1; | 
 
 
 
 
 | 102 |  | 
 
 
 
 
 | 103 | int minDegree = 4; | 
 
 
 
 
 | 104 | int minAdjacentDegree = 4; | 
 
 
 
 
 | 105 |  | 
 
 
 
 
 | 106 | // | 
 
 
 
 
 | 107 | // Find a triangle to start with. The triangle with the lowest degree | 
 
 
 
 
 | 108 | // is picked as a start triangle. If multiple triangles have the same | 
 
 
 
 
 | 109 | // degree then the adjacent triangles are checked for lowest degree. | 
 
 
 
 
 | 110 | // | 
 
 
 
 
 | 111 |  | 
 
 
 
 
 | 112 | for (int t = 0; t < degree.Length; t++) | 
 
 
 
 
 | 113 | { | 
 
 
 
 
 | 114 | if (used[t] || degree[t] == 0) | 
 
 
 
 
 | 115 | continue; | 
 
 
 
 
 | 116 |  | 
 
 
 
 
 | 117 | if (degree[t] < minDegree) | 
 
 
 
 
 | 118 | { | 
 
 
 
 
 | 119 | minDegree = degree[t]; | 
 
 
 
 
 | 120 | minAdjacentDegree = 4; | 
 
 
 
 
 | 121 | current = t; | 
 
 
 
 
 | 122 | } | 
 
 
 
 
 | 123 | else if (degree[t] == minDegree) | 
 
 
 
 
 | 124 | { | 
 
 
 
 
 | 125 | // | 
 
 
 
 
 | 126 | // We have 2 candidates for a start triangle with the same degree. | 
 
 
 
 
 | 127 | // Check their neighbours for lowest degree to decide which candidate to use. | 
 
 
 
 
 | 128 | // | 
 
 
 
 
 | 129 |  | 
 
 
 
 
 | 130 | for (int k = 0; k < 3; k++) | 
 
 
 
 
 | 131 | { | 
 
 
 
 
 | 132 | int a = adjacency[t * 3 + k]; | 
 
 
 
 
 | 133 |  | 
 
 
 
 
 | 134 | if (a == -1 || used[a] || degree[a] == 0) | 
 
 
 
 
 | 135 | continue; | 
 
 
 
 
 | 136 |  | 
 
 
 
 
 | 137 | if (degree[a] < minAdjacentDegree) | 
 
 
 
 
 | 138 | { | 
 
 
 
 
 | 139 | minAdjacentDegree = degree[a]; | 
 
 
 
 
 | 140 | current = t; | 
 
 
 
 
 | 141 | } | 
 
 
 
 
 | 142 | } | 
 
 
 
 
 | 143 | } | 
 
 
 
 
 | 144 | } | 
 
 
 
 
 | 145 |  | 
 
 
 
 
 | 146 | if (current == -1) | 
 
 
 
 
 | 147 | { | 
 
 
 
 
 | 148 | // | 
 
 
 
 
 | 149 | // A start triangle cannot be found. Either there are no more unused triangles left | 
 
 
 
 
 | 150 | // or all remaining triangles have degree = 0. | 
 
 
 
 
 | 151 | // | 
 
 
 
 
 | 152 |  | 
 
 
 
 
 | 153 | return false; | 
 
 
 
 
 | 154 | } | 
 
 
 
 
 | 155 |  | 
 
 
 
 
 | 156 | UseTriangle(current); | 
 
 
 
 
 | 157 |  | 
 
 
 
 
 | 158 | // | 
 
 
 
 
 | 159 | // Find a triangle adjacent to the start triangle so we can decide | 
 
 
 
 
 | 160 | // on a vertex order for the start triangle. If there are multiple | 
 
 
 
 
 | 161 | // adjacent triangles the one with lowest degree is used. | 
 
 
 
 
 | 162 | // | 
 
 
 
 
 | 163 |  | 
 
 
 
 
 | 164 | int next = -1; | 
 
 
 
 
 | 165 | int edge = 0; | 
 
 
 
 
 | 166 |  | 
 
 
 
 
 | 167 | minDegree = 4; | 
 
 
 
 
 | 168 |  | 
 
 
 
 
 | 169 | for (int e = 0; e < 3; e++) | 
 
 
 
 
 | 170 | { | 
 
 
 
 
 | 171 | int a = adjacency[current * 3 + e]; | 
 
 
 
 
 | 172 |  | 
 
 
 
 
 | 173 | if (a == -1 || used[a]) | 
 
 
 
 
 | 174 | continue; | 
 
 
 
 
 | 175 |  | 
 
 
 
 
 | 176 | // | 
 
 
 
 
 | 177 | // NOTE: Don't check for degree = 0. The previous UseTriangle(current) can make | 
 
 
 
 
 | 178 | // adjacent triangles have a 0 degree. It works because all we are interested in | 
 
 
 
 
 | 179 | // is which adjacent triangle has the lowest degree. | 
 
 
 
 
 | 180 | // | 
 
 
 
 
 | 181 |  | 
 
 
 
 
 | 182 | if (degree[a] < minDegree) | 
 
 
 
 
 | 183 | { | 
 
 
 
 
 | 184 | minDegree = degree[a]; | 
 
 
 
 
 | 185 | next = a; | 
 
 
 
 
 | 186 | edge = e; | 
 
 
 
 
 | 187 | } | 
 
 
 
 
 | 188 | } | 
 
 
 
 
 | 189 |  | 
 
 
 
 
 | 190 | // | 
 
 
 
 
 | 191 | // Begin a new triangle strip | 
 
 
 
 
 | 192 | // | 
 
 
 
 
 | 193 |  | 
 
 
 
 
 | 194 | var triangle = new int[3]; | 
 
 
 
 
 | 195 |  | 
 
 
 
 
 | 196 | triangle[0] = tlist[(current * 3) + (edge + 2) % 3]; | 
 
 
 
 
 | 197 | triangle[1] = tlist[(current * 3) + (edge + 0) % 3]; | 
 
 
 
 
 | 198 | triangle[2] = tlist[(current * 3) + (edge + 1) % 3]; | 
 
 
 
 
 | 199 |  | 
 
 
 
 
 | 200 | strips.Add(triangle[0] | BeginStrip); | 
 
 
 
 
 | 201 | strips.Add(triangle[1]); | 
 
 
 
 
 | 202 | strips.Add(triangle[2]); | 
 
 
 
 
 | 203 |  | 
 
 
 
 
 | 204 | // | 
 
 
 
 
 | 205 | // Continue the triangle strip as long as possible | 
 
 
 
 
 | 206 | // | 
 
 
 
 
 | 207 |  | 
 
 
 
 
 | 208 | int order = 0; | 
 
 
 
 
 | 209 |  | 
 
 
 
 
 | 210 | while (next != -1) | 
 
 
 
 
 | 211 | { | 
 
 
 
 
 | 212 | UseTriangle(next); | 
 
 
 
 
 | 213 |  | 
 
 
 
 
 | 214 | triangle[0] = triangle[1 + order]; | 
 
 
 
 
 | 215 |  | 
 
 
 
 
 | 216 | // | 
 
 
 
 
 | 217 | // Search an edge in triangle "next" that matches the "exit" edge of triangle "current" | 
 
 
 
 
 | 218 | // | 
 
 
 
 
 | 219 |  | 
 
 
 
 
 | 220 | for (int v = 0; v < 3; v++) | 
 
 
 
 
 | 221 | { | 
 
 
 
 
 | 222 | int t = next * 3; | 
 
 
 
 
 | 223 |  | 
 
 
 
 
 | 224 | if (tlist[t + v] == triangle[(2 + order) % 3] && tlist[t + (v + 1) % 3] == triangle[order]) | 
 
 
 
 
 | 225 | { | 
 
 
 
 
 | 226 | edge = (v + 2 - order) % 3; | 
 
 
 
 
 | 227 | triangle[1 + order] = tlist[t + (v + 2) % 3]; | 
 
 
 
 
 | 228 | break; | 
 
 
 
 
 | 229 | } | 
 
 
 
 
 | 230 | } | 
 
 
 
 
 | 231 |  | 
 
 
 
 
 | 232 | strips.Add(triangle[1 + order]); | 
 
 
 
 
 | 233 |  | 
 
 
 
 
 | 234 | // | 
 
 
 
 
 | 235 | // Replace "current" with "next" and find a "next" triangle that is adjacent with "current" | 
 
 
 
 
 | 236 | // | 
 
 
 
 
 | 237 |  | 
 
 
 
 
 | 238 | current = next; | 
 
 
 
 
 | 239 | next = adjacency[current * 3 + edge]; | 
 
 
 
 
 | 240 |  | 
 
 
 
 
 | 241 | if (next == -1 || used[next]) | 
 
 
 
 
 | 242 | break; | 
 
 
 
 
 | 243 |  | 
 
 
 
 
 | 244 | UseTriangle(next); | 
 
 
 
 
 | 245 |  | 
 
 
 
 
 | 246 | // | 
 
 
 
 
 | 247 | // Alternate vertex ordering | 
 
 
 
 
 | 248 | // | 
 
 
 
 
 | 249 |  | 
 
 
 
 
 | 250 | order = (order + 1) % 2; | 
 
 
 
 
 | 251 | } | 
 
 
 
 
 | 252 |  | 
 
 
 
 
 | 253 | return true; | 
 
 
 
 
 | 254 | } | 
 
 
 
 
 | 255 |  | 
 
 
 
 
 | 256 | private void UseTriangle(int t) | 
 
 
 
 
 | 257 | { | 
 
 
 
 
 | 258 | degree[t] = 0; | 
 
 
 
 
 | 259 | used[t] = true; | 
 
 
 
 
 | 260 |  | 
 
 
 
 
 | 261 | // | 
 
 
 
 
 | 262 | // Decrease the degree of all adjacent triangles by 1. | 
 
 
 
 
 | 263 | // | 
 
 
 
 
 | 264 |  | 
 
 
 
 
 | 265 | for (int e = 0; e < 3; e++) | 
 
 
 
 
 | 266 | { | 
 
 
 
 
 | 267 | int a = adjacency[t * 3 + e]; | 
 
 
 
 
 | 268 |  | 
 
 
 
 
 | 269 | if (a != -1 && degree[a] > 0) | 
 
 
 
 
 | 270 | degree[a]--; | 
 
 
 
 
 | 271 | } | 
 
 
 
 
 | 272 | } | 
 
 
 
 
 | 273 |  | 
 
 
 
 
 | 274 | #region private struct Edge | 
 
 
 
 
 | 275 |  | 
 
 
 
 
 | 276 | private struct Edge : IEquatable<Edge> | 
 
 
 
 
 | 277 | { | 
 
 
 
 
 | 278 | public readonly int V1; | 
 
 
 
 
 | 279 | public readonly int V2; | 
 
 
 
 
 | 280 |  | 
 
 
 
 
 | 281 | public Edge(int V1, int V2) | 
 
 
 
 
 | 282 | { | 
 
 
 
 
 | 283 | this.V1 = V1; | 
 
 
 
 
 | 284 | this.V2 = V2; | 
 
 
 
 
 | 285 | } | 
 
 
 
 
 | 286 |  | 
 
 
 
 
 | 287 | public static bool operator ==(Edge e1, Edge e2) => e1.V1 == e2.V1 && e1.V2 == e2.V2; | 
 
 
 
 
 | 288 | public static bool operator !=(Edge e1, Edge e2) => e1.V1 != e2.V1 || e1.V2 != e2.V2; | 
 
 
 
 
 | 289 | public bool Equals(Edge edge) => V1 == edge.V1 && V2 == edge.V2; | 
 
 
 
 
 | 290 | public override bool Equals(object obj) => obj is Edge && Equals((Edge)obj); | 
 
 
 
 
 | 291 | public override int GetHashCode() => V1 ^ V2; | 
 
 
 
 
 | 292 | } | 
 
 
 
 
 | 293 |  | 
 
 
 
 
 | 294 | #endregion | 
 
 
 
 
 | 295 |  | 
 
 
 
 
 | 296 | private void GenerateAdjacency() | 
 
 
 
 
 | 297 | { | 
 
 
 
 
 | 298 | adjacency = new int[tlist.Length]; | 
 
 
 
 
 | 299 | degree = new int[tlist.Length / 3]; | 
 
 
 
 
 | 300 | used = new bool[tlist.Length / 3]; | 
 
 
 
 
 | 301 |  | 
 
 
 
 
 | 302 | for (int i = 0; i < adjacency.Length; i++) | 
 
 
 
 
 | 303 | adjacency[i] = -1; | 
 
 
 
 
 | 304 |  | 
 
 
 
 
 | 305 | // | 
 
 
 
 
 | 306 | // Store all the edges in a dictionary for easier lookup | 
 
 
 
 
 | 307 | // | 
 
 
 
 
 | 308 |  | 
 
 
 
 
 | 309 | var edges = new Dictionary<Edge, int>(); | 
 
 
 
 
 | 310 |  | 
 
 
 
 
 | 311 | for (int t = 0; t < tlist.Length; t += 3) | 
 
 
 
 
 | 312 | { | 
 
 
 
 
 | 313 | for (int v = 0; v < 3; v++) | 
 
 
 
 
 | 314 | { | 
 
 
 
 
 | 315 | var edge = new Edge(tlist[t + v], tlist[t + (v + 1) % 3]); | 
 
 
 
 
 | 316 |  | 
 
 
 
 
 | 317 | edges[edge] = t / 3; | 
 
 
 
 
 | 318 | } | 
 
 
 
 
 | 319 | } | 
 
 
 
 
 | 320 |  | 
 
 
 
 
 | 321 | // | 
 
 
 
 
 | 322 | // Fill the adjacency array | 
 
 
 
 
 | 323 | // | 
 
 
 
 
 | 324 |  | 
 
 
 
 
 | 325 | for (int t = 0; t < tlist.Length; t += 3) | 
 
 
 
 
 | 326 | { | 
 
 
 
 
 | 327 | for (int e = 0; e < 3; e++) | 
 
 
 
 
 | 328 | { | 
 
 
 
 
 | 329 | // | 
 
 
 
 
 | 330 | // We already have an adjacent triangle for this edge. | 
 
 
 
 
 | 331 | // This means that there are 3 or more triangles that have a | 
 
 
 
 
 | 332 | // common edge but this is not very common and we'll just | 
 
 
 
 
 | 333 | // ignore it. | 
 
 
 
 
 | 334 | // | 
 
 
 
 
 | 335 |  | 
 
 
 
 
 | 336 | if (adjacency[t + e] != -1) | 
 
 
 
 
 | 337 | continue; | 
 
 
 
 
 | 338 |  | 
 
 
 
 
 | 339 | // | 
 
 
 
 
 | 340 | // Notice that the edge must be reversed compared to the | 
 
 
 
 
 | 341 | // order they were stored in the dictionary to preserve | 
 
 
 
 
 | 342 | // trinangle vertex ordering. | 
 
 
 
 
 | 343 | // | 
 
 
 
 
 | 344 |  | 
 
 
 
 
 | 345 | var edge = new Edge(tlist[t + (e + 1) % 3], tlist[t + e]); | 
 
 
 
 
 | 346 |  | 
 
 
 
 
 | 347 | int k; | 
 
 
 
 
 | 348 |  | 
 
 
 
 
 | 349 | // | 
 
 
 
 
 | 350 | // Note the k != t / 3 check to avoid making degenerate triangles | 
 
 
 
 
 | 351 | // adjacent to themselfs. | 
 
 
 
 
 | 352 | // | 
 
 
 
 
 | 353 |  | 
 
 
 
 
 | 354 | if (edges.TryGetValue(edge, out k) && k != t / 3) | 
 
 
 
 
 | 355 | { | 
 
 
 
 
 | 356 | adjacency[t + e] = k; | 
 
 
 
 
 | 357 | degree[t / 3]++; | 
 
 
 
 
 | 358 | } | 
 
 
 
 
 | 359 | } | 
 
 
 
 
 | 360 | } | 
 
 
 
 
 | 361 | } | 
 
 
 
 
 | 362 | } | 
 
 
 
 
 | 363 | } |