/// <summary> /// Overwrites the current render state with the provided state. To Save the previous state, see <see cref="PushRenderState(ref DeviceRenderState)"/> /// </summary> /// <param name="state"></param> public void SetRenderState(ref DeviceRenderState state) { #if DEBUG ValidateRenderState(); #endif this.visibleState.state = state; }
/// <summary> /// Saves the current render state onto the render state stack, then copies the provided render state in. Reset the state back with a call to <see cref="PopRenderState"/> /// </summary> /// <remarks><para>If you wish to modify the render state temporarily, then it is best to call this method before making change, then call <see cref="PopRenderState"/> after rendering is complete to restore the previous state.</para><para>This will be a lot more efficient than manually storing the states that are changed</para></remarks> public void PushRenderState(ref DeviceRenderState newState) { #if DEBUG ValidateRenderState(); #endif PushRenderState(); this.visibleState.state = newState; }
//each of these 4 methods is more efficient than the previous... //this method is the manual method where each state is setup peice by peice private void DrawManual(DrawState state) { //manual render state //First, take a copy of current render state.. DeviceRenderState currentState = state.RenderState; //The DeviceRenderState structure stores common render state, it's bit-packed so it's small. //The majority of render state is stored, with most commonly used xbox-supported state included. //The entire structure is 16 bytes (the size of a Vector4) // //The DeviceRenderState structure stores four smaller structures: // // StencilTestState StencilTest; (8 bytes) // AlphaBlendState AlphaBlend; (4 bytes) // AlphaTestState AlphaTest; (2 bytes) // DepthColourCullState DepthColourCull; (2 bytes) // //DepthColourCullState combines the three smaller states, Depth testing, Colour masking and FrustumCull mode // //When geometry is rendered, state.RenderState is compared to the current known device state //This comparison is very fast. Any changes detected will be applied at render time. // //Because of this, changing state.RenderState is very fast and efficient, as actual render state //on the GraphicsDevice doesn't change until the geometry is drawn. No logic is run when changing //the value. // //In terms of efficiency, think of setting the DeviceRenderState as equivalent assigning integers. //Here the alpha blend state is changed manually... //reset the state to default (no blending) state.RenderState.AlphaBlend = new AlphaBlendState(); //4 bytes assigned to zero, no heap allocations //set blending... state.RenderState.AlphaBlend.Enabled = true; //one bit is changed state.RenderState.AlphaBlend.SourceBlend = Blend.SourceAlpha; //4 bits are changed state.RenderState.AlphaBlend.DestinationBlend = Blend.InverseSourceAlpha; //4 bits are changed //draw the sphere DrawGeometry(state); //set the previous state back state.SetRenderState(ref currentState); //Note: //you cannot write: //state.RenderState = currentState; //you have to call 'SetRenderState()' instead. }
public void Render(DrawState state, byte clipDepth) { Element parent = _parent; Matrix matrix; DeviceContext context = state.Context; if (parent == null) { _clipTest = false; DeviceRenderState rstate = new DeviceRenderState(); rstate.DepthColourCull.DepthWriteEnabled = false; rstate.DepthColourCull.DepthTestEnabled = false; state.PushRenderState(ref rstate); if (_camera == null) _camera = new ElementCamera(true); state.PushCamera(_camera); } else _clipTest = parent._clipTest | parent.ClipsChildren; StencilTestState stencilState = new StencilTestState(); if (_clipTest) { stencilState.Enabled = true; stencilState.ReferenceValue = clipDepth; stencilState.StencilFunction = Compare.Equal; stencilState.StencilPassOperation = StencilOperation.Keep; } bool clearStencil = false; if (ClipsChildren) { clearStencil = clipDepth == 255; clipDepth--; if (!_clipTest) { stencilState.Enabled = true; stencilState.ReferenceValue = clipDepth; stencilState.StencilPassOperation = StencilOperation.Replace; } else stencilState.StencilPassOperation = StencilOperation.Decrement; } Viewport viewport = context.Viewport; Vector2 scale = new Vector2(viewport.Width, viewport.Height); if ((scale.X != 0 && scale.Y != 0)) { Vector2 size = ElementSize; GetDisplayMatrix(out matrix, scale, ref size); state.PushWorldMatrixMultiply(ref matrix); BindShader(state, false); state.RenderState.AlphaBlend = _blendState; state.RenderState.StencilTest = stencilState; if (!UseSize) size = new Vector2(1, 1); else if (IsNormalised) { size.X *= scale.X; size.Y *= scale.Y; } PreDraw(state.Context, size); DrawElement(state); List<Element> children = Children; if (children != null) foreach (Element child in children) if (child.CullTest(state)) child.Render(state, clipDepth); if (clearStencil) { BindShader(state, true); stencilState = new StencilTestState(); stencilState.Enabled = true; stencilState.StencilFunction = Compare.Never; stencilState.StencilFailOperation = StencilOperation.Zero; state.RenderState.StencilTest = stencilState; DrawElement(state); } state.PopWorldMatrix(); } if (parent == null) { state.PopRenderState(); state.PopCamera(); } }
private void Draw(DrawState state, Vector2 scale, byte clipDepth) { Element parent = this.parent; Matrix matrix; GraphicsDevice device = null; if (parent == null) { if (state.DrawTarget.MultiSampleType != MultiSampleType.None) { device = state.BeginGetGraphicsDevice(StateFlag.None); device.RenderState.MultiSampleAntiAlias = false; } this.clipTestActive = false; DeviceRenderState rstate = new DeviceRenderState(); rstate.DepthColourCull.DepthWriteEnabled = false; rstate.DepthColourCull.DepthTestEnabled = false; state.PushRenderState(ref rstate); if (camera == null) { camera = state.UserValues[cameraID] as Xen.Camera.Camera2D; if (camera == null) { camera = new Xen.Camera.Camera2D(true); state.UserValues[cameraID] = camera; } } state.PushCamera(camera); } else { this.clipTestActive = parent.clipTestActive | parent.ClipsChildren; } StencilTestState stencilState = new StencilTestState(); if (clipTestActive) { stencilState.Enabled = true; stencilState.ReferenceValue = clipDepth; stencilState.StencilFunction = CompareFunction.Equal; stencilState.StencilPassOperation = StencilOperation.Keep; } bool clearStencil = false; if (this.ClipsChildren) { clearStencil = clipDepth == 255; clipDepth--; if (!clipTestActive) { //check there actually is a stencil buffer #if DEBUG DepthFormat format = state.DrawTarget.SurfaceDepthFormat ?? DepthFormat.Unknown; if (format != DepthFormat.Depth24Stencil8) { throw new InvalidOperationException("ElementRect.ClipChildren requires the DrawTarget has a valid Depth Buffer with an 8bit Stencil Buffer"); } #endif stencilState.Enabled = true; stencilState.ReferenceValue = clipDepth; stencilState.StencilPassOperation = StencilOperation.Replace; } else { stencilState.StencilPassOperation = StencilOperation.Decrement; } } if ((scale.X != 0 && scale.Y != 0)) { Vector2 size = ElementSize; GetDisplayMatrix(out matrix, scale, ref size); state.PushWorldMatrixMultiply(ref matrix); BindShader(state, false); state.RenderState.AlphaBlend = blend; state.RenderState.StencilTest = stencilState; if (!UseSize) { size = new Vector2(1, 1); } else if (IsNormalised) { size *= scale; } PreDraw(size); DrawElement(state); List <Element> children = Children; if (children != null) { foreach (Element child in children) { if (((IDraw)child).CullTest(state)) { child.Draw(state, size, clipDepth); } } } if (clearStencil) { BindShader(state, true); stencilState = new StencilTestState(); stencilState.Enabled = true; stencilState.StencilFunction = CompareFunction.Never; stencilState.StencilFailOperation = StencilOperation.Zero; state.RenderState.StencilTest = stencilState; DrawElement(state); } state.PopWorldMatrix(); } if (parent == null) { state.PopRenderState(); state.PopCamera(); } if (device != null) { device.RenderState.MultiSampleAntiAlias = true; state.EndGetGraphicsDevice(); } }