internal unsafe static void SetBodyLinearVelocity(PhysicsBodyHandle body, Vector3 velocity) { AlignedAllocation <Vector4> vec4Aligned = new AlignedAllocation <Vector4>(16L, (uint)sizeof(Vector4)); *((Vector4 *)vec4Aligned.AlignedPointer) = velocity; // WARNING: No longer thread-safe try { unsafe { char *failReason = stackalloc char[InteropUtils.MAX_INTEROP_FAIL_REASON_STRING_LENGTH + 1]; bool success = NativeMethods.PhysicsManager_SetBodyLinearVelocity((IntPtr)failReason, body, vec4Aligned.AlignedPointer); if (!success) { throw new NativeOperationFailedException(Marshal.PtrToStringUni((IntPtr)failReason)); } } } finally { vec4Aligned.Dispose(); } }
public void SetPhysicsShape( PhysicsShapeHandle shapeHandle, Vector3 physicsShapeOffset, float mass, bool forceIntransigence = false, bool disablePerformanceDeactivation = false, bool collideOnlyWithWorld = false, bool collideWithOnlyDynamics = false, float restitution = PhysicsManager.DEFAULT_RESTITUTION, float linearDamping = PhysicsManager.DEFAULT_LINEAR_DAMPING, float angularDamping = PhysicsManager.DEFAULT_ANGULAR_DAMPING, float friction = PhysicsManager.DEFAULT_FRICTION, float rollingFriction = PhysicsManager.DEFAULT_ROLLING_FRICTION) { LosgapSystem.InvokeOnMaster(() => { // Anti-deadlock measures x.x lock (InstanceMutationLock) { if (physicsBody != PhysicsBodyHandle.NULL) { physicsBody.Dispose(); } if (this.physicsShapeOffset == null) { this.physicsShapeOffset = new AlignedAllocation <Vector4>(TRANSFORM_ALIGNMENT, (uint)sizeof(Vector4)); } this.physicsShapeOffset.Value.Write(physicsShapeOffset); physicsBody = PhysicsManager.CreateRigidBody( shapeHandle, mass, disablePerformanceDeactivation, forceIntransigence, collideOnlyWithWorld, collideWithOnlyDynamics, transform.AlignedPointer + 32, transform.AlignedPointer + 16, this.physicsShapeOffset.Value.AlignedPointer ); } }); SetPhysicsProperties(restitution, linearDamping, angularDamping, friction, rollingFriction); }
internal static unsafe void RayTestAllLessGarbage(Vector3 startPoint, Vector3 endPoint, uint maxCollisions, List <RayTestCollisionDesc> reusableResultsList) { RayTestCollisionDesc *collisionArr = stackalloc RayTestCollisionDesc[(int)maxCollisions]; uint maxCollisionsLocal = maxCollisions; RayTestCollisionDesc *collisionArrLocal = collisionArr; uint outNumCollisions; AlignedAllocation <Vector4> startPointAligned = new AlignedAllocation <Vector4>(16L, (uint)sizeof(Vector4)); *((Vector4 *)startPointAligned.AlignedPointer) = startPoint; AlignedAllocation <Vector4> endPointAligned = new AlignedAllocation <Vector4>(16L, (uint)sizeof(Vector4)); *((Vector4 *)endPointAligned.AlignedPointer) = endPoint; // WARNING: No longer thread-safe unsafe { char *failReason = stackalloc char[InteropUtils.MAX_INTEROP_FAIL_REASON_STRING_LENGTH + 1]; bool success = NativeMethods.PhysicsManager_RayTestAll( (IntPtr)failReason, startPointAligned.AlignedPointer, endPointAligned.AlignedPointer, (IntPtr)collisionArrLocal, maxCollisionsLocal, (IntPtr)(&outNumCollisions) ); if (!success) { throw new NativeOperationFailedException(Marshal.PtrToStringUni((IntPtr)failReason)); } } startPointAligned.Dispose(); endPointAligned.Dispose(); reusableResultsList.Clear(); for (uint i = 0U; i < outNumCollisions; ++i) { reusableResultsList.Add(collisionArr[i]); } }
internal GeometryCache(IVertexBuffer[] vertexComponentBuffers, string[] vertexComponentSemantics, ResourceFormat[] vertexComponentFormats, IndexBuffer indices, AlignedAllocation <uint> componentStartPointsAlloc, AlignedAllocation <uint> indexStartPointsAlloc, uint numModels, Type vertexType, int cacheID, Dictionary <string, ModelHandle> nameToHandleMap, bool orderFirst) { Assure.NotNull(vertexComponentBuffers); Assure.NotNull(vertexComponentSemantics); Assure.NotNull(vertexComponentFormats); Assure.NotNull(indices); Assure.Equal(vertexComponentBuffers.Length, vertexComponentSemantics.Length, "One or more vertex component arrays have different lengths."); Assure.Equal(vertexComponentFormats.Length, vertexComponentSemantics.Length, "One or more vertex component arrays have different lengths."); Assure.GreaterThan(vertexComponentBuffers.Length, 0, "Geometry cache with no vertex buffers is invalid."); Assure.NotNull(nameToHandleMap); this.vertexComponentBuffers = vertexComponentBuffers; this.vertexComponentSemantics = vertexComponentSemantics; this.vertexComponentFormats = vertexComponentFormats; this.indices = indices; this.componentStartPointsAlloc = componentStartPointsAlloc; this.indexStartPointsAlloc = indexStartPointsAlloc; this.componentStartPoints = (uint *)this.componentStartPointsAlloc.AlignedPointer; this.indexStartPoints = (uint *)this.indexStartPointsAlloc.AlignedPointer; this.NumModels = numModels; this.VertexType = vertexType; this.ID = cacheID; this.nameToHandleMap = nameToHandleMap; lock (staticMutationLock) { activeCaches.Add(ID, this); if (orderFirst) { activeCacheList.Insert(0, this); } else { activeCacheList.Add(this); } } this.createInputLayoutFunc = CreateInputLayout; GC.AddMemoryPressure(sizeof(uint) * 2 * (NumModels + 1)); }
public static unsafe PhysicsShapeHandle CreateCompoundCurveShape(IEnumerable <Vector3> vertices, CollisionShapeOptionsDesc shapeOptions) { return(LosgapSystem.InvokeOnMaster(() => { AlignedAllocation <CollisionShapeOptionsDesc> shapeOptionsAligned = new AlignedAllocation <CollisionShapeOptionsDesc>(16L, (uint)sizeof(CollisionShapeOptionsDesc)); *((CollisionShapeOptionsDesc *)shapeOptionsAligned.AlignedPointer) = shapeOptions; Vector3 *verticesLocal = stackalloc Vector3[vertices.Count()]; int numVertices = 0; foreach (Vector3 vertex in vertices) { verticesLocal[numVertices++] = vertex; } PhysicsShapeHandle result; InteropUtils.CallNative( NativeMethods.PhysicsManager_CreateCompoundCurveShape, (IntPtr)verticesLocal, (uint)numVertices / 8U, shapeOptionsAligned.AlignedPointer, (IntPtr)(&result) ).ThrowOnFailure(); shapeOptionsAligned.Dispose(); return result; })); }
internal static unsafe PhysicsBodyHandle RayTestNearest(Vector3 startPoint, Vector3 endPoint, out Vector3 hitPoint) { AlignedAllocation <Vector4> hitPointAligned = new AlignedAllocation <Vector4>(16L, (uint)sizeof(Vector4)); Vector4 *hitPoint4Ptr = (Vector4 *)hitPointAligned.AlignedPointer; var result = LosgapSystem.InvokeOnMaster(() => { AlignedAllocation <Vector4> startPointAligned = new AlignedAllocation <Vector4>(16L, (uint)sizeof(Vector4)); *((Vector4 *)startPointAligned.AlignedPointer) = startPoint; AlignedAllocation <Vector4> endPointAligned = new AlignedAllocation <Vector4>(16L, (uint)sizeof(Vector4)); *((Vector4 *)endPointAligned.AlignedPointer) = endPoint; Vector4 *hitPoint4PtrLocal = hitPoint4Ptr; PhysicsBodyHandle outPBH; InteropUtils.CallNative(NativeMethods.PhysicsManager_RayTestNearest, startPointAligned.AlignedPointer, endPointAligned.AlignedPointer, (IntPtr)(&outPBH), (IntPtr)(hitPoint4PtrLocal) ).ThrowOnFailure(); startPointAligned.Dispose(); endPointAligned.Dispose(); return(outPBH); }); try { if (result != PhysicsBodyHandle.NULL) { hitPoint = (Vector3)(*((Vector4 *)hitPointAligned.AlignedPointer)); } else { hitPoint = Vector3.ZERO; } return(result); } finally { hitPointAligned.Dispose(); } }
public void TestReadAndWrite() { // Define variables and constants const int NUM_ALLOCS = 200; AlignedAllocation <Matrix>[] allocs = new AlignedAllocation <Matrix> [NUM_ALLOCS]; // Set up context for (int i = 0; i < allocs.Length; i++) { allocs[i] = new AlignedAllocation <Matrix>(16L); } // Execute for (int i = 0; i < allocs.Length; i++) { allocs[i].Write(new Matrix( i, i * 2, i * 3, i * 4, i * 11, i * 12, i * 13, i * 14, i * 21, i * 22, i * 23, i * 24, i * 31, i * 32, i * 33, i * 34 )); } // Assert outcome for (int i = 0; i < allocs.Length; i++) { Assert.AreEqual(new Matrix( i, i * 2, i * 3, i * 4, i * 11, i * 12, i * 13, i * 14, i * 21, i * 22, i * 23, i * 24, i * 31, i * 32, i * 33, i * 34 ), allocs[i]); } allocs.ForEach(alloc => alloc.Dispose()); }
public void TestAlignment() { // Define variables and constants const int NUM_ALLOCATIONS_PER_TEST_ALIGNMENT = 350; int[] testAlignments = { 1, 2, 3, 4, 6, 8, 12, 16, 32 }; // Set up context // Execute // Assert outcome for (int i = 0; i < testAlignments.Length; i++) { for (int j = 0; j < NUM_ALLOCATIONS_PER_TEST_ALIGNMENT; j++) { AlignedAllocation <Matrix> alignedAlloc = new AlignedAllocation <Matrix>(testAlignments[i]); Assert.IsTrue(((long)alignedAlloc.AlignedPointer) % testAlignments[i] == 0L); alignedAlloc.Dispose(); } } }
/// <summary> /// Builds the <see cref="GeometryCache"/> with all the models that have previously been added with <see cref="AddModel"/>. /// This method may only be called once per GeometryCacheBuilder. /// </summary> /// <returns>A new <see cref="GeometryCache"/> containing 'baked' resource data for all the loaded models and an /// "instance pool", allowing model instances to be created and loaded in to the <see cref="Scene"/>.</returns> public unsafe GeometryCache Build() { lock (instanceMutationLock) { if (isBuilt) { throw new InvalidOperationException("Cache has already been built!"); } FieldInfo[] vertexComponents = typeof(TVertex).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (vertexComponents.Length > VertexShader.MAX_VS_INPUT_BINDINGS) { throw new InvalidOperationException("Vertex type '" + typeof(TVertex).Name + "' has too many components. Maximum " + "permissible is " + VertexShader.MAX_VS_INPUT_BINDINGS + ", but the vertex type has " + vertexComponents.Length + " fields."); } else if (vertexComponents.Length == 0) { throw new InvalidOperationException("Vertex type '" + typeof(TVertex).Name + "' has no components. Please choose a type with " + "at least one field."); } if (vertexCounts.Count == 0) { throw new InvalidOperationException("Can not build empty geometry cache: Please add at least one model first!"); } if (modelNames.AnyDuplicates()) { throw new InvalidOperationException("No two models should have the same name."); } if (GeometryCache.CheckForModelNameClashes(modelNames)) { throw new InvalidOperationException("One or more model names added to this builder have already been used in other active geometry caches."); } IVertexBuffer[] vertexComponentBuffers = new IVertexBuffer[vertexComponents.Length]; string[] vertexComponentSemantics = new string[vertexComponents.Length]; ResourceFormat[] vertexComponentFormats = new ResourceFormat[vertexComponents.Length]; for (int i = 0; i < vertexComponents.Length; ++i) { FieldInfo component = vertexComponents[i]; if (!component.FieldType.IsBlittable()) { throw new InvalidOperationException("Invalid vertex component type: '" + component.FieldType.Name + "'."); } if (!component.HasCustomAttribute <VertexComponentAttribute>()) { throw new InvalidOperationException("Every field on given vertex type (" + typeof(TVertex).Name + ") must be annoted with " + "a " + typeof(VertexComponentAttribute).Name + "!"); } typeof(GeometryCacheBuilder <TVertex>) .GetMethod("FillComponentBuffer", BindingFlags.NonPublic | BindingFlags.Instance) // TODO replace with nameof() operator when C#6 is released .MakeGenericMethod(component.FieldType) .Invoke(this, new object[] { component, i, vertexComponentBuffers, vertexComponentSemantics, vertexComponentFormats }); } IndexBuffer indexBuffer = BufferFactory.NewIndexBuffer().WithInitialData(indices.ToArray()).WithUsage(ResourceUsage.Immutable); Assure.Equal(vertexCounts.Count, indexCounts.Count); AlignedAllocation <uint> componentStartPointsAlloc = AlignedAllocation <uint> .AllocArray( START_POINT_ARRAY_ALIGNMENT, (uint)vertexCounts.Count + 1U // Extra one so we can set the last value to one-past-the-end (performance improvement later on) ); AlignedAllocation <uint> indexStartPointsAlloc = AlignedAllocation <uint> .AllocArray( START_POINT_ARRAY_ALIGNMENT, (uint)vertexCounts.Count + 1U // Extra one so we can set the last value to one-past-the-end (performance improvement later on) ); uint *componentStartPtr = (uint *)componentStartPointsAlloc.AlignedPointer; uint *indexStartPtr = (uint *)indexStartPointsAlloc.AlignedPointer; uint vbCounter = 0U; uint ibCounter = 0U; for (int i = 0; i < vertexCounts.Count; ++i) { componentStartPtr[i] = vbCounter; indexStartPtr[i] = ibCounter; vbCounter += vertexCounts[i]; ibCounter += indexCounts[i]; } // Set the last two elements of each start-point array to one-past-the-last, so we don't have to test // for being the 'last' count later on componentStartPtr[vertexCounts.Count] = (uint)vertices.Count; indexStartPtr[vertexCounts.Count] = (uint)indices.Count; Dictionary <string, ModelHandle> modelNameToHandleMap = new Dictionary <string, ModelHandle>(); for (uint i = 0U; i < modelNames.Count; ++i) { modelNameToHandleMap.Add(modelNames[(int)i], new ModelHandle(cacheID, i)); } isBuilt = true; return(new GeometryCache( vertexComponentBuffers, vertexComponentSemantics, vertexComponentFormats, indexBuffer, componentStartPointsAlloc, indexStartPointsAlloc, (uint)vertexCounts.Count, typeof(TVertex), cacheID, modelNameToHandleMap, orderFirst )); } }
public unsafe void TestGetModelBufferValues() { // Define variables and constants const int FAKE_CACHE_ID = 1351616; IVertexBuffer[] buffers = new IVertexBuffer[2]; buffers[0] = BufferFactory.NewVertexBuffer <Vector3>() .WithInitialData(new[] { Vector3.ONE * 0f, Vector3.ONE * 1f, Vector3.ONE * 2f, Vector3.ONE * 3f, Vector3.ONE * 4f, Vector3.ONE * 5f }) .WithUsage(ResourceUsage.Immutable) .Create(); buffers[1] = BufferFactory.NewVertexBuffer <Vector2>() .WithInitialData(new[] { Vector2.ONE * 0f, Vector2.ONE * 1f, Vector2.ONE * 2f, Vector2.ONE * 3f, Vector2.ONE * 4f, Vector2.ONE * 5f }) .WithUsage(ResourceUsage.Immutable) .Create(); string[] semantics = { "POSITION", "TEXCOORD" }; ResourceFormat[] formats = { ResourceFormat.R32G32B32Float, ResourceFormat.R32G32Float }; IndexBuffer indices = BufferFactory.NewIndexBuffer() .WithInitialData(new uint[] { 0, 1, 2, 1, 2, 0, 2, 1, 0, 3, 4, 5, 4, 5, 3, 5, 3, 4, 5, 3, 4 }) .WithUsage(ResourceUsage.Immutable); AlignedAllocation <uint> componentStartPointsAlloc = AlignedAllocation <uint> .AllocArray(7L, 3); *(((uint *)componentStartPointsAlloc.AlignedPointer) + 0) = 0U; *(((uint *)componentStartPointsAlloc.AlignedPointer) + 1) = 3U; *(((uint *)componentStartPointsAlloc.AlignedPointer) + 2) = 6U; AlignedAllocation <uint> indexStartPointsAlloc = AlignedAllocation <uint> .AllocArray(7L, 3); *(((uint *)indexStartPointsAlloc.AlignedPointer) + 0) = 0U; *(((uint *)indexStartPointsAlloc.AlignedPointer) + 1) = 9U; *(((uint *)indexStartPointsAlloc.AlignedPointer) + 2) = 21U; Dictionary <string, ModelHandle> modelNameMap = new Dictionary <string, ModelHandle>() { { FAKE_CACHE_ID + "A", new ModelHandle(FAKE_CACHE_ID, 0U) }, { FAKE_CACHE_ID + "B", new ModelHandle(FAKE_CACHE_ID, 1U) } }; const uint NUM_MODELS = 2; uint outVBStartIndex, outIBStartIndex, outVBCount, outIBCount; // Set up context GeometryCache cache = new GeometryCache( buffers, semantics, formats, indices, componentStartPointsAlloc, indexStartPointsAlloc, NUM_MODELS, typeof(FakeVertex), FAKE_CACHE_ID, modelNameMap ); // Execute cache.GetModelBufferValues(0U, out outVBStartIndex, out outIBStartIndex, out outVBCount, out outIBCount); // Assert outcome Assert.AreEqual(0U, outVBStartIndex); Assert.AreEqual(0U, outIBStartIndex); Assert.AreEqual(3U, outVBCount); Assert.AreEqual(9U, outIBCount); cache.GetModelBufferValues(1U, out outVBStartIndex, out outIBStartIndex, out outVBCount, out outIBCount); Assert.AreEqual(3U, outVBStartIndex); Assert.AreEqual(9U, outIBStartIndex); Assert.AreEqual(3U, outVBCount); Assert.AreEqual(12U, outIBCount); #if !DEVELOPMENT && !RELEASE try { cache.GetModelBufferValues(2U, out outVBStartIndex, out outIBStartIndex, out outVBCount, out outIBCount); Assert.Fail(); } catch (AssuranceFailedException) { } #endif cache.Dispose(); }
public unsafe void TestGetInputLayout() { // Define variables and constants const int FAKE_CACHE_ID = 1351618; IVertexBuffer[] buffers = new IVertexBuffer[2]; buffers[0] = BufferFactory.NewVertexBuffer <Vector3>() .WithInitialData(new[] { Vector3.ONE * 0f, Vector3.ONE * 1f, Vector3.ONE * 2f, Vector3.ONE * 3f, Vector3.ONE * 4f, Vector3.ONE * 5f }) .WithUsage(ResourceUsage.Immutable) .Create(); buffers[1] = BufferFactory.NewVertexBuffer <float>() .WithInitialData(new[] { 0f, 1f, 2f, 3f, 4f, 5f }) .WithUsage(ResourceUsage.Immutable) .Create(); string[] semantics = { "POSITION", "RANDOM_FLOATS" }; ResourceFormat[] formats = { ResourceFormat.R32G32B32Float, ResourceFormat.R32G32Float }; IndexBuffer indices = BufferFactory.NewIndexBuffer() .WithInitialData(new uint[] { 0, 1, 2, 1, 2, 0, 2, 1, 0, 3, 4, 5, 4, 5, 3, 5, 3, 4, 5, 3, 4 }) .WithUsage(ResourceUsage.Immutable); AlignedAllocation <uint> componentStartPointsAlloc = AlignedAllocation <uint> .AllocArray(7L, 3); *(((uint *)componentStartPointsAlloc.AlignedPointer) + 0) = 0U; *(((uint *)componentStartPointsAlloc.AlignedPointer) + 1) = 3U; *(((uint *)componentStartPointsAlloc.AlignedPointer) + 2) = 6U; AlignedAllocation <uint> indexStartPointsAlloc = AlignedAllocation <uint> .AllocArray(7L, 3); *(((uint *)indexStartPointsAlloc.AlignedPointer) + 0) = 0U; *(((uint *)indexStartPointsAlloc.AlignedPointer) + 1) = 9U; *(((uint *)indexStartPointsAlloc.AlignedPointer) + 2) = 21U; Dictionary <string, ModelHandle> modelNameMap = new Dictionary <string, ModelHandle>() { { FAKE_CACHE_ID + "A", new ModelHandle(FAKE_CACHE_ID, 0U) }, { FAKE_CACHE_ID + "B", new ModelHandle(FAKE_CACHE_ID, 1U) } }; const uint NUM_MODELS = 2; // Set up context GeometryCache cache = new GeometryCache( buffers, semantics, formats, indices, componentStartPointsAlloc, indexStartPointsAlloc, NUM_MODELS, typeof(Vector4), FAKE_CACHE_ID, modelNameMap ); ConstantBuffer <Matrix> instanceCBuffer = BufferFactory.NewConstantBuffer <Matrix>().WithUsage(ResourceUsage.DiscardWrite); VertexShader vs1 = new VertexShader( @"Tests\SimpleVS.cso", new VertexInputBinding(0U, "INSTANCE_TRANSFORM"), new ConstantBufferBinding(0U, "CameraTransform", instanceCBuffer), new VertexInputBinding(1U, "POSITION") ); VertexShader vs2 = new VertexShader( @"Tests\SimpleVS.cso", new VertexInputBinding(0U, "INSTANCE_TRANSFORM"), new ConstantBufferBinding(0U, "CameraTransform", instanceCBuffer), new VertexInputBinding(1U, "RANDOM_FLOATS"), new VertexInputBinding(2U, "POSITION") ); VertexShader vs3 = new VertexShader( @"Tests\SimpleVS.cso", new VertexInputBinding(0U, "INSTANCE"), new ConstantBufferBinding(0U, "VPTransform", instanceCBuffer), new VertexInputBinding(1U, "TEXCOORD") ); // Execute GeometryInputLayout inputLayout1 = cache.GetInputLayout(vs1); GeometryInputLayout inputLayout2 = cache.GetInputLayout(vs2); try { cache.GetInputLayout(vs3); Assert.Fail(); } catch (InvalidOperationException) { } // Assert outcome Assert.AreEqual(cache, inputLayout1.AssociatedCache); Assert.AreEqual(cache, inputLayout2.AssociatedCache); Assert.AreEqual(vs1, inputLayout1.AssociatedShader); Assert.AreEqual(vs2, inputLayout2.AssociatedShader); KeyValuePair <VertexInputBinding, IVertexBuffer>[] boundCompBuffers = inputLayout1.BoundComponentBuffers; Assert.AreEqual(buffers[0], boundCompBuffers.First(kvp => kvp.Key == vs1.GetBindingByIdentifier("POSITION")).Value); Assert.IsFalse(boundCompBuffers.Any(kvp => kvp.Value == buffers[1])); boundCompBuffers = inputLayout2.BoundComponentBuffers; Assert.AreEqual(buffers[0], boundCompBuffers.First(kvp => kvp.Key == vs2.GetBindingByIdentifier("POSITION")).Value); Assert.AreEqual(buffers[1], boundCompBuffers.First(kvp => kvp.Key == vs2.GetBindingByIdentifier("RANDOM_FLOATS")).Value); Assert.AreEqual(inputLayout1, cache.GetInputLayout(vs1)); Assert.AreEqual(inputLayout2, cache.GetInputLayout(vs2)); cache.Dispose(); inputLayout2.Dispose(); inputLayout1.Dispose(); vs1.Dispose(); vs2.Dispose(); vs3.Dispose(); instanceCBuffer.Dispose(); indices.Dispose(); buffers[1].Dispose(); buffers[0].Dispose(); }