chars can now have a color

This commit is contained in:
Irmen de Jong 2019-07-01 23:41:30 +02:00
parent 3242495b0b
commit a56956797a
8 changed files with 183 additions and 102 deletions

View File

@ -542,10 +542,10 @@ class AstVm(val program: Program) {
dialog.canvas.clearScreen(6)
}
"c64scr.clear_screen" -> {
dialog.canvas.clearScreen(args[0].integerValue())
dialog.canvas.clearScreen(args[0].integerValue().toShort())
}
"c64scr.setcc" -> {
dialog.canvas.setChar(args[0].integerValue(), args[1].integerValue(), args[2].integerValue().toShort())
dialog.canvas.setChar(args[0].integerValue(), args[1].integerValue(), args[2].integerValue().toShort(), args[3].integerValue().toShort())
}
"c64scr.plot" -> {
dialog.canvas.setCursorPos(args[0].integerValue(), args[1].integerValue())

View File

@ -1,6 +1,7 @@
package prog8.astvm
import prog8.compiler.target.c64.Charset
import prog8.compiler.target.c64.Colors
import prog8.compiler.target.c64.Petscii
import java.awt.*
import java.awt.event.KeyEvent
@ -47,20 +48,20 @@ class BitmapScreenPanel : KeyListener, JPanel() {
g2d.drawImage(image, 0, 0, image.width * 3, image.height * 3, null)
}
fun clearScreen(color: Int) {
g2d.background = palette[color and 15]
g2d.clearRect(0, 0, BitmapScreenPanel.SCREENWIDTH, BitmapScreenPanel.SCREENHEIGHT)
fun clearScreen(color: Short) {
g2d.background = Colors.palette[color % Colors.palette.size]
g2d.clearRect(0, 0, SCREENWIDTH, SCREENHEIGHT)
cursorX = 0
cursorY = 0
}
fun setPixel(x: Int, y: Int, color: Int) {
image.setRGB(x, y, palette[color and 15].rgb)
fun setPixel(x: Int, y: Int, color: Short) {
image.setRGB(x, y, Colors.palette[color % Colors.palette.size].rgb)
}
fun drawLine(x1: Int, y1: Int, x2: Int, y2: Int, color: Int) {
g2d.color = palette[color and 15]
fun drawLine(x1: Int, y1: Int, x2: Int, y2: Int, color: Short) {
g2d.color = Colors.palette[color % Colors.palette.size]
g2d.drawLine(x1, y1, x2, y2)
}
fun printText(text: String, color: Int, lowercase: Boolean) {
fun printText(text: String, color: Short, lowercase: Boolean) {
val t2 = text.substringBefore(0.toChar())
val lines = t2.split('\n')
for(line in lines.withIndex()) {
@ -71,15 +72,12 @@ class BitmapScreenPanel : KeyListener, JPanel() {
}
}
}
private fun printTextSingleLine(text: String, color: Int, lowercase: Boolean) {
if(color!=1) {
TODO("text can only be white for now")
}
private fun printTextSingleLine(text: String, color: Short, lowercase: Boolean) {
for(clearx in cursorX until cursorX+text.length) {
g2d.clearRect(8*clearx, 8*y, 8, 8)
}
for(sc in Petscii.encodeScreencode(text, lowercase)) {
setChar(cursorX, cursorY, sc)
setChar(cursorX, cursorY, sc, color)
cursorX++
if(cursorX>=(SCREENWIDTH/8)) {
cursorY++
@ -93,7 +91,7 @@ class BitmapScreenPanel : KeyListener, JPanel() {
cursorX=0
cursorY++
} else {
setChar(cursorX, cursorY, char)
setChar(cursorX, cursorY, char, 1)
cursorX++
if (cursorX >= (SCREENWIDTH / 8)) {
cursorY++
@ -102,9 +100,11 @@ class BitmapScreenPanel : KeyListener, JPanel() {
}
}
fun setChar(x: Int, y: Int, screenCode: Short) {
fun setChar(x: Int, y: Int, screenCode: Short, color: Short) {
g2d.clearRect(8*x, 8*y, 8, 8)
g2d.drawImage(Charset.shiftedChars[screenCode.toInt()], 8*x, 8*y , null)
val colorIdx = (color % Colors.palette.size).toShort()
val coloredImage = Charset.getColoredChar(screenCode, colorIdx)
g2d.drawImage(coloredImage, 8*x, 8*y , null)
}
fun setCursorPos(x: Int, y: Int) {
@ -116,18 +116,16 @@ class BitmapScreenPanel : KeyListener, JPanel() {
return Pair(cursorX, cursorY)
}
fun writeText(x: Int, y: Int, text: String, color: Int, lowercase: Boolean) {
fun writeText(x: Int, y: Int, text: String, color: Short, lowercase: Boolean) {
val colorIdx = (color % Colors.palette.size).toShort()
var xx=x
if(color!=1) {
TODO("text can only be white for now")
}
for(clearx in xx until xx+text.length) {
g2d.clearRect(8*clearx, 8*y, 8, 8)
}
for(sc in Petscii.encodeScreencode(text, lowercase)) {
if(sc==0.toShort())
break
setChar(xx++, y, sc)
setChar(xx++, y, sc, colorIdx)
}
}
@ -136,24 +134,6 @@ class BitmapScreenPanel : KeyListener, JPanel() {
const val SCREENWIDTH = 320
const val SCREENHEIGHT = 200
const val SCALING = 3
val palette = listOf( // this is Pepto's Commodore-64 palette http://www.pepto.de/projects/colorvic/
Color(0x000000), // 0 = black
Color(0xFFFFFF), // 1 = white
Color(0x813338), // 2 = red
Color(0x75cec8), // 3 = cyan
Color(0x8e3c97), // 4 = purple
Color(0x56ac4d), // 5 = green
Color(0x2e2c9b), // 6 = blue
Color(0xedf171), // 7 = yellow
Color(0x8e5029), // 8 = orange
Color(0x553800), // 9 = brown
Color(0xc46c71), // 10 = light red
Color(0x4a4a4a), // 11 = dark grey
Color(0x7b7b7b), // 12 = medium grey
Color(0xa9ff9f), // 13 = light green
Color(0x706deb), // 14 = light blue
Color(0xb2b2b2) // 15 = light grey
)
}
}
@ -171,19 +151,19 @@ class ScreenDialog : JFrame() {
// the borders (top, left, right, bottom)
val borderTop = JPanel().apply {
preferredSize = Dimension(BitmapScreenPanel.SCALING * (BitmapScreenPanel.SCREENWIDTH+2*borderWidth), BitmapScreenPanel.SCALING * borderWidth)
background = BitmapScreenPanel.palette[14]
background = Colors.palette[14]
}
val borderBottom = JPanel().apply {
preferredSize =Dimension(BitmapScreenPanel.SCALING * (BitmapScreenPanel.SCREENWIDTH+2*borderWidth), BitmapScreenPanel.SCALING * borderWidth)
background = BitmapScreenPanel.palette[14]
background = Colors.palette[14]
}
val borderLeft = JPanel().apply {
preferredSize =Dimension(BitmapScreenPanel.SCALING * borderWidth, BitmapScreenPanel.SCALING * BitmapScreenPanel.SCREENHEIGHT)
background = BitmapScreenPanel.palette[14]
background = Colors.palette[14]
}
val borderRight = JPanel().apply {
preferredSize =Dimension(BitmapScreenPanel.SCALING * borderWidth, BitmapScreenPanel.SCALING * BitmapScreenPanel.SCREENHEIGHT)
background = BitmapScreenPanel.palette[14]
background = Colors.palette[14]
}
var c = GridBagConstraints()
c.gridx=0; c.gridy=1; c.gridwidth=3

View File

@ -183,4 +183,60 @@ object Charset {
val normalChars = scanChars(normalImg)
val shiftedChars = scanChars(shiftedImg)
private val coloredNormalChars = mutableMapOf<Short, Array<BufferedImage>>()
fun getColoredChar(screenCode: Short, color: Short): BufferedImage {
val colorIdx = (color % Colors.palette.size).toShort()
val chars = coloredNormalChars[colorIdx]
if(chars!=null)
return chars[screenCode.toInt()]
val coloredChars = mutableListOf<BufferedImage>()
val transparent = Color(0,0,0,0).rgb
val rgb = Colors.palette[colorIdx.toInt()].rgb
for(c in normalChars) {
val colored = c.copy()
for(y in 0 until colored.height)
for(x in 0 until colored.width) {
if(colored.getRGB(x, y)!=transparent) {
colored.setRGB(x, y, rgb)
}
}
coloredChars.add(colored)
}
coloredNormalChars[colorIdx] = coloredChars.toTypedArray()
return coloredNormalChars.getValue(colorIdx)[screenCode.toInt()]
}
}
private fun BufferedImage.copy(): BufferedImage {
val bcopy = BufferedImage(this.width, this.height, this.type)
val g = bcopy.graphics
g.drawImage(this, 0, 0, null)
g.dispose()
return bcopy
}
object Colors {
val palette = listOf( // this is Pepto's Commodore-64 palette http://www.pepto.de/projects/colorvic/
Color(0x000000), // 0 = black
Color(0xFFFFFF), // 1 = white
Color(0x813338), // 2 = red
Color(0x75cec8), // 3 = cyan
Color(0x8e3c97), // 4 = purple
Color(0x56ac4d), // 5 = green
Color(0x2e2c9b), // 6 = blue
Color(0xedf171), // 7 = yellow
Color(0x8e5029), // 8 = orange
Color(0x553800), // 9 = brown
Color(0xc46c71), // 10 = light red
Color(0x4a4a4a), // 11 = dark grey
Color(0x7b7b7b), // 12 = medium grey
Color(0xa9ff9f), // 13 = light green
Color(0x706deb), // 14 = light blue
Color(0xb2b2b2) // 15 = light grey
)
}

View File

@ -6,6 +6,9 @@ import kotlin.math.log2
/*
todo advanced expression optimization: common (sub) expression elimination (turn common expressions into single subroutine call + introduce variable to hold it)
Also see https://egorbo.com/peephole-optimizations.html
*/
internal class SimplifyExpressions(private val program: Program) : IAstProcessor {

View File

@ -8,7 +8,7 @@ import kotlin.math.floor
/*
todo: subroutines with 1 or 2 byte args or 1 word arg can be converted to asm sub calling convention (args in registers)
todo: implement usage counters for labels, variables (locals and heap), blocks. Remove if count is zero.
todo: implement usage counters for variables (locals and heap), blocks. Remove if count is zero.
todo analyse for unreachable code and remove that (f.i. code after goto or return that has no label so can never be jumped to) + print warning about this
*/

View File

@ -1,6 +1,7 @@
package prog8.stackvm
import prog8.compiler.target.c64.Charset
import prog8.compiler.target.c64.Colors
import prog8.compiler.target.c64.Petscii
import java.awt.*
import java.awt.event.KeyEvent
@ -47,20 +48,20 @@ class BitmapScreenPanel : KeyListener, JPanel() {
g2d.drawImage(image, 0, 0, image.width * 3, image.height * 3, null)
}
fun clearScreen(color: Int) {
g2d.background = palette[color and 15]
g2d.clearRect(0, 0, BitmapScreenPanel.SCREENWIDTH, BitmapScreenPanel.SCREENHEIGHT)
fun clearScreen(color: Short) {
g2d.background = Colors.palette[color % Colors.palette.size]
g2d.clearRect(0, 0, SCREENWIDTH, SCREENHEIGHT)
cursorX = 0
cursorY = 0
}
fun setPixel(x: Int, y: Int, color: Int) {
image.setRGB(x, y, palette[color and 15].rgb)
fun setPixel(x: Int, y: Int, color: Short) {
image.setRGB(x, y, Colors.palette[color % Colors.palette.size].rgb)
}
fun drawLine(x1: Int, y1: Int, x2: Int, y2: Int, color: Int) {
g2d.color = palette[color and 15]
fun drawLine(x1: Int, y1: Int, x2: Int, y2: Int, color: Short) {
g2d.color = Colors.palette[color % Colors.palette.size]
g2d.drawLine(x1, y1, x2, y2)
}
fun printText(text: String, color: Int, lowercase: Boolean) {
fun printText(text: String, color: Short, lowercase: Boolean) {
val lines = text.split('\n')
for(line in lines.withIndex()) {
printTextSingleLine(line.value, color, lowercase)
@ -70,15 +71,12 @@ class BitmapScreenPanel : KeyListener, JPanel() {
}
}
}
private fun printTextSingleLine(text: String, color: Int, lowercase: Boolean) {
if(color!=1) {
TODO("text can only be white for now")
}
private fun printTextSingleLine(text: String, color: Short, lowercase: Boolean) {
for(clearx in cursorX until cursorX+text.length) {
g2d.clearRect(8*clearx, 8*y, 8, 8)
}
for(sc in Petscii.encodeScreencode(text, lowercase)) {
setChar(cursorX, cursorY, sc)
setChar(cursorX, cursorY, sc, color)
cursorX++
if(cursorX>=(SCREENWIDTH/8)) {
cursorY++
@ -92,7 +90,7 @@ class BitmapScreenPanel : KeyListener, JPanel() {
cursorX=0
cursorY++
} else {
setChar(cursorX, cursorY, char)
setChar(cursorX, cursorY, char, 1)
cursorX++
if (cursorX >= (SCREENWIDTH / 8)) {
cursorY++
@ -101,9 +99,11 @@ class BitmapScreenPanel : KeyListener, JPanel() {
}
}
fun setChar(x: Int, y: Int, screenCode: Short) {
fun setChar(x: Int, y: Int, screenCode: Short, color: Short) {
g2d.clearRect(8*x, 8*y, 8, 8)
g2d.drawImage(Charset.shiftedChars[screenCode.toInt()], 8*x, 8*y , null)
val colorIdx = (color % Colors.palette.size).toShort()
val coloredImage = Charset.getColoredChar(screenCode, colorIdx)
g2d.drawImage(coloredImage, 8*x, 8*y , null)
}
fun setCursorPos(x: Int, y: Int) {
@ -115,16 +115,13 @@ class BitmapScreenPanel : KeyListener, JPanel() {
return Pair(cursorX, cursorY)
}
fun writeText(x: Int, y: Int, text: String, color: Int, lowercase: Boolean) {
fun writeText(x: Int, y: Int, text: String, color: Short, lowercase: Boolean) {
var xx=x
if(color!=1) {
TODO("text can only be white for now")
}
for(clearx in xx until xx+text.length) {
g2d.clearRect(8*clearx, 8*y, 8, 8)
}
for(sc in Petscii.encodeScreencode(text, lowercase)) {
setChar(xx++, y, sc)
setChar(xx++, y, sc, color)
}
}
@ -133,24 +130,6 @@ class BitmapScreenPanel : KeyListener, JPanel() {
const val SCREENWIDTH = 320
const val SCREENHEIGHT = 200
const val SCALING = 3
val palette = listOf( // this is Pepto's Commodore-64 palette http://www.pepto.de/projects/colorvic/
Color(0x000000), // 0 = black
Color(0xFFFFFF), // 1 = white
Color(0x813338), // 2 = red
Color(0x75cec8), // 3 = cyan
Color(0x8e3c97), // 4 = purple
Color(0x56ac4d), // 5 = green
Color(0x2e2c9b), // 6 = blue
Color(0xedf171), // 7 = yellow
Color(0x8e5029), // 8 = orange
Color(0x553800), // 9 = brown
Color(0xc46c71), // 10 = light red
Color(0x4a4a4a), // 11 = dark grey
Color(0x7b7b7b), // 12 = medium grey
Color(0xa9ff9f), // 13 = light green
Color(0x706deb), // 14 = light blue
Color(0xb2b2b2) // 15 = light grey
)
}
}
@ -168,19 +147,19 @@ class ScreenDialog : JFrame() {
// the borders (top, left, right, bottom)
val borderTop = JPanel().apply {
preferredSize = Dimension(BitmapScreenPanel.SCALING * (BitmapScreenPanel.SCREENWIDTH+2*borderWidth), BitmapScreenPanel.SCALING * borderWidth)
background = BitmapScreenPanel.palette[14]
background = Colors.palette[14]
}
val borderBottom = JPanel().apply {
preferredSize =Dimension(BitmapScreenPanel.SCALING * (BitmapScreenPanel.SCREENWIDTH+2*borderWidth), BitmapScreenPanel.SCALING * borderWidth)
background = BitmapScreenPanel.palette[14]
background = Colors.palette[14]
}
val borderLeft = JPanel().apply {
preferredSize =Dimension(BitmapScreenPanel.SCALING * borderWidth, BitmapScreenPanel.SCALING * BitmapScreenPanel.SCREENHEIGHT)
background = BitmapScreenPanel.palette[14]
background = Colors.palette[14]
}
val borderRight = JPanel().apply {
preferredSize =Dimension(BitmapScreenPanel.SCALING * borderWidth, BitmapScreenPanel.SCALING * BitmapScreenPanel.SCREENHEIGHT)
background = BitmapScreenPanel.palette[14]
background = Colors.palette[14]
}
var c = GridBagConstraints()
c.gridx=0; c.gridy=1; c.gridwidth=3

View File

@ -1886,7 +1886,7 @@ class StackVm(private var traceOutputFile: String?) {
else {
when(ins.callLabel) {
"c64.CLEARSCR" -> {
canvas?.clearScreen(mem.getUByte(0xd021).toInt())
canvas?.clearScreen(mem.getUByte(0xd021))
callstack.pop()
}
"c64.CHROUT" -> {
@ -1974,25 +1974,25 @@ class StackVm(private var traceOutputFile: String?) {
// plot pixel at (x, y, color) from stack
val color = evalstack.pop()
val (y, x) = evalstack.pop2()
canvas?.setPixel(x.integerValue(), y.integerValue(), color.integerValue())
canvas?.setPixel(x.integerValue(), y.integerValue(), color.integerValue().toShort())
}
Syscall.VM_GFX_LINE -> {
// draw line at (x1, y1, x2, y2, color) from stack
val color = evalstack.pop()
val (y2, x2) = evalstack.pop2()
val (y1, x1) = evalstack.pop2()
canvas?.drawLine(x1.integerValue(), y1.integerValue(), x2.integerValue(), y2.integerValue(), color.integerValue())
canvas?.drawLine(x1.integerValue(), y1.integerValue(), x2.integerValue(), y2.integerValue(), color.integerValue().toShort())
}
Syscall.VM_GFX_CLEARSCR -> {
val color = evalstack.pop()
canvas?.clearScreen(color.integerValue())
canvas?.clearScreen(color.integerValue().toShort())
}
Syscall.VM_GFX_TEXT -> {
val textPtr = evalstack.pop().integerValue()
val color = evalstack.pop()
val (cy, cx) = evalstack.pop2()
val text = heap.get(textPtr)
canvas?.writeText(cx.integerValue(), cy.integerValue(), text.str!!, color.integerValue(), true)
canvas?.writeText(cx.integerValue(), cy.integerValue(), text.str!!, color.integerValue().toShort(), true)
}
Syscall.FUNC_RND -> evalstack.push(RuntimeValue(DataType.UBYTE, rnd.nextInt() and 255))
Syscall.FUNC_RNDW -> evalstack.push(RuntimeValue(DataType.UWORD, rnd.nextInt() and 65535))
@ -2317,8 +2317,8 @@ class StackVm(private var traceOutputFile: String?) {
val x = variables.getValue("c64scr.setcc.column").integerValue()
val y = variables.getValue("c64scr.setcc.row").integerValue()
val char = variables.getValue("c64scr.setcc.char").integerValue()
// val color = variables.getValue("c64scr.setcc.color").integerValue() // text color other than 1 (white) can't be used right now
canvas?.setChar(x, y, char.toShort())
val color = variables.getValue("c64scr.setcc.color").integerValue()
canvas?.setChar(x, y, char.toShort(), color.toShort())
}
else -> throw VmExecutionException("unimplemented syscall $syscall")
}

View File

@ -1,17 +1,80 @@
;%import c64utils
;%zeropage basicsafe
%import c64flt
%import c64utils
%zeropage basicsafe
~ main {
sub start() {
c64scr.setcc(0,0,160,0)
c64scr.setcc(0,1,160,1)
c64scr.setcc(0,2,160,2)
c64scr.setcc(0,3,160,3)
c64scr.setcc(0,4,160,4)
c64scr.setcc(0,5,160,5)
c64scr.setcc(0,6,160,6)
c64scr.setcc(0,7,160,7)
c64scr.setcc(0,8,160,8)
c64scr.setcc(0,9,160,9)
c64scr.setcc(0,10,160,10)
c64scr.setcc(0,11,160,11)
c64scr.setcc(0,12,160,12)
c64scr.setcc(0,13,160,13)
c64scr.setcc(0,14,160,14)
c64scr.setcc(0,15,160,15)
;float[] xcoor = [ -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0 ]
c64scr.setcc(1,0,160,0)
c64scr.setcc(1,1,160,1)
c64scr.setcc(1,2,160,2)
c64scr.setcc(1,3,160,3)
c64scr.setcc(1,4,160,4)
c64scr.setcc(1,5,160,5)
c64scr.setcc(1,6,160,6)
c64scr.setcc(1,7,160,7)
c64scr.setcc(1,8,160,8)
c64scr.setcc(1,9,160,9)
c64scr.setcc(1,10,160,10)
c64scr.setcc(1,11,160,11)
c64scr.setcc(1,12,160,12)
c64scr.setcc(1,13,160,13)
c64scr.setcc(1,14,160,14)
c64scr.setcc(1,15,160,15)
c64scr.setcc(2,0,160,0)
c64scr.setcc(2,1,160,1)
c64scr.setcc(2,2,160,2)
c64scr.setcc(2,3,160,3)
c64scr.setcc(2,4,160,4)
c64scr.setcc(2,5,160,5)
c64scr.setcc(2,6,160,6)
c64scr.setcc(2,7,160,7)
c64scr.setcc(2,8,160,8)
c64scr.setcc(2,9,160,9)
c64scr.setcc(2,10,160,10)
c64scr.setcc(2,11,160,11)
c64scr.setcc(2,12,160,12)
c64scr.setcc(2,13,160,13)
c64scr.setcc(2,14,160,14)
c64scr.setcc(2,15,160,15)
_x:
goto _x
; for ubyte y in 0 to 3 {
; for ubyte x in 0 to 10 {
; ubyte product = x*y
; c64scr.setcc(x, y, 160, product)
; }
; }
; c64.CHROUT('\n')
; c64.CHROUT('\n')
;
; for ubyte y in 12 to 15 {
; for ubyte x in 0 to 10 {
; ubyte sumv = x+y
; c64scr.setcc(x, y, 160, sumv)
; }
; }
float x
float z = sin(x) * 3
;ubyte bb = len(xcoor)
; storage for rotated coordinates