public void QueryVisibleRenderers(IDrawDevice device, RawList<ICmpRenderer> targetList)
		{
			// Empty the cached list of visible renderers
			targetList.Count = 0;
			targetList.Reserve(this.totalRendererCount);

			// Copy references to all renderers that are visible to the target device
			int visibleCount = 0;
			ICmpRenderer[] targetData = targetList.Data;
			foreach (var pair in this.renderersByType)
			{
				ICmpRenderer[] data = pair.Value.Data;
				for (int i = 0; i < data.Length; i++)
				{
					if (i >= pair.Value.Count) break;

					if ((data[i] as Component).Active && data[i].IsVisible(device))
					{
						targetData[visibleCount] = data[i];
						visibleCount++;
					}
				}
			}
			targetList.Count = visibleCount;
		}
        public void QueryVisibleRenderers(IDrawDevice device, RawList <ICmpRenderer> targetList)
        {
            // Empty the cached list of visible renderers
            targetList.Count = 0;
            targetList.Reserve(this.totalRendererCount);

            // Copy references to all renderers that are visible to the target device
            int visibleCount = 0;

            ICmpRenderer[] targetData = targetList.Data;
            foreach (var pair in this.renderersByType)
            {
                ICmpRenderer[] data = pair.Value.Data;
                for (int i = 0; i < data.Length; i++)
                {
                    if (i >= pair.Value.Count)
                    {
                        break;
                    }

                    if ((data[i] as Component).Active && data[i].IsVisible(device))
                    {
                        targetData[visibleCount] = data[i];
                        visibleCount++;
                    }
                }
            }
            targetList.Count = visibleCount;
        }
        public void QueryVisibleRenderers(DrawDevice device, RawList <ICmpRenderer> visibleRenderers)
        {
            int activeCount = this.cullingInfo.Count;

            CullingInfo[]  cullingData  = this.cullingInfo.Data;
            ICmpRenderer[] rendererData = this.cullingRenderers.Data;

            visibleRenderers.Clear();
            visibleRenderers.Reserve(activeCount);

            ICmpRenderer[] visibleRendererData = visibleRenderers.Data;
            int            visibleCount        = 0;

            VisibilityFlag mask = device.VisibilityMask;

            for (int i = 0; i < activeCount; i++)
            {
                // Check group and overlay / world visibility
                if ((cullingData[i].Visibility & VisibilityFlag.AllGroups & mask) == VisibilityFlag.None)
                {
                    continue;
                }
                if ((cullingData[i].Visibility & VisibilityFlag.ScreenOverlay) != (mask & VisibilityFlag.ScreenOverlay))
                {
                    continue;
                }

                // Check spatial visibility
                if (!device.IsSphereInView(cullingData[i].Position, cullingData[i].Radius))
                {
                    continue;
                }

                // Add renderer to visible result list
                visibleRendererData[visibleCount] = rendererData[i];
                visibleCount++;
            }

            visibleRenderers.Count = visibleCount;
        }
