mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-06-09 14:44:05 +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.Texture
|
||||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||||
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
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.terrarum.modulecomputers.virtualcomputer.tvd.toUlong
|
||||||
import net.torvald.tsvm.TsvmTextureRegionPack
|
import net.torvald.tsvm.TsvmTextureRegionPack
|
||||||
import net.torvald.tsvm.VM
|
import net.torvald.tsvm.VM
|
||||||
@@ -41,6 +42,7 @@ class CLCDDisplay(assetsRoot: String, vm: VM) : GraphicsAdapter(assetsRoot, vm,
|
|||||||
xoff: Float,
|
xoff: Float,
|
||||||
yoff: Float,
|
yoff: Float,
|
||||||
flipY: Boolean,
|
flipY: Boolean,
|
||||||
|
shader: ShaderProgram?,
|
||||||
uiFBO: FrameBuffer?
|
uiFBO: FrameBuffer?
|
||||||
) {
|
) {
|
||||||
batch.shader = null
|
batch.shader = null
|
||||||
@@ -48,7 +50,7 @@ class CLCDDisplay(assetsRoot: String, vm: VM) : GraphicsAdapter(assetsRoot, vm,
|
|||||||
batch.color = Color.WHITE
|
batch.color = Color.WHITE
|
||||||
batch.draw(machine, xoff, yoff)
|
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.Texture
|
||||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||||
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
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.terrarum.modulecomputers.virtualcomputer.tvd.toUlong
|
||||||
import net.torvald.tsvm.TsvmTextureRegionPack
|
import net.torvald.tsvm.TsvmTextureRegionPack
|
||||||
import net.torvald.tsvm.VM
|
import net.torvald.tsvm.VM
|
||||||
@@ -36,6 +37,7 @@ class CharacterLCDdisplay(assetsRoot: String, vm: VM) : GraphicsAdapter(assetsRo
|
|||||||
xoff: Float,
|
xoff: Float,
|
||||||
yoff: Float,
|
yoff: Float,
|
||||||
flipY: Boolean,
|
flipY: Boolean,
|
||||||
|
shader: ShaderProgram?,
|
||||||
uiFBO: FrameBuffer?
|
uiFBO: FrameBuffer?
|
||||||
) {
|
) {
|
||||||
batch.shader = null
|
batch.shader = null
|
||||||
@@ -44,9 +46,9 @@ class CharacterLCDdisplay(assetsRoot: String, vm: VM) : GraphicsAdapter(assetsRo
|
|||||||
batch.draw(machine, xoff, yoff)
|
batch.draw(machine, xoff, yoff)
|
||||||
}
|
}
|
||||||
if (!flipY)
|
if (!flipY)
|
||||||
super.render(delta, batch, xoff+74, yoff+102, flipY, uiFBO)
|
super.render(delta, batch, xoff+74, yoff+102, flipY, shader, uiFBO)
|
||||||
else
|
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
|
// draw BMS and RTC
|
||||||
val batPerc = "89"
|
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.SpriteBatch
|
||||||
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||||
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
||||||
|
import com.badlogic.gdx.graphics.glutils.ShaderProgram
|
||||||
import com.badlogic.gdx.math.Matrix4
|
import com.badlogic.gdx.math.Matrix4
|
||||||
import com.badlogic.gdx.utils.Disposable
|
import com.badlogic.gdx.utils.Disposable
|
||||||
import com.badlogic.gdx.utils.GdxRuntimeException
|
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)
|
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()
|
uiFBO?.end()
|
||||||
|
|
||||||
|
|
||||||
@@ -1346,7 +1347,7 @@ open class GraphicsAdapter(private val assetsRoot: String, val vm: VM, val confi
|
|||||||
uiFBO?.begin()
|
uiFBO?.begin()
|
||||||
|
|
||||||
uiBatch.inUse {
|
uiBatch.inUse {
|
||||||
uiBatch.shader = null
|
uiBatch.shader = shader
|
||||||
//Gdx.gl.glClearColor(0f, 0f, 0f, 0f)
|
//Gdx.gl.glClearColor(0f, 0f, 0f, 0f)
|
||||||
//Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
|
//Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
|
||||||
blendNormal(uiBatch)
|
blendNormal(uiBatch)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import com.badlogic.gdx.graphics.Color
|
|||||||
import com.badlogic.gdx.graphics.GL20
|
import com.badlogic.gdx.graphics.GL20
|
||||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||||
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
||||||
|
import com.badlogic.gdx.graphics.glutils.ShaderProgram
|
||||||
import net.torvald.tsvm.VM
|
import net.torvald.tsvm.VM
|
||||||
import net.torvald.tsvm.kB
|
import net.torvald.tsvm.kB
|
||||||
import kotlin.math.absoluteValue
|
import kotlin.math.absoluteValue
|
||||||
@@ -60,10 +61,11 @@ open class TexticsAdapterBase(assetsRoot: String, vm: VM, config: AdapterConfig)
|
|||||||
xoff: Float,
|
xoff: Float,
|
||||||
yoff: Float,
|
yoff: Float,
|
||||||
flipY: Boolean,
|
flipY: Boolean,
|
||||||
|
shader: ShaderProgram?,
|
||||||
uiFBO: FrameBuffer?
|
uiFBO: FrameBuffer?
|
||||||
) {
|
) {
|
||||||
|
|
||||||
super.render(delta, batch, xoff, yoff, flipY, uiFBO)
|
super.render(delta, batch, xoff, yoff, flipY, shader, uiFBO)
|
||||||
|
|
||||||
batch.inUse {
|
batch.inUse {
|
||||||
batch.enableBlending()
|
batch.enableBlending()
|
||||||
|
|||||||
@@ -5,12 +5,14 @@ import com.badlogic.gdx.Gdx
|
|||||||
import com.badlogic.gdx.graphics.*
|
import com.badlogic.gdx.graphics.*
|
||||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||||
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
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.DefaultGL32Shaders
|
||||||
import net.torvald.terrarum.modulecomputers.tsvmperipheral.WorldRadar
|
|
||||||
import net.torvald.tsvm.peripheral.*
|
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 java.util.concurrent.atomic.AtomicBoolean
|
||||||
|
import kotlin.coroutines.*
|
||||||
|
|
||||||
|
|
||||||
class EmulInstance(
|
class EmulInstance(
|
||||||
@@ -48,10 +50,31 @@ class VMGUI(val loaderInfo: EmulInstance, val viewportWidth: Int, val viewportHe
|
|||||||
lateinit var coroutineJob: Thread
|
lateinit var coroutineJob: Thread
|
||||||
lateinit var memvwr: Memvwr
|
lateinit var memvwr: Memvwr
|
||||||
lateinit var fullscreenQuad: Mesh
|
lateinit var fullscreenQuad: Mesh
|
||||||
|
lateinit var gpuFBO: FrameBuffer
|
||||||
|
|
||||||
val usememvwr = false
|
val usememvwr = false
|
||||||
|
|
||||||
private lateinit var crtGradTex: TextureRegion
|
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() {
|
override fun create() {
|
||||||
super.create()
|
super.create()
|
||||||
@@ -74,6 +97,10 @@ class VMGUI(val loaderInfo: EmulInstance, val viewportWidth: Int, val viewportHe
|
|||||||
it.flip(false, true)
|
it.flip(false, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
crtShader = loadShaderInline(CRT_POST_SHADER)
|
||||||
|
|
||||||
|
gpuFBO = FrameBuffer(Pixmap.Format.RGBA8888, viewportWidth, viewportHeight, false)
|
||||||
|
|
||||||
init()
|
init()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,7 +110,7 @@ class VMGUI(val loaderInfo: EmulInstance, val viewportWidth: Int, val viewportHe
|
|||||||
if (loaderInfo.display != null) {
|
if (loaderInfo.display != null) {
|
||||||
val loadedClass = Class.forName(loaderInfo.display)
|
val loadedClass = Class.forName(loaderInfo.display)
|
||||||
val loadedClassConstructor = loadedClass.getConstructor(String::class.java, vm::class.java)
|
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)
|
gpu = (loadedClassInstance as GraphicsAdapter)
|
||||||
|
|
||||||
vm.peripheralTable[1] = PeripheralEntry(
|
vm.peripheralTable[1] = PeripheralEntry(
|
||||||
@@ -218,15 +245,35 @@ class VMGUI(val loaderInfo: EmulInstance, val viewportWidth: Int, val viewportHe
|
|||||||
private val defaultGuiBackgroundColour = Color(0x444444ff)
|
private val defaultGuiBackgroundColour = Color(0x444444ff)
|
||||||
|
|
||||||
private fun renderGame(delta: Float) {
|
private fun renderGame(delta: Float) {
|
||||||
val clearCol = gpu?.getBackgroundColour() ?: defaultGuiBackgroundColour
|
gpuFBO.begin()
|
||||||
Gdx.gl.glClearColor(clearCol.r, clearCol.g, clearCol.b, clearCol.a)
|
val clearCol = gpu?.getBackgroundColour() ?: defaultGuiBackgroundColour
|
||||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
|
Gdx.gl.glClearColor(clearCol.r, clearCol.g, clearCol.b, clearCol.a)
|
||||||
gpu?.render(delta, batch, (viewportWidth - loaderInfo.drawWidth).div(2).toFloat(), (viewportHeight - loaderInfo.drawHeight).div(2).toFloat())
|
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.inUse {
|
||||||
batch.setBlendFunction(GL20.GL_ONE, GL20.GL_ONE_MINUS_SRC_COLOR)
|
|
||||||
batch.color = Color.WHITE
|
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())
|
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()
|
fullscreenQuad.dispose()
|
||||||
coroutineJob.interrupt()
|
coroutineJob.interrupt()
|
||||||
crtGradTex.texture.dispose()
|
crtGradTex.texture.dispose()
|
||||||
|
crtShader.dispose()
|
||||||
|
gpuFBO.dispose()
|
||||||
vm.dispose()
|
vm.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,3 +372,67 @@ 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