webgl: split vertex shaders; cut shaderEnabled; continue impl
This commit is contained in:
parent
f7e6a41322
commit
54f7e05af6
288
screenEmu.js
288
screenEmu.js
|
@ -272,7 +272,7 @@ const screenEmu = (function () {
|
||||||
HORIZ_DISPLAY, VERT_DISPLAY);
|
HORIZ_DISPLAY, VERT_DISPLAY);
|
||||||
const palVertTotal = PAL_VTOTAL;
|
const palVertTotal = PAL_VTOTAL;
|
||||||
|
|
||||||
const VERTEX_SHADER =`
|
const VERTEX_RENDER_SHADER =`
|
||||||
// an attribute will receive data from a buffer
|
// an attribute will receive data from a buffer
|
||||||
attribute vec4 a_position;
|
attribute vec4 a_position;
|
||||||
attribute vec2 a_texCoord;
|
attribute vec2 a_texCoord;
|
||||||
|
@ -285,6 +285,24 @@ void main() {
|
||||||
gl_Position = a_position;
|
gl_Position = a_position;
|
||||||
v_texCoord = a_texCoord;
|
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 = `
|
const COMPOSITE_SHADER = `
|
||||||
|
@ -335,6 +353,7 @@ void main(void)
|
||||||
precision mediump float;
|
precision mediump float;
|
||||||
|
|
||||||
varying vec2 v_texCoord;
|
varying vec2 v_texCoord;
|
||||||
|
varying vec2 v_texCoord2;
|
||||||
|
|
||||||
uniform sampler2D texture;
|
uniform sampler2D texture;
|
||||||
uniform vec2 textureSize;
|
uniform vec2 textureSize;
|
||||||
|
@ -355,7 +374,7 @@ float PI = 3.14159265358979323846264;
|
||||||
|
|
||||||
void main(void)
|
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 qb = barrel * qc * dot(qc, qc);
|
||||||
vec2 q = v_texCoord + qb;
|
vec2 q = v_texCoord + qb;
|
||||||
|
|
||||||
|
@ -364,7 +383,7 @@ void main(void)
|
||||||
float scanline = sin(PI * textureSize.y * q.y);
|
float scanline = sin(PI * textureSize.y * q.y);
|
||||||
c *= mix(1.0, scanline * scanline, scanlineLevel);
|
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);
|
c *= mix(vec3(1.0, 1.0, 1.0), mask, shadowMaskLevel);
|
||||||
|
|
||||||
vec2 lighting = qc * centerLighting;
|
vec2 lighting = qc * centerLighting;
|
||||||
|
@ -372,7 +391,7 @@ void main(void)
|
||||||
|
|
||||||
c *= luminanceGain;
|
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);
|
c = max(c, texture2D(persistence, qp).rgb * persistenceLevel - 0.5 / 256.0);
|
||||||
|
|
||||||
gl_FragColor = vec4(c, 1.0);
|
gl_FragColor = vec4(c, 1.0);
|
||||||
|
@ -671,7 +690,6 @@ void main(void)
|
||||||
|
|
||||||
this.configurationChanged = true;
|
this.configurationChanged = true;
|
||||||
this.imageChanged = true;
|
this.imageChanged = true;
|
||||||
this.shaderEnabled = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get image() {
|
get image() {
|
||||||
|
@ -752,14 +770,15 @@ void main(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
loadShaders() {
|
loadShaders() {
|
||||||
this.loadShader("COMPOSITE", COMPOSITE_SHADER);
|
this.loadShader("COMPOSITE", COMPOSITE_SHADER, VERTEX_RENDER_SHADER);
|
||||||
this.loadShader("DISPLAY", DISPLAY_SHADER);
|
this.loadShader("RGB", RGB_SHADER, VERTEX_RENDER_SHADER);
|
||||||
this.loadShader("RGB", RGB_SHADER);
|
this.loadShader("DISPLAY", DISPLAY_SHADER, VERTEX_DISPLAY_SHADER);
|
||||||
}
|
}
|
||||||
|
|
||||||
loadShader(name, source) {
|
loadShader(name, fragmentSource, vertexSource) {
|
||||||
const glVertexShader = createShader(this.gl, name, this.gl.VERTEX_SHADER, VERTEX_SHADER);
|
const glVertexShader = createShader(this.gl, name, this.gl.VERTEX_SHADER, vertexSource);
|
||||||
const glFragmentShader = createShader(this.gl, name, this.gl.FRAGMENT_SHADER, source);
|
const glFragmentShader = createShader(this.gl, name, this.gl.FRAGMENT_SHADER,
|
||||||
|
fragmentSource);
|
||||||
const glProgram = createProgram(this.gl, name, glVertexShader, glFragmentShader);
|
const glProgram = createProgram(this.gl, name, glVertexShader, glFragmentShader);
|
||||||
this.gl.deleteShader(glVertexShader);
|
this.gl.deleteShader(glVertexShader);
|
||||||
this.gl.deleteShader(glFragmentShader);
|
this.gl.deleteShader(glFragmentShader);
|
||||||
|
@ -866,7 +885,8 @@ void main(void)
|
||||||
case "CANVAS_CXA2025AS":
|
case "CANVAS_CXA2025AS":
|
||||||
return [this.shaders["COMPOSITE"], "COMPOSITE"];
|
return [this.shaders["COMPOSITE"], "COMPOSITE"];
|
||||||
}
|
}
|
||||||
return [null, null];
|
const decoder = this.display.videoDecoder;
|
||||||
|
throw new Error(`unknown displayConfiguration.videoDecoder: ${decoder}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
configureShaders() {
|
configureShaders() {
|
||||||
|
@ -875,9 +895,6 @@ void main(void)
|
||||||
const [renderShader, renderShaderName] = this.getRenderShader();
|
const [renderShader, renderShaderName] = this.getRenderShader();
|
||||||
const displayShader = this.shaders["DISPLAY"];
|
const displayShader = this.shaders["DISPLAY"];
|
||||||
|
|
||||||
if (!renderShader || !displayShader)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const isCompositeDecoder = (renderShaderName == "COMPOSITE");
|
const isCompositeDecoder = (renderShaderName == "COMPOSITE");
|
||||||
|
|
||||||
// Render shader
|
// Render shader
|
||||||
|
@ -1096,8 +1113,6 @@ void main(void)
|
||||||
renderImage() {
|
renderImage() {
|
||||||
const gl = this.gl;
|
const gl = this.gl;
|
||||||
const [renderShader, renderShaderName] = this.getRenderShader();
|
const [renderShader, renderShaderName] = this.getRenderShader();
|
||||||
if (!renderShader || !this.shaderEnabled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const isCompositeDecoder = (renderShaderName == "COMPOSITE");
|
const isCompositeDecoder = (renderShaderName == "COMPOSITE");
|
||||||
|
|
||||||
|
@ -1222,7 +1237,7 @@ void main(void)
|
||||||
drawDisplayCanvas() {
|
drawDisplayCanvas() {
|
||||||
const gl = this.gl;
|
const gl = this.gl;
|
||||||
|
|
||||||
const displayShader = this.shaderEnabled ? this.shaders["DISPLAY"] : false;
|
const displayShader = this.shaders["DISPLAY"];
|
||||||
|
|
||||||
// Clear
|
// Clear
|
||||||
// TODO(zellyn): uncomment
|
// TODO(zellyn): uncomment
|
||||||
|
@ -1282,104 +1297,159 @@ void main(void)
|
||||||
let barrelTexRect;
|
let barrelTexRect;
|
||||||
|
|
||||||
// Render
|
// Render
|
||||||
let texture;
|
const texture = this.textures["IMAGE_DECODED"];
|
||||||
if (displayShader)
|
|
||||||
texture = this.textures["IMAGE_DECODED"];
|
|
||||||
else
|
|
||||||
texture = this.textures["IMAGE_IN"];
|
|
||||||
|
|
||||||
// Set uniforms
|
// 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);
|
case "SHADOWMASK_TRIAD":
|
||||||
|
shadowMaskTexture = this.textures["SHADOWMASK_TRIAD"];
|
||||||
// Texture
|
shadowMaskAspectRatio = 2 / (274.0 / 240.0);
|
||||||
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;
|
|
||||||
break;
|
break;
|
||||||
}
|
case "SHADOWMASK_INLINE":
|
||||||
|
shadowMaskTexture = this.textures["SHADOWMASK_INLINE"];
|
||||||
const shadowMaskDotPitch = this.display.displayShadowMaskDotPitch;
|
shadowMaskAspectRatio = 2;
|
||||||
|
break;
|
||||||
if (shadowMaskDotPitch <= 0.001)
|
case "SHADOWMASK_APERTURE":
|
||||||
shadowMaskDotPitch = 0.001;
|
shadowMaskTexture = this.textures["SHADOWMASK_APERTURE"];
|
||||||
|
shadowMaskAspectRatio = 2;
|
||||||
const shadowMaskElemX = (displayResolution.width /
|
break;
|
||||||
this.display.displayPixelDensity *
|
case "SHADOWMASK_LCD":
|
||||||
25.4 * 0.5 / shadowMaskDotPitch);
|
shadowMaskTexture = this.textures["SHADOWMASK_LCD"];
|
||||||
const shadowMaskSize = new Size(shadowMaskElemX,
|
shadowMaskAspectRatio = 2;
|
||||||
shadowMaskElemX * shadowMaskAspectRatio /
|
break;
|
||||||
displayAspectRatio);
|
case "SHADOWMASK_BAYER":
|
||||||
|
shadowMaskTexture = this.textures["SHADOWMASK_BAYER"];
|
||||||
gl.activeTexture(gl.TEXTURE1);
|
shadowMaskAspectRatio = 2;
|
||||||
|
break;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
// 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) {
|
getDisplayCanvasTexPoint(p) {
|
||||||
|
|
Loading…
Reference in New Issue