diff --git a/tsvm_executable/src/net/torvald/tsvm/AppLoader.java b/tsvm_executable/src/net/torvald/tsvm/AppLoader.java index c71d433..82cab24 100644 --- a/tsvm_executable/src/net/torvald/tsvm/AppLoader.java +++ b/tsvm_executable/src/net/torvald/tsvm/AppLoader.java @@ -40,7 +40,7 @@ public class AppLoader { // VM vm = new VM(64 << 10, new TheRealWorld(), new VMProgramRom[]{BasicBios.INSTANCE, BasicRom.INSTANCE}); -// VM vm = new VM(64 << 10, new TheRealWorld(), new VMProgramRom[]{OEMBios.INSTANCE, BasicRom.INSTANCE}); +// VM vm = new VM("./assets", 64 << 10, new TheRealWorld(), new VMProgramRom[]{OEMBios.INSTANCE, BasicRom.INSTANCE}, 8, watchdogs); // VM vm = new VM("./assets", 64 << 10, new TheRealWorld(), new VMProgramRom[]{TandemBios.INSTANCE, BasicRom.INSTANCE}, 2, watchdogs); // VM vm = new VM("./assets", 128 << 10, new TheRealWorld(), new VMProgramRom[]{BasicBios.INSTANCE, WPBios.INSTANCE}, 2, watchdogs); VM vm = new VM("./assets", 8192 << 10, new TheRealWorld(), new VMProgramRom[]{TsvmBios.INSTANCE}, 8, watchdogs); diff --git a/tsvm_executable/src/net/torvald/tsvm/VMGUI.kt b/tsvm_executable/src/net/torvald/tsvm/VMGUI.kt index 17b18d2..a9dc54d 100644 --- a/tsvm_executable/src/net/torvald/tsvm/VMGUI.kt +++ b/tsvm_executable/src/net/torvald/tsvm/VMGUI.kt @@ -57,7 +57,6 @@ class VMGUI(val loaderInfo: EmulInstance, val viewportWidth: Int, val viewportHe val usememvwr = false - private lateinit var crtGradTex: TextureRegion private lateinit var crtShader: ShaderProgram fun loadShaderInline(frag0: String): ShaderProgram { @@ -96,10 +95,6 @@ class VMGUI(val loaderInfo: EmulInstance, val viewportWidth: Int, val viewportHe camera.update() batch.projectionMatrix = camera.combined - crtGradTex = TextureRegion(Texture("${vm.assetsDir}/crt_grad.png")).also { - it.flip(false, true) - } - crtShader = loadShaderInline(CRT_POST_SHADER) gpuFBO = FrameBuffer(Pixmap.Format.RGBA8888, viewportWidth, viewportHeight, false) @@ -277,13 +272,9 @@ class VMGUI(val loaderInfo: EmulInstance, val viewportWidth: Int, val viewportHe // draw GPU and border batch.shader = crtShader + batch.shader.setUniformf("resolution", viewportWidth.toFloat(), viewportHeight.toFloat()) batch.setBlendFunctionSeparate(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA, GL20.GL_SRC_ALPHA, GL20.GL_ONE) batch.draw(gpuFBO.colorBufferTexture, 0f, 0f) - - // draw CRT glass overlay - batch.shader = null - batch.setBlendFunction(GL20.GL_ONE, GL20.GL_ONE_MINUS_SRC_COLOR) - batch.draw(crtGradTex, 0f, 0f, viewportWidth.toFloat(), viewportHeight.toFloat()) } vm.findPeribyType("oled")?.let { @@ -337,7 +328,6 @@ class VMGUI(val loaderInfo: EmulInstance, val viewportWidth: Int, val viewportHe batch.dispose() fullscreenQuad.dispose() coroutineJob.interrupt() - crtGradTex.texture.dispose() crtShader.dispose() gpuFBO.dispose() winFBO.dispose() @@ -409,33 +399,33 @@ in vec4 v_color; in vec4 v_generic; in vec2 v_texCoords; uniform sampler2D u_texture; -uniform vec2 resolution = vec2(560.0, 448.0); +uniform vec2 resolution = vec2(640.0, 480.0); out vec4 fragColor; const vec4 scanline = vec4(0.9, 0.9, 0.9, 1.0); const vec4 one = vec4(1.0); +const vec4 pointfive = vec4(0.5); const mat4 rgb_to_yuv = mat4( - 0.2126, -0.09991, 0.615, 0.0, + 0.2126, -0.09991, 0.615, 0.0, 0.7152, -0.33609, -0.55861, 0.0, - 0.0722, 0.436, -0.05639, 0.0, + 0.0722, 0.436, -0.05639, 0.0, 0.0, 0.0, 0.0, 1.0 ); const mat4 yuv_to_rgb = mat4( - 1.0, 1.0, 1.0, 0.0, + 1.0, 1.0, 1.0, 0.0, 0.0, -0.21482, 2.12798, 0.0, - 1.28033,-0.38059, 0.0, 0.0, + 1.28033, -0.38059, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0 ); -const float ALFA = 0.2; -const float BETA = 0.2; +const float CRS = 0.2; const mat4 crosstalk_mat = mat4( 1.0, 0.0, 0.0, 0.0, - ALFA, 1.0, 0.0, 0.0, - BETA, 0.0, 1.0, 0.0, + CRS, 1.0, 0.0, 0.0, + CRS, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ); @@ -445,6 +435,15 @@ const float blurV = 0.4; const vec4 gradingarg = vec4(1.4, 1.1, 1.1, 1.0); +const int bayer[14 * 14] = int[](131,187,8,78,50,18,134,89,155,102,29,95,184,73,22,86,113,171,142,105,34,166,9,60,151,128,40,110,168,137,45,28,64,188,82,54,124,189,80,13,156,56,7,61,186,121,154,6,108,177,24,100,38,176,93,123,83,148,96,17,88,133,44,145,69,161,139,72,30,181,115,27,163,47,178,65,164,14,120,48,5,127,153,52,190,58,126,81,116,21,106,77,173,92,191,63,99,12,76,144,4,185,37,149,192,39,135,23,117,31,170,132,35,172,103,66,129,79,3,97,57,159,70,141,53,94,114,20,49,158,19,146,169,122,183,11,104,180,2,165,152,87,182,118,91,42,67,25,84,147,43,85,125,68,16,136,71,10,193,112,160,138,51,111,162,26,194,46,174,107,41,143,33,74,1,101,195,15,75,140,109,90,32,62,157,98,167,119,179,59,36,130,175,55,0,150); +const float bayerSize = 14.0; +const float bayerDivider = bayerSize * bayerSize; + +uniform float rcount = 96.0; +uniform float gcount = 96.0; +uniform float bcount = 96.0; +uniform float acount = 1.0; + vec4 toYUV(vec4 rgb) { return rgb_to_yuv * rgb; } vec4 toRGB(vec4 ycc) { return yuv_to_rgb * ycc; } @@ -472,6 +471,41 @@ vec4 grading(vec4 col0, vec4 args) { return pow(rgb, power); } +const vec4 gradLow = vec4(0.05, 0.05, 0.05, 0.8); +const vec4 gradHigh = vec4(0.2, 0.2, 0.2, 1.0); +const float SQRT_2 = 1.4142135623730950488; + +vec4 getRadialGrad(vec2 uv0) { + vec2 uv = uv0 * vec2(2.0) - one.xy; // -1..1 + float distFromOrigin = length(uv); // 0..1.4142; origin is (0,0) + float step = 1.0 - pow(distFromOrigin / SQRT_2, 2.0); + return mix(gradLow, gradHigh, step); +} + +vec4 screen(vec4 a, vec4 b) { + return one - (one - a) * (one - b); +} + +vec4 gammaIn(vec4 col) { + return pow(col, vec4(gamma)); +} + +vec4 gammaOut(vec4 col) { + return pow(col, vec4(1.0 / gamma)); +} + +vec4 nearestColour(vec4 incolor) { + vec4 rgbaCounts = vec4(rcount, gcount, bcount, acount); + vec4 color = incolor; + + color.r = floor((rgbaCounts.r - 1.0) * color.r + 0.5) / (rgbaCounts.r - 1.0); + color.g = floor((rgbaCounts.g - 1.0) * color.g + 0.5) / (rgbaCounts.g - 1.0); + color.b = floor((rgbaCounts.b - 1.0) * color.b + 0.5) / (rgbaCounts.b - 1.0); + color.a = 1.0;//floor((rgbaCounts.a - 1.0) * color.a + 0.5) / (rgbaCounts.a - 1.0); + + return color; +} + void main() { vec4 rgbColourIn = v_color * texture(u_texture, v_texCoords); vec4 rgbColourL = v_color * mix( @@ -491,9 +525,13 @@ void main() { vec4 wgtavr = avr(LRavr, colourIn, gamma); vec4 outCol = wgtavr; + vec4 out2 = clamp(grading(outCol, gradingarg) * ((mod(gl_FragCoord.y, 2.0) >= 1.0) ? scanline : one), 0.0, 1.0); - fragColor = grading(outCol, gradingarg) * ((mod(gl_FragCoord.y, 2.0) >= 1.0) ? scanline : one); - + // mix in CRT glass overlay + float spread = 1.0 / (0.299 * (rcount - 1.0) + 0.587 * (gcount - 1.0) + 0.114 * (bcount - 1.0)); // this spread value is optimised one -- try your own values for various effects! + vec4 inColor = screen(out2, getRadialGrad((gl_FragCoord - pointfive).xy / resolution)); + vec2 entry = mod((gl_FragCoord - pointfive).xy, vec2(bayerSize, bayerSize)); + fragColor = nearestColour(inColor + spread * (bayer[int(entry.y) * int(bayerSize) + int(entry.x)] / bayerDivider - 0.5)); } """ \ No newline at end of file