mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-03-07 19:51:51 +09:00
emulator: malloc viewer
This commit is contained in:
@@ -5,6 +5,8 @@ import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration;
|
|||||||
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
|
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
|
||||||
import net.torvald.tsvm.peripheral.*;
|
import net.torvald.tsvm.peripheral.*;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
public class TerranBASIC {
|
public class TerranBASIC {
|
||||||
|
|
||||||
public static String appTitle = "TerranBASIC";
|
public static String appTitle = "TerranBASIC";
|
||||||
@@ -25,7 +27,10 @@ public class TerranBASIC {
|
|||||||
|
|
||||||
appConfig.setWindowedMode(WIDTH, HEIGHT);
|
appConfig.setWindowedMode(WIDTH, HEIGHT);
|
||||||
|
|
||||||
VM tbasvm = new VM("./assets", 64 << 10, new TheRealWorld(), new VMProgramRom[]{TBASRelBios.INSTANCE}, 2);
|
HashMap<String, VMWatchdog> watchdogs = new HashMap<>();
|
||||||
|
watchdogs.put("TEVD_SYNC", TevdSyncWatchdog.INSTANCE);
|
||||||
|
|
||||||
|
VM tbasvm = new VM("./assets", 64 << 10, new TheRealWorld(), new VMProgramRom[]{TBASRelBios.INSTANCE}, 2, watchdogs);
|
||||||
EmulInstance tbasrunner = new EmulInstance(tbasvm, "net.torvald.tsvm.peripheral.ReferenceGraphicsAdapter", "assets/disk0", 560, 448);
|
EmulInstance tbasrunner = new EmulInstance(tbasvm, "net.torvald.tsvm.peripheral.ReferenceGraphicsAdapter", "assets/disk0", 560, 448);
|
||||||
new Lwjgl3Application(new VMGUI(tbasrunner, WIDTH, HEIGHT), appConfig);
|
new Lwjgl3Application(new VMGUI(tbasrunner, WIDTH, HEIGHT), appConfig);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -378,59 +378,76 @@ METADATA -
|
|||||||
uint16 HEIGHT
|
uint16 HEIGHT
|
||||||
uint16 FPS (0: play as fast as can)
|
uint16 FPS (0: play as fast as can)
|
||||||
uint32 NUMBER OF FRAMES
|
uint32 NUMBER OF FRAMES
|
||||||
uint16 PACKET TYPE
|
uint16 GLOBAL PACKET TYPE (will be deprecated; please use 255,0)
|
||||||
byte[12] RESERVED
|
byte[12] RESERVED
|
||||||
|
|
||||||
Packet Type Low Byte:
|
Packet Types:
|
||||||
0: 256-Colour frame
|
<video>
|
||||||
1: 256-Colour frame with palette data
|
0,0: 256-Colour frame
|
||||||
2: 4096-Colour frame (stored as two byte-planes)
|
1,0: 256-Colour frame with palette data
|
||||||
4: iPF no-alpha indicator (see iPF Type Numbers for details)
|
2,0: 4096-Colour frame (stored as two byte-planes)
|
||||||
5: iPF with alpha indicator (see iPF Type Numbers for details)
|
4,t: iPF no-alpha indicator (see iPF Type Numbers for details)
|
||||||
16: Series of JPEGs
|
5,t: iPF with alpha indicator (see iPF Type Numbers for details)
|
||||||
18: Series of PNGs
|
16,0: Series of JPEGs
|
||||||
20: Series of TGAs
|
18,0: Series of PNGs
|
||||||
21: Series of TGA/GZs
|
20,0: Series of TGAs
|
||||||
255: Every frame specifies the type
|
21,0: Series of TGA/GZs
|
||||||
|
255,0: Every frame specifies the type
|
||||||
|
<audio>
|
||||||
|
0,16: Raw PCM Mono
|
||||||
|
1,16: Raw PCM Stereo
|
||||||
|
2,16: ADPCM Mono
|
||||||
|
3,16: ADPCM Stereo
|
||||||
|
<special>
|
||||||
|
255,255: sync packet (wait until the next frame)
|
||||||
|
|
||||||
Packet Type High Byte (iPF Type Numbers)
|
Packet Type High Byte (iPF Type Numbers)
|
||||||
0..7: iPF Type 1..8
|
0..7: iPF Type 1..8
|
||||||
|
|
||||||
Packet Types for Audio (High Byte=16)
|
|
||||||
0: Raw PCM Mono
|
|
||||||
1: Raw PCM Stereo
|
|
||||||
2: ADPCM Mono
|
|
||||||
3: ADPCM Stereo
|
|
||||||
|
|
||||||
|
|
||||||
TYPE 0 Packet -
|
|
||||||
|
GLOBAL TYPE 0 Packet -
|
||||||
uint32 SIZE OF FRAMEDATA
|
uint32 SIZE OF FRAMEDATA
|
||||||
* FRAMEDATA COMPRESSED IN GZIP
|
* FRAMEDATA COMPRESSED IN GZIP
|
||||||
|
|
||||||
TYPE 1 Packet -
|
GLOBAL TYPE 1 Packet -
|
||||||
byte[512] Palette Data
|
byte[512] Palette Data
|
||||||
uint32 SIZE OF FRAMEDATA
|
uint32 SIZE OF FRAMEDATA
|
||||||
* FRAMEDATA COMPRESSED IN GZIP
|
* FRAMEDATA COMPRESSED IN GZIP
|
||||||
|
|
||||||
TYPE 2 Packet -
|
GLOBAL TYPE 2 Packet -
|
||||||
uint32 SIZE OF FRAMEDATA BYTE-PLANE 1
|
uint32 SIZE OF FRAMEDATA BYTE-PLANE 1
|
||||||
* FRAMEDATA COMPRESSED IN GZIP
|
* FRAMEDATA COMPRESSED IN GZIP
|
||||||
uint32 SIZE OF FRAMEDATA BYTE-PLANE 2
|
uint32 SIZE OF FRAMEDATA BYTE-PLANE 2
|
||||||
* FRAMEDATA COMPRESSED IN GZIP
|
* FRAMEDATA COMPRESSED IN GZIP
|
||||||
|
|
||||||
iPF Packet -
|
GLOBAL iPF Packet -
|
||||||
uint32 SIZE OF FRAMEDATA
|
uint32 SIZE OF FRAMEDATA
|
||||||
* FRAMEDATA COMPRESSED IN GZIP // only the actual gzip (and no UNCOMPRESSED SIZE) of the "Blocks.gz" is stored
|
* FRAMEDATA COMPRESSED IN GZIP // only the actual gzip (and no UNCOMPRESSED SIZE) of the "Blocks.gz" is stored
|
||||||
|
|
||||||
TYPE 16+ Packet -
|
GLOBAL TYPE 16+ Packet -
|
||||||
uint32 SIZE OF FRAMEDATA BYTE-PLANE 1
|
uint32 SIZE OF FRAMEDATA BYTE-PLANE 1
|
||||||
* FRAMEDATA (COMPRESSED IN GZIP for TGA/GZ)
|
* FRAMEDATA (COMPRESSED IN GZIP for TGA/GZ)
|
||||||
|
|
||||||
TYPE 255 Packet -
|
GLOBAL TYPE 255 Packet -
|
||||||
uint16 TYPE OF PACKET // follows the Metadata Packet Type scheme
|
uint16 TYPE OF PACKET // follows the Metadata Packet Type scheme
|
||||||
uint32 SIZE OF PACKET
|
uint32 SIZE OF PACKET
|
||||||
* FRAMEDATA or PACKET
|
* FRAMEDATA or PACKET
|
||||||
|
|
||||||
|
Sync Packet (subset of GLOBAL TYPE 255 Packet) -
|
||||||
|
uint16 0xFFFF (type of packet for Global Type 255)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Frame Timing
|
||||||
|
If the global type is not 255, each packet is interpreted as a single full frame, and then will wait for the next
|
||||||
|
frame time; For type 255 however, the assumption no longer holds and each frame can have multiple packets, and thus
|
||||||
|
needs explicit "sync" packet for proper frame timing.
|
||||||
|
|
||||||
|
|
||||||
|
NOTE FROM DEVELOPER
|
||||||
|
In the future, the global packet type will be deprecated.
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|||||||
24
tsvm_executable/src/net/torvald/tsvm/DummyMenu.kt
Normal file
24
tsvm_executable/src/net/torvald/tsvm/DummyMenu.kt
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package net.torvald.tsvm
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by minjaesong on 2023-01-02.
|
||||||
|
*/
|
||||||
|
class DummyMenu(parent: VMEmuExecutable, x: Int, y: Int, w: Int, h: Int) : EmuMenu(parent, x, y, w, h) {
|
||||||
|
|
||||||
|
override fun show() {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hide() {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun update() {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun render(batch: SpriteBatch) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dispose() {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,5 +11,6 @@ abstract class EmuMenu(val parent: VMEmuExecutable, val x: Int, val y: Int, val
|
|||||||
abstract fun hide()
|
abstract fun hide()
|
||||||
abstract fun update()
|
abstract fun update()
|
||||||
abstract fun render(batch: SpriteBatch)
|
abstract fun render(batch: SpriteBatch)
|
||||||
|
abstract fun dispose()
|
||||||
|
|
||||||
}
|
}
|
||||||
123
tsvm_executable/src/net/torvald/tsvm/MMUMenu.kt
Normal file
123
tsvm_executable/src/net/torvald/tsvm/MMUMenu.kt
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
package net.torvald.tsvm
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.Color
|
||||||
|
import com.badlogic.gdx.graphics.Pixmap
|
||||||
|
import com.badlogic.gdx.graphics.Texture
|
||||||
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||||
|
import net.torvald.tsvm.EmulatorGuiToolkit.Theme.COL_LAND
|
||||||
|
import net.torvald.tsvm.EmulatorGuiToolkit.Theme.COL_WELL
|
||||||
|
import net.torvald.tsvm.VMEmuExecutableWrapper.Companion.FONT
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by minjaesong on 2023-01-02.
|
||||||
|
*/
|
||||||
|
class MMUMenu(parent: VMEmuExecutable, x: Int, y: Int, w: Int, h: Int) : EmuMenu(parent, x, y, w, h) {
|
||||||
|
|
||||||
|
override fun show() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hide() {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun update() {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun render(batch: SpriteBatch) {
|
||||||
|
batch.color = Color.WHITE
|
||||||
|
|
||||||
|
val vmInfo = parent.getCurrentlySelectedVM()
|
||||||
|
|
||||||
|
if (vmInfo == null) {
|
||||||
|
batch.inUse {
|
||||||
|
FONT.draw(batch, "Please select a VM", 12f, 11f + 0* FONT.H)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else vmInfo.let { (vm, vmName) ->
|
||||||
|
batch.inUse {
|
||||||
|
FONT.draw(batch, "Allocated size: ${vm.allocatedBlockCount * vm.MALLOC_UNIT}", 12f, 11f + 0* FONT.H)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
drawAllocMap(batch, vm, 62f, 2f * FONT.H)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val plotColset = intArrayOf(
|
||||||
|
0xea5545ff.toInt(), 0xf46a9bff.toInt(), 0xef9b20ff.toInt(), 0xedbf33ff.toInt(), 0xede15bff.toInt(), 0xbdcf32ff.toInt(),
|
||||||
|
0x87bc45ff.toInt(), 0x27aeefff.toInt(), 0xb33dc6ff.toInt(), 0xe60049ff.toInt(), 0x0bb4ffff.toInt(), 0x50e991ff.toInt(),
|
||||||
|
0xe6d800ff.toInt(), 0x9b19f5ff.toInt(), 0xffa300ff.toInt(), 0xdc0ab4ff.toInt(), 0xb3d4ffff.toInt(), 0x00bfa0ff.toInt(),
|
||||||
|
)
|
||||||
|
private val plotColours = plotColset.map { Color(it) }
|
||||||
|
|
||||||
|
private val memmapPixmap = Pixmap(512, 256, Pixmap.Format.RGBA8888)
|
||||||
|
|
||||||
|
private var mallocMap: List<Pair<Int, Int>> = listOf()
|
||||||
|
|
||||||
|
private fun drawAllocMap(batch: SpriteBatch, vm: VM, x: Float, y: Float) {
|
||||||
|
|
||||||
|
// clear the memmapPixmap
|
||||||
|
memmapPixmap.setColor(0)
|
||||||
|
memmapPixmap.fill()
|
||||||
|
|
||||||
|
// unallocated map as black
|
||||||
|
for (i in 0 until vm.memsize / vm.MALLOC_UNIT) {
|
||||||
|
paintPixel(i.toInt(), 255)
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// try to update the mallocMap
|
||||||
|
mallocMap = vm.javaClass.getDeclaredField("mallocSizes").let {
|
||||||
|
it.isAccessible = true
|
||||||
|
it.get(vm) as HashMap<Int, Int>
|
||||||
|
}.entries.map { it.key to it.value }.sortedBy { it.first }
|
||||||
|
}
|
||||||
|
catch (e: ConcurrentModificationException) { /* skip update for this frame */ }
|
||||||
|
|
||||||
|
// allocated map
|
||||||
|
mallocMap.forEachIndexed { index, (ptr, size) ->
|
||||||
|
for (i in 0 until size) {
|
||||||
|
paintPixel(ptr + i, plotColset[ptr % plotColset.size])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val memmapTex = Texture(memmapPixmap)
|
||||||
|
|
||||||
|
batch.inUse {
|
||||||
|
// draw allocation map
|
||||||
|
batch.color = COL_WELL
|
||||||
|
batch.fillRect(x, y, 512, 256)
|
||||||
|
batch.color = Color.WHITE
|
||||||
|
batch.draw(memmapTex, x, y)
|
||||||
|
|
||||||
|
// draw textual list
|
||||||
|
mallocMap.forEachIndexed { index, (ptr, size) ->
|
||||||
|
// hackishly draw textual list
|
||||||
|
if (index < 52) {
|
||||||
|
val xoff = 15f + 155f * (index / 13)
|
||||||
|
val yoff = 286f + ((index % 13) * FONT.H)
|
||||||
|
|
||||||
|
batch.color = plotColours[ptr % plotColset.size]
|
||||||
|
batch.fillRect(xoff, yoff + 1, 10, 10)
|
||||||
|
batch.color = Color.WHITE
|
||||||
|
FONT.draw(batch, " $size at $ptr", xoff, yoff)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memmapTex.dispose()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun paintPixel(index: Int, colour: Int) {
|
||||||
|
memmapPixmap.setColor(colour)
|
||||||
|
memmapPixmap.drawPixel(index / 256, index % 256)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dispose() {
|
||||||
|
memmapPixmap.dispose()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -206,7 +206,10 @@ class ProfilesMenu(parent: VMEmuExecutable, x: Int, y: Int, w: Int, h: Int) : Em
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun SpriteBatch.setColourBy(colourIfTrue: Color = EmulatorGuiToolkit.Theme.COL_ACTIVE3, colourIfFalse: Color = Color.WHITE, predicate: () -> Boolean) {
|
override fun dispose() {
|
||||||
this.color = if (predicate()) colourIfTrue else colourIfFalse
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun SpriteBatch.setColourBy(colourIfTrue: Color = EmulatorGuiToolkit.Theme.COL_ACTIVE3, colourIfFalse: Color = Color.WHITE, predicate: () -> Boolean) {
|
||||||
|
this.color = if (predicate()) colourIfTrue else colourIfFalse
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package net.torvald.tsvm
|
|||||||
|
|
||||||
import com.badlogic.gdx.ApplicationAdapter
|
import com.badlogic.gdx.ApplicationAdapter
|
||||||
import com.badlogic.gdx.Gdx
|
import com.badlogic.gdx.Gdx
|
||||||
|
import com.badlogic.gdx.Input.Buttons
|
||||||
import com.badlogic.gdx.files.FileHandle
|
import com.badlogic.gdx.files.FileHandle
|
||||||
import com.badlogic.gdx.graphics.*
|
import com.badlogic.gdx.graphics.*
|
||||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||||
@@ -64,11 +65,11 @@ class VMEmuExecutable(val windowWidth: Int, val windowHeight: Int, var panelsX:
|
|||||||
|
|
||||||
val watchdogs = hashMapOf<String, VMWatchdog>("TEVD_SYNC" to TEVD_SYNC)
|
val watchdogs = hashMapOf<String, VMWatchdog>("TEVD_SYNC" to TEVD_SYNC)
|
||||||
|
|
||||||
private data class VMRunnerInfo(val vm: VM, val name: String)
|
data class VMRunnerInfo(val vm: VM, val name: String)
|
||||||
|
|
||||||
private val vms = arrayOfNulls<VMRunnerInfo>(this.panelsX * this.panelsY - 1) // index: # of the window where the reboot was requested
|
private val vms = arrayOfNulls<VMRunnerInfo>(this.panelsX * this.panelsY - 1) // index: # of the window where the reboot was requested
|
||||||
|
|
||||||
private var currentVMselection: Int? = 0 // null: emulator menu is selected
|
var currentVMselection: Int? = 0 // null: emulator menu is selected
|
||||||
|
|
||||||
lateinit var batch: SpriteBatch
|
lateinit var batch: SpriteBatch
|
||||||
lateinit var fbatch: FlippingSpriteBatch
|
lateinit var fbatch: FlippingSpriteBatch
|
||||||
@@ -117,6 +118,8 @@ class VMEmuExecutable(val windowWidth: Int, val windowHeight: Int, var panelsX:
|
|||||||
vms[index] = VMRunnerInfo(vm, profileName)
|
vms[index] = VMRunnerInfo(vm, profileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun getCurrentlySelectedVM(): VMRunnerInfo? = if (currentVMselection == null) null else vms[currentVMselection!!]
|
||||||
|
|
||||||
private fun writeProfilesToFile(outFile: FileHandle) {
|
private fun writeProfilesToFile(outFile: FileHandle) {
|
||||||
val out = StringBuilder()
|
val out = StringBuilder()
|
||||||
out.append('{')
|
out.append('{')
|
||||||
@@ -376,6 +379,7 @@ class VMEmuExecutable(val windowWidth: Int, val windowHeight: Int, var panelsX:
|
|||||||
|
|
||||||
override fun dispose() {
|
override fun dispose() {
|
||||||
super.dispose()
|
super.dispose()
|
||||||
|
tabs.forEach { it.dispose() }
|
||||||
batch.dispose()
|
batch.dispose()
|
||||||
fbatch.dispose()
|
fbatch.dispose()
|
||||||
fullscreenQuad.dispose()
|
fullscreenQuad.dispose()
|
||||||
@@ -390,9 +394,16 @@ class VMEmuExecutable(val windowWidth: Int, val windowHeight: Int, var panelsX:
|
|||||||
private val menuTabX = windowWidth * (panelsX-1) + 2
|
private val menuTabX = windowWidth * (panelsX-1) + 2
|
||||||
private val menuTabY =windowHeight * (panelsY-1) + FONT.H + 2
|
private val menuTabY =windowHeight * (panelsY-1) + FONT.H + 2
|
||||||
|
|
||||||
private val menuTabs = listOf("Profiles", "Machine", "COMs", "Cards", "Setup")
|
private val menuTabs = listOf("Profiles", "MMU", "Machine", "COMs", "Cards", "Setup")
|
||||||
private val tabPos = (menuTabs + "").mapIndexed { index, _ -> 1 + menuTabs.subList(0, index).sumBy { it.length } + 2 * index }
|
private val tabPos = (menuTabs + "").mapIndexed { index, _ -> 1 + menuTabs.subList(0, index).sumBy { it.length } + 2 * index }
|
||||||
private val tabs = listOf(ProfilesMenu(this, menuTabX, menuTabY, menuTabW, menuTabH))
|
private val tabs = listOf(
|
||||||
|
ProfilesMenu(this, menuTabX, menuTabY, menuTabW, menuTabH),
|
||||||
|
MMUMenu(this, menuTabX, menuTabY, menuTabW, menuTabH),
|
||||||
|
DummyMenu(this, menuTabX, menuTabY, menuTabW, menuTabH),
|
||||||
|
DummyMenu(this, menuTabX, menuTabY, menuTabW, menuTabH),
|
||||||
|
DummyMenu(this, menuTabX, menuTabY, menuTabW, menuTabH),
|
||||||
|
DummyMenu(this, menuTabX, menuTabY, menuTabW, menuTabH),
|
||||||
|
)
|
||||||
private var menuTabSel = 0
|
private var menuTabSel = 0
|
||||||
|
|
||||||
private var tabChangeRequested: Int? = 0 // null: not requested
|
private var tabChangeRequested: Int? = 0 // null: not requested
|
||||||
@@ -423,7 +434,7 @@ class VMEmuExecutable(val windowWidth: Int, val windowHeight: Int, var panelsX:
|
|||||||
FONT.draw(batch, menuTabs[k], textX, y)
|
FONT.draw(batch, menuTabs[k], textX, y)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
batch.color = EmulatorGuiToolkit.Theme.COL_TAB_NOT_SELECTED
|
batch.color = if (k % 2 == 0) EmulatorGuiToolkit.Theme.COL_TAB_NOT_SELECTED else EmulatorGuiToolkit.Theme.COL_TAB_NOT_SELECTED2
|
||||||
batch.fillRect(textX - FONT.W, y, FONT.W * (menuTabs[k].length + 2f), FONT.H.toFloat())
|
batch.fillRect(textX - FONT.W, y, FONT.W * (menuTabs[k].length + 2f), FONT.H.toFloat())
|
||||||
|
|
||||||
batch.color = EmulatorGuiToolkit.Theme.COL_ACTIVE2
|
batch.color = EmulatorGuiToolkit.Theme.COL_ACTIVE2
|
||||||
@@ -447,7 +458,22 @@ class VMEmuExecutable(val windowWidth: Int, val windowHeight: Int, var panelsX:
|
|||||||
|
|
||||||
private fun updateMenu() {
|
private fun updateMenu() {
|
||||||
// update the tab
|
// update the tab
|
||||||
|
var tabSelected = -1
|
||||||
|
val x = (panelsX - 1) * windowWidth
|
||||||
|
val y = (panelsY - 1) * windowHeight
|
||||||
|
val mx = Gdx.input.x
|
||||||
|
val my = Gdx.input.y
|
||||||
|
if (Gdx.input.isButtonPressed(Buttons.LEFT) && my in y until y + FONT.H) {
|
||||||
|
for (k in menuTabs.indices) {
|
||||||
|
val textX = x + FONT.W * tabPos[k]
|
||||||
|
if (mx in textX - FONT.W until textX - FONT.W + FONT.W * (menuTabs[k].length + 2)) {
|
||||||
|
tabSelected = k
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tabSelected >= 0 && tabSelected != menuTabSel) {
|
||||||
|
tabChangeRequested = tabSelected
|
||||||
|
}
|
||||||
|
|
||||||
// actually update the view within the tabs
|
// actually update the view within the tabs
|
||||||
tabs[menuTabSel].update()
|
tabs[menuTabSel].update()
|
||||||
@@ -584,11 +610,12 @@ object EmulatorGuiToolkit {
|
|||||||
val COL_HIGHLIGHT = Color(0xe43380ff.toInt()) // magenta
|
val COL_HIGHLIGHT = Color(0xe43380ff.toInt()) // magenta
|
||||||
val COL_DISABLED = Color(0xaaaaaaff.toInt())
|
val COL_DISABLED = Color(0xaaaaaaff.toInt())
|
||||||
|
|
||||||
val COL_TAB_NOT_SELECTED = Color(0x503cd4ff) // dark blue
|
val COL_TAB_NOT_SELECTED = Color(0x4d39cbff) // dark blue
|
||||||
|
val COL_TAB_NOT_SELECTED2 = Color(0x5949e0ff) // dark blue
|
||||||
|
|
||||||
val COL_LAND = Color(0x6b8ba2ff.toInt())
|
val COL_LAND = Color(0x6b8ba2ff.toInt())
|
||||||
val COL_WELL = Color(0x374854ff.toInt())
|
val COL_WELL = Color(0x374854ff.toInt())
|
||||||
val COL_WELL2 = Color(0x3e5261ff.toInt())
|
val COL_WELL2 = Color(0x3f5360ff.toInt())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user