|  |  | 1 |  | // Copyright (c) 2020-2024 dotBunny Inc. | 
|  |  | 2 |  | // dotBunny licenses this file to you under the BSL-1.0 license. | 
|  |  | 3 |  | // See the LICENSE file in the project root for more information. | 
|  |  | 4 |  |  | 
|  |  | 5 |  | using Unity.Mathematics; | 
|  |  | 6 |  | using UnityEngine; | 
|  |  | 7 |  |  | 
|  |  | 8 |  | namespace GDX.Experimental | 
|  |  | 9 |  | { | 
|  |  | 10 |  |     public static class DebugDrawShapes | 
|  |  | 11 |  |     { | 
|  |  | 12 |  |         const float PI = 3.1415927f; | 
|  |  | 13 |  |         const float Deg2Rad = 0.017453292f; | 
|  |  | 14 |  |         const int DefaultCircleVertexCount = 32; | 
|  |  | 15 |  |  | 
|  |  | 16 |  |         /// <summary> | 
|  |  | 17 |  |         ///     The ordered segment index pairs used to describe a cube. | 
|  |  | 18 |  |         /// </summary> | 
|  |  | 19 |  |         /// <remarks> | 
|  |  | 20 |  |         ///     This effectively wraps the left side, then the right, then connects the two sides. | 
|  |  | 21 |  |         /// </remarks> | 
|  | 0 | 22 |  |         public static int[] CubeSegmentIndices = | 
|  |  | 23 |  |         { | 
|  |  | 24 |  |             0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 | 
|  |  | 25 |  |         }; | 
|  |  | 26 |  |  | 
|  | 0 | 27 |  |         static readonly Quaternion k_RotationPrimaryTopLoop = Quaternion.Euler(0, 90, 0); | 
|  | 0 | 28 |  |         static readonly Quaternion k_RotationPrimaryBottomLoop = Quaternion.Euler(0, -90, 180); | 
|  |  | 29 |  |  | 
|  | 0 | 30 |  |         static readonly Quaternion k_RotationSecondaryTopLoop = Quaternion.Euler(0, 180, 0); | 
|  | 0 | 31 |  |         static readonly Quaternion k_RotationSecondaryBottomLoop = Quaternion.Euler(0, 0, 180); | 
|  |  | 32 |  |  | 
|  |  | 33 |  |  | 
|  |  | 34 |  |         static void GetCircleVertices(ref Vector3[] vertices, int startIndex, Vector3 center, Quaternion rotation, | 
|  |  | 35 |  |             float radius, int circleVertexCount = DefaultCircleVertexCount) | 
|  | 0 | 36 |  |         { | 
|  | 0 | 37 |  |             float radiansInterval = PI * 2f / circleVertexCount; | 
|  |  | 38 |  |  | 
|  |  | 39 |  |             // Loop through and figure out the points | 
|  | 0 | 40 |  |             for (int i = 0; i < circleVertexCount; i++) | 
|  | 0 | 41 |  |             { | 
|  | 0 | 42 |  |                 float angle = i * radiansInterval; | 
|  |  | 43 |  |  | 
|  |  | 44 |  |                 // Create base point | 
|  | 0 | 45 |  |                 vertices[i + startIndex] = | 
|  |  | 46 |  |                     rotation * new Vector3(0, math.sin(angle) * radius, math.cos(angle) * radius) + center; | 
|  | 0 | 47 |  |             } | 
|  | 0 | 48 |  |         } | 
|  |  | 49 |  |  | 
|  |  | 50 |  |         static int[] GetCubeSegmentOffset(int offset) | 
|  | 0 | 51 |  |         { | 
|  | 0 | 52 |  |             int[] newIndices = new int[24] | 
|  |  | 53 |  |             { | 
|  |  | 54 |  |                 CubeSegmentIndices[0] + offset, CubeSegmentIndices[1] + offset, CubeSegmentIndices[2] + offset, | 
|  |  | 55 |  |                 CubeSegmentIndices[3] + offset, CubeSegmentIndices[4] + offset, CubeSegmentIndices[5] + offset, | 
|  |  | 56 |  |                 CubeSegmentIndices[6] + offset, CubeSegmentIndices[7] + offset, CubeSegmentIndices[8] + offset, | 
|  |  | 57 |  |                 CubeSegmentIndices[9] + offset, CubeSegmentIndices[10] + offset, CubeSegmentIndices[11] + offset, | 
|  |  | 58 |  |                 CubeSegmentIndices[12] + offset, CubeSegmentIndices[13] + offset, CubeSegmentIndices[14] + offset, | 
|  |  | 59 |  |                 CubeSegmentIndices[15] + offset, CubeSegmentIndices[16] + offset, CubeSegmentIndices[17] + offset, | 
|  |  | 60 |  |                 CubeSegmentIndices[18] + offset, CubeSegmentIndices[19] + offset, CubeSegmentIndices[20] + offset, | 
|  |  | 61 |  |                 CubeSegmentIndices[21] + offset, CubeSegmentIndices[22] + offset, CubeSegmentIndices[23] + offset | 
|  |  | 62 |  |             }; | 
|  | 0 | 63 |  |             return newIndices; | 
|  | 0 | 64 |  |         } | 
|  |  | 65 |  |  | 
|  |  | 66 |  |         static void GetCubeSegmentOffsetNonAlloc(int[] indices, int startIndex, int offset) | 
|  | 0 | 67 |  |         { | 
|  | 0 | 68 |  |             indices[startIndex] = CubeSegmentIndices[0] + offset; | 
|  | 0 | 69 |  |             indices[startIndex + 1] = CubeSegmentIndices[1] + offset; | 
|  | 0 | 70 |  |             indices[startIndex + 2] = CubeSegmentIndices[2] + offset; | 
|  | 0 | 71 |  |             indices[startIndex + 3] = CubeSegmentIndices[3] + offset; | 
|  | 0 | 72 |  |             indices[startIndex + 4] = CubeSegmentIndices[4] + offset; | 
|  | 0 | 73 |  |             indices[startIndex + 5] = CubeSegmentIndices[5] + offset; | 
|  | 0 | 74 |  |             indices[startIndex + 6] = CubeSegmentIndices[6] + offset; | 
|  | 0 | 75 |  |             indices[startIndex + 7] = CubeSegmentIndices[7] + offset; | 
|  | 0 | 76 |  |             indices[startIndex + 8] = CubeSegmentIndices[8] + offset; | 
|  | 0 | 77 |  |             indices[startIndex + 9] = CubeSegmentIndices[9] + offset; | 
|  | 0 | 78 |  |             indices[startIndex + 10] = CubeSegmentIndices[10] + offset; | 
|  | 0 | 79 |  |             indices[startIndex + 11] = CubeSegmentIndices[11] + offset; | 
|  | 0 | 80 |  |             indices[startIndex + 12] = CubeSegmentIndices[12] + offset; | 
|  | 0 | 81 |  |             indices[startIndex + 13] = CubeSegmentIndices[13] + offset; | 
|  | 0 | 82 |  |             indices[startIndex + 14] = CubeSegmentIndices[14] + offset; | 
|  | 0 | 83 |  |             indices[startIndex + 15] = CubeSegmentIndices[15] + offset; | 
|  | 0 | 84 |  |             indices[startIndex + 16] = CubeSegmentIndices[16] + offset; | 
|  | 0 | 85 |  |             indices[startIndex + 17] = CubeSegmentIndices[17] + offset; | 
|  | 0 | 86 |  |             indices[startIndex + 18] = CubeSegmentIndices[18] + offset; | 
|  | 0 | 87 |  |             indices[startIndex + 19] = CubeSegmentIndices[19] + offset; | 
|  | 0 | 88 |  |             indices[startIndex + 20] = CubeSegmentIndices[20] + offset; | 
|  | 0 | 89 |  |             indices[startIndex + 21] = CubeSegmentIndices[21] + offset; | 
|  | 0 | 90 |  |             indices[startIndex + 22] = CubeSegmentIndices[22] + offset; | 
|  | 0 | 91 |  |             indices[startIndex + 23] = CubeSegmentIndices[23] + offset; | 
|  | 0 | 92 |  |         } | 
|  |  | 93 |  |  | 
|  |  | 94 |  |         /// <summary> | 
|  |  | 95 |  |         ///     Get the vertices that make up a cube. | 
|  |  | 96 |  |         /// </summary> | 
|  |  | 97 |  |         /// <remarks> | 
|  |  | 98 |  |         ///     Ordered based on <see cref="CubeSegmentIndices" />. | 
|  |  | 99 |  |         /// </remarks> | 
|  |  | 100 |  |         /// <param name="center">The world space center location of the cube.</param> | 
|  |  | 101 |  |         /// <param name="size">The size of the cube.</param> | 
|  |  | 102 |  |         /// <returns>An array of ordered vertices.</returns> | 
|  |  | 103 |  |         static Vector3[] GetCubeVertices(Vector3 center, Quaternion rotation, Vector3 size) | 
|  | 0 | 104 |  |         { | 
|  | 0 | 105 |  |             Vector3 half = size / 2f; | 
|  |  | 106 |  |  | 
|  | 0 | 107 |  |             float centerMinusHalfX = center.x - half.x; | 
|  | 0 | 108 |  |             float centerMinusHalfY = center.y - half.y; | 
|  | 0 | 109 |  |             float centerMinusHalfZ = center.z - half.z; | 
|  | 0 | 110 |  |             float centerPlusHalfX = center.x + half.x; | 
|  | 0 | 111 |  |             float centerPlusHalfY = center.y + half.y; | 
|  | 0 | 112 |  |             float centerPlusHalfZ = center.z + half.z; | 
|  |  | 113 |  |  | 
|  | 0 | 114 |  |             Vector3[] points = | 
|  |  | 115 |  |             { | 
|  |  | 116 |  |                 rotation * new Vector3(centerMinusHalfX, centerMinusHalfY, centerMinusHalfZ), // Front Bottom Left (0) | 
|  |  | 117 |  |                 rotation * new Vector3(centerMinusHalfX, centerMinusHalfY, centerPlusHalfZ), // Back Bottom Left (1) | 
|  |  | 118 |  |                 rotation * new Vector3(centerMinusHalfX, centerPlusHalfY, centerPlusHalfZ), // Back Top Left (2) | 
|  |  | 119 |  |                 rotation * new Vector3(centerMinusHalfX, centerPlusHalfY, centerMinusHalfZ), // Front Top Left (3) | 
|  |  | 120 |  |                 rotation * new Vector3(centerPlusHalfX, centerMinusHalfY, centerMinusHalfZ), // Front Bottom Right (4) | 
|  |  | 121 |  |                 rotation * new Vector3(centerPlusHalfX, centerMinusHalfY, centerPlusHalfZ), // Back Bottom Right (5) | 
|  |  | 122 |  |                 rotation * new Vector3(centerPlusHalfX, centerPlusHalfY, centerPlusHalfZ), // Back Top Right (6) | 
|  |  | 123 |  |                 rotation * new Vector3(centerPlusHalfX, centerPlusHalfY, centerMinusHalfZ) // Front Top Right (7) | 
|  |  | 124 |  |             }; | 
|  |  | 125 |  |  | 
|  | 0 | 126 |  |             return points; | 
|  | 0 | 127 |  |         } | 
|  |  | 128 |  |  | 
|  |  | 129 |  |         static void GetCubeVerticesNonAlloc(ref Vector3[] points, int startIndex, Vector3 center, Quaternion rotation, | 
|  |  | 130 |  |             Vector3 size) | 
|  | 0 | 131 |  |         { | 
|  | 0 | 132 |  |             Vector3 half = size / 2f; | 
|  |  | 133 |  |  | 
|  | 0 | 134 |  |             float centerMinusHalfX = center.x - half.x; | 
|  | 0 | 135 |  |             float centerMinusHalfY = center.y - half.y; | 
|  | 0 | 136 |  |             float centerMinusHalfZ = center.z - half.z; | 
|  | 0 | 137 |  |             float centerPlusHalfX = center.x + half.x; | 
|  | 0 | 138 |  |             float centerPlusHalfY = center.y + half.y; | 
|  | 0 | 139 |  |             float centerPlusHalfZ = center.z + half.z; | 
|  |  | 140 |  |  | 
|  | 0 | 141 |  |             points[startIndex] = | 
|  |  | 142 |  |                 rotation * new Vector3(centerMinusHalfX, centerMinusHalfY, centerMinusHalfZ); // Front Bottom Left (0) | 
|  | 0 | 143 |  |             points[startIndex + 1] = | 
|  |  | 144 |  |                 rotation * new Vector3(centerMinusHalfX, centerMinusHalfY, centerPlusHalfZ); // Back Bottom Left (1) | 
|  | 0 | 145 |  |             points[startIndex + 2] = | 
|  |  | 146 |  |                 rotation * new Vector3(centerMinusHalfX, centerPlusHalfY, centerPlusHalfZ); // Back Top Left (2) | 
|  | 0 | 147 |  |             points[startIndex + 3] = | 
|  |  | 148 |  |                 rotation * new Vector3(centerMinusHalfX, centerPlusHalfY, centerMinusHalfZ); // Front Top Left (3) | 
|  | 0 | 149 |  |             points[startIndex + 4] = | 
|  |  | 150 |  |                 rotation * new Vector3(centerPlusHalfX, centerMinusHalfY, centerMinusHalfZ); // Front Bottom Right (4) | 
|  | 0 | 151 |  |             points[startIndex + 5] = | 
|  |  | 152 |  |                 rotation * new Vector3(centerPlusHalfX, centerMinusHalfY, centerPlusHalfZ); // Back Bottom Right (5) | 
|  | 0 | 153 |  |             points[startIndex + 6] = | 
|  |  | 154 |  |                 rotation * new Vector3(centerPlusHalfX, centerPlusHalfY, centerPlusHalfZ); // Back Top Right (6) | 
|  | 0 | 155 |  |             points[startIndex + 7] = | 
|  |  | 156 |  |                 rotation * new Vector3(centerPlusHalfX, centerPlusHalfY, centerMinusHalfZ); // Front Top Right (7) | 
|  | 0 | 157 |  |         } | 
|  |  | 158 |  |  | 
|  |  | 159 |  |         /// <summary> | 
|  |  | 160 |  |         ///     Draw a dotted line cube of a specific color to the buffer. | 
|  |  | 161 |  |         /// </summary> | 
|  |  | 162 |  |         /// <param name="color">The color which to draw the dotted line cube with.</param> | 
|  |  | 163 |  |         /// <param name="center">The center world position of the cube.</param> | 
|  |  | 164 |  |         /// <param name="size">The unit size of the cube</param> | 
|  |  | 165 |  |         /// <returns>The created cube's invalidation token.</returns> | 
|  |  | 166 |  |         public static int DrawDottedCube(this DebugDrawBuffer buffer, Color color, Vector3 center, Quaternion rotation, | 
|  |  | 167 |  |             Vector3 size) | 
|  | 0 | 168 |  |         { | 
|  | 0 | 169 |  |             Vector3[] vertices = GetCubeVertices(center, rotation, size); | 
|  | 0 | 170 |  |             return buffer.DrawDottedLines(color, ref vertices, ref CubeSegmentIndices); | 
|  | 0 | 171 |  |         } | 
|  |  | 172 |  |  | 
|  |  | 173 |  |  | 
|  |  | 174 |  |         public static int DrawWireCapsule(this DebugDrawBuffer buffer, Color color, Vector3 bottomSpherePosition, | 
|  |  | 175 |  |             Vector3 topSpherePosition, Quaternion rotation, float radius, | 
|  |  | 176 |  |             int arcVertexCount = DefaultCircleVertexCount / 2) | 
|  | 0 | 177 |  |         { | 
|  |  | 178 |  |             // Calculate total vertices | 
|  | 0 | 179 |  |             int totalVertices = arcVertexCount * 4; | 
|  |  | 180 |  |  | 
|  |  | 181 |  |             // TODO: add circles? | 
|  | 0 | 182 |  |             Vector3[] vertices = new Vector3[totalVertices]; | 
|  | 0 | 183 |  |             float baseAngle = 0f; | 
|  | 0 | 184 |  |             float arcLength = 180f; | 
|  | 0 | 185 |  |             int lineCount = arcVertexCount - 1; | 
|  |  | 186 |  |  | 
|  | 0 | 187 |  |             int bottomPrimaryStartIndex = arcVertexCount; | 
|  | 0 | 188 |  |             int topSecondaryStartIndex = bottomPrimaryStartIndex * 2; | 
|  | 0 | 189 |  |             int bottomSecondaryStartIndex = bottomPrimaryStartIndex * 3; | 
|  |  | 190 |  |  | 
|  | 0 | 191 |  |             Quaternion primaryTopRotation = rotation * k_RotationPrimaryTopLoop; | 
|  | 0 | 192 |  |             Quaternion primaryBottomRotation = rotation * k_RotationPrimaryBottomLoop; | 
|  | 0 | 193 |  |             Quaternion secondaryTopRotation = rotation * k_RotationSecondaryTopLoop; | 
|  | 0 | 194 |  |             Quaternion secondaryBottomRotation = rotation * k_RotationSecondaryBottomLoop; | 
|  |  | 195 |  |  | 
|  | 0 | 196 |  |             for (int i = 0; i < arcVertexCount; i++) | 
|  | 0 | 197 |  |             { | 
|  | 0 | 198 |  |                 float currentAngle = Deg2Rad * baseAngle; | 
|  |  | 199 |  |  | 
|  | 0 | 200 |  |                 Vector3 basePosition = | 
|  |  | 201 |  |                     new Vector3(0, Mathf.Sin(currentAngle) * radius, Mathf.Cos(currentAngle) * radius); | 
|  |  | 202 |  |  | 
|  | 0 | 203 |  |                 vertices[i] = primaryTopRotation * basePosition + topSpherePosition; | 
|  | 0 | 204 |  |                 vertices[i + bottomPrimaryStartIndex] = primaryBottomRotation * basePosition + bottomSpherePosition; | 
|  |  | 205 |  |  | 
|  | 0 | 206 |  |                 vertices[i + topSecondaryStartIndex] = secondaryTopRotation * basePosition + topSpherePosition; | 
|  | 0 | 207 |  |                 vertices[i + bottomSecondaryStartIndex] = secondaryBottomRotation * basePosition + bottomSpherePosition; | 
|  |  | 208 |  |  | 
|  | 0 | 209 |  |                 baseAngle += arcLength / lineCount; | 
|  | 0 | 210 |  |             } | 
|  |  | 211 |  |  | 
|  |  | 212 |  |  | 
|  |  | 213 |  |             // Create segment connections | 
|  | 0 | 214 |  |             int blockSize = lineCount * 2 + 2; | 
|  | 0 | 215 |  |             int[] segments = new int[blockSize * 4]; | 
|  |  | 216 |  |  | 
|  | 0 | 217 |  |             int primaryTopBottomConnectionIndex = blockSize - 2; | 
|  | 0 | 218 |  |             int primaryBottomTopConnectionIndex = blockSize * 2 - 2; | 
|  | 0 | 219 |  |             int secondaryTopBottomConnectionIndex = blockSize * 3 - 2; | 
|  | 0 | 220 |  |             int secondaryBottomTopConnectionIndex = blockSize * 4 - 2; | 
|  |  | 221 |  |  | 
|  | 0 | 222 |  |             int segmentCount = segments.Length; | 
|  | 0 | 223 |  |             int baseCount = 0; | 
|  |  | 224 |  |  | 
|  | 0 | 225 |  |             for (int i = 0; i < segmentCount; i += 2) | 
|  | 0 | 226 |  |             { | 
|  | 0 | 227 |  |                 if (i == primaryTopBottomConnectionIndex || i == primaryBottomTopConnectionIndex || | 
|  |  | 228 |  |                     i == secondaryTopBottomConnectionIndex || i == secondaryBottomTopConnectionIndex) | 
|  | 0 | 229 |  |                 { | 
|  | 0 | 230 |  |                     baseCount++; | 
|  | 0 | 231 |  |                     continue; | 
|  |  | 232 |  |                 } | 
|  |  | 233 |  |  | 
|  | 0 | 234 |  |                 segments[i] = baseCount; | 
|  | 0 | 235 |  |                 baseCount++; | 
|  | 0 | 236 |  |                 segments[i + 1] = baseCount; | 
|  | 0 | 237 |  |             } | 
|  |  | 238 |  |  | 
|  | 0 | 239 |  |             segments[primaryTopBottomConnectionIndex] = segments[primaryTopBottomConnectionIndex - 1]; | 
|  | 0 | 240 |  |             segments[primaryTopBottomConnectionIndex + 1] = segments[primaryTopBottomConnectionIndex + 2]; | 
|  |  | 241 |  |  | 
|  | 0 | 242 |  |             segments[primaryBottomTopConnectionIndex] = segments[primaryBottomTopConnectionIndex - 1]; | 
|  | 0 | 243 |  |             segments[primaryBottomTopConnectionIndex + 1] = segments[0]; | 
|  |  | 244 |  |  | 
|  | 0 | 245 |  |             segments[secondaryTopBottomConnectionIndex] = segments[secondaryTopBottomConnectionIndex - 1]; | 
|  | 0 | 246 |  |             segments[secondaryTopBottomConnectionIndex + 1] = segments[secondaryTopBottomConnectionIndex + 2]; | 
|  |  | 247 |  |  | 
|  | 0 | 248 |  |             segments[secondaryBottomTopConnectionIndex] = segments[secondaryBottomTopConnectionIndex - 1]; | 
|  | 0 | 249 |  |             segments[secondaryBottomTopConnectionIndex + 1] = segments[primaryBottomTopConnectionIndex + 2]; | 
|  |  | 250 |  |  | 
|  |  | 251 |  |             // Link top to bottom | 
|  | 0 | 252 |  |             return buffer.DrawLines(color, ref vertices, ref segments); | 
|  | 0 | 253 |  |         } | 
|  |  | 254 |  |  | 
|  |  | 255 |  |         public static int DrawWireArc(this DebugDrawBuffer buffer, Color color, Vector3 center, Quaternion rotation, | 
|  |  | 256 |  |             float radius, float startAngle = 0f, float endAngle = 180f, | 
|  |  | 257 |  |             int arcVertexCount = DefaultCircleVertexCount / 2) | 
|  | 0 | 258 |  |         { | 
|  |  | 259 |  |             // We do the plus one to complete the full arc segment, otherwise it would not be every peice | 
|  | 0 | 260 |  |             Vector3[] vertices = new Vector3[arcVertexCount]; | 
|  | 0 | 261 |  |             float baseAngle = startAngle; | 
|  | 0 | 262 |  |             float arcLength = endAngle - startAngle; | 
|  | 0 | 263 |  |             int lineCount = arcVertexCount - 1; | 
|  | 0 | 264 |  |             for (int i = 0; i < arcVertexCount; i++) | 
|  | 0 | 265 |  |             { | 
|  | 0 | 266 |  |                 float currentAngle = Deg2Rad * baseAngle; | 
|  | 0 | 267 |  |                 vertices[i] = | 
|  |  | 268 |  |                     rotation * new Vector3(0, Mathf.Sin(currentAngle) * radius, Mathf.Cos(currentAngle) * radius) + | 
|  |  | 269 |  |                     center; | 
|  | 0 | 270 |  |                 baseAngle += arcLength / lineCount; | 
|  | 0 | 271 |  |             } | 
|  |  | 272 |  |  | 
|  |  | 273 |  |             // Create segment connections | 
|  | 0 | 274 |  |             int[] segments = new int[lineCount * 2]; | 
|  | 0 | 275 |  |             int segmentCount = segments.Length; | 
|  | 0 | 276 |  |             int baseCount = 0; | 
|  | 0 | 277 |  |             for (int i = 0; i < segmentCount; i += 2) | 
|  | 0 | 278 |  |             { | 
|  | 0 | 279 |  |                 segments[i] = baseCount; | 
|  | 0 | 280 |  |                 baseCount++; | 
|  | 0 | 281 |  |                 segments[i + 1] = baseCount; | 
|  | 0 | 282 |  |             } | 
|  |  | 283 |  |  | 
|  | 0 | 284 |  |             return buffer.DrawLines(color, ref vertices, ref segments); | 
|  | 0 | 285 |  |         } | 
|  |  | 286 |  |  | 
|  |  | 287 |  |         public static int DrawWireCircle(this DebugDrawBuffer buffer, Color color, Vector3 center, Quaternion rotation, | 
|  |  | 288 |  |             float radius, int circleVertexCount = DefaultCircleVertexCount) | 
|  | 0 | 289 |  |         { | 
|  | 0 | 290 |  |             Vector3[] vertices = new Vector3[circleVertexCount]; | 
|  | 0 | 291 |  |             float radiansInterval = PI * 2f / circleVertexCount; | 
|  |  | 292 |  |  | 
|  |  | 293 |  |             // Loop through and figure out the points | 
|  | 0 | 294 |  |             for (int i = 0; i < circleVertexCount; i++) | 
|  | 0 | 295 |  |             { | 
|  | 0 | 296 |  |                 float angle = i * radiansInterval; | 
|  |  | 297 |  |  | 
|  |  | 298 |  |                 // Create base point | 
|  | 0 | 299 |  |                 vertices[i] = rotation * new Vector3(0, math.sin(angle) * radius, math.cos(angle) * radius) + center; | 
|  | 0 | 300 |  |             } | 
|  |  | 301 |  |  | 
|  | 0 | 302 |  |             int[] segments = new int[circleVertexCount * 2]; | 
|  | 0 | 303 |  |             int segmentCount = segments.Length; | 
|  | 0 | 304 |  |             int baseCount = 0; | 
|  |  | 305 |  |  | 
|  | 0 | 306 |  |             for (int i = 0; i < segmentCount; i += 2) | 
|  | 0 | 307 |  |             { | 
|  | 0 | 308 |  |                 segments[i] = baseCount; | 
|  | 0 | 309 |  |                 baseCount++; | 
|  | 0 | 310 |  |                 segments[i + 1] = baseCount; | 
|  | 0 | 311 |  |             } | 
|  |  | 312 |  |  | 
|  | 0 | 313 |  |             segments[segmentCount - 1] = 0; | 
|  |  | 314 |  |  | 
|  | 0 | 315 |  |             return buffer.DrawLines(color, ref vertices, ref segments); | 
|  | 0 | 316 |  |         } | 
|  |  | 317 |  |  | 
|  |  | 318 |  |         /// <summary> | 
|  |  | 319 |  |         ///     Draw a wireframe cube of a specific color to the buffer. | 
|  |  | 320 |  |         /// </summary> | 
|  |  | 321 |  |         /// <param name="color">The color which to draw the wire cube with.</param> | 
|  |  | 322 |  |         /// <param name="center">The center world position of the cube.</param> | 
|  |  | 323 |  |         /// <param name="size">The unit size of the cube</param> | 
|  |  | 324 |  |         /// <returns>The created cube's invalidation token.</returns> | 
|  |  | 325 |  |         public static int DrawWireCube(this DebugDrawBuffer buffer, Color color, Vector3 center, Quaternion rotation, | 
|  |  | 326 |  |             Vector3 size) | 
|  | 0 | 327 |  |         { | 
|  | 0 | 328 |  |             Vector3[] vertices = GetCubeVertices(center, rotation, size); | 
|  | 0 | 329 |  |             return buffer.DrawLines(color, ref vertices, ref CubeSegmentIndices); | 
|  | 0 | 330 |  |         } | 
|  |  | 331 |  |  | 
|  |  | 332 |  |         public static int DrawWireSphere(this DebugDrawBuffer buffer, Color color, Vector3 center, Quaternion rotation, | 
|  |  | 333 |  |             float radius, int circleVertexCount = DefaultCircleVertexCount) | 
|  | 0 | 334 |  |         { | 
|  | 0 | 335 |  |             int pointCount = circleVertexCount * 2; | 
|  | 0 | 336 |  |             Vector3[] vertices = new Vector3[pointCount]; | 
|  |  | 337 |  |  | 
|  | 0 | 338 |  |             float radiansInterval = PI * 2f / circleVertexCount; | 
|  | 0 | 339 |  |             Quaternion xRotation = Space.Axis.X.ToRotation() * rotation; | 
|  | 0 | 340 |  |             Quaternion yRotation = Space.Axis.Y.ToRotation() * rotation; | 
|  |  | 341 |  |  | 
|  |  | 342 |  |             // Loop through and figure out the points | 
|  | 0 | 343 |  |             for (int i = 0; i < circleVertexCount; i++) | 
|  | 0 | 344 |  |             { | 
|  | 0 | 345 |  |                 float angle = i * radiansInterval; | 
|  |  | 346 |  |  | 
|  |  | 347 |  |                 // Create base points | 
|  | 0 | 348 |  |                 vertices[i] = xRotation * new Vector3(0, math.sin(angle) * radius, math.cos(angle) * radius) + center; | 
|  | 0 | 349 |  |                 vertices[i + circleVertexCount] = | 
|  |  | 350 |  |                     yRotation * new Vector3(0, math.sin(angle) * radius, math.cos(angle) * radius) + center; | 
|  | 0 | 351 |  |             } | 
|  |  | 352 |  |  | 
|  |  | 353 |  |             // Create segment connections | 
|  | 0 | 354 |  |             int[] segments = new int[pointCount * 2]; | 
|  | 0 | 355 |  |             int segmentCount = segments.Length; | 
|  | 0 | 356 |  |             int baseCount = 0; | 
|  | 0 | 357 |  |             for (int i = 0; i < segmentCount; i += 2) | 
|  | 0 | 358 |  |             { | 
|  | 0 | 359 |  |                 segments[i] = baseCount; | 
|  | 0 | 360 |  |                 baseCount++; | 
|  | 0 | 361 |  |                 segments[i + 1] = baseCount; | 
|  | 0 | 362 |  |             } | 
|  |  | 363 |  |  | 
|  | 0 | 364 |  |             segments[pointCount - 1] = 0; | 
|  | 0 | 365 |  |             segments[segmentCount - 1] = circleVertexCount; | 
|  |  | 366 |  |  | 
|  | 0 | 367 |  |             return buffer.DrawLines(color, ref vertices, ref segments); | 
|  | 0 | 368 |  |         } | 
|  |  | 369 |  |     } | 
|  |  | 370 |  | } |