// ===== #region Constructors // Designated constructor public SpriteTexture(Rectangle rectangle, WrappedTexture texture, WrappedShader shader) { // Get ID this.id = nextID++; // Entry logging #if IS_LOGGING_METHODS Log.Write(String.Format("Entering method for {0}", this.Name)); #endif // Set instance variables this.layer = null; this.layerIndex = -1; this.depth = 0; this.needsUpdate = false; this.rectangle = rectangle; this.texture = texture; this.shader = shader; // Initialize vertices this.vertices = new VertexInput[4]; this.vertices[0] = new VertexInput(rectangle.VertexAt(0), Color.White, new Vector2(0, 0)); this.vertices[1] = new VertexInput(rectangle.VertexAt(1), Color.White, new Vector2(1, 0)); this.vertices[2] = new VertexInput(rectangle.VertexAt(2), Color.White, new Vector2(1, 1)); this.vertices[3] = new VertexInput(rectangle.VertexAt(3), Color.White, new Vector2(0, 1)); // Exit logging #if IS_LOGGING_METHODS Log.Write(String.Format("Exiting method for {0}", this.Name)); #endif }
// Draw a layer public void DrawLayer(SpriteLayer layer) { // Entry logging #if IS_LOGGING_METHODS Log.Write(String.Format("Entering method for {0}", this.Name)); #endif // If no sprites, skip if (layer.SpriteCount <= 0) { goto exit; } // Activate layer buffers on device this.ActiveVertexBuffer = layer.VertexBuffer; this.ActiveIndexBuffer = layer.IndexBuffer; // Below, we will render our sprites in batches. For performance // reasons, we want these batches to be as large as possible. Recall // that our sprites are ordered by depth and texture. We will iterate // over each sprite and ask, 'Can this sprite be batched with the next?' // If so, we defer its rendering and add it to the current batch. // Otherwise, we immediately render the current batch. // Initialization Sprite sprite = layer.Sprites[0]; WrappedTexture texture = sprite.Texture; WrappedShader parameters = sprite.Shader; Sprite nextSprite = sprite; WrappedTexture nextTexture = texture; WrappedShader nextParameters = parameters; int vertexStart = 0; int vertexCount = sprite.Vertices.Length; int indexStart = 0; int indexCount = sprite.Indices.Length; int primitiveCount = sprite.Vertices.Length - 2; // Loop for (int i = 0; i < layer.SpriteCount; i++) { // Log #if IS_LOGGING_DRAW Log.Write(String.Format("Now entering iteration {0} of {1} for {2}", i + 1, layer.SpriteCount, sprite.Name)); Log.Write(String.Format("vertexStart = {0}", vertexStart)); Log.Write(String.Format("vertexCount = {0}", vertexCount)); Log.Write(String.Format("indexStart = {0}", indexStart)); Log.Write(String.Format("indexCount = {0}", indexCount)); Log.Write(String.Format("primitiveCount = {0}", primitiveCount)); Log.Write(String.Format("drawCalls = {0}", drawCalls)); #endif // Initialize canBatch, a boolean that equals true if this sprite can // be batched with the next, as false bool canBatch = false; // On the last iteration, there is no 'next' sprite if (i + 1 < layer.SpriteCount) { // Get next sprite nextSprite = layer.Sprites[i + 1]; nextTexture = nextSprite.Texture; nextParameters = nextSprite.Shader; // Check if this sprite can be batched with the next if (texture == nextTexture && parameters == nextParameters) { canBatch = true; } } // 'Can this sprite be batched with the next?' if (canBatch) { // If so, add to batch vertexCount += sprite.Vertices.Length; indexCount += sprite.Indices.Length; primitiveCount += sprite.Vertices.Length - 2; // Log #if IS_LOGGING_DRAW Log.Write(String.Format("This sprite can be grouped with the next. Adding to batch...")); #endif } else { // Otherwise, render current batch // Log #if IS_LOGGING_DRAW Log.Write(String.Format("This sprite CANNOT be grouped with the next. Rendering batch!")); #endif // Set the active texture this.ActiveTexture = texture; // Set the active shader this.ActiveShader = sprite.Shader; // Call draw this.Device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, vertexStart, vertexCount, indexStart, primitiveCount); /* * this.ActiveShader.Effect.CurrentTechnique.Passes[0].Apply(); * Trace.WriteLine(String.Format("updateCount = {0}, drawCalls = {1}:", Globals.Clock.TotalUpdateCount, this.DrawCalls)); * Trace.WriteLine(String.Format("activeShader = {0}", this.ActiveShader.Name)); * Trace.WriteLine(String.Format("texWidth = {0}", this.ActiveShader.Effect.Parameters["tex"].GetValueTexture2D().Width)); * Trace.WriteLine(String.Format("view = {0}", this.ActiveShader.Effect.Parameters["view"].GetValueMatrix())); * Trace.WriteLine(String.Format("projection = {0}", this.ActiveShader.Effect.Parameters["projection"].GetValueMatrix())); * Trace.WriteLine(String.Format("threshold = {0}", this.ActiveShader.Effect.Parameters["threshold"].GetValueSingle())); * Trace.WriteLine(String.Format("alpha = {0}", this.ActiveShader.Effect.Parameters["alpha"].GetValueSingle())); * Trace.WriteLine("=========="); */ /* * String s = String.Format("updateCount = {0}, drawCalls = {1}:", Globals.Clock.TotalUpdateCount, this.DrawCalls); * s += String.Format("\nactiveRenderTarget = {0}", this.activeRenderTarget); * s += String.Format("\nactiveVertexBuffer = {0}", this.activeVertexBuffer); * s += String.Format("\nactiveIndexBuffer = {0}", this.activeIndexBuffer); * s += String.Format("\nactiveView = {0}", this.activeView); * s += String.Format("\nactiveProjection = {0}", this.activeProjection); * s += String.Format("\nactiveTexture = {0}", this.activeTexture); * s += String.Format("\nactiveShader = {0}", this.activeShader); * s += String.Format("\nactiveBlendState = {0}", this.activeBlendState); * s += String.Format("\nactiveDepthStencilState = {0}", this.activeDepthStencilState); * s += "\n=========="; * Trace.WriteLine(s); */ /* * String s = String.Format("updateCount = {0}, device.vB = {1}", Globals.Clock.TotalUpdateCount, this.Device.GetVertexBuffers()[0].VertexBuffer.VertexCount); * Trace.WriteLine(s); */ // Log #if IS_LOGGING_DRAW Log.Write(String.Format("Just rendered the following buffer data:")); for (int l = vertexStart; l < vertexStart + vertexCount; l++) { Log.Write(String.Format("layer.Vertices[{0}] = {1}", l, layer.Vertices[l])); } for (int l = indexStart; l < indexStart + indexCount; l++) { Log.Write(String.Format("layer.Indices[{0}] = {1}", l, layer.Indices[l])); } #endif // This batch is complete this.drawCalls++; // Now, we create a brand new batch vertexStart += vertexCount; indexStart += indexCount; // So far, it only contains the next sprite vertexCount = nextSprite.Vertices.Length; indexCount = nextSprite.Indices.Length; primitiveCount = nextSprite.Vertices.Length - 2; } // Prepare for next iteration sprite = nextSprite; texture = nextTexture; parameters = nextParameters; } // [*] Exit trap: exit: // Exit logging #if IS_LOGGING_METHODS Log.Write(String.Format("Exiting method for {0}", this.Name)); #endif // Exit return; }
// Set a texture parameter public void SetParameter(String parameterName, WrappedTexture value) { this.Effect.Parameters[parameterName].SetValue(value.Texture); }
// ===== #region Constructors // Default constructor public WrappedGraphicsDevice() { // Get ID this.id = nextID++; // Entry logging #if IS_LOGGING_METHODS Log.Write(String.Format("Entering method for {0}", this.Name)); #endif // Set screen size in pixels // WARNING: ApplyChanges() will empty out all vertex and index buffers?! int w = 1280; int h = 720; Globals.Game1.Graphics.PreferredBackBufferWidth = w; Globals.Game1.Graphics.PreferredBackBufferHeight = h; Globals.Game1.Graphics.PreferredDepthStencilFormat = DepthFormat.Depth24Stencil8; Globals.Game1.Graphics.ApplyChanges(); Globals.Game1.IsMouseVisible = true; Globals.Game1.Window.AllowUserResizing = true; // Set instance variables this.activeRenderTarget = null; this.activeVertexBuffer = null; this.activeIndexBuffer = null; this.activeView = Matrix.Identity; this.activeProjection = Matrix.Identity; this.activeTexture = null; this.activeShader = null; this.activeBlendState = null; this.activeDepthStencilState = null; this.backBuffer = new WrappedBackBuffer(); this.renderTargetManager = new RenderTargetManager(); this.quadVertexBuffer = new WrappedVertexBuffer(4); this.quadIndexBuffer = new WrappedIndexBuffer(6); this.quadIndexBuffer.SetData(new int[6] { 0, 1, 2, 0, 2, 3 }); this.backgroundColor = Color.White; this.drawCalls = 0; this.device = Globals.Game1.GraphicsDevice; this.spriteBatch = new SpriteBatch(this.device); // this.device.DepthStencilState = new DepthStencilState() { DepthBufferEnable = false }; this.blendStateAlpha = new BlendState() { AlphaDestinationBlend = Blend.InverseSourceAlpha, ColorDestinationBlend = Blend.InverseSourceAlpha, ColorWriteChannels = ColorWriteChannels.All }; this.blendStateNone = new BlendState() { AlphaDestinationBlend = Blend.InverseSourceAlpha, ColorDestinationBlend = Blend.InverseSourceAlpha, ColorWriteChannels = ColorWriteChannels.None }; this.stencilStateIncrement = new DepthStencilState() { StencilEnable = true, StencilFunction = CompareFunction.LessEqual, ReferenceStencil = 0, StencilPass = StencilOperation.Increment }; this.stencilStateKeep = new DepthStencilState() { StencilEnable = true, StencilFunction = CompareFunction.LessEqual, ReferenceStencil = 0, StencilPass = StencilOperation.Keep }; // Exit logging #if IS_LOGGING_METHODS Log.Write(String.Format("Exiting method for {0}", this.Name)); #endif }