module render import os import math @[packed] pub struct SpaceBody { pub mut: id u32 parent_id u32 rel_x i64 rel_y i64 rel_z i64 radius u32 body_type u8 flags [3]u8 comment [24]u8 } struct Color { r u8 g u8 b u8 } fn get_abs_x(id u32, bodies map[u32]SpaceBody) i64 { if id == 0 || id !in bodies { return 0 } body := bodies[id] if body.parent_id == 0 { return body.rel_x } return body.rel_x + get_abs_x(body.parent_id, bodies) } pub fn draw_bodies_to_bmp(bodies []SpaceBody, output_path string, width int, height int) ! { center_y := height / 2 mut body_map := map[u32]SpaceBody{} for body in bodies { body_map[body.id] = body } mut max_abs_x := f64(1) for body in bodies { abs_x := math.abs(f64(get_abs_x(body.id, body_map))) if abs_x > max_abs_x { max_abs_x = abs_x } } mut pixels := []u8{len: width * height * 3, init: 10} set_pixel := fn (mut px []u8, w int, h int, x int, y int, color Color) { if x >= 0 && x < w && y >= 0 && y < h { idx := (y * w + x) * 3 px[idx] = color.r px[idx + 1] = color.g px[idx + 2] = color.b } } for body in bodies { abs_x := f64(get_abs_x(body.id, body_map)) norm_x := math.sqrt(abs_x / max_abs_x) px_x := int(50 + norm_x * f64(width - 100)) mut col := Color{r: 255, g: 255, b: 255} mut draw_radius := 3 match body.body_type { 1 { col = Color{r: 255, g: 220, b: 50} draw_radius = 12 } 2 { col = Color{r: 100, g: 180, b: 255} draw_radius = 5 } 3 { col = Color{r: 180, g: 180, b: 180} draw_radius = 2 } 4 { col = Color{r: 200, g: 130, b: 100} draw_radius = 3 } else {} } for dy := -draw_radius; dy <= draw_radius; dy++ { for dx := -draw_radius; dx <= draw_radius; dx++ { if dx * dx + dy * dy <= draw_radius * draw_radius { set_pixel(mut pixels, width, height, px_x + dx, center_y + dy, col) } } } } save_bmp(output_path, width, height, pixels)! } fn save_bmp(path string, width int, height int, rgb_pixels []u8) ! { file_header_size := 14 info_header_size := 40 row_padding := (4 - (width * 3) % 4) % 4 pixel_array_size := (width * 3 + row_padding) * height file_size := file_header_size + info_header_size + pixel_array_size mut buf := []u8{cap: file_size} // BMP Header buf << `B` buf << `M` buf << u32_to_bytes(u32(file_size)) buf << [u8(0), 0, 0, 0] buf << u32_to_bytes(u32(file_header_size + info_header_size)) // DIB Header buf << u32_to_bytes(u32(info_header_size)) buf << i32_to_bytes(i32(width)) buf << i32_to_bytes(i32(-height)) buf << [u8(1), 0] buf << [u8(24), 0] buf << u32_to_bytes(0) buf << u32_to_bytes(u32(pixel_array_size)) buf << u32_to_bytes(2835) buf << u32_to_bytes(2835) buf << u32_to_bytes(0) buf << u32_to_bytes(0) // Pixeldaten (BGR-Reihenfolge) for y := 0; y < height; y++ { for x := 0; x < width; x++ { idx := (y * width + x) * 3 buf << rgb_pixels[idx + 2] // B buf << rgb_pixels[idx + 1] // G buf << rgb_pixels[idx] // R } for p := 0; p < row_padding; p++ { buf << u8(0) } } os.write_file(path, buf.bytestr())! } fn u32_to_bytes(val u32) []u8 { return [u8(val & 0xFF), u8((val >> 8) & 0xFF), u8((val >> 16) & 0xFF), u8((val >> 24) & 0xFF)] } fn i32_to_bytes(val i32) []u8 { u := u32(val) return [u8(u & 0xFF), u8((u >> 8) & 0xFF), u8((u >> 16) & 0xFF), u8((u >> 24) & 0xFF)] }