public void GetArrays(out Vector3[] vertices, out Vector3[] normals, out Color32[] colors, out int[] indices) { vertices = NoAllocHelpers.ExtractArrayFromListT(Vertices); normals = NoAllocHelpers.ExtractArrayFromListT(Normals); colors = NoAllocHelpers.ExtractArrayFromListT(Colors); indices = NoAllocHelpers.ExtractArrayFromListT(Indices); }
public unsafe void LateUpdate() { var vertices = this.instance.vertices.cpuReference; fixed(Vector3 *pVertices = vertices) { UnsafeUtility.MemCpy(this.splineVertices.GetUnsafePtr(), (void *)pVertices, UnsafeUtility.SizeOf <Vector3>() * vertices.Length); } handle = new PositionUpdateJob() { normals = this.normals, segments = this.segments, hairVertices = this.splineVertices, vertices = this.triVertices, facing = this.facing.position, hairWidth = this.hairWidth, worldToLocal = this.transform.worldToLocalMatrix }.Schedule(this.segments.Length, 16); JobHandle.ScheduleBatchedJobs(); handle.Complete(); NoAllocHelpers.SetMesh(this.mesh, this.triVertices, null, this.normals); this.mesh.UploadMeshData(false); }
public void ResizeListCorrectCount() { var list = new List <int>(5); NoAllocHelpers.ResizeList(list, 3); Assert.AreEqual(3, list.Count); }
/// <summary>Erases tiles and GameObjects from given bounds within the selected layers.</summary> /// <param name="gridLayout">Grid to erase data from.</param> /// <param name="brushTarget">Target of the erase operation. By default the currently selected GameObject.</param> /// <param name="position">The bounds to erase data from.</param> public override void BoxErase(GridLayout gridLayout, GameObject brushTarget, BoundsInt position) { if (brushTarget == null) { return; } Tilemap map = brushTarget.GetComponent <Tilemap>(); if (map == null) { return; } int count = 0; var identity = Matrix4x4.identity; var listSize = Math.Abs(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) { m_TileChangeDataList.Add(new TileChangeData { position = location, tile = null, transform = identity, color = Color.white }); } var tileChangeData = NoAllocHelpers.ExtractArrayFromListT(m_TileChangeDataList); map.SetTiles(tileChangeData, false); }
void TransformShadows(LayerSubMesh mesh) { if (mesh.uvs.Count == 0) { return; } var rot = Rot4.FromAngleFlat(target); var uvs = mesh.uvs; var vertsc = mesh.verts.Count; var origVerts = NoAllocHelpers.ExtractArrayFromListT(mesh.verts); Util.ResizeIfNeeded(ref tempVerts, vertsc); for (int i = 0; i <= vertsc - 5; i += 5) { var offset = uvs[i / 10]; if (offset == Vector3.zero) { Array.Copy(origVerts, i, tempVerts, i, 5); continue; } var r = offset.RotatedBy(rot) - offset; tempVerts[i] = origVerts[i] + r; tempVerts[i + 1] = origVerts[i + 1] + r; tempVerts[i + 2] = origVerts[i + 2] + r; tempVerts[i + 3] = origVerts[i + 3] + r; tempVerts[i + 4] = origVerts[i + 4] + r; } mesh.mesh.SetVertices(tempVerts, vertsc); }
public static unsafe void *GetUnsafePtr <T>(this List <T> list, out ulong gcHandle) where T : struct { return(UnsafeUtility.PinGCArrayAndGetDataAddress( NoAllocHelpers.ExtractArrayFromListT(list), out gcHandle )); }
public void SetIndexCount(int count) { if (count > Indices.Capacity) { Indices.Capacity = count; } NoAllocHelpers.ResizeList(Indices, count); }
public static Mesh.MeshDataArray AcquireReadOnlyMeshData(List <Mesh> meshes) { if (meshes == null) { throw new ArgumentNullException(nameof(meshes), "Mesh list is null"); } return(new Mesh.MeshDataArray(NoAllocHelpers.ExtractArrayFromListT(meshes), meshes.Count, false)); }
public static void CopyTo <T>(List <T> dst, List <T> src) where T : unmanaged { dst.Capacity = src.Count; NoAllocHelpers.ResizeList(dst, src.Count); using (dst.ViewAsNativeArray(out var dstArray)) using (src.ViewAsNativeArray(out var srcArray)) dstArray.CopyFrom(srcArray); }
public static void ResizeList <T>(List <T> list, int count) { if (list.Capacity < count) { list.Capacity = count; } NoAllocHelpers.ResizeList(list, count); }
public static unsafe List <int> V128Filter(List <int> src, int target) { var dst = new List <int>(src.Count); using var srcDispose = src.ViewAsNativeArray(out var srcArray); using var dstDispose = dst.ViewAsNativeArray(out var dstArray); V128Filter((int *)srcArray.GetUnsafeReadOnlyPtr(), srcArray.Length, target, (int *)dstArray.GetUnsafePtr(), out var dstCount); NoAllocHelpers.ResizeList(dst, dstCount); return(dst); }
public static unsafe List <int> V128Filter(List <int> list, int greaterThan, int lessThan) { var dst = new List <int>(list.Count); using var srcDispose = list.ViewAsNativeArray(out var srcArray); using var dstDispose = dst.ViewAsNativeArray(out var dstArray); V128Filter((int *)srcArray.GetUnsafeReadOnlyPtr(), srcArray.Length, greaterThan, lessThan, (int *)dstArray.GetUnsafePtr(), out var dstCount); NoAllocHelpers.ResizeList(dst, dstCount); return(dst); }
public static unsafe List <u32> V128ForLoop(List <u8> src) { var dst = new List <u32>(src.Count / 3); using (dst.ViewAsNativeArray(out var dstArray)) using (src.ViewAsNativeArray(out var srcArray)) V128ForLoop((u8 *)srcArray.GetUnsafePtr(), (u32 *)dstArray.GetUnsafePtr(), dst.Capacity); NoAllocHelpers.ResizeList(dst, src.Count / 3); return(dst); }
public SoAMesh(int vertexCount, int indexCount) { Vertices = new List <Vector3>(vertexCount); Normals = new List <Vector3>(vertexCount); Colors = new List <Color32>(vertexCount); Indices = new List <int>(indexCount); NoAllocHelpers.ResizeList(Vertices, vertexCount); NoAllocHelpers.ResizeList(Normals, vertexCount); NoAllocHelpers.ResizeList(Colors, vertexCount); NoAllocHelpers.ResizeList(Indices, indexCount); }
// Note: No checking that there is actually this many vertices in here. // However, it will increase capacity if needed. public void SetVertexCount(int count) { if (count > Vertices.Capacity) { Vertices.Capacity = count; Normals.Capacity = count; Colors.Capacity = count; } NoAllocHelpers.ResizeList(Vertices, count); NoAllocHelpers.ResizeList(Normals, count); NoAllocHelpers.ResizeList(Colors, count); }
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]); }
public static unsafe void EmitSessionMetaData <T>(Guid id, int tag, List <T> data) where T : struct { if (data == null) { throw new ArgumentNullException("data"); } var elementType = typeof(T); if (!UnsafeUtility.IsBlittable(typeof(T))) { throw new ArgumentException(string.Format("{0} type must be blittable", elementType)); } Internal_EmitGlobalMetaData_Array(&id, 16, tag, NoAllocHelpers.ExtractArrayFromList(data), data.Count, UnsafeUtility.SizeOf(elementType), false); }
public static void EmitFrameMetaData <T>(Guid id, int tag, List <T> data) where T : struct { if (data == null) { throw new ArgumentNullException("data"); } var elementType = typeof(T); if (!UnsafeUtility.IsBlittable(typeof(T))) { throw new ArgumentException(string.Format("{0} type used in Profiler.ReportFrameStats must be blittable", elementType)); } Internal_EmitFrameMetaData_Array(id.ToByteArray(), tag, NoAllocHelpers.ExtractArrayFromList(data), data.Count, UnsafeUtility.SizeOf(elementType)); }
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); }
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); }
// 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); }
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 unsafe void NativeInject <T>(this List <T> list, int startIndex, void *src, int srcIndex, int length) where T : struct { var newLength = startIndex + length; if (list.Capacity < newLength) { list.Capacity = newLength; } var size = UnsafeUtility.SizeOf <T>(); var dst = list.GetUnsafePtr(out var gcHandle); UnsafeUtility.MemCpy( (void *)((IntPtr)dst + startIndex * size), (void *)((IntPtr)src + srcIndex * size), length * size ); UnsafeUtility.ReleaseGCObject(gcHandle); NoAllocHelpers.ResizeList(list, newLength); }