1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
|
module solar_map
import os
import time
import render
pub type SpaceBody = render.SpaceBody
// Convert a SpaceBody into a 64-byte Little-Endian array
fn body_to_bytes(b SpaceBody) []u8 {
mut bytes := []u8{cap: 64}
bytes << u32_to_bytes(b.id)
bytes << u32_to_bytes(b.parent_id)
bytes << i64_to_bytes(b.rel_x)
bytes << i64_to_bytes(b.rel_y)
bytes << i64_to_bytes(b.rel_z)
bytes << u32_to_bytes(b.radius)
bytes << b.body_type
bytes << b.flags[0]
bytes << b.flags[1]
bytes << b.flags[2]
for i in 0 .. 24 {
bytes << b.comment[i]
}
return bytes
}
// Reconstruct a SpaceBody from a 64-byte slice
fn body_from_bytes(data []u8) SpaceBody {
mut flags_arr := [3]u8{}
flags_arr[0] = data[37]
flags_arr[1] = data[38]
flags_arr[2] = data[39]
mut comment_arr := [24]u8{}
for i in 0 .. 24 {
comment_arr[i] = data[40 + i]
}
return SpaceBody{
id: bytes_to_u32(data[0..4])
parent_id: bytes_to_u32(data[4..8])
rel_x: bytes_to_i64(data[8..16])
rel_y: bytes_to_i64(data[16..24])
rel_z: bytes_to_i64(data[24..32])
radius: bytes_to_u32(data[32..36])
body_type: data[36]
flags: flags_arr
comment: comment_arr
}
}
// Public API function to process a CSV file, output binary data, and optionally render a BMP image
pub fn process_galaxy(csv_path string, generate_image bool) ! {
struct_size := int(sizeof(SpaceBody))
if !os.exists(csv_path) {
return error('File not found: ${csv_path}')
}
// 1. Parse CSV
sw_parse := time.new_stopwatch()
lines := os.read_lines(csv_path)!
mut bodies := []SpaceBody{cap: lines.len - 1}
for i := 1; i < lines.len; i++ {
line := lines[i].trim_space()
if line == '' {
continue
}
parts := line.split(',')
if parts.len < 7 {
continue
}
mut flag_val := u8(0)
if parts.len >= 8 {
flag_val = parts[7].u8()
}
mut body := SpaceBody{
id: parts[0].u32()
parent_id: parts[1].u32()
rel_x: parts[2].i64()
rel_y: parts[3].i64()
rel_z: parts[4].i64()
radius: parts[5].u32()
body_type: parts[6].u8()
flags: [flag_val, u8(0), u8(0)]!
}
if parts.len >= 9 {
comment_str := parts[8].trim_space()
mut bytes_to_copy := comment_str.len
if bytes_to_copy > 24 {
bytes_to_copy = 24
}
for j := 0; j < bytes_to_copy; j++ {
body.comment[j] = comment_str[j]
}
}
bodies << body
}
println('CSV parsed in: ${sw_parse.elapsed().microseconds()} µs')
// 2. Write binary data
bin_path := csv_path.replace('.csv', '.bin')
mut bytes_to_write := []u8{cap: bodies.len * struct_size}
for body in bodies {
bytes_to_write << body_to_bytes(body)
}
os.write_file(bin_path, bytes_to_write.bytestr())!
// 3. Load binary data back (Fast Load validation)
sw_load := time.new_stopwatch()
bin_bytes := os.read_bytes(bin_path)!
body_count := bin_bytes.len / struct_size
mut loaded_bodies := []SpaceBody{cap: body_count}
for i in 0 .. body_count {
offset := i * struct_size
loaded_bodies << body_from_bytes(bin_bytes[offset .. offset + struct_size])
}
println('Binary loaded in: ${sw_load.elapsed().microseconds()} µs')
// 4. Render BMP image if requested
if generate_image {
bmp_path := csv_path.replace('.csv', '.bmp')
sw_render := time.new_stopwatch()
render.draw_bodies_to_bmp(loaded_bodies, bmp_path, 1920, 600)!
println('Image successfully rendered to "${bmp_path}" in ${sw_render.elapsed().microseconds()} µs')
}
}
// Helper functions for Little-Endian conversions
fn u32_to_bytes(v u32) []u8 {
return [u8(v), u8(v >> 8), u8(v >> 16), u8(v >> 24)]
}
fn i64_to_bytes(v i64) []u8 {
u := u64(v)
return [
u8(u),
u8(u >> 8),
u8(u >> 16),
u8(u >> 24),
u8(u >> 32),
u8(u >> 40),
u8(u >> 48),
u8(u >> 56),
]
}
fn bytes_to_u32(b []u8) u32 {
return u32(b[0]) | (u32(b[1]) << 8) | (u32(b[2]) << 16) | (u32(b[3]) << 24)
}
fn bytes_to_i64(b []u8) i64 {
u := u64(b[0]) | (u64(b[1]) << 8) | (u64(b[2]) << 16) | (u64(b[3]) << 24) |
(u64(b[4]) << 32) | (u64(b[5]) << 40) | (u64(b[6]) << 48) | (u64(b[7]) << 56)
return i64(u)
}
|