diff --git a/assets/tiling.frag b/assets/tiling.frag index 481a67309..5512e69c9 100644 --- a/assets/tiling.frag +++ b/assets/tiling.frag @@ -30,6 +30,7 @@ uniform sampler2D tilemap; // RGBA8888 uniform sampler2D tilesAtlas; // terrain, wire, fluids, etc. uniform sampler2D tilesBlendAtlas; // weather mix (e.g. yellowed grass) +uniform sampler2D backbuffer; uniform float tilesBlend = 0.0; // percentage of blending [0f..1f]. 0: draws tilesAtlas, 1: draws tilesBlendAtlas uniform ivec2 tilesInAtlas = ivec2(256, 256); @@ -67,6 +68,7 @@ void main() { // READ THE FUCKING MANUAL, YOU DONKEY !! // // This code purposedly uses flipped fragcoord. // // Make sure you don't use gl_FragCoord unknowingly! // + // Remember, if there's a compile error, shader SILENTLY won't do anything // // default gl_FragCoord takes half-integer (represeting centre of the pixel) -- could be useful for phys solver? @@ -109,6 +111,11 @@ void main() { vec4 finalBreakage = texture2D(tilesAtlas, finalUVCoordForBreakage); - gl_FragColor = colourFilter * (mix(finalTile, finalBreakage, finalBreakage.a)); + vec4 finalColor = mix(finalTile, finalBreakage, finalBreakage.a); + vec4 backbufferColor = texture2D(backbuffer, gl_FragCoord.xy / screenDimension); + + //gl_FragColor = colourFilter * finalColor; + // v + gl_FragColor = colourFilter * mix(backbufferColor, finalColor, 1); } diff --git a/src/net/torvald/terrarum/AppLoader.java b/src/net/torvald/terrarum/AppLoader.java index ddd5e7eeb..bfe41e8cd 100644 --- a/src/net/torvald/terrarum/AppLoader.java +++ b/src/net/torvald/terrarum/AppLoader.java @@ -222,15 +222,9 @@ public class AppLoader implements ApplicationListener { logo = new TextureRegion(new Texture(Gdx.files.internal("assets/graphics/logo_placeholder.tga"))); logo.flip(false, true); - shaderBayerSkyboxFill = new ShaderProgram(Gdx.files.internal("assets/4096.vert"), - Gdx.files.internal("assets/4096_bayer_skyboxfill.frag") - ); - shaderHicolour = new ShaderProgram(Gdx.files.internal("assets/4096.vert"), - Gdx.files.internal("assets/hicolour.frag") - ); - shaderColLUT = new ShaderProgram(Gdx.files.internal("assets/4096.vert"), - Gdx.files.internal("assets/passthru.frag") - ); + shaderBayerSkyboxFill = loadShader("assets/4096.vert", "assets/4096_bayer_skyboxfill.frag"); + shaderHicolour = loadShader("assets/4096.vert", "assets/hicolour.frag"); + shaderColLUT = loadShader("assets/4096.vert", "assets/passthru.frag"); fullscreenQuad = new Mesh( true, 4, 6, @@ -464,9 +458,9 @@ public class AppLoader implements ApplicationListener { defaultSaveDir = defaultDir + "/Saves"; configDir = defaultDir + "/config.json"; - System.out.println("os.name = $OSName (with identifier $operationSystem)"); - System.out.println("os.version = $OSVersion"); - System.out.println("default directory: $defaultDir"); + System.out.println(String.format("os.name = %s (with identifier %s)", OSName, operationSystem)); + System.out.println(String.format("os.version = %s", OSVersion)); + System.out.println(String.format("default directory: %s", defaultDir)); } private void createDirs() { @@ -634,15 +628,25 @@ public class AppLoader implements ApplicationListener { // // - public static final void printdbg(Object obj, Object message) { + public static void printdbg(Object obj, Object message) { if (IS_DEVELOPMENT_BUILD || getConfigBoolean("forcedevbuild")) { System.out.println("[" + obj.getClass().getSimpleName() + "] " + message.toString()); } } - public static final void printdbgerr(Object obj, Object message) { + public static void printdbgerr(Object obj, Object message) { if (IS_DEVELOPMENT_BUILD || getConfigBoolean("forcedevbuild")) { System.err.println("[" + obj.getClass().getSimpleName() + "] " + message.toString()); } } + + public static ShaderProgram loadShader(String vert, String frag) { + ShaderProgram s = new ShaderProgram(Gdx.files.internal(vert), Gdx.files.internal(frag)); + + if (s.getLog().contains("error C")) { + throw new Error(String.format("Shader program loaded with %s, %s failed:\n%s", vert, frag, s.getLog())); + } + + return s; + } } \ No newline at end of file diff --git a/src/net/torvald/terrarum/PostProcessor.kt b/src/net/torvald/terrarum/PostProcessor.kt index 7993d15b3..5d9371345 100644 --- a/src/net/torvald/terrarum/PostProcessor.kt +++ b/src/net/torvald/terrarum/PostProcessor.kt @@ -50,7 +50,6 @@ object PostProcessor { fbo.colorBufferTexture.bind(0) shader?.begin() - shader?.setUniformf("resolution", AppLoader.appConfig.width.toFloat(), AppLoader.appConfig.height.toFloat()) shader?.setUniformMatrix("u_projTrans", projMat) shader?.setUniformi("u_texture", 0) AppLoader.fullscreenQuad.render(shader, GL20.GL_TRIANGLES) diff --git a/src/net/torvald/terrarum/Terrarum.kt b/src/net/torvald/terrarum/Terrarum.kt index 085861e4f..a4e76599c 100644 --- a/src/net/torvald/terrarum/Terrarum.kt +++ b/src/net/torvald/terrarum/Terrarum.kt @@ -328,18 +328,18 @@ object Terrarum : Screen { ShaderProgram.pedantic = false - shaderBlur = ShaderProgram(Gdx.files.internal("assets/blur.vert"), Gdx.files.internal("assets/blur.frag")) + shaderBlur = AppLoader.loadShader("assets/blur.vert", "assets/blur.frag") if (getConfigBoolean("fxdither")) { - shaderBayer = ShaderProgram(Gdx.files.internal("assets/4096.vert"), Gdx.files.internal("assets/4096_bayer.frag")) + shaderBayer = AppLoader.loadShader("assets/4096.vert", "assets/4096_bayer.frag") shaderBayer.begin() shaderBayer.setUniformf("rcount", 64f) shaderBayer.setUniformf("gcount", 64f) shaderBayer.setUniformf("bcount", 64f) shaderBayer.end() - shaderSkyboxFill = ShaderProgram(Gdx.files.internal("assets/4096.vert"), Gdx.files.internal("assets/4096_bayer_skyboxfill.frag")) + shaderSkyboxFill = AppLoader.loadShader("assets/4096.vert", "assets/4096_bayer_skyboxfill.frag") shaderSkyboxFill.begin() shaderSkyboxFill.setUniformf("rcount", 64f) shaderSkyboxFill.setUniformf("gcount", 64f) @@ -347,15 +347,15 @@ object Terrarum : Screen { shaderSkyboxFill.end() } else { - shaderBayer = ShaderProgram(Gdx.files.internal("assets/4096.vert"), Gdx.files.internal("assets/passthru.frag")) - shaderSkyboxFill = ShaderProgram(Gdx.files.internal("assets/4096.vert"), Gdx.files.internal("assets/skyboxfill.frag")) + shaderBayer = AppLoader.loadShader("assets/4096.vert", "assets/passthru.frag") + shaderSkyboxFill = AppLoader.loadShader("assets/4096.vert", "assets/skyboxfill.frag") } - shaderBlendGlow = ShaderProgram(Gdx.files.internal("assets/blendGlow.vert"), Gdx.files.internal("assets/blendGlow.frag")) + shaderBlendGlow = AppLoader.loadShader("assets/blendGlow.vert", "assets/blendGlow.frag") - shaderRGBOnly = ShaderProgram(Gdx.files.internal("assets/4096.vert"), Gdx.files.internal("assets/rgbonly.frag")) - shaderAtoGrey = ShaderProgram(Gdx.files.internal("assets/4096.vert"), Gdx.files.internal("assets/aonly.frag")) + shaderRGBOnly = AppLoader.loadShader("assets/4096.vert", "assets/rgbonly.frag") + shaderAtoGrey = AppLoader.loadShader("assets/4096.vert", "assets/aonly.frag") if (!shaderBlendGlow.isCompiled) { @@ -625,19 +625,20 @@ fun blendDisable(batch: SpriteBatch? = null) { } fun gdxClearAndSetBlend(r: Float, g: Float, b: Float, a: Float) { - Gdx.gl.glClearColor(0f,0f,0f,0f) + Gdx.gl.glClearColor(r,g,b,a) Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT) Gdx.gl.glEnable(GL20.GL_TEXTURE_2D) Gdx.gl.glEnable(GL20.GL_BLEND) - // this assumens premultiplied alpha? - //Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA) - - // ALPHA MUST NOT BE PREMULTIPLIED // - // we're using separate blend func to accomodate not-premultiplied alpha - Gdx.gl.glBlendFuncSeparate(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA, GL20.GL_SRC_ALPHA, GL20.GL_ONE) - Gdx.gl.glBlendEquation(GL20.GL_FUNC_ADD) + // ALPHA *MUST BE* PREMULTIPLIED // + // One way to tell: + // 1. Check (RGB) and (A) values. + // 2. If there exist a pixel such that max(R,G,B) > (A), then the image is NOT premultiplied. + // Easy way: + // Base game (mods/basegame/blocks/terrain.tga.gz) has impure window glass. When looking at the RGB channel only: + // premultipied if the glass looks very dark. + // not premultipied if the glass looks VERY GREEN. // helpful links: // - https://gamedev.stackexchange.com/questions/82741/normal-blend-mode-with-opengl-trouble diff --git a/src/net/torvald/terrarum/modulebasegame/IngameRenderer.kt b/src/net/torvald/terrarum/modulebasegame/IngameRenderer.kt index 9e1f76f61..9972d3a91 100644 --- a/src/net/torvald/terrarum/modulebasegame/IngameRenderer.kt +++ b/src/net/torvald/terrarum/modulebasegame/IngameRenderer.kt @@ -238,7 +238,7 @@ object IngameRenderer { } setCameraPosition(0f, 0f) - BlocksDrawer.drawWall(batch.projectionMatrix) + BlocksDrawer.drawWall(batch.projectionMatrix, fboRGB) batch.inUse { moveCameraToWorldCoord() @@ -247,7 +247,7 @@ object IngameRenderer { } setCameraPosition(0f, 0f) - BlocksDrawer.drawTerrain(batch.projectionMatrix) + BlocksDrawer.drawTerrain(batch.projectionMatrix, fboRGB) batch.inUse { ///////////////// @@ -262,7 +262,7 @@ object IngameRenderer { } setCameraPosition(0f, 0f) - BlocksDrawer.drawFront(batch.projectionMatrix, false) // blue coloured filter of water, etc. + BlocksDrawer.drawFront(batch.projectionMatrix, false, fboRGB) // blue coloured filter of water, etc. batch.inUse { FeaturesDrawer.drawEnvOverlay(batch) diff --git a/src/net/torvald/terrarum/worlddrawer/BlocksDrawerNew.kt b/src/net/torvald/terrarum/worlddrawer/BlocksDrawerNew.kt index 462a9a284..28be9d74d 100644 --- a/src/net/torvald/terrarum/worlddrawer/BlocksDrawerNew.kt +++ b/src/net/torvald/terrarum/worlddrawer/BlocksDrawerNew.kt @@ -2,21 +2,18 @@ package net.torvald.terrarum.worlddrawer import com.badlogic.gdx.Gdx import com.badlogic.gdx.graphics.* -import com.badlogic.gdx.graphics.glutils.ShaderProgram +import com.badlogic.gdx.graphics.glutils.FrameBuffer import com.badlogic.gdx.math.Matrix4 +import net.torvald.terrarum.* import net.torvald.terrarum.AppLoader.printdbg -import net.torvald.terrarum.ModMgr import net.torvald.terrarum.blockproperties.Block import net.torvald.terrarum.blockproperties.BlockCodex -import net.torvald.terrarum.ceilInt -import net.torvald.terrarum.floorInt import net.torvald.terrarum.gameworld.GameWorld import net.torvald.terrarum.gameworld.PairedMapLayer import net.torvald.terrarum.gameworld.fmod import net.torvald.terrarum.modulebasegame.gameworld.GameWorldExtension import net.torvald.terrarum.modulebasegame.gameworld.WorldSimulator import net.torvald.terrarum.modulebasegame.gameworld.WorldTime -import net.torvald.terrarum.roundInt import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack import java.io.BufferedOutputStream import java.io.File @@ -89,7 +86,7 @@ internal object BlocksDrawer { private lateinit var tilesQuad: Mesh - private val shader = ShaderProgram(Gdx.files.internal("assets/4096.vert"), Gdx.files.internal("assets/tiling.frag")) + private val shader = AppLoader.loadShader("assets/4096.vert", "assets/tiling.frag") init { printdbg(this, "Unpacking textures...") @@ -350,33 +347,33 @@ internal object BlocksDrawer { drawTiles(FLUID) } - internal fun drawWall(projectionMatrix: Matrix4) { + internal fun drawWall(projectionMatrix: Matrix4, backbuffer: FrameBuffer) { // blend normal Gdx.gl.glEnable(GL20.GL_TEXTURE_2D) Gdx.gl.glEnable(GL20.GL_BLEND) Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA) - renderUsingBuffer(WALL, projectionMatrix) + renderUsingBuffer(WALL, projectionMatrix, backbuffer) } - internal fun drawTerrain(projectionMatrix: Matrix4) { + internal fun drawTerrain(projectionMatrix: Matrix4, backbuffer: FrameBuffer) { // blend normal Gdx.gl.glEnable(GL20.GL_TEXTURE_2D) Gdx.gl.glEnable(GL20.GL_BLEND) Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA) - renderUsingBuffer(TERRAIN, projectionMatrix) - renderUsingBuffer(FLUID, projectionMatrix) + renderUsingBuffer(TERRAIN, projectionMatrix, backbuffer) + renderUsingBuffer(FLUID, projectionMatrix, backbuffer) } - internal fun drawFront(projectionMatrix: Matrix4, drawWires: Boolean) { + internal fun drawFront(projectionMatrix: Matrix4, drawWires: Boolean, backbuffer: FrameBuffer) { // blend mul Gdx.gl.glEnable(GL20.GL_TEXTURE_2D) Gdx.gl.glEnable(GL20.GL_BLEND) Gdx.gl.glBlendFunc(GL20.GL_DST_COLOR, GL20.GL_ONE_MINUS_SRC_ALPHA) // let's just not MUL on terrain, make it FLUID only... - renderUsingBuffer(FLUID, projectionMatrix) + renderUsingBuffer(FLUID, projectionMatrix, backbuffer) @@ -386,7 +383,7 @@ internal object BlocksDrawer { Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA) if (drawWires) { - renderUsingBuffer(WIRE, projectionMatrix) + renderUsingBuffer(WIRE, projectionMatrix, backbuffer) } } @@ -688,7 +685,7 @@ internal object BlocksDrawer { private var _tilesBufferAsTex: Texture = Texture(1, 1, Pixmap.Format.RGBA8888) - private fun renderUsingBuffer(mode: Int, projectionMatrix: Matrix4) { + private fun renderUsingBuffer(mode: Int, projectionMatrix: Matrix4, backbuffer: FrameBuffer) { //Gdx.gl.glClearColor(.094f, .094f, .094f, 0f) //Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT) @@ -731,6 +728,7 @@ internal object BlocksDrawer { _tilesBufferAsTex.dispose() _tilesBufferAsTex = Texture(tilesBuffer) _tilesBufferAsTex.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest) + backbuffer.colorBufferTexture.bind(3) tilesTerrainBlend.texture.bind(2) _tilesBufferAsTex.bind(1) // trying 1 and 0... tileAtlas.texture.bind(0) // for some fuck reason, it must be bound as last @@ -742,6 +740,7 @@ internal object BlocksDrawer { shader.setUniformi("tilesAtlas", 0) shader.setUniformi("tilesBlendAtlas", 2) shader.setUniformi("tilemap", 1) + shader.setUniformi("backbuffer", 3) shader.setUniformi("tilemapDimension", tilesBuffer.width, tilesBuffer.height) shader.setUniformf("tilesInAxes", tilesInHorizontal.toFloat(), tilesInVertical.toFloat()) shader.setUniformi("cameraTranslation", WorldCamera.x fmod TILE_SIZE, WorldCamera.y fmod TILE_SIZE) // usage of 'fmod' and '%' were depend on the for_x_start, which I can't just do naive int div