diff --git a/assets/mods/basegame/blocks/148.tga b/assets/mods/basegame/blocks/148.tga index 21e5064cc..e4a130099 100644 --- a/assets/mods/basegame/blocks/148.tga +++ b/assets/mods/basegame/blocks/148.tga @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ad51c46cc3bffaa5a56a5efca1b3396bfa29c75a70f554bcf5db65e579fd794f +oid sha256:209e46ede9613db09f7ffca8bba5c8ec002c549d7dc5f60ce908d7b2aa50b6d3 size 50194 diff --git a/assets/mods/basegame/blocks/Terrain - Air tile must have black transparent tile, NOT white.txt b/assets/mods/basegame/blocks/Terrain - Air tile must have black transparent tile, NOT white.txt index 4b6026d38..23952c4bf 100644 --- a/assets/mods/basegame/blocks/Terrain - Air tile must have black transparent tile, NOT white.txt +++ b/assets/mods/basegame/blocks/Terrain - Air tile must have black transparent tile, NOT white.txt @@ -1,3 +1,5 @@ Air tile (tile 0,0) must have colour of 0x00000000, NOT 0xFFFFFF00. You can modify the tga file directly to correct bad exporter behaviour. -All TGA must have alpha premultiplied. \ No newline at end of file +Semitransparency is rendered using dithering, so it is good idea to avoid them. + +If you must add semitransparency to the tile, they must have alpha NOT premultiplied. \ No newline at end of file diff --git a/assets/tiling_dither.frag b/assets/tiling_dither.frag new file mode 100644 index 000000000..5fc101a59 --- /dev/null +++ b/assets/tiling_dither.frag @@ -0,0 +1,123 @@ +/* + +*/ + +#version 120 +#ifdef GL_ES +precision mediump float; +#endif +#extension GL_EXT_gpu_shader4 : enable + +varying vec4 v_color; +varying vec2 v_texCoords; +uniform sampler2D u_texture; + + +uniform vec2 screenDimension; +uniform vec2 tilesInAxes; // size of the tilemap texture; vec2(tiles_in_horizontal, tiles_in_vertical) + +uniform sampler2D tilemap; // RGBA8888 + +uniform sampler2D tilesAtlas; // terrain, wire, fluids, etc. +uniform sampler2D tilesBlendAtlas; // alternative terrain for the weather mix (e.g. yellowed grass) +uniform float tilesBlend = 0.0; // percentage of blending [0f..1f]. 0: draws tilesAtlas, 1: draws tilesBlendAtlas + +uniform vec2 tilesInAtlas = vec2(256.0, 256.0); +uniform vec2 atlasTexSize = vec2(4096.0, 4096.0); + +vec2 _tilesInAtlas = vec2(1.0, 1.0) / tilesInAtlas; +vec2 tileSizeInPx = atlasTexSize * _tilesInAtlas; // should be like ivec2(16.0, 16.0) +vec2 _tileSizeInPx = vec2(1.0, 1.0) / tileSizeInPx; // should be like ivec2(0.06125, 0.06125) + +uniform vec4 colourFilter = vec4(1, 1, 1, 1); // used by WALL to darken it + +uniform ivec2 cameraTranslation = ivec2(0, 0); // used to offset the drawing; it's integer because we want the drawing to be pixel-aligned + +uniform float drawBreakage = 1.0; // set it to 0f to not draw breakage, 1f to draw it; NEVER set to any other values. + +uniform float mulBlendIntensity = 1.0; // used my MUL-blending drawings; works about the same way as the Layer Opacity slider of Photoshop/Krita/etc. + +const vec2 bc = vec2(1.0, 0.0); //binary constant + +// man the traditional bayer crosshatch pattern looks really good on tiles... +int bayer[16] = int[]( +0,8,2,10, +12,4,14,6, +3,11,1,9, +15,7,13,5 +); +float bayerSize = 4.0; +float bayerDivider = 16; + +ivec2 getTileXY(int tileNumber) { + return ivec2(tileNumber % int(tilesInAtlas.x), tileNumber / int(tilesInAtlas.x)); +} + +// return: int=0xaarrggbb +int _colToInt(vec4 color) { + return int(color.b * 255) | (int(color.g * 255) << 8) | (int(color.r * 255) << 16) | (int(color.a * 255) << 24); +} + +// 0x0rggbb where int=0xaarrggbb +// return: [0..1048575] +int getTileFromColor(vec4 color) { + return _colToInt(color) & 0xFFFFF; +} + +// 0x00r00000 where int=0xaarrggbb +// return: [0..15] +int getBreakageFromColor(vec4 color) { + return (_colToInt(color) >> 20) & 0xF; +} + +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? + // This one, however, takes exact integer by rounding down. // + vec2 overscannedScreenDimension = tilesInAxes * tileSizeInPx; // how many tiles will fit into a screen; one used by the tileFromMap; we need this because screen size is not integer multiple of the tile size + vec2 flippedFragCoord = vec2(gl_FragCoord.x, screenDimension.y - gl_FragCoord.y) + cameraTranslation; // NO IVEC2!!; this flips Y + + // get required tile numbers // + + vec4 tileFromMap = texture2D(tilemap, flippedFragCoord / overscannedScreenDimension); // raw tile number + int tile = getTileFromColor(tileFromMap); + int breakage = getBreakageFromColor(tileFromMap); + ivec2 tileXY = getTileXY(tile); + ivec2 breakageXY = getTileXY(breakage + 5); // +5 is hard-coded constant that depends on the contents of the atlas + + // calculate the UV coord value for texture sampling // + + // don't really need highp here; read the GLES spec + vec2 uvCoordForTile = (mod(flippedFragCoord, tileSizeInPx) * _tileSizeInPx) * _tilesInAtlas; // 0..0.00390625 regardless of tile position in atlas + vec2 uvCoordOffsetTile = tileXY * _tilesInAtlas; // where the tile starts in the atlas, using uv coord (0..1) + vec2 uvCoordOffsetBreakage = breakageXY * _tilesInAtlas; + + // get final UV coord for the actual sampling // + + vec2 finalUVCoordForTile = uvCoordForTile + uvCoordOffsetTile;// where we should be actually looking for in atlas, using UV coord (0..1) + vec2 finalUVCoordForBreakage = uvCoordForTile + uvCoordOffsetBreakage; + + // blending a breakage tex with main tex // + + vec4 tileCol = texture2D(tilesAtlas, finalUVCoordForTile); + vec4 tileAltCol = texture2D(tilesBlendAtlas, finalUVCoordForTile); + + vec4 finalTile = mix(tileCol, tileAltCol, tilesBlend); + + vec4 finalBreakage = drawBreakage * texture2D(tilesAtlas, finalUVCoordForBreakage); // drawBreakeage = 0 to not draw, = 1 to draw + + vec4 finalColor =mix(finalTile, finalBreakage, finalBreakage.a) * bc.xxxy + (finalTile * bc.yyyx); + + vec4 undithered = mix(colourFilter, colourFilter * finalColor, mulBlendIntensity); + + vec2 entry = mod(gl_FragCoord.xy, vec2(bayerSize, bayerSize)); + float bayerThreshold = float(bayer[int(entry.y) * int(bayerSize) + int(entry.x)]) / bayerDivider; + + gl_FragColor = undithered * bc.xxxy + vec4((undithered.a > bayerThreshold) ? 1.0 : 0.0) * bc.yyyx; +} diff --git a/src/net/torvald/terrarum/modulebasegame/IngameRenderer.kt b/src/net/torvald/terrarum/modulebasegame/IngameRenderer.kt index eaa88fd2c..6231ca8f4 100644 --- a/src/net/torvald/terrarum/modulebasegame/IngameRenderer.kt +++ b/src/net/torvald/terrarum/modulebasegame/IngameRenderer.kt @@ -34,6 +34,8 @@ import kotlin.system.exitProcess * NOTE: config "fx_dither" only controls the skybox (which is capable of having more than 256 colours * thanks to the hardware linear intp.) because this dithering shader is somewhat heavy. * + * Semitransparency is rendered using dithering, so it is good idea to avoid them. + * If you must add semitransparency to the tile, they must have alpha NOT premultiplied. * Actors' transparency (and not an UI) still uses its own lightweight ditherrer */ object IngameRenderer : Disposable { @@ -282,8 +284,6 @@ object IngameRenderer : Disposable { ) } - - // blending is correct... somewhat. Alpha must be premultiplied } // something about RGB else if (KeyToggler.isOn(Input.Keys.F6) && diff --git a/src/net/torvald/terrarum/worlddrawer/BlocksDrawer.kt b/src/net/torvald/terrarum/worlddrawer/BlocksDrawer.kt index 1ad66b6ab..7997b0918 100644 --- a/src/net/torvald/terrarum/worlddrawer/BlocksDrawer.kt +++ b/src/net/torvald/terrarum/worlddrawer/BlocksDrawer.kt @@ -11,9 +11,9 @@ import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE import net.torvald.terrarum.blockproperties.Block import net.torvald.terrarum.gameitem.ItemID import net.torvald.terrarum.gameworld.GameWorld -import net.torvald.terrarum.gameworld.fmod import net.torvald.terrarum.gameworld.WorldSimulator import net.torvald.terrarum.gameworld.WorldTime +import net.torvald.terrarum.gameworld.fmod import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack import kotlin.math.roundToInt @@ -85,7 +85,7 @@ internal object BlocksDrawer { private lateinit var tilesQuad: Mesh - private val shader = App.loadShaderFromFile("assets/4096.vert", "assets/tiling.frag") + private val shader = App.loadShaderFromFile("assets/4096.vert", "assets/tiling_dither.frag") init { diff --git a/work_files/graphics/! Artists must read me !.txt b/work_files/graphics/! Artists must read me !.txt index 2d5184167..0c64151ac 100644 --- a/work_files/graphics/! Artists must read me !.txt +++ b/work_files/graphics/! Artists must read me !.txt @@ -1,4 +1,4 @@ -All the images must be exported as .tga or .tga.gz. All the alpha must be premultiplied. +All the images must be exported as .tga or .tga.gz. All the alpha must be not premultiplied. (It is good idea to avoid semitransparency alltogether) It is recommended to use ImageMagick command line tool to convert PSD to TGA directly. diff --git a/work_files/graphics/terrain/glass_crude.kra b/work_files/graphics/terrain/glass_crude.kra new file mode 100644 index 000000000..c30844cc3 --- /dev/null +++ b/work_files/graphics/terrain/glass_crude.kra @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d7e44220d202a99947aaa8f46eb252b036cc3085b2ff410b37c4e27b9acd031e +size 82908