@@ -2,14 +2,18 @@ package ua.valeriishymchuk.lobmapeditor.domain.terrain
22
33import com.google.gson.JsonArray
44import com.google.gson.JsonObject
5- import com.google.gson.JsonParser
65import com.google.gson.JsonPrimitive
6+ import com.jogamp.common.nio.Buffers
7+ import ua.valeriishymchuk.lobmapeditor.domain.terrain.HeightMap.BlobHeightCachedRenderData
8+ import ua.valeriishymchuk.lobmapeditor.domain.terrain.TerrainMap.BlobCachedRenderData
79import ua.valeriishymchuk.lobmapeditor.shared.GameConstants
810import ua.valeriishymchuk.lobmapeditor.shared.dimension.ArrayMap2d
11+ import java.nio.IntBuffer
12+ import java.util.concurrent.ConcurrentHashMap
913
10- data class Terrain (
14+ data class Terrain (
1115 val terrainMap : TerrainMap ,
12- val terrainHeight : ArrayMap2d < Int >
16+ val terrainHeight : HeightMap
1317) {
1418
1519 init {
@@ -80,7 +84,6 @@ data class Terrain (
8084 val cellsY = heightPixels / GameConstants .TILE_SIZE
8185
8286
83-
8487 // Deserialize terrain types - column-major order
8588 val terrainsArray = json.getAsJsonArray(" terrains" )
8689 val terrainMap2D = Array (cellsX) { x ->
@@ -114,14 +117,14 @@ data class Terrain (
114117
115118 return Terrain (
116119 terrainMap = TerrainMap (terrainMap2D),
117- terrainHeight = ArrayMap2d (heightMap2D)
120+ terrainHeight = HeightMap (heightMap2D)
118121 )
119122 }
120123
121124 fun ofPixels (pixelSizeX : Int = 1504, pixelSizeY : Int = 1312): Terrain {
122125 return Terrain (
123126 TerrainMap .ofPixels(pixelSizeX, pixelSizeY),
124- ArrayMap2d (Array <Array <Int >>(pixelSizeX / GameConstants .TILE_SIZE ) {
127+ HeightMap (Array <Array <Int >>(pixelSizeX / GameConstants .TILE_SIZE ) {
125128 Array <Int >(pixelSizeY / GameConstants .TILE_SIZE ) {
126129 0
127130 }
@@ -136,9 +139,175 @@ data class Terrain (
136139
137140}
138141
139- class TerrainMap (
142+ class HeightMap (
143+ map : Array <Array <Int >>
144+ ) : ArrayMap2d<Int>(map) {
145+
146+ data class BlobHeightCachedRenderData (
147+ val buffer : IntBuffer
148+ )
149+
150+ private var cachedMaxHeight: Int? = null
151+ private var cachedMinHeight: Int? = null
152+
153+ val maxHeight: Int get() {
154+ var height = cachedMaxHeight
155+ if (height == null ) {
156+ height = map.flatMap { it }.distinct().max()
157+ cachedMaxHeight = height
158+ }
159+ return height
160+ }
161+
162+ val minHeight: Int get() {
163+ var height = cachedMinHeight
164+ if (height == null ) {
165+ height = map.flatMap { it }.distinct().min()
166+ cachedMinHeight = height
167+ }
168+ return height
169+ }
170+
171+ private val cachedBlobRenderHeights = ConcurrentHashMap <Int , BlobHeightCachedRenderData >()
172+
173+ fun getHeightBlobMap (height : Int ): BlobHeightCachedRenderData {
174+ return cachedBlobRenderHeights.computeIfAbsent(height) { _ ->
175+ val buffer = Buffers .newDirectIntBuffer(sizeX * sizeY)
176+ map.flatMap { it }.forEach {
177+ if (height <= it) {
178+ buffer.put(1 )
179+ } else buffer.put(0 )
180+ }
181+ buffer.flip()
182+ BlobHeightCachedRenderData (buffer)
183+ }
184+ }
185+
186+ override fun set (x : Int , y : Int , value : Int ): Int? {
187+ val oldHeight = super .set(x, y, value) ? : return null
188+ cachedBlobRenderHeights.clear()
189+ cachedMaxHeight = null
190+ cachedMinHeight = null
191+ return oldHeight
192+ }
193+
194+
195+ }
196+
197+ class TerrainMap (
140198 map : Array <Array <TerrainType >>
141- ): ArrayMap2d<TerrainType>(map) {
199+ ) : ArrayMap2d<TerrainType>(map) {
200+
201+ private val cachedTerrainRenderTypes = ConcurrentHashMap <TerrainType , TerrainCachedRenderData >()
202+ private val cachedBlobRenderTypes = ConcurrentHashMap <TerrainType , BlobCachedRenderData >()
203+ private val cachedOverlayRenderTypes = ConcurrentHashMap <TerrainType , OverlayCachedRenderData >()
204+
205+ data class TerrainCachedRenderData (
206+ val buffer : IntBuffer ,
207+ val shouldRender : Boolean
208+ )
209+
210+ data class BlobCachedRenderData (
211+ val buffer : IntBuffer
212+ )
213+
214+ data class OverlayCachedRenderData (
215+ val buffer : IntBuffer
216+ )
217+
218+ fun getOverlayRenderMap (type : TerrainType ): OverlayCachedRenderData {
219+ return cachedOverlayRenderTypes.computeIfAbsent(type) { _ ->
220+ val buffer = Buffers .newDirectIntBuffer(sizeX * sizeY)
221+ map.flatMap { it }.forEach {
222+ if (type == it) {
223+ buffer.put(1 )
224+ } else buffer.put(0 )
225+ }
226+ buffer.flip()
227+ OverlayCachedRenderData (buffer)
228+ }
229+ }
230+
231+ fun getBlobRenderMap (type : TerrainType ): BlobCachedRenderData {
232+ return cachedBlobRenderTypes.computeIfAbsent(type) { _ ->
233+ val buffer = Buffers .newDirectIntBuffer(sizeX * sizeY)
234+
235+ map.flatMap { it }.forEach {
236+ if (type == it) {
237+ buffer.put(1 )
238+ return @forEach
239+ }
240+ if (it == TerrainType .BRIDGE && (type == TerrainType .ROAD || type == TerrainType .ROAD_WINTER || type == TerrainType .SUNKEN_ROAD )) {
241+ buffer.put(2 )
242+ return @forEach
243+ }
244+ if (type == TerrainType .BRIDGE && (it == TerrainType .ROAD || it == TerrainType .ROAD_WINTER || it == TerrainType .SUNKEN_ROAD )) {
245+ buffer.put(2 )
246+ return @forEach
247+ }
248+ if (it == TerrainType .SUNKEN_ROAD && type == TerrainType .ROAD || it == TerrainType .ROAD && type == TerrainType .SUNKEN_ROAD ) {
249+ buffer.put(2 )
250+ return @forEach
251+ }
252+ buffer.put(0 )
253+ }
254+
255+ buffer.flip()
256+
257+ BlobCachedRenderData (buffer)
258+ }
259+ }
260+
261+ fun getRenderMap (type : TerrainType ): TerrainCachedRenderData {
262+ return cachedTerrainRenderTypes.computeIfAbsent(type) { _ ->
263+ var hasSomethingToRender = false
264+
265+ val buffer = Buffers .newDirectIntBuffer(sizeX * sizeY)
266+ map.flatMap { it }.forEach {
267+ if (type == it) {
268+ hasSomethingToRender = true
269+ buffer.put(1 )
270+ return @forEach
271+ }
272+ if (it.isFarm) {
273+ hasSomethingToRender = true
274+ buffer.put(2 )
275+ return @forEach
276+ }
277+ buffer.put(0 )
278+ }
279+ buffer.flip()
280+ TerrainCachedRenderData (
281+ buffer,
282+ hasSomethingToRender
283+ )
284+
285+ }
286+ }
287+
288+ override fun set (x : Int , y : Int , value : TerrainType ): TerrainType ? {
289+ val oldTerrainType = super .set(x, y, value) ? : return null
290+ // val isFarm = value.isFarm || oldTerrainType.isFarm
291+ // cachedTerrainRenderTypes.keys.toSet().forEach { type ->
292+ // if (isFarm && type.isFarm) cachedTerrainRenderTypes.remove(type)
293+ // if (value == type || oldTerrainType == value) cachedTerrainRenderTypes.remove(type)
294+ // }
295+ // val roads = setOf(TerrainType.ROAD, TerrainType.ROAD_WINTER, TerrainType.SUNKEN_ROAD)
296+ // val isRoad = roads.contains(value) || roads.contains(oldTerrainType)
297+ // cachedBlobRenderTypes.keys.toSet().forEach { type ->
298+ // if (isRoad && roads.contains(type)) cachedBlobRenderTypes.remove(type)
299+ // if (value == type || oldTerrainType == value) cachedBlobRenderTypes.remove(type)
300+ // }
301+ // cachedOverlayRenderTypes.keys.forEach { type ->
302+ // if (value == type || oldTerrainType == value) cachedOverlayRenderTypes.remove(type)
303+ // }
304+
305+ cachedTerrainRenderTypes.clear()
306+ cachedBlobRenderTypes.clear()
307+ cachedOverlayRenderTypes.clear()
308+
309+ return oldTerrainType
310+ }
142311
143312 fun serialize (): Array <Array <Int >> {
144313 return _map .map {
0 commit comments