Exemplo n.º 1
0
        public void DrawDebugInfo(
            ViewPortInfo viewPort,
            SpriteBatch spriteBatch,
            Rectangle destRectangle,
            SpriteFont spriteFont,
            float globalDispX, float globalDispY)
        {
            float actualBoxWidth  = BoxWidth * viewPort.ActualZoom;
            float actualBoxHeight = BoxHeight * viewPort.ActualZoom;

            int startBoxX = (int)(globalDispX / actualBoxWidth);
            int startBoxY = (int)(globalDispY / actualBoxHeight);

            int viewBoxCountX = (int)Math.Ceiling(destRectangle.Width / actualBoxWidth) + 1;
            int viewBoxCountY = (int)Math.Ceiling(destRectangle.Height / actualBoxHeight) + 1;

            for (int i = 0; i < viewBoxCountX; i++)
            {
                for (int j = 0; j < viewBoxCountY; j++)
                {
                    int I = i + startBoxX;
                    int J = j + startBoxY;

                    if (I < 0 || J < 0 || I >= _boxCountX || J >= _boxCountY)
                    {
                        continue;
                    }

                    int index  = I + J * _boxCountX;
                    int x      = (int)(I * BoxWidth * viewPort.ActualZoom - globalDispX);
                    int y      = (int)(J * BoxHeight * viewPort.ActualZoom - globalDispY);
                    int width  = (int)(BoxWidth * viewPort.ActualZoom) - 1;
                    int height = (int)(BoxHeight * viewPort.ActualZoom) - 1;

                    int    entityCount = _hashLists[index].Count;
                    Color  drawColor   = debugColors[Math.Min(entityCount, debugColors.Length - 1)];
                    string debugText   = string.Format("{0}\n\r{1}", index, entityCount);

                    Vector2 debugTextMeasurements = spriteFont.MeasureString(debugText);

                    SpriteBatchExtensions.DrawRectangle(
                        spriteBatch,
                        new Rectangle(x, y, width, height),
                        drawColor, 0);

                    if (debugTextMeasurements.X < width &&
                        debugTextMeasurements.Y < height)
                    {
                        SpriteBatchExtensions.DrawCenteredString(
                            spriteBatch,
                            spriteFont,
                            debugText,
                            new Vector2(x, y) + new Vector2(width, height) / 2,
                            drawColor);
                    }
                }
            }
        }
Exemplo n.º 2
0
        internal void DrawQuadTreeNode(ViewPortInfo viewPort,
                                       SpriteBatch spriteBatch,
                                       QuadTreeNode node,
                                       Rectangle destRectangle,
                                       SpriteFont spriteFont,
                                       float globalDispX, float globalDispY)
        {
            if (node == null)
            {
                return;
            }

            int actualX = (int)Math.Ceiling(node.pxBounds.X * viewPort.ActualZoom - globalDispX);
            int actualY = (int)Math.Ceiling(node.pxBounds.Y * viewPort.ActualZoom - globalDispY);

            // We need to calculate the 'Actual' width and height otherwise drawing might be innacurate when zoomed.
            int actualWidth  = (int)Math.Ceiling(node.pxBounds.Width * viewPort.ActualZoom);
            int actualHeight = (int)Math.Ceiling(node.pxBounds.Height * viewPort.ActualZoom);

            // Only draw leaf nodes which are within the viewport specified.
            if (node.ChildNode1 == null &&
                new Rectangle(actualX, actualY, actualWidth, actualHeight).Intersects(destRectangle))
            {
                string nodeText = string.Format("{0}\n\r{1}", node.NodeID, node.Entities.Count);

                SpriteBatchExtensions.DrawRectangle(spriteBatch, new Rectangle(actualX, actualY, actualWidth, actualHeight), Color.Lime, 0);
                spriteBatch.DrawString(
                    spriteFont,
                    nodeText,
                    new Vector2(actualX + actualWidth / 2.0f, actualY + actualHeight / 2.0f) - spriteFont.MeasureString(nodeText) / 2,
                    Color.Lime
                    );
            }

            DrawQuadTreeNode(viewPort, spriteBatch, node.ChildNode1, destRectangle, spriteFont, globalDispX, globalDispY);
            DrawQuadTreeNode(viewPort, spriteBatch, node.ChildNode2, destRectangle, spriteFont, globalDispX, globalDispY);
            DrawQuadTreeNode(viewPort, spriteBatch, node.ChildNode3, destRectangle, spriteFont, globalDispX, globalDispY);
            DrawQuadTreeNode(viewPort, spriteBatch, node.ChildNode4, destRectangle, spriteFont, globalDispX, globalDispY);
        }
