mirror of
https://github.com/irmen/ksim65.git
synced 2024-06-06 22:29:33 +00:00
replaced fixed 8x16 bitmap font by psf font
This commit is contained in:
parent
3925c80258
commit
d1d433c3a6
36
README.md
36
README.md
|
@ -6,9 +6,6 @@ JCenter: [![Download from Jcenter](https://api.bintray.com/packages/irmen/maven/
|
||||||
|
|
||||||
*Written by Irmen de Jong (irmen@razorvine.net)*
|
*Written by Irmen de Jong (irmen@razorvine.net)*
|
||||||
|
|
||||||
*Software license: MIT, see file LICENSE*
|
|
||||||
|
|
||||||
|
|
||||||
![6502](https://upload.wikimedia.org/wikipedia/commons/thumb/4/43/KL_MOS_6502.jpg/320px-KL_MOS_6502.jpg)
|
![6502](https://upload.wikimedia.org/wikipedia/commons/thumb/4/43/KL_MOS_6502.jpg/320px-KL_MOS_6502.jpg)
|
||||||
|
|
||||||
This is a Kotlin/JVM library that simulates the 8-bit 6502 and 65C02 microprocessors,
|
This is a Kotlin/JVM library that simulates the 8-bit 6502 and 65C02 microprocessors,
|
||||||
|
@ -67,3 +64,36 @@ various timers and IRQs. It's not cycle perfect, and the video display is drawn
|
||||||
so raster splits/rasterbars are impossible. But many other things work fine.
|
so raster splits/rasterbars are impossible. But many other things work fine.
|
||||||
|
|
||||||
![C64 emulation](c64.png)
|
![C64 emulation](c64.png)
|
||||||
|
|
||||||
|
|
||||||
|
### License information
|
||||||
|
|
||||||
|
Ksim65 itself is licensed under the MIT software license, see file LICENSE.
|
||||||
|
|
||||||
|
It includes the 'Spleen' bitmap font (https://github.com/fcambus/spleen),
|
||||||
|
which has the following license (BSD):
|
||||||
|
|
||||||
|
Copyright (c) 2018-2020, Frederic Cambus
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
|
||||||
|
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
|
@ -1,57 +1,27 @@
|
||||||
package razorvine.examplemachines
|
package razorvine.examplemachines
|
||||||
|
|
||||||
|
import razorvine.fonts.PsfFont
|
||||||
import razorvine.ksim65.*
|
import razorvine.ksim65.*
|
||||||
import java.awt.*
|
import java.awt.*
|
||||||
import java.awt.event.*
|
import java.awt.event.*
|
||||||
import java.awt.image.BufferedImage
|
import java.awt.image.BufferedImage
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.imageio.ImageIO
|
|
||||||
import javax.swing.*
|
import javax.swing.*
|
||||||
import javax.swing.event.MouseInputListener
|
import javax.swing.event.MouseInputListener
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define a monochrome screen that can display 640x480 pixels
|
* Define a monochrome screen that can display 80x30 charaacters
|
||||||
* and/or 80x30 characters (these are 8x16 pixels).
|
* (usually equivalent to 640x480 pixels, but depends on the font size)
|
||||||
*/
|
*/
|
||||||
object ScreenDefs {
|
object ScreenDefs {
|
||||||
const val SCREEN_WIDTH_CHARS = 80
|
const val COLUMNS = 80
|
||||||
const val SCREEN_HEIGHT_CHARS = 30
|
const val ROWS = 30
|
||||||
const val SCREEN_WIDTH = SCREEN_WIDTH_CHARS*8
|
|
||||||
const val SCREEN_HEIGHT = SCREEN_HEIGHT_CHARS*16
|
|
||||||
const val PIXEL_SCALING = 1.5
|
|
||||||
const val BORDER_SIZE = 32
|
const val BORDER_SIZE = 32
|
||||||
|
|
||||||
val BG_COLOR = Color(0, 10, 20)
|
val BG_COLOR = Color(0, 10, 20)
|
||||||
val FG_COLOR = Color(200, 255, 230)
|
val FG_COLOR = Color(200, 255, 230)
|
||||||
val BORDER_COLOR = Color(20, 30, 40)
|
val BORDER_COLOR = Color(20, 30, 40)
|
||||||
val Characters = loadCharacters()
|
|
||||||
|
|
||||||
private fun loadCharacters(): Array<BufferedImage> {
|
|
||||||
val img = ImageIO.read(javaClass.getResourceAsStream("/charset/unscii8x16.png"))
|
|
||||||
val charactersImage = BufferedImage(img.width, img.height, BufferedImage.TYPE_INT_ARGB)
|
|
||||||
charactersImage.createGraphics().drawImage(img, 0, 0, null)
|
|
||||||
|
|
||||||
val black = Color(0, 0, 0).rgb
|
|
||||||
val foreground = FG_COLOR.rgb
|
|
||||||
val nopixel = Color(0, 0, 0, 0).rgb
|
|
||||||
for (y in 0 until charactersImage.height) {
|
|
||||||
for (x in 0 until charactersImage.width) {
|
|
||||||
val col = charactersImage.getRGB(x, y)
|
|
||||||
if (col == black) charactersImage.setRGB(x, y, nopixel)
|
|
||||||
else charactersImage.setRGB(x, y, foreground)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val numColumns = charactersImage.width/8
|
|
||||||
val charImages = (0..255).map {
|
|
||||||
val charX = it%numColumns
|
|
||||||
val charY = it/numColumns
|
|
||||||
charactersImage.getSubimage(charX*8, charY*16, 8, 16)
|
|
||||||
}
|
|
||||||
|
|
||||||
return charImages.toTypedArray()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class BitmapScreenPanel : JPanel() {
|
private class BitmapScreenPanel : JPanel() {
|
||||||
|
@ -61,15 +31,21 @@ private class BitmapScreenPanel : JPanel() {
|
||||||
private var cursorX: Int = 0
|
private var cursorX: Int = 0
|
||||||
private var cursorY: Int = 0
|
private var cursorY: Int = 0
|
||||||
private var cursorState: Boolean = false
|
private var cursorState: Boolean = false
|
||||||
|
private val screenFont = PsfFont("spleen-12x24") // nice fonts: sun12x22, iso01-12x22, ter-124b, spleen-12x24, default8x16
|
||||||
|
private val PIXEL_SCALING: Double = if(screenFont.width <= 8) 1.5 else 1.0
|
||||||
|
private val screenFontImage: BufferedImage
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
println("SCREENFONT WIDTH: ${screenFont.width}")
|
||||||
|
|
||||||
val ge = GraphicsEnvironment.getLocalGraphicsEnvironment()
|
val ge = GraphicsEnvironment.getLocalGraphicsEnvironment()
|
||||||
val gd = ge.defaultScreenDevice.defaultConfiguration
|
val gd = ge.defaultScreenDevice.defaultConfiguration
|
||||||
image = gd.createCompatibleImage(ScreenDefs.SCREEN_WIDTH, ScreenDefs.SCREEN_HEIGHT, Transparency.OPAQUE)
|
image = gd.createCompatibleImage(ScreenDefs.COLUMNS*screenFont.width, ScreenDefs.ROWS*screenFont.height, Transparency.OPAQUE)
|
||||||
g2d = image.graphics as Graphics2D
|
g2d = image.graphics as Graphics2D
|
||||||
|
screenFontImage = screenFont.convertToImage(g2d, ScreenDefs.FG_COLOR)
|
||||||
|
|
||||||
val size = Dimension((image.width*ScreenDefs.PIXEL_SCALING).toInt(),
|
val size = Dimension((image.width*PIXEL_SCALING).toInt(),
|
||||||
(image.height*ScreenDefs.PIXEL_SCALING).toInt())
|
(image.height*PIXEL_SCALING).toInt())
|
||||||
minimumSize = size
|
minimumSize = size
|
||||||
maximumSize = size
|
maximumSize = size
|
||||||
preferredSize = size
|
preferredSize = size
|
||||||
|
@ -82,13 +58,13 @@ private class BitmapScreenPanel : JPanel() {
|
||||||
override fun paint(graphics: Graphics) {
|
override fun paint(graphics: Graphics) {
|
||||||
val g2d = graphics as Graphics2D
|
val g2d = graphics as Graphics2D
|
||||||
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR)
|
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR)
|
||||||
g2d.drawImage(image, 0, 0, (image.width*ScreenDefs.PIXEL_SCALING).toInt(),
|
g2d.drawImage(image, 0, 0, (image.width*PIXEL_SCALING).toInt(),
|
||||||
(image.height*ScreenDefs.PIXEL_SCALING).toInt(), null)
|
(image.height*PIXEL_SCALING).toInt(), null)
|
||||||
if (cursorState) {
|
if (cursorState) {
|
||||||
val scx = (cursorX*ScreenDefs.PIXEL_SCALING*8).toInt()
|
val scx = (cursorX*PIXEL_SCALING*screenFont.width).toInt()
|
||||||
val scy = (cursorY*ScreenDefs.PIXEL_SCALING*16).toInt()
|
val scy = (cursorY*PIXEL_SCALING*screenFont.height).toInt()
|
||||||
val scw = (8*ScreenDefs.PIXEL_SCALING).toInt()
|
val scw = (screenFont.width*PIXEL_SCALING).toInt()
|
||||||
val sch = (16*ScreenDefs.PIXEL_SCALING).toInt()
|
val sch = (screenFont.height*PIXEL_SCALING).toInt()
|
||||||
g2d.setXORMode(Color.CYAN)
|
g2d.setXORMode(Color.CYAN)
|
||||||
g2d.fillRect(scx, scy, scw, sch)
|
g2d.fillRect(scx, scy, scw, sch)
|
||||||
g2d.setPaintMode()
|
g2d.setPaintMode()
|
||||||
|
@ -98,7 +74,7 @@ private class BitmapScreenPanel : JPanel() {
|
||||||
|
|
||||||
fun clearScreen() {
|
fun clearScreen() {
|
||||||
g2d.background = ScreenDefs.BG_COLOR
|
g2d.background = ScreenDefs.BG_COLOR
|
||||||
g2d.clearRect(0, 0, ScreenDefs.SCREEN_WIDTH, ScreenDefs.SCREEN_HEIGHT)
|
g2d.clearRect(0, 0, ScreenDefs.COLUMNS*screenFont.width, ScreenDefs.ROWS*screenFont.height)
|
||||||
cursorPos(0, 0)
|
cursorPos(0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,20 +86,26 @@ private class BitmapScreenPanel : JPanel() {
|
||||||
fun getPixel(x: Int, y: Int) = image.getRGB(x, y) != ScreenDefs.BG_COLOR.rgb
|
fun getPixel(x: Int, y: Int) = image.getRGB(x, y) != ScreenDefs.BG_COLOR.rgb
|
||||||
|
|
||||||
fun setChar(x: Int, y: Int, character: Char) {
|
fun setChar(x: Int, y: Int, character: Char) {
|
||||||
g2d.clearRect(8*x, 16*y, 8, 16)
|
val charnum = character.toInt()
|
||||||
val coloredImage = ScreenDefs.Characters[character.toInt()]
|
val cx = charnum % (screenFontImage.width/screenFont.width)
|
||||||
g2d.drawImage(coloredImage, 8*x, 16*y, null)
|
val cy = charnum / (screenFontImage.width/screenFont.width)
|
||||||
|
g2d.clearRect(x*screenFont.width, y*screenFont.height, screenFont.width, screenFont.height)
|
||||||
|
g2d.drawImage(screenFontImage, x*screenFont.width, y*screenFont.height, (x+1)*screenFont.width,
|
||||||
|
(y+1)*screenFont.height, cx*screenFont.width, cy*screenFont.height,
|
||||||
|
(cx+1)*screenFont.width, (cy+1)*screenFont.height, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun scrollUp() {
|
fun scrollUp() {
|
||||||
g2d.copyArea(0, 16, ScreenDefs.SCREEN_WIDTH, ScreenDefs.SCREEN_HEIGHT-16, 0, -16)
|
g2d.copyArea(0, screenFont.height,
|
||||||
|
ScreenDefs.COLUMNS*screenFont.width, (ScreenDefs.ROWS-1)*screenFont.height,
|
||||||
|
0, -screenFont.height)
|
||||||
g2d.background = ScreenDefs.BG_COLOR
|
g2d.background = ScreenDefs.BG_COLOR
|
||||||
g2d.clearRect(0, ScreenDefs.SCREEN_HEIGHT-16, ScreenDefs.SCREEN_WIDTH, 16)
|
g2d.clearRect(0, (ScreenDefs.ROWS-1)*screenFont.height, ScreenDefs.COLUMNS*screenFont.width, screenFont.height)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun mousePixelPosition(): Point? {
|
fun mousePixelPosition(): Point? {
|
||||||
val pos = mousePosition ?: return null
|
val pos = mousePosition ?: return null
|
||||||
return Point((pos.x/ScreenDefs.PIXEL_SCALING).toInt(), (pos.y/ScreenDefs.PIXEL_SCALING).toInt())
|
return Point((pos.x/PIXEL_SCALING).toInt(), (pos.y/PIXEL_SCALING).toInt())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun cursorPos(x: Int, y: Int) {
|
fun cursorPos(x: Int, y: Int) {
|
||||||
|
|
|
@ -21,7 +21,7 @@ class EhBasicMachine(title: String) {
|
||||||
val rom = Rom(0xc000, 0xffff).also { it.load(javaClass.getResourceAsStream("/ehbasic_C000.bin").readBytes()) }
|
val rom = Rom(0xc000, 0xffff).also { it.load(javaClass.getResourceAsStream("/ehbasic_C000.bin").readBytes()) }
|
||||||
|
|
||||||
private val hostDisplay = MainWindow(title)
|
private val hostDisplay = MainWindow(title)
|
||||||
private val display = Display(0xd000, 0xd00a, hostDisplay, ScreenDefs.SCREEN_WIDTH_CHARS, ScreenDefs.SCREEN_HEIGHT_CHARS)
|
private val display = Display(0xd000, 0xd00a, hostDisplay, ScreenDefs.COLUMNS, ScreenDefs.ROWS)
|
||||||
private val keyboard = Keyboard(0xd400, 0xd400, hostDisplay)
|
private val keyboard = Keyboard(0xd400, 0xd400, hostDisplay)
|
||||||
private var paused = false
|
private var paused = false
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ class VirtualMachine(title: String) : IVirtualMachine {
|
||||||
private val monitor = Monitor(bus, cpu)
|
private val monitor = Monitor(bus, cpu)
|
||||||
private val debugWindow = DebugWindow(this)
|
private val debugWindow = DebugWindow(this)
|
||||||
private val hostDisplay = MainWindow(title)
|
private val hostDisplay = MainWindow(title)
|
||||||
private val display = Display(0xd000, 0xd00a, hostDisplay, ScreenDefs.SCREEN_WIDTH_CHARS, ScreenDefs.SCREEN_HEIGHT_CHARS)
|
private val display = Display(0xd000, 0xd00a, hostDisplay, ScreenDefs.COLUMNS, ScreenDefs.ROWS)
|
||||||
private val mouse = Mouse(0xd300, 0xd305, hostDisplay)
|
private val mouse = Mouse(0xd300, 0xd305, hostDisplay)
|
||||||
private val keyboard = Keyboard(0xd400, 0xd400, hostDisplay)
|
private val keyboard = Keyboard(0xd400, 0xd400, hostDisplay)
|
||||||
private var paused = false
|
private var paused = false
|
||||||
|
|
138
src/main/kotlin/razorvine/fonts/PsfFont.kt
Normal file
138
src/main/kotlin/razorvine/fonts/PsfFont.kt
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
package razorvine.fonts
|
||||||
|
|
||||||
|
import java.awt.Color
|
||||||
|
import java.awt.Graphics2D
|
||||||
|
import java.awt.Transparency
|
||||||
|
import java.awt.image.BufferedImage
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileInputStream
|
||||||
|
import java.io.IOException
|
||||||
|
import java.util.zip.GZIPInputStream
|
||||||
|
|
||||||
|
|
||||||
|
class PsfFont(name: String) {
|
||||||
|
|
||||||
|
// font format info: https://www.win.tue.nl/~aeb/linux/kbd/font-formats-1.html
|
||||||
|
|
||||||
|
val numChars: Int
|
||||||
|
val bytesPerChar: Int
|
||||||
|
val height: Int
|
||||||
|
val width: Int
|
||||||
|
private val hasUnicodeTable: Boolean
|
||||||
|
private val rawBitmaps: List<ByteArray>
|
||||||
|
|
||||||
|
init {
|
||||||
|
var data = ByteArray(0)
|
||||||
|
val fontsDirectory = "/usr/share/kbd/consolefonts"
|
||||||
|
var stream = javaClass.getResourceAsStream("/charset/$name.psfu.gz") ?:
|
||||||
|
javaClass.getResourceAsStream("/charset/$name.psf.gz") ?:
|
||||||
|
(if(File("$fontsDirectory/$name.psfu.gz").exists()) FileInputStream("$fontsDirectory/$name.psfu.gz") else null ) ?:
|
||||||
|
(if(File("$fontsDirectory/$name.psf.gz").exists()) FileInputStream("$fontsDirectory/$name.psf.gz") else null ) ?:
|
||||||
|
(if(File("$fontsDirectory/$name.fnt.gz").exists()) FileInputStream("$fontsDirectory/$name.fnt.gz") else null )
|
||||||
|
if(stream==null) {
|
||||||
|
stream = javaClass.getResourceAsStream("/charset/$name.psfu") ?:
|
||||||
|
javaClass.getResourceAsStream("/charset/$name.psf") ?:
|
||||||
|
(if(File("$fontsDirectory/$name.psfu").exists()) FileInputStream("$fontsDirectory/$name.psfu") else null ) ?:
|
||||||
|
(if(File("$fontsDirectory/$name.psf").exists()) FileInputStream("$fontsDirectory/$name.psf") else null ) ?:
|
||||||
|
(if(File("$fontsDirectory/$name.fnt").exists()) FileInputStream("$fontsDirectory/$name.fnt") else null ) ?:
|
||||||
|
throw IOException("no such font: $name")
|
||||||
|
data = stream.readBytes()
|
||||||
|
} else {
|
||||||
|
GZIPInputStream(stream).use { data = it.readBytes() }
|
||||||
|
}
|
||||||
|
stream.close()
|
||||||
|
|
||||||
|
if (data[0] == 0x36.toByte() && data[1] == 0x04.toByte()) {
|
||||||
|
// continue reading PSF1 font
|
||||||
|
val mode = data[2].toInt()
|
||||||
|
numChars = if (mode and 1 != 0) 512 else 256
|
||||||
|
bytesPerChar = data[3].toInt()
|
||||||
|
hasUnicodeTable = mode and 2 != 0
|
||||||
|
height = bytesPerChar
|
||||||
|
width = 8
|
||||||
|
rawBitmaps = (0..numChars).map {
|
||||||
|
data.sliceArray(3+it*bytesPerChar..3+(it+1)*bytesPerChar)
|
||||||
|
}
|
||||||
|
// ignore unicode table for now: val table = stream.readAllBytes()
|
||||||
|
} else {
|
||||||
|
if (data[0] == 0x72.toByte() && data[1] == 0xb5.toByte() && data[2] == 0x4a.toByte() && data[3] == 0x86.toByte()) {
|
||||||
|
// continue reading PSF2 font
|
||||||
|
// skip the version val version = makeInt(data, 4)
|
||||||
|
val headersize = makeInt(data, 8)
|
||||||
|
val flags = makeInt(data, 12)
|
||||||
|
hasUnicodeTable = flags and 1 != 0
|
||||||
|
numChars = makeInt(data, 16)
|
||||||
|
bytesPerChar = makeInt(data, 20)
|
||||||
|
height = makeInt(data, 24)
|
||||||
|
width = makeInt(data, 28)
|
||||||
|
rawBitmaps = (0..numChars).map {
|
||||||
|
data.sliceArray(headersize+it*bytesPerChar..headersize+(it+1)*bytesPerChar)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
hasUnicodeTable = false
|
||||||
|
numChars = 0
|
||||||
|
bytesPerChar = 0
|
||||||
|
height = 0
|
||||||
|
width = 0
|
||||||
|
rawBitmaps = emptyList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun convertToImage(gfx: Graphics2D, textColor: Color): BufferedImage {
|
||||||
|
// create a single image with all the characters in a vertical column from top to bottom.
|
||||||
|
val bitmap = gfx.deviceConfiguration.createCompatibleImage((width+7) and 0b11111000, height*numChars, Transparency.BITMASK)
|
||||||
|
val bytesHoriz = (width+7)/8
|
||||||
|
val color = textColor.rgb
|
||||||
|
val nopixel = Color(0, 0, 0, 0).rgb
|
||||||
|
for (char in 0 until numChars) {
|
||||||
|
for (b in 0 until bytesPerChar) {
|
||||||
|
val c = rawBitmaps[char][b].toInt()
|
||||||
|
val ix = 8*(b%bytesHoriz)
|
||||||
|
val iy = b/bytesHoriz+char*height
|
||||||
|
bitmap.setRGB(ix, iy, if (c and 0b10000000 != 0) color else nopixel)
|
||||||
|
bitmap.setRGB(ix+1, iy, if (c and 0b01000000 != 0) color else nopixel)
|
||||||
|
bitmap.setRGB(ix+2, iy, if (c and 0b00100000 != 0) color else nopixel)
|
||||||
|
bitmap.setRGB(ix+3, iy, if (c and 0b00010000 != 0) color else nopixel)
|
||||||
|
bitmap.setRGB(ix+4, iy, if (c and 0b00001000 != 0) color else nopixel)
|
||||||
|
bitmap.setRGB(ix+5, iy, if (c and 0b00000100 != 0) color else nopixel)
|
||||||
|
bitmap.setRGB(ix+6, iy, if (c and 0b00000010 != 0) color else nopixel)
|
||||||
|
bitmap.setRGB(ix+7, iy, if (c and 0b00000001 != 0) color else nopixel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bitmap
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun makeInt(bytes: ByteArray, offset: Int) =
|
||||||
|
makeInt(bytes[offset], bytes[offset+1], bytes[offset+2], bytes[offset+3])
|
||||||
|
private fun makeInt(b0: Byte, b1: Byte, b2: Byte, b3: Byte) =
|
||||||
|
b0.toInt() or (b1.toInt() shl 8) or (b2.toInt() shl 16) or (b3.toInt() shl 24)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// private fun loadFallbackCharacters(): Array<BufferedImage> {
|
||||||
|
// val img = ImageIO.read(javaClass.getResourceAsStream("/charset/unscii8x16.png"))
|
||||||
|
// val charactersImage = BufferedImage(img.width, img.height, BufferedImage.TYPE_INT_ARGB)
|
||||||
|
// charactersImage.createGraphics().drawImage(img, 0, 0, null)
|
||||||
|
//
|
||||||
|
// val black = Color(0, 0, 0).rgb
|
||||||
|
// val foreground = FG_COLOR.rgb
|
||||||
|
// val nopixel = Color(0, 0, 0, 0).rgb
|
||||||
|
// for (y in 0 until charactersImage.height) {
|
||||||
|
// for (x in 0 until charactersImage.width) {
|
||||||
|
// val col = charactersImage.getRGB(x, y)
|
||||||
|
// if (col == black) charactersImage.setRGB(x, y, nopixel)
|
||||||
|
// else charactersImage.setRGB(x, y, foreground)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// val numColumns = charactersImage.width/8
|
||||||
|
// val charImages = (0..255).map {
|
||||||
|
// val charX = it%numColumns
|
||||||
|
// val charY = it/numColumns
|
||||||
|
// charactersImage.getSubimage(charX*8, charY*16, 8, 16)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return charImages.toTypedArray()
|
||||||
|
// }
|
|
@ -102,7 +102,7 @@ class Display(startAddress: Address, endAddress: Address, private val host: IHos
|
||||||
0x05 -> pixelY = (pixelY and 0xff00) or data.toInt()
|
0x05 -> pixelY = (pixelY and 0xff00) or data.toInt()
|
||||||
0x06 -> pixelY = (pixelY and 0x00ff) or (data.toInt() shl 8)
|
0x06 -> pixelY = (pixelY and 0x00ff) or (data.toInt() shl 8)
|
||||||
0x07 -> {
|
0x07 -> {
|
||||||
if (pixelX in 0 until ScreenDefs.SCREEN_WIDTH && pixelY in 0 until ScreenDefs.SCREEN_HEIGHT) {
|
if (pixelX in 0 until ScreenDefs.COLUMNS*charWidth && pixelY in 0 until ScreenDefs.ROWS*charHeight) {
|
||||||
if (data == 0.toShort()) host.clearPixel(pixelX, pixelY)
|
if (data == 0.toShort()) host.clearPixel(pixelX, pixelY)
|
||||||
else host.setPixel(pixelX, pixelY)
|
else host.setPixel(pixelX, pixelY)
|
||||||
}
|
}
|
||||||
|
|
BIN
src/main/resources/charset/spleen-12x24.psfu.gz
Normal file
BIN
src/main/resources/charset/spleen-12x24.psfu.gz
Normal file
Binary file not shown.
BIN
src/main/resources/charset/spleen-16x32.psfu.gz
Normal file
BIN
src/main/resources/charset/spleen-16x32.psfu.gz
Normal file
Binary file not shown.
BIN
src/main/resources/charset/spleen-8x16.psfu.gz
Normal file
BIN
src/main/resources/charset/spleen-8x16.psfu.gz
Normal file
Binary file not shown.
24
src/main/resources/charset/spleen-LICENSE
Normal file
24
src/main/resources/charset/spleen-LICENSE
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
Copyright (c) 2018-2020, Frederic Cambus
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
|
||||||
|
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
Binary file not shown.
Before Width: | Height: | Size: 1.5 KiB |
Loading…
Reference in New Issue
Block a user