From ceed142d1fad2dff5c4c4f18c5c0a0d5dba1063b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20Ma=CC=88rki?= Date: Mon, 4 Nov 2024 06:54:54 +0100 Subject: [PATCH 01/12] add multiple buffers and other improvmenets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nicolas Märki --- .../mapscore/shared/map/MapCameraInterface.kt | 8 + .../jni/map/NativeMapCameraInterface.cpp | 9 + bridging/ios/MCMapCameraInterface+Private.mm | 7 + bridging/ios/MCMapCameraInterface.h | 2 + djinni/map/core.djinni | 2 + ios/graphics/Model/BaseGraphicsObject.swift | 114 ++- .../Model/Icosahedron/Icosahedron.swift | 10 +- ios/graphics/Model/Line/LineGroup2d.swift | 36 +- ios/graphics/Model/Polygon/Polygon2d.swift | 79 +- .../Model/Polygon/PolygonGroup2d.swift | 9 +- .../Model/Polygon/PolygonPatternGroup2d.swift | 9 +- ios/graphics/Model/Quad/Quad2d.swift | 17 +- ios/graphics/Model/Quad/Quad2dInstanced.swift | 26 +- .../Model/Quad/Quad2dStretchedInstanced.swift | 9 +- ios/graphics/Model/Text/Text.swift | 5 +- ios/graphics/Model/Text/TextInstanced.swift | 37 +- ios/graphics/RenderingContext.swift | 5 + ios/graphics/Shader/Metal/BaseShader.metal | 4 +- ios/graphics/Shader/Metal/LineShader.metal | 4 +- ios/maps/MCMapView.swift | 8 + shared/public/MapCameraInterface.h | 2 + shared/public/Tiled2dMapSourceImpl.h | 670 +++++++++-------- shared/src/map/camera/MapCamera3d.cpp | 696 ++++++++---------- shared/src/map/camera/MapCamera3d.h | 48 +- ...iled2dMapVectorSourceSymbolDataManager.cpp | 4 +- 25 files changed, 1069 insertions(+), 751 deletions(-) diff --git a/bridging/android/java/io/openmobilemaps/mapscore/shared/map/MapCameraInterface.kt b/bridging/android/java/io/openmobilemaps/mapscore/shared/map/MapCameraInterface.kt index 5ba7c3b9e..eb2955453 100644 --- a/bridging/android/java/io/openmobilemaps/mapscore/shared/map/MapCameraInterface.kt +++ b/bridging/android/java/io/openmobilemaps/mapscore/shared/map/MapCameraInterface.kt @@ -80,6 +80,8 @@ abstract class MapCameraInterface { abstract fun mapUnitsFromPixels(distancePx: Double): Double + abstract fun getScalingFactor(): Double + /** padding in percentage, where 1.0 = rect is half of full width and height */ abstract fun coordIsVisibleOnScreen(coord: io.openmobilemaps.mapscore.shared.map.coordinates.Coord, paddingPc: Float): Boolean @@ -316,6 +318,12 @@ abstract class MapCameraInterface { } private external fun native_mapUnitsFromPixels(_nativeRef: Long, distancePx: Double): Double + override fun getScalingFactor(): Double { + assert(!this.destroyed.get()) { error("trying to use a destroyed object") } + return native_getScalingFactor(this.nativeRef) + } + private external fun native_getScalingFactor(_nativeRef: Long): Double + override fun coordIsVisibleOnScreen(coord: io.openmobilemaps.mapscore.shared.map.coordinates.Coord, paddingPc: Float): Boolean { assert(!this.destroyed.get()) { error("trying to use a destroyed object") } return native_coordIsVisibleOnScreen(this.nativeRef, coord, paddingPc) diff --git a/bridging/android/jni/map/NativeMapCameraInterface.cpp b/bridging/android/jni/map/NativeMapCameraInterface.cpp index 0b82d8187..1549209ee 100644 --- a/bridging/android/jni/map/NativeMapCameraInterface.cpp +++ b/bridging/android/jni/map/NativeMapCameraInterface.cpp @@ -328,6 +328,15 @@ CJNIEXPORT jdouble JNICALL Java_io_openmobilemaps_mapscore_shared_map_MapCameraI } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */) } +CJNIEXPORT jdouble JNICALL Java_io_openmobilemaps_mapscore_shared_map_MapCameraInterface_00024CppProxy_native_1getScalingFactor(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef) +{ + try { + const auto& ref = ::djinni::objectFromHandleAddress<::MapCameraInterface>(nativeRef); + auto r = ref->getScalingFactor(); + return ::djinni::release(::djinni::F64::fromCpp(jniEnv, r)); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */) +} + CJNIEXPORT jboolean JNICALL Java_io_openmobilemaps_mapscore_shared_map_MapCameraInterface_00024CppProxy_native_1coordIsVisibleOnScreen(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef, ::djinni_generated::NativeCoord::JniType j_coord, jfloat j_paddingPc) { try { diff --git a/bridging/ios/MCMapCameraInterface+Private.mm b/bridging/ios/MCMapCameraInterface+Private.mm index 94dc9b14c..d95492d8e 100644 --- a/bridging/ios/MCMapCameraInterface+Private.mm +++ b/bridging/ios/MCMapCameraInterface+Private.mm @@ -288,6 +288,13 @@ - (double)mapUnitsFromPixels:(double)distancePx { } DJINNI_TRANSLATE_EXCEPTIONS() } +- (double)getScalingFactor { + try { + auto objcpp_result_ = _cppRefHandle.get()->getScalingFactor(); + return ::djinni::F64::fromCpp(objcpp_result_); + } DJINNI_TRANSLATE_EXCEPTIONS() +} + - (BOOL)coordIsVisibleOnScreen:(nonnull MCCoord *)coord paddingPc:(float)paddingPc { try { diff --git a/bridging/ios/MCMapCameraInterface.h b/bridging/ios/MCMapCameraInterface.h index dacd3951b..04ac91fd6 100644 --- a/bridging/ios/MCMapCameraInterface.h +++ b/bridging/ios/MCMapCameraInterface.h @@ -98,6 +98,8 @@ - (double)mapUnitsFromPixels:(double)distancePx; +- (double)getScalingFactor; + /** padding in percentage, where 1.0 = rect is half of full width and height */ - (BOOL)coordIsVisibleOnScreen:(nonnull MCCoord *)coord paddingPc:(float)paddingPc; diff --git a/djinni/map/core.djinni b/djinni/map/core.djinni index 44bc9d824..94c9f0751 100644 --- a/djinni/map/core.djinni +++ b/djinni/map/core.djinni @@ -181,6 +181,8 @@ map_camera_interface = interface +c { screen_pos_from_coord_zoom(coord: coord, zoom: f32): vec_2_f; map_units_from_pixels(distancePx: f64): f64; + get_scaling_factor(): f64; + # padding in percentage, where 1.0 = rect is half of full width and height coord_is_visible_on_screen(coord: coord, padding_pc: f32): bool; diff --git a/ios/graphics/Model/BaseGraphicsObject.swift b/ios/graphics/Model/BaseGraphicsObject.swift index b93bfac4f..b411012d7 100644 --- a/ios/graphics/Model/BaseGraphicsObject.swift +++ b/ios/graphics/Model/BaseGraphicsObject.swift @@ -13,6 +13,106 @@ import MapCoreSharedModule import Metal import simd + +public struct MultiBufferFloat4x4 { + // Warning: Seems like suited to be generic + // But makeBuffer &reference does not like generic data + let bufferCount = 3 // Triple buffering + var originOffsetBuffers: [MTLBuffer] = [] + var currentBufferIndex = 0 + var currentFrameId = -1 + + init(device: MTLDevice) { + var initialMutable = simd_float4x4(1.0); + for _ in 0 ..< bufferCount { + if let buffer = device + .makeBuffer( + bytes: &initialMutable, + length: MemoryLayout.stride + ) { + originOffsetBuffers.append(buffer) + } + } + } + + public mutating func getNextBuffer(_ context: RenderingContext) -> MTLBuffer? { + if context.frameId != currentFrameId { + currentBufferIndex = (currentBufferIndex + 1) % bufferCount + currentFrameId = context.frameId + } + guard currentBufferIndex < originOffsetBuffers.count else { + return nil + } + return originOffsetBuffers[currentBufferIndex] + } +} + +public struct MultiBufferFloat4 { + // Warning: Seems like suited to be generic + // But makeBuffer &reference does not like generic data + let bufferCount = 3 // Triple buffering + var originOffsetBuffers: [MTLBuffer] = [] + var currentBufferIndex = 0 + var currentFrameId = -1 + + init(device: MTLDevice) { + var initialMutable = simd_float4(0, 0, 0, 0); + for _ in 0 ..< bufferCount { + if let buffer = device + .makeBuffer( + bytes: &initialMutable, + length: MemoryLayout.stride + ) { + originOffsetBuffers.append(buffer) + } + } + } + + public mutating func getNextBuffer(_ context: RenderingContext) -> MTLBuffer? { + if context.frameId != currentFrameId { + currentBufferIndex = (currentBufferIndex + 1) % bufferCount + currentFrameId = context.frameId + } + guard currentBufferIndex < originOffsetBuffers.count else { + return nil + } + return originOffsetBuffers[currentBufferIndex] + } +} + +public struct MultiBufferFloat1 { + // Warning: Seems like suited to be generic + // But makeBuffer &reference does not like generic data + let bufferCount = 3 // Triple buffering + var originOffsetBuffers: [MTLBuffer] = [] + var currentBufferIndex = 0 + var currentFrameId = -1 + + init(device: MTLDevice) { + var initialMutable = simd_float1(0); + for _ in 0 ..< bufferCount { + if let buffer = device + .makeBuffer( + bytes: &initialMutable, + length: MemoryLayout.stride + ) { + originOffsetBuffers.append(buffer) + } + } + } + + public mutating func getNextBuffer(_ context: RenderingContext) -> MTLBuffer? { + if context.frameId != currentFrameId { + currentBufferIndex = (currentBufferIndex + 1) % bufferCount + currentFrameId = context.frameId + } + guard currentBufferIndex < originOffsetBuffers.count else { + return nil + } + return originOffsetBuffers[currentBufferIndex] + } +} + open class BaseGraphicsObject: @unchecked Sendable { private weak var context: MCRenderingContextInterface! @@ -32,17 +132,23 @@ open class BaseGraphicsObject: @unchecked Sendable { public let lock = OSLock() public var originOffset: MCVec3D = .init(x: 0, y: 0, z: 0) - public var originOffsetBuffer: MTLBuffer? + + public var originOffsetBuffers: MultiBufferFloat4 + + public var vpMatrixBuffers: MultiBufferFloat4x4 + public var mMatrixBuffers: MultiBufferFloat4x4 public init(device: MTLDevice, sampler: MTLSamplerState, label: String = "") { self.device = device self.sampler = sampler self.label = label - - var originOffset: simd_float4 = simd_float4(0, 0, 0, 0) - originOffsetBuffer = device.makeBuffer(bytes: &originOffset, length: MemoryLayout.stride, options: []) + self.originOffsetBuffers = .init(device: device) + self.vpMatrixBuffers = .init(device: device) + self.mMatrixBuffers = .init(device: device) } + + open func render(encoder _: MTLRenderCommandEncoder, context _: RenderingContext, renderPass _: MCRenderPassConfig, diff --git a/ios/graphics/Model/Icosahedron/Icosahedron.swift b/ios/graphics/Model/Icosahedron/Icosahedron.swift index e84fd4be0..5f84df3b5 100644 --- a/ios/graphics/Model/Icosahedron/Icosahedron.swift +++ b/ios/graphics/Model/Icosahedron/Icosahedron.swift @@ -69,9 +69,12 @@ final class Icosahedron: BaseGraphicsObject, @unchecked Sendable { shader.preRender(context) encoder.setVertexBuffer(verticesBuffer, offset: 0, index: 0) + + let vpMatrixBuffer = vpMatrixBuffers.getNextBuffer(context) if let matrixPointer = UnsafeRawPointer(bitPattern: Int(vpMatrix)) { - encoder.setVertexBytes(matrixPointer, length: 64, index: 1) + vpMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) } + encoder.setVertexBuffer(vpMatrixBuffer, offset: 0, index: 1) encoder.drawIndexedPrimitives(type: .triangle, indexCount: indicesCount, @@ -120,9 +123,12 @@ extension Icosahedron: MCMaskingObjectInterface { shader.preRender(context) encoder.setVertexBuffer(verticesBuffer, offset: 0, index: 0) + + let vpMatrixBuffer = vpMatrixBuffers.getNextBuffer(context) if let matrixPointer = UnsafeRawPointer(bitPattern: Int(vpMatrix)) { - encoder.setVertexBytes(matrixPointer, length: 64, index: 1) + vpMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) } + encoder.setVertexBuffer(vpMatrixBuffer, offset: 0, index: 1) encoder.drawIndexedPrimitives(type: .triangle, indexCount: indicesCount, diff --git a/ios/graphics/Model/Line/LineGroup2d.swift b/ios/graphics/Model/Line/LineGroup2d.swift index ba7a1d63d..1537ab92e 100644 --- a/ios/graphics/Model/Line/LineGroup2d.swift +++ b/ios/graphics/Model/Line/LineGroup2d.swift @@ -25,17 +25,22 @@ final class LineGroup2d: BaseGraphicsObject, @unchecked Sendable { private var customScreenPixelFactor: Float = 0 private var tileOriginBuffer: MTLBuffer? + private var debugTileOriginBuffers: MultiBufferFloat4 + private var debugRenderOriginBuffers: MultiBufferFloat4 init(shader: MCShaderProgramInterface, metalContext: MetalContext) { guard let shader = shader as? LineGroupShader else { fatalError("LineGroup2d only supports LineGroupShader") } self.shader = shader + debugTileOriginBuffers = MultiBufferFloat4(device: metalContext.device) + debugRenderOriginBuffers = MultiBufferFloat4(device: metalContext.device) super.init(device: metalContext.device, sampler: metalContext.samplerLibrary.value(Sampler.magLinear.rawValue)!, label: "LineGroup2d") var originOffset: simd_float4 = simd_float4(0, 0, 0, 0) tileOriginBuffer = metalContext.device.makeBuffer(bytes: &originOffset, length: MemoryLayout.stride, options: []) + } private func setupStencilBufferDescriptor() { @@ -115,17 +120,39 @@ final class LineGroup2d: BaseGraphicsObject, @unchecked Sendable { encoder.setVertexBuffer(lineVerticesBuffer, offset: 0, index: 0) + let vpMatrixBuffer = vpMatrixBuffers.getNextBuffer(context) if let matrixPointer = UnsafeRawPointer(bitPattern: Int(vpMatrix)) { - encoder.setVertexBytes(matrixPointer, length: 64, index: 1) + vpMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) } + encoder.setVertexBuffer(vpMatrixBuffer, offset: 0, index: 1) + + let originOffsetBuffer = originOffsetBuffers.getNextBuffer(context) if let bufferPointer = originOffsetBuffer?.contents().assumingMemoryBound(to: simd_float4.self) { bufferPointer.pointee.x = Float(originOffset.x - origin.x) bufferPointer.pointee.y = Float(originOffset.y - origin.y) bufferPointer.pointee.z = Float(originOffset.z - origin.z) } + let debugTileOriginBuffer = debugTileOriginBuffers.getNextBuffer(context) + if let bufferPointer = debugTileOriginBuffer?.contents().assumingMemoryBound( + to: simd_float4.self + ) { + bufferPointer.pointee.x = Float(originOffset.x) + bufferPointer.pointee.y = Float(originOffset.y) + bufferPointer.pointee.z = Float(originOffset.z) + } + let debugRenderOriginBuffer = debugRenderOriginBuffers.getNextBuffer(context) + if let bufferPointer = debugRenderOriginBuffer?.contents().assumingMemoryBound( + to: simd_float4.self + ) { + bufferPointer.pointee.x = Float(origin.x) + bufferPointer.pointee.y = Float(origin.y) + bufferPointer.pointee.z = Float(origin.z) + } encoder.setVertexBuffer(originOffsetBuffer, offset: 0, index: 5) encoder.setVertexBuffer(tileOriginBuffer, offset: 0, index: 6) + encoder.setVertexBuffer(debugTileOriginBuffer, offset: 0, index: 7) + encoder.setVertexBuffer(debugRenderOriginBuffer, offset: 0, index: 8) encoder.drawIndexedPrimitives(type: .triangle, indexCount: indicesCount, @@ -136,6 +163,10 @@ final class LineGroup2d: BaseGraphicsObject, @unchecked Sendable { if !isMasked { context.clearStencilBuffer() } + + assert(Polygon2d.renderOrigin?.x == origin.x) + assert(Polygon2d.renderOrigin?.y == origin.y) + assert(Polygon2d.renderOrigin?.z == origin.z) } } @@ -158,6 +189,9 @@ extension LineGroup2d: MCLineGroup2dInterface { bufferPointer.pointee.y = originOffset.yF bufferPointer.pointee.z = originOffset.zF } + else { + fatalError() + } self.lineVerticesBuffer.copyOrCreate(from: lines, device: device) self.lineIndicesBuffer.copyOrCreate(from: indices, device: device) if self.lineVerticesBuffer != nil, self.lineIndicesBuffer != nil { diff --git a/ios/graphics/Model/Polygon/Polygon2d.swift b/ios/graphics/Model/Polygon/Polygon2d.swift index d32c9e17e..c17812620 100644 --- a/ios/graphics/Model/Polygon/Polygon2d.swift +++ b/ios/graphics/Model/Polygon/Polygon2d.swift @@ -23,11 +23,20 @@ final class Polygon2d: BaseGraphicsObject, @unchecked Sendable { private var stencilState: MTLDepthStencilState? private var renderPassStencilState: MTLDepthStencilState? + private var debugTileOriginBuffers: MultiBufferFloat4 + private var debugRenderOriginBuffers: MultiBufferFloat4 + + static var renderOrigin: MCVec3D? + init(shader: MCShaderProgramInterface, metalContext: MetalContext) { self.shader = shader + debugTileOriginBuffers = MultiBufferFloat4(device: metalContext.device) + debugRenderOriginBuffers = MultiBufferFloat4(device: metalContext.device) super.init(device: metalContext.device, sampler: metalContext.samplerLibrary.value(Sampler.magLinear.rawValue)!, label: "Polygon2d") + + } override func render(encoder: MTLRenderCommandEncoder, @@ -79,24 +88,54 @@ final class Polygon2d: BaseGraphicsObject, @unchecked Sendable { shader.preRender(context) encoder.setVertexBuffer(verticesBuffer, offset: 0, index: 0) + + let vpMatrixBuffer = vpMatrixBuffers.getNextBuffer(context) if let matrixPointer = UnsafeRawPointer(bitPattern: Int(vpMatrix)) { - encoder.setVertexBytes(matrixPointer, length: 64, index: 1) + vpMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) } + encoder.setVertexBuffer(vpMatrixBuffer, offset: 0, index: 1) + + let mMatrixBuffer = mMatrixBuffers.getNextBuffer(context) if let matrixPointer = UnsafeRawPointer(bitPattern: Int(mMatrix)) { - encoder.setVertexBytes(matrixPointer, length: 64, index: 2) + vpMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) } + encoder.setVertexBuffer(mMatrixBuffer, offset: 0, index: 2) + + + let originOffsetBuffer = originOffsetBuffers.getNextBuffer(context) if let bufferPointer = originOffsetBuffer?.contents().assumingMemoryBound(to: simd_float4.self) { bufferPointer.pointee.x = Float(originOffset.x - origin.x) bufferPointer.pointee.y = Float(originOffset.y - origin.y) bufferPointer.pointee.z = Float(originOffset.z - origin.z) } + let debugTileOriginBuffer = debugTileOriginBuffers.getNextBuffer(context) + if let bufferPointer = debugTileOriginBuffer?.contents().assumingMemoryBound( + to: simd_float4.self + ) { + bufferPointer.pointee.x = Float(originOffset.x) + bufferPointer.pointee.y = Float(originOffset.y) + bufferPointer.pointee.z = Float(originOffset.z) + } + let debugRenderOriginBuffer = debugRenderOriginBuffers.getNextBuffer(context) + if let bufferPointer = debugRenderOriginBuffer?.contents().assumingMemoryBound( + to: simd_float4.self + ) { + bufferPointer.pointee.x = Float(origin.x) + bufferPointer.pointee.y = Float(origin.y) + bufferPointer.pointee.z = Float(origin.z) + } encoder.setVertexBuffer(originOffsetBuffer, offset: 0, index: 3) + encoder.setVertexBuffer(debugTileOriginBuffer, offset: 0, index: 4) + encoder.setVertexBuffer(debugRenderOriginBuffer, offset: 0, index: 5) encoder.drawIndexedPrimitives(type: .triangle, indexCount: indicesCount, indexType: .uint16, indexBuffer: indicesBuffer, indexBufferOffset: 0) + + + debugRenderOriginBuffer?.didModifyRange(0 ..< 1) } private func setupStencilStates() { @@ -114,6 +153,10 @@ final class Polygon2d: BaseGraphicsObject, @unchecked Sendable { stencilState = device.makeDepthStencilState(descriptor: s2) } + + static var offsetX: Double = 0 + static var offsetY: Double = 0 + static var offsetZ: Double = 0 } extension Polygon2d: MCMaskingObjectInterface { @@ -155,26 +198,54 @@ extension Polygon2d: MCMaskingObjectInterface { encoder.setVertexBuffer(verticesBuffer, offset: 0, index: 0) + let vpMatrixBuffer = vpMatrixBuffers.getNextBuffer(context) if let matrixPointer = UnsafeRawPointer(bitPattern: Int(vpMatrix)) { - encoder.setVertexBytes(matrixPointer, length: 64, index: 1) + vpMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) } + encoder.setVertexBuffer(vpMatrixBuffer, offset: 0, index: 1) + let mMatrixBuffer = mMatrixBuffers.getNextBuffer(context) if let matrixPointer = UnsafeRawPointer(bitPattern: Int(mMatrix)) { - encoder.setVertexBytes(matrixPointer, length: 64, index: 2) + vpMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) } + encoder.setVertexBuffer(mMatrixBuffer, offset: 0, index: 2) + let originOffsetBuffer = originOffsetBuffers.getNextBuffer(context) if let bufferPointer = originOffsetBuffer?.contents().assumingMemoryBound(to: simd_float4.self) { bufferPointer.pointee.x = Float(originOffset.x - origin.x) bufferPointer.pointee.y = Float(originOffset.y - origin.y) bufferPointer.pointee.z = Float(originOffset.z - origin.z) } + let debugTileOriginBuffer = debugTileOriginBuffers.getNextBuffer(context) + if let bufferPointer = debugTileOriginBuffer?.contents().assumingMemoryBound( + to: simd_float4.self + ) { + bufferPointer.pointee.x = Float(originOffset.x) + bufferPointer.pointee.y = Float(originOffset.y) + bufferPointer.pointee.z = Float(originOffset.z) + } + let debugRenderOriginBuffer = debugRenderOriginBuffers.getNextBuffer(context) + if let bufferPointer = debugRenderOriginBuffer?.contents().assumingMemoryBound( + to: simd_float4.self + ) { + bufferPointer.pointee.x = Float(origin.x) + bufferPointer.pointee.y = Float(origin.y) + bufferPointer.pointee.z = Float(origin.z) + } + Self.offsetX = originOffset.x - origin.x + Self.offsetY = originOffset.y - origin.y + Self.offsetZ = originOffset.z - origin.z encoder.setVertexBuffer(originOffsetBuffer, offset: 0, index: 3) + encoder.setVertexBuffer(debugTileOriginBuffer, offset: 0, index: 4) + encoder.setVertexBuffer(debugRenderOriginBuffer, offset: 0, index: 5) encoder.drawIndexedPrimitives(type: .triangle, indexCount: indicesCount, indexType: .uint16, indexBuffer: indicesBuffer, indexBufferOffset: 0) + + Self.renderOrigin = origin } } diff --git a/ios/graphics/Model/Polygon/PolygonGroup2d.swift b/ios/graphics/Model/Polygon/PolygonGroup2d.swift index f6c15c8f5..501395c22 100644 --- a/ios/graphics/Model/Polygon/PolygonGroup2d.swift +++ b/ios/graphics/Model/Polygon/PolygonGroup2d.swift @@ -81,15 +81,22 @@ final class PolygonGroup2d: BaseGraphicsObject, @unchecked Sendable { shader.preRender(context) encoder.setVertexBuffer(verticesBuffer, offset: 0, index: 0) + + let vpMatrixBuffer = vpMatrixBuffers.getNextBuffer(context) if let matrixPointer = UnsafeRawPointer(bitPattern: Int(vpMatrix)) { - encoder.setVertexBytes(matrixPointer, length: 64, index: 1) + vpMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) } + encoder.setVertexBuffer(vpMatrixBuffer, offset: 0, index: 1) + let originOffsetBuffer = originOffsetBuffers.getNextBuffer(context) if let bufferPointer = originOffsetBuffer?.contents().assumingMemoryBound(to: simd_float4.self) { bufferPointer.pointee.x = Float(originOffset.x - origin.x) bufferPointer.pointee.y = Float(originOffset.y - origin.y) bufferPointer.pointee.z = Float(originOffset.z - origin.z) } + else { + fatalError() + } encoder.setVertexBuffer(originOffsetBuffer, offset: 0, index: 2) if self.shader.isStriped { diff --git a/ios/graphics/Model/Polygon/PolygonPatternGroup2d.swift b/ios/graphics/Model/Polygon/PolygonPatternGroup2d.swift index 7c5cc178e..39b7ae32f 100644 --- a/ios/graphics/Model/Polygon/PolygonPatternGroup2d.swift +++ b/ios/graphics/Model/Polygon/PolygonPatternGroup2d.swift @@ -93,9 +93,12 @@ final class PolygonPatternGroup2d: BaseGraphicsObject, @unchecked Sendable { shader.preRender(context) encoder.setVertexBuffer(verticesBuffer, offset: 0, index: 0) + + let vpMatrixBuffer = vpMatrixBuffers.getNextBuffer(context) if let matrixPointer = UnsafeRawPointer(bitPattern: Int(vpMatrix)) { - encoder.setVertexBytes(matrixPointer, length: 64, index: 1) + vpMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) } + encoder.setVertexBuffer(vpMatrixBuffer, offset: 0, index: 1) // scale factors for shaders var pixelFactor: Float = Float(screenPixelAsRealMeterFactor) @@ -121,11 +124,15 @@ final class PolygonPatternGroup2d: BaseGraphicsObject, @unchecked Sendable { encoder.setFragmentBuffer(opacitiesBuffer, offset: 0, index: 0) encoder.setFragmentBuffer(textureCoordinatesBuffer, offset: 0, index: 1) + let originOffsetBuffer = originOffsetBuffers.getNextBuffer(context) if let bufferPointer = originOffsetBuffer?.contents().assumingMemoryBound(to: simd_float4.self) { bufferPointer.pointee.x = Float(originOffset.x - origin.x) bufferPointer.pointee.y = Float(originOffset.y - origin.y) bufferPointer.pointee.z = Float(originOffset.z - origin.z) } + else { + fatalError() + } encoder.setVertexBuffer(originOffsetBuffer, offset: 0, index: 4) encoder.drawIndexedPrimitives(type: .triangle, diff --git a/ios/graphics/Model/Quad/Quad2d.swift b/ios/graphics/Model/Quad/Quad2d.swift index 95c4e355d..e04a30733 100644 --- a/ios/graphics/Model/Quad/Quad2d.swift +++ b/ios/graphics/Model/Quad/Quad2d.swift @@ -125,18 +125,27 @@ final class Quad2d: BaseGraphicsObject, @unchecked Sendable { encoder.setVertexBuffer(verticesBuffer, offset: 0, index: 0) - if let vpMatrixPointer = UnsafeRawPointer(bitPattern: Int(vpMatrix)) { - encoder.setVertexBytes(vpMatrixPointer, length: 64, index: 1) + let vpMatrixBuffer = vpMatrixBuffers.getNextBuffer(context) + if let matrixPointer = UnsafeRawPointer(bitPattern: Int(vpMatrix)) { + vpMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) } - if let mMatrixPointer = UnsafeRawPointer(bitPattern: Int(mMatrix)) { - encoder.setVertexBytes(mMatrixPointer, length: 64, index: 2) + encoder.setVertexBuffer(vpMatrixBuffer, offset: 0, index: 1) + + let mMatrixBuffer = mMatrixBuffers.getNextBuffer(context) + if let matrixPointer = UnsafeRawPointer(bitPattern: Int(mMatrix)) { + vpMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) } + encoder.setVertexBuffer(mMatrixBuffer, offset: 0, index: 2) + let originOffsetBuffer = originOffsetBuffers.getNextBuffer(context) if let bufferPointer = originOffsetBuffer?.contents().assumingMemoryBound(to: simd_float4.self) { bufferPointer.pointee.x = Float(originOffset.x - origin.x) bufferPointer.pointee.y = Float(originOffset.y - origin.y) bufferPointer.pointee.z = Float(originOffset.z - origin.z) } + else { + fatalError() + } encoder.setVertexBuffer(originOffsetBuffer, offset: 0, index: 3) encoder.setFragmentSamplerState(sampler, index: 0) diff --git a/ios/graphics/Model/Quad/Quad2dInstanced.swift b/ios/graphics/Model/Quad/Quad2dInstanced.swift index 772207d3a..904c68054 100644 --- a/ios/graphics/Model/Quad/Quad2dInstanced.swift +++ b/ios/graphics/Model/Quad/Quad2dInstanced.swift @@ -26,7 +26,7 @@ final class Quad2dInstanced: BaseGraphicsObject, @unchecked Sendable { private var rotationsBuffer: MTLBuffer? private var alphaBuffer: MTLBuffer? private var offsetsBuffer: MTLBuffer? - private var originBuffer: MTLBuffer? + private var originBuffers: MultiBufferFloat4 private var textureCoordinatesBuffer: MTLBuffer? @@ -50,11 +50,10 @@ final class Quad2dInstanced: BaseGraphicsObject, @unchecked Sendable { } else { self.isUnitSphere = false } + originBuffers = MultiBufferFloat4(device: metalContext.device) super.init(device: metalContext.device, sampler: metalContext.samplerLibrary.value(Sampler.magLinear.rawValue)!, label: label) - var originOffset: simd_float4 = simd_float4(0, 0, 0, 0) - originBuffer = device.makeBuffer(bytes: &originOffset, length: MemoryLayout.stride, options: []) } private func setupStencilStates() { @@ -137,12 +136,17 @@ final class Quad2dInstanced: BaseGraphicsObject, @unchecked Sendable { encoder.setVertexBuffer(verticesBuffer, offset: 0, index: 0) - if let vpMatrixPointer = UnsafeRawPointer(bitPattern: Int(vpMatrix)) { - encoder.setVertexBytes(vpMatrixPointer, length: 64, index: 1) + let vpMatrixBuffer = vpMatrixBuffers.getNextBuffer(context) + if let matrixPointer = UnsafeRawPointer(bitPattern: Int(vpMatrix)) { + vpMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) } - if let mMatrixPointer = UnsafeRawPointer(bitPattern: Int(mMatrix)) { - encoder.setVertexBytes(mMatrixPointer, length: 64, index: 2) + encoder.setVertexBuffer(vpMatrixBuffer, offset: 0, index: 1) + + let mMatrixBuffer = mMatrixBuffers.getNextBuffer(context) + if let matrixPointer = UnsafeRawPointer(bitPattern: Int(mMatrix)) { + vpMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) } + encoder.setVertexBuffer(mMatrixBuffer, offset: 0, index: 2) encoder.setVertexBuffer(positionsBuffer, offset: 0, index: 3) encoder.setVertexBuffer(scalesBuffer, offset: 0, index: 4) @@ -162,19 +166,27 @@ final class Quad2dInstanced: BaseGraphicsObject, @unchecked Sendable { encoder.setFragmentTexture(texture, index: 0) } + let originOffsetBuffer = originOffsetBuffers.getNextBuffer(context) if let bufferPointer = originOffsetBuffer?.contents().assumingMemoryBound(to: simd_float4.self) { bufferPointer.pointee.x = Float(originOffset.x - origin.x) bufferPointer.pointee.y = Float(originOffset.y - origin.y) bufferPointer.pointee.z = Float(originOffset.z - origin.z) } + else { + fatalError() + } encoder.setVertexBuffer(originOffsetBuffer, offset: 0, index: 9) + let originBuffer = originBuffers.getNextBuffer(context) if let bufferPointer = originBuffer?.contents().assumingMemoryBound(to: simd_float4.self) { bufferPointer.pointee.x = Float(origin.x) bufferPointer.pointee.y = Float(origin.y) bufferPointer.pointee.z = Float(origin.z) } + else { + fatalError() + } encoder.setVertexBuffer(originBuffer, offset: 0, index: 10) encoder.drawIndexedPrimitives(type: .triangle, diff --git a/ios/graphics/Model/Quad/Quad2dStretchedInstanced.swift b/ios/graphics/Model/Quad/Quad2dStretchedInstanced.swift index b9bf356ed..9eedfd871 100644 --- a/ios/graphics/Model/Quad/Quad2dStretchedInstanced.swift +++ b/ios/graphics/Model/Quad/Quad2dStretchedInstanced.swift @@ -121,9 +121,12 @@ final class Quad2dStretchedInstanced: BaseGraphicsObject, @unchecked Sendable { shader.preRender(context) encoder.setVertexBuffer(verticesBuffer, offset: 0, index: 0) + + let vpMatrixBuffer = vpMatrixBuffers.getNextBuffer(context) if let matrixPointer = UnsafeRawPointer(bitPattern: Int(vpMatrix)) { - encoder.setVertexBytes(matrixPointer, length: 64, index: 1) + vpMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) } + encoder.setVertexBuffer(vpMatrixBuffer, offset: 0, index: 1) encoder.setVertexBuffer(positionsBuffer, offset: 0, index: 2) encoder.setVertexBuffer(scalesBuffer, offset: 0, index: 3) @@ -133,11 +136,15 @@ final class Quad2dStretchedInstanced: BaseGraphicsObject, @unchecked Sendable { encoder.setVertexBuffer(alphaBuffer, offset: 0, index: 6) + let originOffsetBuffer = originOffsetBuffers.getNextBuffer(context) if let bufferPointer = originOffsetBuffer?.contents().assumingMemoryBound(to: simd_float4.self) { bufferPointer.pointee.x = Float(originOffset.x - origin.x) bufferPointer.pointee.y = Float(originOffset.y - origin.y) bufferPointer.pointee.z = Float(originOffset.z - origin.z) } + else { + fatalError() + } encoder.setVertexBuffer(originOffsetBuffer, offset: 0, index: 7) encoder.setFragmentBuffer(stretchInfoBuffer, offset: 0, index: 1) diff --git a/ios/graphics/Model/Text/Text.swift b/ios/graphics/Model/Text/Text.swift index cf8bc9da2..4ffaf98e0 100644 --- a/ios/graphics/Model/Text/Text.swift +++ b/ios/graphics/Model/Text/Text.swift @@ -83,9 +83,12 @@ final class Text: BaseGraphicsObject, @unchecked Sendable { shader.preRender(context) encoder.setVertexBuffer(verticesBuffer, offset: 0, index: 0) + + let vpMatrixBuffer = vpMatrixBuffers.getNextBuffer(context) if let matrixPointer = UnsafeRawPointer(bitPattern: Int(vpMatrix)) { - encoder.setVertexBytes(matrixPointer, length: 64, index: 1) + vpMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) } + encoder.setVertexBuffer(vpMatrixBuffer, offset: 0, index: 1) encoder.setFragmentSamplerState(sampler, index: 0) diff --git a/ios/graphics/Model/Text/TextInstanced.swift b/ios/graphics/Model/Text/TextInstanced.swift index 68adde155..8cd79aeeb 100644 --- a/ios/graphics/Model/Text/TextInstanced.swift +++ b/ios/graphics/Model/Text/TextInstanced.swift @@ -28,8 +28,8 @@ final class TextInstanced: BaseGraphicsObject, @unchecked Sendable { private var rotationsBuffer: MTLBuffer? private var styleIndicesBuffer: MTLBuffer? private var styleBuffer: MTLBuffer? - private var originBuffer: MTLBuffer? - private var aspectRatioBuffer: MTLBuffer? + private var originBuffers: MultiBufferFloat4 + private var aspectRatioBuffers: MultiBufferFloat1 private var texture: MTLTexture? @@ -37,15 +37,11 @@ final class TextInstanced: BaseGraphicsObject, @unchecked Sendable { init(shader: MCShaderProgramInterface, metalContext: MetalContext) { self.shader = shader as! TextInstancedShader + self.originBuffers = MultiBufferFloat4(device: metalContext.device) + self.aspectRatioBuffers = MultiBufferFloat1(device: metalContext.device) super.init(device: metalContext.device, sampler: metalContext.samplerLibrary.value(Sampler.magLinear.rawValue)!, label: "TextInstanced") - - var originOffset: simd_float4 = simd_float4(0, 0, 0, 0) - originBuffer = device.makeBuffer(bytes: &originOffset, length: MemoryLayout.stride, options: []) - - var aspectRatio: simd_float1 = simd_float1(0) - aspectRatioBuffer = device.makeBuffer(bytes: &aspectRatio, length: MemoryLayout.stride, options: []) } private func setupStencilStates() { @@ -106,12 +102,17 @@ final class TextInstanced: BaseGraphicsObject, @unchecked Sendable { encoder.setVertexBuffer(verticesBuffer, offset: 0, index: 0) - if let vpMatrixPointer = UnsafeRawPointer(bitPattern: Int(vpMatrix)) { - encoder.setVertexBytes(vpMatrixPointer, length: 64, index: 1) + let vpMatrixBuffer = vpMatrixBuffers.getNextBuffer(context) + if let matrixPointer = UnsafeRawPointer(bitPattern: Int(vpMatrix)) { + vpMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) } - if let mMatrixPointer = UnsafeRawPointer(bitPattern: Int(mMatrix)) { - encoder.setVertexBytes(mMatrixPointer, length: 64, index: 2) + encoder.setVertexBuffer(vpMatrixBuffer, offset: 0, index: 1) + + let mMatrixBuffer = mMatrixBuffers.getNextBuffer(context) + if let matrixPointer = UnsafeRawPointer(bitPattern: Int(mMatrix)) { + vpMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) } + encoder.setVertexBuffer(mMatrixBuffer, offset: 0, index: 2) encoder.setVertexBuffer(positionsBuffer, offset: 0, index: 3) encoder.setVertexBuffer(scalesBuffer, offset: 0, index: 4) @@ -124,23 +125,35 @@ final class TextInstanced: BaseGraphicsObject, @unchecked Sendable { encoder.setVertexBuffer(referencePositionsBuffer, offset: 0, index: 8) } + let originOffsetBuffer = originOffsetBuffers.getNextBuffer(context) if let bufferPointer = originOffsetBuffer?.contents().assumingMemoryBound(to: simd_float4.self) { bufferPointer.pointee.x = Float(originOffset.x - origin.x) bufferPointer.pointee.y = Float(originOffset.y - origin.y) bufferPointer.pointee.z = Float(originOffset.z - origin.z) } + else { + fatalError() + } encoder.setVertexBuffer(originOffsetBuffer, offset: 0, index: 9) + let originBuffer = originBuffers.getNextBuffer(context) if let bufferPointer = originBuffer?.contents().assumingMemoryBound(to: simd_float4.self) { bufferPointer.pointee.x = Float(origin.x) bufferPointer.pointee.y = Float(origin.y) bufferPointer.pointee.z = Float(origin.z) } + else { + fatalError() + } encoder.setVertexBuffer(originBuffer, offset: 0, index: 10) + let aspectRatioBuffer = aspectRatioBuffers.getNextBuffer(context) if let bufferPointer = aspectRatioBuffer?.contents().assumingMemoryBound(to: simd_float1.self) { bufferPointer.pointee = Float(context.aspectRatio) } + else { + fatalError() + } encoder.setVertexBuffer(aspectRatioBuffer, offset: 0, index: 11) encoder.setFragmentSamplerState(sampler, index: 0) diff --git a/ios/graphics/RenderingContext.swift b/ios/graphics/RenderingContext.swift index 92c92104a..67c015fd5 100644 --- a/ios/graphics/RenderingContext.swift +++ b/ios/graphics/RenderingContext.swift @@ -18,6 +18,11 @@ public class RenderingContext: NSObject, @unchecked Sendable { public weak var encoder: MTLRenderCommandEncoder? public weak var computeEncoder: MTLComputeCommandEncoder? public weak var sceneView: MCMapView? + private(set) var frameId: Int = 0 + + public func beginFrame() { + frameId = (frameId + 1) % 1000 + } public var cullMode: MCRenderingCullMode? diff --git a/ios/graphics/Shader/Metal/BaseShader.metal b/ios/graphics/Shader/Metal/BaseShader.metal index 77642033c..c823a42f2 100644 --- a/ios/graphics/Shader/Metal/BaseShader.metal +++ b/ios/graphics/Shader/Metal/BaseShader.metal @@ -49,7 +49,9 @@ vertex VertexOut colorVertexShader(const Vertex3FIn vertexIn [[stage_in]], constant float4x4 &vpMatrix [[buffer(1)]], constant float4x4 &mMatrix [[buffer(2)]], - constant float4 &originOffset [[buffer(3)]]) + constant float4 &originOffset [[buffer(3)]], + constant float4 &debugTileOrigin [[buffer(4)]], + constant float4 &debugRenderOrigin [[buffer(5)]]) { VertexOut out { .position = vpMatrix * ((mMatrix * float4(vertexIn.position.xyz, 1.0)) + originOffset), diff --git a/ios/graphics/Shader/Metal/LineShader.metal b/ios/graphics/Shader/Metal/LineShader.metal index e21da4dfc..558bdec5a 100644 --- a/ios/graphics/Shader/Metal/LineShader.metal +++ b/ios/graphics/Shader/Metal/LineShader.metal @@ -82,7 +82,9 @@ unitSpherelineGroupVertexShader(const LineVertexUnitSphereIn vertexIn [[stage_in constant float &dashingScalingFactor [[buffer(3)]], constant float *styling [[buffer(4)]], constant float4 &originOffset [[buffer(5)]], - constant float4 &tileOrigin [[buffer(6)]]) + constant float4 &tileOrigin [[buffer(6)]], + constant float4 &debugTileOrigin [[buffer(7)]], + constant float4 &debugRenderOrigin [[buffer(8)]]) { int styleIndex = (int(vertexIn.stylingIndex) & 0xFF) * 21; constant LineStyling *style = (constant LineStyling *)(styling + styleIndex); diff --git a/ios/maps/MCMapView.swift b/ios/maps/MCMapView.swift index 31b99fad4..2d9a382d7 100644 --- a/ios/maps/MCMapView.swift +++ b/ios/maps/MCMapView.swift @@ -26,6 +26,7 @@ open class MCMapView: MTKView, @unchecked Sendable { private let framesToRenderAfterInvalidate: Int = 25 private var lastInvalidate = Date() private let renderAfterInvalidate: TimeInterval = 3 // Collision detection might be delayed 3s + private var renderSemaphore = DispatchSemaphore(value: 2) private let touchHandler: MCMapViewTouchHandler private let callbackHandler = MCMapViewCallbackHandler() @@ -165,6 +166,8 @@ extension MCMapView: MTKViewDelegate { return } + renderSemaphore.wait() + framesToRender -= 1 mapInterface.prepare() @@ -185,6 +188,7 @@ extension MCMapView: MTKViewDelegate { } renderingContext.encoder = renderEncoder + renderingContext.beginFrame() // Shared lib stuff if sizeChanged { @@ -201,6 +205,10 @@ extension MCMapView: MTKViewDelegate { return } + commandBuffer.addCompletedHandler { [weak self] _ in + self?.renderSemaphore.signal() + } + // if we want to save the drawable (offscreen rendering), we commit and wait synchronously // until the command buffer completes, also we don't present it if self.saveDrawable { diff --git a/shared/public/MapCameraInterface.h b/shared/public/MapCameraInterface.h index 079e6e634..dc601da59 100644 --- a/shared/public/MapCameraInterface.h +++ b/shared/public/MapCameraInterface.h @@ -88,6 +88,8 @@ class MapCameraInterface { virtual double mapUnitsFromPixels(double distancePx) = 0; + virtual double getScalingFactor() = 0; + /** padding in percentage, where 1.0 = rect is half of full width and height */ virtual bool coordIsVisibleOnScreen(const ::Coord & coord, float paddingPc) = 0; diff --git a/shared/public/Tiled2dMapSourceImpl.h b/shared/public/Tiled2dMapSourceImpl.h index 67ba669da..65406e577 100644 --- a/shared/public/Tiled2dMapSourceImpl.h +++ b/shared/public/Tiled2dMapSourceImpl.h @@ -13,43 +13,41 @@ #include "TiledLayerError.h" #include -#include "PolygonCoord.h" -#include -#include "gpc.h" #include "Logger.h" #include "Matrix.h" +#include "PolygonCoord.h" #include "Vec2DHelper.h" #include "Vec3DHelper.h" +#include "gpc.h" +#include struct VisibleTileCandidate { - int x; int y; + int x; + int y; int levelIndex; - bool operator==(const VisibleTileCandidate& other) const { + bool operator==(const VisibleTileCandidate &other) const { return x == other.x && y == other.y && levelIndex == other.levelIndex; } }; namespace std { - template <> - struct hash { - size_t operator()(const VisibleTileCandidate& candidate) const { - size_t h1 = hash()(candidate.x); - size_t h2 = hash()(candidate.y); - size_t h3 = hash()(candidate.levelIndex); - - // Combine hashes using a simple combining function, based on the one from Boost library - return h1 ^ (h2 << 1) ^ (h3 << 2); - } - }; -} +template <> struct hash { + size_t operator()(const VisibleTileCandidate &candidate) const { + size_t h1 = hash()(candidate.x); + size_t h2 = hash()(candidate.y); + size_t h3 = hash()(candidate.levelIndex); + + // Combine hashes using a simple combining function, based on the one from Boost library + return h1 ^ (h2 << 1) ^ (h3 << 2); + } +}; +} // namespace std -template +template Tiled2dMapSource::Tiled2dMapSource(const MapConfig &mapConfig, const std::shared_ptr &layerConfig, - const std::shared_ptr &conversionHelper, - const std::shared_ptr &scheduler, - float screenDensityPpi, - size_t loaderCount, - std::string layerName) + const std::shared_ptr &conversionHelper, + const std::shared_ptr &scheduler, float screenDensityPpi, + size_t loaderCount, std::string layerName) : mapConfig(mapConfig) , layerConfig(layerConfig) , conversionHelper(conversionHelper) @@ -67,20 +65,19 @@ Tiled2dMapSource::Tiled2dMapSource(const MapConfig &mapConfig, const st const static double VIEWBOUNDS_PADDING_MIN_DIM_PC = 0.15; const static int8_t ALWAYS_KEEP_LEVEL_TARGET_ZOOM_OFFSET = -8; -template -bool Tiled2dMapSource::isTileVisible(const Tiled2dMapTileInfo &tileInfo) { +template bool Tiled2dMapSource::isTileVisible(const Tiled2dMapTileInfo &tileInfo) { return currentVisibleTiles.count(tileInfo) > 0; } -template -static void hash_combine(size_t& seed, const T& value) { +template static void hash_combine(size_t &seed, const T &value) { std::hash hasher; auto v = hasher(value); seed ^= v + 0x9e3779b9 + (seed << 6) + (seed >> 2); } -template -::Vec3D Tiled2dMapSource::transformToView(const ::Coord &position, const std::vector &viewMatrix, const Vec3D & origin) { +template +::Vec3D Tiled2dMapSource::transformToView(const ::Coord &position, const std::vector &viewMatrix, + const Vec3D &origin) { Coord mapCoord = conversionHelper->convertToRenderSystem(position); @@ -88,21 +85,19 @@ ::Vec3D Tiled2dMapSource::transformToView(const ::Coord &position, cons const double ry = origin.y; const double rz = origin.z; - std::vector inVec = {(float) ((mapCoord.z * sin(mapCoord.y) * cos(mapCoord.x) - rx) ), - (float) ((mapCoord.z * cos(mapCoord.y) - ry) ), - (float) ((-mapCoord.z * sin(mapCoord.y) * sin(mapCoord.x) - rz) ), - 1.0}; + std::vector inVec = {(float)((mapCoord.z * sin(mapCoord.y) * cos(mapCoord.x) - rx)), + (float)((mapCoord.z * cos(mapCoord.y) - ry)), + (float)((-mapCoord.z * sin(mapCoord.y) * sin(mapCoord.x) - rz)), 1.0}; std::vector outVec = {0, 0, 0, 0}; Matrix::multiply(viewMatrix, inVec, outVec); - auto point2d = Vec3D(outVec[0] / outVec[3], outVec[1] / outVec[3], outVec[2] / outVec[3]); return point2d; } -template -::Vec3D Tiled2dMapSource::projectToScreen(const ::Vec3D & position, const std::vector & projectionMatrix) { +template +::Vec3D Tiled2dMapSource::projectToScreen(const ::Vec3D &position, const std::vector &projectionMatrix) { std::vector inVec = {(float)position.x, (float)position.y, (float)position.z, 1.0}; std::vector outVec = {0, 0, 0, 0}; @@ -112,10 +107,11 @@ ::Vec3D Tiled2dMapSource::projectToScreen(const ::Vec3D & position, con return point2d; } -template -void Tiled2dMapSource::onCameraChange(const std::vector &viewMatrix, const std::vector &projectionMatrix,const ::Vec3D & origin, - float verticalFov, float horizontalFov, float width, float height, - float focusPointAltitude, const ::Coord & focusPointPosition, float zoom) { +template +void Tiled2dMapSource::onCameraChange(const std::vector &viewMatrix, const std::vector &projectionMatrix, + const ::Vec3D &origin, float verticalFov, float horizontalFov, float width, + float height, float focusPointAltitude, const ::Coord &focusPointPosition, + float zoom) { if (isPaused) { return; @@ -128,7 +124,6 @@ void Tiled2dMapSource::onCameraChange(const std::vector &viewMat std::queue candidates; std::unordered_set candidatesSet; - Coord viewBoundsTopLeft(layerSystemId, 0, 0, 0); Coord viewBoundsTopRight(layerSystemId, 0, 0, 0); Coord viewBoundsBottomLeft(layerSystemId, 0, 0, 0); @@ -143,10 +138,7 @@ void Tiled2dMapSource::onCameraChange(const std::vector &viewMat const auto &level = zoomLevelInfos[index]; if (level.numTilesX > minNumTiles && level.numTilesY > minNumTiles) { if (level.numTilesX * level.numTilesY > 100) { - printf("Ignore seed candidates for %d x %d tiles for %s\n", - level.numTilesX, - level.numTilesY, - layerName.c_str()); + printf("Ignore seed candidates for %d x %d tiles for %s\n", level.numTilesX, level.numTilesY, layerName.c_str()); break; } for (int x = 0; x < level.numTilesX; x++) { @@ -168,13 +160,15 @@ void Tiled2dMapSource::onCameraChange(const std::vector &viewMat gpc_polygon currentViewBoundsPolygon; gpc_polygon currentTilePolygon; gpc_set_polygon({PolygonCoord( - { - conversionHelper->convert(layerSystemId, Coord(4326, -180, 90, 0)), // top left - conversionHelper->convert(layerSystemId, Coord(4326, 180, 90, 0)), // top right - conversionHelper->convert(layerSystemId, Coord(4326, 180, -90, 0)), // bottom right - conversionHelper->convert(layerSystemId, Coord(4326, -180, -90, 0)), // bottom left - conversionHelper->convert(layerSystemId, Coord(4326, -180, 90, 0)) // top left - }, {})}, ¤tViewBoundsPolygon); + { + conversionHelper->convert(layerSystemId, Coord(4326, -180, 90, 0)), // top left + conversionHelper->convert(layerSystemId, Coord(4326, 180, 90, 0)), // top right + conversionHelper->convert(layerSystemId, Coord(4326, 180, -90, 0)), // bottom right + conversionHelper->convert(layerSystemId, Coord(4326, -180, -90, 0)), // bottom left + conversionHelper->convert(layerSystemId, Coord(4326, -180, 90, 0)) // top left + }, + {})}, + ¤tViewBoundsPolygon); auto clipAndFreeLambda = [¤tViewBoundsPolygon, system = layerSystemId](gpc_polygon &polygon) { gpc_polygon_clip(GPC_DIFF, ¤tViewBoundsPolygon, &polygon, ¤tViewBoundsPolygon); gpc_free_polygon(&polygon); @@ -206,10 +200,11 @@ void Tiled2dMapSource::onCameraChange(const std::vector &viewMat return; } - const Tiled2dMapZoomLevelInfo &zoomLevelInfo = zoomLevelInfos.at(candidate.levelIndex); - const double boundsRatio = std::abs(((zoomLevelInfo.bounds.bottomRight.y - zoomLevelInfo.bounds.topLeft.y) / zoomLevelInfo.numTilesY) / ((zoomLevelInfo.bounds.bottomRight.x - zoomLevelInfo.bounds.topLeft.x) / zoomLevelInfo.numTilesX)); + const double boundsRatio = + std::abs(((zoomLevelInfo.bounds.bottomRight.y - zoomLevelInfo.bounds.topLeft.y) / zoomLevelInfo.numTilesY) / + ((zoomLevelInfo.bounds.bottomRight.x - zoomLevelInfo.bounds.topLeft.x) / zoomLevelInfo.numTilesX)); const double tileWidth = zoomLevelInfo.tileWidthLayerSystemUnits; const double tileHeight = zoomLevelInfo.tileWidthLayerSystemUnits * boundsRatio; @@ -226,34 +221,38 @@ void Tiled2dMapSource::onCameraChange(const std::vector &viewMat const double heightRange = 1000; - const Coord topLeft = Coord(layerSystemId, candidate.x * tileWidthAdj + boundsLeft, candidate.y * tileHeightAdj + boundsTop, focusPointAltitude); + const Coord topLeft = Coord(layerSystemId, candidate.x * tileWidthAdj + boundsLeft, candidate.y * tileHeightAdj + boundsTop, + focusPointAltitude); const Coord topRight = Coord(layerSystemId, topLeft.x + tileWidthAdj, topLeft.y, focusPointAltitude - heightRange / 2.0); const Coord bottomLeft = Coord(layerSystemId, topLeft.x, topLeft.y + tileHeightAdj, focusPointAltitude - heightRange / 2.0); - const Coord bottomRight = Coord(layerSystemId, topLeft.x + tileWidthAdj, topLeft.y + tileHeightAdj, focusPointAltitude- heightRange / 2.0); + const Coord bottomRight = + Coord(layerSystemId, topLeft.x + tileWidthAdj, topLeft.y + tileHeightAdj, focusPointAltitude - heightRange / 2.0); - const Coord tileCenter = Coord(layerSystemId, topLeft.x * 0.5 + bottomRight.x * 0.5, topLeft.y * 0.5 + bottomRight.y * 0.5, topLeft.z * 0.5 + bottomRight.z * 0.5); + const Coord tileCenter = Coord(layerSystemId, topLeft.x * 0.5 + bottomRight.x * 0.5, topLeft.y * 0.5 + bottomRight.y * 0.5, + topLeft.z * 0.5 + bottomRight.z * 0.5); gpc_set_polygon({PolygonCoord({topLeft, topRight, bottomRight, bottomLeft, topLeft}, {})}, ¤tTilePolygon); - const auto focusPointClampedToTile = Coord(layerSystemId, - topLeft.x < topRight.x ? std::clamp(focusPointInLayerCoords.x, topLeft.x, topRight.x) : std::clamp(focusPointInLayerCoords.x, topRight.x, topLeft.x), - topLeft.y < bottomLeft.y ? std::clamp(focusPointInLayerCoords.y, topLeft.y, bottomLeft.y) : std::clamp(focusPointInLayerCoords.y, bottomLeft.y, topLeft.y), - focusPointAltitude); + const auto focusPointClampedToTile = + Coord(layerSystemId, + topLeft.x < topRight.x ? std::clamp(focusPointInLayerCoords.x, topLeft.x, topRight.x) + : std::clamp(focusPointInLayerCoords.x, topRight.x, topLeft.x), + topLeft.y < bottomLeft.y ? std::clamp(focusPointInLayerCoords.y, topLeft.y, bottomLeft.y) + : std::clamp(focusPointInLayerCoords.y, bottomLeft.y, topLeft.y), + focusPointAltitude); auto toRight = focusPointClampedToTile.x < tileCenter.x; auto toTop = focusPointClampedToTile.y < tileCenter.y; const double sampleSize = 0.25; - const auto focusPointSampleX = Coord(layerSystemId, - focusPointClampedToTile.x + (toRight ? tileWidthAdj : -tileWidthAdj) * sampleSize, - focusPointClampedToTile.y, - focusPointClampedToTile.z); + const auto focusPointSampleX = + Coord(layerSystemId, focusPointClampedToTile.x + (toRight ? tileWidthAdj : -tileWidthAdj) * sampleSize, + focusPointClampedToTile.y, focusPointClampedToTile.z); - const auto focusPointSampleY = Coord(layerSystemId, - focusPointClampedToTile.x, - focusPointClampedToTile.y + (toTop ? -tileHeightAdj : tileHeightAdj) * sampleSize, - focusPointClampedToTile.z); + const auto focusPointSampleY = + Coord(layerSystemId, focusPointClampedToTile.x, + focusPointClampedToTile.y + (toTop ? -tileHeightAdj : tileHeightAdj) * sampleSize, focusPointClampedToTile.z); const Coord topCenter = Coord(layerSystemId, topLeft.x * 0.5 + topRight.x * 0.5, topLeft.y, topLeft.z); const Coord bottomCenter = Coord(layerSystemId, bottomLeft.x * 0.5 + bottomRight.x * 0.5, bottomLeft.y, bottomLeft.z); @@ -269,7 +268,6 @@ void Tiled2dMapSource::onCameraChange(const std::vector &viewMat use focuspoint in layersystem and clamp to tileBounds */ - auto focusPointClampedView = transformToView(focusPointClampedToTile, viewMatrix, origin); auto focusPointSampleXView = transformToView(focusPointSampleX, viewMatrix, origin); auto focusPointSampleYView = transformToView(focusPointSampleY, viewMatrix, origin); @@ -296,14 +294,13 @@ void Tiled2dMapSource::onCameraChange(const std::vector &viewMat if (!isKeptLevel && diffCenterViewTopLeft.z < 0.0 && diffCenterViewTopRight.z < 0.0 && diffCenterViewBottomLeft.z < 0.0 && diffCenterViewBottomRight.z < 0.0) { clipAndFreeLambda(currentTilePolygon); - // LogDebug << "UBCM: dropping tile (all facing away) " << candidate.levelIndex << "/" << candidate.x << "/" <<= candidate.y; - // Tile is facing away from the camera + // LogDebug << "UBCM: dropping tile (all facing away) " << candidate.levelIndex << "/" << candidate.x << "/" <<= + // candidate.y; Tile is facing away from the camera continue; } auto samplePointOriginViewScreen = projectToScreen(focusPointClampedView, projectionMatrix); - if (!isKeptLevel && - (samplePointOriginViewScreen.x < -1.0 || samplePointOriginViewScreen.x > 1.0 || - samplePointOriginViewScreen.y < -1.0 || samplePointOriginViewScreen.y > 1.0)) { + if (!isKeptLevel && (samplePointOriginViewScreen.x < -1.0 || samplePointOriginViewScreen.x > 1.0 || + samplePointOriginViewScreen.y < -1.0 || samplePointOriginViewScreen.y > 1.0)) { if (mapConfig.mapCoordinateSystem.identifier == CoordinateSystemIdentifiers::UnitSphere()) { // v(0,0,+1) = unit-vector out of screen float topLeftHA = 180.0 / M_PI * atan2(topLeftView.x, -topLeftView.z); @@ -342,11 +339,11 @@ void Tiled2dMapSource::onCameraChange(const std::vector &viewMat (leftCenterVA < bottom || diffCenterViewLeftCenter.z < 0.0) && (rightCenterVA < bottom || diffCenterViewRightCenter.z < 0.0)) { clipAndFreeLambda(currentTilePolygon); - // LogDebug << "UBCM: dropping tile (below) " << candidate.levelIndex << "/" << candidate.x << "/" <<= candidate.y; + // LogDebug << "UBCM: dropping tile (below) " << candidate.levelIndex << "/" << candidate.x << "/" <<= + // candidate.y; continue; // All camera-facing corners are BELOW the viewport } - if ((topLeftHA < left || diffCenterViewTopLeft.z < 0.0) && - (topRightHA < left || diffCenterViewTopRight.z < 0.0) && + if ((topLeftHA < left || diffCenterViewTopLeft.z < 0.0) && (topRightHA < left || diffCenterViewTopRight.z < 0.0) && (bottomLeftHA < left || diffCenterViewBottomLeft.z < 0.0) && (bottomRightHA < left || diffCenterViewBottomRight.z < 0.0) && (topCenterHA < left || diffCenterViewTopCenter.z < 0.0) && @@ -354,11 +351,11 @@ void Tiled2dMapSource::onCameraChange(const std::vector &viewMat (leftCenterHA < left || diffCenterViewLeftCenter.z < 0.0) && (rightCenterHA < left || diffCenterViewRightCenter.z < 0.0)) { clipAndFreeLambda(currentTilePolygon); - // LogDebug << "UBCM: dropping tile (left) " << candidate.levelIndex << "/" << candidate.x << "/" <<= candidate.y; + // LogDebug << "UBCM: dropping tile (left) " << candidate.levelIndex << "/" << candidate.x << "/" <<= + // candidate.y; continue; // All camera-facing corners are TO THE LEFT of the viewport } - if ((topLeftVA > top || diffCenterViewTopLeft.z < 0.0) && - (topRightVA > top || diffCenterViewTopRight.z < 0.0) && + if ((topLeftVA > top || diffCenterViewTopLeft.z < 0.0) && (topRightVA > top || diffCenterViewTopRight.z < 0.0) && (bottomLeftVA > top || diffCenterViewBottomLeft.z < 0.0) && (bottomRightVA > top || diffCenterViewBottomRight.z < 0.0) && (topCenterVA > top || diffCenterViewTopCenter.z < 0.0) && @@ -366,7 +363,8 @@ void Tiled2dMapSource::onCameraChange(const std::vector &viewMat (leftCenterVA > top || diffCenterViewLeftCenter.z < 0.0) && (rightCenterVA > top || diffCenterViewRightCenter.z < 0.0)) { clipAndFreeLambda(currentTilePolygon); - // LogDebug << "UBCM: dropping tile (above) " << candidate.levelIndex << "/" << candidate.x << "/" <<= candidate.y; + // LogDebug << "UBCM: dropping tile (above) " << candidate.levelIndex << "/" << candidate.x << "/" <<= + // candidate.y; continue; // All camera-facing corners are ABOVE the viewport } if ((topLeftHA > right || diffCenterViewTopLeft.z < 0.0) && @@ -378,7 +376,8 @@ void Tiled2dMapSource::onCameraChange(const std::vector &viewMat (leftCenterHA > right || diffCenterViewLeftCenter.z < 0.0) && (rightCenterHA > right || diffCenterViewRightCenter.z < 0.0)) { clipAndFreeLambda(currentTilePolygon); - // LogDebug << "UBCM: dropping tile (right) " << candidate.levelIndex << "/" << candidate.x << "/" <<= candidate.y; + // LogDebug << "UBCM: dropping tile (right) " << candidate.levelIndex << "/" << candidate.x << "/" <<= + // candidate.y; continue; // All camera-facing corners are TO THE RIGHT of the viewport } } else { @@ -405,14 +404,13 @@ void Tiled2dMapSource::onCameraChange(const std::vector &viewMat } } - if (!validViewBounds) { viewBoundsTopLeft = topLeft; viewBoundsBottomRight = bottomRight; validViewBounds = true; } - auto updateBounds = [](double& bound, double value, bool compareLess) { + auto updateBounds = [](double &bound, double value, bool compareLess) { bound = compareLess ? std::min(bound, value) : std::max(bound, value); }; @@ -431,7 +429,8 @@ void Tiled2dMapSource::onCameraChange(const std::vector &viewMat auto samplePointYViewScreen = projectToScreen(focusPointSampleYView, projectionMatrix); auto samplePointXViewScreen = projectToScreen(focusPointSampleXView, projectionMatrix); - Vec2D samplePointOriginViewScreenPx(samplePointOriginViewScreen.x * (width / 2.0), samplePointOriginViewScreen.y * (height / 2.0)); + Vec2D samplePointOriginViewScreenPx(samplePointOriginViewScreen.x * (width / 2.0), + samplePointOriginViewScreen.y * (height / 2.0)); Vec2D samplePointYViewScreenPx(samplePointYViewScreen.x * (width / 2.0), samplePointYViewScreen.y * (height / 2.0)); Vec2D samplePointXViewScreenPx(samplePointXViewScreen.x * (width / 2.0), samplePointXViewScreen.y * (height / 2.0)); @@ -447,9 +446,10 @@ void Tiled2dMapSource::onCameraChange(const std::vector &viewMat const RectCoord rect(topLeft, bottomRight); int t = 0; double priority = -centerZ * 100000; - visibleTilesVec.push_back(std::make_pair(candidate, PrioritizedTiled2dMapTileInfo( - Tiled2dMapTileInfo(rect, candidate.x, candidate.y, t, zoomLevelInfo.zoomLevelIdentifier, zoomLevelInfo.zoom), - priority))); + visibleTilesVec.push_back(std::make_pair( + candidate, PrioritizedTiled2dMapTileInfo(Tiled2dMapTileInfo(rect, candidate.x, candidate.y, t, + zoomLevelInfo.zoomLevelIdentifier, zoomLevelInfo.zoom), + priority))); maxLevel = std::max(maxLevel, zoomLevelInfo.zoomLevelIdentifier); } @@ -499,11 +499,11 @@ void Tiled2dMapSource::onCameraChange(const std::vector &viewMat return; } - std::vector layers; int topMostZoomLevel = zoomLevelInfos.begin()->zoomLevelIdentifier; - for (int previousLayerOffset = 0; (previousLayerOffset <= zoomInfo.numDrawPreviousLayers || zoomInfo.maskTile); previousLayerOffset++) { + for (int previousLayerOffset = 0; (previousLayerOffset <= zoomInfo.numDrawPreviousLayers || zoomInfo.maskTile); + previousLayerOffset++) { VisibleTilesLayer curVisibleTiles(-previousLayerOffset); @@ -512,6 +512,68 @@ void Tiled2dMapSource::onCameraChange(const std::vector &viewMat bool allTopMost = true; for (auto &tile : visibleTilesVec) { + + const auto dataBounds = layerConfig->getBounds(); + + if (dataBounds.has_value()) { + const auto availableTiles = conversionHelper->convertRect(layerSystemId, *dataBounds); + + const Tiled2dMapZoomLevelInfo &zoomLevelInfo = zoomLevelInfos.at(tile.first.levelIndex); + + RectCoord layerBounds = zoomLevelInfo.bounds; + const bool leftToRight = layerBounds.topLeft.x < layerBounds.bottomRight.x; + const bool topToBottom = layerBounds.topLeft.y < layerBounds.bottomRight.y; + + const double boundsRatio = + std::abs(((zoomLevelInfo.bounds.bottomRight.y - zoomLevelInfo.bounds.topLeft.y) / zoomLevelInfo.numTilesY) / + ((zoomLevelInfo.bounds.bottomRight.x - zoomLevelInfo.bounds.topLeft.x) / zoomLevelInfo.numTilesX)); + const double tileWidth = zoomLevelInfo.tileWidthLayerSystemUnits; + const double tileHeight = zoomLevelInfo.tileWidthLayerSystemUnits * boundsRatio; + const double tLength = tileWidth / 256; + const double tHeight = tileHeight / 256; + + const double tileWidthAdj = leftToRight ? tileWidth : -tileWidth; + const double tileHeightAdj = topToBottom ? tileHeight : -tileHeight; + const double tWidthAdj = leftToRight ? tLength : -tLength; + const double tHeightAdj = topToBottom ? tHeight : -tHeight; + const double originX = leftToRight ? zoomLevelInfo.bounds.topLeft.x : -zoomLevelInfo.bounds.bottomRight.x; + const double originY = topToBottom ? zoomLevelInfo.bounds.bottomRight.y : -zoomLevelInfo.bounds.topLeft.y; + const double minAvailableX = leftToRight ? std::min(availableTiles.topLeft.x, availableTiles.bottomRight.x) + : -std::max(availableTiles.topLeft.x, availableTiles.bottomRight.x); + const double minAvailableY = topToBottom ? std::min(availableTiles.topLeft.y, availableTiles.bottomRight.y) + : -std::max(availableTiles.topLeft.y, availableTiles.bottomRight.y); + const double maxAvailableX = leftToRight ? std::max(availableTiles.topLeft.x, availableTiles.bottomRight.x) + : -std::min(availableTiles.topLeft.x, availableTiles.bottomRight.x); + const double maxAvailableY = topToBottom ? std::max(availableTiles.topLeft.y, availableTiles.bottomRight.y) + : -std::min(availableTiles.topLeft.y, availableTiles.bottomRight.y); + + int min_left_pixel = floor((minAvailableX - originX) / tLength); + int min_left = std::max(0, min_left_pixel / 256); + + int max_left_pixel = floor((maxAvailableX - originX) / tLength); + int max_left = std::min(zoomLevelInfo.numTilesX, max_left_pixel / 256); + + int min_top_pixel = floor((minAvailableY - originY) / tHeight); + int min_top = std::max(0, min_top_pixel / 256); + + int max_top_pixel = floor((maxAvailableY - originY) / tHeight); + int max_top = std::min(zoomLevelInfo.numTilesY, max_top_pixel / 256); + + if (tile.second.tileInfo.x < min_left) { + continue; + } + if (tile.second.tileInfo.x > max_left) { + continue; + } + if (tile.second.tileInfo.y < min_top) { + continue; + } + if (tile.second.tileInfo.y > max_top) { + continue; + } + + } + tile.second.tileInfo.tessellationFactor = std::min(std::max(0, maxLevel - tile.second.tileInfo.zoomIdentifier), 4); curVisibleTiles.visibleTiles.insert(tile.second); @@ -524,7 +586,9 @@ void Tiled2dMapSource::onCameraChange(const std::vector &viewMat if (tile.first.levelIndex > 0 && (previousLayerOffset < zoomInfo.numDrawPreviousLayers || zoomInfo.maskTile)) { const Tiled2dMapZoomLevelInfo &zoomLevelInfo = zoomLevelInfos.at(tile.first.levelIndex - 1); - const double boundsRatio = std::abs(((zoomLevelInfo.bounds.bottomRight.y - zoomLevelInfo.bounds.topLeft.y) / zoomLevelInfo.numTilesY) / ((zoomLevelInfo.bounds.bottomRight.x - zoomLevelInfo.bounds.topLeft.x) / zoomLevelInfo.numTilesX)); + const double boundsRatio = + std::abs(((zoomLevelInfo.bounds.bottomRight.y - zoomLevelInfo.bounds.topLeft.y) / zoomLevelInfo.numTilesY) / + ((zoomLevelInfo.bounds.bottomRight.x - zoomLevelInfo.bounds.topLeft.x) / zoomLevelInfo.numTilesX)); const double tileWidth = zoomLevelInfo.tileWidthLayerSystemUnits; const double tileHeight = zoomLevelInfo.tileWidthLayerSystemUnits * boundsRatio; @@ -544,15 +608,18 @@ void Tiled2dMapSource::onCameraChange(const std::vector &viewMat parent.x = floor((tile.second.tileInfo.bounds.topLeft.x - boundsLeft) / tileWidthAdj); parent.y = floor((tile.second.tileInfo.bounds.topLeft.y - boundsTop) / tileHeightAdj); - const Coord topLeft = Coord(layerSystemId, parent.x * tileWidthAdj + boundsLeft, parent.y * tileHeightAdj + boundsTop, focusPointAltitude); - const Coord bottomRight = Coord(layerSystemId, topLeft.x + tileWidthAdj, topLeft.y + tileHeightAdj, focusPointAltitude); + const Coord topLeft = Coord(layerSystemId, parent.x * tileWidthAdj + boundsLeft, + parent.y * tileHeightAdj + boundsTop, focusPointAltitude); + const Coord bottomRight = + Coord(layerSystemId, topLeft.x + tileWidthAdj, topLeft.y + tileHeightAdj, focusPointAltitude); const RectCoord rect(topLeft, bottomRight); int t = 0; double priority = previousLayerOffset * 100000 + tile.second.priority; - nextVisibleTilesVec.push_back(std::make_pair(parent, PrioritizedTiled2dMapTileInfo( - Tiled2dMapTileInfo(rect, parent.x, parent.y, t, zoomLevelInfo.zoomLevelIdentifier, zoomLevelInfo.zoom), - priority))); + nextVisibleTilesVec.push_back(std::make_pair( + parent, PrioritizedTiled2dMapTileInfo(Tiled2dMapTileInfo(rect, parent.x, parent.y, t, + zoomLevelInfo.zoomLevelIdentifier, zoomLevelInfo.zoom), + priority))); } visibleTilesVec = nextVisibleTilesVec; } @@ -574,7 +641,7 @@ void Tiled2dMapSource::onCameraChange(const std::vector &viewMat } } -template +template void Tiled2dMapSource::onVisibleBoundsChanged(const ::RectCoord &visibleBounds, int curT, double zoom) { if (isPaused) { return; @@ -584,7 +651,7 @@ void Tiled2dMapSource::onVisibleBoundsChanged(const ::RectCoord &visibl RectCoord visibleBoundsLayer = conversionHelper->convertRect(layerSystemId, visibleBounds); - const auto bounds = layerConfig->getBounds(); + const auto dataBounds = layerConfig->getBounds(); double centerVisibleX = visibleBoundsLayer.topLeft.x + 0.5 * (visibleBoundsLayer.bottomRight.x - visibleBoundsLayer.topLeft.x); double centerVisibleY = visibleBoundsLayer.topLeft.y + 0.5 * (visibleBoundsLayer.bottomRight.y - visibleBoundsLayer.topLeft.y); @@ -595,9 +662,10 @@ void Tiled2dMapSource::onVisibleBoundsChanged(const ::RectCoord &visibl // Each pixel is assumed to be 0.28mm – https://gis.stackexchange.com/a/315989 const float screenScaleFactor = zoomInfo.adaptScaleToScreen ? screenDensityPpi / (0.0254 / 0.00028) : 1.0; - if (!zoomInfo.underzoom - && (zoomLevelInfos.empty() || zoomLevelInfos[0].zoom * zoomInfo.zoomLevelScaleFactor * screenScaleFactor < zoom) - && (zoomLevelInfos.empty() || zoomLevelInfos[0].zoomLevelIdentifier != 0)) { // enable underzoom if the first zoomLevel is zoomLevelIdentifier == 0 + if (!zoomInfo.underzoom && + (zoomLevelInfos.empty() || zoomLevelInfos[0].zoom * zoomInfo.zoomLevelScaleFactor * screenScaleFactor < zoom) && + (zoomLevelInfos.empty() || + zoomLevelInfos[0].zoomLevelIdentifier != 0)) { // enable underzoom if the first zoomLevel is zoomLevelIdentifier == 0 if (lastVisibleTilesHash != 0) { lastVisibleTilesHash = 0; onVisibleTilesChanged({}, false); @@ -617,12 +685,12 @@ void Tiled2dMapSource::onVisibleBoundsChanged(const ::RectCoord &visibl onVisibleTilesChanged({}, false); return; } - targetZoomLayer = (int) numZoomLevels - 1; + targetZoomLayer = (int)numZoomLevels - 1; } int targetZoomLevelIdentifier = zoomLevelInfos.at(targetZoomLayer).zoomLevelIdentifier; int startZoomLayer = 0; - int endZoomLevel = std::min((int) numZoomLevels - 1, targetZoomLayer + 2); + int endZoomLevel = std::min((int)numZoomLevels - 1, targetZoomLayer + 2); int keepZoomLevelOffset = std::max(zoomLevelInfos.at(startZoomLayer).zoomLevelIdentifier, zoomLevelInfos.at(endZoomLevel).zoomLevelIdentifier + ALWAYS_KEEP_LEVEL_TARGET_ZOOM_OFFSET) - targetZoomLevelIdentifier; @@ -668,7 +736,9 @@ void Tiled2dMapSource::onVisibleBoundsChanged(const ::RectCoord &visibl VisibleTilesLayer curVisibleTiles(i - targetZoomLayer); std::vector curVisibleTilesVec; - const double boundsRatio = std::abs(((zoomLevelInfo.bounds.bottomRight.y - zoomLevelInfo.bounds.topLeft.y) / zoomLevelInfo.numTilesY) / ((zoomLevelInfo.bounds.bottomRight.x - zoomLevelInfo.bounds.topLeft.x) / zoomLevelInfo.numTilesX)); + const double boundsRatio = + std::abs(((zoomLevelInfo.bounds.bottomRight.y - zoomLevelInfo.bounds.topLeft.y) / zoomLevelInfo.numTilesY) / + ((zoomLevelInfo.bounds.bottomRight.x - zoomLevelInfo.bounds.topLeft.x) / zoomLevelInfo.numTilesX)); const double tileWidth = zoomLevelInfo.tileWidthLayerSystemUnits; const double tileHeight = zoomLevelInfo.tileWidthLayerSystemUnits * boundsRatio; @@ -684,17 +754,18 @@ void Tiled2dMapSource::onVisibleBoundsChanged(const ::RectCoord &visibl const double boundsLeft = layerBounds.topLeft.x; int startTileLeft = - std::floor(std::max(leftToRight ? (visibleLeft - boundsLeft) : (boundsLeft - visibleLeft), 0.0) / tileWidth); - int maxTileLeft = std::floor( - std::max(leftToRight ? (visibleRight - boundsLeft) : (boundsLeft - visibleRight), 0.0) / tileWidth); + std::floor(std::max(leftToRight ? (visibleLeft - boundsLeft) : (boundsLeft - visibleLeft), 0.0) / tileWidth); + int maxTileLeft = + std::floor(std::max(leftToRight ? (visibleRight - boundsLeft) : (boundsLeft - visibleRight), 0.0) / tileWidth); const double boundsTop = layerBounds.topLeft.y; - int startTileTop = std::floor(std::max(topToBottom ? (visibleTop - boundsTop) : (boundsTop - visibleTop), 0.0) / tileHeight); - int maxTileTop = std::floor( - std::max(topToBottom ? (visibleBottom - boundsTop) : (boundsTop - visibleBottom), 0.0) / tileHeight); + int startTileTop = + std::floor(std::max(topToBottom ? (visibleTop - boundsTop) : (boundsTop - visibleTop), 0.0) / tileHeight); + int maxTileTop = + std::floor(std::max(topToBottom ? (visibleBottom - boundsTop) : (boundsTop - visibleBottom), 0.0) / tileHeight); - if (bounds.has_value()) { - const auto availableTiles = conversionHelper->convertRect(layerSystemId, *bounds); + if (dataBounds.has_value()) { + const auto availableTiles = conversionHelper->convertRect(layerSystemId, *dataBounds); const double tLength = tileWidth / 256; const double tHeight = tileHeight / 256; @@ -702,11 +773,14 @@ void Tiled2dMapSource::onVisibleBoundsChanged(const ::RectCoord &visibl const double tHeightAdj = topToBottom ? tHeight : -tHeight; const double originX = leftToRight ? zoomLevelInfo.bounds.topLeft.x : -zoomLevelInfo.bounds.bottomRight.x; const double originY = topToBottom ? zoomLevelInfo.bounds.bottomRight.y : -zoomLevelInfo.bounds.topLeft.y; - const double minAvailableX = leftToRight ? std::min(availableTiles.topLeft.x, availableTiles.bottomRight.x) : -std::max(availableTiles.topLeft.x, availableTiles.bottomRight.x); - const double minAvailableY = topToBottom ? std::min(availableTiles.topLeft.y, availableTiles.bottomRight.y) : -std::max(availableTiles.topLeft.y, availableTiles.bottomRight.y); - const double maxAvailableX = leftToRight ? std::max(availableTiles.topLeft.x, availableTiles.bottomRight.x) : -std::min(availableTiles.topLeft.x, availableTiles.bottomRight.x); - const double maxAvailableY = topToBottom ? std::max(availableTiles.topLeft.y, availableTiles.bottomRight.y) : -std::min(availableTiles.topLeft.y, availableTiles.bottomRight.y); - + const double minAvailableX = leftToRight ? std::min(availableTiles.topLeft.x, availableTiles.bottomRight.x) + : -std::max(availableTiles.topLeft.x, availableTiles.bottomRight.x); + const double minAvailableY = topToBottom ? std::min(availableTiles.topLeft.y, availableTiles.bottomRight.y) + : -std::max(availableTiles.topLeft.y, availableTiles.bottomRight.y); + const double maxAvailableX = leftToRight ? std::max(availableTiles.topLeft.x, availableTiles.bottomRight.x) + : -std::min(availableTiles.topLeft.x, availableTiles.bottomRight.x); + const double maxAvailableY = topToBottom ? std::max(availableTiles.topLeft.y, availableTiles.bottomRight.y) + : -std::min(availableTiles.topLeft.y, availableTiles.bottomRight.y); int min_left_pixel = floor((minAvailableX - originX) / tLength); int min_left = std::max(0, min_left_pixel / 256); @@ -741,8 +815,7 @@ void Tiled2dMapSource::onVisibleBoundsChanged(const ::RectCoord &visibl for (int y = startTileTop; y <= maxTileTop && y < zoomLevelInfo.numTilesY; y++) { for (int t = 0; t < zoomLevelInfo.numTilesT; t++) { - - if( abs(t - curT) > zoomInfo.numDrawPreviousOrLaterTLayers ) { + if (abs(t - curT) > zoomInfo.numDrawPreviousOrLaterTLayers) { continue; } @@ -751,7 +824,8 @@ void Tiled2dMapSource::onVisibleBoundsChanged(const ::RectCoord &visibl const double tileCenterX = topLeft.x + 0.5f * tileWidthAdj; const double tileCenterY = topLeft.y + 0.5f * tileHeightAdj; - const double tileCenterDis = std::sqrt(std::pow(tileCenterX - centerVisibleX, 2.0) + std::pow(tileCenterY - centerVisibleY, 2.0)); + const double tileCenterDis = + std::sqrt(std::pow(tileCenterX - centerVisibleX, 2.0) + std::pow(tileCenterY - centerVisibleY, 2.0)); float distanceFactor = (tileCenterDis / maxDisCenter) * distanceWeight; float zoomlevelFactor = zoomDistanceFactor * zoomLevelWeight; @@ -761,8 +835,7 @@ void Tiled2dMapSource::onVisibleBoundsChanged(const ::RectCoord &visibl const RectCoord rect(topLeft, bottomRight); curVisibleTilesVec.push_back(PrioritizedTiled2dMapTileInfo( - Tiled2dMapTileInfo(rect, x, y, t, zoomLevelInfo.zoomLevelIdentifier, zoomLevelInfo.zoom), - priority)); + Tiled2dMapTileInfo(rect, x, y, t, zoomLevelInfo.zoomLevelIdentifier, zoomLevelInfo.zoom), priority)); visibleTilesVec.push_back(curVisibleTilesVec.back()); } @@ -775,39 +848,34 @@ void Tiled2dMapSource::onVisibleBoundsChanged(const ::RectCoord &visibl layers.push_back(curVisibleTiles); } - { - currentZoomLevelIdentifier = targetZoomLevelIdentifier; - } + { currentZoomLevelIdentifier = targetZoomLevelIdentifier; } if (lastVisibleTilesHash != visibleTileHash) { lastVisibleTilesHash = visibleTileHash; onVisibleTilesChanged(layers, false, keepZoomLevelOffset); } - currentViewBounds = {PolygonCoord({ - visibleBoundsLayer.topLeft, - Coord(visibleBoundsLayer.topLeft.systemIdentifier, - visibleBoundsLayer.bottomRight.x, - visibleBoundsLayer.topLeft.y, 0), - visibleBoundsLayer.bottomRight, - Coord(visibleBoundsLayer.topLeft.systemIdentifier, - visibleBoundsLayer.topLeft.x, - visibleBoundsLayer.bottomRight.y, 0) - }, {})}; - + currentViewBounds = {PolygonCoord( + {visibleBoundsLayer.topLeft, + Coord(visibleBoundsLayer.topLeft.systemIdentifier, visibleBoundsLayer.bottomRight.x, visibleBoundsLayer.topLeft.y, 0), + visibleBoundsLayer.bottomRight, + Coord(visibleBoundsLayer.topLeft.systemIdentifier, visibleBoundsLayer.topLeft.x, visibleBoundsLayer.bottomRight.y, 0)}, + {})}; } -template -void Tiled2dMapSource::onVisibleTilesChanged(const std::vector &pyramid, bool enforceMultipleLevels, int keepZoomLevelOffset) { +template +void Tiled2dMapSource::onVisibleTilesChanged(const std::vector &pyramid, bool enforceMultipleLevels, + int keepZoomLevelOffset) { currentVisibleTiles.clear(); std::vector toAdd; // make sure all tiles on the current zoom level are scheduled to load (as well as those from the level we always want to keep) - for (const auto &layer: pyramid) { - if ((layer.targetZoomLevelOffset <= 0 && layer.targetZoomLevelOffset >= -zoomInfo.numDrawPreviousLayers) || layer.targetZoomLevelOffset == keepZoomLevelOffset){ - for (auto const &tileInfo: layer.visibleTiles) { + for (const auto &layer : pyramid) { + if ((layer.targetZoomLevelOffset <= 0 && layer.targetZoomLevelOffset >= -zoomInfo.numDrawPreviousLayers) || + layer.targetZoomLevelOffset == keepZoomLevelOffset) { + for (auto const &tileInfo : layer.visibleTiles) { currentVisibleTiles.insert(tileInfo.tileInfo); size_t currentTilesCount = currentTiles.count(tileInfo.tileInfo); @@ -833,12 +901,11 @@ void Tiled2dMapSource::onVisibleTilesChanged(const std::vector::onVisibleTilesChanged(const std::vector::onVisibleTilesChanged(const std::vectorremoveError( - layerConfig->getTileUrl(removedTile.x, removedTile.y, removedTile.t, removedTile.zoomIdentifier)); + layerConfig->getTileUrl(removedTile.x, removedTile.y, removedTile.t, removedTile.zoomIdentifier)); } for (auto it = currentlyLoading.begin(); it != currentlyLoading.end();) { bool found = false; if (it->first.zoomIdentifier <= currentZoomLevelIdentifier) { - for (const auto &layer: pyramid) { - for (auto const &tile: layer.visibleTiles) { + for (const auto &layer : pyramid) { + for (auto const &tile : layer.visibleTiles) { if (it->first == tile.tileInfo) { found = true; break; } } - if(found) { break; } + if (found) { + break; + } } } - if(!found) { - cancelLoad(it->first, it->second); - it = currentlyLoading.erase(it); - } - else - it++; + if (!found) { + cancelLoad(it->first, it->second); + it = currentlyLoading.erase(it); + } else + it++; } - for (auto &[loaderIndex, errors]: errorTiles) { + for (auto &[loaderIndex, errors] : errorTiles) { for (auto it = errors.begin(); it != errors.end();) { bool found = false; - for (const auto &layer: pyramid) { + for (const auto &layer : pyramid) { auto visibleTile = layer.visibleTiles.find({it->first, 0}); if (visibleTile == layer.visibleTiles.end()) { found = true; @@ -901,7 +971,9 @@ void Tiled2dMapSource::onVisibleTilesChanged(const std::vectorremoveError(layerConfig->getTileUrl(it->first.x, it->first.y, it->first.t, it->first.zoomIdentifier)); + if (errorManager) + errorManager->removeError( + layerConfig->getTileUrl(it->first.x, it->first.y, it->first.t, it->first.zoomIdentifier)); it = errors.erase(it); } else { ++it; @@ -914,15 +986,16 @@ void Tiled2dMapSource::onVisibleTilesChanged(const std::vector +template void Tiled2dMapSource::performLoadingTask(Tiled2dMapTileInfo tile, size_t loaderIndex) { - if (currentlyLoading.count(tile) != 0) return; + if (currentlyLoading.count(tile) != 0) + return; if (currentVisibleTiles.count(tile) == 0) { errorTiles[loaderIndex].erase(tile); @@ -944,22 +1017,23 @@ void Tiled2dMapSource::performLoadingTask(Tiled2dMapTileInfo tile, size auto strongScheduler = strongSelf->scheduler.lock(); if (strongScheduler) { strongScheduler->addTask(std::make_shared( - TaskConfig("postLoadingTask", 0.0, TaskPriority::NORMAL, ExecutionEnvironment::COMPUTATION), - [tile, loaderIndex, weakSelfPtr, weakActor, res] { - auto strongSelf = weakSelfPtr.lock(); - if (strongSelf) { - auto isStillVisible = weakActor.syncAccess([tile](auto actor){ - auto strongSelf = actor.lock(); - return strongSelf ? strongSelf->isTileVisible(tile) : false; - }); - if (isStillVisible == false) { - weakActor.message(&Tiled2dMapSource::didFailToLoad, tile, loaderIndex, LoaderStatus::ERROR_OTHER, std::nullopt); - } else { - weakActor.message(&Tiled2dMapSource::didLoad, tile, loaderIndex, - strongSelf->postLoadingTask(res, tile)); - } + TaskConfig("postLoadingTask", 0.0, TaskPriority::NORMAL, ExecutionEnvironment::COMPUTATION), + [tile, loaderIndex, weakSelfPtr, weakActor, res] { + auto strongSelf = weakSelfPtr.lock(); + if (strongSelf) { + auto isStillVisible = weakActor.syncAccess([tile](auto actor) { + auto strongSelf = actor.lock(); + return strongSelf ? strongSelf->isTileVisible(tile) : false; + }); + if (isStillVisible == false) { + weakActor.message(&Tiled2dMapSource::didFailToLoad, tile, loaderIndex, + LoaderStatus::ERROR_OTHER, std::nullopt); + } else { + weakActor.message(&Tiled2dMapSource::didLoad, tile, loaderIndex, + strongSelf->postLoadingTask(res, tile)); } - })); + } + })); } } else { weakActor.message(&Tiled2dMapSource::didLoad, tile, loaderIndex, strongSelf->postLoadingTask(res, tile)); @@ -971,7 +1045,7 @@ void Tiled2dMapSource::performLoadingTask(Tiled2dMapTileInfo tile, size }); } -template +template void Tiled2dMapSource::didLoad(Tiled2dMapTileInfo tile, size_t loaderIndex, const R &result) { currentlyLoading.erase(tile); std::string layerName = layerConfig->getLayerName(); @@ -988,16 +1062,15 @@ void Tiled2dMapSource::didLoad(Tiled2dMapTileInfo tile, size_t loaderIn } auto bounds = tile.bounds; - PolygonCoord mask({ bounds.topLeft, - Coord(bounds.topLeft.systemIdentifier, bounds.bottomRight.x, bounds.topLeft.y, 0), - bounds.bottomRight, - Coord(bounds.topLeft.systemIdentifier, bounds.topLeft.x, bounds.bottomRight.y, 0), - bounds.topLeft }, {}); + PolygonCoord mask({bounds.topLeft, Coord(bounds.topLeft.systemIdentifier, bounds.bottomRight.x, bounds.topLeft.y, 0), + bounds.bottomRight, Coord(bounds.topLeft.systemIdentifier, bounds.topLeft.x, bounds.bottomRight.y, 0), + bounds.topLeft}, + {}); gpc_polygon tilePolygon; gpc_set_polygon({mask}, &tilePolygon); - currentTiles.insert({tile, TileWrapper(result, std::vector<::PolygonCoord>{ }, mask, tilePolygon, tile.tessellationFactor)}); + currentTiles.insert({tile, TileWrapper(result, std::vector<::PolygonCoord>{}, mask, tilePolygon, tile.tessellationFactor)}); errorTiles[loaderIndex].erase(tile); @@ -1006,8 +1079,9 @@ void Tiled2dMapSource::didLoad(Tiled2dMapTileInfo tile, size_t loaderIn notifyTilesUpdates(); } -template -void Tiled2dMapSource::didFailToLoad(Tiled2dMapTileInfo tile, size_t loaderIndex, const LoaderStatus &status, const std::optional &errorCode) { +template +void Tiled2dMapSource::didFailToLoad(Tiled2dMapTileInfo tile, size_t loaderIndex, const LoaderStatus &status, + const std::optional &errorCode) { currentlyLoading.erase(tile); const bool isVisible = currentVisibleTiles.count(tile); @@ -1019,72 +1093,67 @@ void Tiled2dMapSource::didFailToLoad(Tiled2dMapTileInfo tile, size_t lo auto errorManager = this->errorManager; switch (status) { - case LoaderStatus::OK: { - assert(false); - break; - } - case LoaderStatus::NOOP: { - errorTiles[loaderIndex].erase(tile); + case LoaderStatus::OK: { + assert(false); + break; + } + case LoaderStatus::NOOP: { + errorTiles[loaderIndex].erase(tile); - auto newLoaderIndex = loaderIndex + 1; - performLoadingTask(tile, newLoaderIndex); + auto newLoaderIndex = loaderIndex + 1; + performLoadingTask(tile, newLoaderIndex); - break; + break; + } + case LoaderStatus::ERROR_400: + case LoaderStatus::ERROR_404: { + notFoundTiles.insert(tile); + + errorTiles[loaderIndex].erase(tile); + + if (errorManager) { + errorManager->addTiledLayerError(TiledLayerError(status, errorCode, layerName, + layerConfig->getTileUrl(tile.x, tile.y, tile.t, tile.zoomIdentifier), + false, tile.bounds)); } - case LoaderStatus::ERROR_400: - case LoaderStatus::ERROR_404: { - notFoundTiles.insert(tile); - - errorTiles[loaderIndex].erase(tile); - - if (errorManager) { - errorManager->addTiledLayerError(TiledLayerError(status, - errorCode, - layerName, - layerConfig->getTileUrl(tile.x, tile.y, tile.t,tile.zoomIdentifier), - false, - tile.bounds)); - } - break; + break; + } + + case LoaderStatus::ERROR_TIMEOUT: + case LoaderStatus::ERROR_OTHER: + case LoaderStatus::ERROR_NETWORK: { + const auto now = DateHelper::currentTimeMillis(); + int64_t delay = 0; + if (errorTiles[loaderIndex].count(tile) != 0) { + errorTiles[loaderIndex].at(tile).lastLoad = now; + errorTiles[loaderIndex].at(tile).delay = std::min(2 * errorTiles[loaderIndex].at(tile).delay, MAX_WAIT_TIME); + } else { + errorTiles[loaderIndex][tile] = {now, MIN_WAIT_TIME}; } + delay = errorTiles[loaderIndex].at(tile).delay; - case LoaderStatus::ERROR_TIMEOUT: - case LoaderStatus::ERROR_OTHER: - case LoaderStatus::ERROR_NETWORK: { - const auto now = DateHelper::currentTimeMillis(); - int64_t delay = 0; - if (errorTiles[loaderIndex].count(tile) != 0) { - errorTiles[loaderIndex].at(tile).lastLoad = now; - errorTiles[loaderIndex].at(tile).delay = std::min(2 * errorTiles[loaderIndex].at(tile).delay, MAX_WAIT_TIME); - } else { - errorTiles[loaderIndex][tile] = {now, MIN_WAIT_TIME}; - } - delay = errorTiles[loaderIndex].at(tile).delay; - - if (errorManager) { - errorManager->addTiledLayerError(TiledLayerError(status, - errorCode, - layerConfig->getLayerName(), - layerConfig->getTileUrl(tile.x, tile.y, tile.t, tile.zoomIdentifier), - true, - tile.bounds)); - } + if (errorManager) { + errorManager->addTiledLayerError(TiledLayerError(status, errorCode, layerConfig->getLayerName(), + layerConfig->getTileUrl(tile.x, tile.y, tile.t, tile.zoomIdentifier), + true, tile.bounds)); + } - if (!nextDelayTaskExecution || nextDelayTaskExecution > now + delay ) { - nextDelayTaskExecution = now + delay; + if (!nextDelayTaskExecution || nextDelayTaskExecution > now + delay) { + nextDelayTaskExecution = now + delay; - auto taskIdentifier = "Tiled2dMapSource_loadingErrorTask"; + auto taskIdentifier = "Tiled2dMapSource_loadingErrorTask"; - auto strongScheduler = scheduler.lock(); - if (strongScheduler) { - auto weakActor = WeakActor(mailbox, std::dynamic_pointer_cast(shared_from_this())); - strongScheduler->addTask(std::make_shared(TaskConfig(taskIdentifier, delay, TaskPriority::NORMAL, ExecutionEnvironment::IO), [weakActor] { - weakActor.message(&Tiled2dMapSource::performDelayedTasks); - })); - } + auto strongScheduler = scheduler.lock(); + if (strongScheduler) { + auto weakActor = + WeakActor(mailbox, std::dynamic_pointer_cast(shared_from_this())); + strongScheduler->addTask( + std::make_shared(TaskConfig(taskIdentifier, delay, TaskPriority::NORMAL, ExecutionEnvironment::IO), + [weakActor] { weakActor.message(&Tiled2dMapSource::performDelayedTasks); })); } - break; } + break; + } } updateTileMasks(); @@ -1092,9 +1161,7 @@ void Tiled2dMapSource::didFailToLoad(Tiled2dMapTileInfo tile, size_t lo notifyTilesUpdates(); } - -template -void Tiled2dMapSource::performDelayedTasks() { +template void Tiled2dMapSource::performDelayedTasks() { nextDelayTaskExecution = std::nullopt; const auto now = DateHelper::currentTimeMillis(); @@ -1102,8 +1169,8 @@ void Tiled2dMapSource::performDelayedTasks() { std::vector> toLoad; - for (auto &[loaderIndex, errors]: errorTiles) { - for(auto &[tile, errorInfo]: errors) { + for (auto &[loaderIndex, errors] : errorTiles) { + for (auto &[tile, errorInfo] : errors) { if (errorInfo.lastLoad + errorInfo.delay >= now) { toLoad.push_back({loaderIndex, tile}); } else { @@ -1112,7 +1179,7 @@ void Tiled2dMapSource::performDelayedTasks() { } } - for (auto &[loaderIndex, tile]: toLoad) { + for (auto &[loaderIndex, tile] : toLoad) { performLoadingTask(tile, loaderIndex); } @@ -1124,18 +1191,17 @@ void Tiled2dMapSource::performDelayedTasks() { auto strongScheduler = scheduler.lock(); if (strongScheduler) { auto weakActor = WeakActor(mailbox, std::dynamic_pointer_cast(shared_from_this())); - strongScheduler->addTask(std::make_shared(TaskConfig(taskIdentifier, minDelay, TaskPriority::NORMAL, ExecutionEnvironment::IO), [weakActor] { - weakActor.message(&Tiled2dMapSource::performDelayedTasks); - })); + strongScheduler->addTask( + std::make_shared(TaskConfig(taskIdentifier, minDelay, TaskPriority::NORMAL, ExecutionEnvironment::IO), + [weakActor] { weakActor.message(&Tiled2dMapSource::performDelayedTasks); })); } } } -template -void Tiled2dMapSource::updateTileMasks() { +template void Tiled2dMapSource::updateTileMasks() { if (!zoomInfo.maskTile) { - for (auto it = currentTiles.rbegin(); it != currentTiles.rend(); it++){ + for (auto it = currentTiles.rbegin(); it != currentTiles.rend(); it++) { auto &[tileInfo, tileWrapper] = *it; if (readyTiles.count(tileInfo) == 0) { tileWrapper.state = TileState::IN_SETUP; @@ -1162,7 +1228,7 @@ void Tiled2dMapSource::updateTileMasks() { bool completeViewBoundsDrawn = false; - for (auto it = currentTiles.rbegin(); it != currentTiles.rend(); it++){ + for (auto it = currentTiles.rbegin(); it != currentTiles.rend(); it++) { auto &[tileInfo, tileWrapper] = *it; tileWrapper.state = TileState::VISIBLE; @@ -1229,13 +1295,13 @@ void Tiled2dMapSource::updateTileMasks() { gpc_free_polygon(&polygonDiff); } } else { - tileWrapper.masks = { tileWrapper.tileBounds }; + tileWrapper.masks = {tileWrapper.tileBounds}; } // add tileBounds to currentTileMask if (tileWrapper.state == TileState::VISIBLE) { if (isFirst) { - gpc_set_polygon({ tileWrapper.tileBounds }, ¤tTileMask); + gpc_set_polygon({tileWrapper.tileBounds}, ¤tTileMask); isFirst = false; } else { gpc_polygon result; @@ -1248,39 +1314,40 @@ void Tiled2dMapSource::updateTileMasks() { } } - if(freeCurrent) { + if (freeCurrent) { gpc_free_polygon(¤tTileMask); } gpc_free_polygon(¤tViewBoundsPolygon); } -template -void Tiled2dMapSource::setTileReady(const Tiled2dMapVersionedTileInfo &tile) { +template void Tiled2dMapSource::setTileReady(const Tiled2dMapVersionedTileInfo &tile) { bool needsUpdate = false; - + if (readyTiles.count(tile.tileInfo) == 0) { - if (currentTiles.count(tile.tileInfo) != 0){ + if (currentTiles.count(tile.tileInfo) != 0) { readyTiles.insert(tile.tileInfo); outdatedTiles.erase(tile.tileInfo); needsUpdate = true; } } - - if (!needsUpdate) { return; } - + + if (!needsUpdate) { + return; + } + updateTileMasks(); - + notifyTilesUpdates(); } -template +template void Tiled2dMapSource::setTilesReady(const std::vector &tiles) { bool needsUpdate = false; - - for (auto const &tile: tiles) { + + for (auto const &tile : tiles) { if (readyTiles.count(tile.tileInfo) == 0 || outdatedTiles.count(tile.tileInfo) > 0) { const auto &tileEntry = currentTiles.find(tile.tileInfo); - if (tileEntry != currentTiles.end()){ + if (tileEntry != currentTiles.end()) { if (!zoomInfo.maskTile) { tileEntry->second.state = TileState::VISIBLE; } @@ -1290,50 +1357,41 @@ void Tiled2dMapSource::setTilesReady(const std::vector -void Tiled2dMapSource::setMinZoomLevelIdentifier(std::optional value) { +template void Tiled2dMapSource::setMinZoomLevelIdentifier(std::optional value) { minZoomLevelIdentifier = value; } -template -void Tiled2dMapSource::setMaxZoomLevelIdentifier(std::optional value) { +template void Tiled2dMapSource::setMaxZoomLevelIdentifier(std::optional value) { maxZoomLevelIdentifier = value; } -template -std::optional Tiled2dMapSource::getMinZoomLevelIdentifier() { +template std::optional Tiled2dMapSource::getMinZoomLevelIdentifier() { return minZoomLevelIdentifier; } -template -std::optional Tiled2dMapSource::getMaxZoomLevelIdentifier() { +template std::optional Tiled2dMapSource::getMaxZoomLevelIdentifier() { return maxZoomLevelIdentifier; } -template -void Tiled2dMapSource::pause() { - isPaused = true; -} +template void Tiled2dMapSource::pause() { isPaused = true; } -template -void Tiled2dMapSource::resume() { - isPaused = false; -} +template void Tiled2dMapSource::resume() { isPaused = false; } -template -::LayerReadyState Tiled2dMapSource::isReadyToRenderOffscreen() { +template ::LayerReadyState Tiled2dMapSource::isReadyToRenderOffscreen() { if (notFoundTiles.size() > 0) { return LayerReadyState::ERROR; } - for (auto const &[index, errors]: errorTiles) { + for (auto const &[index, errors] : errorTiles) { if (errors.size() > 0) { return LayerReadyState::ERROR; } @@ -1343,7 +1401,7 @@ ::LayerReadyState Tiled2dMapSource::isReadyToRenderOffscreen() { return LayerReadyState::NOT_READY; } - for (const auto& visible : currentVisibleTiles) { + for (const auto &visible : currentVisibleTiles) { if (currentTiles.count(visible) == 0) { return LayerReadyState::NOT_READY; } @@ -1355,17 +1413,16 @@ ::LayerReadyState Tiled2dMapSource::isReadyToRenderOffscreen() { return LayerReadyState::READY; } -template +template void Tiled2dMapSource::setErrorManager(const std::shared_ptr<::ErrorManager> &errorManager) { this->errorManager = errorManager; } -template -void Tiled2dMapSource::forceReload() { +template void Tiled2dMapSource::forceReload() { - //set delay to 0 for all error tiles - for (auto &[loaderIndex, errors]: errorTiles) { - for(auto &[tile, errorInfo]: errors) { + // set delay to 0 for all error tiles + for (auto &[loaderIndex, errors] : errorTiles) { + for (auto &[tile, errorInfo] : errors) { errorInfo.delay = 1; performLoadingTask(tile, loaderIndex); } @@ -1374,20 +1431,19 @@ void Tiled2dMapSource::forceReload() { onVisibleTilesChanged(currentPyramid, currentKeepZoomLevelOffset); } -template -void Tiled2dMapSource::reloadTiles() { +template void Tiled2dMapSource::reloadTiles() { outdatedTiles.clear(); outdatedTiles.insert(currentTiles.begin(), currentTiles.end()); - + currentTiles.clear(); readyTiles.clear(); - for (auto it = currentlyLoading.begin(); it != currentlyLoading.end(); ++it ) { + for (auto it = currentlyLoading.begin(); it != currentlyLoading.end(); ++it) { cancelLoad(it->first, it->second); } currentlyLoading.clear(); errorTiles.clear(); lastVisibleTilesHash = -1; - onVisibleTilesChanged(currentPyramid, false,currentKeepZoomLevelOffset); + onVisibleTilesChanged(currentPyramid, false, currentKeepZoomLevelOffset); } diff --git a/shared/src/map/camera/MapCamera3d.cpp b/shared/src/map/camera/MapCamera3d.cpp index 9be7abfc8..b16c9fb7c 100644 --- a/shared/src/map/camera/MapCamera3d.cpp +++ b/shared/src/map/camera/MapCamera3d.cpp @@ -9,10 +9,14 @@ */ #include "MapCamera3d.h" +#include "Camera3dConfigFactory.h" #include "Coord.h" #include "CoordAnimation.h" +#include "CoordHelper.h" +#include "CoordinateSystemIdentifiers.h" #include "DateHelper.h" #include "DoubleAnimation.h" +#include "Logger.h" #include "MapConfig.h" #include "MapInterface.h" #include "Matrix.h" @@ -21,37 +25,33 @@ #include "Vec2DHelper.h" #include "Vec2FHelper.h" #include "Vec3DHelper.h" -#include "Logger.h" -#include "CoordinateSystemIdentifiers.h" -#include "CoordHelper.h" #include "VectorHelper.h" -#include "Camera3dConfigFactory.h" -#include "MapCamera3DHelper.h" #include "Camera3dConfig.h" +#include "MapCamera3DHelper.h" #define ROTATION_THRESHOLD 20 #define ROTATION_LOCKING_ANGLE 10 #define ROTATION_LOCKING_FACTOR 1.5 -#define GLOBE_MIN_ZOOM 200'000'000 -#define GLOBE_MAX_ZOOM 5'000'000 +#define GLOBE_MIN_ZOOM 200'000'000 +#define GLOBE_MAX_ZOOM 5'000'000 MapCamera3d::MapCamera3d(const std::shared_ptr &mapInterface, float screenDensityPpi) : mapInterface(mapInterface) , conversionHelper(mapInterface->getCoordinateConverterHelper()) , mapCoordinateSystem(mapInterface->getMapConfig().mapCoordinateSystem) , screenDensityPpi(screenDensityPpi) - , screenPixelAsRealMeterFactor(0.0254 / screenDensityPpi * mapCoordinateSystem.unitToScreenMeterFactor), - focusPointPosition(CoordinateSystemIdentifiers::EPSG4326(), 0, 0, 0), - cameraPitch(0), - zoomMin(GLOBE_MIN_ZOOM), - zoomMax(GLOBE_MAX_ZOOM), - lastOnTouchDownPoint(std::nullopt) - , bounds(mapCoordinateSystem.bounds), - origin(0, 0, 0), -cameraZoomConfig(Camera3dConfigFactory::getBasicConfig()) -{ + , screenPixelAsRealMeterFactor(0.0254 / screenDensityPpi * mapCoordinateSystem.unitToScreenMeterFactor) + , focusPointPosition(CoordinateSystemIdentifiers::EPSG4326(), 0, 0, 0) + , cameraPitch(0) + , zoomMin(GLOBE_MIN_ZOOM) + , zoomMax(GLOBE_MAX_ZOOM) + , lastOnTouchDownPoint(std::nullopt) + , bounds(mapCoordinateSystem.bounds) + , origin(0, 0, 0) + , cameraZoomConfig(Camera3dConfigFactory::getBasicConfig()) + , coordinateConversionHelper(mapInterface->getCoordinateConverterHelper()) { mapSystemRtl = mapCoordinateSystem.bounds.bottomRight.x > mapCoordinateSystem.bounds.topLeft.x; mapSystemTtb = mapCoordinateSystem.bounds.bottomRight.y > mapCoordinateSystem.bounds.topLeft.y; updateZoom(GLOBE_MIN_ZOOM); @@ -91,9 +91,11 @@ void MapCamera3d::moveToCenterPositionZoom(const ::Coord ¢erPosition, double if (cameraFrozen) return; inertia = std::nullopt; - auto [focusPosition, focusZoom] = getBoundsCorrectedCoords(mapInterface->getCoordinateConverterHelper()->convert(focusPointPosition.systemIdentifier, centerPosition), zoom); + auto [focusPosition, focusZoom] = getBoundsCorrectedCoords( + coordinateConversionHelper->convert(focusPointPosition.systemIdentifier, centerPosition), zoom); - if (animated && bounds.topLeft.x == mapCoordinateSystem.bounds.topLeft.x && bounds.bottomRight.x == mapCoordinateSystem.bounds.bottomRight.x) { + if (animated && bounds.topLeft.x == mapCoordinateSystem.bounds.topLeft.x && + bounds.bottomRight.x == mapCoordinateSystem.bounds.bottomRight.x) { // wrappable on longitude if (focusPosition.x - focusPointPosition.x > 180.0) { focusPosition.x -= 360.0; @@ -105,9 +107,11 @@ void MapCamera3d::moveToCenterPositionZoom(const ::Coord ¢erPosition, double if (animated) { std::lock_guard lock(animationMutex); coordAnimation = std::make_shared( - cameraZoomConfig.animationDurationMs, focusPointPosition, focusPosition, centerPosition, InterpolatorFunction::EaseInOut, + cameraZoomConfig.animationDurationMs, focusPointPosition, focusPosition, centerPosition, + InterpolatorFunction::EaseInOut, [=](Coord positionMapSystem) { assert(positionMapSystem.systemIdentifier == 4326); + std::lock_guard lock(paramMutex); this->focusPointPosition = positionMapSystem; clampCenterToPaddingCorrectedBounds(); notifyListeners(ListenerType::BOUNDS); @@ -115,6 +119,7 @@ void MapCamera3d::moveToCenterPositionZoom(const ::Coord ¢erPosition, double }, [=] { assert(this->coordAnimation->endValue.systemIdentifier == 4326); + std::lock_guard lock(paramMutex); this->focusPointPosition = this->coordAnimation->endValue; clampCenterToPaddingCorrectedBounds(); notifyListeners(ListenerType::BOUNDS); @@ -126,6 +131,7 @@ void MapCamera3d::moveToCenterPositionZoom(const ::Coord ¢erPosition, double mapInterface->invalidate(); } else { assert(focusPosition.systemIdentifier == 4326); + std::lock_guard lock(paramMutex); this->focusPointPosition = focusPosition; updateZoom(focusZoom); validVpMatrix = false; @@ -138,9 +144,11 @@ void MapCamera3d::moveToCenterPosition(const ::Coord ¢erPosition, bool anima if (cameraFrozen) return; inertia = std::nullopt; - auto [focusPosition, focusZoom] = getBoundsCorrectedCoords(mapInterface->getCoordinateConverterHelper()->convert(focusPointPosition.systemIdentifier, centerPosition), zoom); + auto [focusPosition, focusZoom] = getBoundsCorrectedCoords( + coordinateConversionHelper->convert(focusPointPosition.systemIdentifier, centerPosition), zoom); - if (animated && bounds.topLeft.x == mapCoordinateSystem.bounds.topLeft.x && bounds.bottomRight.x == mapCoordinateSystem.bounds.bottomRight.x) { + if (animated && bounds.topLeft.x == mapCoordinateSystem.bounds.topLeft.x && + bounds.bottomRight.x == mapCoordinateSystem.bounds.bottomRight.x) { // wrappable on longitude if (focusPosition.x - focusPointPosition.x > 180.0) { focusPosition.x -= 360.0; @@ -152,7 +160,8 @@ void MapCamera3d::moveToCenterPosition(const ::Coord ¢erPosition, bool anima if (animated) { std::lock_guard lock(animationMutex); coordAnimation = std::make_shared( - cameraZoomConfig.animationDurationMs, focusPointPosition, focusPosition, centerPosition, InterpolatorFunction::EaseInOut, + cameraZoomConfig.animationDurationMs, focusPointPosition, focusPosition, centerPosition, + InterpolatorFunction::EaseInOut, [=](Coord positionMapSystem) { assert(positionMapSystem.systemIdentifier == 4326); this->focusPointPosition = positionMapSystem; @@ -179,7 +188,8 @@ void MapCamera3d::moveToCenterPosition(const ::Coord ¢erPosition, bool anima } } -void MapCamera3d::moveToBoundingBox(const RectCoord &boundingBox, float paddingPc, bool animated, std::optional minZoom, std::optional maxZoom) { +void MapCamera3d::moveToBoundingBox(const RectCoord &boundingBox, float paddingPc, bool animated, std::optional minZoom, + std::optional maxZoom) { if (cameraFrozen) return; RectCoord mapSystemBBox = conversionHelper->convertRect(mapCoordinateSystem.identifier, boundingBox); @@ -235,7 +245,7 @@ void MapCamera3d::setZoom(double zoom, bool animated) { if (animated) { std::lock_guard lock(animationMutex); zoomAnimation = std::make_shared( - cameraZoomConfig.animationDurationMs, this->zoom, targetZoom, InterpolatorFunction::EaseIn, + cameraZoomConfig.animationDurationMs, this->zoom, targetZoom, InterpolatorFunction::EaseIn, [=](double zoom) { this->setZoom(zoom, false); }, [=] { this->setZoom(targetZoom, false); @@ -266,7 +276,7 @@ void MapCamera3d::setRotation(float angle, bool animated) { } std::lock_guard lock(animationMutex); rotationAnimation = std::make_shared( - cameraZoomConfig.animationDurationMs, currentAngle, newAngle, InterpolatorFunction::Linear, + cameraZoomConfig.animationDurationMs, currentAngle, newAngle, InterpolatorFunction::Linear, [=](double angle) { this->setRotation(angle, false); }, [=] { this->setRotation(newAngle, false); @@ -275,6 +285,7 @@ void MapCamera3d::setRotation(float angle, bool animated) { rotationAnimation->start(); mapInterface->invalidate(); } else { + std::lock_guard lock(paramMutex); double angleDiff = newAngle - this->angle; Coord centerScreen = focusPointPosition; Coord realCenter = getCenterPosition(); @@ -297,7 +308,7 @@ void MapCamera3d::setPaddingLeft(float padding) { if (coordAnimation && coordAnimation->helperCoord.has_value()) { double targetZoom = (zoomAnimation) ? zoomAnimation->endValue : getZoom(); const auto [adjPosition, adjZoom] = - getBoundsCorrectedCoords(adjustCoordForPadding(*coordAnimation->helperCoord, targetZoom), targetZoom); + getBoundsCorrectedCoords(adjustCoordForPadding(*coordAnimation->helperCoord, targetZoom), targetZoom); coordAnimation->endValue = adjPosition; if (zoomAnimation) { zoomAnimation->endValue = adjZoom; @@ -313,7 +324,7 @@ void MapCamera3d::setPaddingRight(float padding) { if (coordAnimation && coordAnimation->helperCoord.has_value()) { double targetZoom = (zoomAnimation) ? zoomAnimation->endValue : getZoom(); const auto [adjPosition, adjZoom] = - getBoundsCorrectedCoords(adjustCoordForPadding(*coordAnimation->helperCoord, targetZoom), targetZoom); + getBoundsCorrectedCoords(adjustCoordForPadding(*coordAnimation->helperCoord, targetZoom), targetZoom); coordAnimation->endValue = adjPosition; if (zoomAnimation) { zoomAnimation->endValue = adjZoom; @@ -329,7 +340,7 @@ void MapCamera3d::setPaddingTop(float padding) { if (coordAnimation && coordAnimation->helperCoord.has_value()) { double targetZoom = (zoomAnimation) ? zoomAnimation->endValue : getZoom(); const auto [adjPosition, adjZoom] = - getBoundsCorrectedCoords(adjustCoordForPadding(*coordAnimation->helperCoord, targetZoom), targetZoom); + getBoundsCorrectedCoords(adjustCoordForPadding(*coordAnimation->helperCoord, targetZoom), targetZoom); coordAnimation->endValue = adjPosition; if (zoomAnimation) { zoomAnimation->endValue = adjZoom; @@ -345,7 +356,7 @@ void MapCamera3d::setPaddingBottom(float padding) { if (coordAnimation && coordAnimation->helperCoord.has_value()) { double targetZoom = (zoomAnimation) ? zoomAnimation->endValue : getZoom(); const auto [adjPosition, adjZoom] = - getBoundsCorrectedCoords(adjustCoordForPadding(*coordAnimation->helperCoord, targetZoom), targetZoom); + getBoundsCorrectedCoords(adjustCoordForPadding(*coordAnimation->helperCoord, targetZoom), targetZoom); coordAnimation->endValue = adjPosition; if (zoomAnimation) { zoomAnimation->endValue = adjZoom; @@ -372,32 +383,31 @@ void MapCamera3d::removeListener(const std::shared_ptr MapCamera3d::asCameraInterface() { return shared_from_this(); } std::vector MapCamera3d::getVpMatrix() { - if(cameraZoomConfig.rotationSpeed) { - double speed = *(cameraZoomConfig.rotationSpeed); - focusPointPosition.x = fmod(DateHelper::currentTimeMicros() * speed * 0.000003 + 180.0, 360.0) - 180.0; - mapInterface->invalidate(); - } - - return std::get<0>(getVpMatrix(focusPointPosition, true)); + std::lock_guard lock(matrixMutex); + return VectorHelper::clone(vpMatrix); } -std::tuple, std::vector, Vec3D> MapCamera3d::getVpMatrix(const Coord &focusCoord, bool updateVariables) { +void MapCamera3d::updateMatrices() { + std::lock_guard lock(paramMutex); + Vec2I sizeViewport = mapInterface->getRenderingContext()->getViewportSize(); std::vector newViewMatrix(16, 0.0); std::vector newProjectionMatrix(16, 0.0); + auto focusCoord = focusPointPosition; + const float R = 6378137.0; const double longitude = focusCoord.x; // px / R; - const double latitude = focusCoord.y; // 2*atan(exp(py / R)) - 3.1415926 / 2; + const double latitude = focusCoord.y; // 2*atan(exp(py / R)) - 3.1415926 / 2; const double focusPointAltitude = focusCoord.z; - double cameraDistance = getCameraDistance(); + double cameraDistance = getCameraDistance(sizeViewport); double fovy = getCameraFieldOfView(); // 45 // zoom / 70800; const double minCameraDistance = 1.05; if (cameraDistance < minCameraDistance) { double d = minCameraDistance * R; - double pixelsPerMeter = this->screenDensityPpi / 0.0254; + double pixelsPerMeter = this->screenDensityPpi / 0.0254; double w = (double)sizeViewport.y; fovy = atan2(zoom * w / pixelsPerMeter / 2.0, d) * 2.0 / M_PI * 180.0; @@ -408,7 +418,7 @@ std::tuple, std::vector, Vec3D> MapCamera3d::getVpMat const double minD = cameraDistance - 1.0; // aspect ratio - const double vpr = (double) sizeViewport.x / (double) sizeViewport.y; + const double vpr = (double)sizeViewport.x / (double)sizeViewport.y; if (vpr > 1.0) { fovy /= vpr; } @@ -417,7 +427,7 @@ std::tuple, std::vector, Vec3D> MapCamera3d::getVpMat // initial perspective projection MatrixD::perspectiveM(newProjectionMatrix, 0, fovy, vpr, minD, maxD); -// MatrixD::setIdentityM(newProjectionMatrix, 0); + // MatrixD::setIdentityM(newProjectionMatrix, 0); // modify projection // translate anchor point based on padding and vertical displacement @@ -435,7 +445,6 @@ std::tuple, std::vector, Vec3D> MapCamera3d::getVpMat // read from top to bottom as vertex movement relative to fixed camera MatrixD::setIdentityM(newViewMatrix, 0); - MatrixD::translateM(newViewMatrix, 0, 0.0, 0, -cameraDistance); MatrixD::rotateM(newViewMatrix, 0, -cameraPitch, 1.0, 0.0, 0.0); MatrixD::rotateM(newViewMatrix, 0, -angle, 0.0, 0.0, 1.0); @@ -446,11 +455,10 @@ std::tuple, std::vector, Vec3D> MapCamera3d::getVpMat MatrixD::rotateM(newViewMatrix, 0.0, -longitude, 0.0, 1.0, 0.0); MatrixD::rotateM(newViewMatrix, 0.0, -90, 0.0, 1.0, 0.0); // zero longitude in London - const double lo = (longitude - 180.0) * M_PI / 180.0; // [-2 * pi, 0) X - const double la = (latitude - 90.0) * M_PI / 180.0; // [0, -pi] Y + const double la = (latitude - 90.0) * M_PI / 180.0; // [0, -pi] Y const double x = (1.0 * sin(la) * cos(lo)); - const double y = (1.0 * cos(la)) ; + const double y = (1.0 * cos(la)); const double z = -(1.0 * sin(la) * sin(lo)); const Vec3D newOrigin = Vec3D(x, y, z); @@ -467,30 +475,26 @@ std::tuple, std::vector, Vec3D> MapCamera3d::getVpMat std::vector newProjectionMatrixF = VectorHelper::convertToFloat(newProjectionMatrix); std::vector newViewMatrixF = VectorHelper::convertToFloat(newViewMatrix); - - if (updateVariables) { - std::lock_guard lock(vpDataMutex); - lastVpRotation = angle; - lastVpZoom = zoom; - vpMatrix = newVpMatrixF; - vpMatrixD = newVpMatrix; - inverseVPMatrix = newInverseMatrix; - viewMatrix = newViewMatrixF; - projectionMatrix = newProjectionMatrixF; - verticalFov = fovy; - horizontalFov = fovy * vpr; - validVpMatrix = true; - origin = newOrigin; - lastScalingFactor = mapUnitsFromPixels(1.0); - } - return std::make_tuple(newVpMatrixF, newInverseMatrix, newOrigin); + std::lock_guard writeLock(matrixMutex); + lastVpRotation = angle; + lastVpZoom = zoom; + vpMatrix = newVpMatrixF; + vpMatrixD = newVpMatrix; + inverseVPMatrix = newInverseMatrix; + viewMatrix = newViewMatrixF; + projectionMatrix = newProjectionMatrixF; + verticalFov = fovy; + horizontalFov = fovy * vpr; + validVpMatrix = true; + origin = newOrigin; + lastScalingFactor = mapUnitsFromPixels(1.0); } Vec3D MapCamera3d::getOrigin() { + std::lock_guard writeLock(matrixMutex); return origin; } - // Funktion zur Berechnung der Koeffizienten der projizierten Ellipse std::vector MapCamera3d::computeEllipseCoefficients() { std::vector tmp = VectorHelper::clone(vpMatrixD); @@ -501,39 +505,47 @@ std::vector MapCamera3d::computeEllipseCoefficients() { } std::optional> MapCamera3d::getLastVpMatrixD() { - std::lock_guard lock(vpDataMutex); + std::lock_guard lock(matrixMutex); return VectorHelper::clone(vpMatrixD); } std::optional> MapCamera3d::getLastVpMatrix() { // TODO: Add back as soon as visiblerect calculation is done -// if (!lastVpBounds) { -// return std::nullopt; -// } - std::lock_guard lock(vpDataMutex); + // if (!lastVpBounds) { + // return std::nullopt; + // } + std::lock_guard lock(matrixMutex); std::vector vpCopy; std::copy(vpMatrix.begin(), vpMatrix.end(), std::back_inserter(vpCopy)); return vpCopy; } std::optional<::RectCoord> MapCamera3d::getLastVpMatrixViewBounds() { - std::lock_guard lock(vpDataMutex); + std::lock_guard lock(matrixMutex); return lastVpBounds; } std::optional MapCamera3d::getLastVpMatrixRotation() { - std::lock_guard lock(vpDataMutex); + std::lock_guard lock(matrixMutex); return lastVpRotation; } std::optional MapCamera3d::getLastVpMatrixZoom() { - std::lock_guard lock(vpDataMutex); + std::lock_guard lock(matrixMutex); return lastVpZoom; } /** this method is called just before the update methods on all layers */ void MapCamera3d::update() { inertiaStep(); + if (cameraZoomConfig.rotationSpeed) { + std::lock_guard lock(paramMutex); + double speed = *(cameraZoomConfig.rotationSpeed); + focusPointPosition.x = fmod(DateHelper::currentTimeMicros() * speed * 0.000003 + 180.0, 360.0) - 180.0; + mapInterface->invalidate(); + } + focusPointPosition.x = sin(DateHelper::currentTimeMicros() * 0.00001) * 0.01 + 7.44894; + mapInterface->invalidate(); { std::lock_guard lock(animationMutex); if (zoomAnimation) @@ -547,6 +559,7 @@ void MapCamera3d::update() { if (verticalDisplacementAnimation) std::static_pointer_cast(verticalDisplacementAnimation)->update(); } + updateMatrices(); } std::vector MapCamera3d::getInvariantModelMatrix(const ::Coord &coordinate, bool scaleInvariant, bool rotationInvariant) { @@ -557,7 +570,7 @@ std::vector MapCamera3d::getInvariantModelMatrix(const ::Coord &coordinat Matrix::translateM(newMatrix, 0, renderCoord.x, renderCoord.y, renderCoord.z); if (scaleInvariant) { - double zoomFactor = mapUnitsFromPixels(1.0); + double zoomFactor = getScalingFactor(); Matrix::scaleM(newMatrix, 0.0, zoomFactor, zoomFactor, 1.0); } @@ -572,47 +585,49 @@ std::vector MapCamera3d::getInvariantModelMatrix(const ::Coord &coordinat RectCoord MapCamera3d::getVisibleRect() { Vec2I sizeViewport = mapInterface->getRenderingContext()->getViewportSize(); + std::lock_guard lock(paramMutex); return getRectFromViewport(sizeViewport, focusPointPosition); } RectCoord MapCamera3d::getPaddingAdjustedVisibleRect() { // TODO: Implement for Camera3D -// printf("Warning: getPaddingAdjustedVisibleRect incomplete logic.\n"); + // printf("Warning: getPaddingAdjustedVisibleRect incomplete logic.\n"); return RectCoord(Coord(3857, 0, 0, 0), Coord(3857, 0, 0, 0)); -// Vec2I sizeViewport = mapInterface->getRenderingContext()->getViewportSize(); -// -// // adjust viewport -// sizeViewport.x -= (paddingLeft + paddingRight); -// sizeViewport.y -= (paddingTop + paddingBottom); -// -// // also use the padding adjusted center position -// return getRectFromViewport(sizeViewport, getCenterPosition()); + // Vec2I sizeViewport = mapInterface->getRenderingContext()->getViewportSize(); + // + // // adjust viewport + // sizeViewport.x -= (paddingLeft + paddingRight); + // sizeViewport.y -= (paddingTop + paddingBottom); + // + // // also use the padding adjusted center position + // return getRectFromViewport(sizeViewport, getCenterPosition()); } RectCoord MapCamera3d::getRectFromViewport(const Vec2I &sizeViewport, const Coord ¢er) { // TODO: Implement for Camera3D -// printf("Warning: getRectFromViewport incomplete logic.\n"); - return RectCoord(Coord(3857, 0, 0, 0), Coord(3857, 0, 0, 0));; -// double zoomFactor = screenPixelAsRealMeterFactor * zoom; -// -// double halfWidth = sizeViewport.x * 0.5 * zoomFactor; -// double halfHeight = sizeViewport.y * 0.5 * zoomFactor; -// -// double sinAngle = sin(angle * M_PI / 180.0); -// double cosAngle = cos(angle * M_PI / 180.0); -// -// double deltaX = std::abs(halfWidth * cosAngle) + std::abs(halfHeight * sinAngle); -// double deltaY = std::abs(halfWidth * sinAngle) + std::abs(halfHeight * cosAngle); -// -// double topLeftX = center.x - deltaX; -// double topLeftY = center.y + deltaY; -// double bottomRightX = center.x + deltaX; -// double bottomRightY = center.y - deltaY; -// -// Coord topLeft = Coord(center.systemIdentifier, topLeftX, topLeftY, center.z); -// Coord bottomRight = Coord(center.systemIdentifier, bottomRightX, bottomRightY, center.z); -// return RectCoord(topLeft, bottomRight); + // printf("Warning: getRectFromViewport incomplete logic.\n"); + return RectCoord(Coord(3857, 0, 0, 0), Coord(3857, 0, 0, 0)); + ; + // double zoomFactor = screenPixelAsRealMeterFactor * zoom; + // + // double halfWidth = sizeViewport.x * 0.5 * zoomFactor; + // double halfHeight = sizeViewport.y * 0.5 * zoomFactor; + // + // double sinAngle = sin(angle * M_PI / 180.0); + // double cosAngle = cos(angle * M_PI / 180.0); + // + // double deltaX = std::abs(halfWidth * cosAngle) + std::abs(halfHeight * sinAngle); + // double deltaY = std::abs(halfWidth * sinAngle) + std::abs(halfHeight * cosAngle); + // + // double topLeftX = center.x - deltaX; + // double topLeftY = center.y + deltaY; + // double bottomRightX = center.x + deltaX; + // double bottomRightY = center.y - deltaY; + // + // Coord topLeft = Coord(center.systemIdentifier, topLeftX, topLeftY, center.z); + // Coord bottomRight = Coord(center.systemIdentifier, bottomRightX, bottomRightY, center.z); + // return RectCoord(topLeft, bottomRight); } void MapCamera3d::notifyListeners(const int &listenerType) { @@ -620,7 +635,7 @@ void MapCamera3d::notifyListeners(const int &listenerType) { std::optional visibleRect = (listenerType & ListenerType::BOUNDS) ? std::optional(getVisibleRect()) : std::nullopt; -// std::optional visibleRect = std::nullopt; + // std::optional visibleRect = std::nullopt; double angle = this->angle; double zoom = this->zoom; @@ -637,14 +652,15 @@ void MapCamera3d::notifyListeners(const int &listenerType) { if (listenerType & ListenerType::BOUNDS) { bool validVpMatrix = false; { - std::lock_guard lock(vpDataMutex); + std::lock_guard lock(matrixMutex); validVpMatrix = this->validVpMatrix; } if (!validVpMatrix) { - getVpMatrix(); // update matrices + updateMatrices(); // update matrices } { - std::lock_guard lock(vpDataMutex); + std::lock_guard lock(matrixMutex); + std::lock_guard lock2(paramMutex); viewMatrix = this->viewMatrix; projectionMatrix = this->projectionMatrix; @@ -665,7 +681,8 @@ void MapCamera3d::notifyListeners(const int &listenerType) { std::vector viewMatrixF = VectorHelper::clone(viewMatrix); std::vector projectionMatrixF = VectorHelper::clone(projectionMatrix); - listener->onCameraChange(viewMatrixF, projectionMatrixF, origin, verticalFov, horizontalFov, width, height, focusPointAltitude, getCenterPosition(), getZoom()); + listener->onCameraChange(viewMatrixF, projectionMatrixF, origin, verticalFov, horizontalFov, width, height, + focusPointAltitude, getCenterPosition(), getZoom()); } if (listenerType & ListenerType::ROTATION) { listener->onRotationChanged(angle); @@ -685,16 +702,16 @@ bool MapCamera3d::onTouchDown(const ::Vec2F &posScreen) { lastOnTouchDownFocusCoord = std::nullopt; lastOnTouchDownInverseVPMatrix.clear(); return false; - } - else { + } else { + std::lock_guard lock(paramMutex); lastOnTouchDownPoint = posScreen; initialTouchDownPoint = posScreen; lastOnTouchDownFocusCoord = focusPointPosition; #ifdef ANDROID { std::lock_guard lock(vpDataMutex); - const auto [zeroVPMatrix, zeroInverseVPMatrix, zeroOrigin] = getVpMatrix( - Coord(CoordinateSystemIdentifiers::EPSG4326(), 0.0, 0.0, lastOnTouchDownFocusCoord->z), false); + const auto [zeroVPMatrix, zeroInverseVPMatrix, zeroOrigin] = + getVpMatrix(Coord(CoordinateSystemIdentifiers::EPSG4326(), 0.0, 0.0, lastOnTouchDownFocusCoord->z), false); lastOnTouchDownInverseVPMatrix = zeroInverseVPMatrix; lastOnTouchDownVPOrigin = zeroOrigin; } @@ -708,7 +725,8 @@ bool MapCamera3d::onTouchDown(const ::Vec2F &posScreen) { } bool MapCamera3d::onMove(const Vec2F &deltaScreen, bool confirmed, bool doubleClick) { - if (!config.moveEnabled || cameraFrozen || (lastOnTouchDownPoint == std::nullopt) || !lastOnTouchDownCoord || !lastOnTouchDownFocusCoord) { + if (!config.moveEnabled || cameraFrozen || (lastOnTouchDownPoint == std::nullopt) || !lastOnTouchDownCoord || + !lastOnTouchDownFocusCoord) { return false; } @@ -720,7 +738,7 @@ bool MapCamera3d::onMove(const Vec2F &deltaScreen, bool confirmed, bool doubleCl if (initialTouchDownPoint) { // Force update of matrices for coordFromScreenPosition-call, ... - getVpMatrix(); + updateMatrices(); // ..., then find coordinate, that would be below middle-point auto newTouchDownCoord = coordFromScreenPosition(initialTouchDownPoint.value()); @@ -730,12 +748,13 @@ bool MapCamera3d::onMove(const Vec2F &deltaScreen, bool confirmed, bool doubleCl double dx = -(newTouchDownCoord.x - lastOnTouchDownCoord->x); double dy = -(newTouchDownCoord.y - lastOnTouchDownCoord->y); + std::lock_guard lock(paramMutex); + focusPointPosition.x = focusPointPosition.x + dx; focusPointPosition.y = focusPointPosition.y + dy; focusPointPosition.x = std::fmod((focusPointPosition.x + 180 + 360), 360.0) - 180; focusPointPosition.y = std::clamp(focusPointPosition.y, -90.0, 90.0); - } } @@ -754,7 +773,8 @@ bool MapCamera3d::onMove(const Vec2F &deltaScreen, bool confirmed, bool doubleCl return false; } auto newTouchDownCoord = coordFromScreenPosition(lastOnTouchDownInverseVPMatrix, newScreenPos, lastOnTouchDownVPOrigin); - auto lastOnTouchDownZeroCoord = coordFromScreenPosition(lastOnTouchDownInverseVPMatrix, initialTouchDownPoint.value(), lastOnTouchDownVPOrigin); + auto lastOnTouchDownZeroCoord = + coordFromScreenPosition(lastOnTouchDownInverseVPMatrix, initialTouchDownPoint.value(), lastOnTouchDownVPOrigin); #else auto newTouchDownCoord = coordFromScreenPosition(newScreenPos); #endif @@ -763,6 +783,8 @@ bool MapCamera3d::onMove(const Vec2F &deltaScreen, bool confirmed, bool doubleCl return false; } + std::lock_guard lock(paramMutex); + #ifdef ANDROID double dx = -(newTouchDownCoord.x - lastOnTouchDownZeroCoord.x); double dy = -(newTouchDownCoord.y - lastOnTouchDownZeroCoord.y); @@ -829,7 +851,8 @@ bool MapCamera3d::onOneFingerDoubleClickMoveComplete() { } void MapCamera3d::setupInertia() { - float velocityFactor = std::sqrt(currentDragVelocity.x * currentDragVelocity.x + currentDragVelocity.y * currentDragVelocity.y) / zoom; + float velocityFactor = + std::sqrt(currentDragVelocity.x * currentDragVelocity.x + currentDragVelocity.y * currentDragVelocity.y) / zoom; const double t1Factor = 1e-8; const double t2Factor = t1Factor / 100.0; @@ -865,12 +888,10 @@ void MapCamera3d::inertiaStep() { float yDiffMap = (inertia->velocity.y) * factor * deltaPrev; inertia->timestampUpdate = now; - const auto [adjustedPosition, adjustedZoom] = getBoundsCorrectedCoords( - Coord(focusPointPosition.systemIdentifier, - focusPointPosition.x + xDiffMap, - focusPointPosition.y + yDiffMap, - focusPointPosition.z), zoom); - + const auto [adjustedPosition, adjustedZoom] = + getBoundsCorrectedCoords(Coord(focusPointPosition.systemIdentifier, focusPointPosition.x + xDiffMap, + focusPointPosition.y + yDiffMap, focusPointPosition.z), + zoom); focusPointPosition.x = std::fmod((adjustedPosition.x + 180 + 360), 360.0) - 180; focusPointPosition.y = std::clamp(adjustedPosition.y, -90.0, 90.0); @@ -886,7 +907,10 @@ bool MapCamera3d::onDoubleClick(const ::Vec2F &posScreen) { return false; } - inertia = std::nullopt; + { + std::lock_guard lock(animationMutex); + inertia = std::nullopt; + } auto targetZoom = zoom / 2; targetZoom = std::max(std::min(targetZoom, zoomMin), zoomMax); @@ -897,14 +921,17 @@ bool MapCamera3d::onDoubleClick(const ::Vec2F &posScreen) { // Force update of matrices with new zoom for coordFromScreenPosition-call, ... auto originalZoom = zoom; setZoom(targetZoom, false); - getVpMatrix(); + updateMatrices(); // ..., then find coordinate, that would be at touch auto centerCoordAfter = coordFromScreenPosition(posScreen); // Reset zoom before animation - setZoom(originalZoom, false); - getVpMatrix(); + { + std::lock_guard lock(paramMutex); + setZoom(originalZoom, false); + } + updateMatrices(); // Rotate globe to keep initial coordinate at touch if (centerCoordBefore.systemIdentifier != -1 && centerCoordAfter.systemIdentifier != -1) { @@ -920,8 +947,7 @@ bool MapCamera3d::onDoubleClick(const ::Vec2F &posScreen) { moveToCenterPositionZoom(position, targetZoom, true); - } - else { + } else { setZoom(targetZoom, true); } @@ -945,14 +971,14 @@ bool MapCamera3d::onTwoFingerClick(const ::Vec2F &posScreen1, const ::Vec2F &pos // Force update of matrices with new zoom for coordFromScreenPosition-call, ... auto originalZoom = zoom; setZoom(targetZoom, false); - getVpMatrix(); + updateMatrices(); // ..., then find coordinate, that would be below middle-point auto centerCoordAfter = coordFromScreenPosition(posScreen); // Reset zoom before animation setZoom(originalZoom, false); - getVpMatrix(); + updateMatrices(); // Rotate globe to keep initial coordinate at middle-point if (centerCoordBefore.systemIdentifier != -1 && centerCoordAfter.systemIdentifier != -1) { @@ -968,12 +994,10 @@ bool MapCamera3d::onTwoFingerClick(const ::Vec2F &posScreen1, const ::Vec2F &pos moveToCenterPositionZoom(position, targetZoom, true); - } - else { + } else { setZoom(targetZoom, true); } - notifyListeners(ListenerType::MAP_INTERACTION); return true; } @@ -993,10 +1017,10 @@ bool MapCamera3d::onTwoFingerMove(const std::vector<::Vec2F> &posScreenOld, cons inertia = std::nullopt; - if (posScreenOld.size() >= 2) { - double scaleFactor = Vec2FHelper::distance(posScreenNew[0], posScreenNew[1]) / Vec2FHelper::distance(posScreenOld[0], posScreenOld[1]); + double scaleFactor = + Vec2FHelper::distance(posScreenNew[0], posScreenNew[1]) / Vec2FHelper::distance(posScreenOld[0], posScreenOld[1]); double newZoom = zoom / scaleFactor; @@ -1016,7 +1040,7 @@ bool MapCamera3d::onTwoFingerMove(const std::vector<::Vec2F> &posScreenOld, cons updateZoom(newZoom); // Force update of matrices for coordFromScreenPosition-call, ... - getVpMatrix(); + updateMatrices(); // ..., then find coordinate, that would be below middle-point auto screenCenterNew = (posScreenNew[0] + posScreenNew[1]) / 2.0; @@ -1047,7 +1071,6 @@ bool MapCamera3d::onTwoFingerMove(const std::vector<::Vec2F> &posScreenOld, cons } } - const auto [adjPosition, adjZoom] = getBoundsCorrectedCoords(focusPointPosition, zoom); focusPointPosition = adjPosition; updateZoom(adjZoom); @@ -1064,7 +1087,8 @@ bool MapCamera3d::onTwoFingerMoveComplete() { if (config.snapToNorthEnabled && !cameraFrozen && (angle < ROTATION_LOCKING_ANGLE || angle > (360 - ROTATION_LOCKING_ANGLE))) { std::lock_guard lock(animationMutex); rotationAnimation = std::make_shared( - cameraZoomConfig.animationDurationMs, this->angle, angle < ROTATION_LOCKING_ANGLE ? 0 : 360, InterpolatorFunction::EaseInOut, + cameraZoomConfig.animationDurationMs, this->angle, angle < ROTATION_LOCKING_ANGLE ? 0 : 360, + InterpolatorFunction::EaseInOut, [=](double angle) { this->angle = angle; mapInterface->invalidate(); @@ -1085,13 +1109,13 @@ bool MapCamera3d::onTwoFingerMoveComplete() { } Coord MapCamera3d::coordFromScreenPosition(const ::Vec2F &posScreen) { - std::lock_guard lock(vpDataMutex); + std::lock_guard lock(matrixMutex); return coordFromScreenPosition(inverseVPMatrix, posScreen); } -::Coord MapCamera3d::coordFromScreenPositionZoom(const ::Vec2F & posScreen, float zoom) { +::Coord MapCamera3d::coordFromScreenPositionZoom(const ::Vec2F &posScreen, float zoom) { // TODO: fix - std::lock_guard lock(vpDataMutex); + std::lock_guard lock(matrixMutex); return coordFromScreenPosition(inverseVPMatrix, posScreen); } @@ -1099,35 +1123,26 @@ Coord MapCamera3d::coordFromScreenPosition(const std::vector &inverseVPM return coordFromScreenPosition(inverseVPMatrix, posScreen, origin); } -Coord MapCamera3d::coordFromScreenPosition(const std::vector &inverseVPMatrix, const ::Vec2F &posScreen, const Vec3D &origin) { +Coord MapCamera3d::coordFromScreenPosition(const std::vector &inverseVPMatrix, const ::Vec2F &posScreen, + const Vec3D &origin) { auto viewport = mapInterface->getRenderingContext()->getViewportSize(); - auto worldPosFrontVec = Vec4D( - ((double)posScreen.x / (double)viewport.x * 2.0 - 1), - -((double)posScreen.y / (double)viewport.y * 2.0 - 1), - -1, - 1 - ); + auto worldPosFrontVec = + Vec4D(((double)posScreen.x / (double)viewport.x * 2.0 - 1), -((double)posScreen.y / (double)viewport.y * 2.0 - 1), -1, 1); - auto worldPosBackVec = Vec4D( - ((double)posScreen.x / (double)viewport.x * 2.0 - 1), - -((double)posScreen.y / (double)viewport.y * 2.0 - 1), - 1, - 1 - ); + auto worldPosBackVec = + Vec4D(((double)posScreen.x / (double)viewport.x * 2.0 - 1), -((double)posScreen.y / (double)viewport.y * 2.0 - 1), 1, 1); const double rx = origin.x; const double ry = origin.y; const double rz = origin.z; worldPosFrontVec = MatrixD::multiply(inverseVPMatrix, worldPosFrontVec); - auto worldPosFront = Vec3D((worldPosFrontVec.x / worldPosFrontVec.w) + rx, - (worldPosFrontVec.y / worldPosFrontVec.w) + ry, + auto worldPosFront = Vec3D((worldPosFrontVec.x / worldPosFrontVec.w) + rx, (worldPosFrontVec.y / worldPosFrontVec.w) + ry, (worldPosFrontVec.z / worldPosFrontVec.w) + rz); worldPosBackVec = MatrixD::multiply(inverseVPMatrix, worldPosBackVec); - auto worldPosBack = Vec3D((worldPosBackVec.x / worldPosBackVec.w) + rx, - (worldPosBackVec.y / worldPosBackVec.w) + ry, + auto worldPosBack = Vec3D((worldPosBackVec.x / worldPosBackVec.w) + rx, (worldPosBackVec.y / worldPosBackVec.w) + ry, (worldPosBackVec.z / worldPosBackVec.w) + rz); bool didHit = false; @@ -1140,14 +1155,12 @@ Coord MapCamera3d::coordFromScreenPosition(const std::vector &inverseVPM } double latitude = std::asin(point.y) * 180 / M_PI; return Coord(CoordinateSystemIdentifiers::EPSG4326(), longitude, latitude, 0); - } - else { + } else { return Coord(-1, 0, 0, 0); } } -bool MapCamera3d::gluInvertMatrix(const std::vector &m, std::vector &invOut) -{ +bool MapCamera3d::gluInvertMatrix(const std::vector &m, std::vector &invOut) { if (m.size() != 16 || invOut.size() != 16) { return false; @@ -1156,117 +1169,53 @@ bool MapCamera3d::gluInvertMatrix(const std::vector &m, std::vector &m, std::vector lock(matrixMutex); Vec2I sizeViewport = mapInterface->getRenderingContext()->getViewportSize(); if (validVpMatrix && sizeViewport.x != 0 && sizeViewport.y != 0) { auto coordCartesian = convertToCartesianCoordinates(coord); @@ -1292,12 +1242,13 @@ ::Vec2F MapCamera3d::screenPosFromCoord(const Coord &coord) { } Vec2F MapCamera3d::screenPosFromCartesianCoord(const Vec3D &coord, const Vec2I &sizeViewport) { - const auto& cc = Vec4D(coord.x - origin.x, coord.y - origin.y, coord.z - origin.z, 1.0); + const auto &cc = Vec4D(coord.x - origin.x, coord.y - origin.y, coord.z - origin.z, 1.0); return screenPosFromCartesianCoord(cc, sizeViewport); } Vec2F MapCamera3d::screenPosFromCartesianCoord(const Vec4D &coord, const Vec2I &sizeViewport) { - if(validVpMatrix) { + std::lock_guard lock(matrixMutex); + if (validVpMatrix) { const auto &projected = projectedPoint(coord); // Map from [-1, 1] to screenPixels, with (0,0) being the top left corner @@ -1313,14 +1264,13 @@ Vec2F MapCamera3d::screenPosFromCartesianCoord(const Vec4D &coord, const Vec2I & return Vec2F(0.0, 0.0); } -::Vec2F MapCamera3d::screenPosFromCoordZoom(const ::Coord & coord, float zoom) { +::Vec2F MapCamera3d::screenPosFromCoordZoom(const ::Coord &coord, float zoom) { // TODO: fix return screenPosFromCoord(coord); } - // padding in percentage, where 1.0 = rect is half of full width and height -bool MapCamera3d::coordIsVisibleOnScreen(const ::Coord & coord, float paddingPc) { +bool MapCamera3d::coordIsVisibleOnScreen(const ::Coord &coord, float paddingPc) { // 1. Check that coordinate is not on the back of the globe if (coordIsOnFrontHalfOfGlobe(coord) == false || coordIsFarAwayFromFocusPoint(coord)) { return false; @@ -1342,7 +1292,7 @@ bool MapCamera3d::coordIsVisibleOnScreen(const ::Coord & coord, float paddingPc) } } -bool MapCamera3d::coordIsFarAwayFromFocusPoint(const ::Coord & coord) { +bool MapCamera3d::coordIsFarAwayFromFocusPoint(const ::Coord &coord) { const auto coordinateConverter = CoordinateConversionHelperInterface::independentInstance(); Coord wgsC1 = coordinateConverter->convert(CoordinateSystemIdentifiers::EPSG4326(), focusPointPosition); Coord wgsC2 = coordinateConverter->convert(CoordinateSystemIdentifiers::EPSG4326(), coord); @@ -1350,9 +1300,9 @@ bool MapCamera3d::coordIsFarAwayFromFocusPoint(const ::Coord & coord) { const double R = 6371; // Radius of the earth in meters double latDistance = (wgsC2.y - wgsC1.y) * M_PI / 180.0; double lonDistance = (wgsC2.x - wgsC1.x) * M_PI / 180.0; - double a = std::sin(latDistance / 2) * std::sin(latDistance / 2) + - std::cos(wgsC1.y * M_PI / 180.0) * std::cos(wgsC2.y * M_PI / 180.0) * - std::sin(lonDistance / 2) * std::sin(lonDistance / 2); + double a = std::sin(latDistance / 2) * std::sin(latDistance / 2) + std::cos(wgsC1.y * M_PI / 180.0) * + std::cos(wgsC2.y * M_PI / 180.0) * + std::sin(lonDistance / 2) * std::sin(lonDistance / 2); double c = 2 * std::atan2(std::sqrt(a), std::sqrt(1 - a)); return R * c > 4000; } @@ -1364,7 +1314,7 @@ bool MapCamera3d::coordIsOnFrontHalfOfGlobe(Coord coord) { const auto coordCartesian = convertToCartesianCoordinates(coord); const auto projectedCoord = projectedPoint(coordCartesian); - const auto projectedCenter = projectedPoint({0,0,0,1}); + const auto projectedCenter = projectedPoint({0, 0, 0, 1}); bool isInFront = projectedCoord.z <= projectedCenter.z; @@ -1374,12 +1324,8 @@ bool MapCamera3d::coordIsOnFrontHalfOfGlobe(Coord coord) { Vec4D MapCamera3d::convertToCartesianCoordinates(const Coord &coord) const { Coord renderCoord = conversionHelper->convertToRenderSystem(coord); - return { - (renderCoord.z * sin(renderCoord.y) * cos(renderCoord.x)) - origin.x, - (renderCoord.z * cos(renderCoord.y)) - origin.y, - (-renderCoord.z * sin(renderCoord.y) * sin(renderCoord.x)) - origin.z, - 1.0 - }; + return {(renderCoord.z * sin(renderCoord.y) * cos(renderCoord.x)) - origin.x, (renderCoord.z * cos(renderCoord.y)) - origin.y, + (-renderCoord.z * sin(renderCoord.y) * sin(renderCoord.x)) - origin.z, 1.0}; } // Point given in cartesian coordinates, where (0,0,0) is the center of the globe @@ -1395,7 +1341,6 @@ Vec4D MapCamera3d::projectedPoint(const Vec4D &point) const { return projected; } - double MapCamera3d::mapUnitsFromPixels(double distancePx) { Vec2I sizeViewport = mapInterface->getRenderingContext()->getViewportSize(); if (validVpMatrix && sizeViewport.x != 0 && sizeViewport.y != 0) { @@ -1403,10 +1348,13 @@ double MapCamera3d::mapUnitsFromPixels(double distancePx) { const double sampleSize = (M_PI / 180.0) * 0.5; const auto cartOne = convertToCartesianCoordinates(focusRenderCoord); - const auto cartTwo = convertToCartesianCoordinates(Coord(focusRenderCoord.systemIdentifier, focusRenderCoord.x + sampleSize, focusRenderCoord.y + sampleSize * 0.5, focusRenderCoord.z)); + const auto cartTwo = convertToCartesianCoordinates(Coord(focusRenderCoord.systemIdentifier, focusRenderCoord.x + sampleSize, + focusRenderCoord.y + sampleSize * 0.5, focusRenderCoord.z)); const auto projectedOne = projectedPoint(cartOne); const auto projectedTwo = projectedPoint(cartTwo); - const auto sampleDistance = std::sqrt((cartOne.x - cartTwo.x) * (cartOne.x - cartTwo.x) + (cartOne.y - cartTwo.y) * (cartOne.y - cartTwo.y) + (cartOne.z - cartTwo.z) * (cartOne.z - cartTwo.z)); + const auto sampleDistance = + std::sqrt((cartOne.x - cartTwo.x) * (cartOne.x - cartTwo.x) + (cartOne.y - cartTwo.y) * (cartOne.y - cartTwo.y) + + (cartOne.z - cartTwo.z) * (cartOne.z - cartTwo.z)); const auto x = (projectedTwo.x - projectedOne.x) * sizeViewport.x; const auto y = (projectedTwo.y - projectedOne.y) * sizeViewport.y; @@ -1421,6 +1369,7 @@ double MapCamera3d::mapUnitsFromPixels(double distancePx) { } double MapCamera3d::getScalingFactor() { + std::lock_guard writeLock(matrixMutex); return lastScalingFactor; } @@ -1445,7 +1394,7 @@ double MapCamera3d::getMinZoom() { return zoomMin; } double MapCamera3d::getMaxZoom() { return zoomMax; } void MapCamera3d::setBounds(const RectCoord &bounds) { - RectCoord boundsMapSpace = mapInterface->getCoordinateConverterHelper()->convertRect(mapCoordinateSystem.identifier, bounds); + RectCoord boundsMapSpace = coordinateConversionHelper->convertRect(mapCoordinateSystem.identifier, bounds); this->bounds = boundsMapSpace; const auto [adjPosition, adjZoom] = getBoundsCorrectedCoords(focusPointPosition, zoom); @@ -1458,7 +1407,7 @@ void MapCamera3d::setBounds(const RectCoord &bounds) { RectCoord MapCamera3d::getBounds() { return bounds; } bool MapCamera3d::isInBounds(const Coord &coords) { - Coord mapCoords = mapInterface->getCoordinateConverterHelper()->convert(mapCoordinateSystem.identifier, coords); + Coord mapCoords = coordinateConversionHelper->convert(mapCoordinateSystem.identifier, coords); auto const bounds = this->bounds; @@ -1470,9 +1419,8 @@ bool MapCamera3d::isInBounds(const Coord &coords) { return mapCoords.x <= maxHor && mapCoords.x >= minHor && mapCoords.y <= maxVert && mapCoords.y >= minVert; } - Coord MapCamera3d::adjustCoordForPadding(const Coord &coords, double targetZoom) { - Coord coordinates = mapInterface->getCoordinateConverterHelper()->convert(focusPointPosition.systemIdentifier, coords); + Coord coordinates = coordinateConversionHelper->convert(focusPointPosition.systemIdentifier, coords); auto adjustedZoom = std::clamp(targetZoom, zoomMax, zoomMin); @@ -1507,17 +1455,12 @@ std::tuple MapCamera3d::getBoundsCorrectedCoords(const Coord &pos const auto &id = position.systemIdentifier; - Coord topLeft = mapInterface->getCoordinateConverterHelper()->convert(id, bounds.topLeft); - Coord bottomRight = mapInterface->getCoordinateConverterHelper()->convert(id, bounds.bottomRight); + Coord topLeft = coordinateConversionHelper->convert(id, bounds.topLeft); + Coord bottomRight = coordinateConversionHelper->convert(id, bounds.bottomRight); - Coord clampedPosition = Coord(id, - std::clamp(position.x, - std::min(topLeft.x, bottomRight.x), - std::max(topLeft.x, bottomRight.x)), - std::clamp(position.y, - std::min(topLeft.y, bottomRight.y), - std::max(topLeft.y, bottomRight.y)), - position.z); + Coord clampedPosition = + Coord(id, std::clamp(position.x, std::min(topLeft.x, bottomRight.x), std::max(topLeft.x, bottomRight.x)), + std::clamp(position.y, std::min(topLeft.y, bottomRight.y), std::max(topLeft.y, bottomRight.y)), position.z); assert(clampedPosition.systemIdentifier == 4326); return {clampedPosition, zoom}; @@ -1533,21 +1476,21 @@ void MapCamera3d::setBoundsRestrictWholeVisibleRect(bool enabled) { } void MapCamera3d::clampCenterToPaddingCorrectedBounds() { - const auto [newPosition, newZoom] = getBoundsCorrectedCoords( - Coord(focusPointPosition.systemIdentifier, std::fmod(focusPointPosition.x + 540.0, 360.0) - 180.0, focusPointPosition.y, - focusPointPosition.z), zoom); + const auto [newPosition, newZoom] = + getBoundsCorrectedCoords(Coord(focusPointPosition.systemIdentifier, std::fmod(focusPointPosition.x + 540.0, 360.0) - 180.0, + focusPointPosition.y, focusPointPosition.z), + zoom); + std::lock_guard lock(paramMutex); focusPointPosition = newPosition; zoom = newZoom; } - float MapCamera3d::getScreenDensityPpi() { return screenDensityPpi; } -std::shared_ptr MapCamera3d::asMapCamera3d() { - return shared_from_this(); -} +std::shared_ptr MapCamera3d::asMapCamera3d() { return shared_from_this(); } -void MapCamera3d::setCameraConfig(const Camera3dConfig & config, std::optional durationSeconds, std::optional targetZoom, const std::optional<::Coord> & targetCoordinate) { +void MapCamera3d::setCameraConfig(const Camera3dConfig &config, std::optional durationSeconds, + std::optional targetZoom, const std::optional<::Coord> &targetCoordinate) { cameraZoomConfig = config; double initialZoom = zoom; @@ -1571,65 +1514,68 @@ void MapCamera3d::setCameraConfig(const Camera3dConfig & config, std::optional lock(animationMutex); pitchAnimation = std::make_shared( - duration, initialPitch, targetPitch, InterpolatorFunction::EaseInOut, - [=](double pitch) { - this->cameraPitch = pitch; - mapInterface->invalidate(); - }, - [=] { - this->cameraPitch = targetPitch; - this->pitchAnimation = nullptr; - }); + duration, initialPitch, targetPitch, InterpolatorFunction::EaseInOut, + [=](double pitch) { + this->cameraPitch = pitch; + mapInterface->invalidate(); + }, + [=] { + this->cameraPitch = targetPitch; + this->pitchAnimation = nullptr; + }); pitchAnimation->start(); verticalDisplacementAnimation = std::make_shared( - duration, initialVerticalDisplacement, targetVerticalDisplacement, InterpolatorFunction::EaseInOut, - [=](double dis) { - this->cameraVerticalDisplacement = dis; - mapInterface->invalidate(); - }, - [=] { - this->cameraVerticalDisplacement = targetVerticalDisplacement; - this->verticalDisplacementAnimation = nullptr; - }); + duration, initialVerticalDisplacement, targetVerticalDisplacement, InterpolatorFunction::EaseInOut, + [=](double dis) { + this->cameraVerticalDisplacement = dis; + mapInterface->invalidate(); + }, + [=] { + this->cameraVerticalDisplacement = targetVerticalDisplacement; + this->verticalDisplacementAnimation = nullptr; + }); verticalDisplacementAnimation->start(); if (targetZoom) { zoomAnimation = std::make_shared( - duration, initialZoom, *targetZoom, InterpolatorFunction::EaseInOut, - [=](double zoom) { - this->zoom = zoom; - mapInterface->invalidate(); - }, - [=] { - this->zoom = *targetZoom; - this->zoomAnimation = nullptr; - }); + duration, initialZoom, *targetZoom, InterpolatorFunction::EaseInOut, + [=](double zoom) { + this->zoom = zoom; + mapInterface->invalidate(); + }, + [=] { + this->zoom = *targetZoom; + this->zoomAnimation = nullptr; + }); zoomAnimation->start(); } if (targetCoordinate) { - Coord startPosition = mapInterface->getCoordinateConverterHelper()->convert(CoordinateSystemIdentifiers::EPSG4326(), - focusPointPosition); + Coord startPosition = + coordinateConversionHelper->convert(CoordinateSystemIdentifiers::EPSG4326(), focusPointPosition); coordAnimation = std::make_shared( - duration, startPosition, *targetCoordinate, std::nullopt, InterpolatorFunction::EaseInOut, - [=](Coord positionMapSystem) { - assert(positionMapSystem.systemIdentifier == 4326); - this->focusPointPosition = positionMapSystem; - notifyListeners(ListenerType::BOUNDS); - mapInterface->invalidate(); - }, - [=] { - assert(this->coordAnimation->endValue.systemIdentifier == 4326); - this->focusPointPosition = this->coordAnimation->endValue; - notifyListeners(ListenerType::BOUNDS); - mapInterface->invalidate(); - this->coordAnimation = nullptr; - }); + duration, startPosition, *targetCoordinate, std::nullopt, InterpolatorFunction::EaseInOut, + [=](Coord positionMapSystem) { + assert(positionMapSystem.systemIdentifier == 4326); + std::lock_guard lock(paramMutex); + this->focusPointPosition = positionMapSystem; + notifyListeners(ListenerType::BOUNDS); + mapInterface->invalidate(); + }, + [=] { + assert(this->coordAnimation->endValue.systemIdentifier == 4326); + std::lock_guard lock(paramMutex); + this->focusPointPosition = this->coordAnimation->endValue; + notifyListeners(ListenerType::BOUNDS); + mapInterface->invalidate(); + this->coordAnimation = nullptr; + }); coordAnimation->start(); } } else { + std::lock_guard lock(paramMutex); this->cameraPitch = targetPitch; this->cameraVerticalDisplacement = targetVerticalDisplacement; if (targetZoom) { @@ -1643,18 +1589,15 @@ void MapCamera3d::setCameraConfig(const Camera3dConfig & config, std::optionalinvalidate(); } -Camera3dConfig MapCamera3d::getCameraConfig() { - return cameraZoomConfig; -} +Camera3dConfig MapCamera3d::getCameraConfig() { return cameraZoomConfig; } -void MapCamera3d::notifyListenerBoundsChange() { - notifyListeners(ListenerType::BOUNDS); -} +void MapCamera3d::notifyListenerBoundsChange() { notifyListeners(ListenerType::BOUNDS); } void MapCamera3d::updateZoom(double zoom_) { auto zoomMin = getMinZoom(); auto zoomMax = getMaxZoom(); + std::lock_guard lock(paramMutex); zoom = std::clamp(zoom_, zoomMax, zoomMin); cameraVerticalDisplacement = getCameraVerticalDisplacement(); cameraPitch = getCameraPitch(); @@ -1664,33 +1607,28 @@ double MapCamera3d::getCameraVerticalDisplacement() { return valueForZoom(cameraZoomConfig.verticalDisplacementInterpolationValues); } -double MapCamera3d::getCameraPitch() { - return valueForZoom(cameraZoomConfig.pitchInterpolationValues); -} +double MapCamera3d::getCameraPitch() { return valueForZoom(cameraZoomConfig.pitchInterpolationValues); } -double MapCamera3d::getCameraFieldOfView() { - return 42; -} +double MapCamera3d::getCameraFieldOfView() { return 42; } -double MapCamera3d::getCameraDistance() { +double MapCamera3d::getCameraDistance(Vec2I sizeViewport) { double f = getCameraFieldOfView(); - Vec2I sizeViewport = mapInterface->getRenderingContext()->getViewportSize(); double w = (double)sizeViewport.y; - double pixelsPerMeter = this->screenDensityPpi / 0.0254; + double pixelsPerMeter = this->screenDensityPpi / 0.0254; float d = (zoom * w / pixelsPerMeter / 2.0) / tan(f / 2.0 * M_PI / 180.0); float R = 6378137.0; return d / R; } -float MapCamera3d::valueForZoom(const CameraInterpolation& interpolator) { - if(interpolator.stops.size() == 0) { +float MapCamera3d::valueForZoom(const CameraInterpolation &interpolator) { + if (interpolator.stops.size() == 0) { return 0; } // 0 --> minZoom // 1 --> maxZoom auto t = (zoom - zoomMin) / (zoomMax - zoomMin); - const auto& values = interpolator.stops; + const auto &values = interpolator.stops; if (t <= values.front().stop) { return values.front().value; @@ -1703,8 +1641,8 @@ float MapCamera3d::valueForZoom(const CameraInterpolation& interpolator) { // Find the correct segment where t lies for (size_t i = 1; i < values.size(); ++i) { if (t <= values[i].stop) { - const auto& a = values[i - 1]; - const auto& b = values[i]; + const auto &a = values[i - 1]; + const auto &b = values[i]; // Linear interpolation float interp = (t - a.stop) / (b.stop - a.stop); diff --git a/shared/src/map/camera/MapCamera3d.h b/shared/src/map/camera/MapCamera3d.h index d97cb1c70..78ba98a24 100644 --- a/shared/src/map/camera/MapCamera3d.h +++ b/shared/src/map/camera/MapCamera3d.h @@ -10,27 +10,26 @@ #pragma once +#include "Camera3dConfig.h" #include "CameraInterface.h" -#include "MapCamera3dInterface.h" +#include "CameraInterpolation.h" #include "Coord.h" #include "CoordAnimation.h" #include "CoordinateConversionHelperInterface.h" #include "DoubleAnimation.h" +#include "MapCamera3dInterface.h" #include "MapCameraInterface.h" #include "MapCameraListenerInterface.h" #include "MapCoordinateSystem.h" #include "SimpleTouchInterface.h" -#include "Vec2I.h" #include "Vec2F.h" +#include "Vec2I.h" #include "Vec3D.h" #include "Vec4D.h" -#include "Camera3dConfig.h" -#include "CameraInterpolation.h" #include #include #include - class MapCamera3d : public MapCameraInterface, public MapCamera3dInterface, public CameraInterface, @@ -47,8 +46,8 @@ class MapCamera3d : public MapCameraInterface, virtual void moveToCenterPosition(const ::Coord ¢erPosition, bool animated) override; - virtual void moveToBoundingBox(const ::RectCoord &boundingBox, float paddingPc, bool animated, - std::optional minZoom, std::optional maxZoom) override; + virtual void moveToBoundingBox(const ::RectCoord &boundingBox, float paddingPc, bool animated, std::optional minZoom, + std::optional maxZoom) override; virtual ::Coord getCenterPosition() override; @@ -90,6 +89,8 @@ class MapCamera3d : public MapCameraInterface, virtual std::vector getVpMatrix() override; + void updateMatrices(); + virtual ::Vec3D getOrigin() override; virtual std::optional> getLastVpMatrixD() override; @@ -110,13 +111,12 @@ class MapCamera3d : public MapCameraInterface, virtual bool onTouchDown(const ::Vec2F &posScreen) override; - virtual bool onMove(const ::Vec2F &deltaScreen, bool confirmed, bool doubleClick) override; virtual bool onMoveComplete() override; virtual bool onOneFingerDoubleClickMoveComplete() override; - + virtual bool onTwoFingerClick(const ::Vec2F &posScreen1, const ::Vec2F &posScreen2) override; virtual bool onDoubleClick(const ::Vec2F &posScreen) override; @@ -135,13 +135,13 @@ class MapCamera3d : public MapCameraInterface, virtual ::Coord coordFromScreenPosition(const ::Vec2F &posScreen) override; - virtual ::Coord coordFromScreenPositionZoom(const ::Vec2F & posScreen, float zoom) override; + virtual ::Coord coordFromScreenPositionZoom(const ::Vec2F &posScreen, float zoom) override; Vec2F screenPosFromCoord(const Coord &coord) override; - virtual ::Vec2F screenPosFromCoordZoom(const ::Coord & coord, float zoom) override; + virtual ::Vec2F screenPosFromCoordZoom(const ::Coord &coord, float zoom) override; - bool coordIsVisibleOnScreen(const ::Coord & coord, float paddingPc) override; + bool coordIsVisibleOnScreen(const ::Coord &coord, float paddingPc) override; bool gluInvertMatrix(const std::vector &m, std::vector &invOut); @@ -155,12 +155,12 @@ class MapCamera3d : public MapCameraInterface, void setBoundsRestrictWholeVisibleRect(bool centerOnly) override; - virtual float getScreenDensityPpi() override; std::shared_ptr asMapCamera3d() override; - void setCameraConfig(const Camera3dConfig & config, std::optional durationSeconds, std::optional targetZoom, const std::optional<::Coord> & targetCoordinate) override; + void setCameraConfig(const Camera3dConfig &config, std::optional durationSeconds, std::optional targetZoom, + const std::optional<::Coord> &targetCoordinate) override; Camera3dConfig getCameraConfig() override; @@ -168,25 +168,23 @@ class MapCamera3d : public MapCameraInterface, std::vector computeEllipseCoefficients(); - bool coordIsFarAwayFromFocusPoint(const ::Coord & coord); + bool coordIsFarAwayFromFocusPoint(const ::Coord &coord); Vec2F screenPosFromCartesianCoord(const Vec3D &coord, const Vec2I &sizeViewport); -protected: - virtual std::tuple, std::vector, Vec3D> getVpMatrix(const Coord &focusCoord, bool updateVariables); - + protected: virtual ::Coord coordFromScreenPosition(const std::vector &inverseVPMatrix, const ::Vec2F &posScreen); - virtual ::Coord coordFromScreenPosition(const std::vector &inverseVPMatrix, const ::Vec2F &posScreen, const Vec3D &origin); + virtual ::Coord coordFromScreenPosition(const std::vector &inverseVPMatrix, const ::Vec2F &posScreen, + const Vec3D &origin); Vec2F screenPosFromCartesianCoord(const Vec4D &coord, const Vec2I &sizeViewport); - void updateZoom(double zoom); virtual void setupInertia(); - double getCameraDistance(); + double getCameraDistance(Vec2I sizeViewport); double getCameraFieldOfView(); double getCameraVerticalDisplacement(); double getCameraPitch(); @@ -224,7 +222,6 @@ class MapCamera3d : public MapCameraInterface, RectCoord bounds; - std::recursive_mutex vpDataMutex; std::optional lastVpBounds = std::nullopt; std::optional lastVpRotation = std::nullopt; std::optional lastVpZoom = std::nullopt; @@ -269,7 +266,7 @@ class MapCamera3d : public MapCameraInterface, void notifyListeners(const int &listenerType); - float valueForZoom(const CameraInterpolation& interpolator); + float valueForZoom(const CameraInterpolation &interpolator); // MARK: Animations @@ -294,6 +291,9 @@ class MapCamera3d : public MapCameraInterface, Vec4D convertToCartesianCoordinates(const Coord &coord) const; Vec4D projectedPoint(const Vec4D &point) const; + std::recursive_mutex paramMutex; + std::recursive_mutex matrixMutex; + std::vector vpMatrix = std::vector(16, 0.0); std::vector vpMatrixD = std::vector(16, 0.0); std::vector inverseVPMatrix = std::vector(16, 0.0); @@ -314,4 +314,6 @@ class MapCamera3d : public MapCameraInterface, Vec3D lastOnTouchDownVPOrigin = Vec3D(0.0, 0.0, 0.0); Camera3dConfig cameraZoomConfig; + + std::shared_ptr<::CoordinateConversionHelperInterface> coordinateConversionHelper; }; diff --git a/shared/src/map/layers/tiled/vector/symbol/Tiled2dMapVectorSourceSymbolDataManager.cpp b/shared/src/map/layers/tiled/vector/symbol/Tiled2dMapVectorSourceSymbolDataManager.cpp index a83edeff1..ca73b0dc3 100644 --- a/shared/src/map/layers/tiled/vector/symbol/Tiled2dMapVectorSourceSymbolDataManager.cpp +++ b/shared/src/map/layers/tiled/vector/symbol/Tiled2dMapVectorSourceSymbolDataManager.cpp @@ -626,7 +626,7 @@ void Tiled2dMapVectorSourceSymbolDataManager::collisionDetection(std::vectorgetZoomIdentifier(zoom); double rotation = -camera->getRotation(); - auto scaleFactor = camera->mapUnitsFromPixels(1.0); + auto scaleFactor = camera->getScalingFactor(); for (const auto layerIdentifier: layerIdentifiers) { std::vector allObjects; @@ -671,7 +671,7 @@ bool Tiled2dMapVectorSourceSymbolDataManager::update(long long now) { const double zoomIdentifier = layerConfig->getZoomIdentifier(zoom); const double rotation = camera->getRotation(); - const auto scaleFactor = camera->mapUnitsFromPixels(1.0); + const auto scaleFactor = camera->getScalingFactor(); for (const auto &[tile, symbolGroupsMap]: tileSymbolGroupMap) { const auto tileState = tileStateMap.find(tile); From 6e07e748eca8ff18e2f06cee4bb5024e3147d939 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20Ma=CC=88rki?= Date: Mon, 4 Nov 2024 12:03:02 +0100 Subject: [PATCH 02/12] fix tripple buffers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nicolas Märki --- ios/graphics/Model/Line/LineGroup2d.swift | 27 --------- ios/graphics/Model/Polygon/Polygon2d.swift | 59 +------------------ ios/graphics/Model/Quad/Quad2d.swift | 2 +- ios/graphics/Model/Quad/Quad2dInstanced.swift | 2 +- ios/graphics/Model/Text/TextInstanced.swift | 2 +- ios/maps/MCMapView.swift | 2 +- 6 files changed, 6 insertions(+), 88 deletions(-) diff --git a/ios/graphics/Model/Line/LineGroup2d.swift b/ios/graphics/Model/Line/LineGroup2d.swift index 1537ab92e..95e0488ea 100644 --- a/ios/graphics/Model/Line/LineGroup2d.swift +++ b/ios/graphics/Model/Line/LineGroup2d.swift @@ -25,16 +25,12 @@ final class LineGroup2d: BaseGraphicsObject, @unchecked Sendable { private var customScreenPixelFactor: Float = 0 private var tileOriginBuffer: MTLBuffer? - private var debugTileOriginBuffers: MultiBufferFloat4 - private var debugRenderOriginBuffers: MultiBufferFloat4 init(shader: MCShaderProgramInterface, metalContext: MetalContext) { guard let shader = shader as? LineGroupShader else { fatalError("LineGroup2d only supports LineGroupShader") } self.shader = shader - debugTileOriginBuffers = MultiBufferFloat4(device: metalContext.device) - debugRenderOriginBuffers = MultiBufferFloat4(device: metalContext.device) super.init(device: metalContext.device, sampler: metalContext.samplerLibrary.value(Sampler.magLinear.rawValue)!, label: "LineGroup2d") @@ -126,33 +122,14 @@ final class LineGroup2d: BaseGraphicsObject, @unchecked Sendable { } encoder.setVertexBuffer(vpMatrixBuffer, offset: 0, index: 1) - let originOffsetBuffer = originOffsetBuffers.getNextBuffer(context) if let bufferPointer = originOffsetBuffer?.contents().assumingMemoryBound(to: simd_float4.self) { bufferPointer.pointee.x = Float(originOffset.x - origin.x) bufferPointer.pointee.y = Float(originOffset.y - origin.y) bufferPointer.pointee.z = Float(originOffset.z - origin.z) } - let debugTileOriginBuffer = debugTileOriginBuffers.getNextBuffer(context) - if let bufferPointer = debugTileOriginBuffer?.contents().assumingMemoryBound( - to: simd_float4.self - ) { - bufferPointer.pointee.x = Float(originOffset.x) - bufferPointer.pointee.y = Float(originOffset.y) - bufferPointer.pointee.z = Float(originOffset.z) - } - let debugRenderOriginBuffer = debugRenderOriginBuffers.getNextBuffer(context) - if let bufferPointer = debugRenderOriginBuffer?.contents().assumingMemoryBound( - to: simd_float4.self - ) { - bufferPointer.pointee.x = Float(origin.x) - bufferPointer.pointee.y = Float(origin.y) - bufferPointer.pointee.z = Float(origin.z) - } encoder.setVertexBuffer(originOffsetBuffer, offset: 0, index: 5) encoder.setVertexBuffer(tileOriginBuffer, offset: 0, index: 6) - encoder.setVertexBuffer(debugTileOriginBuffer, offset: 0, index: 7) - encoder.setVertexBuffer(debugRenderOriginBuffer, offset: 0, index: 8) encoder.drawIndexedPrimitives(type: .triangle, indexCount: indicesCount, @@ -163,10 +140,6 @@ final class LineGroup2d: BaseGraphicsObject, @unchecked Sendable { if !isMasked { context.clearStencilBuffer() } - - assert(Polygon2d.renderOrigin?.x == origin.x) - assert(Polygon2d.renderOrigin?.y == origin.y) - assert(Polygon2d.renderOrigin?.z == origin.z) } } diff --git a/ios/graphics/Model/Polygon/Polygon2d.swift b/ios/graphics/Model/Polygon/Polygon2d.swift index c17812620..ad4b83ac6 100644 --- a/ios/graphics/Model/Polygon/Polygon2d.swift +++ b/ios/graphics/Model/Polygon/Polygon2d.swift @@ -23,15 +23,8 @@ final class Polygon2d: BaseGraphicsObject, @unchecked Sendable { private var stencilState: MTLDepthStencilState? private var renderPassStencilState: MTLDepthStencilState? - private var debugTileOriginBuffers: MultiBufferFloat4 - private var debugRenderOriginBuffers: MultiBufferFloat4 - - static var renderOrigin: MCVec3D? - init(shader: MCShaderProgramInterface, metalContext: MetalContext) { self.shader = shader - debugTileOriginBuffers = MultiBufferFloat4(device: metalContext.device) - debugRenderOriginBuffers = MultiBufferFloat4(device: metalContext.device) super.init(device: metalContext.device, sampler: metalContext.samplerLibrary.value(Sampler.magLinear.rawValue)!, label: "Polygon2d") @@ -97,36 +90,17 @@ final class Polygon2d: BaseGraphicsObject, @unchecked Sendable { let mMatrixBuffer = mMatrixBuffers.getNextBuffer(context) if let matrixPointer = UnsafeRawPointer(bitPattern: Int(mMatrix)) { - vpMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) + mMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) } encoder.setVertexBuffer(mMatrixBuffer, offset: 0, index: 2) - let originOffsetBuffer = originOffsetBuffers.getNextBuffer(context) if let bufferPointer = originOffsetBuffer?.contents().assumingMemoryBound(to: simd_float4.self) { bufferPointer.pointee.x = Float(originOffset.x - origin.x) bufferPointer.pointee.y = Float(originOffset.y - origin.y) bufferPointer.pointee.z = Float(originOffset.z - origin.z) } - let debugTileOriginBuffer = debugTileOriginBuffers.getNextBuffer(context) - if let bufferPointer = debugTileOriginBuffer?.contents().assumingMemoryBound( - to: simd_float4.self - ) { - bufferPointer.pointee.x = Float(originOffset.x) - bufferPointer.pointee.y = Float(originOffset.y) - bufferPointer.pointee.z = Float(originOffset.z) - } - let debugRenderOriginBuffer = debugRenderOriginBuffers.getNextBuffer(context) - if let bufferPointer = debugRenderOriginBuffer?.contents().assumingMemoryBound( - to: simd_float4.self - ) { - bufferPointer.pointee.x = Float(origin.x) - bufferPointer.pointee.y = Float(origin.y) - bufferPointer.pointee.z = Float(origin.z) - } encoder.setVertexBuffer(originOffsetBuffer, offset: 0, index: 3) - encoder.setVertexBuffer(debugTileOriginBuffer, offset: 0, index: 4) - encoder.setVertexBuffer(debugRenderOriginBuffer, offset: 0, index: 5) encoder.drawIndexedPrimitives(type: .triangle, indexCount: indicesCount, @@ -134,8 +108,6 @@ final class Polygon2d: BaseGraphicsObject, @unchecked Sendable { indexBuffer: indicesBuffer, indexBufferOffset: 0) - - debugRenderOriginBuffer?.didModifyRange(0 ..< 1) } private func setupStencilStates() { @@ -153,10 +125,6 @@ final class Polygon2d: BaseGraphicsObject, @unchecked Sendable { stencilState = device.makeDepthStencilState(descriptor: s2) } - - static var offsetX: Double = 0 - static var offsetY: Double = 0 - static var offsetZ: Double = 0 } extension Polygon2d: MCMaskingObjectInterface { @@ -206,7 +174,7 @@ extension Polygon2d: MCMaskingObjectInterface { let mMatrixBuffer = mMatrixBuffers.getNextBuffer(context) if let matrixPointer = UnsafeRawPointer(bitPattern: Int(mMatrix)) { - vpMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) + mMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) } encoder.setVertexBuffer(mMatrixBuffer, offset: 0, index: 2) @@ -216,36 +184,13 @@ extension Polygon2d: MCMaskingObjectInterface { bufferPointer.pointee.y = Float(originOffset.y - origin.y) bufferPointer.pointee.z = Float(originOffset.z - origin.z) } - let debugTileOriginBuffer = debugTileOriginBuffers.getNextBuffer(context) - if let bufferPointer = debugTileOriginBuffer?.contents().assumingMemoryBound( - to: simd_float4.self - ) { - bufferPointer.pointee.x = Float(originOffset.x) - bufferPointer.pointee.y = Float(originOffset.y) - bufferPointer.pointee.z = Float(originOffset.z) - } - let debugRenderOriginBuffer = debugRenderOriginBuffers.getNextBuffer(context) - if let bufferPointer = debugRenderOriginBuffer?.contents().assumingMemoryBound( - to: simd_float4.self - ) { - bufferPointer.pointee.x = Float(origin.x) - bufferPointer.pointee.y = Float(origin.y) - bufferPointer.pointee.z = Float(origin.z) - } - Self.offsetX = originOffset.x - origin.x - Self.offsetY = originOffset.y - origin.y - Self.offsetZ = originOffset.z - origin.z encoder.setVertexBuffer(originOffsetBuffer, offset: 0, index: 3) - encoder.setVertexBuffer(debugTileOriginBuffer, offset: 0, index: 4) - encoder.setVertexBuffer(debugRenderOriginBuffer, offset: 0, index: 5) encoder.drawIndexedPrimitives(type: .triangle, indexCount: indicesCount, indexType: .uint16, indexBuffer: indicesBuffer, indexBufferOffset: 0) - - Self.renderOrigin = origin } } diff --git a/ios/graphics/Model/Quad/Quad2d.swift b/ios/graphics/Model/Quad/Quad2d.swift index e04a30733..c39afbad0 100644 --- a/ios/graphics/Model/Quad/Quad2d.swift +++ b/ios/graphics/Model/Quad/Quad2d.swift @@ -133,7 +133,7 @@ final class Quad2d: BaseGraphicsObject, @unchecked Sendable { let mMatrixBuffer = mMatrixBuffers.getNextBuffer(context) if let matrixPointer = UnsafeRawPointer(bitPattern: Int(mMatrix)) { - vpMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) + mMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) } encoder.setVertexBuffer(mMatrixBuffer, offset: 0, index: 2) diff --git a/ios/graphics/Model/Quad/Quad2dInstanced.swift b/ios/graphics/Model/Quad/Quad2dInstanced.swift index 904c68054..1bbd0e661 100644 --- a/ios/graphics/Model/Quad/Quad2dInstanced.swift +++ b/ios/graphics/Model/Quad/Quad2dInstanced.swift @@ -144,7 +144,7 @@ final class Quad2dInstanced: BaseGraphicsObject, @unchecked Sendable { let mMatrixBuffer = mMatrixBuffers.getNextBuffer(context) if let matrixPointer = UnsafeRawPointer(bitPattern: Int(mMatrix)) { - vpMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) + mMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) } encoder.setVertexBuffer(mMatrixBuffer, offset: 0, index: 2) diff --git a/ios/graphics/Model/Text/TextInstanced.swift b/ios/graphics/Model/Text/TextInstanced.swift index 8cd79aeeb..5edc6888e 100644 --- a/ios/graphics/Model/Text/TextInstanced.swift +++ b/ios/graphics/Model/Text/TextInstanced.swift @@ -110,7 +110,7 @@ final class TextInstanced: BaseGraphicsObject, @unchecked Sendable { let mMatrixBuffer = mMatrixBuffers.getNextBuffer(context) if let matrixPointer = UnsafeRawPointer(bitPattern: Int(mMatrix)) { - vpMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) + mMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) } encoder.setVertexBuffer(mMatrixBuffer, offset: 0, index: 2) diff --git a/ios/maps/MCMapView.swift b/ios/maps/MCMapView.swift index 2d9a382d7..ac846435d 100644 --- a/ios/maps/MCMapView.swift +++ b/ios/maps/MCMapView.swift @@ -26,7 +26,7 @@ open class MCMapView: MTKView, @unchecked Sendable { private let framesToRenderAfterInvalidate: Int = 25 private var lastInvalidate = Date() private let renderAfterInvalidate: TimeInterval = 3 // Collision detection might be delayed 3s - private var renderSemaphore = DispatchSemaphore(value: 2) + private var renderSemaphore = DispatchSemaphore(value: 3) // using tripple buffers private let touchHandler: MCMapViewTouchHandler private let callbackHandler = MCMapViewCallbackHandler() From c99fbb65ed2749eef2461d62d2072c885c4e36d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20Ma=CC=88rki?= Date: Mon, 4 Nov 2024 13:59:26 +0100 Subject: [PATCH 03/12] remove bounce animation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nicolas Märki --- shared/src/map/camera/MapCamera3d.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/shared/src/map/camera/MapCamera3d.cpp b/shared/src/map/camera/MapCamera3d.cpp index b16c9fb7c..fdabd754b 100644 --- a/shared/src/map/camera/MapCamera3d.cpp +++ b/shared/src/map/camera/MapCamera3d.cpp @@ -91,8 +91,8 @@ void MapCamera3d::moveToCenterPositionZoom(const ::Coord ¢erPosition, double if (cameraFrozen) return; inertia = std::nullopt; - auto [focusPosition, focusZoom] = getBoundsCorrectedCoords( - coordinateConversionHelper->convert(focusPointPosition.systemIdentifier, centerPosition), zoom); + auto [focusPosition, focusZoom] = + getBoundsCorrectedCoords(coordinateConversionHelper->convert(focusPointPosition.systemIdentifier, centerPosition), zoom); if (animated && bounds.topLeft.x == mapCoordinateSystem.bounds.topLeft.x && bounds.bottomRight.x == mapCoordinateSystem.bounds.bottomRight.x) { @@ -144,8 +144,8 @@ void MapCamera3d::moveToCenterPosition(const ::Coord ¢erPosition, bool anima if (cameraFrozen) return; inertia = std::nullopt; - auto [focusPosition, focusZoom] = getBoundsCorrectedCoords( - coordinateConversionHelper->convert(focusPointPosition.systemIdentifier, centerPosition), zoom); + auto [focusPosition, focusZoom] = + getBoundsCorrectedCoords(coordinateConversionHelper->convert(focusPointPosition.systemIdentifier, centerPosition), zoom); if (animated && bounds.topLeft.x == mapCoordinateSystem.bounds.topLeft.x && bounds.bottomRight.x == mapCoordinateSystem.bounds.bottomRight.x) { @@ -544,8 +544,6 @@ void MapCamera3d::update() { focusPointPosition.x = fmod(DateHelper::currentTimeMicros() * speed * 0.000003 + 180.0, 360.0) - 180.0; mapInterface->invalidate(); } - focusPointPosition.x = sin(DateHelper::currentTimeMicros() * 0.00001) * 0.01 + 7.44894; - mapInterface->invalidate(); { std::lock_guard lock(animationMutex); if (zoomAnimation) @@ -1552,8 +1550,7 @@ void MapCamera3d::setCameraConfig(const Camera3dConfig &config, std::optionalconvert(CoordinateSystemIdentifiers::EPSG4326(), focusPointPosition); + Coord startPosition = coordinateConversionHelper->convert(CoordinateSystemIdentifiers::EPSG4326(), focusPointPosition); coordAnimation = std::make_shared( duration, startPosition, *targetCoordinate, std::nullopt, InterpolatorFunction::EaseInOut, From 90ba6ac05a605d9d2907e68bf1c199afbb3b1c53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20Ma=CC=88rki?= Date: Mon, 4 Nov 2024 15:42:34 +0100 Subject: [PATCH 04/12] refactor multi buffers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nicolas Märki --- ios/graphics/Model/BaseGraphicsObject.swift | 104 +----------------- ios/graphics/Model/MultiBuffer.swift | 78 +++++++++++++ ios/graphics/Model/Quad/Quad2dInstanced.swift | 4 +- ios/graphics/Model/Text/TextInstanced.swift | 8 +- 4 files changed, 87 insertions(+), 107 deletions(-) create mode 100644 ios/graphics/Model/MultiBuffer.swift diff --git a/ios/graphics/Model/BaseGraphicsObject.swift b/ios/graphics/Model/BaseGraphicsObject.swift index b411012d7..f0340b03f 100644 --- a/ios/graphics/Model/BaseGraphicsObject.swift +++ b/ios/graphics/Model/BaseGraphicsObject.swift @@ -14,104 +14,6 @@ import Metal import simd -public struct MultiBufferFloat4x4 { - // Warning: Seems like suited to be generic - // But makeBuffer &reference does not like generic data - let bufferCount = 3 // Triple buffering - var originOffsetBuffers: [MTLBuffer] = [] - var currentBufferIndex = 0 - var currentFrameId = -1 - - init(device: MTLDevice) { - var initialMutable = simd_float4x4(1.0); - for _ in 0 ..< bufferCount { - if let buffer = device - .makeBuffer( - bytes: &initialMutable, - length: MemoryLayout.stride - ) { - originOffsetBuffers.append(buffer) - } - } - } - - public mutating func getNextBuffer(_ context: RenderingContext) -> MTLBuffer? { - if context.frameId != currentFrameId { - currentBufferIndex = (currentBufferIndex + 1) % bufferCount - currentFrameId = context.frameId - } - guard currentBufferIndex < originOffsetBuffers.count else { - return nil - } - return originOffsetBuffers[currentBufferIndex] - } -} - -public struct MultiBufferFloat4 { - // Warning: Seems like suited to be generic - // But makeBuffer &reference does not like generic data - let bufferCount = 3 // Triple buffering - var originOffsetBuffers: [MTLBuffer] = [] - var currentBufferIndex = 0 - var currentFrameId = -1 - - init(device: MTLDevice) { - var initialMutable = simd_float4(0, 0, 0, 0); - for _ in 0 ..< bufferCount { - if let buffer = device - .makeBuffer( - bytes: &initialMutable, - length: MemoryLayout.stride - ) { - originOffsetBuffers.append(buffer) - } - } - } - - public mutating func getNextBuffer(_ context: RenderingContext) -> MTLBuffer? { - if context.frameId != currentFrameId { - currentBufferIndex = (currentBufferIndex + 1) % bufferCount - currentFrameId = context.frameId - } - guard currentBufferIndex < originOffsetBuffers.count else { - return nil - } - return originOffsetBuffers[currentBufferIndex] - } -} - -public struct MultiBufferFloat1 { - // Warning: Seems like suited to be generic - // But makeBuffer &reference does not like generic data - let bufferCount = 3 // Triple buffering - var originOffsetBuffers: [MTLBuffer] = [] - var currentBufferIndex = 0 - var currentFrameId = -1 - - init(device: MTLDevice) { - var initialMutable = simd_float1(0); - for _ in 0 ..< bufferCount { - if let buffer = device - .makeBuffer( - bytes: &initialMutable, - length: MemoryLayout.stride - ) { - originOffsetBuffers.append(buffer) - } - } - } - - public mutating func getNextBuffer(_ context: RenderingContext) -> MTLBuffer? { - if context.frameId != currentFrameId { - currentBufferIndex = (currentBufferIndex + 1) % bufferCount - currentFrameId = context.frameId - } - guard currentBufferIndex < originOffsetBuffers.count else { - return nil - } - return originOffsetBuffers[currentBufferIndex] - } -} open class BaseGraphicsObject: @unchecked Sendable { private weak var context: MCRenderingContextInterface! @@ -133,10 +35,10 @@ open class BaseGraphicsObject: @unchecked Sendable { public var originOffset: MCVec3D = .init(x: 0, y: 0, z: 0) - public var originOffsetBuffers: MultiBufferFloat4 + public var originOffsetBuffers: MultiBuffer - public var vpMatrixBuffers: MultiBufferFloat4x4 - public var mMatrixBuffers: MultiBufferFloat4x4 + public var vpMatrixBuffers: MultiBuffer + public var mMatrixBuffers: MultiBuffer public init(device: MTLDevice, sampler: MTLSamplerState, label: String = "") { self.device = device diff --git a/ios/graphics/Model/MultiBuffer.swift b/ios/graphics/Model/MultiBuffer.swift new file mode 100644 index 000000000..ae18e53e2 --- /dev/null +++ b/ios/graphics/Model/MultiBuffer.swift @@ -0,0 +1,78 @@ +// +// MultiBuffer.swift +// MapCore +// +// Created by Nicolas Märki on 04.11.2024. +// + +import Metal +import simd + +private let bufferCount = 3 // Triple buffering + +public struct MultiBuffer { + // Warning: Seems like suited to be generic + // But makeBuffer &reference does not like generic data + var buffers: [MTLBuffer] + var currentBufferIndex = 0 + var currentFrameId = -1 + + fileprivate init(buffers: [MTLBuffer]) { + self.buffers = buffers + } + + public mutating func getNextBuffer(_ context: RenderingContext) + -> MTLBuffer? + { + if context.frameId != currentFrameId { + currentBufferIndex = (currentBufferIndex + 1) % bufferCount + currentFrameId = context.frameId + } + guard currentBufferIndex < buffers.count else { + return nil + } + return buffers[currentBufferIndex] + } +} + +extension MultiBuffer { + public init(device: MTLDevice) { + var initialMutable = simd_float1(1.0) + var buffers: [MTLBuffer] = (0...stride + ) + } + self.init(buffers: buffers) + } +} + +extension MultiBuffer { + public init(device: MTLDevice) { + var initialMutable = simd_float4(0.0, 0.0, 0.0, 0.0) + let buffers: [MTLBuffer] = (0...stride + ) + } + self.init(buffers: buffers) + } +} + +extension MultiBuffer { + public init(device: MTLDevice) { + var initialMutable = simd_float4x4(1.0) + let buffers: [MTLBuffer] = (0...stride + ) + } + self.init(buffers: buffers) + } +} diff --git a/ios/graphics/Model/Quad/Quad2dInstanced.swift b/ios/graphics/Model/Quad/Quad2dInstanced.swift index 1bbd0e661..7a9ad3e37 100644 --- a/ios/graphics/Model/Quad/Quad2dInstanced.swift +++ b/ios/graphics/Model/Quad/Quad2dInstanced.swift @@ -26,7 +26,7 @@ final class Quad2dInstanced: BaseGraphicsObject, @unchecked Sendable { private var rotationsBuffer: MTLBuffer? private var alphaBuffer: MTLBuffer? private var offsetsBuffer: MTLBuffer? - private var originBuffers: MultiBufferFloat4 + private var originBuffers: MultiBuffer private var textureCoordinatesBuffer: MTLBuffer? @@ -50,7 +50,7 @@ final class Quad2dInstanced: BaseGraphicsObject, @unchecked Sendable { } else { self.isUnitSphere = false } - originBuffers = MultiBufferFloat4(device: metalContext.device) + originBuffers = MultiBuffer(device: metalContext.device) super.init(device: metalContext.device, sampler: metalContext.samplerLibrary.value(Sampler.magLinear.rawValue)!, label: label) diff --git a/ios/graphics/Model/Text/TextInstanced.swift b/ios/graphics/Model/Text/TextInstanced.swift index 5edc6888e..4ef2316b4 100644 --- a/ios/graphics/Model/Text/TextInstanced.swift +++ b/ios/graphics/Model/Text/TextInstanced.swift @@ -28,8 +28,8 @@ final class TextInstanced: BaseGraphicsObject, @unchecked Sendable { private var rotationsBuffer: MTLBuffer? private var styleIndicesBuffer: MTLBuffer? private var styleBuffer: MTLBuffer? - private var originBuffers: MultiBufferFloat4 - private var aspectRatioBuffers: MultiBufferFloat1 + private var originBuffers: MultiBuffer + private var aspectRatioBuffers: MultiBuffer private var texture: MTLTexture? @@ -37,8 +37,8 @@ final class TextInstanced: BaseGraphicsObject, @unchecked Sendable { init(shader: MCShaderProgramInterface, metalContext: MetalContext) { self.shader = shader as! TextInstancedShader - self.originBuffers = MultiBufferFloat4(device: metalContext.device) - self.aspectRatioBuffers = MultiBufferFloat1(device: metalContext.device) + self.originBuffers = MultiBuffer(device: metalContext.device) + self.aspectRatioBuffers = MultiBuffer(device: metalContext.device) super.init(device: metalContext.device, sampler: metalContext.samplerLibrary.value(Sampler.magLinear.rawValue)!, label: "TextInstanced") From 5f88de59057951670165ca42ea19117e4b141fe4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20Ma=CC=88rki?= Date: Mon, 4 Nov 2024 17:15:11 +0100 Subject: [PATCH 05/12] improve buffer implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nicolas Märki --- ios/graphics/Model/BaseGraphicsObject.swift | 71 ++--- ios/graphics/Model/Polygon/Polygon2d.swift | 125 +++++---- ios/graphics/Model/Quad/Quad2d.swift | 242 +++++++++++------- ios/graphics/Model/Quad/Quad2dInstanced.swift | 169 +++++++----- ios/graphics/Model/Text/TextInstanced.swift | 174 ++++++++----- ios/graphics/Shader/Metal/BaseShader.metal | 4 +- ios/graphics/Shader/Metal/LineShader.metal | 4 +- 7 files changed, 471 insertions(+), 318 deletions(-) diff --git a/ios/graphics/Model/BaseGraphicsObject.swift b/ios/graphics/Model/BaseGraphicsObject.swift index f0340b03f..c135a36ab 100644 --- a/ios/graphics/Model/BaseGraphicsObject.swift +++ b/ios/graphics/Model/BaseGraphicsObject.swift @@ -13,8 +13,6 @@ import MapCoreSharedModule import Metal import simd - - open class BaseGraphicsObject: @unchecked Sendable { private weak var context: MCRenderingContextInterface! @@ -38,32 +36,33 @@ open class BaseGraphicsObject: @unchecked Sendable { public var originOffsetBuffers: MultiBuffer public var vpMatrixBuffers: MultiBuffer - public var mMatrixBuffers: MultiBuffer - public init(device: MTLDevice, sampler: MTLSamplerState, label: String = "") { + public init(device: MTLDevice, sampler: MTLSamplerState, label: String = "") + { self.device = device self.sampler = sampler self.label = label self.originOffsetBuffers = .init(device: device) self.vpMatrixBuffers = .init(device: device) - self.mMatrixBuffers = .init(device: device) } - - - open func render(encoder _: MTLRenderCommandEncoder, - context _: RenderingContext, - renderPass _: MCRenderPassConfig, - vpMatrix _: Int64, - mMatrix _: Int64, - origin: MCVec3D, - isMasked _: Bool, - screenPixelAsRealMeterFactor _: Double) { + open func render( + encoder _: MTLRenderCommandEncoder, + context _: RenderingContext, + renderPass _: MCRenderPassConfig, + vpMatrix _: Int64, + mMatrix _: Int64, + origin: MCVec3D, + isMasked _: Bool, + screenPixelAsRealMeterFactor _: Double + ) { fatalError("has to be overwritten by subclass") } - open func compute(encoder _: MTLComputeCommandEncoder, - context _: RenderingContext) { + open func compute( + encoder _: MTLComputeCommandEncoder, + context _: RenderingContext + ) { // subclasses may override } } @@ -88,32 +87,42 @@ extension BaseGraphicsObject: MCGraphicsObjectInterface { maskInverse = inversed } - public func render(_ context: MCRenderingContextInterface?, renderPass: MCRenderPassConfig, vpMatrix: Int64, mMatrix: Int64, origin: MCVec3D, isMasked: Bool, screenPixelAsRealMeterFactor: Double) { + public func render( + _ context: MCRenderingContextInterface?, renderPass: MCRenderPassConfig, + vpMatrix: Int64, mMatrix: Int64, origin: MCVec3D, isMasked: Bool, + screenPixelAsRealMeterFactor: Double + ) { guard isReady(), - let context = context as? RenderingContext, - let encoder = context.encoder + let context = context as? RenderingContext, + let encoder = context.encoder else { return } - render(encoder: encoder, - context: context, - renderPass: renderPass, - vpMatrix: vpMatrix, - mMatrix: mMatrix, - origin: origin, - isMasked: isMasked, - screenPixelAsRealMeterFactor: screenPixelAsRealMeterFactor) + render( + encoder: encoder, + context: context, + renderPass: renderPass, + vpMatrix: vpMatrix, + mMatrix: mMatrix, + origin: origin, + isMasked: isMasked, + screenPixelAsRealMeterFactor: screenPixelAsRealMeterFactor) } - public func compute(_ context: (any MCRenderingContextInterface)?, renderPass: MCRenderPassConfig) { + public func compute( + _ context: (any MCRenderingContextInterface)?, + renderPass: MCRenderPassConfig + ) { guard let context = context as? RenderingContext, - let encoder = context.computeEncoder + let encoder = context.computeEncoder else { return } compute(encoder: encoder, context: context) } // MARK: - Stencil - public func maskStencilState(readMask: UInt32 = 0b1111_1111, writeMask: UInt32 = 0b0000_0000) -> MTLDepthStencilState? { + public func maskStencilState( + readMask: UInt32 = 0b1111_1111, writeMask: UInt32 = 0b0000_0000 + ) -> MTLDepthStencilState? { let s = MTLStencilDescriptor() s.stencilCompareFunction = .equal s.stencilFailureOperation = .zero diff --git a/ios/graphics/Model/Polygon/Polygon2d.swift b/ios/graphics/Model/Polygon/Polygon2d.swift index ad4b83ac6..54092cf9f 100644 --- a/ios/graphics/Model/Polygon/Polygon2d.swift +++ b/ios/graphics/Model/Polygon/Polygon2d.swift @@ -23,38 +23,44 @@ final class Polygon2d: BaseGraphicsObject, @unchecked Sendable { private var stencilState: MTLDepthStencilState? private var renderPassStencilState: MTLDepthStencilState? + private var mMatrixBuffers: MultiBuffer + init(shader: MCShaderProgramInterface, metalContext: MetalContext) { + mMatrixBuffers = .init(device: metalContext.device) self.shader = shader - super.init(device: metalContext.device, - sampler: metalContext.samplerLibrary.value(Sampler.magLinear.rawValue)!, - label: "Polygon2d") - + super.init( + device: metalContext.device, + sampler: metalContext.samplerLibrary.value( + Sampler.magLinear.rawValue)!, + label: "Polygon2d") } - override func render(encoder: MTLRenderCommandEncoder, - context: RenderingContext, - renderPass pass: MCRenderPassConfig, - vpMatrix: Int64, - mMatrix: Int64, - origin: MCVec3D, - isMasked: Bool, - screenPixelAsRealMeterFactor _: Double) { + override func render( + encoder: MTLRenderCommandEncoder, + context: RenderingContext, + renderPass pass: MCRenderPassConfig, + vpMatrix: Int64, + mMatrix: Int64, + origin: MCVec3D, + isMasked: Bool, + screenPixelAsRealMeterFactor _: Double + ) { lock.lock() defer { lock.unlock() } guard let verticesBuffer, - let indicesBuffer + let indicesBuffer else { return } -#if DEBUG - encoder.pushDebugGroup(label) - defer { - encoder.popDebugGroup() - } -#endif + #if DEBUG + encoder.pushDebugGroup(label) + defer { + encoder.popDebugGroup() + } + #endif if isMasked { if stencilState == nil { @@ -84,29 +90,34 @@ final class Polygon2d: BaseGraphicsObject, @unchecked Sendable { let vpMatrixBuffer = vpMatrixBuffers.getNextBuffer(context) if let matrixPointer = UnsafeRawPointer(bitPattern: Int(vpMatrix)) { - vpMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) + vpMatrixBuffer?.contents().copyMemory( + from: matrixPointer, byteCount: 64) } encoder.setVertexBuffer(vpMatrixBuffer, offset: 0, index: 1) let mMatrixBuffer = mMatrixBuffers.getNextBuffer(context) if let matrixPointer = UnsafeRawPointer(bitPattern: Int(mMatrix)) { - mMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) + mMatrixBuffer?.contents().copyMemory( + from: matrixPointer, byteCount: 64) } encoder.setVertexBuffer(mMatrixBuffer, offset: 0, index: 2) let originOffsetBuffer = originOffsetBuffers.getNextBuffer(context) - if let bufferPointer = originOffsetBuffer?.contents().assumingMemoryBound(to: simd_float4.self) { + if let bufferPointer = originOffsetBuffer?.contents() + .assumingMemoryBound(to: simd_float4.self) + { bufferPointer.pointee.x = Float(originOffset.x - origin.x) bufferPointer.pointee.y = Float(originOffset.y - origin.y) bufferPointer.pointee.z = Float(originOffset.z - origin.z) } encoder.setVertexBuffer(originOffsetBuffer, offset: 0, index: 3) - encoder.drawIndexedPrimitives(type: .triangle, - indexCount: indicesCount, - indexType: .uint16, - indexBuffer: indicesBuffer, - indexBufferOffset: 0) + encoder.drawIndexedPrimitives( + type: .triangle, + indexCount: indicesCount, + indexType: .uint16, + indexBuffer: indicesBuffer, + indexBufferOffset: 0) } @@ -128,32 +139,35 @@ final class Polygon2d: BaseGraphicsObject, @unchecked Sendable { } extension Polygon2d: MCMaskingObjectInterface { - func render(asMask context: MCRenderingContextInterface?, - renderPass _: MCRenderPassConfig, - vpMatrix: Int64, - mMatrix: Int64, - origin: MCVec3D, - screenPixelAsRealMeterFactor _: Double) { - + func render( + asMask context: MCRenderingContextInterface?, + renderPass _: MCRenderPassConfig, + vpMatrix: Int64, + mMatrix: Int64, + origin: MCVec3D, + screenPixelAsRealMeterFactor _: Double + ) { + lock.lock() defer { lock.unlock() } guard isReady(), - let context = context as? RenderingContext, - let encoder = context.encoder else { return } + let context = context as? RenderingContext, + let encoder = context.encoder + else { return } guard let verticesBuffer, - let indicesBuffer + let indicesBuffer else { return } -#if DEBUG - encoder.pushDebugGroup("Polygon2dMask") - defer { - encoder.popDebugGroup() - } -#endif + #if DEBUG + encoder.pushDebugGroup("Polygon2dMask") + defer { + encoder.popDebugGroup() + } + #endif if let mask = context.polygonMask { encoder.setStencilReferenceValue(0xFF) @@ -168,34 +182,41 @@ extension Polygon2d: MCMaskingObjectInterface { let vpMatrixBuffer = vpMatrixBuffers.getNextBuffer(context) if let matrixPointer = UnsafeRawPointer(bitPattern: Int(vpMatrix)) { - vpMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) + vpMatrixBuffer?.contents().copyMemory( + from: matrixPointer, byteCount: 64) } encoder.setVertexBuffer(vpMatrixBuffer, offset: 0, index: 1) let mMatrixBuffer = mMatrixBuffers.getNextBuffer(context) if let matrixPointer = UnsafeRawPointer(bitPattern: Int(mMatrix)) { - mMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) + mMatrixBuffer?.contents().copyMemory( + from: matrixPointer, byteCount: 64) } encoder.setVertexBuffer(mMatrixBuffer, offset: 0, index: 2) let originOffsetBuffer = originOffsetBuffers.getNextBuffer(context) - if let bufferPointer = originOffsetBuffer?.contents().assumingMemoryBound(to: simd_float4.self) { + if let bufferPointer = originOffsetBuffer?.contents() + .assumingMemoryBound(to: simd_float4.self) + { bufferPointer.pointee.x = Float(originOffset.x - origin.x) bufferPointer.pointee.y = Float(originOffset.y - origin.y) bufferPointer.pointee.z = Float(originOffset.z - origin.z) } encoder.setVertexBuffer(originOffsetBuffer, offset: 0, index: 3) - encoder.drawIndexedPrimitives(type: .triangle, - indexCount: indicesCount, - indexType: .uint16, - indexBuffer: indicesBuffer, - indexBufferOffset: 0) + encoder.drawIndexedPrimitives( + type: .triangle, + indexCount: indicesCount, + indexType: .uint16, + indexBuffer: indicesBuffer, + indexBufferOffset: 0) } } extension Polygon2d: MCPolygon2dInterface { - func setVertices(_ vertices: MCSharedBytes, indices: MCSharedBytes, origin: MCVec3D) { + func setVertices( + _ vertices: MCSharedBytes, indices: MCSharedBytes, origin: MCVec3D + ) { lock.withCritical { self.verticesBuffer.copyOrCreate(from: vertices, device: device) self.indicesBuffer.copyOrCreate(from: indices, device: device) diff --git a/ios/graphics/Model/Quad/Quad2d.swift b/ios/graphics/Model/Quad/Quad2d.swift index c39afbad0..8cf31b527 100644 --- a/ios/graphics/Model/Quad/Quad2d.swift +++ b/ios/graphics/Model/Quad/Quad2d.swift @@ -36,11 +36,19 @@ final class Quad2d: BaseGraphicsObject, @unchecked Sendable { private var frame: MCQuad3dD? private var textureCoordinates: MCRectD? - init(shader: MCShaderProgramInterface, metalContext: MetalContext, label: String = "Quad2d") { + private var mMatrixBuffers: MultiBuffer + + init( + shader: MCShaderProgramInterface, metalContext: MetalContext, + label: String = "Quad2d" + ) { self.shader = shader - super.init(device: metalContext.device, - sampler: metalContext.samplerLibrary.value(Sampler.magLinear.rawValue)!, - label: label) + self.mMatrixBuffers = .init(device: metalContext.device) + super.init( + device: metalContext.device, + sampler: metalContext.samplerLibrary.value( + Sampler.magLinear.rawValue)!, + label: label) } private func setupStencilStates() { @@ -69,36 +77,37 @@ final class Quad2d: BaseGraphicsObject, @unchecked Sendable { return true } - override func render(encoder: MTLRenderCommandEncoder, - context: RenderingContext, - renderPass: MCRenderPassConfig, - vpMatrix: Int64, - mMatrix: Int64, - origin: MCVec3D, - isMasked: Bool, - screenPixelAsRealMeterFactor _: Double) { + override func render( + encoder: MTLRenderCommandEncoder, + context: RenderingContext, + renderPass: MCRenderPassConfig, + vpMatrix: Int64, + mMatrix: Int64, + origin: MCVec3D, + isMasked: Bool, + screenPixelAsRealMeterFactor _: Double + ) { lock.lock() defer { lock.unlock() } guard isReady(), - let verticesBuffer, - let indicesBuffer + let verticesBuffer, + let indicesBuffer else { return } - if shader is AlphaShader || shader is RasterShader, texture == nil { ready = false return } -#if DEBUG - encoder.pushDebugGroup(label) - defer { - encoder.popDebugGroup() - } -#endif + #if DEBUG + encoder.pushDebugGroup(label) + defer { + encoder.popDebugGroup() + } + #endif if isMasked { if stencilState == nil { @@ -124,26 +133,29 @@ final class Quad2d: BaseGraphicsObject, @unchecked Sendable { shader.preRender(context) encoder.setVertexBuffer(verticesBuffer, offset: 0, index: 0) - + let vpMatrixBuffer = vpMatrixBuffers.getNextBuffer(context) if let matrixPointer = UnsafeRawPointer(bitPattern: Int(vpMatrix)) { - vpMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) + vpMatrixBuffer?.contents().copyMemory( + from: matrixPointer, byteCount: 64) } encoder.setVertexBuffer(vpMatrixBuffer, offset: 0, index: 1) let mMatrixBuffer = mMatrixBuffers.getNextBuffer(context) if let matrixPointer = UnsafeRawPointer(bitPattern: Int(mMatrix)) { - mMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) + mMatrixBuffer?.contents().copyMemory( + from: matrixPointer, byteCount: 64) } encoder.setVertexBuffer(mMatrixBuffer, offset: 0, index: 2) let originOffsetBuffer = originOffsetBuffers.getNextBuffer(context) - if let bufferPointer = originOffsetBuffer?.contents().assumingMemoryBound(to: simd_float4.self) { + if let bufferPointer = originOffsetBuffer?.contents() + .assumingMemoryBound(to: simd_float4.self) + { bufferPointer.pointee.x = Float(originOffset.x - origin.x) bufferPointer.pointee.y = Float(originOffset.y - origin.y) bufferPointer.pointee.z = Float(originOffset.z - origin.z) - } - else { + } else { fatalError() } encoder.setVertexBuffer(originOffsetBuffer, offset: 0, index: 3) @@ -154,42 +166,48 @@ final class Quad2d: BaseGraphicsObject, @unchecked Sendable { encoder.setFragmentTexture(texture, index: 0) } - encoder.drawIndexedPrimitives(type: .triangle, - indexCount: indicesCount, - indexType: .uint16, - indexBuffer: indicesBuffer, - indexBufferOffset: 0) + encoder.drawIndexedPrimitives( + type: .triangle, + indexCount: indicesCount, + indexType: .uint16, + indexBuffer: indicesBuffer, + indexBufferOffset: 0) } } extension Quad2d: MCMaskingObjectInterface { - func render(asMask context: MCRenderingContextInterface?, - renderPass: MCRenderPassConfig, - vpMatrix: Int64, - mMatrix: Int64, - origin: MCVec3D, - screenPixelAsRealMeterFactor: Double) { + func render( + asMask context: MCRenderingContextInterface?, + renderPass: MCRenderPassConfig, + vpMatrix: Int64, + mMatrix: Int64, + origin: MCVec3D, + screenPixelAsRealMeterFactor: Double + ) { guard isReady(), - let context = context as? RenderingContext, - let encoder = context.encoder else { return } + let context = context as? RenderingContext, + let encoder = context.encoder + else { return } renderAsMask = true - render(encoder: encoder, - context: context, - renderPass: renderPass, - vpMatrix: vpMatrix, - mMatrix: mMatrix, - origin: origin, - isMasked: false, - screenPixelAsRealMeterFactor: screenPixelAsRealMeterFactor) + render( + encoder: encoder, + context: context, + renderPass: renderPass, + vpMatrix: vpMatrix, + mMatrix: mMatrix, + origin: origin, + isMasked: false, + screenPixelAsRealMeterFactor: screenPixelAsRealMeterFactor) } } extension Quad2d: MCQuad2dInterface { func setSubdivisionFactor(_ factor: Int32) { - let (optFrame, optTextureCoordinates) = lock.withCritical { () -> (MCQuad3dD?, MCRectD?) in + let (optFrame, optTextureCoordinates) = lock.withCritical { + () -> (MCQuad3dD?, MCRectD?) in if self.subdivisionFactor != factor { self.subdivisionFactor = factor return (frame, textureCoordinates) @@ -198,13 +216,18 @@ extension Quad2d: MCQuad2dInterface { } } if let frame = optFrame, - let textureCoordinates = optTextureCoordinates { - setFrame(frame, textureCoordinates: textureCoordinates, origin: self.originOffset, is3d: is3d) + let textureCoordinates = optTextureCoordinates + { + setFrame( + frame, textureCoordinates: textureCoordinates, + origin: self.originOffset, is3d: is3d) } } - - func setFrame(_ frame: MCQuad3dD, textureCoordinates: MCRectD, origin: MCVec3D, is3d: Bool) { + func setFrame( + _ frame: MCQuad3dD, textureCoordinates: MCRectD, origin: MCVec3D, + is3d: Bool + ) { var vertices: [Vertex3DTexture] = [] var indices: [UInt16] = [] @@ -212,14 +235,14 @@ extension Quad2d: MCQuad2dInterface { func transform(_ coordinate: MCVec3D) -> MCVec3D { if is3d { - let x = 1.0 * sin(coordinate.y) * cos(coordinate.x) - origin.x; - let y = 1.0 * cos(coordinate.y) - origin.y; - let z = -1.0 * sin(coordinate.y) * sin(coordinate.x) - origin.z; + let x = 1.0 * sin(coordinate.y) * cos(coordinate.x) - origin.x + let y = 1.0 * cos(coordinate.y) - origin.y + let z = -1.0 * sin(coordinate.y) * sin(coordinate.x) - origin.z return MCVec3D(x: x, y: y, z: z) } else { - let x = coordinate.x - origin.x; - let y = coordinate.y - origin.y; - let z = coordinate.z - origin.z; + let x = coordinate.x - origin.x + let y = coordinate.y - origin.y + let z = coordinate.z - origin.z return MCVec3D(x: x, y: y, z: z) } } @@ -234,29 +257,46 @@ extension Quad2d: MCQuad2dInterface { Where A-C are joined to form two triangles */ vertices = [ - Vertex3DTexture(position: transform(frame.bottomLeft), textureU: textureCoordinates.xF, textureV: textureCoordinates.yF + textureCoordinates.heightF), // A - Vertex3DTexture(position: transform(frame.topLeft), textureU: textureCoordinates.xF, textureV: textureCoordinates.yF), // B - Vertex3DTexture(position: transform(frame.topRight), textureU: textureCoordinates.xF + textureCoordinates.widthF, textureV: textureCoordinates.yF), // C - Vertex3DTexture(position: transform(frame.bottomRight), textureU: textureCoordinates.xF + textureCoordinates.widthF, textureV: textureCoordinates.yF + textureCoordinates.heightF), // D + Vertex3DTexture( + position: transform(frame.bottomLeft), + textureU: textureCoordinates.xF, + textureV: textureCoordinates.yF + textureCoordinates.heightF + ), // A + Vertex3DTexture( + position: transform(frame.topLeft), + textureU: textureCoordinates.xF, + textureV: textureCoordinates.yF), // B + Vertex3DTexture( + position: transform(frame.topRight), + textureU: textureCoordinates.xF + textureCoordinates.widthF, + textureV: textureCoordinates.yF), // C + Vertex3DTexture( + position: transform(frame.bottomRight), + textureU: textureCoordinates.xF + textureCoordinates.widthF, + textureV: textureCoordinates.yF + textureCoordinates.heightF + ), // D ] indices = [ - 0, 2, 1, // ACB - 0, 3, 2, // ADC + 0, 2, 1, // ACB + 0, 3, 2, // ADC ] } else { let numSubd = Int(pow(2.0, Double(sFactor))) - let deltaRTop = MCVec3D(x: Double(frame.topRight.x - frame.topLeft.x), - y: Double(frame.topRight.y - frame.topLeft.y), - z: Double(frame.topRight.z - frame.topLeft.z)) - let deltaDLeft = MCVec3D(x: Double(frame.bottomLeft.x - frame.topLeft.x), - y: Double(frame.bottomLeft.y - frame.topLeft.y), - z: Double(frame.bottomLeft.z - frame.topLeft.z)) - let deltaDRight = MCVec3D(x: Double(frame.bottomRight.x - frame.topRight.x), - y: Double(frame.bottomRight.y - frame.topRight.y), - z: Double(frame.bottomRight.z - frame.topRight.z)) + let deltaRTop = MCVec3D( + x: Double(frame.topRight.x - frame.topLeft.x), + y: Double(frame.topRight.y - frame.topLeft.y), + z: Double(frame.topRight.z - frame.topLeft.z)) + let deltaDLeft = MCVec3D( + x: Double(frame.bottomLeft.x - frame.topLeft.x), + y: Double(frame.bottomLeft.y - frame.topLeft.y), + z: Double(frame.bottomLeft.z - frame.topLeft.z)) + let deltaDRight = MCVec3D( + x: Double(frame.bottomRight.x - frame.topRight.x), + y: Double(frame.bottomRight.y - frame.topRight.y), + z: Double(frame.bottomRight.z - frame.topRight.z)) for iR in 0...numSubd { let pcR = Double(iR) / Double(numSubd) @@ -265,19 +305,34 @@ extension Quad2d: MCQuad2dInterface { let originZ = frame.topLeft.z + pcR * deltaRTop.z for iD in 0...numSubd { let pcD = Double(iD) / Double(numSubd) - let deltaDX = pcD * ((1.0 - pcR) * deltaDLeft.x + pcR * deltaDRight.x) - let deltaDY = pcD * ((1.0 - pcR) * deltaDLeft.y + pcR * deltaDRight.y) - let deltaDZ = pcD * ((1.0 - pcR) * deltaDLeft.z + pcR * deltaDRight.z) - - let u: Float = Float(textureCoordinates.x + pcR * textureCoordinates.width) - let v: Float = Float(textureCoordinates.y + pcD * textureCoordinates.height) - - vertices.append(Vertex3DTexture(position: transform(.init(x: originX + deltaDX, y: originY + deltaDY, z: originZ + deltaDZ)), textureU: u, textureV: v)) + let deltaDX = + pcD * ((1.0 - pcR) * deltaDLeft.x + pcR * deltaDRight.x) + let deltaDY = + pcD * ((1.0 - pcR) * deltaDLeft.y + pcR * deltaDRight.y) + let deltaDZ = + pcD * ((1.0 - pcR) * deltaDLeft.z + pcR * deltaDRight.z) + + let u: Float = Float( + textureCoordinates.x + pcR * textureCoordinates.width) + let v: Float = Float( + textureCoordinates.y + pcD * textureCoordinates.height) + + vertices.append( + Vertex3DTexture( + position: transform( + .init( + x: originX + deltaDX, y: originY + deltaDY, + z: originZ + deltaDZ)), textureU: u, + textureV: v)) if iR < numSubd && iD < numSubd { let baseInd = UInt16(iD + (iR * (numSubd + 1))) - let baseIndNextCol = UInt16(baseInd + UInt16(numSubd + 1)) - indices.append(contentsOf: [baseInd, baseInd + 1, baseIndNextCol + 1, baseInd, baseIndNextCol + 1, baseIndNextCol]) + let baseIndNextCol = UInt16( + baseInd + UInt16(numSubd + 1)) + indices.append(contentsOf: [ + baseInd, baseInd + 1, baseIndNextCol + 1, baseInd, + baseIndNextCol + 1, baseIndNextCol, + ]) } } } @@ -288,18 +343,29 @@ extension Quad2d: MCQuad2dInterface { self.originOffset = origin self.frame = frame self.textureCoordinates = textureCoordinates - self.verticesBuffer.copyOrCreate(bytes: vertices, length: MemoryLayout.stride * vertices.count, device: device) - self.indicesBuffer.copyOrCreate(bytes: indices, length: MemoryLayout.stride * indices.count, device: device) + self.verticesBuffer.copyOrCreate( + bytes: vertices, + length: MemoryLayout.stride * vertices.count, + device: device) + self.indicesBuffer.copyOrCreate( + bytes: indices, + length: MemoryLayout.stride * indices.count, + device: device) if self.verticesBuffer != nil, self.indicesBuffer != nil { self.indicesCount = indices.count - assert(self.indicesCount * 2 == MemoryLayout.stride * indices.count) + assert( + self.indicesCount * 2 == MemoryLayout.stride + * indices.count) } else { self.indicesCount = 0 } } } - func loadTexture(_ context: MCRenderingContextInterface?, textureHolder: MCTextureHolderInterface?) { + func loadTexture( + _ context: MCRenderingContextInterface?, + textureHolder: MCTextureHolderInterface? + ) { guard let textureHolder = textureHolder as? TextureHolder else { fatalError("unexpected TextureHolder") } diff --git a/ios/graphics/Model/Quad/Quad2dInstanced.swift b/ios/graphics/Model/Quad/Quad2dInstanced.swift index 7a9ad3e37..80b34edab 100644 --- a/ios/graphics/Model/Quad/Quad2dInstanced.swift +++ b/ios/graphics/Model/Quad/Quad2dInstanced.swift @@ -27,6 +27,7 @@ final class Quad2dInstanced: BaseGraphicsObject, @unchecked Sendable { private var alphaBuffer: MTLBuffer? private var offsetsBuffer: MTLBuffer? private var originBuffers: MultiBuffer + private var mMatrixBuffers: MultiBuffer private var textureCoordinatesBuffer: MTLBuffer? @@ -42,18 +43,23 @@ final class Quad2dInstanced: BaseGraphicsObject, @unchecked Sendable { public let isUnitSphere: Bool - init(shader: MCShaderProgramInterface, - metalContext: MetalContext, label: String = "Quad2dInstanced") { + init( + shader: MCShaderProgramInterface, + metalContext: MetalContext, label: String = "Quad2dInstanced" + ) { self.shader = shader if let shader = shader as? AlphaInstancedShader { self.isUnitSphere = shader.isUnitSphere } else { self.isUnitSphere = false } - originBuffers = MultiBuffer(device: metalContext.device) - super.init(device: metalContext.device, - sampler: metalContext.samplerLibrary.value(Sampler.magLinear.rawValue)!, - label: label) + originBuffers = .init(device: metalContext.device) + mMatrixBuffers = .init(device: metalContext.device) + super.init( + device: metalContext.device, + sampler: metalContext.samplerLibrary.value( + Sampler.magLinear.rawValue)!, + label: label) } private func setupStencilStates() { @@ -80,28 +86,30 @@ final class Quad2dInstanced: BaseGraphicsObject, @unchecked Sendable { return true } - override func render(encoder: MTLRenderCommandEncoder, - context: RenderingContext, - renderPass _: MCRenderPassConfig, - vpMatrix: Int64, - mMatrix: Int64, - origin: MCVec3D, - isMasked: Bool, - screenPixelAsRealMeterFactor _: Double) { + override func render( + encoder: MTLRenderCommandEncoder, + context: RenderingContext, + renderPass _: MCRenderPassConfig, + vpMatrix: Int64, + mMatrix: Int64, + origin: MCVec3D, + isMasked: Bool, + screenPixelAsRealMeterFactor _: Double + ) { lock.lock() defer { lock.unlock() } - + guard let verticesBuffer, - let indicesBuffer, - instanceCount != 0, - let positionsBuffer, - let scalesBuffer, - let rotationsBuffer, - let textureCoordinatesBuffer, - let alphaBuffer + let indicesBuffer, + instanceCount != 0, + let positionsBuffer, + let scalesBuffer, + let rotationsBuffer, + let textureCoordinatesBuffer, + let alphaBuffer else { return } @@ -111,12 +119,12 @@ final class Quad2dInstanced: BaseGraphicsObject, @unchecked Sendable { return } -#if DEBUG - encoder.pushDebugGroup(label) - defer { - encoder.popDebugGroup() - } -#endif + #if DEBUG + encoder.pushDebugGroup(label) + defer { + encoder.popDebugGroup() + } + #endif if isMasked { if stencilState == nil { @@ -135,16 +143,18 @@ final class Quad2dInstanced: BaseGraphicsObject, @unchecked Sendable { shader.preRender(context) encoder.setVertexBuffer(verticesBuffer, offset: 0, index: 0) - + let vpMatrixBuffer = vpMatrixBuffers.getNextBuffer(context) if let matrixPointer = UnsafeRawPointer(bitPattern: Int(vpMatrix)) { - vpMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) + vpMatrixBuffer?.contents().copyMemory( + from: matrixPointer, byteCount: 64) } encoder.setVertexBuffer(vpMatrixBuffer, offset: 0, index: 1) let mMatrixBuffer = mMatrixBuffers.getNextBuffer(context) if let matrixPointer = UnsafeRawPointer(bitPattern: Int(mMatrix)) { - mMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) + mMatrixBuffer?.contents().copyMemory( + from: matrixPointer, byteCount: 64) } encoder.setVertexBuffer(mMatrixBuffer, offset: 0, index: 2) @@ -156,7 +166,7 @@ final class Quad2dInstanced: BaseGraphicsObject, @unchecked Sendable { encoder.setVertexBuffer(alphaBuffer, offset: 0, index: 7) - if (offsetsBuffer != nil) { + if offsetsBuffer != nil { encoder.setVertexBuffer(offsetsBuffer, offset: 0, index: 8) } @@ -167,58 +177,64 @@ final class Quad2dInstanced: BaseGraphicsObject, @unchecked Sendable { } let originOffsetBuffer = originOffsetBuffers.getNextBuffer(context) - if let bufferPointer = originOffsetBuffer?.contents().assumingMemoryBound(to: simd_float4.self) { + if let bufferPointer = originOffsetBuffer?.contents() + .assumingMemoryBound(to: simd_float4.self) + { bufferPointer.pointee.x = Float(originOffset.x - origin.x) bufferPointer.pointee.y = Float(originOffset.y - origin.y) bufferPointer.pointee.z = Float(originOffset.z - origin.z) - } - else { + } else { fatalError() } encoder.setVertexBuffer(originOffsetBuffer, offset: 0, index: 9) - let originBuffer = originBuffers.getNextBuffer(context) - if let bufferPointer = originBuffer?.contents().assumingMemoryBound(to: simd_float4.self) { + if let bufferPointer = originBuffer?.contents().assumingMemoryBound( + to: simd_float4.self) + { bufferPointer.pointee.x = Float(origin.x) bufferPointer.pointee.y = Float(origin.y) bufferPointer.pointee.z = Float(origin.z) - } - else { + } else { fatalError() } encoder.setVertexBuffer(originBuffer, offset: 0, index: 10) - encoder.drawIndexedPrimitives(type: .triangle, - indexCount: indicesCount, - indexType: .uint16, - indexBuffer: indicesBuffer, - indexBufferOffset: 0, - instanceCount: instanceCount) + encoder.drawIndexedPrimitives( + type: .triangle, + indexCount: indicesCount, + indexType: .uint16, + indexBuffer: indicesBuffer, + indexBufferOffset: 0, + instanceCount: instanceCount) } } extension Quad2dInstanced: MCMaskingObjectInterface { - func render(asMask context: MCRenderingContextInterface?, - renderPass: MCRenderPassConfig, - vpMatrix: Int64, - mMatrix: Int64, - origin: MCVec3D, - screenPixelAsRealMeterFactor: Double) { + func render( + asMask context: MCRenderingContextInterface?, + renderPass: MCRenderPassConfig, + vpMatrix: Int64, + mMatrix: Int64, + origin: MCVec3D, + screenPixelAsRealMeterFactor: Double + ) { guard isReady(), - let context = context as? RenderingContext, - let encoder = context.encoder else { return } + let context = context as? RenderingContext, + let encoder = context.encoder + else { return } renderAsMask = true - render(encoder: encoder, - context: context, - renderPass: renderPass, - vpMatrix: vpMatrix, - mMatrix: mMatrix, - origin: origin, - isMasked: false, - screenPixelAsRealMeterFactor: screenPixelAsRealMeterFactor) + render( + encoder: encoder, + context: context, + renderPass: renderPass, + vpMatrix: vpMatrix, + mMatrix: mMatrix, + origin: origin, + isMasked: false, + screenPixelAsRealMeterFactor: screenPixelAsRealMeterFactor) } } @@ -233,17 +249,26 @@ extension Quad2dInstanced: MCQuad2dInstancedInterface { Where A-C are joined to form two triangles */ let vertices: [Vertex] = [ - Vertex(position: frame.bottomLeft, textureU: 0, textureV: 1), // A - Vertex(position: frame.topLeft, textureU: 0, textureV: 0), // B - Vertex(position: frame.topRight, textureU: 1, textureV: 0), // C - Vertex(position: frame.bottomRight, textureU: 1, textureV: 1), // D + Vertex(position: frame.bottomLeft, textureU: 0, textureV: 1), // A + Vertex(position: frame.topLeft, textureU: 0, textureV: 0), // B + Vertex(position: frame.topRight, textureU: 1, textureV: 0), // C + Vertex(position: frame.bottomRight, textureU: 1, textureV: 1), // D ] let indices: [UInt16] = [ - 0, 2, 1, // ACB - 0, 3, 2, // ADC + 0, 2, 1, // ACB + 0, 3, 2, // ADC ] - guard let verticesBuffer = device.makeBuffer(bytes: vertices, length: MemoryLayout.stride * vertices.count, options: []), let indicesBuffer = device.makeBuffer(bytes: indices, length: MemoryLayout.stride * indices.count, options: []) else { + guard + let verticesBuffer = device.makeBuffer( + bytes: vertices, + length: MemoryLayout.stride * vertices.count, + options: []), + let indicesBuffer = device.makeBuffer( + bytes: indices, + length: MemoryLayout.stride * indices.count, options: [] + ) + else { fatalError("Cannot allocate buffers") } @@ -279,7 +304,8 @@ extension Quad2dInstanced: MCQuad2dInstancedInterface { func setTextureCoordinates(_ textureCoordinates: MCSharedBytes) { lock.withCritical { - textureCoordinatesBuffer.copyOrCreate(from: textureCoordinates, device: device) + textureCoordinatesBuffer.copyOrCreate( + from: textureCoordinates, device: device) } } @@ -289,7 +315,10 @@ extension Quad2dInstanced: MCQuad2dInstancedInterface { } } - func loadTexture(_ context: MCRenderingContextInterface?, textureHolder: MCTextureHolderInterface?) { + func loadTexture( + _ context: MCRenderingContextInterface?, + textureHolder: MCTextureHolderInterface? + ) { guard let textureHolder = textureHolder as? TextureHolder else { fatalError("unexpected TextureHolder") } diff --git a/ios/graphics/Model/Text/TextInstanced.swift b/ios/graphics/Model/Text/TextInstanced.swift index 4ef2316b4..df105929d 100644 --- a/ios/graphics/Model/Text/TextInstanced.swift +++ b/ios/graphics/Model/Text/TextInstanced.swift @@ -30,6 +30,7 @@ final class TextInstanced: BaseGraphicsObject, @unchecked Sendable { private var styleBuffer: MTLBuffer? private var originBuffers: MultiBuffer private var aspectRatioBuffers: MultiBuffer + private var mMatrixBuffers: MultiBuffer private var texture: MTLTexture? @@ -37,11 +38,14 @@ final class TextInstanced: BaseGraphicsObject, @unchecked Sendable { init(shader: MCShaderProgramInterface, metalContext: MetalContext) { self.shader = shader as! TextInstancedShader - self.originBuffers = MultiBuffer(device: metalContext.device) - self.aspectRatioBuffers = MultiBuffer(device: metalContext.device) - super.init(device: metalContext.device, - sampler: metalContext.samplerLibrary.value(Sampler.magLinear.rawValue)!, - label: "TextInstanced") + self.originBuffers = .init(device: metalContext.device) + self.aspectRatioBuffers = .init(device: metalContext.device) + self.mMatrixBuffers = .init(device: metalContext.device) + super.init( + device: metalContext.device, + sampler: metalContext.samplerLibrary.value( + Sampler.magLinear.rawValue)!, + label: "TextInstanced") } private func setupStencilStates() { @@ -60,28 +64,31 @@ final class TextInstanced: BaseGraphicsObject, @unchecked Sendable { stencilState = device.makeDepthStencilState(descriptor: s2) } - override func render(encoder: MTLRenderCommandEncoder, - context: RenderingContext, - renderPass _: MCRenderPassConfig, - vpMatrix: Int64, - mMatrix: Int64, - origin: MCVec3D, - isMasked: Bool, - screenPixelAsRealMeterFactor _: Double) { + override func render( + encoder: MTLRenderCommandEncoder, + context: RenderingContext, + renderPass _: MCRenderPassConfig, + vpMatrix: Int64, + mMatrix: Int64, + origin: MCVec3D, + isMasked: Bool, + screenPixelAsRealMeterFactor _: Double + ) { lock.lock() defer { lock.unlock() } guard let verticesBuffer, - let indicesBuffer, - let positionsBuffer, - let scalesBuffer, - let rotationsBuffer, - let textureCoordinatesBuffer, - let styleIndicesBuffer, - let styleBuffer, - instanceCount != 0 else { return } + let indicesBuffer, + let positionsBuffer, + let scalesBuffer, + let rotationsBuffer, + let textureCoordinatesBuffer, + let styleIndicesBuffer, + let styleBuffer, + instanceCount != 0 + else { return } if isMasked { if stencilState == nil { @@ -93,24 +100,26 @@ final class TextInstanced: BaseGraphicsObject, @unchecked Sendable { encoder.setDepthStencilState(context.defaultMask) } -#if DEBUG - encoder.pushDebugGroup(label + "-Halo") -#endif + #if DEBUG + encoder.pushDebugGroup(label + "-Halo") + #endif shader.setupProgram(context) shader.preRender(context) encoder.setVertexBuffer(verticesBuffer, offset: 0, index: 0) - + let vpMatrixBuffer = vpMatrixBuffers.getNextBuffer(context) if let matrixPointer = UnsafeRawPointer(bitPattern: Int(vpMatrix)) { - vpMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) + vpMatrixBuffer?.contents().copyMemory( + from: matrixPointer, byteCount: 64) } encoder.setVertexBuffer(vpMatrixBuffer, offset: 0, index: 1) let mMatrixBuffer = mMatrixBuffers.getNextBuffer(context) if let matrixPointer = UnsafeRawPointer(bitPattern: Int(mMatrix)) { - mMatrixBuffer?.contents().copyMemory(from: matrixPointer, byteCount: 64) + mMatrixBuffer?.contents().copyMemory( + from: matrixPointer, byteCount: 64) } encoder.setVertexBuffer(mMatrixBuffer, offset: 0, index: 2) @@ -119,39 +128,44 @@ final class TextInstanced: BaseGraphicsObject, @unchecked Sendable { encoder.setVertexBuffer(rotationsBuffer, offset: 0, index: 5) encoder.setVertexBuffer(textureCoordinatesBuffer, offset: 0, index: 6) encoder.setVertexBuffer(styleIndicesBuffer, offset: 0, index: 7) - + if shader.isUnitSphere, - let referencePositionsBuffer { - encoder.setVertexBuffer(referencePositionsBuffer, offset: 0, index: 8) + let referencePositionsBuffer + { + encoder.setVertexBuffer( + referencePositionsBuffer, offset: 0, index: 8) } let originOffsetBuffer = originOffsetBuffers.getNextBuffer(context) - if let bufferPointer = originOffsetBuffer?.contents().assumingMemoryBound(to: simd_float4.self) { + if let bufferPointer = originOffsetBuffer?.contents() + .assumingMemoryBound(to: simd_float4.self) + { bufferPointer.pointee.x = Float(originOffset.x - origin.x) bufferPointer.pointee.y = Float(originOffset.y - origin.y) bufferPointer.pointee.z = Float(originOffset.z - origin.z) - } - else { + } else { fatalError() } encoder.setVertexBuffer(originOffsetBuffer, offset: 0, index: 9) let originBuffer = originBuffers.getNextBuffer(context) - if let bufferPointer = originBuffer?.contents().assumingMemoryBound(to: simd_float4.self) { + if let bufferPointer = originBuffer?.contents().assumingMemoryBound( + to: simd_float4.self) + { bufferPointer.pointee.x = Float(origin.x) bufferPointer.pointee.y = Float(origin.y) bufferPointer.pointee.z = Float(origin.z) - } - else { + } else { fatalError() } encoder.setVertexBuffer(originBuffer, offset: 0, index: 10) let aspectRatioBuffer = aspectRatioBuffers.getNextBuffer(context) - if let bufferPointer = aspectRatioBuffer?.contents().assumingMemoryBound(to: simd_float1.self) { + if let bufferPointer = aspectRatioBuffer?.contents() + .assumingMemoryBound(to: simd_float1.self) + { bufferPointer.pointee = Float(context.aspectRatio) - } - else { + } else { fatalError() } encoder.setVertexBuffer(aspectRatioBuffer, offset: 0, index: 11) @@ -166,31 +180,35 @@ final class TextInstanced: BaseGraphicsObject, @unchecked Sendable { var isHalo: Bool = true - encoder.setFragmentBytes(&isHalo, length: MemoryLayout.stride, index: 2) + encoder.setFragmentBytes( + &isHalo, length: MemoryLayout.stride, index: 2) - encoder.drawIndexedPrimitives(type: .triangle, - indexCount: indicesCount, - indexType: .uint16, - indexBuffer: indicesBuffer, - indexBufferOffset: 0, - instanceCount: instanceCount) + encoder.drawIndexedPrimitives( + type: .triangle, + indexCount: indicesCount, + indexType: .uint16, + indexBuffer: indicesBuffer, + indexBufferOffset: 0, + instanceCount: instanceCount) isHalo = false -#if DEBUG - encoder.popDebugGroup() - encoder.pushDebugGroup(label) - defer { + #if DEBUG encoder.popDebugGroup() - } -#endif - - encoder.setFragmentBytes(&isHalo, length: MemoryLayout.stride, index: 2) - - encoder.drawIndexedPrimitives(type: .triangle, - indexCount: indicesCount, - indexType: .uint16, - indexBuffer: indicesBuffer, - indexBufferOffset: 0, - instanceCount: instanceCount) + encoder.pushDebugGroup(label) + defer { + encoder.popDebugGroup() + } + #endif + + encoder.setFragmentBytes( + &isHalo, length: MemoryLayout.stride, index: 2) + + encoder.drawIndexedPrimitives( + type: .triangle, + indexCount: indicesCount, + indexType: .uint16, + indexBuffer: indicesBuffer, + indexBufferOffset: 0, + instanceCount: instanceCount) } } @@ -205,17 +223,26 @@ extension TextInstanced: MCTextInstancedInterface { Where A-C are joined to form two triangles */ let vertecies: [Vertex] = [ - Vertex(position: frame.bottomLeft, textureU: 0, textureV: 1), // A - Vertex(position: frame.topLeft, textureU: 0, textureV: 0), // B - Vertex(position: frame.topRight, textureU: 1, textureV: 0), // C - Vertex(position: frame.bottomRight, textureU: 1, textureV: 1), // D + Vertex(position: frame.bottomLeft, textureU: 0, textureV: 1), // A + Vertex(position: frame.topLeft, textureU: 0, textureV: 0), // B + Vertex(position: frame.topRight, textureU: 1, textureV: 0), // C + Vertex(position: frame.bottomRight, textureU: 1, textureV: 1), // D ] let indices: [UInt16] = [ - 0, 2, 1, // ACB - 0, 3, 2, // ADC + 0, 2, 1, // ACB + 0, 3, 2, // ADC ] - guard let verticesBuffer = device.makeBuffer(bytes: vertecies, length: MemoryLayout.stride * vertecies.count, options: []), let indicesBuffer = device.makeBuffer(bytes: indices, length: MemoryLayout.stride * indices.count, options: []) else { + guard + let verticesBuffer = device.makeBuffer( + bytes: vertecies, + length: MemoryLayout.stride * vertecies.count, + options: []), + let indicesBuffer = device.makeBuffer( + bytes: indices, + length: MemoryLayout.stride * indices.count, options: [] + ) + else { fatalError("Cannot allocate buffers") } @@ -227,7 +254,10 @@ extension TextInstanced: MCTextInstancedInterface { } } - func loadTexture(_ context: MCRenderingContextInterface?, textureHolder: MCTextureHolderInterface?) { + func loadTexture( + _ context: MCRenderingContextInterface?, + textureHolder: MCTextureHolderInterface? + ) { guard let textureHolder = textureHolder as? TextureHolder else { fatalError("unexpected TextureHolder") } @@ -245,7 +275,8 @@ extension TextInstanced: MCTextInstancedInterface { func setReferencePositions(_ positions: MCSharedBytes) { lock.withCritical { - referencePositionsBuffer.copyOrCreate(from: positions, device: device) + referencePositionsBuffer.copyOrCreate( + from: positions, device: device) } } @@ -257,7 +288,8 @@ extension TextInstanced: MCTextInstancedInterface { func setTextureCoordinates(_ textureCoordinates: MCSharedBytes) { lock.withCritical { - textureCoordinatesBuffer.copyOrCreate(from: textureCoordinates, device: device) + textureCoordinatesBuffer.copyOrCreate( + from: textureCoordinates, device: device) } } diff --git a/ios/graphics/Shader/Metal/BaseShader.metal b/ios/graphics/Shader/Metal/BaseShader.metal index c823a42f2..77642033c 100644 --- a/ios/graphics/Shader/Metal/BaseShader.metal +++ b/ios/graphics/Shader/Metal/BaseShader.metal @@ -49,9 +49,7 @@ vertex VertexOut colorVertexShader(const Vertex3FIn vertexIn [[stage_in]], constant float4x4 &vpMatrix [[buffer(1)]], constant float4x4 &mMatrix [[buffer(2)]], - constant float4 &originOffset [[buffer(3)]], - constant float4 &debugTileOrigin [[buffer(4)]], - constant float4 &debugRenderOrigin [[buffer(5)]]) + constant float4 &originOffset [[buffer(3)]]) { VertexOut out { .position = vpMatrix * ((mMatrix * float4(vertexIn.position.xyz, 1.0)) + originOffset), diff --git a/ios/graphics/Shader/Metal/LineShader.metal b/ios/graphics/Shader/Metal/LineShader.metal index 558bdec5a..e21da4dfc 100644 --- a/ios/graphics/Shader/Metal/LineShader.metal +++ b/ios/graphics/Shader/Metal/LineShader.metal @@ -82,9 +82,7 @@ unitSpherelineGroupVertexShader(const LineVertexUnitSphereIn vertexIn [[stage_in constant float &dashingScalingFactor [[buffer(3)]], constant float *styling [[buffer(4)]], constant float4 &originOffset [[buffer(5)]], - constant float4 &tileOrigin [[buffer(6)]], - constant float4 &debugTileOrigin [[buffer(7)]], - constant float4 &debugRenderOrigin [[buffer(8)]]) + constant float4 &tileOrigin [[buffer(6)]]) { int styleIndex = (int(vertexIn.stylingIndex) & 0xFF) * 21; constant LineStyling *style = (constant LineStyling *)(styling + styleIndex); From 4e5d0befd207d5f9c983509d61864330d9ec6aad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20Ma=CC=88rki?= Date: Mon, 4 Nov 2024 17:16:54 +0100 Subject: [PATCH 06/12] code review fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nicolas Märki --- ios/graphics/Model/MultiBuffer.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ios/graphics/Model/MultiBuffer.swift b/ios/graphics/Model/MultiBuffer.swift index ae18e53e2..007599241 100644 --- a/ios/graphics/Model/MultiBuffer.swift +++ b/ios/graphics/Model/MultiBuffer.swift @@ -38,11 +38,11 @@ public struct MultiBuffer { extension MultiBuffer { public init(device: MTLDevice) { var initialMutable = simd_float1(1.0) - var buffers: [MTLBuffer] = (0...stride + length: MemoryLayout.stride ) } self.init(buffers: buffers) @@ -56,7 +56,7 @@ extension MultiBuffer { device .makeBuffer( bytes: &initialMutable, - length: MemoryLayout.stride + length: MemoryLayout.stride ) } self.init(buffers: buffers) From 53815634233a0491d5559068e275870353fa89dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20Ma=CC=88rki?= Date: Mon, 4 Nov 2024 17:38:29 +0100 Subject: [PATCH 07/12] improve render semaphore usage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nicolas Märki --- ios/maps/MCMapView.swift | 195 +++++++++++++++++++++++++-------------- 1 file changed, 124 insertions(+), 71 deletions(-) diff --git a/ios/maps/MCMapView.swift b/ios/maps/MCMapView.swift index ac846435d..fb3084dff 100644 --- a/ios/maps/MCMapView.swift +++ b/ios/maps/MCMapView.swift @@ -20,34 +20,43 @@ open class MCMapView: MTKView, @unchecked Sendable { private var sizeChanged = false private var backgroundDisable = false private var saveDrawable = false - private lazy var renderToImageQueue = DispatchQueue(label: "io.openmobilemaps.renderToImagQueue", qos: .userInteractive) + private lazy var renderToImageQueue = DispatchQueue( + label: "io.openmobilemaps.renderToImagQueue", qos: .userInteractive) private var framesToRender: Int = 1 private let framesToRenderAfterInvalidate: Int = 25 private var lastInvalidate = Date() - private let renderAfterInvalidate: TimeInterval = 3 // Collision detection might be delayed 3s - private var renderSemaphore = DispatchSemaphore(value: 3) // using tripple buffers + private let renderAfterInvalidate: TimeInterval = 3 // Collision detection might be delayed 3s + private var renderSemaphore = DispatchSemaphore(value: 3) // using tripple buffers private let touchHandler: MCMapViewTouchHandler private let callbackHandler = MCMapViewCallbackHandler() public weak var sizeDelegate: MCMapSizeDelegate? - public init(mapConfig: MCMapConfig = MCMapConfig(mapCoordinateSystem: MCCoordinateSystemFactory.getEpsg3857System()), pixelsPerInch: Float? = nil, is3D: Bool = false) { + public init( + mapConfig: MCMapConfig = MCMapConfig( + mapCoordinateSystem: MCCoordinateSystemFactory.getEpsg3857System()), + pixelsPerInch: Float? = nil, is3D: Bool = false + ) { let renderingContext = RenderingContext() - guard let mapInterface = MCMapInterface.create(GraphicsFactory(), - shaderFactory: ShaderFactory(), - renderingContext: renderingContext, - mapConfig: mapConfig, - scheduler: MCThreadPoolScheduler.create(), - pixelDensity: pixelsPerInch ?? Float(UIScreen.pixelsPerInch), - is3D: is3D) else { + guard + let mapInterface = MCMapInterface.create( + GraphicsFactory(), + shaderFactory: ShaderFactory(), + renderingContext: renderingContext, + mapConfig: mapConfig, + scheduler: MCThreadPoolScheduler.create(), + pixelDensity: pixelsPerInch ?? Float(UIScreen.pixelsPerInch), + is3D: is3D) + else { fatalError("Can't create MCMapInterface") } self.mapInterface = mapInterface self.renderingContext = renderingContext - touchHandler = MCMapViewTouchHandler(touchHandler: mapInterface.getTouchHandler()) + touchHandler = MCMapViewTouchHandler( + touchHandler: mapInterface.getTouchHandler()) super.init(frame: .zero, device: MetalContext.current.device) setup() } @@ -88,7 +97,7 @@ open class MCMapView: MTKView, @unchecked Sendable { preferredFramesPerSecond = 120 - sampleCount = 1 // samples per pixel + sampleCount = 1 // samples per pixel callbackHandler.invalidateCallback = { [weak self] in self?.invalidate() @@ -105,13 +114,15 @@ open class MCMapView: MTKView, @unchecked Sendable { } private func addEventListeners() { - NotificationCenter.default.addObserver(self, - selector: #selector(willEnterForeground), - name: UIApplication.willEnterForegroundNotification, - object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackground), - name: UIApplication.didEnterBackgroundNotification, - object: nil) + NotificationCenter.default.addObserver( + self, + selector: #selector(willEnterForeground), + name: UIApplication.willEnterForegroundNotification, + object: nil) + NotificationCenter.default.addObserver( + self, selector: #selector(didEnterBackground), + name: UIApplication.didEnterBackgroundNotification, + object: nil) } @objc func willEnterForeground() { @@ -137,7 +148,8 @@ open class MCMapView: MTKView, @unchecked Sendable { } set { super.backgroundColor = newValue - mapInterface.setBackgroundColor(newValue?.mapCoreColor ?? UIColor.clear.mapCoreColor) + mapInterface.setBackgroundColor( + newValue?.mapCoreColor ?? UIColor.clear.mapCoreColor) isOpaque = newValue?.isOpaque ?? false } } @@ -158,24 +170,30 @@ extension MCMapView: MTKViewDelegate { public func draw(in view: MTKView) { guard !backgroundDisable else { isPaused = true - return // don't execute metal calls in background + return // don't execute metal calls in background } - guard framesToRender > 0 || -lastInvalidate.timeIntervalSinceNow < renderAfterInvalidate else { + guard + framesToRender > 0 + || -lastInvalidate.timeIntervalSinceNow < renderAfterInvalidate + else { isPaused = true return } - renderSemaphore.wait() - framesToRender -= 1 + // Ensure that tripple-buffers are not over-used + renderSemaphore.wait() + mapInterface.prepare() guard let renderPassDescriptor = view.currentRenderPassDescriptor, - let commandBuffer = MetalContext.current.commandQueue.makeCommandBuffer(), - let computeEncoder = commandBuffer.makeComputeCommandEncoder() + let commandBuffer = MetalContext.current.commandQueue + .makeCommandBuffer(), + let computeEncoder = commandBuffer.makeComputeCommandEncoder() else { + self.renderSemaphore.signal() return } @@ -183,7 +201,11 @@ extension MCMapView: MTKViewDelegate { mapInterface.compute() computeEncoder.endEncoding() - guard let renderEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor) else { + guard + let renderEncoder = commandBuffer.makeRenderCommandEncoder( + descriptor: renderPassDescriptor) + else { + self.renderSemaphore.signal() return } @@ -202,6 +224,7 @@ extension MCMapView: MTKViewDelegate { renderEncoder.endEncoding() guard let drawable = view.currentDrawable else { + self.renderSemaphore.signal() return } @@ -220,10 +243,18 @@ extension MCMapView: MTKViewDelegate { } } - public func renderToImage(size: CGSize, timeout: Float, bounds: MCRectCoord, callbackQueue: DispatchQueue = .main, callback: @escaping @Sendable (UIImage?, MCLayerReadyState) -> Void) { + public func renderToImage( + size: CGSize, timeout: Float, bounds: MCRectCoord, + callbackQueue: DispatchQueue = .main, + callback: @escaping @Sendable (UIImage?, MCLayerReadyState) -> Void + ) { renderToImageQueue.async { DispatchQueue.main.sync { - self.frame = CGRect(origin: .zero, size: .init(width: size.width / UIScreen.main.scale, height: size.height / UIScreen.main.scale)) + self.frame = CGRect( + origin: .zero, + size: .init( + width: size.width / UIScreen.main.scale, + height: size.height / UIScreen.main.scale)) self.setNeedsLayout() self.layoutIfNeeded() } @@ -233,13 +264,14 @@ extension MCMapView: MTKViewDelegate { mapReadyCallbacks.callback = callback mapReadyCallbacks.callbackQueue = callbackQueue - self.mapInterface.drawReadyFrame(bounds, timeout: timeout, callbacks: mapReadyCallbacks) + self.mapInterface.drawReadyFrame( + bounds, timeout: timeout, callbacks: mapReadyCallbacks) } } } -private extension MCMapView { - func currentDrawableImage() -> UIImage? { +extension MCMapView { + fileprivate func currentDrawableImage() -> UIImage? { self.saveDrawable = true self.invalidate() self.draw(in: self) @@ -248,14 +280,16 @@ private extension MCMapView { guard let texture = self.currentDrawable?.texture else { return nil } let context = CIContext() - let kciOptions: [CIImageOption: Any] = [.colorSpace: CGColorSpaceCreateDeviceRGB()] + let kciOptions: [CIImageOption: Any] = [ + .colorSpace: CGColorSpaceCreateDeviceRGB() + ] let cImg = CIImage(mtlTexture: texture, options: kciOptions)! return context.createCGImage(cImg, from: cImg.extent)?.toImage() } } -private extension CGImage { - func toImage() -> UIImage? { +extension CGImage { + fileprivate func toImage() -> UIImage? { let w = Double(width) let h = Double(height) UIGraphicsBeginImageContext(CGSize(width: w, height: h)) @@ -271,33 +305,44 @@ private extension CGImage { extension CGSize { var vec2: MCVec2I { - MCVec2I(x: Int32(width), - y: Int32(height)) + MCVec2I( + x: Int32(width), + y: Int32(height)) } } -public extension MCMapView { - override func touchesBegan(_ touches: Set, with event: UIEvent?) { +extension MCMapView { + public override func touchesBegan( + _ touches: Set, with event: UIEvent? + ) { super.touchesBegan(touches, with: event) touchHandler.touchesBegan(touches, with: event) } - override func touchesEnded(_ touches: Set, with event: UIEvent?) { + public override func touchesEnded( + _ touches: Set, with event: UIEvent? + ) { super.touchesEnded(touches, with: event) touchHandler.touchesEnded(touches, with: event) } - override func touchesCancelled(_ touches: Set, with event: UIEvent?) { + public override func touchesCancelled( + _ touches: Set, with event: UIEvent? + ) { super.touchesCancelled(touches, with: event) touchHandler.touchesCancelled(touches, with: event) } - override func touchesMoved(_ touches: Set, with event: UIEvent?) { + public override func touchesMoved( + _ touches: Set, with event: UIEvent? + ) { super.touchesMoved(touches, with: event) touchHandler.touchesMoved(touches, with: event) } - override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { + public override func gestureRecognizerShouldBegin( + _ gestureRecognizer: UIGestureRecognizer + ) -> Bool { var isiOSAppOnMac = false if #available(iOS 14.0, *) { isiOSAppOnMac = ProcessInfo.processInfo.isiOSAppOnMac @@ -306,52 +351,52 @@ public extension MCMapView { } } -public extension MCMapView { - var camera: MCMapCameraInterface { +extension MCMapView { + public var camera: MCMapCameraInterface { mapInterface.getCamera()! } - var camera3d: MCMapCamera3dInterface? { + public var camera3d: MCMapCamera3dInterface? { camera.asMapCamera3d() } - func add(layer: MCLayerInterface?) { + public func add(layer: MCLayerInterface?) { mapInterface.addLayer(layer) } - func insert(layer: MCLayerInterface?, at index: Int) { + public func insert(layer: MCLayerInterface?, at index: Int) { mapInterface.insertLayer(at: layer, at: Int32(index)) } - func insert(layer: MCLayerInterface?, above: MCLayerInterface?) { + public func insert(layer: MCLayerInterface?, above: MCLayerInterface?) { mapInterface.insertLayer(above: layer, above: above) } - func insert(layer: MCLayerInterface?, below: MCLayerInterface?) { + public func insert(layer: MCLayerInterface?, below: MCLayerInterface?) { mapInterface.insertLayer(below: layer, below: below) } - func remove(layer: MCLayerInterface?) { + public func remove(layer: MCLayerInterface?) { mapInterface.removeLayer(layer) } - func add(layer: any Layer) { + public func add(layer: any Layer) { mapInterface.addLayer(layer.interface) } - func insert(layer: any Layer, at index: Int) { + public func insert(layer: any Layer, at index: Int) { mapInterface.insertLayer(at: layer.interface, at: Int32(index)) } - func insert(layer: any Layer, above: MCLayerInterface?) { + public func insert(layer: any Layer, above: MCLayerInterface?) { mapInterface.insertLayer(above: layer.interface, above: above) } - func insert(layer: any Layer, below: MCLayerInterface?) { + public func insert(layer: any Layer, below: MCLayerInterface?) { mapInterface.insertLayer(below: layer.interface, below: below) } - func remove(layer: any Layer) { + public func remove(layer: any Layer) { mapInterface.removeLayer(layer.interface) } } @@ -367,12 +412,14 @@ extension MCMapView: UIGestureRecognizerDelegate { guard isiOSAppOnMac else { return } - let pinch = UIPinchGestureRecognizer(target: self, action: #selector(pinched)) + let pinch = UIPinchGestureRecognizer( + target: self, action: #selector(pinched)) pinch.delegate = self pinch.allowedTouchTypes = [] self.addGestureRecognizer(pinch) - let pan = UIPanGestureRecognizer(target: self, action: #selector(panned)) + let pan = UIPanGestureRecognizer( + target: self, action: #selector(panned)) pan.delegate = self if #available(iOS 13.4, *) { pan.allowedScrollTypesMask = .continuous @@ -383,7 +430,11 @@ extension MCMapView: UIGestureRecognizerDelegate { pan.require(toFail: pinch) } - public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { + public func gestureRecognizer( + _ gestureRecognizer: UIGestureRecognizer, + shouldRecognizeSimultaneouslyWith otherGestureRecognizer: + UIGestureRecognizer + ) -> Bool { true } @@ -396,7 +447,9 @@ extension MCMapView: UIGestureRecognizerDelegate { } } -private class MCMapViewMapReadyCallbacks: @preconcurrency MCMapReadyCallbackInterface, @unchecked Sendable { +private class MCMapViewMapReadyCallbacks: @preconcurrency + MCMapReadyCallbackInterface, @unchecked Sendable +{ public nonisolated(unsafe) weak var delegate: MCMapView? public var callback: ((UIImage?, MCLayerReadyState) -> Void)? public var callbackQueue: DispatchQueue? @@ -411,16 +464,16 @@ private class MCMapViewMapReadyCallbacks: @preconcurrency MCMapReadyCallbackInte callbackQueue?.async { switch state { - case .NOT_READY: - break - case .ERROR, .TIMEOUT_ERROR: - self.callback?(nil, state) - case .READY: - MainActor.assumeIsolated { - self.callback?(delegate.currentDrawableImage(), state) - } - @unknown default: - break + case .NOT_READY: + break + case .ERROR, .TIMEOUT_ERROR: + self.callback?(nil, state) + case .READY: + MainActor.assumeIsolated { + self.callback?(delegate.currentDrawableImage(), state) + } + @unknown default: + break } self.semaphore.signal() } From e9a09fff3e981ec373beec3bea2bdae221d4310c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20Ma=CC=88rki?= Date: Mon, 4 Nov 2024 20:29:50 +0100 Subject: [PATCH 08/12] use global buffer index MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nicolas Märki --- ios/graphics/Model/MultiBuffer.swift | 22 +++---- ios/graphics/RenderingContext.swift | 91 +++++++++++++++++----------- 2 files changed, 62 insertions(+), 51 deletions(-) diff --git a/ios/graphics/Model/MultiBuffer.swift b/ios/graphics/Model/MultiBuffer.swift index 007599241..e05239ce5 100644 --- a/ios/graphics/Model/MultiBuffer.swift +++ b/ios/graphics/Model/MultiBuffer.swift @@ -8,14 +8,10 @@ import Metal import simd -private let bufferCount = 3 // Triple buffering - public struct MultiBuffer { // Warning: Seems like suited to be generic // But makeBuffer &reference does not like generic data var buffers: [MTLBuffer] - var currentBufferIndex = 0 - var currentFrameId = -1 fileprivate init(buffers: [MTLBuffer]) { self.buffers = buffers @@ -24,21 +20,15 @@ public struct MultiBuffer { public mutating func getNextBuffer(_ context: RenderingContext) -> MTLBuffer? { - if context.frameId != currentFrameId { - currentBufferIndex = (currentBufferIndex + 1) % bufferCount - currentFrameId = context.frameId - } - guard currentBufferIndex < buffers.count else { - return nil - } - return buffers[currentBufferIndex] + return buffers[context.currentBufferIndex] } } extension MultiBuffer { public init(device: MTLDevice) { var initialMutable = simd_float1(1.0) - let buffers: [MTLBuffer] = (0.. { extension MultiBuffer { public init(device: MTLDevice) { var initialMutable = simd_float4(0.0, 0.0, 0.0, 0.0) - let buffers: [MTLBuffer] = (0.. { extension MultiBuffer { public init(device: MTLDevice) { var initialMutable = simd_float4x4(1.0) - let buffers: [MTLBuffer] = (0.. Date: Mon, 4 Nov 2024 21:21:26 +0100 Subject: [PATCH 09/12] improve swift buffers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nicolas Märki --- ios/graphics/RenderingContext.swift | 5 ++++- ios/maps/MCMapView.swift | 8 ++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/ios/graphics/RenderingContext.swift b/ios/graphics/RenderingContext.swift index 603c73463..bdb5b5c44 100644 --- a/ios/graphics/RenderingContext.swift +++ b/ios/graphics/RenderingContext.swift @@ -77,14 +77,17 @@ public class RenderingContext: NSObject, @unchecked Sendable { var isScissoringDirty = false var currentPipeline: MTLRenderPipelineState? + var currentPipelineHash = 0 open func setRenderPipelineStateIfNeeded( _ pipelineState: MTLRenderPipelineState ) { - guard currentPipeline?.hash != pipelineState.hash else { + let newHash = pipelineState.hash + guard currentPipelineHash != newHash else { return } currentPipeline = pipelineState + currentPipelineHash = newHash encoder?.setRenderPipelineState(pipelineState) } diff --git a/ios/maps/MCMapView.swift b/ios/maps/MCMapView.swift index fb3084dff..023171b78 100644 --- a/ios/maps/MCMapView.swift +++ b/ios/maps/MCMapView.swift @@ -27,7 +27,7 @@ open class MCMapView: MTKView, @unchecked Sendable { private let framesToRenderAfterInvalidate: Int = 25 private var lastInvalidate = Date() private let renderAfterInvalidate: TimeInterval = 3 // Collision detection might be delayed 3s - private var renderSemaphore = DispatchSemaphore(value: 3) // using tripple buffers + private var renderSemaphore = DispatchSemaphore(value: 3) // using triple buffers private let touchHandler: MCMapViewTouchHandler private let callbackHandler = MCMapViewCallbackHandler() @@ -183,7 +183,7 @@ extension MCMapView: MTKViewDelegate { framesToRender -= 1 - // Ensure that tripple-buffers are not over-used + // Ensure that triple-buffers are not over-used renderSemaphore.wait() mapInterface.prepare() @@ -228,8 +228,8 @@ extension MCMapView: MTKViewDelegate { return } - commandBuffer.addCompletedHandler { [weak self] _ in - self?.renderSemaphore.signal() + commandBuffer.addCompletedHandler {_ in + self.renderSemaphore.signal() } // if we want to save the drawable (offscreen rendering), we commit and wait synchronously From 9c0d86d0fd4c7e932df02096b502f07ae02ead38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20Ma=CC=88rki?= Date: Tue, 5 Nov 2024 07:15:29 +0100 Subject: [PATCH 10/12] revert pipeline hash comparison change MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nicolas Märki --- ios/graphics/RenderingContext.swift | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ios/graphics/RenderingContext.swift b/ios/graphics/RenderingContext.swift index bdb5b5c44..603c73463 100644 --- a/ios/graphics/RenderingContext.swift +++ b/ios/graphics/RenderingContext.swift @@ -77,17 +77,14 @@ public class RenderingContext: NSObject, @unchecked Sendable { var isScissoringDirty = false var currentPipeline: MTLRenderPipelineState? - var currentPipelineHash = 0 open func setRenderPipelineStateIfNeeded( _ pipelineState: MTLRenderPipelineState ) { - let newHash = pipelineState.hash - guard currentPipelineHash != newHash else { + guard currentPipeline?.hash != pipelineState.hash else { return } currentPipeline = pipelineState - currentPipelineHash = newHash encoder?.setRenderPipelineState(pipelineState) } From 2ec143dd107aa180cc773d7c5e384f8a45fe3a90 Mon Sep 17 00:00:00 2001 From: Christoph Maurhofer Date: Tue, 12 Nov 2024 13:01:37 +0100 Subject: [PATCH 11/12] Readd custom vp computation matrices --- shared/src/map/camera/MapCamera3d.cpp | 42 ++++++++++++++++----------- shared/src/map/camera/MapCamera3d.h | 3 ++ 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/shared/src/map/camera/MapCamera3d.cpp b/shared/src/map/camera/MapCamera3d.cpp index fdabd754b..d2f36581a 100644 --- a/shared/src/map/camera/MapCamera3d.cpp +++ b/shared/src/map/camera/MapCamera3d.cpp @@ -389,14 +389,17 @@ std::vector MapCamera3d::getVpMatrix() { void MapCamera3d::updateMatrices() { std::lock_guard lock(paramMutex); + computeMatrices(focusPointPosition, false); +} + +std::optional, std::vector, Vec3D>> MapCamera3d::computeMatrices(const Coord &focusCoord, bool onlyReturnResult) { + std::lock_guard lock(paramMutex); Vec2I sizeViewport = mapInterface->getRenderingContext()->getViewportSize(); std::vector newViewMatrix(16, 0.0); std::vector newProjectionMatrix(16, 0.0); - auto focusCoord = focusPointPosition; - const float R = 6378137.0; const double longitude = focusCoord.x; // px / R; const double latitude = focusCoord.y; // 2*atan(exp(py / R)) - 3.1415926 / 2; @@ -475,19 +478,25 @@ void MapCamera3d::updateMatrices() { std::vector newProjectionMatrixF = VectorHelper::convertToFloat(newProjectionMatrix); std::vector newViewMatrixF = VectorHelper::convertToFloat(newViewMatrix); - std::lock_guard writeLock(matrixMutex); - lastVpRotation = angle; - lastVpZoom = zoom; - vpMatrix = newVpMatrixF; - vpMatrixD = newVpMatrix; - inverseVPMatrix = newInverseMatrix; - viewMatrix = newViewMatrixF; - projectionMatrix = newProjectionMatrixF; - verticalFov = fovy; - horizontalFov = fovy * vpr; - validVpMatrix = true; - origin = newOrigin; - lastScalingFactor = mapUnitsFromPixels(1.0); + if (onlyReturnResult) { + return std::tuple{newVpMatrix, newInverseMatrix, newOrigin}; + } else { + std::lock_guard writeLock(matrixMutex); + lastVpRotation = angle; + lastVpZoom = zoom; + vpMatrix = newVpMatrixF; + vpMatrixD = newVpMatrix; + inverseVPMatrix = newInverseMatrix; + viewMatrix = newViewMatrixF; + projectionMatrix = newProjectionMatrixF; + verticalFov = fovy; + horizontalFov = fovy * vpr; + validVpMatrix = true; + origin = newOrigin; + lastScalingFactor = mapUnitsFromPixels(1.0); + + return std::nullopt; + } } Vec3D MapCamera3d::getOrigin() { @@ -707,9 +716,8 @@ bool MapCamera3d::onTouchDown(const ::Vec2F &posScreen) { lastOnTouchDownFocusCoord = focusPointPosition; #ifdef ANDROID { - std::lock_guard lock(vpDataMutex); const auto [zeroVPMatrix, zeroInverseVPMatrix, zeroOrigin] = - getVpMatrix(Coord(CoordinateSystemIdentifiers::EPSG4326(), 0.0, 0.0, lastOnTouchDownFocusCoord->z), false); + *computeMatrices(Coord(CoordinateSystemIdentifiers::EPSG4326(), 0.0, 0.0, lastOnTouchDownFocusCoord->z), true); lastOnTouchDownInverseVPMatrix = zeroInverseVPMatrix; lastOnTouchDownVPOrigin = zeroOrigin; } diff --git a/shared/src/map/camera/MapCamera3d.h b/shared/src/map/camera/MapCamera3d.h index 78ba98a24..8d7da211f 100644 --- a/shared/src/map/camera/MapCamera3d.h +++ b/shared/src/map/camera/MapCamera3d.h @@ -91,6 +91,8 @@ class MapCamera3d : public MapCameraInterface, void updateMatrices(); + std::optional, std::vector, Vec3D>> computeMatrices(const Coord &focusCoord, bool onlyReturnResult); + virtual ::Vec3D getOrigin() override; virtual std::optional> getLastVpMatrixD() override; @@ -316,4 +318,5 @@ class MapCamera3d : public MapCameraInterface, Camera3dConfig cameraZoomConfig; std::shared_ptr<::CoordinateConversionHelperInterface> coordinateConversionHelper; + }; From e96bcbbd317a804fb2f6820d730ac17a8232a1aa Mon Sep 17 00:00:00 2001 From: Christoph Maurhofer Date: Tue, 12 Nov 2024 14:05:19 +0100 Subject: [PATCH 12/12] Remove superfluous conversion helper interface --- shared/src/map/camera/MapCamera3d.cpp | 43 +++++++++++++-------------- shared/src/map/camera/MapCamera3d.h | 2 -- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/shared/src/map/camera/MapCamera3d.cpp b/shared/src/map/camera/MapCamera3d.cpp index d2f36581a..9905f5714 100644 --- a/shared/src/map/camera/MapCamera3d.cpp +++ b/shared/src/map/camera/MapCamera3d.cpp @@ -38,20 +38,19 @@ #define GLOBE_MAX_ZOOM 5'000'000 MapCamera3d::MapCamera3d(const std::shared_ptr &mapInterface, float screenDensityPpi) - : mapInterface(mapInterface) - , conversionHelper(mapInterface->getCoordinateConverterHelper()) - , mapCoordinateSystem(mapInterface->getMapConfig().mapCoordinateSystem) - , screenDensityPpi(screenDensityPpi) - , screenPixelAsRealMeterFactor(0.0254 / screenDensityPpi * mapCoordinateSystem.unitToScreenMeterFactor) - , focusPointPosition(CoordinateSystemIdentifiers::EPSG4326(), 0, 0, 0) - , cameraPitch(0) - , zoomMin(GLOBE_MIN_ZOOM) - , zoomMax(GLOBE_MAX_ZOOM) - , lastOnTouchDownPoint(std::nullopt) - , bounds(mapCoordinateSystem.bounds) - , origin(0, 0, 0) - , cameraZoomConfig(Camera3dConfigFactory::getBasicConfig()) - , coordinateConversionHelper(mapInterface->getCoordinateConverterHelper()) { + : mapInterface(mapInterface), + conversionHelper(mapInterface->getCoordinateConverterHelper()), + mapCoordinateSystem(mapInterface->getMapConfig().mapCoordinateSystem), + screenDensityPpi(screenDensityPpi), + screenPixelAsRealMeterFactor(0.0254 / screenDensityPpi * mapCoordinateSystem.unitToScreenMeterFactor), + focusPointPosition(CoordinateSystemIdentifiers::EPSG4326(), 0, 0, 0), + cameraPitch(0), + zoomMin(GLOBE_MIN_ZOOM), + zoomMax(GLOBE_MAX_ZOOM), + lastOnTouchDownPoint(std::nullopt), + bounds(mapCoordinateSystem.bounds), + origin(0, 0, 0), + cameraZoomConfig(Camera3dConfigFactory::getBasicConfig()) { mapSystemRtl = mapCoordinateSystem.bounds.bottomRight.x > mapCoordinateSystem.bounds.topLeft.x; mapSystemTtb = mapCoordinateSystem.bounds.bottomRight.y > mapCoordinateSystem.bounds.topLeft.y; updateZoom(GLOBE_MIN_ZOOM); @@ -92,7 +91,7 @@ void MapCamera3d::moveToCenterPositionZoom(const ::Coord ¢erPosition, double return; inertia = std::nullopt; auto [focusPosition, focusZoom] = - getBoundsCorrectedCoords(coordinateConversionHelper->convert(focusPointPosition.systemIdentifier, centerPosition), zoom); + getBoundsCorrectedCoords(conversionHelper->convert(focusPointPosition.systemIdentifier, centerPosition), zoom); if (animated && bounds.topLeft.x == mapCoordinateSystem.bounds.topLeft.x && bounds.bottomRight.x == mapCoordinateSystem.bounds.bottomRight.x) { @@ -145,7 +144,7 @@ void MapCamera3d::moveToCenterPosition(const ::Coord ¢erPosition, bool anima return; inertia = std::nullopt; auto [focusPosition, focusZoom] = - getBoundsCorrectedCoords(coordinateConversionHelper->convert(focusPointPosition.systemIdentifier, centerPosition), zoom); + getBoundsCorrectedCoords(conversionHelper->convert(focusPointPosition.systemIdentifier, centerPosition), zoom); if (animated && bounds.topLeft.x == mapCoordinateSystem.bounds.topLeft.x && bounds.bottomRight.x == mapCoordinateSystem.bounds.bottomRight.x) { @@ -1400,7 +1399,7 @@ double MapCamera3d::getMinZoom() { return zoomMin; } double MapCamera3d::getMaxZoom() { return zoomMax; } void MapCamera3d::setBounds(const RectCoord &bounds) { - RectCoord boundsMapSpace = coordinateConversionHelper->convertRect(mapCoordinateSystem.identifier, bounds); + RectCoord boundsMapSpace = conversionHelper->convertRect(mapCoordinateSystem.identifier, bounds); this->bounds = boundsMapSpace; const auto [adjPosition, adjZoom] = getBoundsCorrectedCoords(focusPointPosition, zoom); @@ -1413,7 +1412,7 @@ void MapCamera3d::setBounds(const RectCoord &bounds) { RectCoord MapCamera3d::getBounds() { return bounds; } bool MapCamera3d::isInBounds(const Coord &coords) { - Coord mapCoords = coordinateConversionHelper->convert(mapCoordinateSystem.identifier, coords); + Coord mapCoords = conversionHelper->convert(mapCoordinateSystem.identifier, coords); auto const bounds = this->bounds; @@ -1426,7 +1425,7 @@ bool MapCamera3d::isInBounds(const Coord &coords) { } Coord MapCamera3d::adjustCoordForPadding(const Coord &coords, double targetZoom) { - Coord coordinates = coordinateConversionHelper->convert(focusPointPosition.systemIdentifier, coords); + Coord coordinates = conversionHelper->convert(focusPointPosition.systemIdentifier, coords); auto adjustedZoom = std::clamp(targetZoom, zoomMax, zoomMin); @@ -1461,8 +1460,8 @@ std::tuple MapCamera3d::getBoundsCorrectedCoords(const Coord &pos const auto &id = position.systemIdentifier; - Coord topLeft = coordinateConversionHelper->convert(id, bounds.topLeft); - Coord bottomRight = coordinateConversionHelper->convert(id, bounds.bottomRight); + Coord topLeft = conversionHelper->convert(id, bounds.topLeft); + Coord bottomRight = conversionHelper->convert(id, bounds.bottomRight); Coord clampedPosition = Coord(id, std::clamp(position.x, std::min(topLeft.x, bottomRight.x), std::max(topLeft.x, bottomRight.x)), @@ -1558,7 +1557,7 @@ void MapCamera3d::setCameraConfig(const Camera3dConfig &config, std::optionalconvert(CoordinateSystemIdentifiers::EPSG4326(), focusPointPosition); + Coord startPosition = conversionHelper->convert(CoordinateSystemIdentifiers::EPSG4326(), focusPointPosition); coordAnimation = std::make_shared( duration, startPosition, *targetCoordinate, std::nullopt, InterpolatorFunction::EaseInOut, diff --git a/shared/src/map/camera/MapCamera3d.h b/shared/src/map/camera/MapCamera3d.h index 8d7da211f..c8ac5ad90 100644 --- a/shared/src/map/camera/MapCamera3d.h +++ b/shared/src/map/camera/MapCamera3d.h @@ -317,6 +317,4 @@ class MapCamera3d : public MapCameraInterface, Camera3dConfig cameraZoomConfig; - std::shared_ptr<::CoordinateConversionHelperInterface> coordinateConversionHelper; - };