diff --git a/docs/README.md b/docs/README.md index b5bd14e..8b5bbbd 100644 --- a/docs/README.md +++ b/docs/README.md @@ -30,5 +30,6 @@ The SDK and toolchain guides for creating your own `.elf` userland binaries. - [`Widget API`](appdev/widget_api.md): High-level UI components like buttons, textboxes, and scrollbars using `libwidget.h`. - [`Custom Apps`](appdev/custom_apps.md): A step-by-step tutorial on writing a new graphical C application, editing the Makefile, and bundling it into the ISO. - [`Example Apps`](appdev/examples/README.md): A collection of sample C applications ranging from basic terminal output to advanced TCP networking. +- [`Grapher`](appdev/grapher.md): Full reference for the built-in mathematical graphing application — equation syntax, keyboard controls, architecture, and configuration. --- diff --git a/docs/appdev/grapher.md b/docs/appdev/grapher.md new file mode 100644 index 0000000..48abc69 --- /dev/null +++ b/docs/appdev/grapher.md @@ -0,0 +1,330 @@ +
+

Grapher

+

An interactive mathematical expression plotter for BoredOS, supporting both 2D and 3D visualizations.

+
+ +--- + +Grapher is a built-in GUI application that lets you type any mathematical equation and see it plotted in real time. It supports 2D explicit and implicit curves as well as full 3D surface visualization — including both explicit surfaces (`z = f(x, y)`) and implicit surfaces (`f(x, y, z) = c`). + +> [!NOTE] +> Grapher is located at `src/userland/gui/grapher.c`. It runs as a standard BoredOS GUI process and can be launched from the terminal or from the dock. + +--- + +## Features at a Glance + +| Feature | Details | +|---|---| +| **2D Explicit** | Plot `y = f(x)` curves | +| **2D Implicit** | Plot any `f(x, y) = g(x, y)` contour via marching squares | +| **3D Explicit** | Plot `z = f(x, y)` surfaces | +| **3D Implicit** | Plot `f(x, y, z) = c` surfaces via Z-axis root finding (has rendering issues in filled mode)| +| **Rendering modes** | Wireframe and filled polygon modes | +| **Height coloring** | Surfaces are colored by a blue→green→yellow→red gradient based on Z height | +| **Phong-style shading** | Filled mode computes per-face normals and applies diffuse + ambient lighting | +| **Parallel rendering** | Evaluation and projection are distributed across 4 worker threads via `sys_parallel_run` | +| **Preset equations** | 7 built-in presets accessible from the toolbar | +| **Auto-fit** | 2D view auto-fits the Y axis to the plotted curve on first plot | +| **Z-buffer** | All 3D drawing uses a per-pixel depth buffer with atomic CAS for thread safety | + +--- + +## Launching Grapher + +From the BoredOS terminal: +```sh +grapher +``` + +Or click the **Grapher icon** in the system dock. + +--- + + + +### Toolbar Controls + +| Control | Function | +|---|---| +| **Equation box** | Type your mathematical expression, then press **Enter** or **Plot** | +| **Plot button** | Parse and render the current equation | +| **Wire / Filled button** | Toggle wireframe vs. shaded polygon mode (3D only) | +| **Presets button** | Open a dropdown of example equations | + +### Status Bar Controls (3D mode) + +| Control | Function | +|---|---| +| **`+` button** | Increase the 3D world range (zoom out in world space) | +| **`-` button** | Decrease the 3D world range (zoom in in world space) | + +--- + +## Keyboard Shortcuts + +| Shortcut | Action | +|---|---| +| **Enter** (in equation box) | Plot the equation | +| **Ctrl + R** | Reset the view to defaults | +| **F** | Toggle filled / wireframe rendering (3D mode) | +| **Scroll wheel** | Zoom in/out (2D mode adjusts viewport; 3D mode adjusts camera zoom) | +| **Right-click drag** | Rotate the 3D surface | + +--- + +## Writing Equations + +Grapher parses equations entered as plain text. It supports a subset of mathematical notation with automatic implicit multiplication. + +### Supported Functions + +| Syntax | Meaning | +|---|---| +| `sin(x)` | Sine | +| `cos(x)` | Cosine | +| `tan(x)` | Tangent | +| `sqrt(x)` | Square root | +| `abs(x)` | Absolute value | +| `log(x)` | Natural logarithm (base *e*) | + +### Supported Operators + +| Operator | Meaning | +|---|---| +| `+` `-` `*` `/` | Arithmetic | +| `^` | Exponentiation (right-associative) | +| `(` `)` | Grouping | + +### Special Values + +| Token | Value | +|---|---| +| `pi` or `PI` | π ≈ 3.14159… | + +### Implicit Multiplication + +Adjacent tokens that would normally require a `*` are multiplied automatically: + +``` +2x → 2 * x +3sin(x) → 3 * sin(x) +(x+1)(x) → (x+1) * x +``` + +### How Equations Are Classified + +Grapher looks at which variables appear in your equation to automatically choose the rendering mode: + +| Equation form | Auto-detected as | +|---|---| +| `y = f(x)` or just `f(x)` | 2D explicit | +| `f(x, y) = g(x, y)` | 2D implicit | +| `z = f(x, y)` | 3D explicit | +| `f(x, y, z) = c` | 3D implicit | + +If you omit the `=` sign, Grapher treats the input as `y = ` when no `y` or `z` is present, or as ` = 0` otherwise. + +--- + +## Example Equations + +### 2D Examples + +``` +y = sin(x) +y = x^2 +y = cos(x)*x +y = abs(x) - 2 +x^2 + y^2 = 25 ← circle (implicit) +y = log(x) +``` + +### 3D Explicit Examples + +``` +z = sin(x)*cos(y) +z = x^2 - y^2 ← saddle surface +z = sqrt(25 - x^2 - y^2) +``` + +### 3D Implicit Examples + +``` +x^2 + y^2 + z^2 = 25 ← sphere +x^2 + y^2 = 16 ← cylinder +x^2 + y^2 - z^2 = 1 ← hyperboloid +``` + +--- + +## Navigation Controls + +### 2D Mode + +| Input | Action | +|---|---| +| **Scroll up** | Zoom in | +| **Scroll down** | Zoom out | +| **Ctrl+R** | Reset to default view (`x: [-10, 10]`) | + +### 3D Mode + +| Input | Action | +|---|---| +| **Right-click drag** | Rotate the surface (orbit camera) | +| **Scroll up** | Zoom camera in | +| **Scroll down** | Zoom camera out | +| **`+` / `-` buttons** | Increase / decrease world range | +| **Ctrl+R** | Reset rotation and zoom | + +> [!TIP] +> In 3D mode, the surface auto-rotates slowly by default. This can be disabled by setting `#define ROTATE 0` in the source file. + +--- + +## Architecture Overview + +Grapher is implemented as a single self-contained C file. Below is a high-level breakdown of its major components: + +### Math Library + +Grapher uses the BoredOS freestanding **`libc/math.h`** library, which provides all the math functions it needs without depending on a host standard library: + +| Function | Description | +|---|---| +| `sin`, `cos`, `tan` | Trigonometry via Taylor series (8 terms, range-reduced to `[-π, π]`) | +| `sqrt` | Newton-Raphson iteration (25 steps) | +| `log` | Natural logarithm via Padé-style series | +| `log2`, `log10` | Derived from `log` | +| `exp` | Range-reduced Taylor series for `e^x` | +| `pow` | Integer exponents use fast binary exponentiation; fractional exponents use `exp(e * log(b))` | +| `fabs`, `fmod` | Absolute value and floating-point remainder | +| `floor`, `ceil` | Rounding | +| `sinh`, `cosh`, `tanh` | Hyperbolic functions | +| `hypot`, `fmin`, `fmax`, `fclamp` | Utility helpers | + +The constants `M_PI`, `M_E`, `M_LN2`, `M_SQRT2` are also defined in the header. + +This library is automatically linked into every userland ELF — any app can `#include "math.h"` to use it. + +### Expression Parser + +Equations are parsed in three stages: + +1. **Tokenizer** (`tokenize`) — converts the input string into a flat token array. Handles implicit multiplication by inserting `*` tokens where needed. +2. **Recursive Descent Parser** (`parse_expr`, `parse_term`, `parse_power`, `parse_unary`, `parse_atom`) — produces an Abstract Syntax Tree (AST) with up to `MAX_NODES = 128` nodes. +3. **Bytecode Compiler** (`compile_ast`) — walks the AST in post-order and emits a flat instruction sequence for a simple stack machine. This avoids recursive evaluation during rendering hot paths. + +The resulting bytecode is then executed by `run_bc` for every sample point. + +### Rendering Pipeline + +#### 2D Rendering + +- **Explicit** — evaluates `y = f(x)` at every pixel column and connects adjacent samples with Bresenham lines. +- **Implicit** — applies **marching squares** on a 200×130 grid to find sign changes in `f(x,y) - g(x,y)` and plots intersection pixels. + +#### 3D Rendering + +The 3D pipeline is a three-pass system, each parallelised across 4 threads: + +| Pass | Function | Description | +|---|---|---| +| 1 | **Evaluation** | Samples the surface at every grid point in a `GRID_3D × GRID_3D` grid | +| 2 | **Projection** | Projects 3D world coordinates to 2D screen coordinates with perspective | +| 3 | **Drawing** | Rasterizes wireframe lines or filled triangles with Z-buffering | + +For **implicit surfaces**, Pass 1 additionally marches along the Z axis at 512 steps per column using bisection (15 iterations) to find up to `MAX_Z_PER_POINT = 4` roots. + +Surface normals are estimated using central finite differences of the implicit function. + +#### Filled Mod + +When filled mode is active, each quad cell is split into two triangles. The average surface normal across the four corner vertices is computed and fed into `apply_shading`, which calculates: + +``` +intensity = ambient(0.3) + diffuse(0.7) * dot(normal, light_direction) +``` + +The light direction is fixed at `(0.577, 0.707, 0.408)` (normalized diagonal). + +#### Z-Buffer + +The depth buffer (`graph_zb`) stores integer depth values. `gfb_pixel_z` uses a **compare-and-swap (CAS) loop** via `__atomic_compare_exchange_n` so multiple parallel draw threads cannot produce race conditions. + +### Coordinate Systems + +#### 2D + +World coordinates map linearly to screen pixels: + +```c +screen_x = (wx - view_x_min) / (view_x_max - view_x_min) * graph_w +screen_y = (view_y_max - wy) / (view_y_max - view_y_min) * graph_h +``` + +#### 3D + +Points are first rotated by two Euler angles (`rot_y`, `rot_x`) then projected with a simple perspective divide: + +``` +persp = d / (pz + d) // d = range_3d * 5 +sx = px * scale * persp + screen_cx +sy = -py * scale * persp + screen_cy +``` + +--- + +## Configuration Constants + +These can be changed at the top of `grapher.c` to tune behaviour: + +| Constant | Default | Effect | +|---|---|---| +| `ROTATE` | `1` | Set to `0` to disable auto-rotation in 3D mode | +| `GRID_3D` | `256` | Grid resolution for 3D sampling. Higher = more detail, much slower | + +> [!WARNING] +> Setting `GRID_3D` too high (e.g. 9000) will exhaust available memory. The `surf` grid and `surf_x`/`surf_y_3d` arrays are statically allocated at compile time: memory usage grows as **O(GRID_3D²)**. Values above ~512 are not recommended. + +> [!TIP] +> `GRID_3D = 256` gives a good balance of detail and performance on typical BoredOS hardware emulation. + +--- + +## Color Palette + + +3D surfaces are colored by height using a 4-stop rainbow ramp: + +``` +Low → Blue → Cyan → Green → Yellow → Red → High +``` + +--- + +## Preset Equations + +The built-in presets are shown in the dropdown when you click **Presets**: + +| Label | Type | +|---|---| +| `y = sin(x)` | 2D explicit | +| `y = x^2` | 2D explicit | +| `y = cos(x)*x` | 2D explicit | +| `z = sin(x)*cos(y)` | 3D explicit | +| `z = x^2 - y^2` | 3D explicit | +| `x^2+y^2+z^2=25` | 3D implicit (sphere) | +| `x^2+y^2=16` | 3D implicit (cylinder) | + +--- + +## Known Limitations + +- **No parameter slider** — equations are static; there is no way to animate a parameter. +- **No multiple equations** — only one equation can be graphed at a time. +- **Implicit surface gaps** — very thin or high-frequency implicit surfaces may have small gaps due to the fixed Z marching step count (512 steps per column). +- **3D implicit performance** — implicit surfaces require significantly more work than explicit ones; evaluating `x^2+y^2+z^2=25` at `GRID_3D=256` takes a noticeable fraction of a second. +- **Integer axis labels only for large values** — very large axis values are capped at `>2G` or `<-2G` due to `itoa` limitations. +- **3D polygon implicit mode** - 3D polygon implicit mode has problems with connecting hemispheres of a circle causing for dead space on the equator. diff --git a/docs/appdev/sdk_reference.md b/docs/appdev/sdk_reference.md index 7cde6cd..2fed154 100644 --- a/docs/appdev/sdk_reference.md +++ b/docs/appdev/sdk_reference.md @@ -8,6 +8,8 @@ BoredOS provides a custom `libc` implementation necessary for writing userland applications (`.elf` binaries). By avoiding a full-blown standard library like `glibc`, the OS ensures a minimal executable footprint tailored strictly to the existing kernel features. All headers are located in `src/userland/libc/` (standard functions) and `src/wm/` (UI and widgets). +- `stdlib.h`: Memory, strings, and basic I/O. +- `math.h`: Freestanding floating-point math library. - `libui.h`: Core window and drawing API. - `libwidget.h`: High-level UI components. @@ -47,7 +49,60 @@ The standard library wrappers provide memory management, string manipulation, an --- -## System Calls (`syscall.h`) +## Math Library (`math.h`) + +BoredOS ships a freestanding floating-point math library in `libc/math.h`. It uses pure arithmetic — Taylor series, Newton-Raphson, and range-reduction — with no dependency on a host `libm` or hardware math intrinsics. It is automatically linked into every userland ELF. + +```c +#include "math.h" +``` + +### Constants + +| Constant | Value | Description | +|---|---|---| +| `M_PI` | 3.14159… | π | +| `M_E` | 2.71828… | Euler's number | +| `M_LN2` | 0.69315… | Natural log of 2 | +| `M_SQRT2` | 1.41421… | √2 | +| `HUGE_VAL` | ~+∞ | Overflow sentinel | + +### Functions + +#### Absolute value & remainder +* `double fabs(double x);` — Absolute value. +* `double fmod(double x, double y);` — Floating-point remainder. Returns `0` when `y == 0`. + +#### Rounding +* `double floor(double x);` — Largest integer ≤ x. +* `double ceil(double x);` — Smallest integer ≥ x. + +#### Trigonometry *(arguments in radians)* +* `double sin(double x);` — Sine. Range-reduced to `[-π, π]` then computed via 8-term Taylor series. +* `double cos(double x);` — Cosine. Computed via `sin(x + π/2)`. +* `double tan(double x);` — Tangent. Returns sentinel `1e15` near poles. + +#### Exponential & logarithm +* `double sqrt(double x);` — Square root via Newton-Raphson (25 iterations). Returns `0` for `x ≤ 0`. +* `double log(double x);` — Natural logarithm (ln). Returns `-1e30` for `x ≤ 0`. +* `double log2(double x);` — Base-2 logarithm. +* `double log10(double x);` — Base-10 logarithm. +* `double exp(double x);` — e^x. Saturates to `1e300` for `x > 700`, `0` for `x < -700`. +* `double pow(double base, double exponent);` — General power. Integer exponents use fast binary exponentiation; fractional exponents use `exp(e * log(b))`. + +#### Hyperbolic +* `double sinh(double x);` — Hyperbolic sine. +* `double cosh(double x);` — Hyperbolic cosine. +* `double tanh(double x);` — Hyperbolic tangent. + +#### Utility +* `double hypot(double x, double y);` — `sqrt(x² + y²)` without intermediate overflow. +* `double fmin(double a, double b);` — Minimum of two values. +* `double fmax(double a, double b);` — Maximum of two values. +* `double fclamp(double x, double lo, double hi);` — Clamps `x` into `[lo, hi]`. + +> [!NOTE] +> The implementation file is named `libc/libmath.c` (not `libc/math.c`) to avoid a name collision with the `math` CLI calculator app in userland. The public header is still included as `#include "math.h"`. For advanced operations, `syscall.h` provides direct wrappers into the kernel.