Skip to content

Commit

Permalink
fix virtualization bugs and constraint position of the scene camera
Browse files Browse the repository at this point in the history
  • Loading branch information
mi-sts committed Dec 1, 2023
1 parent 64afcdc commit b894606
Show file tree
Hide file tree
Showing 9 changed files with 164 additions and 67 deletions.
52 changes: 44 additions & 8 deletions src/main/kotlin/solve/rendering/canvas/SceneCanvas.kt
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
package solve.rendering.canvas

import javafx.application.Platform
import org.joml.Vector2f
import org.joml.Vector2i
import solve.rendering.engine.rendering.renderers.FramesRenderer
import solve.rendering.engine.scene.Scene
import solve.rendering.engine.utils.minus
import solve.rendering.engine.utils.times
import solve.rendering.engine.utils.toFloatVector
import solve.scene.controller.SceneController
import solve.scene.model.VisualizationFrame
import solve.utils.ServiceLocator
import solve.utils.ceilToInt

class SceneCanvas : OpenGLCanvas() {
private var sceneController: SceneController? = null
Expand All @@ -19,28 +22,44 @@ class SceneCanvas : OpenGLCanvas() {
private var dragStartCameraPoint = Vector2f()
private var dragStartPoint = Vector2i()

private var leftUpperCornerCameraPosition = Vector2f()
private var rightLowerCornerCameraPosition = Vector2f()

private var framesSelectionSize = 0
private var framesSize = Vector2i()
private var columnsNumber = 0
private val rowsNumber: Int
get() = (framesSelectionSize.toFloat() / columnsNumber.toFloat()).ceilToInt()

init {
initializeCanvasEvents()
}

fun setNewSceneFrames(frames: List<VisualizationFrame>) {
fun setNewSceneFrames(frames: List<VisualizationFrame>, framesSize: Vector2i) {
framesRenderer?.setNewSceneFrames(frames)
this.framesSize = framesSize
}

fun setFramesSelection(framesSelection: List<VisualizationFrame>) {
framesRenderer?.setFramesSelection(framesSelection)
framesSelectionSize = framesSelection.count()
Platform.runLater {
recalculateCameraCornersPositions()
window.camera.position = leftUpperCornerCameraPosition
}
}

fun setColumnsNumber(columnsNumber: Int) {
framesRenderer?.setGridWidth(columnsNumber)
this.columnsNumber = columnsNumber
}

fun dragTo(toScreenPoint: Vector2i) {
val mousePoint = fromScreenToCameraPoint(toScreenPoint)
if (isDraggingScene) {
val dragVector = mousePoint - dragStartPoint
window.camera.position = dragStartCameraPoint - dragVector.toFloatVector() / window.camera.scaledZoom
constraintCameraPosition()
}
}

Expand All @@ -57,11 +76,12 @@ class SceneCanvas : OpenGLCanvas() {
fun zoomToPoint(screenPoint: Vector2i, newZoom: Float) {
val cameraPoint = fromScreenToCameraPoint(screenPoint)
window.camera.zoomToPoint(cameraPoint, newZoom)

recalculateCameraCornersPositions()
constraintCameraPosition()
}

override fun onInit() {
moveCameraToLeftUpperCorner()

val controller = ServiceLocator.getService<SceneController>() ?: return
sceneController = controller

Expand All @@ -76,15 +96,31 @@ class SceneCanvas : OpenGLCanvas() {

private fun fromScreenToCameraPoint(screenPoint: Vector2i) = screenPoint - (window.size / 2)

private fun moveCameraToLeftUpperCorner() {
window.camera.position =
Vector2f(window.width.toFloat(), window.height.toFloat()) / (2f * window.camera.scaledZoom)
private fun constraintCameraPosition() {
window.camera.position.x =
window.camera.position.x.coerceIn(leftUpperCornerCameraPosition.x, rightLowerCornerCameraPosition.x)
window.camera.position.y =
window.camera.position.y.coerceIn(leftUpperCornerCameraPosition.y, rightLowerCornerCameraPosition.y)
}

private fun recalculateCameraCornersPositions() {
val halfScreenSize = (Vector2f(window.width.toFloat(), window.height.toFloat()) / 2f) / window.camera.scaledZoom
leftUpperCornerCameraPosition = halfScreenSize

val framesSelectionSize =
Vector2i(columnsNumber * framesSize.x, rowsNumber * framesSize.y).toFloatVector()
val framesSelectionScreenSize =
framesSelectionSize * window.camera.zoom / IdentityFramesSizeScale / window.camera.scaledZoom

rightLowerCornerCameraPosition = framesSelectionScreenSize - leftUpperCornerCameraPosition

rightLowerCornerCameraPosition.x =
rightLowerCornerCameraPosition.x.coerceAtLeast(leftUpperCornerCameraPosition.x)
rightLowerCornerCameraPosition.y =
rightLowerCornerCameraPosition.y.coerceAtLeast(leftUpperCornerCameraPosition.y)
}

companion object {
private const val DefaultMinZoom = 0.1f
private const val DefaultMaxZoom = 10f
const val IdentityFramesSizeScale = 1.605f
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class DefaultRenderer(
val gameObject = spriteRenderer.sceneObject ?: return@forEach

val texture = sprite.texture
val textureSidesRatio = texture.width.toFloat() / texture.height.toFloat()
val batch = getAvailableBatch(texture, gameObject.transform.zIndex)
val textureID = batch.getTextureLocalID(texture)
val scale = gameObject.transform.scale
Expand All @@ -70,7 +71,10 @@ class DefaultRenderer(
val uvCoordinates = sprite.uvCoordinates

spriteLocalVerticesPositions.forEachIndexed { index, vertexPosition ->
val vertexLocalVector = Vector2f(vertexPosition.x * scale.x, vertexPosition.y * scale.y)
val vertexLocalVector = Vector2f(
vertexPosition.x * scale.x * textureSidesRatio,
vertexPosition.y * scale.y
)

batch.pushVector2f(position + vertexLocalVector)
batch.pushVector4f(color.toVector4f())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,22 @@ import solve.rendering.engine.shader.ShaderProgram
import solve.rendering.engine.shader.ShaderType
import solve.rendering.engine.structures.IntRect
import solve.rendering.engine.utils.minus
import solve.rendering.engine.utils.toFloatVector
import solve.rendering.engine.utils.toIntVector
import solve.scene.model.VisualizationFrame
import solve.utils.ceilToInt
import java.util.Date
import kotlin.math.abs
import kotlin.math.min

class FramesRenderer(
window: Window
) : Renderer(window) {
private data class LoadedBufferFrameData(val textureData: Texture2DData, val bufferIndex: Int)
private data class LoadedBufferFrameData(
val textureData: Texture2DData,
val bufferIndex: Int,
val time: Long
)

override val maxBatchSize = 1000
private var modelsCommonMatrix = Matrix4f().identity()
Expand All @@ -46,7 +53,10 @@ class FramesRenderer(
private var framesChannelsType = TextureChannelsType.RGBA
private var selectedFrames = emptyList<VisualizationFrame>()

private var cameraLastGridCellPosition = getCameraGridCellPosition()
private val framesRatio: Float
get() = framesWidth.toFloat() / framesHeight.toFloat()

private var cameraLastGridCellPosition = getScreenCenterGridCellPosition()

private val bufferFramesToUpload = mutableListOf<LoadedBufferFrameData>()
private val framesLoadingCoroutineScope = CoroutineScope(Dispatchers.Default)
Expand All @@ -64,7 +74,7 @@ class FramesRenderer(
return
}

this.gridWidth = gridWidth
this.gridWidth = min(gridWidth, selectedFrames.count())
}

fun setNewSceneFrames(frames: List<VisualizationFrame>) {
Expand All @@ -78,10 +88,6 @@ class FramesRenderer(
}

fun setFramesSelection(frames: List<VisualizationFrame>) {
if (frames.isEmpty()) {
return
}

this.selectedFrames = frames
haveNewFramesSelection = true
}
Expand All @@ -102,6 +108,8 @@ class FramesRenderer(
shaderProgram.uploadInt(GridWidthUniformName, gridWidth)
shaderProgram.uploadVector2i(BuffersSizeUniformName, buffersSize)
shaderProgram.uploadInt(TexturesArrayUniformName, 0)
shaderProgram.uploadFloat(TexturesRatioUniformName, framesRatio)
shaderProgram.uploadVector2f(CameraPositionUniformName, getScreenCenterGridCellPosition().toFloatVector())
}

override fun createNewBatch(zIndex: Int) =
Expand Down Expand Up @@ -142,14 +150,14 @@ class FramesRenderer(

private fun uploadLoadedFramesToBuffers() {
bufferFramesToUpload.toList().forEach { frame ->
bufferFramesArrayTexture?.uploadTexture(frame.textureData, frame.bufferIndex)
bufferFramesToUpload.remove(frame)
bufferFramesArrayTexture?.uploadTexture(frame.textureData, frame.bufferIndex)
Texture2D.freeData(frame.textureData)
}
}

private fun updateBuffersTextures() {
val cameraGridCellPosition = getCameraGridCellPosition()
val cameraGridCellPosition = getScreenCenterGridCellPosition()
if (cameraGridCellPosition != cameraLastGridCellPosition) {
loadNewTexturesToBuffers(cameraGridCellPosition)
}
Expand Down Expand Up @@ -196,7 +204,7 @@ class FramesRenderer(
val framesRect = mutableListOf<List<VisualizationFrame>>()
for (y in rect.y0 until rect.y0 + rect.height) {
val framesFromIndex = (gridWidth * y + rect.x0).coerceIn(0..selectedFrames.lastIndex)
val framesToIndex = (framesFromIndex + rect.width).coerceIn(0..selectedFrames.lastIndex)
val framesToIndex = (framesFromIndex + rect.width).coerceIn(0..selectedFrames.count())

framesRect.add(selectedFrames.subList(framesFromIndex, framesToIndex))
}
Expand All @@ -212,10 +220,10 @@ class FramesRenderer(
}

val buffersOffset = Vector2i(framesRect.x0 % buffersSize.x, framesRect.y0 % buffersSize.y)
if (framesRect.width > buffersSize.x || framesRect.height > buffersSize.y) {
/*if (framesRect.width > buffersSize.x || framesRect.height > buffersSize.y) {
println("The size of the loading frames is out of buffers bounds!")
return
}
}*/

for (y in 0 until rectFrames.count()) {
for (x in 0 until rectFrames[y].count()) {
Expand All @@ -226,8 +234,9 @@ class FramesRenderer(
}
}

private fun getCameraGridCellPosition(): Vector2i {
return (window.camera.position - Vector2f(buffersSize) / 2f).toIntVector()
private fun getScreenCenterGridCellPosition(): Vector2i {
val cameraGridCellPosition = Vector2f(window.camera.position.x / framesRatio, window.camera.position.y)
return (cameraGridCellPosition - Vector2f(buffersSize) / 2f).toIntVector()
}

private fun uploadAllFramesToBuffer() {
Expand All @@ -250,14 +259,15 @@ class FramesRenderer(
}

private fun uploadFrameToBuffersArray(frame: VisualizationFrame, index: Int) {
val loadTime = Date().time
framesLoadingCoroutineScope.launch {
val textureData = Texture2D.loadData(frame.imagePath.toString())
if (textureData == null) {
println("The read texture is null!")
return@launch
}

bufferFramesToUpload.add(LoadedBufferFrameData(textureData, index))
bufferFramesToUpload.add(LoadedBufferFrameData(textureData, index, loadTime))
}
}

Expand All @@ -267,9 +277,11 @@ class FramesRenderer(
private const val GridWidthUniformName = "uGridWidth"
private const val BuffersSizeUniformName = "uBuffersSize"
private const val TexturesArrayUniformName = "uTextures"
private const val TexturesRatioUniformName = "uTexturesRatio"
private const val CameraPositionUniformName = "uCameraPosition"

private const val DefaultGridWidth = 10

private val defaultBuffersSize = Vector2i(4, 4)
private val defaultBuffersSize = Vector2i(5, 5)
}
}
14 changes: 9 additions & 5 deletions src/main/kotlin/solve/scene/controller/SceneController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package solve.scene.controller
import javafx.beans.property.SimpleDoubleProperty
import javafx.beans.property.SimpleIntegerProperty
import javafx.beans.property.SimpleObjectProperty
import solve.rendering.canvas.SceneCanvas
import solve.scene.model.Scene
import solve.scene.view.SceneView
import solve.utils.ServiceLocator
Expand Down Expand Up @@ -95,7 +96,10 @@ class SceneController : Controller() {
var scale: Double
get() = scaleProperty.value
private set(value) {
scaleProperty.value = value.coerceIn(installedMinScale, installedMaxScale)
scaleProperty.value = value.coerceIn(
max(installedMinScale, minScale),
min(installedMaxScale, maxScale)
)
}

private val minScale: Double
Expand Down Expand Up @@ -137,7 +141,7 @@ class SceneController : Controller() {
fun increaseScale() {
scale *= ScaleFactor
}

fun decreaseScale() {
scale /= ScaleFactor
}
Expand Down Expand Up @@ -194,8 +198,8 @@ class SceneController : Controller() {
return min(
max(
installedMinScale,
sceneWidthProperty.value /
((scene.frameSize.width + SceneView.framesMargin) * columnsNumber)
sceneWidthProperty.value / ((scene.frameSize.width + SceneView.framesMargin) * columnsNumber) *
SceneCanvas.IdentityFramesSizeScale
),
DefaultMaxScale
)
Expand All @@ -210,7 +214,7 @@ class SceneController : Controller() {
const val DefaultMinScale = 0.2
const val DefaultMaxScale = 20.0

const val MaxColumnsNumber = 5
const val MaxColumnsNumber = 6

private const val DefaultX = 0.0
private const val DefaultY = 0.0
Expand Down
5 changes: 3 additions & 2 deletions src/main/kotlin/solve/scene/model/Scene.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package solve.scene.model

import solve.utils.loadBufferedImage
import solve.utils.structures.Size as DoubleSize

/**
Expand All @@ -17,8 +18,8 @@ class Scene(
*/
val frameSize: DoubleSize by lazy {
frames.firstOrNull()?.let {
// TODO
DoubleSize(0.0, 0.0)
val image = loadBufferedImage(it.imagePath.toString()) ?: return@let null
return@let DoubleSize(image.width.toDouble(), image.height.toDouble())
} ?: DoubleSize(0.0, 0.0)
}

Expand Down
6 changes: 4 additions & 2 deletions src/main/kotlin/solve/scene/view/SceneView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ class SceneView : View() {
override val root = canvas.canvas

private val projectChangedEventHandler = InvalidationListener {
canvas.setNewSceneFrames(controller.scene.frames)
val framesSize = controller.scene.frameSize
val framesSizeVector = Vector2i(framesSize.width.toInt(), framesSize.height.toInt())
canvas.setNewSceneFrames(controller.scene.frames, framesSizeVector)
}
private val framesChangedEventHandler = InvalidationListener {
canvas.setFramesSelection(controller.scene.frames)
Expand Down Expand Up @@ -108,7 +110,7 @@ class SceneView : View() {
private const val OnWheelScrolledScaleMultiplier = 1.1f
private val MouseDragButton = MouseButton.MIDDLE

const val framesMargin = 10.0
const val framesMargin = 0.0
const val scrollSpeed = 20.0
}
}
6 changes: 5 additions & 1 deletion src/main/resources/engine/shaders/frame/frame.frag
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,9 @@ out vec4 color;

void main()
{
color = texture(uTextures, vec3(fTexCoords, fTexID));
if (fTexID == -1.0) {
color = vec4(0.0, 0.0, 0.0, 0.0);
} else {
color = texture(uTextures, vec3(fTexCoords, fTexID));
}
}
Loading

0 comments on commit b894606

Please sign in to comment.