public gxtAABB GetAABB(Vector2 position, float rotation, Vector2 scale) { Vector2 c = (Start + End) * 0.5f; float rX = gxtMath.Abs((End.X - c.X) * scale.X); float rY = gxtMath.Abs((End.Y - c.Y) * scale.Y); gxtAABB localAABB = new gxtAABB(c, new Vector2(rX, rY)); return gxtAABB.Update(position, rotation, localAABB); }
public gxtDynamicIndexedPrimitive(Vector2[] verts, PrimitiveType primitiveType = PrimitiveType.TriangleList) { gxtDebug.Assert(gxtRoot.SingletonIsInitialized); this.primitiveType = primitiveType; int indicesArraySize = CalcIndicesArraySize(verts.Length, primitiveType); this.primitiveCount = CalcPrimitiveCount(indicesArraySize, primitiveType); SetupVertices(verts); SetupIndices(indicesArraySize, primitiveType); localAABB = gxtGeometry.ComputeAABB(verts); }
public gxtDynamicIndexedPrimitive(Vector2[] verts, PrimitiveType primitiveType, gxtIMaterial material, Texture2D texture, Vector2[] textureCoordinates) { gxtDebug.Assert(gxtRoot.SingletonIsInitialized); this.primitiveType = primitiveType; int indicesArraySize = CalcIndicesArraySize(verts.Length, primitiveType); this.material = material; this.texture = texture; // set up vertices SetupVertices(verts, textureCoordinates); SetupIndices(indicesArraySize, primitiveType); localAABB = gxtGeometry.ComputeAABB(verts); }
/// <summary> /// A simple boolean ray-aabb intersection test with options /// for max values of t and inside/outside checks /// </summary> /// <param name="aabb">AABB</param> /// <param name="tmax">Max Distance</param> /// <param name="insideIsCollision">If the ray origin inside the AABB still counts as a collision</param> /// <returns>If intersecting</returns> public bool IntersectsAABB(gxtAABB aabb, float tmax = float.MaxValue, bool insideIsCollision = false) { gxtDebug.Assert(tmax >= 0.0f); // special case, confirms a collision if the origin is inside the AABB // only set insideIsCollision to true if the AABB is for a more complex // narrowphase shape (e.g. a polygon) if (insideIsCollision) if (aabb.Contains(origin)) return true; Vector2 absDirection = new Vector2(gxtMath.Abs(direction.X), gxtMath.Abs(direction.Y)); Vector2 aabbMin = aabb.Min; Vector2 aabbMax = aabb.Max; float tmin = float.MinValue; //float tmax = float.MaxValue; if (absDirection.X < float.Epsilon) { // then we know it is parallel if (origin.X < aabbMin.X || origin.X > aabbMax.X) { return false; } } else { float oneOverDX = 1.0f / direction.X; float t1X = (aabbMin.X - origin.X) * oneOverDX; float t2X = (aabbMax.X - origin.X) * oneOverDX; if (t1X > t2X) { float holderTX = t1X; t1X = t2X; t2X = holderTX; } if (t1X > tmin) { tmin = t1X; } tmax = gxtMath.Min(tmax, t2X); if (tmin > tmax) return false; } if (absDirection.Y < float.Epsilon) { // then we know it is parallel if (origin.Y < aabbMin.Y || origin.Y > aabbMax.Y) { return false; } } else { float oneOverDY = 1.0f / direction.Y; float t1Y = (aabbMin.Y - origin.Y) * oneOverDY; float t2Y = (aabbMax.Y - origin.Y) * oneOverDY; if (t1Y > t2Y) { float holderTY = t1Y; t1Y = t2Y; t2Y = holderTY; } if (t1Y > tmin) { tmin = t1Y; } tmax = gxtMath.Min(tmax, t2Y); if (tmin > tmax) return false; } if (tmin < 0.0f || tmax < tmin) return false; return true; }
public void SetVertices(Vector2[] verts, Vector2[] textureCoordinates, bool setDefaultIndices = true) { gxtDebug.Assert(verts != null && verts.Length >= 3); gxtDebug.Assert(indices != null && indices.Length >= 3); gxtDebug.Assert(textureCoordinates != null && textureCoordinates.Length >= 3); gxtDebug.Assert(verts.Length == textureCoordinates.Length); vertices = new VertexPositionColorTexture[verts.Length]; if (vertexBuffer == null) vertexBuffer = new DynamicVertexBuffer(gxtRoot.Singleton.Graphics, typeof(VertexPositionColorTexture), verts.Length, BufferUsage.WriteOnly); if (material == null) { for (int i = 0; i < verts.Length; ++i) { vertices[i] = new VertexPositionColorTexture(new Vector3(verts[i].X, verts[i].Y, 0.0f), gxtMaterial.DEFAULT_COLOR_OVERLAY, textureCoordinates[i]); } } else { for (int i = 0; i < verts.Length; ++i) { vertices[i] = new VertexPositionColorTexture(new Vector3(verts[i].X, verts[i].Y, 0.0f), material.ColorOverlay, textureCoordinates[i]); } } vertexBuffer.SetData<VertexPositionColorTexture>(vertices); localAABB = gxtGeometry.ComputeAABB(verts); if (setDefaultIndices) SetDefaultIndices(3 + ((verts.Length - 3) * 3)); }
public void SetVertices(Vector2[] verts, bool setDefaultIndices = true) { gxtDebug.Assert(verts != null && verts.Length >= 3, "Vertices in a triangle mesh cannot be null or have a size less than 3!"); vertices = new VertexPositionColorTexture[verts.Length]; if (vertexBuffer == null) vertexBuffer = new DynamicVertexBuffer(gxtRoot.Singleton.Graphics, typeof(VertexPositionColorTexture), verts.Length, BufferUsage.WriteOnly); if (material == null) { for (int i = 0; i < verts.Length; ++i) { vertices[i] = new VertexPositionColorTexture(new Vector3(verts[i].X, verts[i].Y, 0.0f), gxtMaterial.DEFAULT_COLOR_OVERLAY, Vector2.Zero); } } else { for (int i = 0; i < verts.Length; ++i) { vertices[i] = new VertexPositionColorTexture(new Vector3(verts[i].X, verts[i].Y, 0.0f), gxtMaterial.DEFAULT_COLOR_OVERLAY, Vector2.Zero); } } vertexBuffer.SetData<VertexPositionColorTexture>(vertices); localAABB = gxtGeometry.ComputeAABB(verts); if (setDefaultIndices) SetDefaultIndices(3 + ((verts.Length - 3) * 3)); }
public void SetupMesh(Vector2[] verts, int[] indices, Vector2[] textureCoordinates) { gxtDebug.Assert(verts != null && verts.Length >= 3, "Vertices array is null or less than 3 vertices"); gxtDebug.Assert(indices != null && indices.Length >= 3, "Indices array is null or less than 3 indices"); gxtDebug.Assert(textureCoordinates != null && textureCoordinates.Length >= 3, "Texture Coordinates array is null or less than 3 UV coordinates"); gxtDebug.Assert(verts.Length == textureCoordinates.Length, "The vertices array and texture coordinates array have a size mismatch!"); // set up verts vertices = new VertexPositionColorTexture[verts.Length]; if (vertexBuffer == null) vertexBuffer = new DynamicVertexBuffer(gxtRoot.Singleton.Graphics, typeof(VertexPositionColorTexture), verts.Length, BufferUsage.WriteOnly); Color overlay = (material != null) ? material.ColorOverlay : gxtMaterial.DEFAULT_COLOR_OVERLAY; for (int i = 0; i < verts.Length; ++i) { vertices[i] = new VertexPositionColorTexture(new Vector3(verts[i].X, verts[i].Y, 0.0f), overlay, textureCoordinates[i]); } vertexBuffer.SetData<VertexPositionColorTexture>(vertices); localAABB = gxtGeometry.ComputeAABB(verts); // set up indices // deep copy necessary? for (int i = 0; i < indices.Length; ++i) { this.indices[i] = indices[i]; } if (indexBuffer == null) indexBuffer = new DynamicIndexBuffer(gxtRoot.Singleton.Graphics, typeof(int), indices.Length, BufferUsage.WriteOnly); indexBuffer.SetData<int>(indices); this.primitiveCount = indices.Length / 3; }
/// <summary> /// Gets the merged world space AABB of the node. /// Takes into account the AABB's of all drawable /// objects for all children nodes and merges them into /// one AABB. Potentially useful for culling algorithms. /// </summary> /// <returns>Merged AABB</returns> public virtual gxtAABB GetAABB() { Vector2 pos = GetDerivedPosition(); Vector2 s = GetDerivedScale(); float r = GetDerivedRotation(); gxtAABB aabb = new gxtAABB(pos, Vector2.Zero); gxtAABB curDrawableAABB; int i; for (i = 0; i < NumDrawables; ++i) { curDrawableAABB = drawables[i].GetLocalAABB(); curDrawableAABB = curDrawableAABB.GetRotatedAABB(r); curDrawableAABB = gxtAABB.Update(relativePosition, relativeRotation, curDrawableAABB); curDrawableAABB = new gxtAABB(pos, new Vector2(gxtMath.Abs(curDrawableAABB.Extents.X * s.X), gxtMath.Abs(curDrawableAABB.Extents.Y * s.Y))); aabb = gxtAABB.Merge(aabb, curDrawableAABB); } for (i = 0; i < NumChildrenNodes; ++i) { aabb = gxtAABB.Merge(children[i].GetAABB(), aabb); } return aabb; }
/* private static float CalculateArea(IEnumerator<Vector2> ptSet, Vector2 pt) { float minE = 0.0f, minEperp = 0.0f, maxE = 0.0f, maxEperp = 0.0f; ptSet.Reset(); while (ptSet.MoveNext()) { Vector2 diff = ptSet.Current - prev; // Project along edge axis // Store min and max scalar projections on this axis float dot = Vector2.Dot(diff, e); if (dot < minE) minE = dot; if (dot > maxE) maxE = dot; // Same for perpendicular axis dot = Vector2.Dot(diff, ePerp); if (dot < minEperp) minEperp = dot; if (dot > maxEperp) maxEperp = dot; } // Calculate area of rectangle, compare to existing minimum float area = (maxE - minE) * (maxEperp - minEperp); } public static gxtOBB ComputeOBB(IEnumerator<Vector2> ptSet) { // Area comparison value float minArea = float.MaxValue; // Instantiates members of OBB Vector2 c = new Vector2(); Vector2 r = new Vector2(); Vector2 localX = new Vector2(); Vector2 localY = new Vector2(); while (ptSet.MoveNext()) { Vector2 prev = ptSet.Current; ptSet.MoveNext(); Vector2 cur = ptSet.Current; Vector2 e = cur - prev; e.Normalize(); Vector2 ePerp = new Vector2(-e.Y, e.X); float minE = 0.0f, minEperp = 0.0f, maxE = 0.0f, maxEperp = 0.0f; ptSet.Reset(); while (ptSet.MoveNext()) { Vector2 diff = ptSet.Current - prev; // Project along edge axis // Store min and max scalar projections on this axis float dot = Vector2.Dot(diff, e); if (dot < minE) minE = dot; if (dot > maxE) maxE = dot; // Same for perpendicular axis dot = Vector2.Dot(diff, ePerp); if (dot < minEperp) minEperp = dot; if (dot > maxEperp) maxEperp = dot; } // Calculate area of rectangle, compare to existing minimum float area = (maxE - minE) * (maxEperp - minEperp); if (area < minArea) { // Store new min minArea = area; // Like finding the center of an AABB // Start with first edge point, project over to new maximum along each axis // Divide by two c = prev + 0.5f * ((minE + maxE) * e + (minEperp + maxEperp) * ePerp); // Half-Width Extents r = new Vector2((maxE - minE) * 0.5f, (maxEperp - minEperp) * 0.5f); // New axes for the OBB localX = e; localY = ePerp; } } // Setting up the for loop this way avoids modulo and lets you iterate once smoothly for (int i = 0, j = ptSet.Length - 1; i < ptSet.Length; j = i, i++) { // Normalized edge axis Vector2 e = ptSet[i] - ptSet[j]; e.Normalize(); // Perpendicular edge axis Vector2 ePerp = new Vector2(-e.Y, e.X); // The min and max projections along the edge axis and its perpendicular axis float minE = 0.0f, minEperp = 0.0f, maxE = 0.0f, maxEperp = 0.0f; // Project all points along these two axes for (int k = 0; k < ptSet.Length; k++) { Vector2 diff = ptSet[k] - ptSet[j]; // Project along edge axis // Store min and max scalar projections on this axis float dot = Vector2.Dot(diff, e); if (dot < minE) minE = dot; if (dot > maxE) maxE = dot; // Same for perpendicular axis dot = Vector2.Dot(diff, ePerp); if (dot < minEperp) minEperp = dot; if (dot > maxEperp) maxEperp = dot; } // Calculate area of rectangle, compare to existing minimum float area = (maxE - minE) * (maxEperp - minEperp); if (area < minArea) { // Store new min minArea = area; // Like finding the center of an AABB // Start with first edge point, project over to new maximum along each axis // Divide by two c = ptSet[j] + 0.5f * ((minE + maxE) * e + (minEperp + maxEperp) * ePerp); // Half-Width Extents r = new Vector2((maxE - minE) * 0.5f, (maxEperp - minEperp) * 0.5f); // New axes for the OBB localX = e; localY = ePerp; } } return new gxtOBB(c, r, localX, localY); } */ /// <summary> /// Converts an AABB to a valid polygon with 4 vertices /// </summary> /// <param name="aabb">AABB</param> /// <returns>Polygon</returns> public static gxtPolygon ComputePolygonFromAABB(gxtAABB aabb) { return new gxtPolygon(ComputeVerticesFromAABB(aabb)); }
/// <summary> /// /// </summary> /// <param name="sphere"></param> /// <param name="hitGeoms"></param> /// <param name="collisionGroup"></param> /// <returns></returns> public bool SphereCastAll(gxtSphere sphere, out List<gxtGeom> hitGeoms, gxtCollisionGroup collisionGroup = gxtCollisionGroup.ALL) { if (collisionGroup == gxtCollisionGroup.NONE) { hitGeoms = new List<gxtGeom>(); return false; } // we pass an aabb of the sphere thru the broadphase collider...for now // narrowphase tests use the actual sphere gxtAABB aabb = new gxtAABB(sphere.Position, new Vector2(sphere.Radius)); hitGeoms = broadphaseCollider.AABBCastAll(aabb); if (hitGeoms.Count == 0) return false; gxtPolygon geomPolygon; for (int i = hitGeoms.Count - 1; i >= 0; i--) { if (!CanCollide(collisionGroup, hitGeoms[i])) hitGeoms.RemoveAt(i); else { geomPolygon = hitGeoms[i].Polygon; // must ue the guranteed world centroid to ensure an accurate test // http://www.gamedev.net/topic/308060-circle-polygon-intersection-more-2d-collisions/ if (!gxtGJKCollider.Intersects(ref geomPolygon, hitGeoms[i].GetWorldCentroid(), sphere)) hitGeoms.RemoveAt(i); } } return hitGeoms.Count != 0; }
/// <summary> /// /// </summary> /// <param name="aabb"></param> /// <param name="hitGeoms"></param> /// <param name="collisionGroupName"></param> /// <returns></returns> public bool AABBCastAll(gxtAABB aabb, out List<gxtGeom> hitGeoms, string collisionGroupName) { gxtDebug.Assert(collisionGroupsMap.ContainsKey(collisionGroupName), "Named Collision Group: {0} Does Not Exist In Physics World"); gxtCollisionGroup cgroup = collisionGroupsMap[collisionGroupName]; return AABBCastAll(aabb, out hitGeoms, cgroup); }
/// <summary> /// /// </summary> /// <param name="aabb"></param> /// <param name="hitGeoms"></param> /// <param name="collisionGroup"></param> /// <returns></returns> public bool AABBCastAll(gxtAABB aabb, out List<gxtGeom> hitGeoms, gxtCollisionGroup collisionGroup = gxtCollisionGroup.ALL) { gxtDebug.Assert(aabb.Extents.X >= 0.0f && aabb.Extents.Y >= 0.0f, "An AABB with negative extents will not intersect anything"); if (collisionGroup == gxtCollisionGroup.NONE) { hitGeoms = new List<gxtGeom>(); return false; } hitGeoms = broadphaseCollider.AABBCastAll(aabb); if (hitGeoms.Count == 0) return false; gxtPolygon boxPolygon = gxtGeometry.ComputePolygonFromAABB(aabb); gxtPolygon geomPolygon; for (int i = hitGeoms.Count - 1; i >= 0; i--) { if (!CanCollide(collisionGroup, hitGeoms[i])) hitGeoms.RemoveAt(i); else { geomPolygon = hitGeoms[i].Polygon; if (!gxtGJKCollider.Intersects(ref boxPolygon, aabb.Position, ref geomPolygon, hitGeoms[i].Position)) hitGeoms.RemoveAt(i); } } return hitGeoms.Count != 0; }
/// <summary> /// /// </summary> /// <param name="aabb"></param> /// <param name="hitGeom"></param> /// <param name="collisionGroup"></param> /// <returns></returns> public bool AABBCast(gxtAABB aabb, out gxtGeom hitGeom, gxtCollisionGroup collisionGroup = gxtCollisionGroup.ALL) { hitGeom = null; List<gxtGeom> geoms; if (AABBCastAll(aabb, out geoms, collisionGroup)) { float minDist = float.MaxValue; float tmpDist; for (int i = 0; i < geoms.Count; i++) { tmpDist = (aabb.Position - geoms[i].GetWorldCentroid()).LengthSquared(); if (tmpDist < minDist) { hitGeom = geoms[i]; minDist = tmpDist; } } return true; } return false; }
/// <summary> /// Gets the AABB of the camera /// </summary> /// <returns></returns> public virtual gxtAABB GetViewAABB() { Vector2 r = halfWidthScreenExtents; float s = 1.0f / (screenScale + zoom); r *= s; gxtAABB scaledAABB = new gxtAABB(position, r); scaledAABB = scaledAABB.GetRotatedAABB(rotation); return scaledAABB; }
public gxtAABB GetAABB(Vector2 position, float rotation, Vector2 scale) { float rX = gxtMath.Abs(Origin.X * scale.X); float rY = gxtMath.Abs(Origin.Y * scale.Y); gxtAABB aabb = new gxtAABB(Vector2.Zero, new Vector2(rX, rY)); aabb = aabb.GetRotatedAABB(rotation); aabb.Translate(position); return aabb; }
public void SetVertices(Vector2[] verts, bool setDefaultIndices = true) { // overwrite the existing vertices vertices = new VertexPositionColorTexture[verts.Length]; Color overlay = (material != null) ? material.ColorOverlay : gxtMaterial.DEFAULT_COLOR_OVERLAY; for (int i = 0; i < verts.Length; ++i) { vertices[i] = new VertexPositionColorTexture(new Vector3(verts[i].X, verts[i].Y, 0.0f), overlay, Vector2.Zero); } this.localAABB = gxtGeometry.ComputeAABB(verts); if (setDefaultIndices) { indices = new int[verts.Length]; for (int i = 0; i < indices.Length; ++i) { indices[i] = i; } this.primitiveCount = indices.Length / 2; } }
public void SetVertices(Vector2[] verts, bool setDefaultIndices = true) { // overwrite the existing vertices vertices = new VertexPositionColorTexture[verts.Length]; if (vertexBuffer == null) vertexBuffer = new VertexBuffer(gxtRoot.Singleton.Graphics, typeof(VertexPositionColorTexture), verts.Length, BufferUsage.WriteOnly); Color overlay = (material != null) ? material.ColorOverlay : gxtMaterial.DEFAULT_COLOR_OVERLAY; for (int i = 0; i < verts.Length; ++i) { vertices[i] = new VertexPositionColorTexture(new Vector3(verts[i].X, verts[i].Y, 0.0f), overlay, Vector2.Zero); } vertexBuffer.SetData<VertexPositionColorTexture>(vertices); this.localAABB = gxtGeometry.ComputeAABB(verts); if (setDefaultIndices) { indices = new int[verts.Length]; for (int i = 0; i < indices.Length; ++i) { indices[i] = i; } if (indexBuffer == null) indexBuffer = new IndexBuffer(gxtRoot.Singleton.Graphics, typeof(int), indices.Length, BufferUsage.WriteOnly); indexBuffer.SetData<int>(indices); this.primitiveCount = indices.Length / 2; } }
public gxtDynamicIndexedPrimitive(Vector2[] verts, int[] indices, PrimitiveType primitiveType, int primitiveCount) { this.primitiveType = primitiveType; this.primitiveCount = primitiveCount; SetupVertices(verts); SetupIndices(indices); localAABB = gxtGeometry.ComputeAABB(verts); }
/// <summary> /// Equivalent to ComputePolygonFromAABB() but returns the data /// as an array of vertices instead /// </summary> /// <param name="aabb"></param> /// <returns></returns> public static Vector2[] ComputeVerticesFromAABB(gxtAABB aabb) { Vector2[] verts = new Vector2[4]; Vector2 c = aabb.Position; Vector2 r = aabb.Extents; verts[0] = c - r; verts[1] = c + new Vector2(-r.X, r.Y); verts[2] = c + r; verts[3] = c + new Vector2(r.X, -r.Y); return verts; }
public void Draw(ref SpriteBatch spriteBatch, gxtAABB cameraAABB) { // brute force culling, for now for (int i = 0; i < drawableList.Count; i++) { if (gxtAABB.Intersects(cameraAABB, drawableList[i].GetAABB())) drawableList[i].Draw(ref spriteBatch); } }