private void setClipRegion(dfControl control, ref Rect screenRect) { var controlSize = control.Size; var padding = control.GetClipPadding(); var horzPadding = Mathf.Min(Mathf.Max(0, Mathf.Min(controlSize.x, padding.horizontal)), controlSize.x); var vertPadding = Mathf.Min(Mathf.Max(0, Mathf.Min(controlSize.y, padding.vertical)), controlSize.y); this.clipInfo = new ClipRegionInfo(); this.clipInfo.Size = Vector2.Max(new Vector2(controlSize.x - horzPadding, controlSize.y - vertPadding), Vector3.zero); this.clipInfo.Offset = new Vector3(padding.left - padding.right, -(padding.top - padding.bottom)) * 0.5f; clipRect = containerRect.IsEmpty() ? screenRect : containerRect.Intersection(screenRect); }
private void setClipRegion( dfControl control, ref Rect screenRect ) { var controlSize = control.Size; var padding = control.GetClipPadding(); var horzPadding = Mathf.Min( Mathf.Max( 0, Mathf.Min( controlSize.x, padding.horizontal ) ), controlSize.x ); var vertPadding = Mathf.Min( Mathf.Max( 0, Mathf.Min( controlSize.y, padding.vertical ) ), controlSize.y ); this.clipInfo = new ClipRegionInfo(); this.clipInfo.Size = Vector2.Max( new Vector2( controlSize.x - horzPadding, controlSize.y - vertPadding ), Vector3.zero ); this.clipInfo.Offset = new Vector3( padding.left - padding.right, -( padding.top - padding.bottom ) ) * 0.5f; clipRect = containerRect.IsEmpty() ? screenRect : containerRect.Intersection( screenRect ); }
private void renderControl( ref dfRenderData buffer, dfControl control, uint checksum, float opacity ) { // Don't render controls that are not currently active if( !control.enabled || !control.gameObject.activeSelf ) return; // Don't render controls that are invisible. Keeping a running // accumulator for opacity allows us to know a control's final // calculated opacity var effectiveOpacity = opacity * control.Opacity; if( effectiveOpacity <= 0.001f ) { return; } // If this control has a dfRenderGroup component on it, then pass off all // responsibility for rendering that control to the component. var renderGroup = GetRenderGroupForControl( control, true ); if( renderGroup != null && renderGroup != this && renderGroup.enabled ) { renderGroups.Add( renderGroup ); renderGroup.Render( renderCamera, control, groupOccluders, groupControls, checksum, effectiveOpacity ); return; } // Don't render controls that have the IsVisible flag set to FALSE. Note that this is tested // *after* checking for the presence of a dfRenderGroup component, since that component (if // present) will need to update its own internal state if the control's IsVisible property // has changed. if( !control.GetIsVisibleRaw() ) return; // Grab the current clip region information off the stack var clipInfo = clipStack.Peek(); // Update the checksum to include the current control checksum = dfChecksumUtil.Calculate( checksum, control.Version ); // Retrieve the control's bounds, which will be used in intersection testing // and triangle clipping. var bounds = control.GetBounds(); var screenRect = control.GetScreenRect(); var occluder = getControlOccluder( ref screenRect, control ); // Indicates whether the control was not rendered because it fell outside // of the currently-active clipping region var wasClipped = false; if( !( control is IDFMultiRender ) ) { // Ask the control to render itself and return a buffer of the // information needed to render it as a Mesh var controlData = control.Render(); if( controlData != null ) { processRenderData( ref buffer, controlData, ref bounds, ref screenRect, checksum, clipInfo, ref wasClipped ); } } else { // Ask the control to render itself and return as many dfRenderData buffers // as needed to render all elements of the control as a Mesh var childBuffers = ( (IDFMultiRender)control ).RenderMultiple(); if( childBuffers != null ) { var buffers = childBuffers.Items; var bufferCount = childBuffers.Count; for( int i = 0; i < bufferCount; i++ ) { var childBuffer = buffers[ i ]; if( childBuffer != null ) { processRenderData( ref buffer, childBuffer, ref bounds, ref screenRect, checksum, clipInfo, ref wasClipped ); } } } } // Allow control to keep track of its clipping state control.setClippingState( wasClipped ); // Keep track of which controls are rendered, and where they appear on-screen groupOccluders.Add( occluder ); groupControls.Add( control ); // If the control has the "Clip child controls" option set, push // its clip region information onto the stack so that all controls // lower in the hierarchy are clipped against that region. if( control.ClipChildren ) { if( !Application.isPlaying || clipType == dfClippingMethod.Software ) { clipInfo = dfTriangleClippingRegion.Obtain( clipInfo, control ); clipStack.Push( clipInfo ); } else if( this.clipInfo.IsEmpty ) { setClipRegion( control, ref screenRect ); } } // Dereference raw child control list for direct access var childControls = control.Controls.Items; var childCount = control.Controls.Count; // Ensure lists contain enough space for child controls groupControls.EnsureCapacity( groupControls.Count + childCount ); groupOccluders.EnsureCapacity( groupOccluders.Count + childCount ); // Render all child controls for( int i = 0; i < childCount; i++ ) { renderControl( ref buffer, childControls[ i ], checksum, effectiveOpacity ); } // No longer need the current control's clip region information if( control.ClipChildren ) { if( !Application.isPlaying || clipType == dfClippingMethod.Software ) { clipStack.Pop().Release(); } } }
internal void Render( Camera renderCamera, dfControl control, dfList<Rect> occluders, dfList<dfControl> controlsRendered, uint checksum, float opacity ) { if( meshRenderer == null ) { initialize(); } this.renderCamera = renderCamera; this.attachedControl = control; if( !isDirty ) { // Update the caller's lists occluders.AddRange( groupOccluders ); controlsRendered.AddRange( groupControls ); return; } // Clear lists that will contain the results of the rendering process groupOccluders.Clear(); groupControls.Clear(); renderGroups.Clear(); resetDrawCalls(); // Disable shader clipping by default this.clipInfo = new ClipRegionInfo(); this.clipRect = new Rect(); // Define the main draw call buffer, which will be assigned as needed // by the renderControl() method var buffer = (dfRenderData)null; using( var defaultClipRegion = dfTriangleClippingRegion.Obtain() ) { // Initialize the clipping region stack clipStack.Clear(); clipStack.Push( defaultClipRegion ); // Render the control and all of its children renderControl( ref buffer, control, checksum, opacity ); // The clip stack is reset after every frame as it's only needed during rendering clipStack.Pop(); } // Remove any empty draw call buffers. There might be empty // draw call buffers due to controls that were clipped. drawCallBuffers.RemoveAll( isEmptyBuffer ); drawCallCount = drawCallBuffers.Count; // At this point, the drawCallCount variable contains the // number of draw calls needed to render the user interface. if( drawCallBuffers.Count == 0 ) { meshRenderer.enabled = false; return; } else { meshRenderer.enabled = true; } // Consolidate all draw call buffers into one master buffer // that will be used to build the Mesh var masterBuffer = compileMasterBuffer(); // Build the master mesh var mesh = renderMesh; mesh.Clear( true ); mesh.vertices = masterBuffer.Vertices.ToTempArray(); mesh.uv = masterBuffer.UV.ToTempArray(); mesh.colors32 = masterBuffer.Colors.ToTempArray(); #region Set sub-meshes mesh.subMeshCount = submeshes.Count; for( int i = 0; i < submeshes.Count; i++ ) { // Calculate the start and length of the submesh array var startIndex = submeshes[ i ]; var length = masterBuffer.Triangles.Count - startIndex; if( i < submeshes.Count - 1 ) { length = submeshes[ i + 1 ] - startIndex; } var submeshTriangles = dfTempArray<int>.Obtain( length, 128 ); masterBuffer.Triangles.CopyTo( startIndex, submeshTriangles, 0, length ); // Set the submesh's triangle index array mesh.SetTriangles( submeshTriangles, i ); } #endregion // This render group no longer requires updating isDirty = false; // Update the caller's lists occluders.AddRange( groupOccluders ); controlsRendered.AddRange( groupControls ); }
private void renderControl(ref dfRenderData buffer, dfControl control, uint checksum, float opacity) { // Don't render controls that are not currently active if (!control.enabled || !control.gameObject.activeSelf) { return; } // Don't render controls that are invisible. Keeping a running // accumulator for opacity allows us to know a control's final // calculated opacity var effectiveOpacity = opacity * control.Opacity; if (effectiveOpacity <= 0.001f) { return; } // If this control has a dfRenderGroup component on it, then pass off all // responsibility for rendering that control to the component. var renderGroup = GetRenderGroupForControl(control, true); if (renderGroup != null && renderGroup != this && renderGroup.enabled) { renderGroups.Add(renderGroup); renderGroup.Render(renderCamera, control, groupOccluders, groupControls, checksum, effectiveOpacity); return; } // Don't render controls that have the IsVisible flag set to FALSE. Note that this is tested // *after* checking for the presence of a dfRenderGroup component, since that component (if // present) will need to update its own internal state if the control's IsVisible property // has changed. if (!control.GetIsVisibleRaw()) { return; } // Grab the current clip region information off the stack var clipInfo = clipStack.Peek(); // Update the checksum to include the current control checksum = dfChecksumUtil.Calculate(checksum, control.Version); // Retrieve the control's bounds, which will be used in intersection testing // and triangle clipping. var bounds = control.GetBounds(); var screenRect = control.GetScreenRect(); var occluder = getControlOccluder(ref screenRect, control); // Indicates whether the control was not rendered because it fell outside // of the currently-active clipping region var wasClipped = false; if (!(control is IDFMultiRender)) { // Ask the control to render itself and return a buffer of the // information needed to render it as a Mesh var controlData = control.Render(); if (controlData != null) { processRenderData(ref buffer, controlData, ref bounds, ref screenRect, checksum, clipInfo, ref wasClipped); } } else { // Ask the control to render itself and return as many dfRenderData buffers // as needed to render all elements of the control as a Mesh var childBuffers = ((IDFMultiRender)control).RenderMultiple(); if (childBuffers != null) { var buffers = childBuffers.Items; var bufferCount = childBuffers.Count; for (int i = 0; i < bufferCount; i++) { var childBuffer = buffers[i]; if (childBuffer != null) { processRenderData(ref buffer, childBuffer, ref bounds, ref screenRect, checksum, clipInfo, ref wasClipped); } } } } // Allow control to keep track of its clipping state control.setClippingState(wasClipped); // Keep track of which controls are rendered, and where they appear on-screen groupOccluders.Add(occluder); groupControls.Add(control); // If the control has the "Clip child controls" option set, push // its clip region information onto the stack so that all controls // lower in the hierarchy are clipped against that region. if (control.ClipChildren) { if (!Application.isPlaying || clipType == dfClippingMethod.Software) { clipInfo = dfTriangleClippingRegion.Obtain(clipInfo, control); clipStack.Push(clipInfo); } else if (this.clipInfo.IsEmpty) { setClipRegion(control, ref screenRect); } } // Dereference raw child control list for direct access var childControls = control.Controls.Items; var childCount = control.Controls.Count; // Ensure lists contain enough space for child controls groupControls.EnsureCapacity(groupControls.Count + childCount); groupOccluders.EnsureCapacity(groupOccluders.Count + childCount); // Render all child controls for (int i = 0; i < childCount; i++) { renderControl(ref buffer, childControls[i], checksum, effectiveOpacity); } // No longer need the current control's clip region information if (control.ClipChildren) { if (!Application.isPlaying || clipType == dfClippingMethod.Software) { clipStack.Pop().Release(); } } }
internal void Render(Camera renderCamera, dfControl control, dfList <Rect> occluders, dfList <dfControl> controlsRendered, uint checksum, float opacity) { if (meshRenderer == null) { initialize(); } this.renderCamera = renderCamera; this.attachedControl = control; if (!isDirty) { // Update the caller's lists occluders.AddRange(groupOccluders); controlsRendered.AddRange(groupControls); return; } // Clear lists that will contain the results of the rendering process groupOccluders.Clear(); groupControls.Clear(); renderGroups.Clear(); resetDrawCalls(); // Disable shader clipping by default this.clipInfo = new ClipRegionInfo(); this.clipRect = new Rect(); // Define the main draw call buffer, which will be assigned as needed // by the renderControl() method var buffer = (dfRenderData)null; using (var defaultClipRegion = dfTriangleClippingRegion.Obtain()) { // Initialize the clipping region stack clipStack.Clear(); clipStack.Push(defaultClipRegion); // Render the control and all of its children renderControl(ref buffer, control, checksum, opacity); // The clip stack is reset after every frame as it's only needed during rendering clipStack.Pop(); } // Remove any empty draw call buffers. There might be empty // draw call buffers due to controls that were clipped. drawCallBuffers.RemoveAll(isEmptyBuffer); drawCallCount = drawCallBuffers.Count; // At this point, the drawCallCount variable contains the // number of draw calls needed to render the user interface. if (drawCallBuffers.Count == 0) { meshRenderer.enabled = false; return; } else { meshRenderer.enabled = true; } // Consolidate all draw call buffers into one master buffer // that will be used to build the Mesh var masterBuffer = compileMasterBuffer(); // Build the master mesh var mesh = renderMesh; mesh.Clear(true); mesh.vertices = masterBuffer.Vertices.Items; mesh.uv = masterBuffer.UV.Items; mesh.colors32 = masterBuffer.Colors.Items; #region Set sub-meshes mesh.subMeshCount = submeshes.Count; for (int i = 0; i < submeshes.Count; i++) { // Calculate the start and length of the submesh array var startIndex = submeshes[i]; var length = masterBuffer.Triangles.Count - startIndex; if (i < submeshes.Count - 1) { length = submeshes[i + 1] - startIndex; } var submeshTriangles = dfTempArray <int> .Obtain(length); masterBuffer.Triangles.CopyTo(startIndex, submeshTriangles, 0, length); // Set the submesh's triangle index array mesh.SetTriangles(submeshTriangles, i); } #endregion // This render group no longer requires updating isDirty = false; // Update the caller's lists occluders.AddRange(groupOccluders); controlsRendered.AddRange(groupControls); }