mirror of
https://github.com/irmen/prog8.git
synced 2024-12-24 16:29:21 +00:00
added gfx_line function
This commit is contained in:
parent
6d343bd75d
commit
b96bb23a54
96
compiler/examples/spincube.p8
Normal file
96
compiler/examples/spincube.p8
Normal file
@ -0,0 +1,96 @@
|
||||
%option enable_floats
|
||||
|
||||
~ irq {
|
||||
word global_time
|
||||
byte time_changed
|
||||
|
||||
sub irq() {
|
||||
global_time++
|
||||
time_changed = 1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
~ main {
|
||||
|
||||
const word width = 320
|
||||
const word height = 200
|
||||
|
||||
float x1 = -1.0
|
||||
float y1 = 1.0
|
||||
|
||||
float x2 = 1.0
|
||||
float y2 = 1.0
|
||||
|
||||
float x3 = 1.0
|
||||
float y3 = -1.0
|
||||
|
||||
float x4 = -1.0
|
||||
float y4 = -1.0
|
||||
|
||||
|
||||
float rx1
|
||||
float rx2
|
||||
float rx3
|
||||
float rx4
|
||||
float ry1
|
||||
float ry2
|
||||
float ry3
|
||||
float ry4
|
||||
|
||||
sub start() {
|
||||
float t
|
||||
_vm_gfx_clearscr(0)
|
||||
|
||||
while(1) {
|
||||
if irq.time_changed {
|
||||
irq.time_changed = 0
|
||||
_vm_gfx_clearscr(0)
|
||||
_vm_gfx_text(130, 80, 5, "Spin !!!")
|
||||
t = flt(irq.global_time) / 60.0
|
||||
rotate_all(t)
|
||||
plot_pixels()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub rotate_all(t: float) {
|
||||
rx1 = x1 * cos(t) - y1 * sin(t)
|
||||
ry1 = x1 * sin(t) + y1 * cos(t)
|
||||
|
||||
rx2 = x2 * cos(t) - y2 * sin(t)
|
||||
ry2 = x2 * sin(t) + y2 * cos(t)
|
||||
|
||||
rx3 = x3 * cos(t) - y3 * sin(t)
|
||||
ry3 = x3 * sin(t) + y3 * cos(t)
|
||||
|
||||
rx4 = x4 * cos(t) - y4 * sin(t)
|
||||
ry4 = x4 * sin(t) + y4 * cos(t)
|
||||
}
|
||||
|
||||
|
||||
sub plot_pixels() {
|
||||
word sx1
|
||||
word sx2
|
||||
word sx3
|
||||
word sx4
|
||||
word sy1
|
||||
word sy2
|
||||
word sy3
|
||||
word sy4
|
||||
|
||||
sx1 = floor(rx1 * height/3 + width/2)
|
||||
sx2 = floor(rx2 * height/3 + width/2)
|
||||
sx3 = floor(rx3 * height/3 + width/2)
|
||||
sx4 = floor(rx4 * height/3 + width/2)
|
||||
sy1 = floor(ry1 * height/3 + height/2)
|
||||
sy2 = floor(ry2 * height/3 + height/2)
|
||||
sy3 = floor(ry3 * height/3 + height/2)
|
||||
sy4 = floor(ry4 * height/3 + height/2)
|
||||
|
||||
_vm_gfx_line(sx1, sy1, sx2, sy2, 1)
|
||||
_vm_gfx_line(sx2, sy2, sx3, sy3, 7)
|
||||
_vm_gfx_line(sx3, sy3, sx4, sy4, 10)
|
||||
_vm_gfx_line(sx4, sy4, sx1, sy1, 14)
|
||||
}
|
||||
}
|
25
compiler/examples/swirl.p8
Normal file
25
compiler/examples/swirl.p8
Normal file
@ -0,0 +1,25 @@
|
||||
%option enable_floats
|
||||
|
||||
~ main {
|
||||
|
||||
sub start() {
|
||||
|
||||
_vm_gfx_clearscr(0)
|
||||
_vm_gfx_text(5, 5, 7, "Swirl !!!")
|
||||
|
||||
const word width = 320
|
||||
const word height = 200
|
||||
float x
|
||||
float y
|
||||
float t
|
||||
byte color
|
||||
|
||||
while(1) {
|
||||
x = ((sin(t*1.01) +cos(t*1.1234)) * width/4.1) + width/2
|
||||
y = ((cos(t)+sin(t*0.03456)) * height/4.1) + height/2
|
||||
_vm_gfx_pixel(floor(x),floor(y), color//16)
|
||||
t += 0.01
|
||||
color++
|
||||
}
|
||||
}
|
||||
}
|
@ -201,8 +201,12 @@ class AstChecker(private val namespace: INameScope,
|
||||
.filter { it is InlineAssembly }
|
||||
.map { (it as InlineAssembly).assembly }
|
||||
.count { "rts" in it || "\trts" in it || "jmp" in it || "\tjmp" in it }
|
||||
if (amount == 0 && subroutine.returnvalues.isNotEmpty())
|
||||
if (amount == 0) {
|
||||
if(subroutine.returnvalues.isNotEmpty())
|
||||
err("subroutine has result value(s) and thus must have at least one 'return' or 'goto' in it (or 'rts' / 'jmp' in case of %asm)")
|
||||
// if there's no return statement, we add the implicit one at the end.
|
||||
subroutine.statements.add(Return(emptyList(), subroutine.position))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -530,7 +534,7 @@ class AstChecker(private val namespace: INameScope,
|
||||
else {
|
||||
for (arg in args.withIndex().zip(func.parameters)) {
|
||||
if(arg.first.value.resultingDatatype(namespace, heap) !in arg.second.possibleDatatypes)
|
||||
checkResult.add(SyntaxError("argument ${arg.first.index+1} has invalid type, expected ${arg.second.possibleDatatypes}", position))
|
||||
checkResult.add(ExpressionError("argument ${arg.first.index+1} has invalid type, expected ${arg.second.possibleDatatypes}", position))
|
||||
}
|
||||
}
|
||||
} else if(target is Subroutine) {
|
||||
@ -539,7 +543,7 @@ class AstChecker(private val namespace: INameScope,
|
||||
else {
|
||||
for (arg in args.withIndex().zip(target.parameters)) {
|
||||
if(arg.first.value.resultingDatatype(namespace, heap) != arg.second.type)
|
||||
checkResult.add(SyntaxError("argument ${arg.first.index+1} has invalid type, expected ${arg.second.type}", position))
|
||||
checkResult.add(ExpressionError("argument ${arg.first.index+1} has invalid type, expected ${arg.second.type}", position))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -68,6 +68,12 @@ val BuiltinFunctions = mapOf(
|
||||
BuiltinFunctionParam("x", listOf(DataType.BYTE, DataType.WORD)),
|
||||
BuiltinFunctionParam("y", listOf(DataType.BYTE, DataType.WORD)),
|
||||
BuiltinFunctionParam("color", listOf(DataType.BYTE))), null),
|
||||
"_vm_gfx_line" to FunctionSignature(false, listOf(
|
||||
BuiltinFunctionParam("x1", listOf(DataType.BYTE, DataType.WORD)),
|
||||
BuiltinFunctionParam("y1", listOf(DataType.BYTE, DataType.WORD)),
|
||||
BuiltinFunctionParam("x2", listOf(DataType.BYTE, DataType.WORD)),
|
||||
BuiltinFunctionParam("y2", listOf(DataType.BYTE, DataType.WORD)),
|
||||
BuiltinFunctionParam("color", listOf(DataType.BYTE))), null),
|
||||
"_vm_gfx_text" to FunctionSignature(false, listOf(
|
||||
BuiltinFunctionParam("x", listOf(DataType.BYTE, DataType.WORD)),
|
||||
BuiltinFunctionParam("y", listOf(DataType.BYTE, DataType.WORD)),
|
||||
|
@ -37,12 +37,17 @@ class BitmapScreenPanel : JPanel() {
|
||||
fun setPixel(x: Int, y: Int, color: Int) {
|
||||
image.setRGB(x, y, palette[color and 15].rgb)
|
||||
}
|
||||
fun drawLine(x1: Int, y1: Int, x2: Int, y2: Int, color: Int) {
|
||||
g2d.color = palette[color and 15]
|
||||
g2d.drawLine(x1, y1, x2, y2)
|
||||
}
|
||||
fun writeText(x: Int, y: Int, text: String, color: Int) {
|
||||
g2d.font = Font(Font.MONOSPACED, Font.PLAIN, 10)
|
||||
g2d.color = palette[color and 15]
|
||||
g2d.drawString(text, x, y + g2d.font.size - 1)
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
const val SCREENWIDTH = 320
|
||||
const val SCREENHEIGHT = 200
|
||||
|
@ -131,6 +131,7 @@ enum class Syscall(val callNr: Short) {
|
||||
GFX_PIXEL(16), // plot a pixel at (x,y,color) pushed on stack in that order
|
||||
GFX_CLEARSCR(17), // clear the screen with color pushed on stack
|
||||
GFX_TEXT(18), // write text on screen at (x,y,color,text) pushed on stack in that order
|
||||
GFX_LINE(19), // draw line on screen at (x1,y1,x2,y2,color) pushed on stack in that order
|
||||
|
||||
FUNC_SIN(66),
|
||||
FUNC_COS(67),
|
||||
@ -277,9 +278,9 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
irqStartInstruction = program.labels["irq.irq"]
|
||||
}
|
||||
|
||||
fun step(instructionCount: Int = 10000) {
|
||||
fun step(instructionCount: Int = 5000) {
|
||||
// step is invoked every 1/100 sec
|
||||
// we execute 10k instructions in one go so we end up doing 1 million vm instructions per second
|
||||
// we execute 5k instructions in one go so we end up doing 0.5 million vm instructions per second
|
||||
val start = System.currentTimeMillis()
|
||||
for(i:Int in 1..instructionCount) {
|
||||
try {
|
||||
@ -494,6 +495,13 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
val (y, x) = evalstack.pop2()
|
||||
canvas?.setPixel(x.integerValue(), y.integerValue(), color.integerValue())
|
||||
}
|
||||
Syscall.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())
|
||||
}
|
||||
Syscall.GFX_CLEARSCR -> {
|
||||
val color = evalstack.pop()
|
||||
canvas?.clearScreen(color.integerValue())
|
||||
|
@ -116,16 +116,20 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
|
||||
return when(leftDt) {
|
||||
DataType.BYTE -> {
|
||||
// BYTE can become WORD if right operand is WORD, or when value is too large for byte
|
||||
if(result.toDouble() >= 256)
|
||||
if(result.toDouble() >= 256 && rightDt!=DataType.FLOAT)
|
||||
return Value(DataType.WORD, result)
|
||||
when(rightDt) {
|
||||
DataType.BYTE -> Value(DataType.BYTE, result)
|
||||
DataType.WORD -> Value(DataType.WORD, result)
|
||||
DataType.FLOAT -> throw VmExecutionException("floating point loss of precision")
|
||||
DataType.FLOAT -> throw VmExecutionException("floating point loss of precision on byte")
|
||||
else -> throw VmExecutionException("$op on non-numeric result type")
|
||||
}
|
||||
}
|
||||
DataType.WORD -> Value(DataType.WORD, result)
|
||||
DataType.WORD -> {
|
||||
if(rightDt==DataType.FLOAT)
|
||||
throw VmExecutionException("floating point loss of precision on word")
|
||||
Value(DataType.WORD, result)
|
||||
}
|
||||
DataType.FLOAT -> Value(DataType.FLOAT, result)
|
||||
else -> throw VmExecutionException("$op on non-numeric type")
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user