• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

excaliburjs / Excalibur / 19716357641

26 Nov 2025 08:18PM UTC coverage: 88.641% (+0.07%) from 88.576%
19716357641

Pull #3585

github

web-flow
Merge 7d0f94fd5 into 3b683c589
Pull Request #3585: feat!: debug draw improvements

5289 of 7219 branches covered (73.26%)

280 of 306 new or added lines in 18 files covered. (91.5%)

4 existing lines in 2 files now uncovered.

14655 of 16533 relevant lines covered (88.64%)

24567.88 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.91
/src/engine/Graphics/Context/debug-line-renderer/debug-line-renderer.ts
1
import type { Vector } from '../../../Math/vector';
2
import { vec } from '../../../Math/vector';
3
import type { Color } from '../../../Color';
4
import lineVertexSource from './debug-line-vertex.glsl?raw';
5
import lineFragmentSource from './debug-line-fragment.glsl?raw';
6
import type { ExcaliburGraphicsContextWebGL } from '../ExcaliburGraphicsContextWebGL';
7
import type { RendererPlugin } from '../renderer';
8
import { Shader, VertexBuffer, VertexLayout } from '../..';
9
import { GraphicsDiagnostics } from '../../GraphicsDiagnostics';
10

11
export class DebugLineRenderer implements RendererPlugin {
12
  public readonly type = 'ex.debug-line';
12✔
13
  public priority: number = 0;
12✔
14
  private _context!: ExcaliburGraphicsContextWebGL;
15
  private _gl!: WebGL2RenderingContext;
16
  private _shader!: Shader;
17
  private _maxLines: number = 10922;
12✔
18
  private _vertexBuffer!: VertexBuffer;
19
  private _layout!: VertexLayout;
20
  private _vertexIndex = 0;
12✔
21
  private _lineCount = 0;
12✔
22
  initialize(gl: WebGL2RenderingContext, context: ExcaliburGraphicsContextWebGL): void {
23
    this._gl = gl;
12✔
24
    this._context = context;
12✔
25
    this._shader = new Shader({
12✔
26
      graphicsContext: context,
27
      vertexSource: lineVertexSource,
28
      fragmentSource: lineFragmentSource
29
    });
30
    this._shader.compile();
12✔
31
    this._shader.use();
12✔
32

33
    this._shader.setUniformMatrix('u_matrix', this._context.ortho);
12✔
34

35
    this._vertexBuffer = new VertexBuffer({
12✔
36
      gl,
37
      size: 7 * 6 * this._maxLines, // 7 floats per vert, 6 verts per line
38
      type: 'dynamic'
39
    });
40

41
    this._layout = new VertexLayout({
12✔
42
      gl,
43
      vertexBuffer: this._vertexBuffer,
44
      shader: this._shader,
45
      attributes: [
46
        ['a_position', 2],
47
        ['a_color', 4],
48
        ['a_lengthSoFar', 1]
49
      ]
50
    });
51
  }
52

53
  public dispose() {
54
    this._vertexBuffer.dispose();
12✔
55
    this._shader.dispose();
12✔
56
    this._context = null as any;
12✔
57
    this._gl = null as any;
12✔
58
  }
59

60
  private _startScratch = vec(0, 0);
12✔
61
  private _endScratch = vec(0, 0);
12✔
62
  private _lengthSoFar = 0;
12✔
63
  private _currentlyDashed = false;
12✔
64
  draw(start: Vector, end: Vector, color: Color, width = 2, dashed: boolean = false): void {
889✔
65
    // Force a render if the batch is full or we switch form dashed -> not dashed or vice versa
66
    if (this._isFull() || this._currentlyDashed !== dashed) {
471✔
67
      this._currentlyDashed = dashed;
2✔
68
      this.flush();
2✔
69
    }
70

71
    this._lineCount++;
471✔
72

73
    const transform = this._context.getTransform();
471✔
74
    const finalStart = transform.multiply(start, this._startScratch);
471✔
75
    const finalEnd = transform.multiply(end, this._endScratch);
471✔
76

77
    const dir = finalEnd.sub(finalStart);
471✔
78
    const dist = finalStart.distance(finalEnd);
471✔
79
    const normal = dir.normal();
471✔
80
    const halfWidth = width / 2;
471✔
81

82
    const vertexBuffer = this._vertexBuffer.bufferData;
471✔
83
    // Start Bottom Vert
84
    vertexBuffer[this._vertexIndex++] = finalStart.x - normal.x * halfWidth;
471✔
85
    vertexBuffer[this._vertexIndex++] = finalStart.y - normal.y * halfWidth;
471✔
86
    vertexBuffer[this._vertexIndex++] = color.r / 255;
471✔
87
    vertexBuffer[this._vertexIndex++] = color.g / 255;
471✔
88
    vertexBuffer[this._vertexIndex++] = color.b / 255;
471✔
89
    vertexBuffer[this._vertexIndex++] = color.a;
471✔
90
    vertexBuffer[this._vertexIndex++] = this._lengthSoFar;
471✔
91

92
    // Start Top Vert
93
    vertexBuffer[this._vertexIndex++] = finalStart.x + normal.x * halfWidth;
471✔
94
    vertexBuffer[this._vertexIndex++] = finalStart.y + normal.y * halfWidth;
471✔
95
    vertexBuffer[this._vertexIndex++] = color.r / 255;
471✔
96
    vertexBuffer[this._vertexIndex++] = color.g / 255;
471✔
97
    vertexBuffer[this._vertexIndex++] = color.b / 255;
471✔
98
    vertexBuffer[this._vertexIndex++] = color.a;
471✔
99
    vertexBuffer[this._vertexIndex++] = this._lengthSoFar;
471✔
100

101
    // End Bottom Vert
102
    vertexBuffer[this._vertexIndex++] = finalEnd.x - normal.x * halfWidth;
471✔
103
    vertexBuffer[this._vertexIndex++] = finalEnd.y - normal.y * halfWidth;
471✔
104
    vertexBuffer[this._vertexIndex++] = color.r / 255;
471✔
105
    vertexBuffer[this._vertexIndex++] = color.g / 255;
471✔
106
    vertexBuffer[this._vertexIndex++] = color.b / 255;
471✔
107
    vertexBuffer[this._vertexIndex++] = color.a;
471✔
108
    vertexBuffer[this._vertexIndex++] = this._lengthSoFar + dist;
471✔
109

110
    // End Bottom Vert
111
    vertexBuffer[this._vertexIndex++] = finalEnd.x - normal.x * halfWidth;
471✔
112
    vertexBuffer[this._vertexIndex++] = finalEnd.y - normal.y * halfWidth;
471✔
113
    vertexBuffer[this._vertexIndex++] = color.r / 255;
471✔
114
    vertexBuffer[this._vertexIndex++] = color.g / 255;
471✔
115
    vertexBuffer[this._vertexIndex++] = color.b / 255;
471✔
116
    vertexBuffer[this._vertexIndex++] = color.a;
471✔
117
    vertexBuffer[this._vertexIndex++] = this._lengthSoFar + dist;
471✔
118

119
    // Start Top Vert
120
    vertexBuffer[this._vertexIndex++] = finalStart.x + normal.x * halfWidth;
471✔
121
    vertexBuffer[this._vertexIndex++] = finalStart.y + normal.y * halfWidth;
471✔
122
    vertexBuffer[this._vertexIndex++] = color.r / 255;
471✔
123
    vertexBuffer[this._vertexIndex++] = color.g / 255;
471✔
124
    vertexBuffer[this._vertexIndex++] = color.b / 255;
471✔
125
    vertexBuffer[this._vertexIndex++] = color.a;
471✔
126
    vertexBuffer[this._vertexIndex++] = this._lengthSoFar;
471✔
127

128
    // End Top Vert
129
    vertexBuffer[this._vertexIndex++] = finalEnd.x + normal.x * halfWidth;
471✔
130
    vertexBuffer[this._vertexIndex++] = finalEnd.y + normal.y * halfWidth;
471✔
131
    vertexBuffer[this._vertexIndex++] = color.r / 255;
471✔
132
    vertexBuffer[this._vertexIndex++] = color.g / 255;
471✔
133
    vertexBuffer[this._vertexIndex++] = color.b / 255;
471✔
134
    vertexBuffer[this._vertexIndex++] = color.a;
471✔
135
    vertexBuffer[this._vertexIndex++] = this._lengthSoFar + dist;
471✔
136
  }
137

138
  private _isFull() {
139
    if (this._lineCount >= this._maxLines) {
471!
NEW
140
      return true;
×
141
    }
142
    return false;
471✔
143
  }
144

145
  hasPendingDraws(): boolean {
146
    return this._lineCount !== 0;
8✔
147
  }
148

149
  flush(): void {
150
    // nothing to draw early exit
151
    if (this._lineCount === 0) {
14✔
152
      return;
2✔
153
    }
154

155
    const gl = this._gl;
12✔
156
    this._shader.use();
12✔
157
    this._layout.use(true);
12✔
158

159
    this._shader.setUniformMatrix('u_matrix', this._context.ortho);
12✔
160
    this._shader.setUniformBoolean('u_dashed', this._currentlyDashed);
12✔
161

162
    gl.drawArrays(gl.TRIANGLES, 0, this._lineCount * 6); // 6 verts per line
12✔
163

164
    GraphicsDiagnostics.DrawnImagesCount += this._lineCount;
12✔
165
    GraphicsDiagnostics.DrawCallCount++;
12✔
166

167
    // reset
168
    this._vertexIndex = 0;
12✔
169
    this._lineCount = 0;
12✔
170
    this._lengthSoFar = 0;
12✔
171
  }
172
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc