Move Odin renderer into gui/ with per-project Makefiles
Each sub-project (gui, api, infra) now owns its own Makefile, and the root Makefile is a lean delegator for the base commands (run, build, test, clean, fmt). Odin source, deps, and web assets live under gui/ (gui/src, gui/lib, gui/www), with scripts kept under gui/scripts for build tooling only.
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
package main
|
||||
|
||||
import "core:math"
|
||||
import "core:math/rand"
|
||||
import rl "vendor:raylib"
|
||||
|
||||
WIDTH :: 1280
|
||||
HEIGHT :: 720
|
||||
|
||||
// Number of procedurally generated points standing in for the DESI catalog.
|
||||
// This is replaced by real survey data once ingestion lands.
|
||||
POINT_COUNT :: 4_000
|
||||
WORLD_RADIUS :: f32(500.0)
|
||||
|
||||
Galaxy :: struct {
|
||||
position: rl.Vector3,
|
||||
color: rl.Color,
|
||||
}
|
||||
|
||||
camera: rl.Camera3D
|
||||
universe: [dynamic]Galaxy
|
||||
|
||||
// Deterministic generator so the placeholder sky is stable between runs.
|
||||
rng: rand.Default_Random_State
|
||||
|
||||
main :: proc() {
|
||||
rng = rand.create(0xDE51_0000)
|
||||
context.random_generator = rand.default_random_generator(&rng)
|
||||
|
||||
rl.SetConfigFlags({.WINDOW_RESIZABLE, .VSYNC_HINT, .MSAA_4X_HINT})
|
||||
rl.InitWindow(WIDTH, HEIGHT, "DESI Explorer")
|
||||
defer rl.CloseWindow()
|
||||
rl.SetTargetFPS(60)
|
||||
|
||||
camera = make_camera()
|
||||
make_universe(&universe, POINT_COUNT)
|
||||
defer delete(universe)
|
||||
|
||||
for !rl.WindowShouldClose() {
|
||||
update()
|
||||
draw()
|
||||
}
|
||||
}
|
||||
|
||||
make_camera :: proc() -> rl.Camera3D {
|
||||
return {
|
||||
position = {0, 220, 220},
|
||||
target = {0, 0, 0},
|
||||
up = {0, 1, 0},
|
||||
fovy = 60,
|
||||
projection = .PERSPECTIVE,
|
||||
}
|
||||
}
|
||||
|
||||
make_universe :: proc(u: ^[dynamic]Galaxy, count: int) {
|
||||
clear(u)
|
||||
reserve(u, count)
|
||||
for _ in 0 ..< count {
|
||||
pos := random_sphere_point(WORLD_RADIUS)
|
||||
append(u, Galaxy{position = pos, color = color_for_position(pos)})
|
||||
}
|
||||
}
|
||||
|
||||
// Uniformly distributed random point inside the scene's bounding sphere.
|
||||
random_sphere_point :: proc(radius: f32) -> rl.Vector3 {
|
||||
for {
|
||||
x := rand.float32_range(-1, 1)
|
||||
y := rand.float32_range(-1, 1)
|
||||
z := rand.float32_range(-1, 1)
|
||||
len_sq := x * x + y * y + z * z
|
||||
if len_sq > 0.0001 && len_sq < 1.0 {
|
||||
return {x * radius, y * radius, z * radius}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Maps distance from the origin to a blue (near) -> red (far) gradient, a
|
||||
// stand-in for redshift until real colors are computed from survey metadata.
|
||||
color_for_position :: proc(p: rl.Vector3) -> rl.Color {
|
||||
d := math.sqrt(p.x * p.x + p.y * p.y + p.z * p.z)
|
||||
t := math.clamp(d / WORLD_RADIUS, 0, 1)
|
||||
return rl.Color{u8(40 + 180 * t), 120, u8(255 - 180 * t), 255}
|
||||
}
|
||||
|
||||
update :: proc() {
|
||||
// Orbital camera: drag to rotate, scroll to zoom, right-drag / shift to pan.
|
||||
rl.UpdateCamera(&camera, .ORBITAL)
|
||||
}
|
||||
|
||||
draw :: proc() {
|
||||
rl.BeginDrawing()
|
||||
defer rl.EndDrawing()
|
||||
|
||||
rl.ClearBackground({5, 5, 15, 255})
|
||||
|
||||
rl.BeginMode3D(camera)
|
||||
defer rl.EndMode3D()
|
||||
|
||||
rl.DrawGrid(20, 50.0)
|
||||
|
||||
for galaxy in universe {
|
||||
rl.DrawPoint3D(galaxy.position, galaxy.color)
|
||||
}
|
||||
|
||||
rl.DrawFPS(10, 10)
|
||||
rl.DrawText(
|
||||
"DESI Explorer — drag to rotate, scroll to zoom",
|
||||
10,
|
||||
34,
|
||||
18,
|
||||
rl.RAYWHITE,
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user