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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
//! Typed attribute / parameter names — compile-time witnesses for ɴsɪ
//! `NSIParam_t` identifiers.
//!
//! On the C side, ɴsɪ uses a single `NSIParam_t` struct everywhere. On the
//! Rust side that single C concept splits into two semantic roles, both of
//! which boil down to the *same* underlying type:
//!
//! - [`Attribute<T>`] — properties **set on a node** (govern how the scene
//! looks): `P`, `Pw`, `fov`, `transformationmatrix`, `uknot`, …
//! - [`Parameter<T>`] — optional arguments **to a function** (govern how
//! the call behaves): `streamformat`, `errorhandler`, `stoppedcallback`, …
//!
//! `Parameter<T>` is just a type alias for `Attribute<T>` — the conceptual
//! split exists so the constants and docs read more naturally, but the
//! machinery is identical.
//!
//! End-users normally don't write these types out — they just reference the
//! exported `const`s through the parameter macros:
//!
//! ```text
//! nsi::point_slice!(POSITION, &points) // node attribute (was: P)
//! nsi::string!(STREAM_FORMAT, "nsi") // function parameter to NSIBegin
//! ```
//!
//! Renderer- or app-specific entries are added in downstream crates without
//! touching this one — `Attribute::new` is `const`:
//!
//! ```ignore
//! pub const MY_RENDERER_THING: Attribute<f32> = Attribute::new("custom_thing");
//! ```
use PhantomData;
// ─── Geometric type aliases ─────────────────────────────────────────────────
//
// Scalar attribute data uses the Rust primitives directly (`f32`, `f64`,
// `i32`, `i64`) -- no aliases. Geometric types are aliases of fixed-size
// arrays so that slice length is a multiple of the component count at the
// type level.
/// 2D point with `f32` components — typically a parametric (u, v) coordinate.
pub type Point2F32 = ;
/// 3D point with `f32` components — Cartesian position.
pub type Point3F32 = ;
/// 4D point with `f32` components — rational/weighted homogeneous (xyzw).
pub type Point4F32 = ;
/// 2D vector with `f32` components.
pub type Vector2F32 = ;
/// 3D vector with `f32` components.
pub type Vector3F32 = ;
/// 3D normal with `f32` components.
pub type Normal3F32 = ;
/// RGB color with `f32` components.
pub type Color3F32 = ;
/// RGBA color with `f32` components.
pub type Color4F32 = ;
/// 3×3 matrix with `f32` components.
pub type Matrix3F32 = ;
/// 4×4 matrix with `f32` components.
pub type Matrix4F32 = ;
/// 4×4 matrix with `f64` components.
pub type Matrix4F64 = ;
// ─── Attribute<T> ───────────────────────────────────────────────────────────
/// Typed name of an ɴsɪ attribute.
///
/// `T` is the data shape the attribute accepts. Slice-typed `T = [U]` means
/// the attribute carries an array of `U`.
// Manual derives so generic bounds don't require T: Clone/Copy/Debug — T is
// only ever used in PhantomData<fn() -> T> which is already Copy/Send/Sync.
// SAFETY: Attribute<T> contains only a `&'static str` and PhantomData.
// PhantomData<fn() -> T> is variant-correct (covariant in T) and Send + Sync
// regardless of T, so the auto-derive would also be Send + Sync — but we make
// it explicit so users don't worry about T's bounds.
unsafe
unsafe
/// Typed name of an ɴsɪ function-parameter — alias of [`Attribute<T>`].
///
/// Used for the optional arguments passed to ɴsɪ calls (`NSIBegin`,
/// `NSIRenderControl`, `NSIEvaluate`, …) that govern *how the call behaves*,
/// as opposed to [`Attribute<T>`] which is set on nodes to govern *how the
/// scene looks*. The C side uses a single `NSIParam_t` struct for both, so
/// `Parameter<T>` and `Attribute<T>` are the same Rust type — the alias
/// exists so consumers and docs can name the role precisely.
pub type Parameter<T> = ;
// ─── Standard ɴsɪ attribute names ───────────────────────────────────────────
//
// Rust constant identifiers are derived from the **new** wire-name convention
// (see the `naming-convention.md` chapter in the ɴsɪ spec). Mapping rule:
// take the new name, replace `-` and `.` with `_`, uppercase. Examples:
//
// new wire Rust const
// -------- ----------
// field-of-view FIELD_OF_VIEW
// u.count U_COUNT
// trim-curves. TRIM_CURVES_*
// callback.error CALLBACK_ERROR
//
// The string literals below intentionally still hold the **old** wire names
// (e.g. `"fov"`, `"nu"`, `"errorhandler"`) so the constants work against a
// pre-rename 3DelightNSI. Once the renderer ships the new names, only the
// string literals here need to change -- the public Rust API stays stable.
// Camera --------------------------------------------------------------------
/// `field-of-view` (currently `fov`) — perspective camera FOV in degrees.
pub const FIELD_OF_VIEW: = new;
// Screen --------------------------------------------------------------------
/// `resolution` — pixel resolution of a `screen` node, `[width, height]`.
pub const RESOLUTION: = new;
/// `oversampling` — pixel oversampling rate.
pub const OVERSAMPLING: = new;
// Transform / shading -------------------------------------------------------
/// `matrix` (currently `transformationmatrix`) — 4×4 row-major matrix (`f64`).
pub const MATRIX: =
new;
/// `filename` (currently `shaderfilename`) — OSL shader filename.
pub const FILENAME: = new;
// Common geometry attrs -----------------------------------------------------
/// `position` (currently `P`) — Cartesian control points / vertices.
///
/// Slice of 3-component f32 points; total component count is divisible by 3
/// at the type level.
pub const POSITION: = new;
/// `weighted-position` (currently `Pw`) — rational (weighted homogeneous)
/// control points: xyzw.
pub const WEIGHTED_POSITION: = new;
// NURBS surface intrinsics --------------------------------------------------
/// `u.count` (currently `nu`) — control-point count along *u*.
pub const U_COUNT: = new;
/// `v.count` (currently `nv`) — control-point count along *v*.
pub const V_COUNT: = new;
/// `u.order` (currently `uorder`) — order along *u* (degree + 1, ≥ 2).
pub const U_ORDER: = new;
/// `v.order` (currently `vorder`) — order along *v* (degree + 1, ≥ 2).
pub const V_ORDER: = new;
/// `u.knot` (currently `uknot`) — knot vector along *u*; length = `nu + uorder`.
pub const U_KNOT: = new;
/// `v.knot` (currently `vknot`) — knot vector along *v*; length = `nv + vorder`.
pub const V_KNOT: = new;
// NURBS trim curves ---------------------------------------------------------
/// `trim-curves.loop-count` (currently `trimcurves.nloops`) — number of
/// trim loops on a NURBS surface.
pub const TRIM_CURVES_LOOP_COUNT: =
new;
/// `trim-curves.curve-count` (currently `trimcurves.ncurves`) — curves per loop.
pub const TRIM_CURVES_CURVE_COUNT: =
new;
/// `trim-curves.cv-count` (currently `trimcurves.n`) — control-point count
/// per trim curve.
pub const TRIM_CURVES_CV_COUNT: =
new;
/// `trim-curves.order` — order per trim curve (degree + 1).
pub const TRIM_CURVES_ORDER: =
new;
/// `trim-curves.knot` — concatenated knots; total length = Σ(`n[i] + order[i]`).
pub const TRIM_CURVES_KNOT: =
new;
/// `trim-curves.min` — parametric start per trim curve.
pub const TRIM_CURVES_MIN: = new;
/// `trim-curves.max` — parametric end per trim curve.
pub const TRIM_CURVES_MAX: = new;
/// `trim-curves.u` — concatenated *u* control values; length = Σ`n[i]`.
pub const TRIM_CURVES_U: = new;
/// `trim-curves.v` — concatenated *v* control values; length = Σ`n[i]`.
pub const TRIM_CURVES_V: = new;
/// `trim-curves.w` — concatenated weights; length = Σ`n[i]`.
pub const TRIM_CURVES_W: = new;
/// `trim-curves.sense` — one per loop. `0` = keep inside, `1` = keep outside (hole).
pub const TRIM_CURVES_SENSE: =
new;
// Globals / render-control --------------------------------------------------
/// `bucket-order` (currently `bucketorder`) — bucket traversal pattern
/// (`"horizontal"`, `"spiral"`, …).
pub const BUCKET_ORDER: = new;
// ─── Function-level parameters (Parameter<T>) ───────────────────────────────
//
// These govern how an ɴsɪ *call* behaves rather than how a node looks. The
// underlying type is the same -- `Parameter<T>` is just an alias for
// `Attribute<T>` -- the split is purely for readability at call sites.
/// `stream.format` (currently `streamformat`) — output stream format for
/// `NSIBegin` (`"nsi"`, `"binarynsi"`, `"autonsi"`).
pub const STREAM_FORMAT: =
new;
/// `stream.filename` (currently `streamfilename`) — output file path when
/// `NSIBegin` is invoked in stream-to-file mode.
pub const STREAM_FILENAME: =
new;
/// `stream.path-replacement` (currently `streampathreplace`) — substitution
/// pairs applied to paths in the output stream.
pub const STREAM_PATH_REPLACEMENT: =
new;
/// `callback.error` (currently `errorhandler`) — error-handler callback
/// registered through `NSIBegin`.
pub const CALLBACK_ERROR: =
new;
/// `callback.stop` (currently `stoppedcallback`) — callback fired when an
/// interactive render stops.
pub const CALLBACK_STOP: =
new;