// image-surface.el - Native own-core raster PNG surface (the image efferent // twin of audio). Renders a 64x64 RGB scene deterministically from a frame's // meaning-geometry, then serialises a byte-valid PNG entirely own-core: // 8-byte magic, IHDR, IDAT (zlib STORED/uncompressed DEFLATE + Adler32), IEND, // with a per-chunk CRC32 computed via software xor32 (EL has no bitwise ops). // // The RGB palette basis is read from elp/faculty/sig/scene.basis (data, not // literals) - the same read-from-learned discipline as the audio signatures. // Integer-only throughout; pixels are composed functionally (painter's order) // so no list mutation is needed. // -- small int/parse helpers (self-contained) ---------------------------------- fn i_str_to_int(s: String) -> Int { let n: Int = str_len(s) let i: Int = 0 let v: Int = 0 while i < n { let c: Int = str_char_code(s, i) if c >= 48 { if c < 58 { let v: Int = v * 10 + (c - 48) } } let i: Int = i + 1 } return v } fn basis_load(path: String) -> [String] { return str_split(fs_read(path), "\n") } fn basis_field(lines: [String], key: String) -> String { let pref: String = key + ": " let n: Int = native_list_len(lines) let plen: Int = str_len(pref) let i: Int = 0 while i < n { let ln: String = native_list_get(lines, i) if str_starts_with(ln, pref) { return str_slice(ln, plen, str_len(ln)) } let i: Int = i + 1 } return "" } fn parse_rgb(csv: String) -> [Int] { let parts: [String] = str_split(csv, ",") let out: [Int] = native_list_empty() let n: Int = native_list_len(parts) let i: Int = 0 while i < n { let v: Int = i_str_to_int(native_list_get(parts, i)) let out: [Int] = native_list_append(out, v) let i: Int = i + 1 } return out } // -- software 32-bit XOR (no bitwise ops in EL) -------------------------------- fn xor32(a: Int, b: Int) -> Int { let r: Int = 0 let bit: Int = 1 let i: Int = 0 while i < 32 { let abit: Int = (a / bit) % 2 let bbit: Int = (b / bit) % 2 if abit != bbit { let add: Int = bit let r: Int = r + add } let bit: Int = bit * 2 let i: Int = i + 1 } return r } // -- CRC32 (table-driven, table built with xor32) ------------------------------ fn crc_table() -> [Int] { let t: [Int] = native_list_empty() let n: Int = 0 while n < 256 { let c: Int = n let k: Int = 0 while k < 8 { if c % 2 == 1 { let h: Int = c / 2 let c: Int = xor32(h, 3988292384) } else { let c: Int = c / 2 } let k: Int = k + 1 } let t: [Int] = native_list_append(t, c) let n: Int = n + 1 } return t } fn crc32_of(bytes: [Int], table: [Int]) -> Int { let crc: Int = 4294967295 let n: Int = native_list_len(bytes) let i: Int = 0 while i < n { let b: Int = native_list_get(bytes, i) let lo: Int = crc % 256 let idx: Int = xor32(lo, b) % 256 let tv: Int = native_list_get(table, idx) let hi: Int = crc / 256 let crc: Int = xor32(hi, tv) let i: Int = i + 1 } return xor32(crc, 4294967295) } // -- Adler32 (for the zlib trailer) -------------------------------------------- fn adler32_of(bytes: [Int]) -> Int { let a: Int = 1 let b: Int = 0 let n: Int = native_list_len(bytes) let i: Int = 0 while i < n { let byte: Int = native_list_get(bytes, i) let a: Int = (a + byte) % 65521 let b: Int = (b + a) % 65521 let i: Int = i + 1 } return b * 65536 + a } // -- byte-list append helpers -------------------------------------------------- fn app_u32be(dst: [Int], v: Int) -> [Int] { let dst: [Int] = native_list_append(dst, (v / 16777216) % 256) let dst: [Int] = native_list_append(dst, (v / 65536) % 256) let dst: [Int] = native_list_append(dst, (v / 256) % 256) let dst: [Int] = native_list_append(dst, v % 256) return dst } fn app_tag(dst: [Int], s: String) -> [Int] { let n: Int = str_len(s) let i: Int = 0 while i < n { let dst: [Int] = native_list_append(dst, str_char_code(s, i)) let i: Int = i + 1 } return dst } fn app_all(dst: [Int], src: [Int]) -> [Int] { let n: Int = native_list_len(src) let i: Int = 0 while i < n { let dst: [Int] = native_list_append(dst, native_list_get(src, i)) let i: Int = i + 1 } return dst } // -- plan: frame meaning-geometry -> shape atoms ------------------------------- // shape = [type, x, y, size, r, g, b] (type 0=rect 1=disc 2=triangle) fn charsum(s: String) -> Int { let n: Int = str_len(s) let i: Int = 0 let acc: Int = 0 while i < n { let c: Int = str_char_code(s, i) let acc: Int = acc + c let i: Int = i + 1 } return acc } fn micro_of(s: String) -> Int { let dot: Int = str_index_of(s, ".") if dot < 0 { return i_str_to_int(s) * 1000000 } let n: Int = str_len(s) let fp: String = str_slice(s, dot + 1, n) let ip: String = str_slice(s, 0, dot) let iv: Int = i_str_to_int(ip) let fv: Int = 0 let scale: Int = 100000 let fl: Int = str_len(fp) let i: Int = 0 while i < 6 { let d: Int = 0 if i < fl { let d: Int = str_char_code(fp, i) - 48 } let fv: Int = fv + d * scale let scale: Int = scale / 10 let i: Int = i + 1 } return iv * 1000000 + fv } fn plan_scene(frames: [[String]], warm: [Int], cool: [Int]) -> [[Int]] { let shapes: [[Int]] = native_list_empty() let nf: Int = native_list_len(frames) let fi: Int = 0 while fi < nf { let fr: [String] = native_list_get(frames, fi) let relation: String = surface_get(fr, "relation") let polarity: String = surface_get(fr, "polarity") let confidence: String = surface_get(fr, "confidence") let importance: String = surface_get(fr, "importance") let salience: String = surface_get(fr, "salience") // relation -> shape type let stype: Int = charsum(relation) % 3 // confidence -> size (8..22) let cmi: Int = micro_of(confidence) let size: Int = 8 + cmi / 71428 // salience -> y let sal: Int = i_str_to_int(salience) let y: Int = 6 + sal * 26 // subj_id/index -> x let x: Int = 4 + (fi * 10) % 48 // polarity -> warm/cool base color let br: Int = native_list_get(warm, 0) let bg2: Int = native_list_get(warm, 1) let bb: Int = native_list_get(warm, 2) if str_eq(polarity, "neg") { let br: Int = native_list_get(cool, 0) let bg2: Int = native_list_get(cool, 1) let bb: Int = native_list_get(cool, 2) } // importance -> brightness (500..1000 permille) let imi: Int = micro_of(importance) let bpm: Int = 500 + imi / 2000 let r: Int = br * bpm / 1000 let g: Int = bg2 * bpm / 1000 let b: Int = bb * bpm / 1000 let sh: [Int] = native_list_empty() let sh: [Int] = native_list_append(sh, stype) let sh: [Int] = native_list_append(sh, x) let sh: [Int] = native_list_append(sh, y) let sh: [Int] = native_list_append(sh, size) let sh: [Int] = native_list_append(sh, r) let sh: [Int] = native_list_append(sh, g) let sh: [Int] = native_list_append(sh, b) let shapes: [[Int]] = native_list_append(shapes, sh) let fi: Int = fi + 1 } return shapes } // covers: is (px,py) inside this shape? fn covers(sh: [Int], px: Int, py: Int) -> Bool { let stype: Int = native_list_get(sh, 0) let sx: Int = native_list_get(sh, 1) let sy: Int = native_list_get(sh, 2) let size: Int = native_list_get(sh, 3) let cx: Int = sx + size / 2 if stype == 0 { if px >= sx { if px < sx + size { if py >= sy { if py < sy + size { return true } } } } return false } if stype == 1 { let rad: Int = size / 2 let dx: Int = px - cx let dy: Int = py - (sy + rad) if dx * dx + dy * dy <= rad * rad { return true } return false } // triangle: apex at top (sy), base at sy+size if py >= sy { if py < sy + size { let dyv: Int = py - sy let halfw: Int = dyv / 2 let dxv: Int = px - cx let adx: Int = dxv if adx < 0 { let adx: Int = 0 - dxv } if adx <= halfw { return true } } } return false } // pixel_color: painter's algorithm - last covering shape wins. Returns [r,g,b]. fn pixel_color(px: Int, py: Int, shapes: [[Int]], bg: [Int]) -> [Int] { let r: Int = native_list_get(bg, 0) let g: Int = native_list_get(bg, 1) let b: Int = native_list_get(bg, 2) let n: Int = native_list_len(shapes) let i: Int = 0 while i < n { let sh: [Int] = native_list_get(shapes, i) if covers(sh, px, py) { let r: Int = native_list_get(sh, 4) let g: Int = native_list_get(sh, 5) let b: Int = native_list_get(sh, 6) } let i: Int = i + 1 } let out: [Int] = native_list_empty() let out: [Int] = native_list_append(out, r) let out: [Int] = native_list_append(out, g) let out: [Int] = native_list_append(out, b) return out } // rasterize: build the raw (filtered) scanline byte stream, filter byte 0 / row. fn rasterize(w: Int, h: Int, shapes: [[Int]], bg: [Int]) -> [Int] { let raw: [Int] = native_list_empty() let y: Int = 0 while y < h { let raw: [Int] = native_list_append(raw, 0) let x: Int = 0 while x < w { let col: [Int] = pixel_color(x, y, shapes, bg) let raw: [Int] = native_list_append(raw, native_list_get(col, 0)) let raw: [Int] = native_list_append(raw, native_list_get(col, 1)) let raw: [Int] = native_list_append(raw, native_list_get(col, 2)) let x: Int = x + 1 } let y: Int = y + 1 } return raw } // zlib stream with a single STORED (uncompressed) DEFLATE block + Adler32. fn zlib_store(raw: [Int]) -> [Int] { let z: [Int] = native_list_empty() let z: [Int] = native_list_append(z, 120) let z: [Int] = native_list_append(z, 1) let z: [Int] = native_list_append(z, 1) let len: Int = native_list_len(raw) let nlen: Int = 65535 - len let z: [Int] = native_list_append(z, len % 256) let z: [Int] = native_list_append(z, (len / 256) % 256) let z: [Int] = native_list_append(z, nlen % 256) let z: [Int] = native_list_append(z, (nlen / 256) % 256) let z: [Int] = app_all(z, raw) let ad: Int = adler32_of(raw) let z: [Int] = app_u32be(z, ad) return z } // append a full PNG chunk: length + (type+data) + crc32(type+data). fn app_chunk(png: [Int], type_and_data: [Int], table: [Int]) -> [Int] { let total: Int = native_list_len(type_and_data) let dlen: Int = total - 4 let png: [Int] = app_u32be(png, dlen) let png: [Int] = app_all(png, type_and_data) let crc: Int = crc32_of(type_and_data, table) let png: [Int] = app_u32be(png, crc) return png } fn png_build(w: Int, h: Int, raw: [Int], table: [Int]) -> [Int] { let png: [Int] = native_list_empty() // 8-byte signature let png: [Int] = native_list_append(png, 137) let png: [Int] = native_list_append(png, 80) let png: [Int] = native_list_append(png, 78) let png: [Int] = native_list_append(png, 71) let png: [Int] = native_list_append(png, 13) let png: [Int] = native_list_append(png, 10) let png: [Int] = native_list_append(png, 26) let png: [Int] = native_list_append(png, 10) // IHDR let ihdr: [Int] = native_list_empty() let ihdr: [Int] = app_tag(ihdr, "IHDR") let ihdr: [Int] = app_u32be(ihdr, w) let ihdr: [Int] = app_u32be(ihdr, h) let ihdr: [Int] = native_list_append(ihdr, 8) let ihdr: [Int] = native_list_append(ihdr, 2) let ihdr: [Int] = native_list_append(ihdr, 0) let ihdr: [Int] = native_list_append(ihdr, 0) let ihdr: [Int] = native_list_append(ihdr, 0) let png: [Int] = app_chunk(png, ihdr, table) // IDAT let z: [Int] = zlib_store(raw) let idat: [Int] = native_list_empty() let idat: [Int] = app_tag(idat, "IDAT") let idat: [Int] = app_all(idat, z) let png: [Int] = app_chunk(png, idat, table) // IEND let iend: [Int] = native_list_empty() let iend: [Int] = app_tag(iend, "IEND") let png: [Int] = app_chunk(png, iend, table) return png } fn png_write(path: String, png: [Int]) -> Int { let n: Int = native_list_len(png) let buf: String = __str_alloc(n) let i: Int = 0 while i < n { let buf: String = __str_set_char(buf, i, native_list_get(png, i)) let i: Int = i + 1 } let ok: Int = fs_write_bytes(path, buf, n) return ok }