@JustinBeckwith pointed out in #262 that `npm install` was broken in node 13.x, and @DanielRuf pointed in #254 that test fail for node 11+ because of a change to stability of sorting. This PR seeks to address both of those. The installation issue was fixed by just regenerating `package-lock.json` without needing to bump any of the direct dependency versions. The test failure issue requires manual intervention. To fix the sort stability issue, I updated the tests to use the stable sort values (these were all the correct values, though some of the test values were incorrect). To make the suite still pass for node 10, I added a hack where I override `Array.prototype.sort` with a stable implementation that's *only* used in tests (See comments in code for a justification for why) ## Test Plan Before this PR: `npm install` on node 13.x fails & `npm run jest` results in test failures After this PR: `npm install` on node 13.x passes & `npm run jest` passes for node 10, 12, and 13.
143 lines
3.6 KiB
TypeScript
143 lines
3.6 KiB
TypeScript
import {Rect, Vec2, AffineTransform} from '../lib/math'
|
|
import {Color} from '../lib/color'
|
|
import {Graphics} from './graphics'
|
|
import {setUniformAffineTransform} from './utils'
|
|
|
|
const vertexFormat = new Graphics.VertexFormat()
|
|
vertexFormat.add('configSpacePos', Graphics.AttributeType.FLOAT, 2)
|
|
vertexFormat.add('color', Graphics.AttributeType.FLOAT, 3)
|
|
|
|
const vert = `
|
|
uniform mat3 configSpaceToNDC;
|
|
|
|
attribute vec2 configSpacePos;
|
|
attribute vec3 color;
|
|
varying vec3 vColor;
|
|
|
|
void main() {
|
|
vColor = color;
|
|
vec2 position = (configSpaceToNDC * vec3(configSpacePos, 1)).xy;
|
|
gl_Position = vec4(position, 1, 1);
|
|
}
|
|
`
|
|
|
|
const frag = `
|
|
precision mediump float;
|
|
varying vec3 vColor;
|
|
|
|
void main() {
|
|
gl_FragColor = vec4(vColor.rgb, 1);
|
|
}
|
|
`
|
|
|
|
export class RectangleBatch {
|
|
private rects: Rect[] = []
|
|
private colors: Color[] = []
|
|
constructor(private gl: Graphics.Context) {}
|
|
|
|
getRectCount() {
|
|
return this.rects.length
|
|
}
|
|
|
|
private buffer: Graphics.VertexBuffer | null = null
|
|
getBuffer(): Graphics.VertexBuffer {
|
|
if (this.buffer) {
|
|
return this.buffer
|
|
}
|
|
|
|
const corners = [
|
|
[0, 0],
|
|
[1, 0],
|
|
[0, 1],
|
|
[1, 0],
|
|
[0, 1],
|
|
[1, 1],
|
|
]
|
|
|
|
const bytes = new Uint8Array(vertexFormat.stride * corners.length * this.rects.length)
|
|
const floats = new Float32Array(bytes.buffer)
|
|
let idx = 0
|
|
|
|
for (let i = 0; i < this.rects.length; i++) {
|
|
const rect = this.rects[i]
|
|
const color = this.colors[i]
|
|
|
|
// TODO(jlfwong): In the conversion from regl to graphics.ts, I lost the
|
|
// ability to do instanced drawing. This is a pretty significant hit to
|
|
// the performance here since I need 6x the memory to allocate these
|
|
// things. Adding instanced drawing to graphics.ts is non-trivial, so I'm
|
|
// just going to try this for now.
|
|
for (let corner of corners) {
|
|
floats[idx++] = rect.origin.x + corner[0] * rect.size.x
|
|
floats[idx++] = rect.origin.y + corner[1] * rect.size.y
|
|
|
|
floats[idx++] = color.r
|
|
floats[idx++] = color.g
|
|
floats[idx++] = color.b
|
|
}
|
|
}
|
|
|
|
if (idx !== floats.length) {
|
|
throw new Error("Buffer expected to be full but wasn't")
|
|
}
|
|
|
|
this.buffer = this.gl.createVertexBuffer(bytes.length)
|
|
this.buffer.upload(bytes)
|
|
return this.buffer
|
|
}
|
|
|
|
addRect(rect: Rect, color: Color) {
|
|
this.rects.push(rect)
|
|
this.colors.push(color)
|
|
|
|
if (this.buffer) {
|
|
this.buffer.free()
|
|
this.buffer = null
|
|
}
|
|
}
|
|
|
|
free() {
|
|
if (this.buffer) {
|
|
this.buffer.free()
|
|
this.buffer = null
|
|
}
|
|
}
|
|
}
|
|
|
|
export interface RectangleBatchRendererProps {
|
|
batch: RectangleBatch
|
|
configSpaceSrcRect: Rect
|
|
physicalSpaceDstRect: Rect
|
|
}
|
|
|
|
export class RectangleBatchRenderer {
|
|
material: Graphics.Material
|
|
constructor(private gl: Graphics.Context) {
|
|
this.material = gl.createMaterial(vertexFormat, vert, frag)
|
|
}
|
|
|
|
render(props: RectangleBatchRendererProps) {
|
|
setUniformAffineTransform(
|
|
this.material,
|
|
'configSpaceToNDC',
|
|
(() => {
|
|
const configToPhysical = AffineTransform.betweenRects(
|
|
props.configSpaceSrcRect,
|
|
props.physicalSpaceDstRect,
|
|
)
|
|
|
|
const viewportSize = new Vec2(this.gl.viewport.width, this.gl.viewport.height)
|
|
|
|
const physicalToNDC = AffineTransform.withTranslation(new Vec2(-1, 1)).times(
|
|
AffineTransform.withScale(new Vec2(2, -2).dividedByPointwise(viewportSize)),
|
|
)
|
|
|
|
return physicalToNDC.times(configToPhysical)
|
|
})(),
|
|
)
|
|
|
|
this.gl.setUnpremultipliedBlendState()
|
|
this.gl.draw(Graphics.Primitive.TRIANGLES, this.material, props.batch.getBuffer())
|
|
}
|
|
}
|