Skip to content

Commit 8621045

Browse files
committed
Merged with the mrt branch
2 parents 0fad112 + 1a6a708 commit 8621045

File tree

4 files changed

+191
-33
lines changed

4 files changed

+191
-33
lines changed

index.html

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,13 @@
99
<body>
1010
<div id="app">
1111
<div id="editor"></div>
12-
<output>
13-
<canvas id="output" width="400" height="400"></canvas>
14-
</output>
15-
<controls></controls>
12+
<divider></divider>
13+
<div id="output-and-controls">
14+
<output>
15+
<canvas id="output" width="400" height="400"></canvas>
16+
</output>
17+
<controls></controls>
18+
</div>
1619
</div>
1720
<script type="module" src="/src/main.ts"></script>
1821
</body>

src/main.ts

Lines changed: 146 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -43,19 +43,42 @@ self.MonacoEnvironment = {
4343
},
4444
}
4545

46-
const initialContent = `void ColorPass(in float r, in float g, in float b, in float p, in int width, in int height, sampler2D background, out vec4 out_color)
46+
const initialContent = `void ColorPass(
47+
in float r,
48+
in float g,
49+
in float b,
50+
in float p,
51+
in int width,
52+
in int height,
53+
sampler2D background,
54+
sampler2D tex1,
55+
sampler2D tex2,
56+
out vec4 out_color
57+
)
4758
{{
4859
vec2 complex_sqr(vec2 z) { return vec2(z[0] * z[0] - z[1] * z[1], z[1] * z[0] * 2.); }
4960
void main()
5061
{
5162
vec2 res = vec2(width, height);
63+
if (gl_FragCoord.x > res.x - 200.0 && gl_FragCoord.y > res.y - 200.0) {
64+
65+
float mult = 0.2;
66+
vec2 rel = gl_FragCoord.xy - (res - 200.0);
67+
vec2 checkerboard = round(fract(rel * mult));
68+
vec4 a = texelFetch(tex1, ivec2(rel.xy), 0);
69+
vec4 b = texelFetch(tex2, ivec2(rel.xy), 0);
70+
71+
out_color = mix(a, b, checkerboard.x * checkerboard.y);
72+
return;
73+
}
74+
5275
vec2 uv = gl_FragCoord.xy / res.xy;
5376
float i = gl_FragCoord.x;
5477
float j = gl_FragCoord.y;
5578
vec2 s = res;
5679
int n = int(s.x * 0.5);
5780
vec2 c = vec2(-0.8, cos(2. * p));
58-
vec2 z = vec2(i / float(n) - 1., j / float(n) - 1.) * 2.;
81+
vec2 z = vec2(i / float(n) - 1., j / float(n) - 1.0) * 2.;
5982
int iterations = 0;
6083
while (sqrt(dot(z, z)) < 20. && iterations < 50) {
6184
z = complex_sqr(z) + c;
@@ -80,6 +103,16 @@ void DEBUGPassUV(in int width, in int height, out vec4 out_color)
80103
}
81104
}}
82105
106+
void TwoOutputsShader(out vec4 out_color1, out vec4 out_color2)
107+
{{
108+
void main()
109+
{
110+
out_color1 = vec4(1.0f, 0.5f, 0.0f, 1.0f);
111+
out_color2 = vec4(0.0f, 0.5f, 1.0f, 1.0f);
112+
}
113+
}}
114+
115+
83116
[declaration: "smoothing"]
84117
{{
85118
float SmoothOverTime(float val, string name, float ratio = 0.95)
@@ -109,6 +142,14 @@ void RenderGraphMain()
109142
uvImage
110143
);
111144
145+
146+
Image img1 = GetImage(GetSwapchainImage().GetSize(), rgba16f);
147+
Image img2 = GetImage(GetSwapchainImage().GetSize(), rgba16f);
148+
TwoOutputsShader(
149+
img1,
150+
img2
151+
);
152+
112153
ColorPass(
113154
SliderFloat("R", 0.0f, 1.0f, 0.5f),
114155
SliderFloat("G", 0.0f, 1.0f, 0.5f),
@@ -117,6 +158,8 @@ void RenderGraphMain()
117158
sc.GetSize().x,
118159
sc.GetSize().y,
119160
uvImage,
161+
img1,
162+
img2,
120163
sc
121164
);
122165
@@ -247,7 +290,10 @@ function CreateRasterProgram(
247290
return program
248291
}
249292

250-
function InitWebGL(canvas: HTMLCanvasElement): GPUState {
293+
function InitWebGL(
294+
canvas: HTMLCanvasElement,
295+
raiseError: RaisesErrorFN
296+
): GPUState {
251297
const options = {
252298
premultipliedAlpha: true,
253299
alpha: true,
@@ -264,6 +310,15 @@ function InitWebGL(canvas: HTMLCanvasElement): GPUState {
264310
})
265311

266312
const gl = canvas.getContext("webgl2", options) as WebGL2RenderingContext
313+
314+
const extensions = ["EXT_color_buffer_float", "EXT_color_buffer_half_float"]
315+
for (const extensionName of extensions) {
316+
const extension = gl.getExtension(extensionName)
317+
if (!extension) {
318+
raiseError(`${extensionName} could not be loaded`)
319+
}
320+
}
321+
267322
// a reusable fbo
268323
const fbo = gl.createFramebuffer()
269324
if (!fbo) {
@@ -296,7 +351,10 @@ function UpdateFramegraph(
296351
}
297352

298353
for (const desc of result.shader_descs || []) {
299-
const outputs = desc.outs.map(({ name, type }) => `out ${type} ${name};\n`)
354+
const outputs = desc.outs.map(
355+
({ name, type }, index) =>
356+
`layout(location=${index}) out ${type} ${name};\n`
357+
)
300358
const uniforms = desc.uniforms.map(
301359
({ name, type }) => `uniform ${type} ${name};\n`
302360
)
@@ -342,6 +400,7 @@ function UpdateFramegraph(
342400
samplers: desc.samplers.map(({ name }) => {
343401
return gl.getUniformLocation(program, name)
344402
}),
403+
fboAttachmentIds: desc.outs.map((_, i) => gl.COLOR_ATTACHMENT0 + i),
345404
}
346405
}
347406
}
@@ -350,6 +409,42 @@ function RaiseError(err: string) {
350409
console.error("RaiseError:", err)
351410
}
352411

412+
function AttachDragger(
413+
dragEl: HTMLElement,
414+
resizeTarget: HTMLElement,
415+
cb: (rect: DOMRect) => void
416+
) {
417+
418+
const dragWidth = dragEl.getBoundingClientRect().width
419+
420+
let down = false
421+
dragEl.addEventListener(
422+
"mousedown",
423+
(e) => {
424+
down = true
425+
e.preventDefault()
426+
},
427+
{ passive: false }
428+
)
429+
window.addEventListener("mouseup", (_) => {
430+
down = false
431+
})
432+
window.addEventListener("mousemove", (e) => {
433+
const parentEl = dragEl.parentElement
434+
if (!down || !parentEl) {
435+
return
436+
}
437+
438+
const parentRect = parentEl.getBoundingClientRect()
439+
const parentLeft = parentRect.left
440+
const newWidth = e.clientX - parentLeft - dragWidth / 2
441+
resizeTarget.style.width = `${newWidth.toFixed(0)}px`
442+
resizeTarget.style.flexGrow = "0"
443+
parentRect.width = newWidth
444+
cb(parentRect)
445+
})
446+
}
447+
353448
function SliderControlCreate(
354449
name: string,
355450
value: string,
@@ -383,9 +478,10 @@ function SliderControlCreate(
383478
async function Init(
384479
editorEl: HTMLElement | null,
385480
canvasEl: HTMLElement | null,
386-
controlsEl: HTMLElement | null
481+
controlsEl: HTMLElement | null,
482+
draggerEl: HTMLElement | null
387483
) {
388-
if (!editorEl || !canvasEl || !controlsEl) {
484+
if (!editorEl || !canvasEl || !controlsEl || !draggerEl) {
389485
throw new Error("please provide an editor element and canvas element")
390486
}
391487

@@ -396,6 +492,14 @@ async function Init(
396492
throw new Error("could not initialize monaco")
397493
}
398494

495+
const editorResizeHandler = CreateEditorResizeHandler(editor, editorEl)
496+
window.addEventListener("resize", editorResizeHandler)
497+
editorResizeHandler()
498+
499+
AttachDragger(draggerEl, editorEl, (rect: DOMRect) => {
500+
editor.layout({ width: rect.width, height: rect.height })
501+
})
502+
399503
editor.focus()
400504

401505
function Control(
@@ -466,10 +570,10 @@ async function Init(
466570
control.el.innerText = value
467571
},
468572
}
469-
573+
470574
const state: State = {
471575
editor,
472-
gpu: InitWebGL(canvasEl as HTMLCanvasElement),
576+
gpu: InitWebGL(canvasEl as HTMLCanvasElement, console.error),
473577
framegraph: {
474578
passes: {},
475579
},
@@ -557,7 +661,6 @@ function ExecuteFrame(dt: number, state: State) {
557661

558662
const gpu = state.gpu
559663

560-
// TODO: fix this, position:relative causes pain w.r.t. flexbox
561664
// Ensure we're sized properly w.r.t. pixel ratio
562665
const rect = gpu.container.getBoundingClientRect()
563666
if (gpu.dims[0] !== rect.width || gpu.dims[1] !== rect.height) {
@@ -711,18 +814,23 @@ function ExecuteFrame(dt: number, state: State) {
711814
} else {
712815
// TODO: bind more than one output
713816
gl.bindFramebuffer(gl.FRAMEBUFFER, state.gpu.fbo)
714-
const target = ImageCacheGetImage(
715-
state.imageCache,
716-
invocation.color_attachments[0].id
717-
)
718-
gl.framebufferTexture2D(
719-
gl.FRAMEBUFFER,
720-
// TODO: MRT
721-
gl.COLOR_ATTACHMENT0,
722-
gl.TEXTURE_2D,
723-
target,
724-
0
725-
)
817+
for (
818+
let attachmentIndex = 0;
819+
attachmentIndex < invocation.color_attachments.length;
820+
attachmentIndex++
821+
) {
822+
const attachment = invocation.color_attachments[attachmentIndex]
823+
const target = ImageCacheGetImage(state.imageCache, attachment.id)
824+
gl.framebufferTexture2D(
825+
gl.FRAMEBUFFER,
826+
pass.fboAttachmentIds[attachmentIndex],
827+
gl.TEXTURE_2D,
828+
target,
829+
0
830+
)
831+
}
832+
// TODO: handle framebuffer completeness
833+
gl.drawBuffers(pass.fboAttachmentIds)
726834
}
727835

728836
gl.viewport(0, 0, gpu.canvas.width, gpu.canvas.height)
@@ -747,16 +855,30 @@ function InitEditor(editorEl: HTMLElement) {
747855
enabled: false,
748856
},
749857
tabSize: 2,
750-
automaticLayout: true,
858+
automaticLayout: false,
751859
theme: "vs-dark",
752-
glyphMargin: true,
860+
glyphMargin: false,
753861
})
754862

755863
return editor
756864
}
757865

866+
function CreateEditorResizeHandler(
867+
editor: monaco.editor.IStandaloneCodeEditor,
868+
editorEl: HTMLElement
869+
) {
870+
return () => {
871+
// editor.layout({ width: 0, height: 0 })
872+
window.requestAnimationFrame(() => {
873+
const { width, height } = editorEl.getBoundingClientRect()
874+
editor.layout({ width, height })
875+
})
876+
}
877+
}
878+
758879
Init(
759880
document.querySelector("#editor"),
760881
document.querySelector("output canvas"),
761-
document.querySelector("controls")
882+
document.querySelector("controls"),
883+
document.querySelector("divider")
762884
)

src/style.css

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
html, html {
1+
html,
2+
html {
23
padding: 0;
34
margin: 0;
45
height: 100%;
@@ -28,9 +29,10 @@ body {
2829
}
2930

3031
#app #editor {
31-
border-right: 1px solid #ccc;
3232
height: 100%;
33-
flex: 2;
33+
flex: 1;
34+
box-sizing: border-box;
35+
padding: 1px;
3436
}
3537

3638
#app #editor .compileErrorGlyph {
@@ -41,12 +43,42 @@ body {
4143
/* background-color: red; */
4244
}
4345

46+
#app divider {
47+
cursor: ew-resize;
48+
width: 0px;
49+
flex: 0 0 auto;
50+
padding: 0 3px;
51+
}
52+
#app divider::before {
53+
content: "";
54+
display: block;
55+
width: 1px;
56+
height: 100%;
57+
background: #AAA;
58+
margin: 0 auto;
59+
border-right: #666 1px solid;
60+
border-left: #666 1px solid;
61+
62+
}
63+
#app divider:hover::before {
64+
background: #EEE;
65+
margin: 0 auto;
66+
border-right: #666 1px solid;
67+
border-left: #666 1px solid;
68+
}
69+
70+
#app #output-and-controls {
71+
display: flex;
72+
flex-direction: column;
73+
box-sizing: border-box;
74+
flex: 1 1 auto;
75+
}
4476

4577
#app output {
4678
height: 100%;
4779
width: 100%;
4880
margin: auto;
49-
position:relative;
81+
position: relative;
5082
flex: 2;
5183
}
5284

@@ -61,7 +93,7 @@ body {
6193
}
6294

6395
#app controls control {
64-
display:block;
96+
display: block;
6597
margin-top: 1em;
6698
margin-left: 1em;
6799
}

src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export type FramegraphPass = {
1212
program: WebGLProgram
1313
uniforms: (WebGLUniformLocation | null)[]
1414
samplers: (WebGLUniformLocation | null)[]
15+
fboAttachmentIds: number[]
1516
}
1617

1718
export type FramegraphPasses = {

0 commit comments

Comments
 (0)