randomised tiling

This commit is contained in:
minjaesong
2023-11-04 17:21:15 +09:00
parent 6ae39d38e3
commit eaef2f0c6a
4 changed files with 167 additions and 97 deletions

View File

@@ -6,6 +6,7 @@ import com.badlogic.gdx.graphics.*
import com.badlogic.gdx.math.Matrix4
import com.jme3.math.FastMath
import net.torvald.gdx.graphics.Cvec
import net.torvald.random.XXHash64
import net.torvald.terrarum.*
import net.torvald.terrarum.App.measureDebugTime
import net.torvald.terrarum.App.printdbg
@@ -15,6 +16,7 @@ import net.torvald.terrarum.gamecontroller.KeyToggler
import net.torvald.terrarum.gameitems.ItemID
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.fmod
import net.torvald.terrarum.serialise.toBig64
import net.torvald.terrarum.worlddrawer.CreateTileAtlas.Companion.WALL_OVERLAY_COLOUR
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
import kotlin.math.roundToInt
@@ -303,6 +305,11 @@ internal object BlocksDrawer {
}
private fun getHashCoord(x: Int, y: Int, mod: Int) =
(XXHash64.hash((y.toLong().shl(32) or x.toLong().and(0xFFFFFFFF)).toBig64(), mod.toLong()).and(0x7FFFFFFFFFFFFFFFL) % mod).toInt()
/**
* Autotiling; writes to buffer. Actual draw code must be called after this operation.
*
@@ -348,6 +355,10 @@ internal object BlocksDrawer {
else -> throw IllegalArgumentException()
}
var hash = if ((mode == WALL || mode == TERRAIN) && !BlockCodex[world.tileNumberToNameMap[thisTile.toLong()]].hasTag("NORANDTILE"))
getHashCoord(x, y, 8)
else 0
// draw a tile
val nearbyTilesInfo = if (mode == OCCLUSION) {
getNearbyTilesInfoFakeOcc(x, y)
@@ -359,19 +370,20 @@ internal object BlocksDrawer {
getNearbyTilesInfoFluids(x, y)
}*/
else if (treeTiles.binarySearch(thisTile) >= 0) {
getNearbyTilesInfoTrees(x, y, mode)
getNearbyTilesInfoTrees(x, y, mode).swizzle8(thisTile, hash)
}
else if (platformTiles.binarySearch(thisTile) >= 0) {
getNearbyTilesInfoPlatform(x, y)
hash %= 2
getNearbyTilesInfoPlatform(x, y)//.swizzleH2(thisTile, hash)
}
else if (wallStickerTiles.binarySearch(thisTile) >= 0) {
getNearbyTilesInfoWallSticker(x, y)
}
else if (connectMutualTiles.binarySearch(thisTile) >= 0) {
getNearbyTilesInfoConMutual(x, y, mode)
getNearbyTilesInfoConMutual(x, y, mode).swizzle8(thisTile, hash)
}
else if (connectSelfTiles.binarySearch(thisTile) >= 0) {
getNearbyTilesInfoConSelf(x, y, mode, thisTile)
getNearbyTilesInfoConSelf(x, y, mode, thisTile).swizzle8(thisTile, hash)
}
else {
0
@@ -420,21 +432,40 @@ internal object BlocksDrawer {
val breakingStage = if (mode == TERRAIN || mode == WALL || mode == ORES) (breakage / maxHealth).coerceIn(0f, 1f).times(BREAKAGE_STEPS).roundToInt() else 0
// draw a tile
writeToBuffer(mode, bufferX, bufferY, thisTileX, thisTileY, breakingStage)
writeToBuffer(mode, bufferX, bufferY, thisTileX, thisTileY, breakingStage, hash)
}
}
}
private val swizzleMap8 = arrayOf(
arrayOf(0,1,2,3,4,5,6,7), /* normal */
arrayOf(4,3,2,1,0,7,6,5), /* horz flip */
arrayOf(2,3,4,5,6,7,0,1), /* CW 90 */
arrayOf(2,1,0,7,6,5,4,3), /* hfCW 90 */
arrayOf(4,5,6,7,0,1,2,3), /* CW 180 */
arrayOf(0,7,6,5,4,3,2,1), /* hfCW 180 */
arrayOf(6,7,0,1,2,3,4,5), /* CW 270 */
arrayOf(6,5,4,3,2,1,0,7), /* hfCW 270 */
)
private fun Int.swizzle8(tile: Int, hash: Int): Int {
var ret = 0
swizzleMap8[hash].forEachIndexed { index, ord ->
ret = ret or this.ushr(ord).and(1).shl(index)
}
return ret
}
private fun getNearbyTilesPos(x: Int, y: Int): Array<Point2i> {
return arrayOf(
Point2i(x + 1, y),
Point2i(x + 1, y + 1),
Point2i(x, y + 1),
Point2i(x - 1, y + 1),
Point2i(x - 1, y),
Point2i(x - 1, y - 1),
Point2i(x, y - 1),
Point2i(x + 1, y - 1)
Point2i(x + 1, y),
Point2i(x + 1, y + 1),
Point2i(x, y + 1),
Point2i(x - 1, y + 1),
Point2i(x - 1, y),
Point2i(x - 1, y - 1),
Point2i(x, y - 1),
Point2i(x + 1, y - 1)
)
}
@@ -617,16 +648,17 @@ internal object BlocksDrawer {
*
* @return Raw colour bits in RGBA8888 format
*/
private fun sheetXYToTilemapColour(mode: Int, sheetX: Int, sheetY: Int, breakage: Int): Int =
private fun sheetXYToTilemapColour(mode: Int, sheetX: Int, sheetY: Int, breakage: Int, hash: Int): Int =
// the tail ".or(255)" is there to write 1.0 to the A channel (remember, return type is RGBA)
// this code is synced to the tilesTerrain's tile configuration, but everything else is hard-coded
// right now.
(tilesTerrain.horizontalCount * sheetY + sheetX).shl(8).or(255) or // the actual tile bits
breakage.and(15).shl(28) // breakage bits
breakage.and(15).shl(28) or // breakage bits
hash.and(15).shl(24) // flip-rot
private fun writeToBuffer(mode: Int, bufferPosX: Int, bufferPosY: Int, sheetX: Int, sheetY: Int, breakage: Int) {
private fun writeToBuffer(mode: Int, bufferPosX: Int, bufferPosY: Int, sheetX: Int, sheetY: Int, breakage: Int, hash: Int) {
val sourceBuffer = when(mode) {
TERRAIN -> terrainTilesBuffer
WALL -> wallTilesBuffer
@@ -638,7 +670,7 @@ internal object BlocksDrawer {
}
sourceBuffer[bufferPosY][bufferPosX] = sheetXYToTilemapColour(mode, sheetX, sheetY, breakage)
sourceBuffer[bufferPosY][bufferPosX] = sheetXYToTilemapColour(mode, sheetX, sheetY, breakage, hash)
}
private var _tilesBufferAsTex: Texture = Texture(1, 1, Pixmap.Format.RGBA8888)

View File

@@ -48,9 +48,9 @@ ivec2 getTileXY(int tileNumber) {
return ivec2(tileNumber % int(tilesInAtlas.x), tileNumber / int(tilesInAtlas.x));
}
// return: int=0xaarrggbb
// return: int=0x(aa)rrggbb
int _colToInt(vec4 color) {
return int(color.b * 255) | (int(color.g * 255) << 8) | (int(color.r * 255) << 16) | (int(color.a * 255) << 24);
return int(color.b * 255) | (int(color.g * 255) << 8) | (int(color.r * 255) << 16);// | (int(color.a * 255) << 24);
}
// 0x00ggbb where int=0xaarrggbb
@@ -65,6 +65,41 @@ int getBreakageFromColor(vec4 color) {
return (_colToInt(color) >> 20) & 0xF;
}
// 0x000r0000 where int=0xaarrggbb
// return: [0..15]
int getTileFlipRotFromColor(vec4 color) {
return (_colToInt(color) >> 16) & 0xF;
}
mat2[] flipRotMat = mat2[](
mat2( 1.0, 0.0, 0.0, 1.0),
mat2(-1.0, 0.0, 0.0, 1.0),
mat2( 0.0, -1.0, 1.0, 0.0),
mat2( 0.0, 1.0, 1.0, 0.0),
mat2(-1.0, 0.0, 0.0, -1.0),
mat2( 1.0, 0.0, 0.0, -1.0),
mat2( 0.0, 1.0, -1.0, 0.0),
mat2( 0.0, -1.0, -1.0, 0.0)
);
vec2[] flipRotOffset = vec2[](
vec2(0, 0),
vec2(1, 0),
vec2(0, 1),
vec2(0, 0),
vec2(1, 1),
vec2(0, 1),
vec2(1, 0),
vec2(1, 1)
);
vec2 uvFlipRot(int op, vec2 uv) {
return flipRotMat[op] * uv + flipRotOffset[op] * tileSizeInPx;
}
void main() {
// READ THE FUCKING MANUAL, YOU DONKEY !! //
@@ -83,13 +118,14 @@ void main() {
vec4 tileFromMap = texture(tilemap, flippedFragCoord / overscannedScreenDimension); // raw tile number
int tile = getTileFromColor(tileFromMap);
int breakage = getBreakageFromColor(tileFromMap);
int flipRot = getTileFlipRotFromColor(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 uvCoordForTile = uvFlipRot(flipRot, 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;