nx_decl_simple_scene.nx source
↩ module page · 163 lines · 6428 B
1// nx_decl_simple_scene.nx -- second declarative #tag-style primitive.
2//
3// license_tier: ORIGINAL
4//
5// One substrate call composes random_environment + camera + lighting
6// into a fully-specified "simple scene" struct. Equivalent of the
7// TypeScript `#simple_scene <modifier>` directive. Validates that
8// the #tag pattern COMPOSES: nx_decl_simple_scene calls
9// nx_decl_random_environment for the env half, then adds camera +
10// light defaults per modifier.
11//
12// Per S-class roadmap §A3 -- second slice toward the user's vision:
13// "define something like #random_environment real and it generates
14// with other things like size or other stuff"
15
16// nx_safety_envelope:
17// intended_use: AUTO_APPLIED -- primitive-specific tuning queued
18// sil_target: SIL1
19// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail]
20// verdict: NOT_YET_EVALUATED
21
22import "nx_syscalls.nx"
23import "nx_types.nx"
24import "nx_tier.nx"
25import "nx_biome_classifier.nx"
26import "nx_decl_random_environment.nx"
27
28struct NxSimpleScene {
29 seed: nx_int,
30 modifier: nx_int,
31 // Pointer to environment (allocated by alloc helper).
32 env: *NxRandomEnvironment,
33 // Camera (Q14 fixed-point).
34 cam_yaw_q14: nx_int, // 0..2*pi in Q14 (0..102943)
35 cam_pitch_q14: nx_int, // -pi/2..pi/2 in Q14
36 cam_distance_m: nx_int, // meters from origin
37 cam_fov_deg: nx_int, // 0..180
38 // Light.
39 light_kind: nx_int, // sealed enum NX_SS_LIGHT_*
40 light_temp_kelvin: nx_int, // 1500..10000 K
41 light_intensity_q10: nx_int, // 0..1024
42 is_valid: nx_int,
43}
44
45// Light kinds (sealed enum).
46const NX_SS_LIGHT_DAWN: nx_int = 0 // 2800K, warm low sun
47const NX_SS_LIGHT_NOON: nx_int = 1 // 5500K, neutral overhead
48const NX_SS_LIGHT_DUSK: nx_int = 2 // 3200K, warm low sun
49const NX_SS_LIGHT_NIGHT: nx_int = 3 // 4100K, moonlight blue
50const NX_SS_LIGHT_OVERCAST: nx_int = 4 // 6500K, flat diffuse
51const NX_SS_LIGHT_ALIEN: nx_int = 5 // 9000K, sci-fi cool
52const NX_SS_LIGHT_FANTASTICAL: nx_int = 6 // 7500K, magical
53const NX_SS_LIGHT_N: nx_int = 7
54
55func nx_ss_light_is_valid(l: nx_int) -> nx_int {
56 if l < 0 { return 0 }
57 if l >= NX_SS_LIGHT_N { return 0 }
58 return 1
59}
60
61// Elm-style reflection: light kind -> human name.
62func nx_ss_light_name(l: nx_int) -> *u8 {
63 if l == NX_SS_LIGHT_DAWN { return "DAWN" as *u8 }
64 if l == NX_SS_LIGHT_NOON { return "NOON" as *u8 }
65 if l == NX_SS_LIGHT_DUSK { return "DUSK" as *u8 }
66 if l == NX_SS_LIGHT_NIGHT { return "NIGHT" as *u8 }
67 if l == NX_SS_LIGHT_OVERCAST { return "OVERCAST" as *u8 }
68 if l == NX_SS_LIGHT_ALIEN { return "ALIEN" as *u8 }
69 if l == NX_SS_LIGHT_FANTASTICAL { return "FANTASTICAL" as *u8 }
70 return "<invalid light>" as *u8
71}
72
73// Light defaults per (modifier, biome).
74func _ss_default_light(modifier: nx_int, biome: nx_int, seed: nx_int) -> nx_int {
75 if modifier == NX_RE_MODIFIER_SCI_FI { return NX_SS_LIGHT_ALIEN }
76 if modifier == NX_RE_MODIFIER_FANTASY { return NX_SS_LIGHT_FANTASTICAL }
77 // REAL: roll one of the four diurnal kinds from seed.
78 let roll: nx_int = _re_hash_mod(seed, 7, 5)
79 if roll == 0 { return NX_SS_LIGHT_DAWN }
80 if roll == 1 { return NX_SS_LIGHT_NOON }
81 if roll == 2 { return NX_SS_LIGHT_DUSK }
82 if roll == 3 { return NX_SS_LIGHT_NIGHT }
83 return NX_SS_LIGHT_OVERCAST
84}
85
86// Temperature (Kelvin) for a given light kind. Substrate-internal
87// table; mirrors the kind names.
88func _ss_light_kelvin(kind: nx_int) -> nx_int {
89 if kind == NX_SS_LIGHT_DAWN { return 2800 }
90 if kind == NX_SS_LIGHT_NOON { return 5500 }
91 if kind == NX_SS_LIGHT_DUSK { return 3200 }
92 if kind == NX_SS_LIGHT_NIGHT { return 4100 }
93 if kind == NX_SS_LIGHT_OVERCAST { return 6500 }
94 if kind == NX_SS_LIGHT_ALIEN { return 9000 }
95 if kind == NX_SS_LIGHT_FANTASTICAL { return 7500 }
96 return 5500
97}
98
99// Intensity Q10 for kind.
100func _ss_light_intensity_q10(kind: nx_int) -> nx_int {
101 if kind == NX_SS_LIGHT_DAWN { return 384 } // 0.375
102 if kind == NX_SS_LIGHT_NOON { return 1024 } // 1.0
103 if kind == NX_SS_LIGHT_DUSK { return 384 } // 0.375
104 if kind == NX_SS_LIGHT_NIGHT { return 102 } // 0.1
105 if kind == NX_SS_LIGHT_OVERCAST { return 640 } // 0.625
106 if kind == NX_SS_LIGHT_ALIEN { return 768 }
107 if kind == NX_SS_LIGHT_FANTASTICAL { return 896 }
108 return 512
109}
110
111// Default camera per modifier.
112func _ss_default_cam_distance(modifier: nx_int, env_size: nx_int) -> nx_int {
113 // Distance scales with environment size; ~3x tile size for a
114 // medium-far establishing shot.
115 return env_size * 3
116}
117
118func _ss_default_cam_fov(modifier: nx_int) -> nx_int {
119 if modifier == NX_RE_MODIFIER_SCI_FI { return 90 }
120 if modifier == NX_RE_MODIFIER_FANTASY { return 75 }
121 return 60
122}
123
124// Main declarator. Composes random_environment + camera + light.
125func nx_decl_simple_scene(out: *NxSimpleScene, modifier: nx_int, seed: nx_int) -> nx_int {
126 if nx_re_modifier_is_valid(modifier) == 0 {
127 out.is_valid = 0
128 return 0
129 }
130 out.seed = seed
131 out.modifier = modifier
132
133 // Phase 1: allocate + populate environment.
134 let env: *NxRandomEnvironment = nx_re_alloc()
135 nx_decl_random_environment(env, modifier, seed)
136 if env.is_valid == 0 {
137 out.is_valid = 0
138 return 0
139 }
140 out.env = env
141
142 // Phase 2: camera. Yaw is seed-hashed in [0, 2pi) Q14.
143 // 2*pi in Q14 = 102943. Q14 = 16384 per unit.
144 let two_pi_q14: nx_int = 102943
145 out.cam_yaw_q14 = _re_hash_mod(seed, 3, two_pi_q14)
146 out.cam_pitch_q14 = -8192 // -pi/4 Q14 (slight downward tilt)
147 out.cam_distance_m = _ss_default_cam_distance(modifier, env.size_tiles)
148 out.cam_fov_deg = _ss_default_cam_fov(modifier)
149
150 // Phase 3: light.
151 out.light_kind = _ss_default_light(modifier, env.biome, seed)
152 out.light_temp_kelvin = _ss_light_kelvin(out.light_kind)
153 out.light_intensity_q10 = _ss_light_intensity_q10(out.light_kind)
154
155 out.is_valid = 1
156 return 1
157}
158
159func nx_ss_alloc() -> *NxSimpleScene {
160 let raw: *u8 = sys_mmap(256)
161 let s: *NxSimpleScene = raw as *NxSimpleScene
162 return s
163}