mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-03-07 19:51:51 +09:00
crt-like shader
This commit is contained in:
@@ -4,6 +4,7 @@ import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.Texture
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
||||
import com.badlogic.gdx.graphics.glutils.ShaderProgram
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.toUlong
|
||||
import net.torvald.tsvm.TsvmTextureRegionPack
|
||||
import net.torvald.tsvm.VM
|
||||
@@ -41,6 +42,7 @@ class CLCDDisplay(assetsRoot: String, vm: VM) : GraphicsAdapter(assetsRoot, vm,
|
||||
xoff: Float,
|
||||
yoff: Float,
|
||||
flipY: Boolean,
|
||||
shader: ShaderProgram?,
|
||||
uiFBO: FrameBuffer?
|
||||
) {
|
||||
batch.shader = null
|
||||
@@ -48,7 +50,7 @@ class CLCDDisplay(assetsRoot: String, vm: VM) : GraphicsAdapter(assetsRoot, vm,
|
||||
batch.color = Color.WHITE
|
||||
batch.draw(machine, xoff, yoff)
|
||||
}
|
||||
super.render(delta, batch, xoff+60, yoff+90, flipY, uiFBO)
|
||||
super.render(delta, batch, xoff+60, yoff+90, flipY, shader, uiFBO)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.Texture
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
||||
import com.badlogic.gdx.graphics.glutils.ShaderProgram
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.toUlong
|
||||
import net.torvald.tsvm.TsvmTextureRegionPack
|
||||
import net.torvald.tsvm.VM
|
||||
@@ -36,6 +37,7 @@ class CharacterLCDdisplay(assetsRoot: String, vm: VM) : GraphicsAdapter(assetsRo
|
||||
xoff: Float,
|
||||
yoff: Float,
|
||||
flipY: Boolean,
|
||||
shader: ShaderProgram?,
|
||||
uiFBO: FrameBuffer?
|
||||
) {
|
||||
batch.shader = null
|
||||
@@ -44,9 +46,9 @@ class CharacterLCDdisplay(assetsRoot: String, vm: VM) : GraphicsAdapter(assetsRo
|
||||
batch.draw(machine, xoff, yoff)
|
||||
}
|
||||
if (!flipY)
|
||||
super.render(delta, batch, xoff+74, yoff+102, flipY, uiFBO)
|
||||
super.render(delta, batch, xoff+74, yoff+102, flipY, shader, uiFBO)
|
||||
else
|
||||
super.render(delta, batch, xoff+74, yoff+72, flipY, uiFBO)
|
||||
super.render(delta, batch, xoff+74, yoff+72, flipY, shader, uiFBO)
|
||||
|
||||
// draw BMS and RTC
|
||||
val batPerc = "89"
|
||||
|
||||
@@ -10,6 +10,7 @@ import com.badlogic.gdx.graphics.g2d.Gdx2DPixmap
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
||||
import com.badlogic.gdx.graphics.glutils.ShaderProgram
|
||||
import com.badlogic.gdx.math.Matrix4
|
||||
import com.badlogic.gdx.utils.Disposable
|
||||
import com.badlogic.gdx.utils.GdxRuntimeException
|
||||
@@ -1039,7 +1040,7 @@ open class GraphicsAdapter(private val assetsRoot: String, val vm: VM, val confi
|
||||
|
||||
private val isRefSize = (WIDTH == 560 && HEIGHT == 448)
|
||||
|
||||
open fun render(delta: Float, uiBatch: SpriteBatch, xoff: Float, yoff: Float, flipY: Boolean = false, uiFBO: FrameBuffer? = null) {
|
||||
open fun render(delta: Float, uiBatch: SpriteBatch, xoff: Float, yoff: Float, flipY: Boolean = false, shader: ShaderProgram? = null, uiFBO: FrameBuffer? = null) {
|
||||
uiFBO?.end()
|
||||
|
||||
|
||||
@@ -1346,7 +1347,7 @@ open class GraphicsAdapter(private val assetsRoot: String, val vm: VM, val confi
|
||||
uiFBO?.begin()
|
||||
|
||||
uiBatch.inUse {
|
||||
uiBatch.shader = null
|
||||
uiBatch.shader = shader
|
||||
//Gdx.gl.glClearColor(0f, 0f, 0f, 0f)
|
||||
//Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
|
||||
blendNormal(uiBatch)
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.GL20
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
||||
import com.badlogic.gdx.graphics.glutils.ShaderProgram
|
||||
import net.torvald.tsvm.VM
|
||||
import net.torvald.tsvm.kB
|
||||
import kotlin.math.absoluteValue
|
||||
@@ -60,10 +61,11 @@ open class TexticsAdapterBase(assetsRoot: String, vm: VM, config: AdapterConfig)
|
||||
xoff: Float,
|
||||
yoff: Float,
|
||||
flipY: Boolean,
|
||||
shader: ShaderProgram?,
|
||||
uiFBO: FrameBuffer?
|
||||
) {
|
||||
|
||||
super.render(delta, batch, xoff, yoff, flipY, uiFBO)
|
||||
super.render(delta, batch, xoff, yoff, flipY, shader, uiFBO)
|
||||
|
||||
batch.inUse {
|
||||
batch.enableBlending()
|
||||
|
||||
@@ -5,12 +5,14 @@ import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.graphics.*
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||
import kotlin.coroutines.*
|
||||
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
||||
import com.badlogic.gdx.graphics.glutils.ShaderProgram
|
||||
import net.torvald.terrarum.DefaultGL32Shaders
|
||||
import net.torvald.terrarum.modulecomputers.tsvmperipheral.WorldRadar
|
||||
import net.torvald.tsvm.peripheral.*
|
||||
import java.io.File
|
||||
import net.torvald.tsvm.peripheral.GraphicsAdapter.Companion.DRAW_SHADER_VERT
|
||||
import java.util.*
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import kotlin.coroutines.*
|
||||
|
||||
|
||||
class EmulInstance(
|
||||
@@ -48,10 +50,31 @@ class VMGUI(val loaderInfo: EmulInstance, val viewportWidth: Int, val viewportHe
|
||||
lateinit var coroutineJob: Thread
|
||||
lateinit var memvwr: Memvwr
|
||||
lateinit var fullscreenQuad: Mesh
|
||||
lateinit var gpuFBO: FrameBuffer
|
||||
|
||||
val usememvwr = false
|
||||
|
||||
private lateinit var crtGradTex: TextureRegion
|
||||
private lateinit var crtShader: ShaderProgram
|
||||
|
||||
fun loadShaderInline(frag0: String): ShaderProgram {
|
||||
// insert version code
|
||||
val frag: String
|
||||
if (Gdx.graphics.glVersion.majorVersion >= 4) {
|
||||
frag = "#version 400\n$frag0"
|
||||
}
|
||||
else {
|
||||
frag = "#version 330\n#define fma(a,b,c) (((a)*(b))+(c))\n$frag0"
|
||||
}
|
||||
|
||||
val s = ShaderProgram(DRAW_SHADER_VERT, frag)
|
||||
|
||||
if (s.log.lowercase(Locale.getDefault()).contains("error")) {
|
||||
throw java.lang.Error(String.format("Shader program loaded with %s failed:\n%s", frag, s.log))
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
override fun create() {
|
||||
super.create()
|
||||
@@ -74,6 +97,10 @@ class VMGUI(val loaderInfo: EmulInstance, val viewportWidth: Int, val viewportHe
|
||||
it.flip(false, true)
|
||||
}
|
||||
|
||||
crtShader = loadShaderInline(CRT_POST_SHADER)
|
||||
|
||||
gpuFBO = FrameBuffer(Pixmap.Format.RGBA8888, viewportWidth, viewportHeight, false)
|
||||
|
||||
init()
|
||||
}
|
||||
|
||||
@@ -83,7 +110,7 @@ class VMGUI(val loaderInfo: EmulInstance, val viewportWidth: Int, val viewportHe
|
||||
if (loaderInfo.display != null) {
|
||||
val loadedClass = Class.forName(loaderInfo.display)
|
||||
val loadedClassConstructor = loadedClass.getConstructor(String::class.java, vm::class.java)
|
||||
val loadedClassInstance = loadedClassConstructor.newInstance("./assets", vm, )
|
||||
val loadedClassInstance = loadedClassConstructor.newInstance("./assets", vm)
|
||||
gpu = (loadedClassInstance as GraphicsAdapter)
|
||||
|
||||
vm.peripheralTable[1] = PeripheralEntry(
|
||||
@@ -218,15 +245,35 @@ class VMGUI(val loaderInfo: EmulInstance, val viewportWidth: Int, val viewportHe
|
||||
private val defaultGuiBackgroundColour = Color(0x444444ff)
|
||||
|
||||
private fun renderGame(delta: Float) {
|
||||
val clearCol = gpu?.getBackgroundColour() ?: defaultGuiBackgroundColour
|
||||
Gdx.gl.glClearColor(clearCol.r, clearCol.g, clearCol.b, clearCol.a)
|
||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
|
||||
gpu?.render(delta, batch, (viewportWidth - loaderInfo.drawWidth).div(2).toFloat(), (viewportHeight - loaderInfo.drawHeight).div(2).toFloat())
|
||||
gpuFBO.begin()
|
||||
val clearCol = gpu?.getBackgroundColour() ?: defaultGuiBackgroundColour
|
||||
Gdx.gl.glClearColor(clearCol.r, clearCol.g, clearCol.b, clearCol.a)
|
||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
|
||||
|
||||
gpu?.render(
|
||||
delta, batch,
|
||||
(viewportWidth - loaderInfo.drawWidth).div(2).toFloat(),
|
||||
(viewportHeight - loaderInfo.drawHeight).div(2).toFloat(),
|
||||
flipY = true,
|
||||
uiFBO = gpuFBO
|
||||
)
|
||||
gpuFBO.end()
|
||||
|
||||
|
||||
Gdx.gl.glClearColor(0f, 0f, 0f, 0f)
|
||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
|
||||
|
||||
// draw CRT glass overlay
|
||||
batch.inUse {
|
||||
batch.setBlendFunction(GL20.GL_ONE, GL20.GL_ONE_MINUS_SRC_COLOR)
|
||||
batch.color = Color.WHITE
|
||||
|
||||
// draw GPU and border
|
||||
batch.shader = crtShader
|
||||
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())
|
||||
}
|
||||
|
||||
@@ -269,6 +316,8 @@ class VMGUI(val loaderInfo: EmulInstance, val viewportWidth: Int, val viewportHe
|
||||
fullscreenQuad.dispose()
|
||||
coroutineJob.interrupt()
|
||||
crtGradTex.texture.dispose()
|
||||
crtShader.dispose()
|
||||
gpuFBO.dispose()
|
||||
vm.dispose()
|
||||
}
|
||||
|
||||
@@ -322,4 +371,68 @@ class VMGUI(val loaderInfo: EmulInstance, val viewportWidth: Int, val viewportHe
|
||||
}
|
||||
}
|
||||
|
||||
const val EMDASH = 0x2014.toChar()
|
||||
const val EMDASH = 0x2014.toChar()
|
||||
|
||||
const val CRT_POST_SHADER = """
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
|
||||
in vec4 v_color;
|
||||
in vec4 v_generic;
|
||||
in vec2 v_texCoords;
|
||||
uniform sampler2D u_texture;
|
||||
uniform vec2 resolution = vec2(560.0, 448.0);
|
||||
out vec4 fragColor;
|
||||
|
||||
const vec4 scanline = vec4(0.9, 0.9, 0.9, 1.0);
|
||||
const vec4 one = vec4(1.0);
|
||||
|
||||
const mat4 rgb_to_yuv = mat4(
|
||||
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.0, 0.0, 0.0, 1.0
|
||||
);
|
||||
|
||||
const mat4 yuv_to_rgb = mat4(
|
||||
1.0, 1.0, 1.0, 0.0,
|
||||
0.0, -0.21482, 2.12798, 0.0,
|
||||
1.28033,-0.38059, 0.0, 0.0,
|
||||
0.0, 0.0, 0.0, 1.0
|
||||
);
|
||||
|
||||
const float gamma = 2.4;
|
||||
const float blur = 0.8;
|
||||
|
||||
vec4 toYUV(vec4 rgb) { return rgb_to_yuv * rgb; }
|
||||
vec4 toRGB(vec4 ycc) { return yuv_to_rgb * ycc; }
|
||||
|
||||
vec4 avr(vec4 a, vec4 b, float gam) {
|
||||
return vec4(
|
||||
pow((pow(a.x, 1.0 / gam) + pow(b.x, 1.0 / gam)) / 2.0, gam),
|
||||
(a.y + b.y) / 2.0,
|
||||
(a.z + b.z) / 2.0,
|
||||
(a.w + b.w) / 2.0
|
||||
);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec4 rgbColourIn = v_color * texture(u_texture, v_texCoords);
|
||||
vec4 rgbColourL = v_color * texture(u_texture, v_texCoords + (vec2(-blur, 0.0) / resolution));
|
||||
vec4 rgbColourR = v_color * texture(u_texture, v_texCoords + (vec2(+blur, 0.0) / resolution));
|
||||
|
||||
vec4 colourIn = toYUV(rgbColourIn);
|
||||
vec4 colourL = toYUV(rgbColourL);
|
||||
vec4 colourR = toYUV(rgbColourR);
|
||||
|
||||
vec4 LRavr = avr(colourL, colourR, gamma);
|
||||
vec4 wgtavr = avr(LRavr, colourIn, gamma);
|
||||
|
||||
vec4 outCol = wgtavr * ((mod(gl_FragCoord.y, 2.0) >= 1.0) ? scanline : one);
|
||||
|
||||
fragColor = toRGB(outCol);
|
||||
|
||||
}
|
||||
|
||||
"""
|
||||
Reference in New Issue
Block a user