internal void CheckMaxCount() { if (MaxCount == 0) { return; } float time = EngineApp.Instance.Time; if (time == checkMaxCountTime) { return; } checkMaxCountTime = time; while (createdDecals.Count > MaxCount) { Decal decal = createdDecals.First.Value; createdDecals.Remove(decal); decal.SetShouldDelete(); } }
void CreateDecalForStaticObject(ShapeTriangleID startTriangle, Vec3 pos, Vec3 normal, MapObject parentMapObject) { Shape currentShape = null; Mat4 shapeTransform = Mat4.Zero; Vec3[] shapeVertices = null; int[] shapeIndices = null; bool existsNormalsMore45Degrees = false; //find near triangles //Set<ShapeTriangleID> triangleIDs = new Set<ShapeTriangleID>(); { Sphere checkSphere = new Sphere(pos, Type.Size * .5f * 1.41f); //Sqrt(2) //Set<ShapeTriangleID> checkedTriangles = new Set<ShapeTriangleID>(); //Stack<ShapeTriangleID> trianglesForCheck = new Stack<ShapeTriangleID>( 16 ); trianglesForCheck.Push(startTriangle); while (trianglesForCheck.Count != 0) { ShapeTriangleID triangle = trianglesForCheck.Pop(); //add to checked triangles if (!checkedTriangles.AddWithCheckAlreadyContained(triangle)) { //ignore already checked triangles continue; } //get triangle points Vec3 p0, p1, p2; { if (currentShape != triangle.shape) { currentShape = triangle.shape; if (currentShape.ShapeType == Shape.Type.Mesh) { ((MeshShape)currentShape).GetData(out shapeVertices, out shapeIndices); } else if (currentShape.ShapeType == Shape.Type.HeightField) { ((HeightFieldShape)currentShape).GetVerticesAndIndices(true, out shapeVertices, out shapeIndices); } else { Log.Fatal("DecalCreator: Not supported shape type ({0}).", currentShape.ShapeType.ToString()); } shapeTransform = currentShape.Body.GetTransform(); if (!currentShape.IsIdentityTransform) { shapeTransform *= currentShape.GetTransform(); } } int index = triangle.triangleID * 3; p0 = shapeTransform * shapeVertices[shapeIndices[index + 0]]; p1 = shapeTransform * shapeVertices[shapeIndices[index + 1]]; p2 = shapeTransform * shapeVertices[shapeIndices[index + 2]]; } //cull by checkBounds if (!checkSphere.TriangleIntersection(p0, p1, p2)) { continue; } //check normal bool correctNormal = false; if (Type.SpreadType != DecalCreatorType.SpreadTypes.Directional) { Plane plane = Plane.FromPoints(p0, p1, p2); if (plane.GetSide(pos + normal) == Plane.Side.Positive) { Radian angle = MathFunctions.ACos(Vec3.Dot(normal, plane.Normal)); if (angle <= new Degree(70.0f).InRadians()) { if (!existsNormalsMore45Degrees && angle >= new Degree(45.0f).InRadians()) { existsNormalsMore45Degrees = true; } correctNormal = true; } } } else { correctNormal = true; } if (correctNormal) { //add triangle to result list triangleIDs.Add(triangle); } //add near triangles to check list { //expand vertices const float border = .001f; Vec3 center = (p0 + p1 + p2) * (1.0f / 3.0f); Vec3 diff0 = p0 - center; Vec3 diff1 = p1 - center; Vec3 diff2 = p2 - center; if (diff0 != Vec3.Zero && diff1 != Vec3.Zero && diff2 != Vec3.Zero) { p0 += diff0.GetNormalize() * border; p1 += diff1.GetNormalize() * border; p2 += diff2.GetNormalize() * border; Vec3 p01 = (p0 + p1) * .5f; Vec3 p12 = (p1 + p2) * .5f; Vec3 p20 = (p2 + p0) * .5f; //find triangles for (int n = 0; n < 3; n++) { Vec3 p = Vec3.Zero; switch (n) { case 0: p = p01; break; case 1: p = p12; break; case 2: p = p20; break; } RayCastResult[] piercingResult = PhysicsWorld.Instance.RayCastPiercing(new Ray( p + normal * .025f, -normal * .05f), (int)ContactGroup.CastOnlyCollision); foreach (RayCastResult result in piercingResult) { if (result.Shape != null) { trianglesForCheck.Push(new ShapeTriangleID( result.Shape, result.TriangleID)); } } } } } } checkedTriangles.Clear(); } if (triangleIDs.Count == 0) { return; } //calculate perpendiculars to normal Vec3 side1Normal; Vec3 side2Normal; { if (Math.Abs(normal.X) > .001f || Math.Abs(normal.Y) > .001f) { side1Normal = Mat3.FromRotateByZ(MathFunctions.PI / 2) * new Vec3(normal.X, normal.Y, 0); side1Normal.Normalize(); } else { side1Normal = new Vec3(1, 0, 0); } side2Normal = Vec3.Cross(normal, side1Normal); } //generate clip planes Plane[] clipPlanes = new Plane[6]; { float halfSize = Type.Size * .5f; if (existsNormalsMore45Degrees) { halfSize *= 1.41f; } Plane p; p = Plane.FromVectors(normal, -side2Normal, Position); clipPlanes[0] = new Plane(p.Normal, p.Distance + halfSize); p = Plane.FromVectors(normal, side2Normal, Position); clipPlanes[1] = new Plane(p.Normal, p.Distance + halfSize); p = Plane.FromVectors(normal, -side1Normal, Position); clipPlanes[2] = new Plane(p.Normal, p.Distance + halfSize); p = Plane.FromVectors(normal, side1Normal, Position); clipPlanes[3] = new Plane(p.Normal, p.Distance + halfSize); p = Plane.FromVectors(side1Normal, side2Normal, Position); clipPlanes[4] = new Plane(p.Normal, p.Distance + halfSize); //clipPlanes[ 4 ] = new Plane( p.Normal, p.Distance + halfSize * .5f ); p = Plane.FromVectors(side1Normal, -side2Normal, Position); clipPlanes[5] = new Plane(p.Normal, p.Distance + halfSize); //clipPlanes[ 5 ] = new Plane( p.Normal, p.Distance + halfSize * .5f ); } //generate vertices and indices by triangles //List<Decal.Vertex> vertices = new List<Decal.Vertex>( triangleIDs.Count * 3 ); //List<int> indices = new List<int>( triangleIDs.Count * 3 ); List <Decal.Vertex> vertices = tempVertices; List <int> indices = tempIndices; vertices.Clear(); indices.Clear(); { foreach (ShapeTriangleID triangle in triangleIDs) { Vec3 p0, p1, p2; { if (currentShape != triangle.shape) { currentShape = triangle.shape; if (currentShape.ShapeType == Shape.Type.Mesh) { ((MeshShape)currentShape).GetData(out shapeVertices, out shapeIndices); } else if (currentShape.ShapeType == Shape.Type.HeightField) { ((HeightFieldShape)currentShape).GetVerticesAndIndices(true, out shapeVertices, out shapeIndices); } else { Log.Fatal("DecalCreator: Not supported shape type ({0}).", currentShape.ShapeType.ToString()); } shapeTransform = currentShape.Body.GetTransform(); if (!currentShape.IsIdentityTransform) { shapeTransform *= currentShape.GetTransform(); } } int index = triangle.triangleID * 3; p0 = shapeTransform * shapeVertices[shapeIndices[index + 0]]; p1 = shapeTransform * shapeVertices[shapeIndices[index + 1]]; p2 = shapeTransform * shapeVertices[shapeIndices[index + 2]]; } List <Vec3> list = new List <Vec3>(); list.Add(p0); list.Add(p1); list.Add(p2); //clip by planes foreach (Plane plane in clipPlanes) { list = CutConvexPlanePolygonByPlane(list, plane); if (list == null) { break; } } //add to vertices and indices lists if (list != null) { int vertexCount = vertices.Count; Vec3 norm = Plane.FromPoints(p0, p1, p2).Normal; foreach (Vec3 p in list) { vertices.Add(new Decal.Vertex(p, norm, Vec2.Zero, Vec3.Zero)); } for (int n = 1; n < list.Count - 1; n++) { indices.Add(vertexCount); indices.Add(vertexCount + n); indices.Add(vertexCount + n + 1); } } } } triangleIDs.Clear(); if (indices.Count == 0) { return; } //calculate texCoord and Type.DepthRenderOffset { Plane planeSide1 = Plane.FromVectors(normal, side1Normal, Position); Plane planeSide2 = Plane.FromVectors(normal, side2Normal, Position); float invSize = 1.0f / Type.Size; for (int n = 0; n < vertices.Count; n++) { Decal.Vertex vertex = vertices[n]; //calculate texCoord float distance1 = planeSide1.GetDistance(vertex.position); float distance2 = planeSide2.GetDistance(vertex.position); vertex.texCoord = new Vec2(distance1 * invSize + .5f, distance2 * invSize + .5f); //add Type.DepthRenderOffset vertex.position = vertex.position + normal * Type.DepthRenderOffset; vertices[n] = vertex; } } //calculate tangent vectors { int triangleCount = indices.Count / 3; for (int nTriangle = 0; nTriangle < triangleCount; nTriangle++) { int index0 = indices[nTriangle * 3 + 0]; int index1 = indices[nTriangle * 3 + 1]; int index2 = indices[nTriangle * 3 + 2]; Decal.Vertex vertex0 = vertices[index0]; Decal.Vertex vertex1 = vertices[index1]; Decal.Vertex vertex2 = vertices[index2]; Vec3 tangent = MathUtils.CalculateTangentSpaceVector( vertex0.position, vertex0.texCoord, vertex1.position, vertex1.texCoord, vertex2.position, vertex2.texCoord); vertex0.tangent += tangent; vertex1.tangent += tangent; vertex2.tangent += tangent; vertices[index0] = vertex0; vertices[index1] = vertex1; vertices[index2] = vertex2; } for (int n = 0; n < vertices.Count; n++) { Decal.Vertex vertex = vertices[n]; if (vertex.tangent != Vec3.Zero) { vertex.tangent.Normalize(); } vertices[n] = vertex; } } //subtract decal position (make local vertices coordinates) { for (int n = 0; n < vertices.Count; n++) { Decal.Vertex vertex = vertices[n]; vertex.position -= Position; vertices[n] = vertex; } } //get material string materialName = null; { string physicsMaterialName = startTriangle.shape.MaterialName; string defaultMaterialName = ""; foreach (DecalCreatorType.MaterialItem item in Type.Materials) { if (item.PhysicsMaterialName == physicsMaterialName) { materialName = item.MaterialName; } if (string.IsNullOrEmpty(item.PhysicsMaterialName)) { defaultMaterialName = item.MaterialName; } } if (materialName == null) { materialName = defaultMaterialName; } } //create Decal Decal decal = (Decal)Entities.Instance.Create("Decal", Map.Instance); decal.Position = Position; decal.Init(this, vertices.ToArray(), indices.ToArray(), materialName, parentMapObject); decal.PostCreate(); Type.AddDecalToCreatedList(decal); decals.Add(decal); }
internal void RemoveDecal(Decal decal) { Type.RemoveDecalFromCreatedList(decal); decals.Remove(decal); }
internal void RemoveDecalFromCreatedList(Decal decal) { createdDecals.Remove(decal); }
internal void AddDecalToCreatedList(Decal decal) { createdDecals.AddLast(decal); }