diff --git a/app/src/main/java/com/mirenkov/ktheightmap/MainActivity.kt b/app/src/main/java/com/mirenkov/ktheightmap/MainActivity.kt index 48b87a0..e861aae 100644 --- a/app/src/main/java/com/mirenkov/ktheightmap/MainActivity.kt +++ b/app/src/main/java/com/mirenkov/ktheightmap/MainActivity.kt @@ -23,6 +23,7 @@ import androidx.compose.material3.Slider import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableFloatStateOf +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -72,6 +73,8 @@ class MainActivity : ComponentActivity() { @Composable fun Main(vm: TileViewModel = viewModel()) { val sliderValue = rememberSaveable { mutableFloatStateOf(1F) } + val coroutineScope = rememberCoroutineScope() + val tileContainer = TileContainer(vm, coroutineScope) KtHeightMapTheme { Box(modifier = Modifier.background(color = colorScheme.background)) { Scaffold( @@ -84,6 +87,7 @@ fun Main(vm: TileViewModel = viewModel()) { gridColor = colorScheme.primary, backColor = colorScheme.background, scale = sliderValue, + tileContainer = tileContainer, modifier = Modifier.padding(innerPadding), ) } diff --git a/app/src/main/java/com/mirenkov/ktheightmap/MapCanvas.kt b/app/src/main/java/com/mirenkov/ktheightmap/MapCanvas.kt index 79aa5da..e781f84 100644 --- a/app/src/main/java/com/mirenkov/ktheightmap/MapCanvas.kt +++ b/app/src/main/java/com/mirenkov/ktheightmap/MapCanvas.kt @@ -2,8 +2,6 @@ package com.mirenkov.ktheightmap import androidx.compose.foundation.Canvas import androidx.compose.foundation.gestures.detectDragGestures -import androidx.compose.foundation.gestures.rememberTransformableState -import androidx.compose.foundation.gestures.transformable import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableFloatState @@ -13,6 +11,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.input.pointer.pointerInput @@ -21,6 +20,7 @@ fun MapCanvas( backColor: Color, gridColor: Color, scale: MutableFloatState, + tileContainer: TileContainer, modifier: Modifier = Modifier ) { val offsetX = rememberSaveable { mutableFloatStateOf(0F) } @@ -40,25 +40,43 @@ fun MapCanvas( size = size ) + val tileOffsetX = offsetX.floatValue.toInt() / TILE_SIZE.toInt() + val tileOffsetY = offsetY.floatValue.toInt() / TILE_SIZE.toInt() val strippedOffsetX = offsetX.floatValue % TILE_SIZE val strippedOffsetY = offsetY.floatValue % TILE_SIZE val level = scale.floatValue.toInt() - val strippedScale = scale.floatValue + 1 - level - val actualTileSize = TILE_SIZE * strippedScale val offset = Offset(strippedOffsetX, strippedOffsetY) - val grid = size / actualTileSize + + val grid = size / TILE_SIZE + val gridWidth = grid.width.toInt() val gridHeight = grid.height.toInt() + + val tiles = tileContainer.getTiles(tileOffsetX, tileOffsetY, tileOffsetX + gridWidth, tileOffsetY + gridHeight, level) + for (cellX in 0 .. gridWidth + 2) { - val offsetX = actualTileSize * (cellX - 1) + val tileX = tileOffsetX + cellX + val offsetX = TILE_SIZE * (cellX - 1) for (cellY in 0 .. gridHeight + 2) { - val offsetY = actualTileSize * (cellY - 1) + val tileY = tileOffsetY + cellY + val offsetY = TILE_SIZE * (cellY - 1) + + val bitmap = tiles.find { it.x == tileX && it.y == tileY && it.level == level }?.getBitmap() + + bitmap?.let { + val imageBitmap = bitmap.asImageBitmap() + drawImage( + image = imageBitmap, + topLeft = offset + Offset(offsetX, offsetY) + ) + } + drawRect( color = gridColor, - size = Size(actualTileSize, actualTileSize), + size = Size(TILE_SIZE, TILE_SIZE), topLeft = offset + Offset(offsetX, offsetY), style = Stroke(width = 4F) ) diff --git a/app/src/main/java/com/mirenkov/ktheightmap/TileContainer.kt b/app/src/main/java/com/mirenkov/ktheightmap/TileContainer.kt new file mode 100644 index 0000000..8e257d9 --- /dev/null +++ b/app/src/main/java/com/mirenkov/ktheightmap/TileContainer.kt @@ -0,0 +1,65 @@ +package com.mirenkov.ktheightmap + +import kotlinx.coroutines.CoroutineScope + +class TileContainer(private val vm: TileViewModel, private val coroutineScope: CoroutineScope) { + private val tiles: MutableList = mutableListOf() + + private var startX = 0 + private var startY = 0 + + private var endX = 0 + private var endY = 0 + + private var level = 1 + + fun getTiles(_startX: Int, _startY: Int, _endX: Int, _endY: Int, _level: Int): List { + val newParams = arrayOf( _startX, _startY, _endX, _endY, _level ) + val oldParams = arrayOf( startX, startY, endX, endY, level ) + var isInvalid = false + for (i in 0 until newParams.size) { + if (oldParams[i] != newParams[i]) { + isInvalid = true + break + } + } + + if (isInvalid) { + updateTileList(_startX, _startY, _endX, _endY, _level) + } + + updateValues(_startX, _startY, _endX, _endY, _level) + + return tiles + } + + private fun updateTileList(_startX: Int, _startY: Int, _endX: Int, _endY: Int, _level: Int) { + tiles.removeIf { + it.level != _level || + it.x < _startX || + it.x > _endX || + it.y < _startY || + it.y > _endY + } + for (x in _startX .. _endX) { + for (y in _startY .. _endY) { + if (tiles.find { it.x == x && it.y == y && it.level == _level } == null) { + val tile = vm.repository.getTile(x, y, _level) + if (tile == null) { + tiles.add(Tile(x, y, _level)) + } else { + tiles.add(tile) + } + } + } + } + } + + private fun updateValues(_startX: Int, _startY: Int, _endX: Int, _endY: Int, _level: Int) { + startX = _startX + startY = _startY + endX = _endX + endY = _endY + level = _level + } +} \ No newline at end of file diff --git a/app/src/main/java/com/mirenkov/ktheightmap/TileRepository.kt b/app/src/main/java/com/mirenkov/ktheightmap/TileRepository.kt index 655ace9..8ada061 100644 --- a/app/src/main/java/com/mirenkov/ktheightmap/TileRepository.kt +++ b/app/src/main/java/com/mirenkov/ktheightmap/TileRepository.kt @@ -3,6 +3,7 @@ package com.mirenkov.ktheightmap import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async +import kotlinx.coroutines.future.future import kotlinx.coroutines.launch class TileRepository(private val tileDao: TileDao) { @@ -12,11 +13,11 @@ class TileRepository(private val tileDao: TileDao) { coroutineScope.launch(Dispatchers.IO) { tileDao.pushTile(tile) } } - suspend fun getTile(x: Int, y: Int, level: Int): Tile? { - val tileDeferred = coroutineScope.async(Dispatchers.IO) { + fun getTile(x: Int, y: Int, level: Int): Tile? { + val tileFuture = coroutineScope.future(Dispatchers.IO) { tileDao.getTile(x, y, level) } - return tileDeferred.await() + return tileFuture.join() } fun clearTiles() {