Optimized memory allocations slightly by allocating the Point2f at the beginning

This commit is contained in:
Josh Larson
2022-07-18 19:05:23 -05:00
parent 33f9d4fb6a
commit f95f6d452e
18 changed files with 74 additions and 66 deletions
@@ -1,6 +1,6 @@
package com.projectswg.common.data.swgiff.parsers.terrain
import com.projectswg.common.data.location.Rectangle2f
import com.projectswg.common.data.location.Point2f
import com.projectswg.common.data.swgiff.IffChunk
import com.projectswg.common.data.swgiff.IffForm
import com.projectswg.common.data.swgiff.parsers.SWGParser
@@ -176,7 +176,7 @@ class TerrainTemplate : SWGParser {
var height = -Float.MAX_VALUE
if (useGlobalWaterTable)
height = globalWaterTableHeight
height = max(height, getWaterHeightRecursive(x, z, topTerrainLayer))
height = max(height, getWaterHeightRecursive(Point2f(x, z), topTerrainLayer))
return if (height == -Float.MAX_VALUE) Float.NaN else height
}
@@ -246,27 +246,28 @@ class TerrainTemplate : SWGParser {
}
private fun getHeightAt(x: Float, z: Float): HeightInformation {
val p = Point2f(x, z)
val height = HeightInformation(1f, 0f)
getLayerHeight(topTerrainLayer, x, z, height)
getLayerHeight(topTerrainLayer, p, height)
return height
}
private fun getLayerHeight(layer: TerrainListLayer, x: Float, z: Float, height: HeightInformation) {
private fun getLayerHeight(layer: TerrainListLayer, p: Point2f, height: HeightInformation) {
var transformValue = if (layer.boundaries.isEmpty()) 1f else 0f
val rectangle = layer.extent
for (boundary in layer.boundaries) {
if (!boundary.isContained(x, z))
if (!boundary.isContained(p))
continue
transformValue = max(transformValue, calculateFeathering(boundary.process(x, z), boundary.featherType))
transformValue = max(transformValue, calculateFeathering(boundary.process(p), boundary.featherType))
}
if (layer.invertBoundaries)
transformValue = 1.0f - transformValue
for (filter in layer.filters) {
transformValue = min(transformValue, calculateFeathering(filter.process(x, z, transformValue, height.height, rectangle, lookupInformation), filter.featherType))
transformValue = min(transformValue, calculateFeathering(filter.process(p, transformValue, height.height, rectangle, lookupInformation), filter.featherType))
if (transformValue == 0f)
break
}
@@ -278,7 +279,7 @@ class TerrainTemplate : SWGParser {
if (transformValue > 0f) {
for (affector in layer.heights) {
height.height = affector.process(x, z, transformValue * height.transformValue, height.height, lookupInformation)
height.height = affector.process(p, transformValue * height.transformValue, height.height, lookupInformation)
}
}
@@ -287,7 +288,7 @@ class TerrainTemplate : SWGParser {
transformValue = 1f
val returnHeight = HeightInformation(transformValue * height.transformValue, height.height)
for (child in layer.children) {
getLayerHeight(child, x, z, returnHeight)
getLayerHeight(child, p, returnHeight)
}
height.height = returnHeight.height
}
@@ -302,17 +303,17 @@ class TerrainTemplate : SWGParser {
}
}
private fun getWaterHeightRecursive(x: Float, z: Float, layer: TerrainListLayer): Float {
private fun getWaterHeightRecursive(p: Point2f, layer: TerrainListLayer): Float {
var waterHeight = -Float.MAX_VALUE
for (boundary in layer.boundaries) {
if (boundary is BoundaryPolygon && boundary.useWaterHeight && boundary.isContained(x, z)) {
if (boundary is BoundaryPolygon && boundary.useWaterHeight && boundary.isContained(p)) {
waterHeight = max(waterHeight, boundary.waterHeight)
} else if (boundary is BoundaryRectangle && boundary.useWaterHeight && boundary.isContained(x, z)) {
} else if (boundary is BoundaryRectangle && boundary.useWaterHeight && boundary.isContained(p)) {
waterHeight = max(waterHeight, boundary.waterHeight)
}
}
for (child in layer.children) {
waterHeight = max(waterHeight, getWaterHeightRecursive(x, z, child))
waterHeight = max(waterHeight, getWaterHeightRecursive(p, child))
}
return waterHeight
}
@@ -1,5 +1,6 @@
package com.projectswg.common.data.swgiff.parsers.terrain.affectors
import com.projectswg.common.data.location.Point2f
import com.projectswg.common.data.swgiff.IffChunk
import com.projectswg.common.data.swgiff.IffForm
import com.projectswg.common.data.swgiff.parsers.SWGParser
@@ -10,7 +11,7 @@ class AffectorHeightConstant : AffectorHeightLayer(), SWGParser {
private var transformType = 0
private var height = 0f
override fun process(x: Float, z: Float, transformAmount: Float, baseValue: Float, terrainInfo: TerrainInfoLookup): Float {
override fun process(p: Point2f, transformAmount: Float, baseValue: Float, terrainInfo: TerrainInfoLookup): Float {
if (transformAmount <= 0f)
return baseValue
@@ -1,5 +1,6 @@
package com.projectswg.common.data.swgiff.parsers.terrain.affectors
import com.projectswg.common.data.location.Point2f
import com.projectswg.common.data.swgiff.IffChunk
import com.projectswg.common.data.swgiff.IffForm
import com.projectswg.common.data.swgiff.parsers.SWGParser
@@ -11,11 +12,11 @@ class AffectorHeightFractal : AffectorHeightLayer(), SWGParser {
private var transformType = 0
private var height = 0f
override fun process(x: Float, z: Float, transformAmount: Float, baseValue: Float, terrainInfo: TerrainInfoLookup): Float {
override fun process(p: Point2f, transformAmount: Float, baseValue: Float, terrainInfo: TerrainInfoLookup): Float {
if (transformAmount == 0f)
return baseValue
val fractal = terrainInfo.fractals[fractalId] ?: return 0f
val noiseResult = fractal.getNoise(x, z) * height
val noiseResult = fractal.getNoise(p.x, p.z) * height
return when (transformType) {
1 -> baseValue + transformAmount * noiseResult
@@ -1,11 +1,12 @@
package com.projectswg.common.data.swgiff.parsers.terrain.affectors
import com.projectswg.common.data.location.Point2f
import com.projectswg.common.data.swgiff.parsers.terrain.TerrainInfoLookup
import com.projectswg.common.data.swgiff.parsers.terrain.TerrainLayer
abstract class AffectorHeightLayer : TerrainLayer() {
abstract fun process(x: Float, z: Float, transformAmount: Float, baseValue: Float, terrainInfo: TerrainInfoLookup): Float
abstract fun process(p: Point2f, transformAmount: Float, baseValue: Float, terrainInfo: TerrainInfoLookup): Float
}
@@ -23,37 +23,35 @@ class AffectorHeightRoad : AffectorHeightLayer(), SWGParser {
private var hasFixedHeights = false
private var extent = Rectangle2f(Float.MAX_VALUE, Float.MAX_VALUE, -Float.MAX_VALUE, -Float.MAX_VALUE)
override fun process(x: Float, z: Float, transformAmount: Float, baseValue: Float, terrainInfo: TerrainInfoLookup): Float {
override fun process(p: Point2f, transformAmount: Float, baseValue: Float, terrainInfo: TerrainInfoLookup): Float {
if (transformAmount <= 0)
return baseValue
val p = Point2f(x, z)
if (!extent.isWithin(p, width))
return baseValue
val halfWidth = width / 2f
val halfWidthSquared = halfWidth*halfWidth
val closestLine = p.getClosestLineOnPolygon(vertices, closed=false)
val startIndex = vertices.indexOf(closestLine.p2)
val matchPoint = p.getClosestPointOnPolygon(if (startIndex < segments.size) segments[startIndex] else segments[0], closed=false)
if (closestLine.squaredDistance >= halfWidthSquared)
return baseValue
if (hasFixedHeights)
return getRampedHeight(x, z, baseValue)
return getRampedHeight(p, closestLine, baseValue)
val startIndex = vertices.indexOf(closestLine.p2)
val matchPoint = p.getClosestPointOnPolygon(if (startIndex < segments.size) segments[startIndex] else segments[0], closed=false)
val t = sqrt(closestLine.squaredDistance) / halfWidth
if (t <= (1 - featheringAmount))
return matchPoint.y.toFloat()
return matchPoint.y.toFloat() + (baseValue - matchPoint.y.toFloat()) * t
}
private fun getRampedHeight(x: Float, y: Float, baseValue: Float): Float {
val p = Point2f(x, y)
private fun getRampedHeight(p: Point2f, closestLine: Point2f.ClosestLine2f, baseValue: Float): Float {
val widthSquared = width*width / 4f
val closestLine = p.getClosestLineOnPolygon(vertices, closed=false)
if (closestLine.squaredDistance >= widthSquared)
return baseValue
@@ -1,5 +1,6 @@
package com.projectswg.common.data.swgiff.parsers.terrain.affectors
import com.projectswg.common.data.location.Point2f
import com.projectswg.common.data.swgiff.IffChunk
import com.projectswg.common.data.swgiff.IffForm
import com.projectswg.common.data.swgiff.parsers.SWGParser
@@ -10,7 +11,7 @@ class AffectorHeightTerrace : AffectorHeightLayer(), SWGParser {
private var fraction = 0f
private var height = 0f
override fun process(x: Float, z: Float, transformAmount: Float, baseValue: Float, terrainInfo: TerrainInfoLookup): Float {
override fun process(p: Point2f, transformAmount: Float, baseValue: Float, terrainInfo: TerrainInfoLookup): Float {
if (transformAmount <= 0f || height <= 0f)
return baseValue
@@ -1,5 +1,6 @@
package com.projectswg.common.data.swgiff.parsers.terrain.boundaries
import com.projectswg.common.data.location.Point2f
import com.projectswg.common.data.location.Rectangle2f
import com.projectswg.common.data.swgiff.IffChunk
import com.projectswg.common.data.swgiff.IffForm
@@ -12,19 +13,19 @@ class BoundaryCircle : BoundaryLayer(), SWGParser {
private var radius = 0f
private var radiusSquared = 0f
override fun isContained(x: Float, z: Float): Boolean {
val rX = x - this.x
val rZ = z - this.z
override fun isContained(p: Point2f): Boolean {
val rX = p.x - this.x
val rZ = p.z - this.z
return rX*rX + rZ*rZ <= radius*radius
}
override fun process(x: Float, z: Float): Float {
if (!isContained(x, z))
override fun process(p: Point2f): Float {
if (!isContained(p))
return 0f
val distanceX = x - this.x
val distanceZ = z - this.z
val distanceX = p.x - this.x
val distanceZ = p.z - this.z
val distanceSquared = distanceX*distanceX + distanceZ*distanceZ
if (distanceSquared >= radiusSquared)
return 0f
@@ -1,5 +1,6 @@
package com.projectswg.common.data.swgiff.parsers.terrain.boundaries
import com.projectswg.common.data.location.Point2f
import com.projectswg.common.data.location.Rectangle2f
import com.projectswg.common.data.swgiff.parsers.terrain.TerrainLayer
@@ -9,8 +10,8 @@ abstract class BoundaryLayer : TerrainLayer() {
var featherAmount = 0f
open val hasWater = false
abstract fun isContained(x: Float, z: Float): Boolean
abstract fun process(x: Float, z: Float): Float
abstract fun isContained(p: Point2f): Boolean
abstract fun process(p: Point2f): Float
open var extent = Rectangle2f(0f, 0f, 0f, 0f)
protected set
@@ -13,15 +13,14 @@ class BoundaryPolyLine : BoundaryLayer() {
private var vertices = ArrayList<Point2f>()
private var lineWidth = 0f
override fun isContained(x: Float, z: Float): Boolean {
return extent.isWithin(x, z)
override fun isContained(p: Point2f): Boolean {
return extent.isWithin(p)
}
override fun process(x: Float, z: Float): Float {
if (!isContained(x, z))
override fun process(p: Point2f): Float {
if (!isContained(p))
return 0.0f
val p = Point2f(x, z)
val closestPoint = p.getClosestPointOnPolygon(vertices, closed=false)
val closestDistance = p.squaredDistanceTo(closestPoint)
@@ -21,8 +21,8 @@ class BoundaryPolygon : BoundaryLayer() {
var waterType = 0
private set
override fun isContained(x: Float, z: Float): Boolean {
if (!extent.isWithin(x, z))
override fun isContained(p: Point2f): Boolean {
if (!extent.isWithin(p))
return false
var j = vertices.size - 1
@@ -32,20 +32,19 @@ class BoundaryPolygon : BoundaryLayer() {
val v2 = vertices[j]
j = i
if ((((v1.z <= z) && (z < v2.z)) || ((v2.z <= z) && (z < v1.z))) && x < (v2.x - v1.x) * (z - v1.z) / (v2.z - v1.z) + v1.x)
if ((((v1.z <= p.z) && (p.z < v2.z)) || ((v2.z <= p.z) && (p.z < v1.z))) && p.x < (v2.x - v1.x) * (p.z - v1.z) / (v2.z - v1.z) + v1.x)
crossings++
}
return crossings % 2 == 1
}
override fun process(x: Float, z: Float): Float {
if (!isContained(x, z))
override fun process(p: Point2f): Float {
if (!isContained(p))
return 0.0f
if (featherAmount == 0f)
return 1.0f
val p = Point2f(x, z)
val closestPoint = p.getClosestPointOnPolygon(vertices)
val closestDistance = p.squaredDistanceTo(closestPoint)
@@ -1,5 +1,6 @@
package com.projectswg.common.data.swgiff.parsers.terrain.boundaries
import com.projectswg.common.data.location.Point2f
import com.projectswg.common.data.location.Rectangle2f
import com.projectswg.common.data.swgiff.IffChunk
import com.projectswg.common.data.swgiff.IffForm
@@ -19,12 +20,12 @@ class BoundaryRectangle : BoundaryLayer() {
var waterType = 0
private set
override fun isContained(x: Float, z: Float): Boolean {
return extent.isWithin(x, z)
override fun isContained(p: Point2f): Boolean {
return extent.isWithin(p)
}
override fun process(x: Float, z: Float): Float {
if (!isContained(x, z))
override fun process(p: Point2f): Float {
if (!isContained(p))
return 0f
val minX = extent.minX
val minZ = extent.minZ
@@ -33,11 +34,10 @@ class BoundaryRectangle : BoundaryLayer() {
val feather = min(maxX - minX, maxZ - minZ) * featherAmount / 2f
if (x in minX+feather..maxX-feather && z in minZ+feather..maxZ-feather)
if (p.x in minX+feather..maxX-feather && p.z in minZ+feather..maxZ-feather)
return 1f
return min(feather, min(x - minX, min(maxX - x, min(z - minZ, maxZ - z)))) / feather
return min(feather, min(p.x - minX, min(maxX - p.x, min(p.z - minZ, maxZ - p.z)))) / feather
}
override fun read(form: IffForm) {
@@ -1,11 +1,11 @@
package com.projectswg.common.data.swgiff.parsers.terrain.filters
import com.projectswg.common.data.location.Point2f
import com.projectswg.common.data.location.Rectangle2f
import com.projectswg.common.data.swgiff.IffChunk
import com.projectswg.common.data.swgiff.IffForm
import com.projectswg.common.data.swgiff.parsers.terrain.TerrainInfoLookup
import com.projectswg.common.data.swgiff.parsers.terrain.bitmap.TargaBitmap
import kotlin.math.min
class FilterBitmap : FilterLayer() {
@@ -15,15 +15,15 @@ class FilterBitmap : FilterLayer() {
private var gain = 0f
private var bitmap: TargaBitmap? = null
override fun process(x: Float, z: Float, transformValue: Float, baseValue: Float, rectangle: Rectangle2f, terrainInfo: TerrainInfoLookup): Float {
override fun process(p: Point2f, transformValue: Float, baseValue: Float, rectangle: Rectangle2f, terrainInfo: TerrainInfoLookup): Float {
if (bitmap == null)
bitmap = terrainInfo.bitmaps[bitmapId]?.bitmap
val bitmap = bitmap ?: return 1f // Didnt find bitmap for filter
val width = bitmap.width
val height = bitmap.height
val transformedX = (x - rectangle.minX) * width / (rectangle.maxX - rectangle.minX)
val transformedZ = (z - rectangle.minZ) * height / (rectangle.maxZ - rectangle.minZ)
val transformedX = (p.x - rectangle.minX) * width / (rectangle.maxX - rectangle.minX)
val transformedZ = (p.z - rectangle.minZ) * height / (rectangle.maxZ - rectangle.minZ)
val bitmapZ0 = transformedZ.toInt()
val bitmapX0 = transformedX.toInt()
val bitmapX1 = bitmapX0 + 1
@@ -1,17 +1,17 @@
package com.projectswg.common.data.swgiff.parsers.terrain.filters
import com.projectswg.common.data.location.Point2f
import com.projectswg.common.data.location.Rectangle2f
import com.projectswg.common.data.swgiff.IffChunk
import com.projectswg.common.data.swgiff.IffForm
import com.projectswg.common.data.swgiff.parsers.terrain.TerrainInfoLookup
import com.projectswg.common.data.swgiff.parsers.terrain.bitmap.TargaBitmap
class FilterDirection : FilterLayer() {
private var minAngle = 0f
private var maxAngle = 0f
override fun process(x: Float, z: Float, transformValue: Float, baseValue: Float, rectangle: Rectangle2f, terrainInfo: TerrainInfoLookup): Float {
override fun process(p: Point2f, transformValue: Float, baseValue: Float, rectangle: Rectangle2f, terrainInfo: TerrainInfoLookup): Float {
TODO("unimplemented")
}
@@ -1,5 +1,6 @@
package com.projectswg.common.data.swgiff.parsers.terrain.filters
import com.projectswg.common.data.location.Point2f
import com.projectswg.common.data.location.Rectangle2f
import com.projectswg.common.data.swgiff.IffChunk
import com.projectswg.common.data.swgiff.IffForm
@@ -12,9 +13,9 @@ class FilterFractal : FilterLayer() {
var max = 0f
var step = 0f
override fun process(x: Float, z: Float, transformValue: Float, baseValue: Float, rectangle: Rectangle2f, terrainInfo: TerrainInfoLookup): Float {
override fun process(p: Point2f, transformValue: Float, baseValue: Float, rectangle: Rectangle2f, terrainInfo: TerrainInfoLookup): Float {
val fractal = terrainInfo.fractals[fractalId] ?: return 0f
val noiseResult = fractal.getNoise(x, z) * step
val noiseResult = fractal.getNoise(p.x, p.z) * step
if (noiseResult !in min..max)
return 0f
@@ -24,7 +25,7 @@ class FilterFractal : FilterLayer() {
return (noiseResult - min) / feather
if (noiseResult > max - feather)
return (max - noiseResult) / feather
return 1f;
return 1f
}
override fun read(form: IffForm) {
@@ -1,5 +1,6 @@
package com.projectswg.common.data.swgiff.parsers.terrain.filters
import com.projectswg.common.data.location.Point2f
import com.projectswg.common.data.location.Rectangle2f
import com.projectswg.common.data.swgiff.IffChunk
import com.projectswg.common.data.swgiff.IffForm
@@ -10,7 +11,7 @@ class FilterHeight : FilterLayer() {
private var minHeight = 0f
private var maxHeight = 0f
override fun process(x: Float, z: Float, transformValue: Float, baseValue: Float, rectangle: Rectangle2f, terrainInfo: TerrainInfoLookup): Float {
override fun process(p: Point2f, transformValue: Float, baseValue: Float, rectangle: Rectangle2f, terrainInfo: TerrainInfoLookup): Float {
if (baseValue <= minHeight || baseValue >= maxHeight)
return 0f
@@ -1,5 +1,6 @@
package com.projectswg.common.data.swgiff.parsers.terrain.filters
import com.projectswg.common.data.location.Point2f
import com.projectswg.common.data.location.Rectangle2f
import com.projectswg.common.data.swgiff.parsers.terrain.TerrainInfoLookup
import com.projectswg.common.data.swgiff.parsers.terrain.TerrainLayer
@@ -9,6 +10,6 @@ abstract class FilterLayer : TerrainLayer() {
var featherType = 0
var featherAmount = 0f
abstract fun process(x: Float, z: Float, transformValue: Float, baseValue: Float, rectangle: Rectangle2f, terrainInfo: TerrainInfoLookup): Float
abstract fun process(p: Point2f, transformValue: Float, baseValue: Float, rectangle: Rectangle2f, terrainInfo: TerrainInfoLookup): Float
}
@@ -1,5 +1,6 @@
package com.projectswg.common.data.swgiff.parsers.terrain.filters
import com.projectswg.common.data.location.Point2f
import com.projectswg.common.data.location.Rectangle2f
import com.projectswg.common.data.swgiff.IffChunk
import com.projectswg.common.data.swgiff.IffForm
@@ -9,7 +10,7 @@ class FilterShader : FilterLayer() {
private var shaderId: Int = 0
override fun process(x: Float, z: Float, transformValue: Float, baseValue: Float, rectangle: Rectangle2f, terrainInfo: TerrainInfoLookup): Float {
override fun process(p: Point2f, transformValue: Float, baseValue: Float, rectangle: Rectangle2f, terrainInfo: TerrainInfoLookup): Float {
return 0f
}
@@ -1,5 +1,6 @@
package com.projectswg.common.data.swgiff.parsers.terrain.filters
import com.projectswg.common.data.location.Point2f
import com.projectswg.common.data.location.Rectangle2f
import com.projectswg.common.data.swgiff.IffChunk
import com.projectswg.common.data.swgiff.IffForm
@@ -15,7 +16,7 @@ class FilterSlope : FilterLayer() {
private var minAngleSin = 0f
private var maxAngleSin = 0f
override fun process(x: Float, z: Float, transformValue: Float, baseValue: Float, rectangle: Rectangle2f, terrainInfo: TerrainInfoLookup): Float {
override fun process(p: Point2f, transformValue: Float, baseValue: Float, rectangle: Rectangle2f, terrainInfo: TerrainInfoLookup): Float {
return if (baseValue > minAngleSin && baseValue < maxAngleSin) {
val featherResult = (maxAngleSin - minAngleSin * featherAmount * 0.5).toFloat()
if (minAngleSin + featherResult <= baseValue) {