webgl: split vertex shaders; cut shaderEnabled; continue impl

This commit is contained in:
Zellyn Hunter 2018-05-13 22:13:01 -04:00
parent f7e6a41322
commit 54f7e05af6
1 changed files with 179 additions and 109 deletions

View File

@ -272,7 +272,7 @@ const screenEmu = (function () {
HORIZ_DISPLAY, VERT_DISPLAY);
const palVertTotal = PAL_VTOTAL;
const VERTEX_SHADER =`
const VERTEX_RENDER_SHADER =`
// an attribute will receive data from a buffer
attribute vec4 a_position;
attribute vec2 a_texCoord;
@ -285,6 +285,24 @@ void main() {
gl_Position = a_position;
v_texCoord = a_texCoord;
}
`;
const VERTEX_DISPLAY_SHADER =`
// an attribute will receive data from a buffer
attribute vec4 a_position;
attribute vec2 a_texCoord;
attribute vec2 a_texCoord2;
varying vec2 v_texCoord;
varying vec2 v_texCoord2;
// all shaders have a main function
void main() {
// gl_Position is a special variable a vertex shader
// is responsible for setting
gl_Position = a_position;
v_texCoord = a_texCoord;
v_texCoord2 = a_texCoord2;
}
`;
const COMPOSITE_SHADER = `
@ -335,6 +353,7 @@ void main(void)
precision mediump float;
varying vec2 v_texCoord;
varying vec2 v_texCoord2;
uniform sampler2D texture;
uniform vec2 textureSize;
@ -355,7 +374,7 @@ float PI = 3.14159265358979323846264;
void main(void)
{
vec2 qc = (v_texCoord - vec2(0.5, 0.5)) * barrelSize;
vec2 qc = (v_texCoord2 - vec2(0.5, 0.5)) * barrelSize;
vec2 qb = barrel * qc * dot(qc, qc);
vec2 q = v_texCoord + qb;
@ -364,7 +383,7 @@ void main(void)
float scanline = sin(PI * textureSize.y * q.y);
c *= mix(1.0, scanline * scanline, scanlineLevel);
vec3 mask = texture2D(shadowMask, (v_texCoord + qb) * shadowMaskSize).rgb;
vec3 mask = texture2D(shadowMask, (v_texCoord2 + qb) * shadowMaskSize).rgb;
c *= mix(vec3(1.0, 1.0, 1.0), mask, shadowMaskLevel);
vec2 lighting = qc * centerLighting;
@ -372,7 +391,7 @@ void main(void)
c *= luminanceGain;
vec2 qp = v_texCoord * persistenceSize + persistenceOrigin;
vec2 qp = v_texCoord2 * persistenceSize + persistenceOrigin;
c = max(c, texture2D(persistence, qp).rgb * persistenceLevel - 0.5 / 256.0);
gl_FragColor = vec4(c, 1.0);
@ -671,7 +690,6 @@ void main(void)
this.configurationChanged = true;
this.imageChanged = true;
this.shaderEnabled = true;
}
get image() {
@ -752,14 +770,15 @@ void main(void)
}
loadShaders() {
this.loadShader("COMPOSITE", COMPOSITE_SHADER);
this.loadShader("DISPLAY", DISPLAY_SHADER);
this.loadShader("RGB", RGB_SHADER);
this.loadShader("COMPOSITE", COMPOSITE_SHADER, VERTEX_RENDER_SHADER);
this.loadShader("RGB", RGB_SHADER, VERTEX_RENDER_SHADER);
this.loadShader("DISPLAY", DISPLAY_SHADER, VERTEX_DISPLAY_SHADER);
}
loadShader(name, source) {
const glVertexShader = createShader(this.gl, name, this.gl.VERTEX_SHADER, VERTEX_SHADER);
const glFragmentShader = createShader(this.gl, name, this.gl.FRAGMENT_SHADER, source);
loadShader(name, fragmentSource, vertexSource) {
const glVertexShader = createShader(this.gl, name, this.gl.VERTEX_SHADER, vertexSource);
const glFragmentShader = createShader(this.gl, name, this.gl.FRAGMENT_SHADER,
fragmentSource);
const glProgram = createProgram(this.gl, name, glVertexShader, glFragmentShader);
this.gl.deleteShader(glVertexShader);
this.gl.deleteShader(glFragmentShader);
@ -866,7 +885,8 @@ void main(void)
case "CANVAS_CXA2025AS":
return [this.shaders["COMPOSITE"], "COMPOSITE"];
}
return [null, null];
const decoder = this.display.videoDecoder;
throw new Error(`unknown displayConfiguration.videoDecoder: ${decoder}`);
}
configureShaders() {
@ -875,9 +895,6 @@ void main(void)
const [renderShader, renderShaderName] = this.getRenderShader();
const displayShader = this.shaders["DISPLAY"];
if (!renderShader || !displayShader)
return;
const isCompositeDecoder = (renderShaderName == "COMPOSITE");
// Render shader
@ -1096,8 +1113,6 @@ void main(void)
renderImage() {
const gl = this.gl;
const [renderShader, renderShaderName] = this.getRenderShader();
if (!renderShader || !this.shaderEnabled)
return;
const isCompositeDecoder = (renderShaderName == "COMPOSITE");
@ -1222,7 +1237,7 @@ void main(void)
drawDisplayCanvas() {
const gl = this.gl;
const displayShader = this.shaderEnabled ? this.shaders["DISPLAY"] : false;
const displayShader = this.shaders["DISPLAY"];
// Clear
// TODO(zellyn): uncomment
@ -1282,104 +1297,159 @@ void main(void)
let barrelTexRect;
// Render
let texture;
if (displayShader)
texture = this.textures["IMAGE_DECODED"];
else
texture = this.textures["IMAGE_IN"];
const texture = this.textures["IMAGE_DECODED"];
// Set uniforms
if (displayShader)
gl.useProgram(displayShader);
// Texture
const texSize = texture.size;
gl.uniform1i(gl.getUniformLocation(displayShader, "texture"), 0);
gl.uniform2f(gl.getUniformLocation(displayShader, "textureSize"),
texSize.width, texSize.height);
// Barrel
barrelTexRect = new Rect(-0.5, -0.5 / displayAspectRatio,
1.0, 1.0 / displayAspectRatio);
gl.uniform2f(gl.getUniformLocation(displayShader, "barrelSize"),
1, 1.0 / displayAspectRatio);
// Scanlines
const scanlineHeight = canvasVideoSize.height / this.image.height;
let scanlineLevel = this.display.displayScanlineLevel;
scanlineLevel = ((scanlineHeight > 2.5) ? scanlineLevel :
(scanlineHeight < 2) ? 0 :
(scanlineHeight - 2) / (2.5 - 2) * scanlineLevel);
gl.uniform1f(gl.getUniformLocation(displayShader, "scanlineLevel"), scanlineLevel);
// Shadow mask
let shadowMaskTexture;
let shadowMaskAspectRatio;
switch (this.display.displayShadowMask)
{
gl.useProgram(displayShader);
// Texture
const texSize = texture.size;
gl.uniform1i(gl.getUniformLocation(displayShader, "texture"), 0);
gl.uniform2f(gl.getUniformLocation(displayShader, "textureSize"),
texSize.width, texSize.height);
// Barrel
barrelTexRect = new Rect(-0.5, -0.5 / displayAspectRatio,
1.0, 1.0 / displayAspectRatio);
gl.uniform2f(gl.getUniformLocation(displayShader, "barrelSize"),
1, 1.0 / displayAspectRatio);
// Scanlines
const scanlineHeight = canvasVideoSize.height / this.image.height;
let scanlineLevel = this.display.displayScanlineLevel;
scanlineLevel = ((scanlineHeight > 2.5) ? scanlineLevel :
(scanlineHeight < 2) ? 0 :
(scanlineHeight - 2) / (2.5 - 2) * scanlineLevel);
gl.uniform1f(gl.getUniformLocation(displayShader, "scanlineLevel"), scanlineLevel);
// Shadow mask
let shadowMaskTexture;
let shadowMaskAspectRatio;
switch (this.display.displayShadowMask)
{
case "SHADOWMASK_TRIAD":
shadowMaskTexture = this.textures["SHADOWMASK_TRIAD"];
shadowMaskAspectRatio = 2 / (274.0 / 240.0);
break;
case "SHADOWMASK_INLINE":
shadowMaskTexture = this.textures["SHADOWMASK_INLINE"];
shadowMaskAspectRatio = 2;
break;
case "SHADOWMASK_APERTURE":
shadowMaskTexture = this.textures["SHADOWMASK_APERTURE"];
shadowMaskAspectRatio = 2;
break;
case "SHADOWMASK_LCD":
shadowMaskTexture = this.textures["SHADOWMASK_LCD"];
shadowMaskAspectRatio = 2;
break;
case "SHADOWMASK_BAYER":
shadowMaskTexture = this.textures["SHADOWMASK_BAYER"];
shadowMaskAspectRatio = 2;
case "SHADOWMASK_TRIAD":
shadowMaskTexture = this.textures["SHADOWMASK_TRIAD"];
shadowMaskAspectRatio = 2 / (274.0 / 240.0);
break;
}
const shadowMaskDotPitch = this.display.displayShadowMaskDotPitch;
if (shadowMaskDotPitch <= 0.001)
shadowMaskDotPitch = 0.001;
const shadowMaskElemX = (displayResolution.width /
this.display.displayPixelDensity *
25.4 * 0.5 / shadowMaskDotPitch);
const shadowMaskSize = new Size(shadowMaskElemX,
shadowMaskElemX * shadowMaskAspectRatio /
displayAspectRatio);
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, shadowMaskTexture.glTexture);
gl.uniform2f(gl.getUniformLocation(displayShader, "shadowMaskSize"),
shadowMaskSize.width, shadowMaskSize.height);
// Persistence
gl.activeTexture(gl.TEXTURE2);
gl.bindTexture(gl.TEXTURE_2D, this.textures["IMAGE_PERSISTENCE"].glTexture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.activeTexture(gl.TEXTURE0);
gl.uniform1i(gl.getUniformLocation(displayShader, "persistence"), 2);
gl.uniform2f(gl.getUniformLocation(displayShader, "persistenceOrigin"),
this.persistenceTexRect.x, this.persistenceTexRect.y);
gl.uniform2f(gl.getUniformLocation(displayShader, "persistenceSize"),
this.persistenceTexRect.width, this.persistenceTexRect.height);
case "SHADOWMASK_INLINE":
shadowMaskTexture = this.textures["SHADOWMASK_INLINE"];
shadowMaskAspectRatio = 2;
break;
case "SHADOWMASK_APERTURE":
shadowMaskTexture = this.textures["SHADOWMASK_APERTURE"];
shadowMaskAspectRatio = 2;
break;
case "SHADOWMASK_LCD":
shadowMaskTexture = this.textures["SHADOWMASK_LCD"];
shadowMaskAspectRatio = 2;
break;
case "SHADOWMASK_BAYER":
shadowMaskTexture = this.textures["SHADOWMASK_BAYER"];
shadowMaskAspectRatio = 2;
break;
}
const shadowMaskDotPitch = this.display.displayShadowMaskDotPitch;
if (shadowMaskDotPitch <= 0.001)
shadowMaskDotPitch = 0.001;
const shadowMaskElemX = (displayResolution.width /
this.display.displayPixelDensity *
25.4 * 0.5 / shadowMaskDotPitch);
const shadowMaskSize = new Size(shadowMaskElemX,
shadowMaskElemX * shadowMaskAspectRatio /
displayAspectRatio);
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, shadowMaskTexture.glTexture);
gl.uniform2f(gl.getUniformLocation(displayShader, "shadowMaskSize"),
shadowMaskSize.width, shadowMaskSize.height);
// Persistence
gl.activeTexture(gl.TEXTURE2);
gl.bindTexture(gl.TEXTURE_2D, this.textures["IMAGE_PERSISTENCE"].glTexture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.activeTexture(gl.TEXTURE0);
gl.uniform1i(gl.getUniformLocation(displayShader, "persistence"), 2);
gl.uniform2f(gl.getUniformLocation(displayShader, "persistenceOrigin"),
this.persistenceTexRect.x, this.persistenceTexRect.y);
gl.uniform2f(gl.getUniformLocation(displayShader, "persistenceSize"),
this.persistenceTexRect.width, this.persistenceTexRect.height);
// Old fixed pipeline stuff.
// gl.loadIdentity();
// gl.rotatef(180, 1, 0, 0);
gl.bindTexture(gl.TEXTURE_2D, texture.glTexture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
// TODO(zellyn): implement
// zjh:begin
/*
// Render
gl.begin(gl.QUADS);
gl.texCoord2f(OEMinX(canvasTexRect), OEMinY(canvasTexRect));
gl.multiTexCoord2d(1, OEMinX(baseTexRect), OEMinY(baseTexRect));
gl.vertex2f(OEMinX(vertexRect), OEMinY(vertexRect));
gl.texCoord2f(OEMaxX(canvasTexRect), OEMinY(canvasTexRect));
gl.multiTexCoord2d(1, OEMaxX(baseTexRect), OEMinY(baseTexRect));
gl.vertex2f(OEMaxX(vertexRect), OEMinY(vertexRect));
gl.texCoord2f(OEMaxX(canvasTexRect), OEMaxY(canvasTexRect));
gl.multiTexCoord2d(1, OEMaxX(baseTexRect), OEMaxY(baseTexRect));
gl.vertex2f(OEMaxX(vertexRect), OEMaxY(vertexRect));
gl.texCoord2f(OEMinX(canvasTexRect), OEMaxY(canvasTexRect));
gl.multiTexCoord2d(1, OEMinX(baseTexRect), OEMaxY(baseTexRect));
gl.vertex2f(OEMinX(vertexRect), OEMaxY(vertexRect));
gl.end();
if (displayConfiguration.displayPersistence != 0.0)
{
updateTextureSize(OPENGLCANVAS_IMAGE_PERSISTENCE, viewportSize);
gl.bindTexture(gl.TEXTURE_2D, texture[OPENGLCANVAS_IMAGE_PERSISTENCE]);
gl.readBuffer(gl.BACK);
gl.copyTexSubImage2D(gl.TEXTURE_2D, 0,
0, 0, 0, 0,
viewportSize.width, viewportSize.height);
OESize persistenceTexSize = OEMakeSize(viewportSize.width /
textureSize[OPENGLCANVAS_IMAGE_PERSISTENCE].width,
viewportSize.height /
textureSize[OPENGLCANVAS_IMAGE_PERSISTENCE].height);
persistenceTexRect = OEMakeRect((vertexRect.origin.x + 1) * 0.5F * persistenceTexSize.width,
(vertexRect.origin.y + 1) * 0.5F * persistenceTexSize.height,
vertexRect.size.width * 0.5F * persistenceTexSize.width,
vertexRect.size.height * 0.5F * persistenceTexSize.height);
persistenceTexRect.origin.y += persistenceTexRect.size.height;
persistenceTexRect.size.height = -persistenceTexRect.size.height;
}
gl.useProgram(0);
// zjh:end
*/
}
getDisplayCanvasTexPoint(p) {