/// <returns>True if visible decals are found</returns> private static bool IterateVisibleRenderIDs(HashSet <uint> visibleRenderIDs, MyDecalFlags targetFlag, float squaredDistanceMax, uint sinceStartTs) { bool ret = false; foreach (uint renderID in visibleRenderIDs) { List <DecalNode> decals; bool found = m_entityDecals.TryGetValue(renderID, out decals); if (!found) { continue; } foreach (DecalNode node in decals) { if (node.Value.FadeTimestamp < sinceStartTs) { RemoveDecalByNode(node); continue; } MyScreenDecal decal = node.Value; MyDecalFlags flag = decal.Flags & MyDecalFlags.Transparent; if (flag == targetFlag && IsDecalWithinRadius(decal, squaredDistanceMax)) { AddDecalNodeForDraw(node); ret = true; } } } return(ret); }
/// <returns>True if visible decals are found</returns> private static bool IterateDecals(HashSet <uint> visibleRenderIDs, MyDecalFlags targetFlag, float squaredDistanceMax, uint sinceStartTs) { bool ret = false; int count = m_decals.Count; DecalNode current = m_decals.First; int it = 0; while (current != null && it < count) { DecalNode next = current.Next; if (current.Value.FadeTimestamp < sinceStartTs) { RemoveDecalByNode(current); current = next; continue; } MyScreenDecal decal = current.Value; MyDecalFlags flag = decal.Flags & MyDecalFlags.Transparent; if (flag == targetFlag && (visibleRenderIDs == null || visibleRenderIDs.Contains(decal.ParentID)) && IsDecalWithinRadius(decal, squaredDistanceMax)) { AddDecalNodeForDraw(current); ret = true; } current = next; it++; } return(ret); }
// ENABLE-ME: As soon as a relieble list of frustum visible ojects IDs is available internal static void Draw(HashSet <uint> visibleRenderIDs, bool transparent) { if (m_decals.Count == 0) { return; } uint sinceStartTs = GetTimeStampSinceStart(); MyDecalFlags targetFlag = transparent ? MyDecalFlags.Transparent : MyDecalFlags.None; bool visibleDecals; if (visibleRenderIDs.Count > m_decals.Count) { visibleDecals = IterateDecals(visibleRenderIDs, targetFlag, sinceStartTs); } else { visibleDecals = IterateVisibleRenderIDs(visibleRenderIDs, targetFlag, sinceStartTs); } if (!visibleDecals) { return; } DrawInternal(transparent, sinceStartTs); }
/// <param name="visibleRenderIDs">Optional list of visible render object IDs</param> internal static void Draw(bool transparent, HashSet <uint> visibleRenderIDs = null, float squaredDistanceMax = VISIBLE_DECALS_SQ_TH) { if (m_decals.Count == 0) { return; } uint sinceStartTs = GetTimeStampSinceStart(); MyDecalFlags targetFlag = transparent ? MyDecalFlags.Transparent : MyDecalFlags.None; bool visibleDecals; if (visibleRenderIDs == null || visibleRenderIDs.Count > m_decals.Count) { visibleDecals = IterateDecals(visibleRenderIDs, targetFlag, squaredDistanceMax, sinceStartTs); } else { visibleDecals = IterateVisibleRenderIDs(visibleRenderIDs, targetFlag, squaredDistanceMax, sinceStartTs); } if (!visibleDecals) { return; } DrawInternal(transparent, sinceStartTs); }
/// <returns>True if visible decals are found</returns> private static bool IterateDecals(HashSet <uint> visibleRenderIDs, MyDecalFlags targetFlag, uint sinceStartTs) { bool ret = false; int count = m_decals.Count; DecalNode current = m_decals.First; int it = 0; while (current != null && it < count) { DecalNode next = current.Next; if (current.Value.FadeTimestamp < sinceStartTs) { RemoveDecalByNode(current); current = next; continue; } MyDecalFlags flag = current.Value.Flags & MyDecalFlags.Transparent; if (flag == targetFlag && visibleRenderIDs.Contains(current.Value.ParentID)) { AddDecalNodeForDraw(current); ret = true; } current = next; it++; } return(ret); }
private static Matrix ComputeOBB(ref MyDecalTopoData data, MyDecalFlags flags) { var perp = Vector3.CalculatePerpendicularVector(data.Normal); if (data.Rotation != 0) { // Rotate around normal Quaternion q = Quaternion.CreateFromAxisAngle(data.Normal, data.Rotation); perp = new Vector3((new Quaternion(perp, 0) * q).ToVector4()); } Matrix pos = Matrix.CreateWorld(data.Position, data.Normal, perp); return(Matrix.CreateScale(data.Scale) * pos); }
internal static void Draw(bool transparent) { if (m_decals.Count == 0) { return; } uint sinceStart = GetTimeStampSinceStart(); MyDecalFlags targetFlag = transparent ? MyDecalFlags.Transparent : MyDecalFlags.None; bool decalsToDraw = false; DecalNode current = m_decals.First; while (current != null) { DecalNode next = current.Next; if (current.Value.FadeTimestamp < sinceStart) { RemoveDecalByNode(current); current = next; continue; } MyDecalFlags flag = current.Value.Flags & MyDecalFlags.Transparent; if (targetFlag == flag) { AddDecalForDraw(current.Value); decalsToDraw = true; } current = next; } if (!decalsToDraw) { return; } DrawInternal(transparent, sinceStart); }
internal static void AddDecal(uint ID, uint ParentID, ref MyDecalTopoData topoData, MyDecalFlags flags, string sourceTarget, string material, int matIndex) { if (m_decals.Count >= m_decalsQueueSize && m_decals.Count != 0) { MarkForRemove(m_decals.First); } MyScreenDecal decal = new MyScreenDecal(); decal.FadeTimestamp = uint.MaxValue; decal.ID = ID; decal.ParentID = ParentID; decal.TopoData = topoData; decal.Flags = flags; decal.SourceTarget = sourceTarget; decal.Material = material; decal.MaterialId = X.TEXT_(material); decal.MaterialIndex = matIndex; if (!flags.HasFlag(MyDecalFlags.World)) { var parent = MyIDTracker <MyActor> .FindByID(ParentID); if (parent == null) { return; } decal.TopoData.WorldPosition = Vector3D.Transform(topoData.MatrixCurrent.Translation, ref parent.WorldMatrix); } DecalNode node = m_decals.AddLast(decal); m_nodeMap[ID] = node; List <DecalNode> handles; bool found = m_entityDecals.TryGetValue(ParentID, out handles); if (!found) { handles = new List <DecalNode>(); m_entityDecals.Add(ParentID, handles); } handles.Add(node); }
public static void AddDecal(uint ID, uint ParentID, ref MyDecalTopoData data, MyDecalFlags flags, string sourceTarget, string material, int matIndex) { if (m_decals.Count == m_decalsQueueSize) { MarkForRemove(m_decals.First.Value); } MyScreenDecal decal = new MyScreenDecal(); decal.FadeTimestamp = uint.MaxValue; decal.ID = ID; decal.ParentID = ParentID; decal.Data = data; decal.Flags = flags; decal.OBBox = ComputeOBB(ref data, flags); decal.SourceTarget = sourceTarget; decal.Material = material; decal.MaterialId = X.TEXT_(material); decal.MaterialIndex = matIndex; DecalNode node = m_decals.AddLast(decal); m_nodeMap[ID] = node; List <DecalNode> handles; bool found = m_entityDecals.TryGetValue(ParentID, out handles); if (!found) { handles = new List <DecalNode>(); m_entityDecals.Add(ParentID, handles); } handles.Add(node); }
public static uint CreateDecal(int parentId, ref MyDecalTopoData data, MyDecalFlags flags, string sourceTarget, string material, int matIndex) { var message = MessagePool.Get<MyRenderMessageCreateScreenDecal>(MyRenderMessageEnum.CreateScreenDecal); message.ID = GetMessageId(ObjectType.ScreenDecal); message.ParentID = (uint) parentId; message.TopoData = data; message.SourceTarget = sourceTarget; message.Flags = flags; message.Material = material; message.MaterialIndex = matIndex; EnqueueMessage(message); return message.ID; }
uint?IMyDecalHandler.AddDecal(ref MyDecalRenderInfo data) { CheckEnabled(); IReadOnlyList <MyDecalMaterial> materials; bool found = MyDecalMaterials.TryGetDecalMaterial(Source.String, data.Material.String, out materials); if (!found) { if (MyFakes.ENABLE_USE_DEFAULT_DAMAGE_DECAL) { found = MyDecalMaterials.TryGetDecalMaterial(DEFAULT, DEFAULT, out materials); } if (!found) { return(null); } } MyDecalBindingInfo binding; if (data.Binding == null) { binding = new MyDecalBindingInfo(); binding.Position = data.Position; binding.Normal = data.Normal; binding.Transformation = Matrix.Identity; } else { binding = data.Binding.Value; } int index = (int)Math.Round(MyRandom.Instance.NextFloat() * (materials.Count - 1)); MyDecalMaterial material = materials[index]; float rotation = material.Rotation; if (material.Rotation == float.PositiveInfinity) { rotation = MyRandom.Instance.NextFloat() * MathHelper.TwoPi; } var bindingPerp = Vector3.CalculatePerpendicularVector(binding.Normal); if (rotation != 0) { // Rotate around normal Quaternion q = Quaternion.CreateFromAxisAngle(binding.Normal, rotation); bindingPerp = new Vector3((new Quaternion(bindingPerp, 0) * q).ToVector4()); } bindingPerp = Vector3.Normalize(bindingPerp); var size = material.MinSize; if (material.MaxSize > material.MinSize) { size += MyRandom.Instance.NextFloat() * (material.MaxSize - material.MinSize); } Vector3 scale = new Vector3(size, size, material.Depth); MyDecalTopoData topoData = new MyDecalTopoData(); Matrix pos; Vector3 worldPosition; if (data.Flags.HasFlag(MyDecalFlags.World)) { // Using tre translation component here would loose accuracy pos = Matrix.CreateWorld(Vector3.Zero, binding.Normal, bindingPerp); worldPosition = data.Position; } else { pos = Matrix.CreateWorld(binding.Position, binding.Normal, bindingPerp); worldPosition = Vector3.Invalid; // Set in the render thread } topoData.MatrixBinding = Matrix.CreateScale(scale) * pos; topoData.WorldPosition = worldPosition; topoData.MatrixCurrent = binding.Transformation * topoData.MatrixBinding; topoData.BoneIndices = data.BoneIndices; topoData.BoneWeights = data.BoneWeights; MyDecalFlags flags = material.Transparent ? MyDecalFlags.Transparent : MyDecalFlags.None; string sourceTarget = MyDecalMaterials.GetStringId(Source, data.Material); return(MyRenderProxy.CreateDecal(data.RenderObjectId, ref topoData, data.Flags | flags, sourceTarget, material.StringId, index)); }