aboutsummaryrefslogtreecommitdiff
path: root/solar_map.v
blob: eea0faf1a2c1d2b988ab2839ba0ffa5b867e6e9e (plain)
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)
}