Files
microw8/platform/src/platform.cwa

674 lines
15 KiB
Plaintext

import "env.memory" memory(4);
import "env.sin" fn sin(f32) -> f32;
import "env.cos" fn cos(f32) -> f32;
import "env.pow" fn pow(f32, f32) -> f32;
import "env.exp" fn exp(f32) -> f32;
import "env.logChar" fn logChar(i32);
export fn time() -> f32 {
(0!64) as f32 / 1000 as f32
}
///////////
// INPUT //
///////////
export fn isButtonPressed(btn: i32) -> i32 {
(68!0 >> btn) & 1
}
export fn isButtonTriggered(btn: i32) -> i32 {
((68!0 & (-1 - 68!4)) >> btn) & 1
}
////////////
// RANDOM //
////////////
global mut randomState: i64 = 37i64;
export fn random() -> i32 {
(random64() >> 32i64) as i32
}
export fn random64() -> i64 {
let lazy state = randomState ^ (randomState #>> 12i64);
let lazy state = state ^ (state << 25i64);
randomState = state ^ (state #>> 27i64);
randomState * 0x2545f4914f6cdd1di64
}
export fn randomf() -> f32 {
f32.reinterpret_i32(0x3f800000 | (random() #>> 9)) - 1 as f32
}
export fn randomSeed(s: i32) {
randomState = (s as i64 << 32i64) ^ ((63 - s) as i64);
randomState = random64();
randomState = random64();
}
export fn fmod(a: f32, b: f32) -> f32 {
a - floor(a / b) * b
}
/////////////
// DRAWING //
/////////////
export fn cls(col: i32) {
let i: i32;
textCursorX = 0;
textCursorY = 0;
outputChannel = 0;
memory.fill(120, col, 320*240);
}
export fn setPixel(x: i32, y: i32, col: i32) {
if x #< 320 & y #< 240 {
(x + y * 320)?120 = col
}
}
export fn getPixel(x: i32, y: i32) -> i32 {
if x #< 320 & y #< 240 {
(x + y * 320)?120
} else {
0
}
}
fn clamp(v: i32, min: i32, max: i32) -> i32 {
select(v < min, min, select(v > max, max, v))
}
export fn hline(x1: i32, x2: i32, y: i32, col: i32) {
x1 = clamp(x1, 0, 320);
x2 = clamp(x2, 0, 320);
if y #>= 240 {
return;
}
let word_start = (x1 + 3) & -4;
let word_end = x2 & -4;
if word_end > word_start {
col = (col & 255) * 0x1010101;
let ptr = y * 320 + x1;
let end = ptr + word_start - x1;
if ptr + 2 <= end {
ptr?120 = col;
ptr?121 = col;
ptr += 2;
}
if ptr < end {
ptr?120 = col;
ptr += 1;
}
end += word_end - word_start;
loop words {
if ptr + 16 <= end {
ptr!120 = col;
ptr!124 = col;
ptr!128 = col;
ptr!132 = col;
ptr += 16;
branch words;
}
if ptr + 8 <= end {
ptr!120 = col;
ptr!124 = col;
ptr += 8;
}
if ptr < end {
ptr!120 = col;
ptr += 4;
}
}
end += x2 - word_end;
if ptr + 2 <= end {
ptr?120 = col;
ptr?121 = col;
ptr += 2;
}
if ptr < end {
ptr?120 = col;
}
} else {
let ptr = y * 320 + x1;
let end = ptr + x2 - x1;
if ptr + 4 <= end {
ptr?120 = col;
ptr?121 = col;
ptr?122 = col;
ptr?123 = col;
ptr += 4;
}
if ptr + 2 <= end {
ptr?120 = col;
ptr?121 = col;
ptr += 2;
}
if ptr < end {
ptr?120 = col;
}
}
}
export fn rectangle(x: f32, y: f32, w: f32, h: f32, col: i32) {
if abs(w) == w & abs(h) == h {
let x1 = nearest(x) as i32;
let y1 = clamp(nearest(y) as i32, 0, 240);
let x2 = nearest(x + w) as i32;
let y2 = clamp(nearest(y + h) as i32, 0, 240);
block done {
loop lines {
branch_if y1 >= y2: done;
hline(x1, x2, y1, col);
y1 = y1 + 1;
branch lines;
}
}
}
}
export fn rectangle_outline(x: f32, y: f32, w: f32, h: f32, col: i32) {
let xl = nearest(x) as i32;
let xr = nearest(x + w) as i32;
let yt = nearest(y) as i32;
let yb = nearest(y + h) as i32;
hline(xl, xr, yt, col);
if yt < yb {
hline(xl, xr, yb - 1, col);
loop y {
setPixel(xl, yt, col);
if xl < xr {
setPixel(xr - 1, yt, col);
}
branch_if (yt := yt + 1) < yb: y;
}
}
}
export fn circle(cx: f32, cy: f32, radius: f32, col: i32) {
let y = clamp(nearest(cy - radius) as i32, 0, 240);
let maxY = clamp(nearest(cy + radius) as i32, 0, 240);
block done {
loop lines {
branch_if y >= maxY: done;
let lazy dy = y as f32 - cy + 0.5;
let lazy q = radius * radius - dy * dy;
if abs(q) == q {
let lazy w = sqrt(q);
hline(nearest(cx - w) as i32, nearest(cx + w) as i32, y, col);
}
y = y + 1;
branch lines;
}
}
}
export fn circle_outline(cx: f32, cy: f32, radius: f32, col: i32) {
let prev_w: f32;
let y = clamp(nearest(cy - radius) as i32, -1, 241);
let maxY = clamp(nearest(cy + radius) as i32, -1, 241);
loop lines {
let lazy dy = y as f32 - cy + 0.5;
let inline q = radius * radius - dy * dy;
let w = sqrt(max(0 as f32, q));
let xlp = nearest(cx - prev_w) as i32;
let xl = nearest(cx - w) as i32;
let xrp = nearest(cx + prev_w) as i32;
let xr = nearest(cx + w) as i32;
if w >= prev_w {
if xl < xlp {
hline(xl, xlp, y, col);
} else {
if xl < xr {
setPixel(xl, y, col);
}
}
if xr > xrp {
hline(xrp, xr, y, col);
} else {
if xl < xr {
setPixel(xr - 1, y, col);
}
}
} else {
if xl > xlp {
hline(xlp, xl, y - 1, col);
} else {
if xlp < xrp {
setPixel(xlp, y - 1, col);
}
}
if xr < xrp {
hline(xr, xrp, y - 1, col);
} else {
if xlp < xrp {
setPixel(xrp - 1, y - 1, col);
}
}
}
y = y + 1;
prev_w = w;
branch_if y <= maxY: lines;
}
}
export fn line(x1: f32, y1: f32, x2: f32, y2: f32, col: i32) {
let swapTmp: f32;
if x1 > x2 {
swapTmp = x1;
x1 = x2;
x2 = swapTmp;
swapTmp = y1;
y1 = y2;
y2 = swapTmp;
}
if x1 < 0 as f32 & x2 >= 0 as f32 {
y1 = y1 + (y2 - y1) * -x1 / (x2 - x1);
x1 = 0 as f32;
}
if x1 < 320 as f32 & x2 >= 320 as f32 {
y2 = y2 + (y2 - y1) * (320 as f32 - x2) / (x2 - x1);
x2 = 320 as f32;
}
if y1 > y2 {
swapTmp = x1;
x1 = x2;
x2 = swapTmp;
swapTmp = y1;
y1 = y2;
y2 = swapTmp;
}
if y1 < 0 as f32 & y2 >= 0 as f32 {
x1 = x1 + (x2 - x1) * -y1 / (y2 - y1);
y1 = 0 as f32;
}
if y1 < 240 as f32 & y2 >= 240 as f32 {
x2 = x2 + (x2 - x1) * (240 as f32 - y2) / (y2 - y1);
y2 = 240 as f32;
}
let lazy dx = x2 - x1;
let lazy dy = y2 - y1;
let max_axis: f32;
let p: f32;
if abs(dx) >= dy {
max_axis = dx;
p = x1;
} else {
max_axis = dy;
p = y1;
}
if max_axis == 0 as f32 {
setPixel(x1 as i32, y1 as i32, col);
return;
}
let steps = floor(p + max_axis) as i32 - floor(p) as i32;
p = floor(p) + 0.5 - p;
if max_axis < 0 as f32 {
steps = -steps;
p = -p;
max_axis = -max_axis;
}
dx = dx / max_axis;
dy = dy / max_axis;
let f = min(max_axis, max(0 as f32, p));
setPixel(i32.trunc_sat_f32_s(x1 + f * dx), i32.trunc_sat_f32_s(y1 + f * dy), col);
if !steps {
return;
}
x1 = x1 + (1 as f32 + p) * dx;
y1 = y1 + (1 as f32 + p) * dy;
p = p + steps as f32;
loop pixels {
if steps := steps - 1 {
setPixel(i32.trunc_sat_f32_s(x1), i32.trunc_sat_f32_s(y1), col);
x1 = x1 + dx;
y1 = y1 + dy;
branch pixels;
}
}
f = min(max_axis, p) - p;
setPixel(i32.trunc_sat_f32_s(x1 + f * dx), i32.trunc_sat_f32_s(y1 + f * dy), col);
}
//////////
// TEXT //
//////////
global mut textCursorX = 0;
global mut textCursorY = 0;
global mut textColor = 15;
global mut bgColor = 0;
global mut outputChannel = 0;
export fn printChar(char: i32) {
loop chars {
printSingleChar(char & 255);
branch_if (char := char #>> 8): chars;
}
}
global mut controlCodeLength = 0;
fn printSingleChar(char: i32) {
if outputChannel >= 2 & (char < 4 | char > 6) {
logChar(char);
return;
}
controlCodeLength?0x12d20 = char;
controlCodeLength = controlCodeLength + 1;
char = 0x12d20?0;
if char < 32 & controlCodeLength < char?0x12d00 {
return;
}
controlCodeLength = 0;
if char == 1 {
drawChar(0x12d20?1);
return;
}
if char >= 4 & char <= 6 {
outputChannel = char - 4;
if !outputChannel {
textCursorX = 0;
textCursorY = 0;
}
return;
}
if char == 7 {
80?0 = 80?0 ^ 2;
return;
}
if char == 8 {
textCursorX = textCursorX - 8;
if !outputChannel & textCursorX < 0 {
textCursorX = 320-8;
printSingleChar(11);
}
return;
}
if char == 9 {
if !outputChannel & textCursorX >= 320 {
printChar(0xd0a);
}
textCursorX = textCursorX + 8;
return;
}
if char == 10 {
textCursorY = textCursorY + 8;
if !outputChannel & textCursorY >= 240 {
textCursorY = 240 - 8;
let i: i32;
loop scroll_copy {
i!120 = i!(120 + 320 * 8);
branch_if (i := i + 4) < 320 * (240 - 8): scroll_copy;
}
rectangle(0 as f32, (240 - 8) as f32, 320 as f32, 8 as f32, bgColor);
}
return;
}
if char == 11 {
textCursorY = textCursorY - 8;
if !outputChannel & textCursorY < 0 {
textCursorY = 0;
let i = 320 * (240 - 8);
loop scroll_copy {
i!(116 + 320 * 8) = i!116;
branch_if (i := i - 4): scroll_copy;
}
rectangle(0 as f32, 0 as f32, 320 as f32, 8 as f32, bgColor);
}
return;
}
if char == 12 {
cls(bgColor);
return;
}
if char == 13 {
textCursorX = 0;
return;
}
if char == 14 {
bgColor = 0x12d20?1;
return;
}
if char == 15 {
textColor = 0x12d20?1;
return;
}
if char == 24 {
let tmp = textColor;
textColor = bgColor;
bgColor = tmp;
return;
}
if char == 31 {
textCursorX = 0x12d20?1 * (8 - outputChannel * 6);
textCursorY = 0x12d20?2 * (8 - outputChannel * 7);
return;
}
if char < 31 {
return;
}
drawChar(char);
}
data(0x12d00) {
i8(
1, 2, 1, 1, // 0-3
1, 1, 1, 1, // 4-7
1, 1, 1, 1, // 8-11
1, 1, 2, 2, // 12-15,
1, 1, 1, 1, // 16-19,
1, 1, 1, 1, // 20-23,
1, 1, 1, 1, // 24-27,
1, 1, 1, 3 // 28-31
)
}
fn drawChar(char: i32) {
if !outputChannel & textCursorX >= 320 {
printChar(0xd0a);
}
let y: i32;
loop rows {
let bits = (char * 8 + y)?0x13400;
let x = 0;
if outputChannel {
loop pixels {
if (bits := bits << 1) & 256 {
setPixel(textCursorX + x, textCursorY + y, textColor);
}
branch_if (x := x + 1) < 8: pixels;
}
} else {
loop pixels {
setPixel(textCursorX + x, textCursorY + y, select((bits := bits << 1) & 256, textColor, bgColor));
branch_if (x := x + 1) < 8: pixels;
}
}
branch_if (y := y + 1) < 8: rows;
}
textCursorX = textCursorX + 8;
}
export fn printString(ptr: i32) {
loop chars {
let lazy char = ptr?0;
if char {
printChar(char);
ptr = ptr + 1;
branch chars;
}
}
}
export fn printInt(num: i32) {
let lazy p = 0x12fff;
p?0 = 0;
if num < 0 {
printChar(45);
num = -num;
}
loop digits {
(p := p - 1)?0 = 48 + num #% 10;
branch_if (num := num #/ 10): digits;
}
printString(p);
}
export fn setTextColor(col: i32) {
textColor = col;
}
export fn setBackgroundColor(col: i32) {
bgColor = col;
}
export fn setCursorPosition(x: i32, y: i32) {
let lazy scale = select(outputChannel, 1, 8);
textCursorX = x * scale;
textCursorY = y * scale;
}
///////////
// SOUND //
///////////
include "ges.cwa"
export fn playNote(channel: i32, note: i32) {
(channel * 6)?80 = (channel * 6)?80 & 0xfe ^ if note {
(channel * 6)?83 = note & 127;
2 | !(note >> 7)
} else {
0
};
}
data 80 {
i8(
0x80, 0xc0, 0, 81, 0xa0, 0x50,
0xc4, 0, 0, 69, 0x60, 0x40,
0x44, 0xb0, 0, 69, 0x90, 0x43,
0x4, 0xf0, 0, 69, 0xa4, 0x44,
0xff, 0xff,
1, 1, 0, 100, 0, 100
)
}
///////////
// SETUP //
///////////
export fn endFrame() {
68!4 = 68!0;
}
start fn setup() {
let i: i32 = 12*16*3-1;
let avg: f32;
loop gradients {
let lazy scale = (i % 48) as f32 / 48 as f32;
let inline angle = i as f32 * (3.1416 / 1.5 - 3.1416 / (11.0 * 16.0 * 1.5));
let lazy c = 0.4 - cos(angle);
let inline ulimit = avg + 0.8;
let inline llimit = avg - 0.8;
let lazy a = max(llimit, min(ulimit, c)) * (scale + 0.05);
let lazy b = scale * scale * 0.8;
let inline v = (select(i < 11*16*3, max(0 as f32, min(a + b - a * b, 1 as f32)), scale) * 255 as f32) as i32;
(i%3 + i/3*4)?0x13000 = v;
avg = (avg + c) * 0.5;
branch_if i := i - 1: gradients;
}
i = 255;
loop expand_sweetie {
let lazy channel = i & 3;
let lazy index = i >> 2;
let lazy first_step = index >= 32;
let inline src1 = select(first_step, index % 32 / 2, index * 2);
let inline src2 = select(first_step, (index + 1) % 32 / 2, index * 2 + 1);
let inline c1 = (src1 * 4 + channel)?(0x13000+192*4);
let inline c2 = (src2 * 4 + channel)?(0x13000+192*4);
i?(0x13000+192*4) = (c1 + c2) * (3 + first_step) / 8;
branch_if (i := i - 1) >= 0: expand_sweetie;
}
memory.fill(0, 0, 64);
memory.fill(112, 0, 8);
memory.fill(0x14000, 0, 0x2c000);
cls(0);
randomSeed(random());
}
data 0x12c78 {
i32(80)
}
data 0x13000+192*4 {
i32(
0x2c1c1a,
0x5d275d,
0x533eb1,
0x577def,
0x75cdff,
0x70f0a7,
0x64b738,
0x797125,
0x6f3629,
0xc95d3b,
0xf6a641,
0xf7ef73,
0xf4f4f4,
0xc2b094,
0x866c56,
0x573c33
)
}
data 0x13400 {
file("../target/font.bin")
}