示例#4
0
        private static void GenerateCollisionShapes(TileEdgeMap edgeMap, Vector2 origin, Vector2 tileSize, bool roundedCorners, IList <ShapeInfo> shapeList)
        {
            // Traverse the edge map and gradually create chain / loop
            // shapes until all edges have been used.
            RawList <Point2>  currentChain = new RawList <Point2>();
            RawList <Vector2> vertexBuffer = new RawList <Vector2>();

            while (true)
            {
                // Begin a new continuous chain of nodes
                currentChain.Clear();

                // Find a starting node for our current chain.
                // If there is none, we found and handled all edges.
                Point2 start = edgeMap.FindNonEmpty();
                if (start == new Point2(-1, -1))
                {
                    break;
                }

                // Traverse the current chain node-by-node from the start we found
                Point2 current = start;
                while (true)
                {
                    // Add the current node to our continuous chain
                    currentChain.Add(current);

                    // Find the next node that connects to the current one.
                    // If there is none, our current chain is done.
                    Point2 next = edgeMap.GetClockwiseNextFrom(current);
                    if (next == new Point2(-1, -1))
                    {
                        break;
                    }

                    // Remove the edge we used to get to the next node
                    edgeMap.RemoveEdge(current, next);

                    // Use the next node as origin for traversing further
                    current = next;
                }

                // Generate a shape from the current chain
                bool isLoop = (start == currentChain[currentChain.Count - 1]);
                if (isLoop)
                {
                    currentChain.RemoveAt(currentChain.Count - 1);
                }
                vertexBuffer.Clear();

                // Rounded corners
                if (roundedCorners && currentChain.Count >= 3)
                {
                    vertexBuffer.Reserve(currentChain.Count * 2);
                    vertexBuffer.Count = 0;
                    for (int i = 0; i < currentChain.Count; i++)
                    {
                        int prevIndex = (i - 1 + currentChain.Count) % currentChain.Count;
                        int nextIndex = (i + 1) % currentChain.Count;

                        Vector2 currentVert = origin + tileSize * (Vector2)currentChain[i];
                        Vector2 prevVert    = origin + tileSize * (Vector2)currentChain[prevIndex];
                        Vector2 nextVert    = origin + tileSize * (Vector2)currentChain[nextIndex];

                        if (nextVert - currentVert != currentVert - prevVert)
                        {
                            if (!isLoop && (i == 0 || i == currentChain.Count - 1))
                            {
                                vertexBuffer.Add(currentVert);
                            }
                            else
                            {
                                vertexBuffer.Add(currentVert + (prevVert - currentVert).Normalized * tileSize * 0.2f);
                                vertexBuffer.Add(currentVert + (nextVert - currentVert).Normalized * tileSize * 0.2f);
                            }
                        }
                    }
                }
                // Sharp corners
                else
                {
                    vertexBuffer.Reserve(currentChain.Count);
                    vertexBuffer.Count = 0;
                    for (int i = 0; i < currentChain.Count; i++)
                    {
                        int prevIndex = (i - 1 + currentChain.Count) % currentChain.Count;
                        int nextIndex = (i + 1) % currentChain.Count;

                        Vector2 currentVert = origin + tileSize * (Vector2)currentChain[i];
                        Vector2 prevVert    = origin + tileSize * (Vector2)currentChain[prevIndex];
                        Vector2 nextVert    = origin + tileSize * (Vector2)currentChain[nextIndex];

                        if (nextVert - currentVert != currentVert - prevVert)
                        {
                            vertexBuffer.Add(currentVert);
                        }
                    }
                }

                Vector2[] vertices = new Vector2[vertexBuffer.Count];
                vertexBuffer.CopyTo(vertices, 0);
                shapeList.Add(isLoop ?
                              (ShapeInfo) new LoopShapeInfo(vertices) :
                              (ShapeInfo) new ChainShapeInfo(vertices));
            }
        }
