From af9783c838a03b54fa6a58d0ae3c739cce20aa17 Mon Sep 17 00:00:00 2001 From: Jamie Wong Date: Wed, 22 Nov 2017 19:19:10 -0800 Subject: [PATCH] Batch rectangle renderer with regl --- flamechart.ts | 76 +++++++++++++++++++++++++++++++++++++++++++++++ index.tsx | 51 ++++++++++++++++++++++++++++++- package-lock.json | 5 ++++ package.json | 3 ++ regl.d.ts | 51 +++++++++++++++++++++++++++++++ 5 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 regl.d.ts diff --git a/flamechart.ts b/flamechart.ts index 93884a7..11ef3c5 100644 --- a/flamechart.ts +++ b/flamechart.ts @@ -1,4 +1,5 @@ import {Profile, Frame} from './profile' +import regl, {ReglCommandConstructor} from 'regl' interface FlamechartFrame { frame: Frame @@ -49,4 +50,79 @@ export class Flamechart { profile.forEachSample(this.appendSample.bind(this)) this.layers = this.layers.map(Flamechart.mergeAdjacentFrames) } +} + +interface Rect { + left: number + top: number + width: number + height: number +} + +type vec2 = [number, number] +type vec3 = [number, number, number] +type mat3 = [number, number, number, number, number, number, number, number, number] + +export const rectangleBatchRenderer = (ctx: WebGLRenderingContext, rects: Rect[], colors: vec3[]) => { + const gl = regl(ctx) + + const positions: vec2[] = [] + const vertexColors: vec3[] = [] + + const addRectangle = (r: Rect, color: [number, number, number]) => { + const NW: [number, number] = [r.left, r.top] + const NE: [number, number] = [r.left + r.width, r.top] + const SW: [number, number] = [r.left, r.top + r.height] + const SE: [number, number] = [r.left + r.width, r.top + r.height] + + positions.push(NW) + positions.push(SW) + positions.push(NE) + + positions.push(SW) + positions.push(NE) + positions.push(SE) + + for (let i = 0; i < 6; i++) vertexColors.push(color) + } + + for (let i = 0; i < rects.length; i++) addRectangle(rects[i], colors[i]) + + return gl<{ + configSpaceToNDC: mat3 + }>({ + vert: ` + uniform mat3 configSpaceToNDC; + attribute vec2 position; + attribute vec3 color; + varying vec3 vColor; + void main() { + vColor = color; + gl_Position = vec4((configSpaceToNDC * vec3(position, 1)).xy, 0, 1); + } + `, + + frag: ` + precision mediump float; + varying vec3 vColor; + void main() { + gl_FragColor = vec4(vColor, 1); + } + `, + + attributes: { + position: positions, + color: vertexColors + }, + + uniforms: { + configSpaceToNDC: (context, props) => { + return props.configSpaceToNDC + } + }, + + primitive: 'triangles', + + count: colors.length + }) } \ No newline at end of file diff --git a/index.tsx b/index.tsx index 58a3a28..26c7c49 100644 --- a/index.tsx +++ b/index.tsx @@ -2,6 +2,53 @@ import {h, render, Component} from 'preact' import {StyleSheet, css} from 'aphrodite' import {importFromStackprof} from './stackprof' +import {Flamechart, rectangleBatchRenderer} from './flamechart' + +import { request } from 'https'; + +interface Rect { + left: number + top: number + width: number + height: number +} + +class Canvas extends Component<{}, void> { + canvasRef = (element?: Element) => { + if (element) { + const rectangles: Rect[] = [] + const colors: [number, number, number][] = [] + + for (let i = 0; i < 1000; i++) { + rectangles.push({ + left: 2 * Math.random() - 1, + top: 2 * Math.random() - 1, + width: 2 * Math.random(), + height: 2 * Math.random(), + }) + colors.push([Math.random(), Math.random(), Math.random()]) + } + const renderer = rectangleBatchRenderer((element as HTMLCanvasElement).getContext('webgl')!, rectangles, colors) + + ;(function doit() { + renderer({ + configSpaceToNDC: [ + 1, 0, 0, + 0, 1, 0, + 0, 0, 1, + ] + }) + requestAnimationFrame(doit) + })() + } + } + + render() { + const width = window.innerWidth + const height = window.innerHeight + return + } +} class Application extends Component<{}, void> { onDrop = (ev: DragEvent) => { @@ -19,6 +66,7 @@ class Application extends Component<{}, void> { render() { return
+
} } @@ -26,7 +74,8 @@ class Application extends Component<{}, void> { const style = StyleSheet.create({ root: { width: '100vw', - height: '100vw' + height: '100vh', + overflow: 'hidden' } }) diff --git a/package-lock.json b/package-lock.json index f4a2d27..1821ef9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -628,6 +628,11 @@ "is-equal-shallow": "0.1.3" } }, + "regl": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/regl/-/regl-1.3.0.tgz", + "integrity": "sha1-zN6C7/iooGilWVgc6svvGv6njr0=" + }, "remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", diff --git a/package.json b/package.json index 8ec00a1..d8e6d1e 100644 --- a/package.json +++ b/package.json @@ -23,5 +23,8 @@ "rollup-plugin-replace": "^2.0.0", "rollup-plugin-typescript": "^0.8.1", "typescript": "^2.6.1" + }, + "dependencies": { + "regl": "^1.3.0" } } diff --git a/regl.d.ts b/regl.d.ts new file mode 100644 index 0000000..e9e756d --- /dev/null +++ b/regl.d.ts @@ -0,0 +1,51 @@ +declare module "regl" { + interface ReglProp {} + + type ReglPrimitiveValue = + boolean | + number | + number[] | + number[][] | + ReglProp + + type ReglValue

= ReglPrimitiveValue | {(context: any, props: P, batchId: number): ReglPrimitiveValue} + + interface ReglCommandParameters

{ + /** Source code of vertex shader */ + vert: string + + /** Source code of fragment shader */ + frag: string + + attributes: {[attributeName: string]: ReglValue

} + + uniforms: {[uniformName: string]: ReglValue

} + + /** Number of vertices to draw */ + count: number + + /** */ + primitive?: 'points' | 'lines' | 'line strip' | 'triangles' | 'triangle strip' | 'triangle fan' + + /** Offset of primitives to draw */ + offset?: number + } + + interface ReglCommand

{ + (p: P): void + } + + export interface ReglCommandConstructor { +

(params: ReglCommandParameters

): ReglCommand

+ } + + function ReglConstructor(): ReglCommandConstructor + function ReglConstructor(ctx: WebGLRenderingContext): ReglCommandConstructor + function ReglConstructor(canvas: HTMLCanvasElement): ReglCommandConstructor + + namespace ReglConstructor { + function prop(name: string): ReglProp + } + + export default ReglConstructor +}