/// <summary>
                /// Draws a billboard in world space facing the +Z direction of the matrix given. Units in meters,
                /// matrix transform notwithstanding. Dont forget to compensate for perspective scaling!
                /// </summary
                public void Draw(ref CroppedBox box, ref MatrixD matrix)
                {
                    ContainmentType containment = ContainmentType.Contains;

                    if (box.mask != null)
                    {
                        box.mask.Value.Contains(ref box.bounds, out containment);
                    }

                    if (containment != ContainmentType.Disjoint)
                    {
                        if (updateMatFit && matFrame.Material != Material.Default)
                        {
                            Vector2 boxSize = box.bounds.Size;
                            minBoard.texCoords = matFrame.GetMaterialAlignment(boxSize.X / boxSize.Y);
                            updateMatFit       = false;
                        }

                        if (containment == ContainmentType.Contains)
                        {
                            minBoard.Draw(ref box, ref matrix);
                        }
                        else if (containment == ContainmentType.Intersects && matFrame.Material == Material.Default)
                        {
                            minBoard.DrawCropped(ref box, ref matrix);
                        }
                        else
                        {
                            minBoard.DrawCroppedTex(ref box, ref matrix);
                        }
                    }
                }
                /// <summary>
                /// Draws the text board in world space on the XY plane of the matrix, facing in the +Z
                /// direction.
                /// </summary>
                public void Draw(BoundingBox2 box, BoundingBox2 mask, MatrixD[] matrix)
                {
                    ContainmentType containment;

                    mask.Contains(ref box, out containment);

                    if (containment != ContainmentType.Disjoint)
                    {
                        if (offsetsAreStale)
                        {
                            UpdateOffsets();
                        }
                        else if (lineRangeIsStale || (endLine == -1 && lines.Count > 0))
                        {
                            UpdateLineRange();
                        }

                        if (AutoResize)
                        {
                            _textOffset = Vector2.Zero;
                        }

                        if (updateEvent && (eventTimer.ElapsedTicks / TimeSpan.TicksPerMillisecond) > 500)
                        {
                            TextChanged?.Invoke();
                            eventTimer.Restart();
                            updateEvent = false;
                        }

                        BoundingBox2 textMask = box.Intersect(mask);
                        Vector2      offset   = box.Center + _textOffset * Scale;

                        IReadOnlyList <Line> lineList = lines.PooledLines;
                        CroppedBox           bb       = default(CroppedBox);
                        bb.mask = textMask;

                        // Draw glyphs
                        for (int ln = startLine; ln <= endLine && ln < lines.Count; ln++)
                        {
                            Line line = lineList[ln];

                            for (int ch = 0; ch < line.Count; ch++)
                            {
                                GlyphLocData locData  = line.LocData[ch];
                                Vector2      halfSize = locData.bbSize * Scale * .5f,
                                             pos      = offset + locData.bbOffset * Scale;

                                bb.bounds = new BoundingBox2(pos - halfSize, pos + halfSize);
                                bb.mask.Value.Contains(ref bb.bounds, out containment);

                                if (containment == ContainmentType.Contains)
                                {
                                    line.GlyphBoards[ch].Draw(ref bb, ref matrix[0]);
                                }
                                else if (containment != ContainmentType.Disjoint)
                                {
                                    line.GlyphBoards[ch].DrawCroppedTex(ref bb, ref matrix[0]);
                                }
                            }
                        }

                        QuadBoard underlineBoard = QuadBoard.Default;

                        // Draw underlines
                        for (int n = 0; n < underlines.Count; n++)
                        {
                            Vector2 halfSize = underlines[n].size * Scale * .5f,
                                    pos      = offset + underlines[n].offset * Scale;

                            bb.bounds = new BoundingBox2(pos - halfSize, pos + halfSize);
                            bb.mask.Value.Contains(ref bb.bounds, out containment);
                            underlineBoard.bbColor = underlines[n].color;

                            if (containment == ContainmentType.Contains)
                            {
                                underlineBoard.Draw(ref bb, ref matrix[0]);
                            }
                            else if (containment != ContainmentType.Disjoint)
                            {
                                underlineBoard.DrawCropped(ref bb, ref matrix[0]);
                            }
                        }
                    }
                }