mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-06-10 15:04:03 +09:00
gpu: framebuffer is now UnsafePtr instead of being Pixmap
This commit is contained in:
@@ -155,7 +155,7 @@ From the start of the memory space:
|
|||||||
1 byte
|
1 byte
|
||||||
command (writing to this memory address changes the status)
|
command (writing to this memory address changes the status)
|
||||||
1: reset palette to default
|
1: reset palette to default
|
||||||
2: fill framebuffer with given colour (arg1)
|
2: fill framebuffer with given colour (arg1). If framebuffer 2 is there, it will be filled with arg2
|
||||||
3: do '1' then do '2'
|
3: do '1' then do '2'
|
||||||
|
|
||||||
16: copy Low Font ROM (char 0–127) to mapping area
|
16: copy Low Font ROM (char 0–127) to mapping area
|
||||||
|
|||||||
@@ -16,11 +16,7 @@ class DMADelegate(val vm: VM) {
|
|||||||
|
|
||||||
fun ramToFrame(from: Int, devnum: Int, offset: Int, length: Int) {
|
fun ramToFrame(from: Int, devnum: Int, offset: Int, length: Int) {
|
||||||
(vm.peripheralTable[devnum].peripheral as? GraphicsAdapter)?.let {
|
(vm.peripheralTable[devnum].peripheral as? GraphicsAdapter)?.let {
|
||||||
val data = ByteArray(length)
|
UnsafeHelper.memcpyRaw(null, vm.usermem.ptr + from, null, it.framebuffer.ptr + offset, length.toLong())
|
||||||
UnsafeHelper.memcpyRaw(null, vm.usermem.ptr + from, data, UnsafeHelper.getArrayOffset(data), length.toLong())
|
|
||||||
it.framebuffer.pixels.position(offset)
|
|
||||||
it.framebuffer.pixels.put(data)
|
|
||||||
it.framebuffer.pixels.position(0) // rewinding to avoid graphical glitch
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,11 +31,7 @@ class DMADelegate(val vm: VM) {
|
|||||||
|
|
||||||
fun frameToRam(from: Int, to: Int, devnum: Int, length: Int) {
|
fun frameToRam(from: Int, to: Int, devnum: Int, length: Int) {
|
||||||
(vm.peripheralTable[devnum].peripheral as? GraphicsAdapter)?.let {
|
(vm.peripheralTable[devnum].peripheral as? GraphicsAdapter)?.let {
|
||||||
val data = ByteArray(length)
|
UnsafeHelper.memcpyRaw(null, it.framebuffer.ptr + from, null, vm.usermem.ptr + to, length.toLong())
|
||||||
it.framebuffer.pixels.position(from)
|
|
||||||
it.framebuffer.pixels.get(data)
|
|
||||||
it.framebuffer.pixels.position(0) // rewinding to avoid graphical glitch
|
|
||||||
UnsafeHelper.memcpyRaw(data, UnsafeHelper.getArrayOffset(data), null, vm.usermem.ptr + to, length.toLong())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,8 +69,8 @@ class GraphicsJSR223Delegate(val vm: VM) {
|
|||||||
|
|
||||||
fun scrollFrame(xdelta: Int, ydelta: Int) {
|
fun scrollFrame(xdelta: Int, ydelta: Int) {
|
||||||
getFirstGPU()?.let {
|
getFirstGPU()?.let {
|
||||||
it.framebufferScrollX = (it.framebufferScrollX + xdelta) fmod it.framebuffer.width
|
it.framebufferScrollX = (it.framebufferScrollX + xdelta) fmod it.WIDTH
|
||||||
it.framebufferScrollY = (it.framebufferScrollY + ydelta) fmod it.framebuffer.height
|
it.framebufferScrollY = (it.framebufferScrollY + ydelta) fmod it.HEIGHT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +97,7 @@ class GraphicsJSR223Delegate(val vm: VM) {
|
|||||||
fun getGraphicsMode() = getFirstGPU()?.mmio_read(12L)?.toUint() ?: 0
|
fun getGraphicsMode() = getFirstGPU()?.mmio_read(12L)?.toUint() ?: 0
|
||||||
|
|
||||||
fun getPixelDimension(): IntArray {
|
fun getPixelDimension(): IntArray {
|
||||||
getFirstGPU()?.let { return intArrayOf(it.framebuffer.width, it.framebuffer.height) }
|
getFirstGPU()?.let { return intArrayOf(it.WIDTH, it.HEIGHT) }
|
||||||
return intArrayOf(-1, -1)
|
return intArrayOf(-1, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,16 +54,17 @@ open class GraphicsAdapter(private val assetsRoot: String, val vm: VM, val confi
|
|||||||
return vm
|
return vm
|
||||||
}
|
}
|
||||||
|
|
||||||
protected val WIDTH = config.width
|
val WIDTH = config.width
|
||||||
protected val HEIGHT = config.height
|
val HEIGHT = config.height
|
||||||
protected val VRAM_SIZE = config.vramSize
|
val VRAM_SIZE = config.vramSize
|
||||||
protected val TTY_FORE_DEFAULT = config.ttyDefaultFore
|
protected val TTY_FORE_DEFAULT = config.ttyDefaultFore
|
||||||
protected val TTY_BACK_DEFAULT = config.ttyDefaultBack
|
protected val TTY_BACK_DEFAULT = config.ttyDefaultBack
|
||||||
protected val theme = config.theme
|
protected val theme = config.theme
|
||||||
protected val TAB_SIZE = 8
|
protected val TAB_SIZE = 8
|
||||||
|
|
||||||
internal val framebuffer = Pixmap(WIDTH, HEIGHT, Pixmap.Format.Alpha)
|
internal val framebuffer = UnsafeHelper.allocate(WIDTH.toLong() * HEIGHT)//Pixmap(WIDTH, HEIGHT, Pixmap.Format.Alpha)
|
||||||
internal val framebuffer2 = Pixmap(WIDTH, HEIGHT, Pixmap.Format.RGBA8888)
|
internal val framebuffer2 = if (sgr.bankCount >= 2) UnsafeHelper.allocate(WIDTH.toLong() * HEIGHT) else null
|
||||||
|
internal val framebufferOut = Pixmap(WIDTH, HEIGHT, Pixmap.Format.RGBA8888)
|
||||||
protected var rendertex = Texture(1, 1, Pixmap.Format.RGBA8888)
|
protected var rendertex = Texture(1, 1, Pixmap.Format.RGBA8888)
|
||||||
internal val paletteOfFloats = FloatArray(1024) {
|
internal val paletteOfFloats = FloatArray(1024) {
|
||||||
val rgba = DEFAULT_PALETTE[it / 4]
|
val rgba = DEFAULT_PALETTE[it / 4]
|
||||||
@@ -159,12 +160,11 @@ open class GraphicsAdapter(private val assetsRoot: String, val vm: VM, val confi
|
|||||||
outFBObatch.projectionMatrix = m
|
outFBObatch.projectionMatrix = m
|
||||||
|
|
||||||
|
|
||||||
framebuffer.blending = Pixmap.Blending.None
|
framebufferOut.blending = Pixmap.Blending.None
|
||||||
framebuffer2.blending = Pixmap.Blending.None
|
|
||||||
textForePixmap.blending = Pixmap.Blending.None
|
textForePixmap.blending = Pixmap.Blending.None
|
||||||
textBackPixmap.blending = Pixmap.Blending.None
|
textBackPixmap.blending = Pixmap.Blending.None
|
||||||
framebuffer.setColor(-1)
|
framebuffer.fillWith(-1) // FF for palette mode, RGBA(15, 15, x, x) for direct colour
|
||||||
framebuffer.fill()
|
framebuffer2?.fillWith(-16) // RGBA(x, x, 15, 0) for direct colour
|
||||||
|
|
||||||
unusedArea.fillWith(0)
|
unusedArea.fillWith(0)
|
||||||
scanlineOffsets.fillWith(0)
|
scanlineOffsets.fillWith(0)
|
||||||
@@ -191,14 +191,18 @@ open class GraphicsAdapter(private val assetsRoot: String, val vm: VM, val confi
|
|||||||
}
|
}
|
||||||
|
|
||||||
setCursorPos(0, 0)
|
setCursorPos(0, 0)
|
||||||
|
|
||||||
println("Framebuffer pixels limit: ${framebuffer.pixels.limit()}")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun peek(addr: Long): Byte? {
|
override fun peek(addr: Long): Byte? {
|
||||||
val adi = addr.toInt()
|
val adi = addr.toInt()
|
||||||
|
if (framebuffer2 != null) {
|
||||||
|
return when (addr - 262144) {
|
||||||
|
in 0 until 250880 -> framebuffer2[addr]
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
return when (addr) {
|
return when (addr) {
|
||||||
in 0 until 250880 -> framebuffer.pixels.get(adi)//framebuffer.getPixel(adi % WIDTH, adi / WIDTH).toByte()
|
in 0 until 250880 -> framebuffer[addr]
|
||||||
in 252030 until 252030+1920 -> mappedFontRom[adi- 252030]
|
in 252030 until 252030+1920 -> mappedFontRom[adi- 252030]
|
||||||
in 250880 until 250880+1024 -> unusedArea[addr - 250880]
|
in 250880 until 250880+1024 -> unusedArea[addr - 250880]
|
||||||
in 253950 until 261632 -> textArea[addr - 253950]
|
in 253950 until 261632 -> textArea[addr - 253950]
|
||||||
@@ -214,10 +218,19 @@ open class GraphicsAdapter(private val assetsRoot: String, val vm: VM, val confi
|
|||||||
override fun poke(addr: Long, byte: Byte) {
|
override fun poke(addr: Long, byte: Byte) {
|
||||||
val adi = addr.toInt()
|
val adi = addr.toInt()
|
||||||
val bi = byte.toInt().and(255)
|
val bi = byte.toInt().and(255)
|
||||||
|
if (framebuffer2 != null) {
|
||||||
|
when (addr - 262144) {
|
||||||
|
in 0 until 250880 -> {
|
||||||
|
lastUsedColour = byte
|
||||||
|
framebuffer2[addr] = byte
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
when (addr) {
|
when (addr) {
|
||||||
in 0 until 250880 -> {
|
in 0 until 250880 -> {
|
||||||
lastUsedColour = byte
|
lastUsedColour = byte
|
||||||
framebuffer.pixels.put(adi, byte)
|
framebuffer[addr] = byte
|
||||||
}
|
}
|
||||||
250883L -> {
|
250883L -> {
|
||||||
unusedArea[addr - 250880] = byte
|
unusedArea[addr - 250880] = byte
|
||||||
@@ -311,8 +324,8 @@ open class GraphicsAdapter(private val assetsRoot: String, val vm: VM, val confi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
2 -> {
|
2 -> {
|
||||||
framebuffer.setColor(0f,0f,0f,arg1 / 255f)
|
framebuffer.fillWith(arg1.toByte())
|
||||||
framebuffer.fill()
|
framebuffer2?.fillWith(arg2.toByte())
|
||||||
}
|
}
|
||||||
3 -> {
|
3 -> {
|
||||||
for (it in 0 until 1024) {
|
for (it in 0 until 1024) {
|
||||||
@@ -320,8 +333,8 @@ open class GraphicsAdapter(private val assetsRoot: String, val vm: VM, val confi
|
|||||||
val channel = it % 4
|
val channel = it % 4
|
||||||
rgba.shr((3 - channel) * 8).and(255) / 255f
|
rgba.shr((3 - channel) * 8).and(255) / 255f
|
||||||
}
|
}
|
||||||
framebuffer.setColor(0f,0f,0f,arg1 / 255f)
|
framebuffer.fillWith(arg1.toByte())
|
||||||
framebuffer.fill()
|
framebuffer2?.fillWith(arg2.toByte())
|
||||||
}
|
}
|
||||||
16, 17 -> readFontRom(opcode - 16)
|
16, 17 -> readFontRom(opcode - 16)
|
||||||
18, 19 -> writeFontRom(opcode - 18)
|
18, 19 -> writeFontRom(opcode - 18)
|
||||||
@@ -335,8 +348,8 @@ open class GraphicsAdapter(private val assetsRoot: String, val vm: VM, val confi
|
|||||||
open fun readFontRom(mode: Int) {
|
open fun readFontRom(mode: Int) {
|
||||||
// max char size: 8*15
|
// max char size: 8*15
|
||||||
fontRomMappingMode = mode
|
fontRomMappingMode = mode
|
||||||
val cw = config.width / config.textCols
|
val cw = WIDTH / config.textCols
|
||||||
val ch = config.height / config.textRows
|
val ch = HEIGHT / config.textRows
|
||||||
if (cw > 8 || ch > 15) throw UnsupportedOperationException()
|
if (cw > 8 || ch > 15) throw UnsupportedOperationException()
|
||||||
|
|
||||||
val pixmap = chrrom
|
val pixmap = chrrom
|
||||||
@@ -368,8 +381,8 @@ open class GraphicsAdapter(private val assetsRoot: String, val vm: VM, val confi
|
|||||||
open fun writeFontRom(mode: Int) {
|
open fun writeFontRom(mode: Int) {
|
||||||
// max char size: 8*15
|
// max char size: 8*15
|
||||||
fontRomMappingMode = mode
|
fontRomMappingMode = mode
|
||||||
val cw = config.width / config.textCols
|
val cw = WIDTH / config.textCols
|
||||||
val ch = config.height / config.textRows
|
val ch = HEIGHT / config.textRows
|
||||||
|
|
||||||
if (cw > 8 || ch > 15) throw UnsupportedOperationException()
|
if (cw > 8 || ch > 15) throw UnsupportedOperationException()
|
||||||
|
|
||||||
@@ -701,8 +714,9 @@ open class GraphicsAdapter(private val assetsRoot: String, val vm: VM, val confi
|
|||||||
|
|
||||||
override fun dispose() {
|
override fun dispose() {
|
||||||
//testTex.dispose()
|
//testTex.dispose()
|
||||||
framebuffer.dispose()
|
framebuffer.destroy()
|
||||||
framebuffer2.dispose()
|
framebuffer2?.destroy()
|
||||||
|
framebufferOut.dispose()
|
||||||
rendertex.dispose()
|
rendertex.dispose()
|
||||||
textArea.destroy()
|
textArea.destroy()
|
||||||
textForePixmap.dispose()
|
textForePixmap.dispose()
|
||||||
@@ -733,18 +747,18 @@ open class GraphicsAdapter(private val assetsRoot: String, val vm: VM, val confi
|
|||||||
unusedArea[1].toInt().and(15).toFloat() / 15f,
|
unusedArea[1].toInt().and(15).toFloat() / 15f,
|
||||||
unusedArea[2].toInt().and(15).toFloat() / 15f, 1f)
|
unusedArea[2].toInt().and(15).toFloat() / 15f, 1f)
|
||||||
|
|
||||||
private val isRefSize = (config.width == 560 && config.height == 448)
|
private val isRefSize = (WIDTH == 560 && HEIGHT == 448)
|
||||||
|
|
||||||
open fun render(delta: Float, uiBatch: SpriteBatch, xoff: Float, yoff: Float, flipY: Boolean = false, uiFBO: FrameBuffer? = null) {
|
open fun render(delta: Float, uiBatch: SpriteBatch, xoff: Float, yoff: Float, flipY: Boolean = false, uiFBO: FrameBuffer? = null) {
|
||||||
uiFBO?.end()
|
uiFBO?.end()
|
||||||
|
|
||||||
|
|
||||||
// must reset positions as pixmaps expect them to be zero
|
// must reset positions as pixmaps expect them to be zero
|
||||||
framebuffer.pixels.position(0)
|
framebufferOut.pixels.position(0)
|
||||||
framebuffer2.pixels.position(0)
|
|
||||||
chrrom.pixels.position(0)
|
chrrom.pixels.position(0)
|
||||||
|
|
||||||
framebuffer2.setColor(-1);framebuffer2.fill()
|
framebufferOut.setColor(-1);framebufferOut.fill()
|
||||||
|
// if (isRefSize && graphicsMode == 4 && )
|
||||||
if (isRefSize && (graphicsMode == 1 || graphicsMode == 2)) {
|
if (isRefSize && (graphicsMode == 1 || graphicsMode == 2)) {
|
||||||
val layerOrder = (if (graphicsMode == 1) LAYERORDERS4 else LAYERORDERS2)[layerArrangement]
|
val layerOrder = (if (graphicsMode == 1) LAYERORDERS4 else LAYERORDERS2)[layerArrangement]
|
||||||
for (y in 0..223) {
|
for (y in 0..223) {
|
||||||
@@ -756,7 +770,7 @@ open class GraphicsAdapter(private val assetsRoot: String, val vm: VM, val confi
|
|||||||
for (x in xs) {
|
for (x in xs) {
|
||||||
val colour = layerOrder.map { layer ->
|
val colour = layerOrder.map { layer ->
|
||||||
if (graphicsMode == 1) {
|
if (graphicsMode == 1) {
|
||||||
val colourIndex = framebuffer.pixels.get((280 * 224 * layer) + (y * 280 + x)).toUint()
|
val colourIndex = framebuffer[(280L * 224 * layer) + (y * 280 + x)].toUint()
|
||||||
Color(
|
Color(
|
||||||
paletteOfFloats[4 * colourIndex],
|
paletteOfFloats[4 * colourIndex],
|
||||||
paletteOfFloats[4 * colourIndex + 1],
|
paletteOfFloats[4 * colourIndex + 1],
|
||||||
@@ -765,8 +779,8 @@ open class GraphicsAdapter(private val assetsRoot: String, val vm: VM, val confi
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val lowBits = framebuffer.pixels.get((280 * 224 * layer * 2) + (y * 280 + x)).toUint()
|
val lowBits = framebuffer[(280L * 224 * layer * 2) + (y * 280 + x)].toUint()
|
||||||
val highBits = framebuffer.pixels.get((280 * 224 * (layer*2 + 1)) + (y * 280 + x)).toUint()
|
val highBits = framebuffer[(280L * 224 * (layer*2 + 1)) + (y * 280 + x)].toUint()
|
||||||
val r = lowBits.ushr(4).and(15)
|
val r = lowBits.ushr(4).and(15)
|
||||||
val g = lowBits.and(15)
|
val g = lowBits.and(15)
|
||||||
val b = highBits.ushr(4).and(15)
|
val b = highBits.ushr(4).and(15)
|
||||||
@@ -793,31 +807,31 @@ open class GraphicsAdapter(private val assetsRoot: String, val vm: VM, val confi
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
framebuffer2.setColor(colour)
|
framebufferOut.setColor(colour)
|
||||||
framebuffer2.drawPixel(x*2, y*2)
|
framebufferOut.drawPixel(x*2, y*2)
|
||||||
framebuffer2.drawPixel(x*2+1, y*2)
|
framebufferOut.drawPixel(x*2+1, y*2)
|
||||||
framebuffer2.drawPixel(x*2, y*2+1)
|
framebufferOut.drawPixel(x*2, y*2+1)
|
||||||
framebuffer2.drawPixel(x*2+1, y*2+1)
|
framebufferOut.drawPixel(x*2+1, y*2+1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (y in 0 until config.height) {
|
for (y in 0 until HEIGHT) {
|
||||||
var xoff = scanlineOffsets[2L * y].toUint() or scanlineOffsets[2L * y + 1].toUint().shl(8)
|
var xoff = scanlineOffsets[2L * y].toUint() or scanlineOffsets[2L * y + 1].toUint().shl(8)
|
||||||
if (xoff.and(0x8000) != 0) xoff = xoff or 0xFFFF0000.toInt()
|
if (xoff.and(0x8000) != 0) xoff = xoff or 0xFFFF0000.toInt()
|
||||||
val xs = (0 + xoff).coerceIn(0, config.width - 1)..(config.width - 1 + xoff).coerceIn(0, config.width - 1)
|
val xs = (0 + xoff).coerceIn(0, WIDTH - 1)..(WIDTH - 1 + xoff).coerceIn(0, WIDTH - 1)
|
||||||
|
|
||||||
if (xoff in -(config.width - 1) until config.width) {
|
if (xoff in -(WIDTH - 1) until WIDTH) {
|
||||||
for (x in xs) {
|
for (x in xs) {
|
||||||
// this only works because framebuffer is guaranteed to be 8bpp
|
// this only works because framebuffer is guaranteed to be 8bpp
|
||||||
/*framebuffer2.pixels.put(
|
/*framebuffer2.pixels.put(
|
||||||
y * config.width + x,
|
y * WIDTH + x,
|
||||||
framebuffer.pixels.get(y * config.width + (x - xoff)) // coerceIn not required as (x - xoff) never escapes 0..559
|
framebuffer.pixels.get(y * WIDTH + (x - xoff)) // coerceIn not required as (x - xoff) never escapes 0..559
|
||||||
)*/
|
)*/
|
||||||
val colourIndex = framebuffer.pixels.get(y * config.width + (x - xoff)).toUint() // coerceIn not required as (x - xoff) never escapes 0..559
|
val colourIndex = framebuffer[y.toLong() * WIDTH + (x - xoff)].toUint() // coerceIn not required as (x - xoff) never escapes 0..559
|
||||||
framebuffer2.setColor(paletteOfFloats[4*colourIndex], paletteOfFloats[4*colourIndex+1], paletteOfFloats[4*colourIndex+2], paletteOfFloats[4*colourIndex+3])
|
framebufferOut.setColor(paletteOfFloats[4*colourIndex], paletteOfFloats[4*colourIndex+1], paletteOfFloats[4*colourIndex+2], paletteOfFloats[4*colourIndex+3])
|
||||||
framebuffer2.drawPixel(x, y)
|
framebufferOut.drawPixel(x, y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -826,10 +840,10 @@ open class GraphicsAdapter(private val assetsRoot: String, val vm: VM, val confi
|
|||||||
chrrom0.dispose()
|
chrrom0.dispose()
|
||||||
chrrom0 = Texture(chrrom)
|
chrrom0 = Texture(chrrom)
|
||||||
rendertex.dispose()
|
rendertex.dispose()
|
||||||
rendertex = Texture(framebuffer2, Pixmap.Format.RGBA8888, false)
|
rendertex = Texture(framebufferOut, Pixmap.Format.RGBA8888, false)
|
||||||
|
|
||||||
val texOffX = (framebufferScrollX fmod framebuffer.width) * -1f
|
val texOffX = (framebufferScrollX fmod WIDTH) * -1f
|
||||||
val texOffY = (framebufferScrollY fmod framebuffer.height) * 1f
|
val texOffY = (framebufferScrollY fmod HEIGHT) * 1f
|
||||||
|
|
||||||
outFBOs[1].inUse {
|
outFBOs[1].inUse {
|
||||||
outFBObatch.inUse {
|
outFBObatch.inUse {
|
||||||
@@ -868,9 +882,9 @@ open class GraphicsAdapter(private val assetsRoot: String, val vm: VM, val confi
|
|||||||
|
|
||||||
// draw framebuffer
|
// draw framebuffer
|
||||||
outFBObatch.draw(rendertex, texOffX, texOffY)
|
outFBObatch.draw(rendertex, texOffX, texOffY)
|
||||||
outFBObatch.draw(rendertex, texOffX + framebuffer.width, texOffY)
|
outFBObatch.draw(rendertex, texOffX + WIDTH, texOffY)
|
||||||
outFBObatch.draw(rendertex, texOffX + framebuffer.width, texOffY - framebuffer.height)
|
outFBObatch.draw(rendertex, texOffX + WIDTH, texOffY - HEIGHT)
|
||||||
outFBObatch.draw(rendertex, texOffX, texOffY - framebuffer.height)
|
outFBObatch.draw(rendertex, texOffX, texOffY - HEIGHT)
|
||||||
|
|
||||||
// draw texts or sprites
|
// draw texts or sprites
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user