void TransformVerts(LayerSubMesh mesh) { var offset = Rot4.FromAngleFlat(target); var offseti = offset.AsInt; var uvs = mesh.uvs; var vertsc = mesh.verts.Count; var origVerts = NoAllocHelpers.ExtractArrayFromListT(mesh.verts); // Rotate around a center if (PrintPlanePatch.plantMats.Contains(mesh.material) || GraphicPrintPatch.graphicSingle.Contains(mesh.material)) { if (uvs.Count * 4 != vertsc) { Log.ErrorOnce($"Carousel: Bad material {mesh.material}", mesh.material.GetHashCode()); return; } Util.ResizeIfNeeded(ref tempVerts, vertsc); for (int i = 0; i < vertsc; i += 4) { // The mesh data lists are only used during mesh building and are otherwise unused // In between mesh rebuilding, Carousel uses the uv list to store object centers for rotation var c = uvs[i / 4]; tempVerts[i] = c + (origVerts[i] - c).RotatedBy(offset); tempVerts[i + 1] = c + (origVerts[i + 1] - c).RotatedBy(offset); tempVerts[i + 2] = c + (origVerts[i + 2] - c).RotatedBy(offset); tempVerts[i + 3] = c + (origVerts[i + 3] - c).RotatedBy(offset); } mesh.mesh.SetVertices(tempVerts, vertsc); } // Exchange vertices if (GraphicPrintPatch.matData.ContainsKey(mesh.material) || LinkedPrintPatch.linkedMaterials.Contains(mesh.material)) { Util.ResizeIfNeeded(ref tempVerts, vertsc); for (int i = 0; i < vertsc; i += 4) { tempVerts[i].SetXZY(ref origVerts[i + (offseti & 3)], origVerts[i].y); tempVerts[i + 1].SetXZY(ref origVerts[i + (offseti + 1 & 3)], origVerts[i + 1].y); tempVerts[i + 2].SetXZY(ref origVerts[i + (offseti + 2 & 3)], origVerts[i + 2].y); tempVerts[i + 3].SetXZY(ref origVerts[i + (offseti + 3 & 3)], origVerts[i + 3].y); } mesh.mesh.SetVertices(tempVerts, vertsc); } }
void TransformAtlas(LayerSubMesh mesh, TextureAtlasGroup group) { var offset = Rot4.FromAngleFlat(target); var offseti = offset.AsInt; var vertsc = mesh.verts.Count / 5 * 4; var uvsc = mesh.uvs.Count; var vertsArr = NoAllocHelpers.ExtractArrayFromListT(mesh.verts); var uvsArr = NoAllocHelpers.ExtractArrayFromListT(mesh.uvs); Util.ResizeIfNeeded(ref tempVerts, vertsc); Util.ResizeIfNeeded(ref tempUVs, uvsc); for (int i = 0; i < vertsc; i += 4) { var data = vertsArr[vertsc + i / 4]; if (data.x == PrintPlanePatch.SPECIAL_X) { ExchangeVerts(tempVerts, vertsArr, i, offseti); var rotData = ((int)data.z & 0b1100) >> 2; var flipData = (int)data.z & 0b0011; var relRot = GenMath.PositiveMod(rotData - Rot4.FromAngleFlat(target).AsInt, 4); var flipped = relRot == 1 && ((flipData & 1) == 1) || relRot == 3 && ((flipData & 2) == 2) ? 1 : 0; var rotatedMat = GraphicPrintPatch_SetData.intToGraphic[(int)data.y].mats[(rotData + Rot4.FromAngleFlat(-target).AsInt) % 4]; Graphic.TryGetTextureAtlasReplacementInfo(rotatedMat, group, false, false, out _, out var uvs, out _); FixUVs( tempUVs, uvs, i, flipped ); } else if (data.x != PrintPlanePatch.EMPTY_X) { RotateVerts(tempVerts, vertsArr, i, data, offset); Array.Copy(uvsArr, i, tempUVs, i, 4); } else { Array.Copy(vertsArr, i, tempVerts, i, 4); Array.Copy(uvsArr, i, tempUVs, i, 4); } } mesh.mesh.SetVertices(tempVerts, vertsc); mesh.mesh.SetUVs(tempUVs, uvsc); }
/// <summary>Box fills tiles and GameObjects into given bounds within the selected layers.</summary> /// <param name="gridLayout">Grid to box fill data to.</param> /// <param name="brushTarget">Target of the box fill operation. By default the currently selected GameObject.</param> /// <param name="position">The bounds to box fill data into.</param> public override void BoxFill(GridLayout gridLayout, GameObject brushTarget, BoundsInt position) { if (brushTarget == null) { return; } Tilemap map = brushTarget.GetComponent <Tilemap>(); if (map == null) { return; } int count = 0; var listSize = position.size.x * position.size.y * position.size.z; if (m_TileChangeDataList == null || m_TileChangeDataList.Capacity != listSize) { m_TileChangeDataList = new List <TileChangeData>(listSize); } m_TileChangeDataList.Clear(); foreach (Vector3Int location in position.allPositionsWithin) { Vector3Int local = location - position.min; BrushCell cell = m_Cells[GetCellIndexWrapAround(local.x, local.y, local.z)]; if (cell.tile == null) { continue; } var tcd = new TileChangeData { position = location, tile = cell.tile, transform = cell.matrix, color = cell.color }; m_TileChangeDataList.Add(tcd); count++; } // Duplicate empty slots in the list, as ExtractArrayFromListT returns full list if (0 < count && count < listSize) { var tcd = m_TileChangeDataList[count - 1]; for (int i = count; i < listSize; ++i) { m_TileChangeDataList.Add(tcd); } } var tileChangeData = NoAllocHelpers.ExtractArrayFromListT(m_TileChangeDataList); map.SetTiles(tileChangeData, false); }
/// <summary> /// View <paramref name="list"/> as a <see cref="NativeArray{T}"/> without having to copy it or doing all the boilerplate for getting the pointer out of a list. /// Useful for allowing a job to work on a list. /// /// <para> /// Put this thing in a disposable scope unless you can guarantee that the list will never change size or reallocate (in that case consider using a <see cref="NativeArray{T}"/> instead), /// as Unity will <b>not</b> tell you if you're out of bounds, accessing invalid data, or accessing stale data because you have a stale/invalid view of the list. /// The following changes to the list will turn a view invalid/stale: /// <list type="number"> /// <item>The contents of the array will be stale (not reflect any changes to the values in the list) in case of a reallocation (changes to, or adding more items than, <see cref="List{T}.Capacity"/> or using <see cref="List{T}.TrimExcess"/>)</item> /// <item>The length of the array will be wrong if you add/remove elements from the list</item> /// </list> /// </para> /// /// <para> /// The <paramref name="nativeArray"/> itself does not need to be disposed, but you need to dispose the <see cref="NativeArrayViewHandle"/> you get back, Unity's Memory Leak Detection will tell you if you forget. /// Do not use the array after calling <see cref="NativeArrayViewHandle.Dispose"/> on the <see cref="NativeArrayViewHandle"/> returned from this function, /// as you can risk the garbage collector removing the data from down under you, Unity's Collections Safety Checks will tell you if you do this. /// There is <b>no</b> race detection for accessing multiple different views of the same list in different jobs concurrently, or modifying the list while a job is working on a view. /// </para> /// /// Usage: /// <code> /// List<int> list; /// using (list.ViewAsNativeArray(out var nativeArray)) /// { /// // work on nativeArray /// } /// </code> /// </summary> public unsafe static NativeArrayViewHandle ViewAsNativeArray <T>(this List <T> list, out NativeArray <T> nativeArray) where T : struct { var lArray = NoAllocHelpers.ExtractArrayFromListT(list); var ptr = UnsafeUtility.PinGCArrayAndGetDataAddress(lArray, out var handle); nativeArray = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray <T>(ptr, list.Count, Allocator.None); #if ENABLE_UNITY_COLLECTIONS_CHECKS DisposeSentinel.Create(out var safety, out var sentinel, 0, Allocator.None); NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref nativeArray, safety); return(new NativeArrayViewHandle(handle, safety, sentinel)); #else return(new NativeArrayViewHandle(handle)); #endif }
private static NativeArray <int> ArrayFromList(List <int> list, Allocator allocator) { if (list == null || list.Count == 0) { return(new NativeArray <int>()); } var array = new NativeArray <int>(list.Count, allocator, NativeArrayOptions.UninitializedMemory); // Use explicit copy length because the internal list might be longer than Count, which causes an error NativeArray <int> .Copy(NoAllocHelpers.ExtractArrayFromListT(list), array, list.Count); return(array); }
public unsafe static int PointerDefaultIndexOf(List <int> list, int target) { var len = list.Count; fixed(int *p = NoAllocHelpers.ExtractArrayFromListT(list)) for (int i = 0; i < len; i++) { if (p[i] == target) { return(i); } } return(-1); }
public void ExtractArrayFromListTReturnsInternalList() { var list = new List <int>(5); for (var i = 0; i < 5; i++) { list.Add(0); } var array = NoAllocHelpers.ExtractArrayFromListT(list); array[3] = 4; Assert.AreEqual(4, list[3]); }
void TransformVerts(LayerSubMesh mesh) { var offset = Rot4.FromAngleFlat(target); var offseti = offset.AsInt; // Rotate around a center if (PrintPlanePatch.plantMats.Contains(mesh.material) || GraphicPrintPatch_TransformMats.graphicSingle.Contains(mesh.material)) { var vertsc = mesh.verts.Count / 5 * 4; var vertsArr = NoAllocHelpers.ExtractArrayFromListT(mesh.verts); Util.ResizeIfNeeded(ref tempVerts, vertsc); for (int i = 0; i < vertsc; i += 4) { // The mesh data lists are only used during mesh building and are otherwise unused. // In between mesh rebuilding, Carousel reuses the lists to recalculate the meshes // but also appends additional information to the end of the vertex list var center = vertsArr[vertsc + i / 4]; RotateVerts(tempVerts, vertsArr, i, center, offset); } mesh.mesh.SetVertices(tempVerts, vertsc); } // Exchange vertices // This doesn't change the set of their values but changes their order if (GraphicPrintPatch_TransformMats.exchangeMats.ContainsKey(mesh.material) || LinkedPrintPatch.linkedMaterials.Contains(mesh.material)) { var vertsc = mesh.verts.Count; var vertsArr = NoAllocHelpers.ExtractArrayFromListT(mesh.verts); Util.ResizeIfNeeded(ref tempVerts, vertsc); for (int i = 0; i < vertsc; i += 4) { ExchangeVerts(tempVerts, vertsArr, i, offseti); } mesh.mesh.SetVertices(tempVerts, vertsc); } }
public unsafe static int PointerDefaultIndexOfThrows(List <int> list, int target) { var len = list.Count; fixed(int *p = NoAllocHelpers.ExtractArrayFromListT(list)) for (int i = 0; i < len; i++) { if (i < 0 || i >= len) { throw new ArgumentOutOfRangeException(); } if (p[i] == target) { return(i); } } return(-1); }
// https://forum.unity.com/threads/nativearray-and-mesh.522951/ // avoid having to call NativeList.ToArray() when assigning a Mesh attribute which results in garbage // There seems some GCAllocs still happen, but CPU spikes seem to be improved alot // NOTE: that the buffer resizes up to the size of native, and does not shrink to avoid allocations -> Potential Memory Hog // TODO: This HACK will go away with the official support of NativeArrays / NativeLists? in https://forum.unity.com/threads/feedback-wanted-mesh-scripting-api-improvements.684670/ static unsafe void assignNativeListToBuffer <TNative, T> (NativeList <TNative> native, ref List <T> buffer) where TNative : struct where T : struct { //Debug.Assert(buffer.Count == 0); Debug.Assert(UnsafeUtility.SizeOf <TNative>() == UnsafeUtility.SizeOf <T>()); if (native.Length > 0) { if (buffer.Capacity < native.Length) { buffer.Capacity = native.Length; } var arr = NoAllocHelpers.ExtractArrayFromListT(buffer); var size = UnsafeUtility.SizeOf <T>(); var ptr = (byte *)UnsafeUtility.AddressOf(ref arr[0]); UnsafeUtility.MemCpy(ptr, native.GetUnsafePtr(), native.Length * (long)size); } NoAllocHelpers.ResizeList(buffer, native.Length); }
public static unsafe void CopyIntegers(NativeList <int> src, List <int> dst) { if (dst.Capacity < src.Length) { dst.Capacity = src.Length; } var array = NoAllocHelpers.ExtractArrayFromListT(dst); fixed(int *arrayPtr = array) { var dstSlice = NativeSliceUnsafeUtility.ConvertExistingDataToNativeSlice <int>(arrayPtr, sizeof(int), src.Length); #if ENABLE_UNITY_COLLECTIONS_CHECKS NativeSliceUnsafeUtility.SetAtomicSafetyHandle(ref dstSlice, AtomicSafetyHandle.GetTempUnsafePtrSliceHandle()); #endif dstSlice.CopyFrom((NativeArray <int>)src); } NoAllocHelpers.ResizeList(dst, src.Length); }
static unsafe void NativeAddRange <T>(this List <T> list, NativeSlice <T> nativeSlice) where T : struct { var index = list.Count; var newLength = index + nativeSlice.Length; // Resize our list if we require if (list.Capacity < newLength) { list.Capacity = newLength; } var items = NoAllocHelpers.ExtractArrayFromListT(list); var size = UnsafeUtility.SizeOf <T>(); // Get the pointer to the end of the list var bufferStart = (IntPtr)UnsafeUtility.AddressOf(ref items[0]); var buffer = (byte *)(bufferStart + (size * index)); UnsafeUtility.MemCpy(buffer, nativeSlice.GetUnsafePtr(), nativeSlice.Length * (long)size); NoAllocHelpers.ResizeList(list, newLength); }
private static GameObject CreateMesh(string ifcGuid, IFCObjectID ifcObjectData, MemoryMap map) { var dimensions = map.Dimensions; int offset = 0; for (int i = 0; i < ifcObjectData.Voxel.Layer; i++) { offset += dimensions[i].x * dimensions[i].y * dimensions[i].z; } var begin = map.Contains[offset + ifcObjectData.Voxel.Index].Begin; var vertexInfo = map.VerticesInfo[begin + ifcObjectData.Index].Vertex; var vertexCount = vertexInfo.End - vertexInfo.Begin; var indexInfo = map.VerticesInfo[begin + ifcObjectData.Index].Indices; var indexCount = indexInfo.End - indexInfo.Begin; Debug.Assert(indexCount > 0); var vertices = new List <Vector3>(vertexCount); NoAllocHelpers.ResizeList(vertices, vertexCount); fixed(Vector3 *p = NoAllocHelpers.ExtractArrayFromListT(vertices)) { UnsafeUtility.MemCpy(p, &map.Vertices[vertexInfo.Begin], vertexCount * sizeof(Vector3)); } var normals = new List <Vector3>(vertexCount); NoAllocHelpers.ResizeList(normals, vertexCount); fixed(Vector3 *p = NoAllocHelpers.ExtractArrayFromListT(normals)) { UnsafeUtility.MemCpy(p, &map.Normals[vertexInfo.Begin], vertexCount * sizeof(Vector3)); } var colors = new List <Color32>(vertexCount); NoAllocHelpers.ResizeList(colors, vertexCount); for (int i = 0; i < colors.Count; i++) { colors[i] = Color.magenta; } var indices = new List <int>(indexCount); NoAllocHelpers.ResizeList(indices, indexCount); fixed(int *p = NoAllocHelpers.ExtractArrayFromListT(indices)) { UnsafeUtility.MemCpy(p, &map.Indices[indexInfo.Begin], indexCount * sizeof(int)); } for (int i = 0; i < indices.Count; i++) { vertices[indices[i]] += normals[indices[i]] * 0.01f; } var mesh = new Mesh(); mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; mesh.SetVertices(vertices); mesh.SetNormals(normals); mesh.SetColors(colors); mesh.SetTriangles(indices, 0); var go = GameObject.CreatePrimitive(PrimitiveType.Cube); go.name = ifcGuid; var filter = go.GetComponent <MeshFilter>(); filter.mesh = mesh; var renderer = go.GetComponent <MeshRenderer>(); renderer.material = Globals.Instance.data.OpaqueMaterial; return(go); }
public static T[] array <T>(this List <T> list) { return(NoAllocHelpers <T> .ExtractArrayFromListT(list)); }
public static ref T refAt <T>(this List <T> list, int index) { var array = NoAllocHelpers <T> .ExtractArrayFromListT(list); return(ref array[index]); }