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 char >= 4 & char <= 6 { outputChannel = char - 4; if !outputChannel { textCursorX = 0; textCursorY = 0; } return; } if outputChannel >= 2 { 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 == 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") }