352 lines
8.6 KiB
Markdown
352 lines
8.6 KiB
Markdown
# Cordial Language Reference
|
|
|
|
Cordial is the primary source language for the Cord geometry system.
|
|
It compiles to a trigonometric intermediate representation (TrigGraph)
|
|
which can be evaluated as an f64 reference, compiled to WGSL shaders
|
|
for GPU raymarching, or lowered to pure CORDIC shift-and-add arithmetic.
|
|
|
|
File extension: `.crd`
|
|
|
|
---
|
|
|
|
## Variables
|
|
|
|
```
|
|
let r = 5
|
|
let height = 2 * pi
|
|
let s: Obj = sphere(r)
|
|
```
|
|
|
|
- `let` introduces a new variable.
|
|
- `: Obj` type annotation marks a variable as a renderable 3D object.
|
|
- Variables can be reassigned: `r = 10` (no `let` on reassignment).
|
|
|
|
---
|
|
|
|
## Constants
|
|
|
|
| Name | Value |
|
|
|-----------|---------------|
|
|
| `pi`, `PI`| 3.14159... |
|
|
| `e`, `E` | 2.71828... |
|
|
| `x` | Input X coord |
|
|
| `y` | Input Y coord |
|
|
| `z` | Input Z coord |
|
|
| `reg` | NaN register |
|
|
|
|
`x`, `y`, `z` are the spatial coordinates — use them to build
|
|
mathematical expressions and SDF fields directly.
|
|
|
|
---
|
|
|
|
## Arithmetic
|
|
|
|
| Syntax | Operation |
|
|
|---------|----------------|
|
|
| `a + b` | Addition |
|
|
| `a - b` | Subtraction |
|
|
| `a * b` | Multiplication |
|
|
| `a / b` | Division |
|
|
| `a ^ b` | Power (²,³ optimized) |
|
|
| `-a` | Negation |
|
|
|
|
Precedence: unary > power > multiplicative > additive.
|
|
Parentheses for grouping: `(a + b) * c`.
|
|
|
|
---
|
|
|
|
## Comments
|
|
|
|
```
|
|
// line comment
|
|
/= also a line comment
|
|
|
|
/* block comment */
|
|
/* nested /* block */ comments */
|
|
```
|
|
|
|
---
|
|
|
|
## Trig Functions
|
|
|
|
| Function | Aliases | Description |
|
|
|----------|---------|-------------|
|
|
| `sin(x)` | | Sine |
|
|
| `cos(x)` | | Cosine |
|
|
| `tan(x)` | | Tangent |
|
|
| `asin(x)` | `arcsin` | Inverse sine |
|
|
| `acos(x)` | `arccos`, `arcos` | Inverse cosine |
|
|
| `atan(x)` | `arctan` | Inverse tangent |
|
|
| `sinh(x)` | | Hyperbolic sine |
|
|
| `cosh(x)` | | Hyperbolic cosine |
|
|
| `tanh(x)` | | Hyperbolic tangent |
|
|
| `asinh(x)` | `arcsinh` | Inverse hyperbolic sine |
|
|
| `acosh(x)` | `arccosh`, `arcosh` | Inverse hyperbolic cosine |
|
|
| `atanh(x)` | `arctanh` | Inverse hyperbolic tangent |
|
|
|
|
---
|
|
|
|
## Math Functions
|
|
|
|
| Function | Aliases | Description |
|
|
|----------|---------|-------------|
|
|
| `sqrt(x)` | | Square root |
|
|
| `exp(x)` | | e^x |
|
|
| `ln(x)` | `log` | Natural logarithm |
|
|
| `abs(x)` | | Absolute value |
|
|
| `hypot(a, b)` | | √(a² + b²) |
|
|
| `atan2(y, x)` | | Two-argument arctangent |
|
|
| `min(a, b)` | | Minimum |
|
|
| `max(a, b)` | | Maximum |
|
|
| `length(a, b)` | `mag` | Magnitude (2D or 3D) |
|
|
| `mix(a, b, t)` | `lerp` | Linear interpolation |
|
|
| `clip(x, lo, hi)` | `clamp` | Clamp to range |
|
|
| `smoothstep(e0, e1, x)` | | Hermite interpolation |
|
|
| `quantize(x, step)` | | Snap to grid |
|
|
|
|
---
|
|
|
|
## SDF Primitives
|
|
|
|
These construct signed distance fields centered at the origin.
|
|
All dimensions are half-extents (centered geometry).
|
|
|
|
| Function | Arguments | Description |
|
|
|----------|-----------|-------------|
|
|
| `sphere(r)` | radius | Sphere |
|
|
| `box(hx, hy, hz)` | half-extents | Axis-aligned box |
|
|
| `cylinder(r, h)` | radius, half-height | Z-axis cylinder |
|
|
| `ngon(n, side)` | sides (≥3), side length | Regular polygon prism |
|
|
| `N-gon(side)` | side length | Shorthand: `6-gon(2)` = hexagonal prism |
|
|
|
|
---
|
|
|
|
## Transforms
|
|
|
|
Transforms take an SDF as the first argument and modify its coordinate space.
|
|
|
|
| Function | Aliases | Arguments | Description |
|
|
|----------|---------|-----------|-------------|
|
|
| `translate(sdf, tx, ty, tz)` | `mov`, `move` | SDF + offsets | Translate |
|
|
| `rotate_x(sdf, angle)` | `rx` | SDF + radians | Rotate around X |
|
|
| `rotate_y(sdf, angle)` | `ry` | SDF + radians | Rotate around Y |
|
|
| `rotate_z(sdf, angle)` | `rz` | SDF + radians | Rotate around Z |
|
|
| `scale(sdf, factor)` | | SDF + uniform scale | Uniform scale |
|
|
| `mirror_x(sdf)` | `mx` | SDF | Mirror across YZ plane |
|
|
| `mirror_y(sdf)` | `my` | SDF | Mirror across XZ plane |
|
|
| `mirror_z(sdf)` | `mz` | SDF | Mirror across XY plane |
|
|
|
|
---
|
|
|
|
## CSG Boolean Operations
|
|
|
|
| Function | Aliases | Arguments | Description |
|
|
|----------|---------|-----------|-------------|
|
|
| `union(a, b)` | | two SDFs | Union (min) |
|
|
| `intersect(a, b)` | | two SDFs | Intersection (max) |
|
|
| `diff(a, b)` | `subtract` | two SDFs | Difference (max(a, -b)) |
|
|
|
|
---
|
|
|
|
## Waveform Functions
|
|
|
|
| Function | Arguments | Description |
|
|
|----------|-----------|-------------|
|
|
| `saw(x)` | input | Sawtooth wave |
|
|
| `tri(x)` | input | Triangle wave |
|
|
| `square(x)` | input | Square wave |
|
|
|
|
---
|
|
|
|
## DSP / Signal Functions
|
|
|
|
| Function | Arguments | Description |
|
|
|----------|-----------|-------------|
|
|
| `am(signal, carrier, depth)` | | Amplitude modulation |
|
|
| `fm(signal, carrier, index)` | | Frequency modulation |
|
|
| `lpf(signal, cutoff)` | | Low-pass filter approximation |
|
|
| `hpf(signal, cutoff)` | | High-pass filter approximation |
|
|
| `bpf(signal, lo, hi)` | | Band-pass filter approximation |
|
|
| `dft(signal, n)` | | Discrete Fourier approximation |
|
|
| `hilbert(x)` | `envelope` | Analytic signal envelope |
|
|
| `phase(x)` | | Instantaneous phase |
|
|
|
|
---
|
|
|
|
## User-Defined Functions
|
|
|
|
```
|
|
f(a, b) = a^2 + b^2
|
|
let result = f(3, 4)
|
|
```
|
|
|
|
Define with `name(params) = body`. Body extends to the next
|
|
newline or semicolon. Functions are expanded inline at each call site.
|
|
|
|
---
|
|
|
|
## Schematics (`sch`)
|
|
|
|
Schematics are parameterized multi-statement blocks — like functions but
|
|
with full block bodies containing `let` bindings, intermediate variables,
|
|
and arbitrary nesting. The last expression is the return value.
|
|
|
|
```
|
|
sch Bracket(w, h, t) {
|
|
let plate: Obj = box(w, h, t)
|
|
let rib: Obj = box(t, h/2, t)
|
|
union(plate, translate(rib, w/2, 0, 0))
|
|
}
|
|
|
|
let b = Bracket(10, 5, 0.5)
|
|
cast(b)
|
|
```
|
|
|
|
Schematics can call other schematics and user-defined functions.
|
|
They can contain any number of statements.
|
|
|
|
```
|
|
sch Peg(r, h) {
|
|
let shaft = cylinder(r, h)
|
|
let head = translate(sphere(r * 1.5), 0, 0, h)
|
|
union(shaft, head)
|
|
}
|
|
|
|
sch PegRow(n, spacing) {
|
|
map(i, 0..n) { translate(Peg(0.5, 3), i * spacing, 0, 0) }
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Iteration (`map`)
|
|
|
|
`map` evaluates a body for each integer in a range and unions all
|
|
results. Iteration is unrolled at parse time — the TrigGraph is a DAG
|
|
with no runtime loops.
|
|
|
|
```
|
|
map(variable, start..end) { body }
|
|
```
|
|
|
|
- `variable` — bound to each integer in `[start, end)`
|
|
- `start..end` — exclusive range; bounds must resolve to constants
|
|
- `body` — any expression or block; can reference the iteration variable
|
|
- All iterations are unioned (min)
|
|
- Max 1024 iterations
|
|
|
|
### Examples
|
|
|
|
```
|
|
// Row of 5 spheres along X
|
|
let row = map(i, 0..5) { translate(sphere(1), i * 3, 0, 0) }
|
|
|
|
// Ring of 8 spheres
|
|
let ring = map(i, 0..8) {
|
|
rotate_z(translate(sphere(0.5), 5, 0, 0), i * pi/4)
|
|
}
|
|
|
|
// Grid using nested maps inside a schematic
|
|
sch Grid(nx, ny, spacing) {
|
|
map(i, 0..nx) {
|
|
map(j, 0..ny) {
|
|
translate(sphere(0.4), i * spacing, j * spacing, 0)
|
|
}
|
|
}
|
|
}
|
|
|
|
let g = Grid(4, 6, 2)
|
|
cast()
|
|
```
|
|
|
|
Since `map` is an expression, it works anywhere: inside `let` bindings,
|
|
as arguments to functions, inside schematic bodies, or nested in other maps.
|
|
|
|
---
|
|
|
|
## Rendering with `cast()`
|
|
|
|
Nothing renders without an explicit `cast()` call.
|
|
|
|
| Syntax | Effect |
|
|
|--------|--------|
|
|
| `cast()` | Render all defined variables |
|
|
| `cast(name)` | Render a specific variable |
|
|
| `name.cast()` | Dot syntax (Obj-typed variables only) |
|
|
|
|
Multiple `cast()` calls accumulate. The GUI provides a Render button
|
|
that inserts `cast()` automatically when new variables exist since
|
|
the last cast.
|
|
|
|
### Example
|
|
|
|
```
|
|
let a: Obj = sphere(3)
|
|
let b: Obj = box(4, 2, 1)
|
|
let c: Obj = translate(a, 5, 0, 0)
|
|
cast()
|
|
```
|
|
|
|
This renders `a`, `b`, and `c` as a union. Without `cast()`, nothing appears.
|
|
|
|
---
|
|
|
|
## Plotting with `plot()`
|
|
|
|
| Syntax | Effect |
|
|
|--------|--------|
|
|
| `plot()` | Plot all bare expressions |
|
|
| `plot(expr)` | Plot a specific expression |
|
|
|
|
The GUI provides a Plot button that inserts `plot()` when new
|
|
expressions exist since the last plot.
|
|
|
|
### Example
|
|
|
|
```
|
|
sin(x) * exp(-x^2)
|
|
plot()
|
|
```
|
|
|
|
---
|
|
|
|
## Complete Example
|
|
|
|
```
|
|
// Bolt head: hexagonal prism with a sphere on top
|
|
let head: Obj = 6-gon(3)
|
|
let dome: Obj = translate(sphere(3.2), 0, 0, 1.5)
|
|
let cap: Obj = intersect(head, dome)
|
|
|
|
// Shaft
|
|
let shaft: Obj = cylinder(1.2, 8)
|
|
let bolt: Obj = union(translate(cap, 0, 0, 8), shaft)
|
|
|
|
// Cross hole
|
|
let slot: Obj = box(0.4, 3, 10)
|
|
let slot2: Obj = rotate_z(slot, pi/2)
|
|
let cross: Obj = union(slot, slot2)
|
|
|
|
let final: Obj = diff(bolt, cross)
|
|
cast(final)
|
|
```
|
|
|
|
### Schematics + Iteration
|
|
|
|
```
|
|
// Reusable peg schematic
|
|
sch Peg(r, h) {
|
|
let shaft = cylinder(r, h)
|
|
let head = translate(sphere(r * 1.5), 0, 0, h)
|
|
union(shaft, head)
|
|
}
|
|
|
|
// Base plate with a ring of pegs
|
|
let plate: Obj = box(20, 20, 1)
|
|
let pegs: Obj = map(i, 0..8) {
|
|
rotate_z(translate(Peg(0.5, 3), 8, 0, 1), i * pi/4)
|
|
}
|
|
let assembly: Obj = union(plate, pegs)
|
|
cast(assembly)
|
|
```
|