From 6811b73b88c0da79bf12efb8cf1a85c66a669076 Mon Sep 17 00:00:00 2001 From: Stanislav Mishchenko Date: Wed, 5 Jun 2024 16:47:04 +0300 Subject: [PATCH 01/12] add mouse input handler tests --- .../engine/components/SpriteRenderer.kt | 37 ------- .../engine/core/batch/RenderBatch.kt | 2 +- .../engine/core/input/MouseInputHandler.kt | 16 --- .../utils/RenderingTestsOpenGLUtils.kt | 22 ++++ .../engine/core/batch/RenderBatchTests.kt | 36 ++++++ .../core/input/MouseInputHandlerTests.kt | 104 ++++++++++++++++++ 6 files changed, 163 insertions(+), 54 deletions(-) delete mode 100644 src/main/kotlin/solve/rendering/engine/components/SpriteRenderer.kt create mode 100644 src/test/kotlin/solve/rendering/utils/RenderingTestsOpenGLUtils.kt create mode 100644 src/test/kotlin/solve/unit/rendering/engine/core/batch/RenderBatchTests.kt create mode 100644 src/test/kotlin/solve/unit/rendering/engine/core/input/MouseInputHandlerTests.kt diff --git a/src/main/kotlin/solve/rendering/engine/components/SpriteRenderer.kt b/src/main/kotlin/solve/rendering/engine/components/SpriteRenderer.kt deleted file mode 100644 index 4a15ff3f..00000000 --- a/src/main/kotlin/solve/rendering/engine/components/SpriteRenderer.kt +++ /dev/null @@ -1,37 +0,0 @@ -package solve.rendering.engine.components - -import solve.rendering.engine.core.texture.Texture2D -import solve.rendering.engine.scene.Transform -import solve.rendering.engine.structures.Color - -class SpriteRenderer(val transform: Transform = Transform()) { - var color = Color.white - private set - var sprite: Sprite? = null - private set - - val texture: Texture2D? - get() = sprite?.texture - - constructor(texture: Texture2D) : this() { - setTexture(texture) - } - - constructor(sprite: Sprite) : this() { - setSprite(sprite) - } - - fun setColor(color: Color) { - this.color = color - } - - fun setSprite(sprite: Sprite) { - this.sprite = sprite - } - - fun setTexture(texture: Texture2D) { - if (sprite?.texture != texture) { - sprite = Sprite(texture) - } - } -} diff --git a/src/main/kotlin/solve/rendering/engine/core/batch/RenderBatch.kt b/src/main/kotlin/solve/rendering/engine/core/batch/RenderBatch.kt index 6d033a9d..fd143ee7 100644 --- a/src/main/kotlin/solve/rendering/engine/core/batch/RenderBatch.kt +++ b/src/main/kotlin/solve/rendering/engine/core/batch/RenderBatch.kt @@ -190,7 +190,7 @@ open class RenderBatch( } companion object { - private const val MaxTexturesNumber = 7 + const val MaxTexturesNumber = 7 private val batchComparator = Comparator.comparingInt { it.zIndex } } diff --git a/src/main/kotlin/solve/rendering/engine/core/input/MouseInputHandler.kt b/src/main/kotlin/solve/rendering/engine/core/input/MouseInputHandler.kt index f005f700..55067a6f 100644 --- a/src/main/kotlin/solve/rendering/engine/core/input/MouseInputHandler.kt +++ b/src/main/kotlin/solve/rendering/engine/core/input/MouseInputHandler.kt @@ -1,14 +1,11 @@ package solve.rendering.engine.core.input -import javafx.scene.robot.Robot import org.joml.Vector2i import solve.rendering.engine.utils.minus import solve.rendering.engine.utils.pointToSegmentDistance import solve.rendering.engine.utils.toFloatVector import solve.rendering.engine.utils.toVector2i import solve.scene.model.Landmark -import java.awt.Color -import java.awt.MouseInfo object MouseInputHandler { private const val LineHandledDistanceMultiplier = 4f @@ -62,17 +59,4 @@ object MouseInputHandler { return minKeypointDistanceIndex } - - fun getClickedPixelColor(): Color { - val pointerLocation = MouseInfo.getPointerInfo().location - val robot = Robot() - - val javaFXColor = robot.getPixelColor(pointerLocation.x.toDouble(), pointerLocation.y.toDouble()) - - return Color( - (javaFXColor.red * ColorSegmentMaxValue).toInt(), - (javaFXColor.green * ColorSegmentMaxValue).toInt(), - (javaFXColor.blue * ColorSegmentMaxValue).toInt() - ) - } } diff --git a/src/test/kotlin/solve/rendering/utils/RenderingTestsOpenGLUtils.kt b/src/test/kotlin/solve/rendering/utils/RenderingTestsOpenGLUtils.kt new file mode 100644 index 00000000..916c664a --- /dev/null +++ b/src/test/kotlin/solve/rendering/utils/RenderingTestsOpenGLUtils.kt @@ -0,0 +1,22 @@ +package solve.rendering.utils + +import com.huskerdev.openglfx.canvas.GLCanvas +import com.huskerdev.openglfx.canvas.GLCanvasAnimator +import com.huskerdev.openglfx.lwjgl.LWJGLExecutor +import org.lwjgl.opengl.GL.createCapabilities + +internal fun runInOpenGLContext(action: () -> Unit) { + val openGLCanvas = GLCanvas(LWJGLExecutor.LWJGL_MODULE) + openGLCanvas.animator = GLCanvasAnimator(60.0) + openGLCanvas.addOnInitEvent { + createCapabilities() + } + var isActionRan = false + openGLCanvas.addOnRenderEvent { + if (isActionRan) { + return@addOnRenderEvent + } + + action() + } +} diff --git a/src/test/kotlin/solve/unit/rendering/engine/core/batch/RenderBatchTests.kt b/src/test/kotlin/solve/unit/rendering/engine/core/batch/RenderBatchTests.kt new file mode 100644 index 00000000..0f021801 --- /dev/null +++ b/src/test/kotlin/solve/unit/rendering/engine/core/batch/RenderBatchTests.kt @@ -0,0 +1,36 @@ +package solve.unit.rendering.engine.core.batch + +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.testfx.framework.junit5.ApplicationExtension +import solve.constants.IconsCatalogueApplyPath +import solve.interactive.InteractiveTestClass +import solve.rendering.engine.core.batch.PrimitiveType +import solve.rendering.engine.core.batch.RenderBatch +import solve.rendering.engine.core.texture.Texture2D +import solve.rendering.utils.runInOpenGLContext +import solve.utils.getResourceAbsolutePath + +@ExtendWith(ApplicationExtension::class) +internal class RenderBatchTests : InteractiveTestClass() { + @Test + fun `Fully fills a render batch with textures`() { + runInOpenGLContext { + val renderBatch = RenderBatch(1000, 0, PrimitiveType.Quad, emptyList()) + assertEquals(false, renderBatch.isTexturesFull) + repeat(RenderBatch.MaxTexturesNumber - 1) { + renderBatch.addTexture(createTestTexture()) + assertEquals(false, renderBatch.isTexturesFull) + } + renderBatch.addTexture(createTestTexture()) + assertEquals(true, renderBatch.isTexturesFull) + } + } + + companion object { + fun createTestTexture(): Texture2D { + return Texture2D(getResourceAbsolutePath(IconsCatalogueApplyPath).toString()) + } + } +} diff --git a/src/test/kotlin/solve/unit/rendering/engine/core/input/MouseInputHandlerTests.kt b/src/test/kotlin/solve/unit/rendering/engine/core/input/MouseInputHandlerTests.kt new file mode 100644 index 00000000..2e37f1d5 --- /dev/null +++ b/src/test/kotlin/solve/unit/rendering/engine/core/input/MouseInputHandlerTests.kt @@ -0,0 +1,104 @@ +package solve.unit.rendering.engine.core.input + +import junit.framework.TestCase.assertEquals +import org.joml.Vector2i +import org.junit.jupiter.api.Test +import solve.rendering.engine.core.input.MouseInputHandler.indexOfClickedLineLandmark +import solve.rendering.engine.core.input.MouseInputHandler.indexOfClickedPointLandmark +import solve.scene.model.ColorManager +import solve.scene.model.Landmark +import solve.scene.model.LayerSettings +import solve.scene.model.LayerState +import solve.scene.model.Point + +class MouseInputHandlerTests { + @Test + fun `Getting the index of the clicked line landmark (1st test)`() { + val clickedLineIndex = indexOfClickedLineLandmark(testLineLandmarks, Vector2i(10, 3), 1f) + assertEquals(0, clickedLineIndex) + } + + @Test + fun `Getting the index of the clicked line landmark (2nd test)`() { + val clickedLineIndex = indexOfClickedLineLandmark(testLineLandmarks, Vector2i(23, 9), 1f) + assertEquals(5, clickedLineIndex) + } + + @Test + fun `Getting the index of the clicked line landmark (3rd test)`() { + val clickedLineIndex = indexOfClickedLineLandmark(testLineLandmarks, Vector2i(14, 19), 1f) + assertEquals(4, clickedLineIndex) + } + + @Test + fun `Getting the index of the clicked line landmark (4th test)`() { + val clickedLineIndex = indexOfClickedLineLandmark(testLineLandmarks, Vector2i(33, 16), 1f) + assertEquals(6, clickedLineIndex) + } + + @Test + fun `Trying to get the index of the non-existing line landmark`() { + val clickedLineIndex = indexOfClickedLineLandmark(testLineLandmarks, Vector2i(25, 26), 1f) + assertEquals(-1, clickedLineIndex) + } + + @Test + fun `Getting the index of the clicked point landmark (1st test)`() { + val clickedPointIndex = indexOfClickedPointLandmark(testPointLandmarks, Vector2i(8, 13), 1f) + assertEquals(5, clickedPointIndex) + } + + @Test + fun `Getting the index of the clicked point landmark (2nd test)`() { + val clickedPointIndex = indexOfClickedPointLandmark(testPointLandmarks, Vector2i(21, 16), 1f) + assertEquals(8, clickedPointIndex) + } + + @Test + fun `Getting the index of the clicked point landmark (3rd test)`() { + val clickedPointIndex = indexOfClickedPointLandmark(testPointLandmarks, Vector2i(26, 19), 1f) + assertEquals(11, clickedPointIndex) + } + + companion object { + val testLinesLayerSettings = LayerSettings.LineLayerSettings( + "test_lines_layer", + "", + ColorManager() + ) + val testLinesLayerState = LayerState("test_lines_layer_state") + val testLineLandmarks = listOf( + Landmark.Line(0L, testLinesLayerSettings, testLinesLayerState, Point(4, 2), Point(31, 9)), + Landmark.Line(1L, testLinesLayerSettings, testLinesLayerState, Point(11, 3), Point(9, 16)), + Landmark.Line(2L, testLinesLayerSettings, testLinesLayerState, Point(5, 30), Point(31, 30)), + Landmark.Line(3L, testLinesLayerSettings, testLinesLayerState, Point(23, 15), Point(28, 18)), + Landmark.Line(4L, testLinesLayerSettings, testLinesLayerState, Point(8, 10), Point(19, 26)), + Landmark.Line(5L, testLinesLayerSettings, testLinesLayerState, Point(3, 17), Point(33, 5)), + Landmark.Line(6L, testLinesLayerSettings, testLinesLayerState, Point(33, 16), Point(30, 24)) + ) + + val testPointsLayerSettings = LayerSettings.PointLayerSettings( + "test_points_layer", + "", + ColorManager() + ) + val testPointsLayerState = LayerState("test_points_layer_state") + val testPointLandmarks = listOf( + Landmark.Keypoint(0L, testPointsLayerSettings, testPointsLayerState, Point(6, 3)), + Landmark.Keypoint(1L, testPointsLayerSettings, testPointsLayerState, Point(18, 5)), + Landmark.Keypoint(2L, testPointsLayerSettings, testPointsLayerState, Point(32, 4)), + Landmark.Keypoint(3L, testPointsLayerSettings, testPointsLayerState, Point(26, 10)), + Landmark.Keypoint(4L, testPointsLayerSettings, testPointsLayerState, Point(32, 10)), + Landmark.Keypoint(5L, testPointsLayerSettings, testPointsLayerState, Point(8, 13)), + Landmark.Keypoint(6L, testPointsLayerSettings, testPointsLayerState, Point(17, 14)), + Landmark.Keypoint(7L, testPointsLayerSettings, testPointsLayerState, Point(8, 15)), + Landmark.Keypoint(8L, testPointsLayerSettings, testPointsLayerState, Point(20, 16)), + Landmark.Keypoint(9L, testPointsLayerSettings, testPointsLayerState, Point(28, 19)), + Landmark.Keypoint(10L, testPointsLayerSettings, testPointsLayerState, Point(6, 20)), + Landmark.Keypoint(11L, testPointsLayerSettings, testPointsLayerState, Point(26, 20)), + Landmark.Keypoint(12L, testPointsLayerSettings, testPointsLayerState, Point(13, 26)), + Landmark.Keypoint(13L, testPointsLayerSettings, testPointsLayerState, Point(28, 19)), + Landmark.Keypoint(14L, testPointsLayerSettings, testPointsLayerState, Point(29, 31)) + ) + } +} From 606e607ebbfc34aceee1175cb1874c79de673032 Mon Sep 17 00:00:00 2001 From: Stanislav Mishchenko Date: Sat, 8 Jun 2024 18:12:16 +0300 Subject: [PATCH 02/12] add association manager tests --- .../utils/RenderingTestsOpenGLUtils.kt | 22 ---- .../engine/core/batch/RenderBatchTests.kt | 36 ----- .../association/AssociationManagerTests.kt | 123 ++++++++++++++++++ 3 files changed, 123 insertions(+), 58 deletions(-) delete mode 100644 src/test/kotlin/solve/rendering/utils/RenderingTestsOpenGLUtils.kt delete mode 100644 src/test/kotlin/solve/unit/rendering/engine/core/batch/RenderBatchTests.kt create mode 100644 src/test/kotlin/solve/unit/scene/view/association/AssociationManagerTests.kt diff --git a/src/test/kotlin/solve/rendering/utils/RenderingTestsOpenGLUtils.kt b/src/test/kotlin/solve/rendering/utils/RenderingTestsOpenGLUtils.kt deleted file mode 100644 index 916c664a..00000000 --- a/src/test/kotlin/solve/rendering/utils/RenderingTestsOpenGLUtils.kt +++ /dev/null @@ -1,22 +0,0 @@ -package solve.rendering.utils - -import com.huskerdev.openglfx.canvas.GLCanvas -import com.huskerdev.openglfx.canvas.GLCanvasAnimator -import com.huskerdev.openglfx.lwjgl.LWJGLExecutor -import org.lwjgl.opengl.GL.createCapabilities - -internal fun runInOpenGLContext(action: () -> Unit) { - val openGLCanvas = GLCanvas(LWJGLExecutor.LWJGL_MODULE) - openGLCanvas.animator = GLCanvasAnimator(60.0) - openGLCanvas.addOnInitEvent { - createCapabilities() - } - var isActionRan = false - openGLCanvas.addOnRenderEvent { - if (isActionRan) { - return@addOnRenderEvent - } - - action() - } -} diff --git a/src/test/kotlin/solve/unit/rendering/engine/core/batch/RenderBatchTests.kt b/src/test/kotlin/solve/unit/rendering/engine/core/batch/RenderBatchTests.kt deleted file mode 100644 index 0f021801..00000000 --- a/src/test/kotlin/solve/unit/rendering/engine/core/batch/RenderBatchTests.kt +++ /dev/null @@ -1,36 +0,0 @@ -package solve.unit.rendering.engine.core.batch - -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith -import org.testfx.framework.junit5.ApplicationExtension -import solve.constants.IconsCatalogueApplyPath -import solve.interactive.InteractiveTestClass -import solve.rendering.engine.core.batch.PrimitiveType -import solve.rendering.engine.core.batch.RenderBatch -import solve.rendering.engine.core.texture.Texture2D -import solve.rendering.utils.runInOpenGLContext -import solve.utils.getResourceAbsolutePath - -@ExtendWith(ApplicationExtension::class) -internal class RenderBatchTests : InteractiveTestClass() { - @Test - fun `Fully fills a render batch with textures`() { - runInOpenGLContext { - val renderBatch = RenderBatch(1000, 0, PrimitiveType.Quad, emptyList()) - assertEquals(false, renderBatch.isTexturesFull) - repeat(RenderBatch.MaxTexturesNumber - 1) { - renderBatch.addTexture(createTestTexture()) - assertEquals(false, renderBatch.isTexturesFull) - } - renderBatch.addTexture(createTestTexture()) - assertEquals(true, renderBatch.isTexturesFull) - } - } - - companion object { - fun createTestTexture(): Texture2D { - return Texture2D(getResourceAbsolutePath(IconsCatalogueApplyPath).toString()) - } - } -} diff --git a/src/test/kotlin/solve/unit/scene/view/association/AssociationManagerTests.kt b/src/test/kotlin/solve/unit/scene/view/association/AssociationManagerTests.kt new file mode 100644 index 00000000..b029477f --- /dev/null +++ b/src/test/kotlin/solve/unit/scene/view/association/AssociationManagerTests.kt @@ -0,0 +1,123 @@ +package solve.unit.scene.view.association + +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test +import solve.scene.model.ColorManager +import solve.scene.model.Landmark +import solve.scene.model.Layer +import solve.scene.model.LayerSettings +import solve.scene.model.VisualizationFrame +import solve.scene.view.association.AssociationManager +import kotlin.io.path.Path + +internal class AssociationManagerTests { + @Test + fun `Associates two frames`() { + val associationManager = AssociationManager() + associationManager.setFramesSelection(testFrames) + associationManager.associate(0, 1) + assert(associationManager.associationConnections.any { + it.firstFrameIndex == 0 && it.secondFrameIndex == 1 + }) + } + + @Test + fun `Associate three frames transitively`() { + val associationManager = AssociationManager() + associationManager.setFramesSelection(testFrames) + associationManager.associate(0, 1) + associationManager.associate(1, 2) + associationManager.associate(2, 0) + assert(associationManager.associationConnections.any { + it.firstFrameIndex == 0 && it.secondFrameIndex == 1 + } && associationManager.associationConnections.any { + it.firstFrameIndex == 1 && it.secondFrameIndex == 2 + } && associationManager.associationConnections.any { + it.firstFrameIndex == 2 && it.secondFrameIndex == 0 + }) + } + + @Test + fun `Associates an existing frame with a non-existing frame`() { + val associationManager = AssociationManager() + associationManager.setFramesSelection(testFrames) + associationManager.associate(1, 10) + assert(associationManager.associationConnections.isEmpty()) + } + + @Test + fun `Associates frames a few times`() { + val associationManager = AssociationManager() + associationManager.setFramesSelection(testFrames) + associationManager.associate(0, 1) + associationManager.associate(0, 1) + assertEquals(1, associationManager.associationConnections.count()) + associationManager.associate(1, 0) + assertEquals(1, associationManager.associationConnections.count()) + } + + @Test + fun `Associates frames and clears association for the first frame`() { + val associationManager = AssociationManager() + associationManager.setFramesSelection(testFrames) + associationManager.associate(0, 1) + assertEquals(1, associationManager.associationConnections.count()) + associationManager.clearAssociation(0) + assertEquals(0, associationManager.associationConnections.count()) + } + + @Test + fun `Associates frames and clears association for the second frame`() { + val associationManager = AssociationManager() + associationManager.setFramesSelection(testFrames) + associationManager.associate(0, 1) + assertEquals(1, associationManager.associationConnections.count()) + associationManager.clearAssociation(1) + assertEquals(0, associationManager.associationConnections.count()) + } + + @Test + fun `Associates many-to-one frames and clears associations`() { + val associationManager = AssociationManager() + associationManager.setFramesSelection(testFrames) + associationManager.associate(1, 0) + associationManager.associate(2, 0) + associationManager.associate(3, 0) + associationManager.associate(4, 0) + assertEquals(4, associationManager.associationConnections.count()) + associationManager.clearAssociation(0) + assertEquals(0, associationManager.associationConnections.count()) + } + + companion object { + val testPointLayers = listOf( + Layer.PointLayer( + "0", + LayerSettings.PointLayerSettings("0", "0", ColorManager()) + ) { emptyList() }, + Layer.PointLayer( + "1", + LayerSettings.PointLayerSettings("1", "1", ColorManager()) + ) { emptyList() }, + Layer.PointLayer( + "2", + LayerSettings.PointLayerSettings("2", "2", ColorManager()) + ) { emptyList() }, + Layer.PointLayer( + "3", + LayerSettings.PointLayerSettings("3", "3", ColorManager()) + ) { emptyList() }, + Layer.PointLayer( + "4", + LayerSettings.PointLayerSettings("4", "4", ColorManager()) + ) { emptyList() } + ) + val testFrames = listOf( + VisualizationFrame(0L, Path("0.png"), listOf(testPointLayers[0])), + VisualizationFrame(1L, Path("1.png"), listOf(testPointLayers[1])), + VisualizationFrame(2L, Path("1.png"), listOf(testPointLayers[2])), + VisualizationFrame(3L, Path("1.png"), listOf(testPointLayers[3])), + VisualizationFrame(4L, Path("1.png"), listOf(testPointLayers[4])) + ) + } +} \ No newline at end of file From 4beec499ab27b21c6a18d62e619aeccac8b4ab2e Mon Sep 17 00:00:00 2001 From: Stanislav Mishchenko Date: Sat, 8 Jun 2024 18:58:17 +0300 Subject: [PATCH 03/12] add calculation utils tests --- .../rendering/engine/structures/ColorTests.kt | 7 ++ .../engine/utils/CalculationUtilsTests.kt | 65 +++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 src/test/kotlin/solve/unit/rendering/engine/utils/CalculationUtilsTests.kt diff --git a/src/test/kotlin/solve/unit/rendering/engine/structures/ColorTests.kt b/src/test/kotlin/solve/unit/rendering/engine/structures/ColorTests.kt index bbd63b41..f382421d 100644 --- a/src/test/kotlin/solve/unit/rendering/engine/structures/ColorTests.kt +++ b/src/test/kotlin/solve/unit/rendering/engine/structures/ColorTests.kt @@ -19,6 +19,13 @@ internal class ColorTests { assertEquals(testColor, color) } + @Test + fun `Compares same colors`() { + val firstColor = Color(0.5f, 1f, 0.25f, 1f) + val secondColor = Color(0.5f, 1f, 0.25f, 1f) + assert(firstColor == secondColor) + } + companion object { val testColor = Color(0.5f, 0.25f, 0.75f, 0.9f) } diff --git a/src/test/kotlin/solve/unit/rendering/engine/utils/CalculationUtilsTests.kt b/src/test/kotlin/solve/unit/rendering/engine/utils/CalculationUtilsTests.kt new file mode 100644 index 00000000..0f2cd90e --- /dev/null +++ b/src/test/kotlin/solve/unit/rendering/engine/utils/CalculationUtilsTests.kt @@ -0,0 +1,65 @@ +package solve.unit.rendering.engine.utils + +import org.joml.Vector2f +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test +import solve.rendering.engine.utils.pointToSegmentDistance +import solve.rendering.engine.utils.pointToSegmentDistanceSquared +import kotlin.math.sqrt + +internal class CalculationUtilsTests { + @Test + fun `Calculates the square distance from the point to the line segment (1st test)`() { + val pointPosition = Vector2f(6f, 1f) + val segmentStartPosition = Vector2f(1f, 3f) + val segmentEndPosition = Vector2f(1f, 5f) + assertEquals( + 29f, + pointToSegmentDistanceSquared(pointPosition, segmentStartPosition, segmentEndPosition) + ) + } + + @Test + fun `Calculates the square distance from the point to the line segment (2nd test)`() { + val pointPosition = Vector2f(4f, 0f) + val segmentStartPosition = Vector2f(5f, 1f) + val segmentEndPosition = Vector2f(8f, 4f) + assertEquals( + 2f, + pointToSegmentDistanceSquared(pointPosition, segmentStartPosition, segmentEndPosition) + ) + } + + @Test + fun `Calculates the square distance from the point to the line segment (3rd test)`() { + val pointPosition = Vector2f(2f, -2f) + val segmentStartPosition = Vector2f(-1f, -3f) + val segmentEndPosition = Vector2f(5f, -1f) + assertEquals( + 0f, + pointToSegmentDistanceSquared(pointPosition, segmentStartPosition, segmentEndPosition) + ) + } + + @Test + fun `Calculates the square distance from the point to the line segment (4th test)`() { + val pointPosition = Vector2f(2f, 6f) + val segmentStartPosition = Vector2f(-2f, 4f) + val segmentEndPosition = Vector2f(4f, 2f) + assertEquals( + 10f, + pointToSegmentDistanceSquared(pointPosition, segmentStartPosition, segmentEndPosition) + ) + } + + @Test + fun `Calculates the distance from the point to the line segment`() { + val pointPosition = Vector2f(2f, -5f) + val segmentStartPosition = Vector2f(-2f, -2f) + val segmentEndPosition = Vector2f(-2f, -7f) + assertEquals( + 4f, + pointToSegmentDistance(pointPosition, segmentStartPosition, segmentEndPosition) + ) + } +} \ No newline at end of file From 088c451dd1e5c21e25d888a00e958af3b25093a7 Mon Sep 17 00:00:00 2001 From: Stanislav Mishchenko Date: Sat, 8 Jun 2024 19:13:22 +0300 Subject: [PATCH 04/12] codestyle --- .../engine/utils/CalculationUtilsTests.kt | 3 +-- .../association/AssociationManagerTests.kt | 27 ++++++++++--------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/test/kotlin/solve/unit/rendering/engine/utils/CalculationUtilsTests.kt b/src/test/kotlin/solve/unit/rendering/engine/utils/CalculationUtilsTests.kt index 0f2cd90e..88f498be 100644 --- a/src/test/kotlin/solve/unit/rendering/engine/utils/CalculationUtilsTests.kt +++ b/src/test/kotlin/solve/unit/rendering/engine/utils/CalculationUtilsTests.kt @@ -5,7 +5,6 @@ import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test import solve.rendering.engine.utils.pointToSegmentDistance import solve.rendering.engine.utils.pointToSegmentDistanceSquared -import kotlin.math.sqrt internal class CalculationUtilsTests { @Test @@ -62,4 +61,4 @@ internal class CalculationUtilsTests { pointToSegmentDistance(pointPosition, segmentStartPosition, segmentEndPosition) ) } -} \ No newline at end of file +} diff --git a/src/test/kotlin/solve/unit/scene/view/association/AssociationManagerTests.kt b/src/test/kotlin/solve/unit/scene/view/association/AssociationManagerTests.kt index b029477f..247d539c 100644 --- a/src/test/kotlin/solve/unit/scene/view/association/AssociationManagerTests.kt +++ b/src/test/kotlin/solve/unit/scene/view/association/AssociationManagerTests.kt @@ -3,7 +3,6 @@ package solve.unit.scene.view.association import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test import solve.scene.model.ColorManager -import solve.scene.model.Landmark import solve.scene.model.Layer import solve.scene.model.LayerSettings import solve.scene.model.VisualizationFrame @@ -16,9 +15,11 @@ internal class AssociationManagerTests { val associationManager = AssociationManager() associationManager.setFramesSelection(testFrames) associationManager.associate(0, 1) - assert(associationManager.associationConnections.any { - it.firstFrameIndex == 0 && it.secondFrameIndex == 1 - }) + assert( + associationManager.associationConnections.any { + it.firstFrameIndex == 0 && it.secondFrameIndex == 1 + } + ) } @Test @@ -28,13 +29,15 @@ internal class AssociationManagerTests { associationManager.associate(0, 1) associationManager.associate(1, 2) associationManager.associate(2, 0) - assert(associationManager.associationConnections.any { - it.firstFrameIndex == 0 && it.secondFrameIndex == 1 - } && associationManager.associationConnections.any { - it.firstFrameIndex == 1 && it.secondFrameIndex == 2 - } && associationManager.associationConnections.any { - it.firstFrameIndex == 2 && it.secondFrameIndex == 0 - }) + assert( + associationManager.associationConnections.any { + it.firstFrameIndex == 0 && it.secondFrameIndex == 1 + } && associationManager.associationConnections.any { + it.firstFrameIndex == 1 && it.secondFrameIndex == 2 + } && associationManager.associationConnections.any { + it.firstFrameIndex == 2 && it.secondFrameIndex == 0 + } + ) } @Test @@ -120,4 +123,4 @@ internal class AssociationManagerTests { VisualizationFrame(4L, Path("1.png"), listOf(testPointLayers[4])) ) } -} \ No newline at end of file +} From f629fa55eb2ef15f8fe8aa1ec60e6d2e841c77e9 Mon Sep 17 00:00:00 2001 From: Stanislav Mishchenko Date: Sat, 8 Jun 2024 21:58:34 +0300 Subject: [PATCH 05/12] add comments --- .../solve/rendering/canvas/OpenGLCanvas.kt | 3 ++ .../solve/rendering/canvas/SceneCanvas.kt | 4 +++ .../solve/rendering/engine/camera/Camera.kt | 4 +++ .../rendering/engine/components/Sprite.kt | 32 ------------------- .../engine/core/batch/PrimitiveType.kt | 3 ++ .../engine/core/batch/RenderBatch.kt | 13 ++++++++ .../engine/core/input/MouseInputHandler.kt | 3 ++ .../engine/core/renderers/FramesRenderer.kt | 8 +++++ .../core/renderers/LandmarkLayerRenderer.kt | 4 +++ .../renderers/PointAssociationsRenderer.kt | 3 ++ .../engine/core/renderers/Renderer.kt | 4 +++ .../engine/core/texture/ArrayTexture.kt | 3 ++ .../rendering/engine/core/texture/Texture.kt | 4 +++ .../engine/core/texture/Texture2D.kt | 3 ++ .../engine/core/texture/Texture2DData.kt | 3 ++ .../core/texture/TextureChannelsType.kt | 3 ++ .../solve/rendering/engine/scene/Scene.kt | 3 ++ .../solve/rendering/engine/scene/Transform.kt | 10 ------ .../rendering/engine/shader/ShaderProgram.kt | 3 ++ src/main/kotlin/solve/scene/model/Scene.kt | 1 + 20 files changed, 72 insertions(+), 42 deletions(-) delete mode 100644 src/main/kotlin/solve/rendering/engine/components/Sprite.kt delete mode 100644 src/main/kotlin/solve/rendering/engine/scene/Transform.kt diff --git a/src/main/kotlin/solve/rendering/canvas/OpenGLCanvas.kt b/src/main/kotlin/solve/rendering/canvas/OpenGLCanvas.kt index 5f584749..22ff0e8c 100644 --- a/src/main/kotlin/solve/rendering/canvas/OpenGLCanvas.kt +++ b/src/main/kotlin/solve/rendering/canvas/OpenGLCanvas.kt @@ -30,6 +30,9 @@ import solve.rendering.engine.utils.plus import solve.rendering.engine.utils.toFloatVector import com.huskerdev.openglfx.canvas.GLCanvas as OpenGLFXCanvas +/** + * Encapsulates initialization logic of the OpenGLFX library component. + */ abstract class OpenGLCanvas { val canvas: OpenGLFXCanvas = OpenGLFXCanvas(LWJGLExecutor.LWJGL_MODULE, flipY = true) diff --git a/src/main/kotlin/solve/rendering/canvas/SceneCanvas.kt b/src/main/kotlin/solve/rendering/canvas/SceneCanvas.kt index 07f7c82a..1b0ba203 100644 --- a/src/main/kotlin/solve/rendering/canvas/SceneCanvas.kt +++ b/src/main/kotlin/solve/rendering/canvas/SceneCanvas.kt @@ -41,6 +41,10 @@ import solve.utils.structures.DoublePoint import tornadofx.* import solve.rendering.engine.scene.Scene as EngineScene +/** + * Aggregates logic related to scene control. + * Provides interface for managing frames and changing visualization settings. + */ class SceneCanvas : OpenGLCanvas() { private var sceneController: SceneController? = null private var engineScene: EngineScene? = null diff --git a/src/main/kotlin/solve/rendering/engine/camera/Camera.kt b/src/main/kotlin/solve/rendering/engine/camera/Camera.kt index fe7d109c..46148d99 100644 --- a/src/main/kotlin/solve/rendering/engine/camera/Camera.kt +++ b/src/main/kotlin/solve/rendering/engine/camera/Camera.kt @@ -7,6 +7,10 @@ import solve.rendering.engine.utils.plus import solve.rendering.engine.utils.times import solve.rendering.engine.utils.toFloatVector +/** + * Used to move around the scene and scale it. + * Provides methods for calculating projection matrices that are used in shaders. + */ class Camera(var position: Vector2f = Vector2f(), zoom: Float = 1f) { var zoom: Float = zoom private set(value) { diff --git a/src/main/kotlin/solve/rendering/engine/components/Sprite.kt b/src/main/kotlin/solve/rendering/engine/components/Sprite.kt deleted file mode 100644 index c2dc9829..00000000 --- a/src/main/kotlin/solve/rendering/engine/components/Sprite.kt +++ /dev/null @@ -1,32 +0,0 @@ -package solve.rendering.engine.components - -import org.joml.Vector2f -import solve.rendering.engine.core.texture.Texture2D - -class Sprite(val texture: Texture2D, uvCoordinates: List = defaultUVCoordinates) { - val uvCoordinates: List - - val width: Int - get() = texture.width - val height: Int - get() = texture.height - - init { - if (uvCoordinates.count() != UVCoordinatesNumber) { - println("The number of the uv coordinates is incorrect!") - this.uvCoordinates = defaultUVCoordinates - } else { - this.uvCoordinates = uvCoordinates - } - } - - companion object { - private const val UVCoordinatesNumber = 4 - private val defaultUVCoordinates = listOf( - Vector2f(0f, 0f), - Vector2f(0f, 1f), - Vector2f(1f, 1f), - Vector2f(1f, 0f) - ) - } -} diff --git a/src/main/kotlin/solve/rendering/engine/core/batch/PrimitiveType.kt b/src/main/kotlin/solve/rendering/engine/core/batch/PrimitiveType.kt index 4d3c3e7c..2864c056 100644 --- a/src/main/kotlin/solve/rendering/engine/core/batch/PrimitiveType.kt +++ b/src/main/kotlin/solve/rendering/engine/core/batch/PrimitiveType.kt @@ -4,6 +4,9 @@ import org.lwjgl.opengl.GL11.GL_LINES import org.lwjgl.opengl.GL11.GL_POINTS import org.lwjgl.opengl.GL11.GL_TRIANGLES +/** + * Used to draw with EBO in OpenGL. + */ enum class PrimitiveType( val verticesNumber: Int, val openGLPrimitive: Int, diff --git a/src/main/kotlin/solve/rendering/engine/core/batch/RenderBatch.kt b/src/main/kotlin/solve/rendering/engine/core/batch/RenderBatch.kt index fd143ee7..b28949e1 100644 --- a/src/main/kotlin/solve/rendering/engine/core/batch/RenderBatch.kt +++ b/src/main/kotlin/solve/rendering/engine/core/batch/RenderBatch.kt @@ -22,6 +22,13 @@ import solve.rendering.engine.core.texture.Texture import solve.rendering.engine.shader.ShaderAttributeType import solve.rendering.engine.utils.toList +/** + * Used to draw similar objects in a single draw call. + * @param maxBatchSize maximum allowed number of the objects in the batch. + * @param zIndex depth index of the batch. + * @param primitiveType used to determine the type of the drawing primitives in EBO. + * @param attributes used to specify the attributes of each vertex. + */ open class RenderBatch( private val maxBatchSize: Int, val zIndex: Int, @@ -58,25 +65,30 @@ open class RenderBatch( textures.clear() } + // Compares batches according to their depth. override fun compareTo(other: RenderBatch): Int = batchComparator.compare(this, other) + // Binds vertices data, attributes data and textures before the rendering. fun bind() { glBindVertexArray(vaoID) attributes.forEachIndexed { index, _ -> glEnableVertexAttribArray(index) } textures.forEachIndexed { index, texture -> texture.bindToSlot(index + 1) } } + // Unbinds vertices data, attributes data and textures after the rendering. fun unbind() { attributes.forEachIndexed { index, _ -> glDisableVertexAttribArray(index) } textures.forEach { texture -> texture.unbind() } glBindVertexArray(0) } + // Cleans the vertices data buffer. fun rebuffer() { glBindBuffer(GL_ARRAY_BUFFER, vboID) glBufferSubData(GL_ARRAY_BUFFER, 0, verticesDataBuffer) } + // Deletes the batch buffers. fun deleteBuffers() { glDeleteBuffers(vboID) glDeleteBuffers(eboID) @@ -150,6 +162,7 @@ open class RenderBatch( } } + // Used to generate vertex indices to specify an order of their drawing. private fun generateElementsIndices(): IntArray { val elementsBuffer = IntArray(maxBatchSize * primitiveType.drawingOrderElementsNumber) for (i in 0 until maxBatchSize) { diff --git a/src/main/kotlin/solve/rendering/engine/core/input/MouseInputHandler.kt b/src/main/kotlin/solve/rendering/engine/core/input/MouseInputHandler.kt index 55067a6f..f296ee7e 100644 --- a/src/main/kotlin/solve/rendering/engine/core/input/MouseInputHandler.kt +++ b/src/main/kotlin/solve/rendering/engine/core/input/MouseInputHandler.kt @@ -7,6 +7,9 @@ import solve.rendering.engine.utils.toFloatVector import solve.rendering.engine.utils.toVector2i import solve.scene.model.Landmark +/** + * Used to handle mouse click on landmarks. + */ object MouseInputHandler { private const val LineHandledDistanceMultiplier = 4f private const val PointHandledDistanceMultiplier = 1.5f diff --git a/src/main/kotlin/solve/rendering/engine/core/renderers/FramesRenderer.kt b/src/main/kotlin/solve/rendering/engine/core/renderers/FramesRenderer.kt index a6427379..90ae555f 100644 --- a/src/main/kotlin/solve/rendering/engine/core/renderers/FramesRenderer.kt +++ b/src/main/kotlin/solve/rendering/engine/core/renderers/FramesRenderer.kt @@ -33,6 +33,10 @@ import kotlin.math.abs import kotlin.math.max import kotlin.math.min +/** + * Used to draw the frames. + * Encapsulates logic to provide virtualization at the data layer.* + */ class FramesRenderer( window: Window ) : Renderer(window) { @@ -165,6 +169,7 @@ class FramesRenderer( } } + // Updates the buffers with actual frames textures. private fun updateBuffersTextures() { val cameraGridCellPosition = getScreenTopLeftGridCellPosition() if (cameraGridCellPosition != cameraLastGridCellPosition) { @@ -173,6 +178,7 @@ class FramesRenderer( cameraLastGridCellPosition = cameraGridCellPosition } + // Defines textures that became visible in the last draw call and uploads them to the buffers. private fun loadNewTexturesToBuffers(cameraGridCellPosition: Vector2i) { val cameraPosition = Vector2i(cameraGridCellPosition) cameraPosition.x.coerceIn(0 until gridWidth) @@ -226,6 +232,7 @@ class FramesRenderer( return framesRect } + // Uploads the rect of frames (that was taken from frames selection) to the buffers. private fun loadRectFramesToBuffers(framesRect: IntRect) { val rectFrames = getFramesAtRect(framesRect) @@ -250,6 +257,7 @@ class FramesRenderer( } } + // Returns the integer position of the frame cell located in the top-left corner of the screen. private fun getScreenTopLeftGridCellPosition(): Vector2i { val cameraGridCellPosition = getCameraCellPosition() return (cameraGridCellPosition - Vector2f(buffersSize) / 2f).toIntVector() diff --git a/src/main/kotlin/solve/rendering/engine/core/renderers/LandmarkLayerRenderer.kt b/src/main/kotlin/solve/rendering/engine/core/renderers/LandmarkLayerRenderer.kt index 218f973c..7e3390f0 100644 --- a/src/main/kotlin/solve/rendering/engine/core/renderers/LandmarkLayerRenderer.kt +++ b/src/main/kotlin/solve/rendering/engine/core/renderers/LandmarkLayerRenderer.kt @@ -8,6 +8,10 @@ import solve.scene.model.Landmark import solve.scene.model.Layer import solve.scene.model.Scene +/** + * The base class for all landmarks renderers. + * Encapsulates logic to provide virtualization at the data layer. + */ abstract class LandmarkLayerRenderer( window: Window, protected val getScene: () -> Scene? diff --git a/src/main/kotlin/solve/rendering/engine/core/renderers/PointAssociationsRenderer.kt b/src/main/kotlin/solve/rendering/engine/core/renderers/PointAssociationsRenderer.kt index 5c18a684..0cb545f4 100644 --- a/src/main/kotlin/solve/rendering/engine/core/renderers/PointAssociationsRenderer.kt +++ b/src/main/kotlin/solve/rendering/engine/core/renderers/PointAssociationsRenderer.kt @@ -18,6 +18,9 @@ import solve.rendering.engine.utils.toVector2i import solve.scene.view.association.AssociationManager import kotlin.math.min +/** + * Used to draw points associations. + */ class PointAssociationsRenderer( window: Window, private val associationManager: AssociationManager diff --git a/src/main/kotlin/solve/rendering/engine/core/renderers/Renderer.kt b/src/main/kotlin/solve/rendering/engine/core/renderers/Renderer.kt index fa0c9af2..998127cd 100644 --- a/src/main/kotlin/solve/rendering/engine/core/renderers/Renderer.kt +++ b/src/main/kotlin/solve/rendering/engine/core/renderers/Renderer.kt @@ -14,6 +14,10 @@ import solve.scene.model.VisualizationFrame import solve.utils.ceilToInt import kotlin.math.min +/** + * The base class for all renderers. + * Provides methods for managing shaders and controlling the rendering process + */ abstract class Renderer(protected val window: Window) : Comparable { protected abstract val maxBatchSize: Int diff --git a/src/main/kotlin/solve/rendering/engine/core/texture/ArrayTexture.kt b/src/main/kotlin/solve/rendering/engine/core/texture/ArrayTexture.kt index 7d6bd081..bcead802 100644 --- a/src/main/kotlin/solve/rendering/engine/core/texture/ArrayTexture.kt +++ b/src/main/kotlin/solve/rendering/engine/core/texture/ArrayTexture.kt @@ -11,6 +11,9 @@ import org.lwjgl.opengl.GL30.GL_TEXTURE_2D_ARRAY import org.lwjgl.opengl.GL30.glGenerateMipmap import java.nio.ByteBuffer +/** + * Used to store a large number of textures of the same size. + */ class ArrayTexture( width: Int, height: Int, diff --git a/src/main/kotlin/solve/rendering/engine/core/texture/Texture.kt b/src/main/kotlin/solve/rendering/engine/core/texture/Texture.kt index c0e987f8..7aef6149 100644 --- a/src/main/kotlin/solve/rendering/engine/core/texture/Texture.kt +++ b/src/main/kotlin/solve/rendering/engine/core/texture/Texture.kt @@ -17,6 +17,10 @@ enum class TextureFilterType(val openGLParamValue: Int) { Smoothed(GL_LINEAR) } +/** + * The base class for all textures. + * Provides an interface for creating, binding and deleting. + */ abstract class Texture(private val filterType: TextureFilterType = TextureFilterType.Smoothed) { protected abstract val textureOpenGLType: Int diff --git a/src/main/kotlin/solve/rendering/engine/core/texture/Texture2D.kt b/src/main/kotlin/solve/rendering/engine/core/texture/Texture2D.kt index 66eac86f..5c0254e6 100644 --- a/src/main/kotlin/solve/rendering/engine/core/texture/Texture2D.kt +++ b/src/main/kotlin/solve/rendering/engine/core/texture/Texture2D.kt @@ -11,6 +11,9 @@ import org.lwjgl.stb.STBImage.stbi_image_free import org.lwjgl.stb.STBImage.stbi_load import org.lwjgl.stb.STBImage.stbi_set_flip_vertically_on_load +/** + * Used to store a default 2D texture. + */ class Texture2D( private val filePath: String, filterType: TextureFilterType = TextureFilterType.Smoothed diff --git a/src/main/kotlin/solve/rendering/engine/core/texture/Texture2DData.kt b/src/main/kotlin/solve/rendering/engine/core/texture/Texture2DData.kt index bc6f52e2..f068b243 100644 --- a/src/main/kotlin/solve/rendering/engine/core/texture/Texture2DData.kt +++ b/src/main/kotlin/solve/rendering/engine/core/texture/Texture2DData.kt @@ -2,6 +2,9 @@ package solve.rendering.engine.core.texture import java.nio.ByteBuffer +/** + * Used to store a texture data before it can be loaded to the GPU memory. + */ class Texture2DData( val data: ByteBuffer, val width: Int, diff --git a/src/main/kotlin/solve/rendering/engine/core/texture/TextureChannelsType.kt b/src/main/kotlin/solve/rendering/engine/core/texture/TextureChannelsType.kt index 50e9b16d..aa33cd0c 100644 --- a/src/main/kotlin/solve/rendering/engine/core/texture/TextureChannelsType.kt +++ b/src/main/kotlin/solve/rendering/engine/core/texture/TextureChannelsType.kt @@ -3,6 +3,9 @@ package solve.rendering.engine.core.texture import org.lwjgl.opengl.GL11.GL_RGB import org.lwjgl.opengl.GL11.GL_RGBA +/** + * Used to store a type of color encoding of the texture. + */ enum class TextureChannelsType(val channelsNumber: Int, val openGLType: Int) { RGB(3, GL_RGB), RGBA(4, GL_RGBA); diff --git a/src/main/kotlin/solve/rendering/engine/scene/Scene.kt b/src/main/kotlin/solve/rendering/engine/scene/Scene.kt index 68ef8b7c..5ac96f20 100644 --- a/src/main/kotlin/solve/rendering/engine/scene/Scene.kt +++ b/src/main/kotlin/solve/rendering/engine/scene/Scene.kt @@ -14,6 +14,9 @@ import solve.scene.model.Scene import solve.scene.model.VisualizationFrame import java.util.concurrent.CopyOnWriteArrayList +/** + * Aggregates all renderers of the application scene. + */ class Scene( val framesRenderer: FramesRenderer, val pointAssociationsRenderer: PointAssociationsRenderer, diff --git a/src/main/kotlin/solve/rendering/engine/scene/Transform.kt b/src/main/kotlin/solve/rendering/engine/scene/Transform.kt deleted file mode 100644 index fde69d6c..00000000 --- a/src/main/kotlin/solve/rendering/engine/scene/Transform.kt +++ /dev/null @@ -1,10 +0,0 @@ -package solve.rendering.engine.scene - -import org.joml.Vector2f - -data class Transform( - val position: Vector2f = Vector2f(), - val rotation: Float = 0f, - val scale: Vector2f = Vector2f(1f), - val zIndex: Int = 0 -) diff --git a/src/main/kotlin/solve/rendering/engine/shader/ShaderProgram.kt b/src/main/kotlin/solve/rendering/engine/shader/ShaderProgram.kt index 9e558933..a258da84 100644 --- a/src/main/kotlin/solve/rendering/engine/shader/ShaderProgram.kt +++ b/src/main/kotlin/solve/rendering/engine/shader/ShaderProgram.kt @@ -45,6 +45,9 @@ import org.lwjgl.opengl.GL20.glValidateProgram import solve.rendering.engine.shader.ShaderType.Companion.getShaderTypeID import solve.utils.readResourcesFileText +/** + * Used to create, link and manage shaders. + */ class ShaderProgram { private val shaderProgramID: Int = glCreateProgram() diff --git a/src/main/kotlin/solve/scene/model/Scene.kt b/src/main/kotlin/solve/scene/model/Scene.kt index bc194359..533fd73d 100644 --- a/src/main/kotlin/solve/scene/model/Scene.kt +++ b/src/main/kotlin/solve/scene/model/Scene.kt @@ -9,6 +9,7 @@ import solve.utils.structures.Size as DoubleSize * * @param frames images with related landmarks selected in the catalog {@link CatalogueController}. * @param layerSettings information about layers in the project, used to determine current order of a layer. + * @param layerStates stores current layers states. */ class Scene( val frames: List, From 58f4ef8ac204c528f70e259a326e11613035ac78 Mon Sep 17 00:00:00 2001 From: Stanislav Mishchenko Date: Sat, 8 Jun 2024 22:43:31 +0300 Subject: [PATCH 06/12] add mouse position scale factor --- build.gradle.kts | 4 +++- src/main/kotlin/solve/scene/view/SceneView.kt | 10 ++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index d54249de..0b369b00 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -75,7 +75,9 @@ application { "--add-opens", "javafx.graphics/javafx.scene.image=ALL-UNNAMED", "--add-exports", "javafx.graphics/com.sun.javafx.scene=ALL-UNNAMED", "-Xms2g", - "-Xmx4g" + "-Xmx4g", + "-Dglass.win.uiScale=1.0", + "-Dsun.java2d.uiScale=1.0" ) } diff --git a/src/main/kotlin/solve/scene/view/SceneView.kt b/src/main/kotlin/solve/scene/view/SceneView.kt index 86c6b241..2caa6a14 100644 --- a/src/main/kotlin/solve/scene/view/SceneView.kt +++ b/src/main/kotlin/solve/scene/view/SceneView.kt @@ -3,6 +3,7 @@ package solve.scene.view import javafx.application.Platform import javafx.beans.InvalidationListener import javafx.scene.input.MouseEvent +import javafx.stage.Screen import org.joml.Vector2i import solve.rendering.canvas.SceneCanvas import solve.rendering.engine.core.input.MouseButton @@ -23,6 +24,7 @@ class SceneView : View() { private var mouseScreenPoint = Vector2i() private var wasMouseDragging = false + private var screen = Screen.getPrimary() override val root = canvas.canvas @@ -38,8 +40,12 @@ class SceneView : View() { addBindings() } - private fun extrudeEventMousePosition(event: MouseEvent) = Vector2i(event.x.toInt(), event.y.toInt()) - + private fun extrudeEventMousePosition(event: MouseEvent) : Vector2i { + return Vector2i( + (event.x * screen.outputScaleX).toInt(), + (event.y * screen.outputScaleY).toInt() + ) + } private fun addBindings() { addSceneParamsBindings() addSceneFramesBindings() From de20ce33272479a10d39c14af44178a1b7356f6a Mon Sep 17 00:00:00 2001 From: Stanislav Mishchenko Date: Sat, 8 Jun 2024 22:57:07 +0300 Subject: [PATCH 07/12] add a scale factor to the frames identity scale --- src/main/kotlin/solve/rendering/canvas/SceneCanvas.kt | 8 ++++++-- src/main/kotlin/solve/scene/controller/SceneController.kt | 2 +- src/main/kotlin/solve/scene/view/SceneView.kt | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/solve/rendering/canvas/SceneCanvas.kt b/src/main/kotlin/solve/rendering/canvas/SceneCanvas.kt index 1b0ba203..f012f8db 100644 --- a/src/main/kotlin/solve/rendering/canvas/SceneCanvas.kt +++ b/src/main/kotlin/solve/rendering/canvas/SceneCanvas.kt @@ -4,6 +4,7 @@ import io.github.palexdev.materialfx.controls.MFXContextMenu import javafx.scene.Node import javafx.scene.input.Clipboard import javafx.scene.input.ClipboardContent +import javafx.stage.Screen import org.joml.Vector2f import org.joml.Vector2i import solve.parsers.planes.ImagePlanesParser @@ -371,7 +372,7 @@ class SceneCanvas : OpenGLCanvas() { rowsNumber * framesSize.y + (rowsNumber - 1) * Renderer.getSpacingWidth(framesSize) ) val framesSelectionScreenSize = - framesSelectionSize * window.camera.zoom / IdentityFramesSizeScale / window.camera.scaledZoom + framesSelectionSize * window.camera.zoom / scaledIdentityFramesSizeScale / window.camera.scaledZoom rightLowerCornerCameraPosition = framesSelectionScreenSize - leftUpperCornerCameraPosition @@ -450,7 +451,7 @@ class SceneCanvas : OpenGLCanvas() { ) } val getScreenScale = { - window.camera.zoom.toDouble() / IdentityFramesSizeScale + window.camera.zoom.toDouble() / scaledIdentityFramesSizeScale } val associationAdorner = AssociationAdorner( framesSize.x.toDouble(), @@ -484,6 +485,9 @@ class SceneCanvas : OpenGLCanvas() { companion object { const val IdentityFramesSizeScale = 1.605f + val scaledIdentityFramesSizeScale: Float + get() = IdentityFramesSizeScale * Screen.getPrimary().outputScaleX.toFloat() + private val landmarkInteractionMouseButton = MouseButton.Left private val contextMenuMouseButton = MouseButton.Right diff --git a/src/main/kotlin/solve/scene/controller/SceneController.kt b/src/main/kotlin/solve/scene/controller/SceneController.kt index 7c6970d1..fa3009b1 100644 --- a/src/main/kotlin/solve/scene/controller/SceneController.kt +++ b/src/main/kotlin/solve/scene/controller/SceneController.kt @@ -198,7 +198,7 @@ class SceneController : Controller() { max( installedMinScale, sceneWidthProperty.value / ((scene.frameSize.width + SceneView.framesMargin) * columnsNumber) * - SceneCanvas.IdentityFramesSizeScale + SceneCanvas.scaledIdentityFramesSizeScale ), DefaultMaxScale ) diff --git a/src/main/kotlin/solve/scene/view/SceneView.kt b/src/main/kotlin/solve/scene/view/SceneView.kt index 2caa6a14..346e0ba5 100644 --- a/src/main/kotlin/solve/scene/view/SceneView.kt +++ b/src/main/kotlin/solve/scene/view/SceneView.kt @@ -24,7 +24,6 @@ class SceneView : View() { private var mouseScreenPoint = Vector2i() private var wasMouseDragging = false - private var screen = Screen.getPrimary() override val root = canvas.canvas @@ -41,6 +40,7 @@ class SceneView : View() { } private fun extrudeEventMousePosition(event: MouseEvent) : Vector2i { + val screen = Screen.getPrimary() return Vector2i( (event.x * screen.outputScaleX).toInt(), (event.y * screen.outputScaleY).toInt() From c438980304a3fa409b19ce008e27806a3ba5f61c Mon Sep 17 00:00:00 2001 From: Stanislav Mishchenko Date: Sat, 8 Jun 2024 22:57:37 +0300 Subject: [PATCH 08/12] codestyle --- src/main/kotlin/solve/scene/view/SceneView.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/solve/scene/view/SceneView.kt b/src/main/kotlin/solve/scene/view/SceneView.kt index 346e0ba5..0d93d287 100644 --- a/src/main/kotlin/solve/scene/view/SceneView.kt +++ b/src/main/kotlin/solve/scene/view/SceneView.kt @@ -39,7 +39,7 @@ class SceneView : View() { addBindings() } - private fun extrudeEventMousePosition(event: MouseEvent) : Vector2i { + private fun extrudeEventMousePosition(event: MouseEvent): Vector2i { val screen = Screen.getPrimary() return Vector2i( (event.x * screen.outputScaleX).toInt(), From 10b9b70342952772fc17c27e6075cd9ab7438827 Mon Sep 17 00:00:00 2001 From: Stanislav Mishchenko Date: Sun, 9 Jun 2024 11:54:31 +0300 Subject: [PATCH 09/12] update identity scale calculation --- build.gradle.kts | 4 +--- src/main/kotlin/solve/rendering/canvas/SceneCanvas.kt | 10 ++++++---- .../kotlin/solve/scene/controller/SceneController.kt | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 0b369b00..d54249de 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -75,9 +75,7 @@ application { "--add-opens", "javafx.graphics/javafx.scene.image=ALL-UNNAMED", "--add-exports", "javafx.graphics/com.sun.javafx.scene=ALL-UNNAMED", "-Xms2g", - "-Xmx4g", - "-Dglass.win.uiScale=1.0", - "-Dsun.java2d.uiScale=1.0" + "-Xmx4g" ) } diff --git a/src/main/kotlin/solve/rendering/canvas/SceneCanvas.kt b/src/main/kotlin/solve/rendering/canvas/SceneCanvas.kt index f012f8db..8b868598 100644 --- a/src/main/kotlin/solve/rendering/canvas/SceneCanvas.kt +++ b/src/main/kotlin/solve/rendering/canvas/SceneCanvas.kt @@ -4,7 +4,6 @@ import io.github.palexdev.materialfx.controls.MFXContextMenu import javafx.scene.Node import javafx.scene.input.Clipboard import javafx.scene.input.ClipboardContent -import javafx.stage.Screen import org.joml.Vector2f import org.joml.Vector2i import solve.parsers.planes.ImagePlanesParser @@ -47,6 +46,11 @@ import solve.rendering.engine.scene.Scene as EngineScene * Provides interface for managing frames and changing visualization settings. */ class SceneCanvas : OpenGLCanvas() { + val scaledIdentityFramesSizeScale: Float + get() { + return IdentityFramesSizeScale * (canvas.scene?.window?.renderScaleX?.toFloat() ?: 1f) + } + private var sceneController: SceneController? = null private var engineScene: EngineScene? = null @@ -83,6 +87,7 @@ class SceneCanvas : OpenGLCanvas() { init { initializeCanvasEvents() + ServiceLocator.registerService(this) } fun setNewScene(scene: Scene) { @@ -485,9 +490,6 @@ class SceneCanvas : OpenGLCanvas() { companion object { const val IdentityFramesSizeScale = 1.605f - val scaledIdentityFramesSizeScale: Float - get() = IdentityFramesSizeScale * Screen.getPrimary().outputScaleX.toFloat() - private val landmarkInteractionMouseButton = MouseButton.Left private val contextMenuMouseButton = MouseButton.Right diff --git a/src/main/kotlin/solve/scene/controller/SceneController.kt b/src/main/kotlin/solve/scene/controller/SceneController.kt index fa3009b1..b01f58cf 100644 --- a/src/main/kotlin/solve/scene/controller/SceneController.kt +++ b/src/main/kotlin/solve/scene/controller/SceneController.kt @@ -198,7 +198,7 @@ class SceneController : Controller() { max( installedMinScale, sceneWidthProperty.value / ((scene.frameSize.width + SceneView.framesMargin) * columnsNumber) * - SceneCanvas.scaledIdentityFramesSizeScale + (ServiceLocator.getService()?.scaledIdentityFramesSizeScale ?: 1f) ), DefaultMaxScale ) From cd95241709b539365b0a62d2378d51c08356047d Mon Sep 17 00:00:00 2001 From: Stanislav Mishchenko Date: Sun, 9 Jun 2024 12:39:59 +0300 Subject: [PATCH 10/12] update adorner logic --- src/main/kotlin/solve/rendering/canvas/SceneCanvas.kt | 11 ++++++----- .../scene/view/association/AssociationManager.kt | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/solve/rendering/canvas/SceneCanvas.kt b/src/main/kotlin/solve/rendering/canvas/SceneCanvas.kt index 8b868598..7539774d 100644 --- a/src/main/kotlin/solve/rendering/canvas/SceneCanvas.kt +++ b/src/main/kotlin/solve/rendering/canvas/SceneCanvas.kt @@ -46,10 +46,11 @@ import solve.rendering.engine.scene.Scene as EngineScene * Provides interface for managing frames and changing visualization settings. */ class SceneCanvas : OpenGLCanvas() { + val displayScale: Float + get () = canvas.scene?.window?.renderScaleX?.toFloat() ?: 1f + val scaledIdentityFramesSizeScale: Float - get() { - return IdentityFramesSizeScale * (canvas.scene?.window?.renderScaleX?.toFloat() ?: 1f) - } + get() = IdentityFramesSizeScale * displayScale private var sceneController: SceneController? = null private var engineScene: EngineScene? = null @@ -168,8 +169,8 @@ class SceneCanvas : OpenGLCanvas() { val canvasScreenPosition = canvas.getScreenPosition() contextMenu.show( canvas.scene.window, - canvasScreenPosition.x + screenPoint.x.toDouble(), - canvasScreenPosition.y + screenPoint.y.toDouble() + canvasScreenPosition.x + screenPoint.x.toDouble() / displayScale, + canvasScreenPosition.y + screenPoint.y.toDouble() / displayScale ) } } diff --git a/src/main/kotlin/solve/scene/view/association/AssociationManager.kt b/src/main/kotlin/solve/scene/view/association/AssociationManager.kt index 2fb6ac17..42b42639 100644 --- a/src/main/kotlin/solve/scene/view/association/AssociationManager.kt +++ b/src/main/kotlin/solve/scene/view/association/AssociationManager.kt @@ -7,7 +7,7 @@ class AssociationManager { private var framesSelection = listOf() private val _associationConnections = mutableListOf() val associationConnections: List - get() = _associationConnections + get() = _associationConnections.toList() fun setFramesSelection(framesSelection: List) { this.framesSelection = framesSelection From 196566274e59fdc5caa39ad50a5c9d767d763516 Mon Sep 17 00:00:00 2001 From: Stanislav Mishchenko Date: Sun, 9 Jun 2024 12:44:50 +0300 Subject: [PATCH 11/12] codestyle --- src/main/kotlin/solve/rendering/canvas/SceneCanvas.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/solve/rendering/canvas/SceneCanvas.kt b/src/main/kotlin/solve/rendering/canvas/SceneCanvas.kt index 7539774d..922be995 100644 --- a/src/main/kotlin/solve/rendering/canvas/SceneCanvas.kt +++ b/src/main/kotlin/solve/rendering/canvas/SceneCanvas.kt @@ -47,7 +47,7 @@ import solve.rendering.engine.scene.Scene as EngineScene */ class SceneCanvas : OpenGLCanvas() { val displayScale: Float - get () = canvas.scene?.window?.renderScaleX?.toFloat() ?: 1f + get() = canvas.scene?.window?.renderScaleX?.toFloat() ?: 1f val scaledIdentityFramesSizeScale: Float get() = IdentityFramesSizeScale * displayScale From 0a795e2039859152485ce64ee0bb46446405a519 Mon Sep 17 00:00:00 2001 From: Stanislav Mishchenko Date: Sun, 9 Jun 2024 13:30:51 +0300 Subject: [PATCH 12/12] update frames selection size calculation --- src/main/kotlin/solve/rendering/canvas/SceneCanvas.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/solve/rendering/canvas/SceneCanvas.kt b/src/main/kotlin/solve/rendering/canvas/SceneCanvas.kt index 922be995..e721c95d 100644 --- a/src/main/kotlin/solve/rendering/canvas/SceneCanvas.kt +++ b/src/main/kotlin/solve/rendering/canvas/SceneCanvas.kt @@ -378,7 +378,7 @@ class SceneCanvas : OpenGLCanvas() { rowsNumber * framesSize.y + (rowsNumber - 1) * Renderer.getSpacingWidth(framesSize) ) val framesSelectionScreenSize = - framesSelectionSize * window.camera.zoom / scaledIdentityFramesSizeScale / window.camera.scaledZoom + framesSelectionSize * window.camera.zoom / IdentityFramesSizeScale / window.camera.scaledZoom rightLowerCornerCameraPosition = framesSelectionScreenSize - leftUpperCornerCameraPosition