Exemplo n.º 3
0
        public ViewPortInfo DrawWorldViewPort(SpriteBatch spriteBatch, Vector2 center, float zoom, Rectangle destRectangle, Color color, SamplerState samplerState, SpriteFont spriteFont = null)
        {
            ViewPortInfo viewPortInfo = new ViewPortInfo();

            {
                viewPortInfo.pxTileWidth  = (int)Math.Ceiling(Map.TileWidth * zoom);
                viewPortInfo.pxTileHeight = (int)Math.Ceiling(Map.TileHeight * zoom);

                // Note about ActualZoom Property:
                // because there is a loss of data between to conversion from Map.pxTileWidth * Zoom -> (int)
                // we need to determine what was the actual level of zoom that was applied to the tiles and use that
                // this ensures that entities that will be drawn will be placed correctly on the screen.
                viewPortInfo.ActualZoom = viewPortInfo.pxTileWidth / Map.TileWidth;

                viewPortInfo.pxWidth  = destRectangle.Width / viewPortInfo.ActualZoom;
                viewPortInfo.pxHeight = destRectangle.Height / viewPortInfo.ActualZoom;

                viewPortInfo.pxTopLeftX = center.X - viewPortInfo.pxWidth / 2.0f;
                viewPortInfo.pxTopLeftY = center.Y - viewPortInfo.pxHeight / 2.0f;

                viewPortInfo.TileCountX = (int)Math.Ceiling((double)viewPortInfo.pxWidth / Map.TileWidth) + 1;
                viewPortInfo.TileCountY = (int)Math.Ceiling((double)viewPortInfo.pxHeight / Map.TileHeight) + 1;

                // Prevent the View from going outisde of the WORLD coordinates.
                if (viewPortInfo.pxTopLeftX < 0)
                {
                    viewPortInfo.pxTopLeftX = 0;
                }
                if (viewPortInfo.pxTopLeftY < 0)
                {
                    viewPortInfo.pxTopLeftY = 0;
                }

                if (viewPortInfo.pxTopLeftX + viewPortInfo.pxWidth >= Map.pxWidth)
                {
                    viewPortInfo.pxTopLeftX = Map.pxWidth - viewPortInfo.pxWidth;
                }
                if (viewPortInfo.pxTopLeftY + viewPortInfo.pxHeight >= Map.pxHeight)
                {
                    viewPortInfo.pxTopLeftY = Map.pxHeight - viewPortInfo.pxHeight;
                }

                // Calculate any decimal displacement required (For Positions with decimal points).
                viewPortInfo.pxDispX = viewPortInfo.pxTopLeftX - ((int)viewPortInfo.pxTopLeftX / Map.TileWidth) * Map.TileWidth;
                viewPortInfo.pxDispY = viewPortInfo.pxTopLeftY - ((int)viewPortInfo.pxTopLeftY / Map.TileHeight) * Map.TileHeight;

                viewPortInfo.pxViewPortBounds = new Rectangle(
                    (int)Math.Ceiling(viewPortInfo.pxTopLeftX),
                    (int)Math.Ceiling(viewPortInfo.pxTopLeftY),
                    (int)Math.Ceiling(viewPortInfo.pxWidth),
                    (int)Math.Ceiling(viewPortInfo.pxHeight)
                    );
            }

            // RENDER THE GAME WORLD TO THE VIEWPORT RENDER TARGET
            GraphicsDevice.SetRenderTarget(_inputBuffer);
            GraphicsDevice.Clear(Map.Background);

            // DRAW THE WORLD MAP
            OverallPerformance.StartTiming("TileRenderingTime");

            // Deferred Rendering should be fine for rendering tile as long as we draw tile layers one at a time
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, samplerState, null, null);
            {
                for (int layerIndex = 0; layerIndex < Map.TileLayers.Count; layerIndex++)
                {
                    // DRAW EACH LAYER
                    TileLayer tileLayer = Map.TileLayers[layerIndex];

                    if (tileLayer.Visible)
                    {
                        Color layerColor = new Color()
                        {
                            R = tileLayer.Color.R,
                            G = tileLayer.Color.G,
                            B = tileLayer.Color.B,
                            A = (byte)(tileLayer.Color.A * tileLayer.Opacity)
                        };

                        float depth = 1 - (layerIndex / 10000.0f);

                        for (int i = 0; i < viewPortInfo.TileCountX; i++)
                        {
                            for (int j = 0; j < viewPortInfo.TileCountY; j++)
                            {
                                int tileX = (int)(i + viewPortInfo.pxTopLeftX / Map.TileWidth);
                                int tileY = (int)(j + viewPortInfo.pxTopLeftY / Map.TileHeight);

                                int tileGid = tileLayer[tileX, tileY];

                                Rectangle pxTileDestRect = new Rectangle(
                                    (int)Math.Ceiling(i * viewPortInfo.pxTileWidth - viewPortInfo.pxDispX * viewPortInfo.ActualZoom),
                                    (int)Math.Ceiling(j * viewPortInfo.pxTileHeight - viewPortInfo.pxDispY * viewPortInfo.ActualZoom),
                                    (int)viewPortInfo.pxTileWidth,
                                    (int)viewPortInfo.pxTileHeight
                                    );

                                if (tileGid != 0 && tileGid != -1)   // NULL or INVALID Tile Gid is ignored
                                {
                                    Tile tile = Map.Tiles[tileGid];

                                    spriteBatch.Draw(
                                        tile.sourceTexture,
                                        pxTileDestRect,
                                        tile.SourceRectangle,
                                        layerColor,
                                        0, Vector2.Zero,
                                        SpriteEffects.None,
                                        depth
                                        );
                                }

                                // DRAW THE TILE LAYER GRID IF ENABLE
                                if (DrawingOptions.ShowTileGrid && layerIndex == Map.TileLayers.Count - 1)
                                {
                                    spriteBatch.DrawRectangle(pxTileDestRect, Color.Black, 0);
                                }
                            }
                        }
                    }
                }
            }
            spriteBatch.End();

            OverallPerformance.StopTiming("TileRenderingTime");

            // Calculate the entity Displacement caused by pxTopLeft at a global scale to prevent jittering.
            // Each entity should be displaced by the *same amount* based on the pxTopLeftX/Y values
            // this is to prevent entities 'jittering on the screen' when moving the camera.
            float globalDispX = (int)Math.Ceiling(viewPortInfo.pxTopLeftX * viewPortInfo.ActualZoom);
            float globalDispY = (int)Math.Ceiling(viewPortInfo.pxTopLeftY * viewPortInfo.ActualZoom);

            // DRAW VISIBLE REGISTERED ENTITIES
            OverallPerformance.RestartTiming("TotalEntityRenderTime");
            spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend, samplerState, null, null);
            {
                EntitiesOnScreen = Collider.GetIntersectingEntites(new FRectangle(viewPortInfo.pxViewPortBounds));

                // DRAW EACH ENTITIY THAT IS WITHIN THE SCREENS VIEWPORT
                foreach (Entity entity in EntitiesOnScreen)
                {
                    EntityRenderPerformance.RestartTiming(entity.Name);

                    if (!entity.Visible)
                    {
                        continue;
                    }
                    entity.IsOnScreen = true;

                    // Determine the absolute position on the screen for entity position and the bounding box.
                    Vector2 pxAbsEntityPos = new Vector2(
                        entity.Pos.X * viewPortInfo.ActualZoom - globalDispX,
                        entity.Pos.Y * viewPortInfo.ActualZoom - globalDispY
                        );

                    FRectangle pxAbsBoundingBox = new FRectangle(
                        entity.CurrentBoundingBox.X * viewPortInfo.ActualZoom - globalDispX,
                        entity.CurrentBoundingBox.Y * viewPortInfo.ActualZoom - globalDispY,
                        entity.CurrentBoundingBox.Width * viewPortInfo.ActualZoom,
                        entity.CurrentBoundingBox.Height * viewPortInfo.ActualZoom
                        );

                    // DRAW ENTITY BOUNDING BOXES IF ENABLED
                    if (DrawingOptions.ShowBoundingBoxes)
                    {
                        spriteBatch.DrawRectangle(pxAbsBoundingBox.ToRectangle(), Color.Red, 0.0001f);
                        SpriteBatchExtensions.DrawCross(
                            spriteBatch,
                            new Vector2(
                                (int)Math.Ceiling(pxAbsEntityPos.X),
                                (int)Math.Ceiling(pxAbsEntityPos.Y)
                                ),
                            13, Color.Black, 0f);
                    }

                    // DRAW ENTITY DETAILS IF ENABLED (ENTITY DEBUG INFO)
                    if (DrawingOptions.ShowEntityDebugInfo)
                    {
                        SpriteBatchExtensions.DrawMultiLineString(
                            spriteBatch,
                            spriteFont,
                            entity.GetDebugInfo(),
                            (int)entity.CurrentBoundingBox.Width * 2,
                            4,
                            new Vector2(
                                pxAbsBoundingBox.X + pxAbsBoundingBox.Width / 2,
                                pxAbsBoundingBox.Y + pxAbsBoundingBox.Height / 2
                                ),
                            Color.Purple);
                    }

                    // DRAW EVERY GAMEDRAWABLE INSTANCE CURRENTLY ACTIVE IN THE ENTITIES DRAWABLE SET.
                    HashSet <GameDrawableInstance> drawableInstances = entity.Drawables.GetByState(entity.CurrentDrawableState);

                    if (drawableInstances != null)
                    {
                        foreach (GameDrawableInstance drawable in drawableInstances)
                        {
                            if (!drawable.Visible)
                            {
                                continue;
                            }

                            // The relative position of the object should always be (X,Y) - (globalDispX, globalDispY). globalDispX and globalDispY
                            // are based on viewPortInfo.TopLeftX and viewPortInfo.TopLeftY. viewPortInfo.TopLeftX and viewPortInfo.TopLeftY have
                            // already been corrected in terms of the bounds of the WORLD map coordinates. This allows for panning at the edges.
                            Rectangle pxCurrentFrame = drawable.GetSourceRectangle(LastUpdateTime);

                            int pxObjectWidth  = (int)Math.Ceiling(pxCurrentFrame.Width * entity.ScaleX * viewPortInfo.ActualZoom);
                            int pxObjectHeight = (int)Math.Ceiling(pxCurrentFrame.Height * entity.ScaleY * viewPortInfo.ActualZoom);

                            // Draw the Object based on the current Frame dimensions and the specified Object Width Height values.
                            Rectangle objectDestRect = new Rectangle(
                                (int)Math.Ceiling(pxAbsEntityPos.X) + (int)Math.Ceiling(drawable.Offset.X * viewPortInfo.ActualZoom),
                                (int)Math.Ceiling(pxAbsEntityPos.Y) + (int)Math.Ceiling(drawable.Offset.Y * viewPortInfo.ActualZoom),
                                pxObjectWidth,
                                pxObjectHeight
                                );

                            Vector2 drawableOrigin = new Vector2(
                                (float)Math.Ceiling(drawable.Drawable.Origin.X * pxCurrentFrame.Width),
                                (float)Math.Ceiling(drawable.Drawable.Origin.Y * pxCurrentFrame.Height)
                                );

                            Color drawableColor = new Color()
                            {
                                R = drawable.Color.R,
                                G = drawable.Color.G,
                                B = drawable.Color.B,
                                A = (byte)(drawable.Color.A * entity.Opacity)
                            };

                            // Layer depth should depend how far down the object is on the map (Relative to Y).
                            // Important to also take into account the animation layers for the entity.
                            float layerDepth = Math.Min(0.99f, 1 / (entity.Pos.Y + ((float)drawable.Layer / Map.pxHeight)));

                            // FINALLY ... DRAW
                            spriteBatch.Draw(
                                drawable.GetSourceTexture(LastUpdateTime),
                                objectDestRect,
                                pxCurrentFrame,
                                drawableColor,
                                drawable.Rotation,
                                drawableOrigin,
                                drawable.SpriteEffects,
                                layerDepth);

                            // DRAW BOUNDING BOXES OF EACH INDIVIDUAL DRAWABLE COMPONENT
                            if (DrawingOptions.ShowDrawableComponents)
                            {
                                Rectangle drawableComponentRect = new Rectangle(
                                    (int)Math.Floor(objectDestRect.X - objectDestRect.Width * drawable.Drawable.Origin.X),
                                    (int)Math.Floor(objectDestRect.Y - objectDestRect.Height * drawable.Drawable.Origin.Y),
                                    objectDestRect.Width, objectDestRect.Height);

                                SpriteBatchExtensions.DrawRectangle(
                                    spriteBatch, drawableComponentRect, Color.Blue, 0);
                            }
                        }
                    }

                    EntityRenderPerformance.StopTiming(entity.Name);
                }
            }
            spriteBatch.End();
            OverallPerformance.StopTiming("TotalEntityRenderTime");

            // APPLY GAME SHADERS TO THE RESULTANT IMAGE
            OverallPerformance.RestartTiming("TotalPostGameShaderRenderTime");
            foreach (PostGameShader postGameShader in GameShaders)
            {
                if (postGameShader.Enabled)
                {
                    postGameShader.ApplyShader(spriteBatch, viewPortInfo, LastUpdateTime, _inputBuffer, _outputBuffer);

                    // Swap buffers after each render.
                    _dummyBuffer  = _inputBuffer;
                    _inputBuffer  = _outputBuffer;
                    _outputBuffer = _dummyBuffer;
                }
            }
            OverallPerformance.StopTiming("TotalPostGameShaderRenderTime");

            // DRAW COLLIDER DEBUG INFORMATION IF ENABLED
            if (DrawingOptions.ShowColliderDebugInfo)
            {
                spriteBatch.Begin();
                Collider.DrawDebugInfo(viewPortInfo, spriteBatch, destRectangle, spriteFont, globalDispX, globalDispY);
                spriteBatch.End();
            }

            // DRAW THE VIEWPORT TO THE STANDARD SCREEN
            GraphicsDevice.SetRenderTarget(null);
            spriteBatch.Begin();
            {
                spriteBatch.Draw(_inputBuffer, destRectangle, color);
            }
            spriteBatch.End();

            return(viewPortInfo);
        }