示例#5
0
        private void UpdateComponents <T>(Action <T> updateAction) where T : class
        {
            Profile.TimeUpdateSceneComponents.BeginMeasure();

            // Gather a list of updatable Components
            RawList <Component>   updatableComponents = new RawList <Component>(256);
            RawList <UpdateEntry> updateMap           = new RawList <UpdateEntry>();

            foreach (var pair in this.componentsByType)
            {
                // Skip Component types that aren't updatable anyway
                Component sampleComponent = pair.Value.FirstOrDefault();
                if (!(sampleComponent is T))
                {
                    continue;
                }

                int oldCount = updatableComponents.Count;

                // Collect Components
                updatableComponents.Reserve(updatableComponents.Count + pair.Value.Count);
                for (int i = 0; i < pair.Value.Count; i++)
                {
                    updatableComponents.Add(pair.Value[i]);
                }

                // Keep in mind how many Components of each type we have in what order
                if (updatableComponents.Count - oldCount > 0)
                {
                    updateMap.Add(new UpdateEntry
                    {
                        Type     = pair.Key,
                        Count    = updatableComponents.Count - oldCount,
                        Profiler = Profile.RequestCounter <TimeCounter>(Profile.TimeUpdateScene.FullName + @"\" + pair.Key.Name)
                    });
                }
            }

            // Update all Components. They're still sorted by type.
            {
                int           updateMapIndex = -1;
                int           updateMapBegin = -1;
                TimeCounter   activeProfiler = null;
                Component[]   data           = updatableComponents.Data;
                UpdateEntry[] updateData     = updateMap.Data;

                for (int i = 0; i < data.Length; i++)
                {
                    if (i >= updatableComponents.Count)
                    {
                        break;
                    }

                    // Manage profilers per Component type
                    if (i == 0 || i - updateMapBegin >= updateData[updateMapIndex].Count)
                    {
                        // Note:
                        // Since we're doing this based on index-count ranges, this needs to be
                        // done before skipping inactive Components, so we don't run out of sync.

                        updateMapIndex++;
                        updateMapBegin = i;

                        if (activeProfiler != null)
                        {
                            activeProfiler.EndMeasure();
                        }
                        activeProfiler = updateData[updateMapIndex].Profiler;
                        activeProfiler.BeginMeasure();
                    }

                    // Skip inactive, disposed and detached Components
                    if (!data[i].Active)
                    {
                        continue;
                    }

                    // Invoke the Component's update action
                    updateAction(data[i] as T);
                }

                if (activeProfiler != null)
                {
                    activeProfiler.EndMeasure();
                }
            }

            Profile.TimeUpdateSceneComponents.EndMeasure();
        }
示例#6
0
        /// <summary>
        /// Draws the tile layer of the <see cref="TilesetView"/>.
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnPaintTiles(PaintEventArgs e)
        {
            Tileset tileset = this.tileset.Res;

            // Early-out if there are no tiles to draw
            if (tileset == null)
            {
                return;
            }
            if (this.totalTileCount == 0)
            {
                return;
            }

            // Determine which tiles are visible in the current viewport, so not all of them are drawn needlessly
            // Note: Not using clip rectangle here, because the multicolumn rendering algorithm assumes that
            // we always start at the beginning.
            int   firstIndex   = this.PickTileIndexAt(0, 0, true, true);
            int   lastIndex    = this.PickTileIndexAt(this.ClientSize.Width - 1, this.ClientSize.Height - 1, true, true);
            Point firstItemPos = this.GetTileIndexLocation(firstIndex);

            if (lastIndex < firstIndex)
            {
                return;
            }

            Size texSize = new Size(
                MathF.NextPowerOfTwo(this.tileBitmap.Width),
                MathF.NextPowerOfTwo(this.tileBitmap.Height));

            // ToDo: Cleanup the below algorithm, it's hard to understand and has far too many
            // special cases. If performance doesn't suffer too much, maybe even do a 2D grid draw
            // and query tile indices using PickTileIndexAt?

            // Determine rendering data for all visible tile items
            paintTileBuffer.Count = 0;
            paintTileBuffer.Reserve(lastIndex - firstIndex);
            {
                Point basePos             = firstItemPos;
                Point curPos              = basePos;
                int   itemsPerRow         = (this.multiColumnMode == MultiColumnMode.Vertical) ? this.multiColumnLength : this.tileCount.X;
                int   skipItemsPerRow     = (firstIndex % itemsPerRow);
                int   itemsPerRenderedRow = itemsPerRow - skipItemsPerRow;
                int   itemsInCurrentRow   = 0;
                for (int i = firstIndex; i <= lastIndex; i++)
                {
                    Rectangle tileRect = new Rectangle(curPos.X, curPos.Y, this.displayedTileSize.Width, this.displayedTileSize.Height);

                    // If the tile is actually visible, add the required data to the paint buffer
                    if (e.ClipRectangle.IntersectsWith(tileRect))
                    {
                        Point2 atlasTilePos;
                        Point2 atlasTileSize;
                        tileset.LookupTileSourceRect(this.displayedConfigIndex, i, out atlasTilePos, out atlasTileSize);

                        paintTileBuffer.Count++;
                        paintTileBuffer.Data[paintTileBuffer.Count - 1] = new TilesetViewPaintTileData
                        {
                            TileIndex  = i,
                            SourceRect = new Rectangle(atlasTilePos.X, atlasTilePos.Y, atlasTileSize.X, atlasTileSize.Y),
                            ViewRect   = tileRect
                        };
                    }

                    itemsInCurrentRow++;
                    bool isLastIndexInRow = (itemsInCurrentRow == itemsPerRenderedRow);
                    bool isLastIndexInHorizontalMultiColumn =
                        (this.multiColumnMode == MultiColumnMode.Horizontal) &&
                        (i % (this.tileCount.X * this.multiColumnLength)) == (this.tileCount.X * this.multiColumnLength - 1);

                    if (isLastIndexInHorizontalMultiColumn)
                    {
                        // Determine how many tiles we need to skip to the next horizontal multicolumn
                        int baseIndexInRow         = firstIndex % this.tileCount.X;
                        int tilesToNextMultiColumn = this.tileCount.X - baseIndexInRow;

                        // Switch to the next horizontal multicolumn
                        itemsInCurrentRow = 0;
                        basePos.X        += tilesToNextMultiColumn * (this.displayedTileSize.Width + this.spacing.Width);
                        curPos            = basePos;
                        i = this.PickTileIndexAt(curPos.X, curPos.Y, true, false);
                        if (i == -1)
                        {
                            break;
                        }

                        // Recalculate regular rowskip values because we switched to the next horizontal multicolumn
                        // If we previously rendered the last part of a row, this no longer applies. Since we are
                        // now back at the beginning of a row, we don't skip any items prior and render full rows instead.
                        // (Yes, this could be optimized, but there's no need right now)
                        skipItemsPerRow     = 0;
                        itemsPerRenderedRow = itemsPerRow - skipItemsPerRow;

                        i--;
                    }
                    else if (isLastIndexInRow)
                    {
                        curPos.X          = basePos.X;
                        curPos.Y         += this.displayedTileSize.Height + this.spacing.Height;
                        itemsInCurrentRow = 0;
                        i += skipItemsPerRow;

                        if (this.multiColumnMode == MultiColumnMode.Vertical)
                        {
                            i = this.PickTileIndexAt(curPos.X, curPos.Y, true, false);
                            if (i == -1)
                            {
                                break;
                            }

                            // Recalculate regular rowskip values because we might have switched to the next
                            // vertical multicolumn and might need to skip some tiles at the end because they
                            // don't map to a valid model index
                            int maxValidItemsInThisRow = this.tileCount.X - this.GetTilePos(i).X;
                            skipItemsPerRow     = itemsPerRow - Math.Min(this.multiColumnLength, maxValidItemsInThisRow);
                            itemsPerRenderedRow = itemsPerRow - skipItemsPerRow;

                            i--;
                        }
                    }
                    else
                    {
                        curPos.X += this.displayedTileSize.Width + this.spacing.Width;
                    }
                }
            }

            // Set the interpolation mode based on whether we're scaling up or down
            Vector2 scaleFactor    = new Vector2(this.displayedTileSize.Width, this.displayedTileSize.Height) / tileset.TileSize;
            bool    scalingUpClean =
                scaleFactor.X > 1.0f &&
                scaleFactor.X == scaleFactor.Y &&
                scaleFactor.X == (int)scaleFactor.X &&
                scaleFactor.Y == (int)scaleFactor.Y;

            if (scalingUpClean)
            {
                e.Graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
            }
            else
            {
                e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
            }

            // Draw the previously determined visible tiles accordingly
            TilesetViewPaintTileData[] rawPaintData = paintTileBuffer.Data;
            int paintedTileCount = paintTileBuffer.Count;

            for (int i = 0; i < rawPaintData.Length; i++)
            {
                if (i >= paintedTileCount)
                {
                    break;
                }

                // Adjust the image rect by half the scale factor in pixels,
                // because for some reason the nearest-neighbor-filtered image
                // might end up too small otherwise.
                Rectangle imageRect = rawPaintData[i].ViewRect;
                if (scalingUpClean)
                {
                    imageRect.Width  += MathF.RoundToInt(scaleFactor.X / 2.0f);
                    imageRect.Height += MathF.RoundToInt(scaleFactor.Y / 2.0f);
                }

                e.Graphics.DrawImage(
                    this.tileBitmap,
                    imageRect,
                    rawPaintData[i].SourceRect,
                    GraphicsUnit.Pixel);
            }
            e.Graphics.InterpolationMode = InterpolationMode.Default;

            // Invoke the event handler
            if (this.PaintTiles != null)
            {
                this.PaintTiles(this, new TilesetViewPaintTilesEventArgs(
                                    e.Graphics,
                                    e.ClipRectangle,
                                    tileset,
                                    this.tileBitmap,
                                    paintTileBuffer));
            }
        }
示例#7
0
        private static void GenerateCollisionShapes(TileEdgeMap edgeMap, Vector2 origin, Vector2 tileSize, bool roundedCorners, IList<ShapeInfo> shapeList)
        {
            // Traverse the edge map and gradually create chain / loop
            // shapes until all edges have been used.
            RawList<Point2> currentChain = new RawList<Point2>();
            RawList<Vector2> vertexBuffer = new RawList<Vector2>();
            while (true)
            {
                // Begin a new continuous chain of nodes
                currentChain.Clear();

                // Find a starting node for our current chain.
                // If there is none, we found and handled all edges.
                Point2 start = edgeMap.FindNonEmpty();
                if (start == new Point2(-1, -1))
                    break;

                // Traverse the current chain node-by-node from the start we found
                Point2 current = start;
                while (true)
                {
                    // Add the current node to our continuous chain
                    currentChain.Add(current);

                    // Find the next node that connects to the current one.
                    // If there is none, our current chain is done.
                    Point2 next = edgeMap.GetClockwiseNextFrom(current);
                    if (next == new Point2(-1, -1))
                        break;

                    // Remove the edge we used to get to the next node
                    edgeMap.RemoveEdge(current, next);

                    // Use the next node as origin for traversing further
                    current = next;
                }

                // Generate a shape from the current chain
                bool isLoop = (start == currentChain[currentChain.Count - 1]);
                if (isLoop) currentChain.RemoveAt(currentChain.Count - 1);
                vertexBuffer.Clear();

                // Rounded corners
                if (roundedCorners && currentChain.Count >= 3)
                {
                    vertexBuffer.Reserve(currentChain.Count * 2);
                    vertexBuffer.Count = 0;
                    for (int i = 0; i < currentChain.Count; i++)
                    {
                        int prevIndex = (i - 1 + currentChain.Count) % currentChain.Count;
                        int nextIndex = (i + 1) % currentChain.Count;

                        Vector2 currentVert = origin + tileSize * (Vector2)currentChain[i];
                        Vector2 prevVert = origin + tileSize * (Vector2)currentChain[prevIndex];
                        Vector2 nextVert = origin + tileSize * (Vector2)currentChain[nextIndex];

                        if (nextVert - currentVert != currentVert - prevVert)
                        {
                            if (!isLoop && (i == 0 || i == currentChain.Count - 1))
                            {
                                vertexBuffer.Add(currentVert);
                            }
                            else
                            {
                                vertexBuffer.Add(currentVert + (prevVert - currentVert).Normalized * tileSize * 0.2f);
                                vertexBuffer.Add(currentVert + (nextVert - currentVert).Normalized * tileSize * 0.2f);
                            }
                        }
                    }
                }
                // Sharp corners
                else
                {
                    vertexBuffer.Reserve(currentChain.Count);
                    vertexBuffer.Count = 0;
                    for (int i = 0; i < currentChain.Count; i++)
                    {
                        int prevIndex = (i - 1 + currentChain.Count) % currentChain.Count;
                        int nextIndex = (i + 1) % currentChain.Count;

                        Vector2 currentVert = origin + tileSize * (Vector2)currentChain[i];
                        Vector2 prevVert = origin + tileSize * (Vector2)currentChain[prevIndex];
                        Vector2 nextVert = origin + tileSize * (Vector2)currentChain[nextIndex];

                        if (nextVert - currentVert != currentVert - prevVert)
                            vertexBuffer.Add(currentVert);
                    }
                }
                shapeList.Add(isLoop ?
                    (ShapeInfo)new LoopShapeInfo(vertexBuffer) :
                    (ShapeInfo)new ChainShapeInfo(vertexBuffer));
            }
        }