156 lines
3.9 KiB
Zig
156 lines
3.9 KiB
Zig
// SPDX-License-Identifier: LCL-1.0
|
|
// Copyright (c) 2026 Markus Maiwald
|
|
// Stewardship: Self Sovereign Society Foundation
|
|
//
|
|
// This file is part of the Nexus Commonwealth.
|
|
// See legal/LICENSE_COMMONWEALTH.md for license terms.
|
|
|
|
//! Rumpk Layer 0: The Canvas (Static Framebuffer)
|
|
//!
|
|
//! Implements the primary graphics buffer (VRAM) living in BSS.
|
|
//! Provides primitives for pixel plotting, rect-filling, and screen fading.
|
|
//!
|
|
//! SAFETY: All drawing operations include clipping logic to prevent BSS overflow.
|
|
//! Resolution is fixed at 1920x1080 ARGB.
|
|
|
|
const std = @import("std");
|
|
|
|
// Resolution: 1920x1080 @ 32bpp (ARGB)
|
|
pub const WIDTH: usize = 1920;
|
|
pub const HEIGHT: usize = 1080;
|
|
pub const STRIDE: usize = WIDTH;
|
|
|
|
// The Physical Backing Store (~7.9MB in BSS)
|
|
// Zero-initialized at boot.
|
|
var fb_memory: [WIDTH * HEIGHT]u32 = [_]u32{0} ** (WIDTH * HEIGHT);
|
|
|
|
// Clip rectangle (for MU_COMMAND_CLIP)
|
|
var clip_x: i32 = 0;
|
|
var clip_y: i32 = 0;
|
|
var clip_w: i32 = WIDTH;
|
|
var clip_h: i32 = HEIGHT;
|
|
|
|
pub const Rect = struct {
|
|
x: i32,
|
|
y: i32,
|
|
w: i32,
|
|
h: i32,
|
|
};
|
|
|
|
pub fn get_buffer() [*]u32 {
|
|
return &fb_memory;
|
|
}
|
|
|
|
pub fn fb_get_buffer_phys() usize {
|
|
// Identity mapping for now
|
|
return @intFromPtr(&fb_memory);
|
|
}
|
|
|
|
pub fn get_size() usize {
|
|
return WIDTH * HEIGHT * @sizeOf(u32);
|
|
}
|
|
|
|
pub fn init() void {
|
|
// Clear to dark blue (Nexus brand)
|
|
clear(0xFF101030);
|
|
}
|
|
|
|
pub fn clear(color: u32) void {
|
|
@memset(&fb_memory, color);
|
|
}
|
|
|
|
pub fn set_clip(r: Rect) void {
|
|
clip_x = r.x;
|
|
clip_y = r.y;
|
|
clip_w = r.w;
|
|
clip_h = r.h;
|
|
}
|
|
|
|
pub fn put_pixel(x: i32, y: i32, color: u32) void {
|
|
if (x < 0 or y < 0) return;
|
|
if (x >= @as(i32, @intCast(WIDTH)) or y >= @as(i32, @intCast(HEIGHT))) return;
|
|
|
|
// Clip check
|
|
if (x < clip_x or x >= clip_x + clip_w) return;
|
|
if (y < clip_y or y >= clip_y + clip_h) return;
|
|
|
|
const ux: usize = @intCast(x);
|
|
const uy: usize = @intCast(y);
|
|
fb_memory[uy * WIDTH + ux] = color;
|
|
}
|
|
|
|
// Optimized Rect Fill (The Workhorse for microui)
|
|
pub fn fill_rect(x: i32, y: i32, w: i32, h: i32, color: u32) void {
|
|
// Clipping to screen
|
|
var rx = x;
|
|
var ry = y;
|
|
var rw = w;
|
|
var rh = h;
|
|
|
|
if (rx < 0) {
|
|
rw += rx;
|
|
rx = 0;
|
|
}
|
|
if (ry < 0) {
|
|
rh += ry;
|
|
ry = 0;
|
|
}
|
|
if (rx + rw > @as(i32, @intCast(WIDTH))) {
|
|
rw = @as(i32, @intCast(WIDTH)) - rx;
|
|
}
|
|
if (ry + rh > @as(i32, @intCast(HEIGHT))) {
|
|
rh = @as(i32, @intCast(HEIGHT)) - ry;
|
|
}
|
|
if (rw <= 0 or rh <= 0) return;
|
|
|
|
// Clip to clip rect
|
|
if (rx < clip_x) {
|
|
rw -= (clip_x - rx);
|
|
rx = clip_x;
|
|
}
|
|
if (ry < clip_y) {
|
|
rh -= (clip_y - ry);
|
|
ry = clip_y;
|
|
}
|
|
if (rx + rw > clip_x + clip_w) {
|
|
rw = clip_x + clip_w - rx;
|
|
}
|
|
if (ry + rh > clip_y + clip_h) {
|
|
rh = clip_y + clip_h - ry;
|
|
}
|
|
if (rw <= 0 or rh <= 0) return;
|
|
|
|
const start_row: usize = @intCast(ry);
|
|
const end_row: usize = start_row + @as(usize, @intCast(rh));
|
|
const start_col: usize = @intCast(rx);
|
|
const cols: usize = @intCast(rw);
|
|
|
|
var row = start_row;
|
|
while (row < end_row) : (row += 1) {
|
|
const offset = row * WIDTH + start_col;
|
|
@memset(fb_memory[offset .. offset + cols], color);
|
|
}
|
|
}
|
|
|
|
// THE FADE (Optimization: Dim pixels instead of clearing)
|
|
// This creates the "Ghost Trail" effect cheaply.
|
|
pub fn fade_screen(factor: u8) void {
|
|
for (&fb_memory) |*pixel| {
|
|
if (pixel.* == 0) continue;
|
|
|
|
// Extract Green Channel (Assuming 0xAARRGGBB)
|
|
// We only care about green for the matrix effect
|
|
var g = (pixel.* >> 8) & 0xFF;
|
|
|
|
if (g > factor) {
|
|
g -= factor;
|
|
} else {
|
|
g = 0;
|
|
}
|
|
|
|
// Reconstruct: Keep it mostly green but allow it to fade to black
|
|
// We zero out Red and Blue for the matrix look during fade.
|
|
pixel.* = (@as(u32, g) << 8) | 0xFF000000;
|
|
}
|
|
}
|