tsvm: mouse coord fix

This commit is contained in:
minjaesong
2026-05-24 12:40:51 +09:00
parent 054295fdab
commit de82435f6e
2 changed files with 50 additions and 7 deletions

View File

@@ -3,6 +3,8 @@ package net.torvald.tsvm.peripheral
import com.badlogic.gdx.Gdx import com.badlogic.gdx.Gdx
import com.badlogic.gdx.Input import com.badlogic.gdx.Input
import com.badlogic.gdx.InputProcessor import com.badlogic.gdx.InputProcessor
import com.badlogic.gdx.math.Vector2
import com.badlogic.gdx.utils.viewport.Viewport
import net.torvald.AddressOverflowException import net.torvald.AddressOverflowException
import net.torvald.DanglingPointerException import net.torvald.DanglingPointerException
import net.torvald.UnsafeHelper import net.torvald.UnsafeHelper
@@ -18,10 +20,18 @@ class IOSpace(val vm: VM) : PeriBase("io"), InputProcessor {
return vm return vm
} }
/** Absolute x-position of the computer GUI */ /**
var guiPosX = 0 * Viewport that maps screen pixels (as reported by `Gdx.input.x/y`) to the VM's
/** Absolute y-position of the computer GUI */ * logical framebuffer coordinate space. The host application owns the rendering
var guiPosY = 0 * camera, so the host is responsible for installing a viewport whose world
* coordinates match the VM framebuffer (origin top-left, world size = framebuffer
* size in pixels) and whose screen rectangle matches where the VM is drawn.
*
* If left null, `Gdx.input.x/y` is forwarded verbatim — only correct when the VM
* occupies the entire window at 1:1 scale.
*/
var inputViewport: Viewport? = null
private val tmpMouseVec = Vector2()
/** Accepts a keycode */ /** Accepts a keycode */
private val keyboardBuffer = CircularArray<Byte>(32, true) private val keyboardBuffer = CircularArray<Byte>(32, true)
@@ -296,9 +306,20 @@ class IOSpace(val vm: VM) : PeriBase("io"), InputProcessor {
keyEventBuffers.fill(0) keyEventBuffers.fill(0)
if (isFocused) { if (isFocused) {
// store mouse info // store mouse info; unproject through the host-provided viewport so the
mouseX = (Gdx.input.x + guiPosX).toShort() // VM sees logical framebuffer pixels regardless of window magnification,
mouseY = (Gdx.input.y + guiPosY).toShort() // letterboxing or sub-region placement done by an embedding GDX app.
val vp = inputViewport
if (vp != null) {
tmpMouseVec.set(Gdx.input.x.toFloat(), Gdx.input.y.toFloat())
vp.unproject(tmpMouseVec)
mouseX = tmpMouseVec.x.toInt().toShort()
mouseY = tmpMouseVec.y.toInt().toShort()
}
else {
mouseX = Gdx.input.x.toShort()
mouseY = Gdx.input.y.toShort()
}
mouseButtons = (if (Gdx.input.isButtonPressed(Input.Buttons.LEFT)) 1 else 0) or mouseButtons = (if (Gdx.input.isButtonPressed(Input.Buttons.LEFT)) 1 else 0) or
(if (Gdx.input.isButtonPressed(Input.Buttons.RIGHT)) 2 else 0) (if (Gdx.input.isButtonPressed(Input.Buttons.RIGHT)) 2 else 0)

View File

@@ -8,6 +8,8 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.badlogic.gdx.graphics.g2d.TextureRegion import com.badlogic.gdx.graphics.g2d.TextureRegion
import com.badlogic.gdx.graphics.glutils.FrameBuffer import com.badlogic.gdx.graphics.glutils.FrameBuffer
import com.badlogic.gdx.graphics.glutils.ShaderProgram import com.badlogic.gdx.graphics.glutils.ShaderProgram
import com.badlogic.gdx.utils.viewport.StretchViewport
import com.badlogic.gdx.utils.viewport.Viewport
import net.torvald.terrarum.DefaultGL32Shaders import net.torvald.terrarum.DefaultGL32Shaders
import net.torvald.tsvm.peripheral.* import net.torvald.tsvm.peripheral.*
import net.torvald.tsvm.peripheral.GraphicsAdapter.Companion.DRAW_SHADER_VERT import net.torvald.tsvm.peripheral.GraphicsAdapter.Companion.DRAW_SHADER_VERT
@@ -48,6 +50,14 @@ class VMGUI(val loaderInfo: EmulInstance, val viewportWidth: Int, val viewportHe
lateinit var batch: SpriteBatch lateinit var batch: SpriteBatch
lateinit var camera: OrthographicCamera lateinit var camera: OrthographicCamera
/**
* Maps window pixels to the VM framebuffer (origin top-left, world size =
* viewportWidth × viewportHeight). Stretches to fill the whole window so it
* matches the `MAGN`-scaled blit at the end of [renderGame]. Handed to
* [IOSpace.inputViewport] so mouse coordinates unproject correctly.
*/
lateinit var inputViewport: Viewport
var gpu: GraphicsAdapter? = null var gpu: GraphicsAdapter? = null
lateinit var vmRunner: VMRunner lateinit var vmRunner: VMRunner
lateinit var coroutineJob: Thread lateinit var coroutineJob: Thread
@@ -103,9 +113,20 @@ class VMGUI(val loaderInfo: EmulInstance, val viewportWidth: Int, val viewportHe
gpuFBO = FrameBuffer(Pixmap.Format.RGBA8888, viewportWidth, viewportHeight, false) gpuFBO = FrameBuffer(Pixmap.Format.RGBA8888, viewportWidth, viewportHeight, false)
winFBO = FrameBuffer(Pixmap.Format.RGBA8888, viewportWidth, viewportHeight, false) winFBO = FrameBuffer(Pixmap.Format.RGBA8888, viewportWidth, viewportHeight, false)
val inputCam = OrthographicCamera().also {
it.setToOrtho(true, viewportWidth.toFloat(), viewportHeight.toFloat())
}
inputViewport = StretchViewport(viewportWidth.toFloat(), viewportHeight.toFloat(), inputCam)
inputViewport.update(Gdx.graphics.width, Gdx.graphics.height, true)
init() init()
} }
override fun resize(width: Int, height: Int) {
super.resize(width, height)
inputViewport.update(width, height, true)
}
private fun init() { private fun init() {
vm.init() vm.init()
@@ -148,6 +169,7 @@ class VMGUI(val loaderInfo: EmulInstance, val viewportWidth: Int, val viewportHe
} }
Gdx.input.inputProcessor = vm.getIO() Gdx.input.inputProcessor = vm.getIO()
vm.getIO().inputViewport = inputViewport
if (usememvwr) memvwr = Memvwr(vm) if (usememvwr) memvwr = Memvwr(vm)