# design - textures package

## Design

A quad mesh on a regular grid is completely determined by a tiny recipe: the grid `dimension` (nx, ny cells), the `extent` (xmin, xmax, ymin, ymax), and the y orientation (`ydown`). Everything in textures is a view of that recipe at some level of materialization:

- `quad_spec()` - the recipe itself, a plain serializable list, nothing materialized
- `quad_edges()` - the unexpanded intermediate, the x and y coordinates of the cell edges as two short vectors (nx + 1 and ny + 1 values)
- `quad_index()`, `quad_vertex()` - the materialized components, the 4 x (nx * ny) vertex index and the expanded vertex coordinates
- `quad_mesh()`, `quad()`, `quad_texture()` - assembled ‘mesh3d’ objects

‘mesh3d’ objects are constructed directly (rgl is not required, it lives in Suggests). With rgl installed they plot with `plot3d()`, `shade3d()`, `persp3d()`, `wire3d()`, or `dot3d()`, and `as.mesh3d()` works on a quad_spec via delayed S3 registration. A 2D base graphics `plot()` method is included.

### Conventions

- Default extent is the unit square, “y-up” (y begins at 0).
- Quads are emitted in cell order, x fastest - the `matrix()`/`image()` convention, and raster cell order when `ydown = TRUE`. Face-indexed values (colours, `na.rm`) align with grid cell order.
- Quad vertex winding is counter-clockwise, as required by rgl (see `material3d` `back` argument).
- `ydown` flips the orientation so y coordinates begin at the top and count down, and rotates the index cycle so winding remains correct.
- Texture coordinates are the extent-normalized vertex coordinates, so they remain valid for any mesh whose vertices lie in the extent. Mesh density (`dimension`) is independent of the pixel dimension of a texture image: a coarse mesh may carry a full-resolution image, the graphics engine interpolates within each quad.
- Coordinate transformation belongs outside the core: the mesh vertex matrix is the interchange, transform it (e.g. with reproj) and the texture drapes unchanged.

### Large grids

`quad_index()` returns integer storage where it fits, and transparently promotes to double storage (exact for integer values to 2^53) when the vertex count or index length exceeds the integer maximum. R subsetting and ‘mesh3d’ use accept double indexes natively; take care not to apply `as.integer()` to such an index. The compact spec and the edges intermediate are the escape hatch when full materialization is not wanted at all.

### Compiled code

Registered via cpp11 in `src/quad-build.cpp`, callable from R as internal functions:

    cpp11::integers quad_index_cpp(int nx, int ny, bool ydown)
    cpp11::doubles  quad_index_dbl_cpp(double nx, double ny, bool ydown)
    cpp11::doubles  quad_vertex_cpp(int nx, int ny, bool ydown, bool zh)
    cpp11::writable::doubles_matrix<> quad_vertex_matrix_cpp(int nx, int ny, bool ydown, bool zh)

### Headers

`inst/include/textures/quad.h`, namespace `quad`, installed so that other packages may generate mesh components via `LinkingTo: textures`:

    cpp11::writable::integers quad_ib(int nx, int ny, bool ydown)
    cpp11::writable::doubles  quad_ib_dbl(double nx, double ny, bool ydown)
    cpp11::writable::doubles  quad_vb(int nx, int ny, bool ydown, bool zh)
    cpp11::writable::doubles_matrix<> quad_matrix_vb(int nx, int ny, bool ydown, bool zh)

`quad_ib` and `quad_vb` return flat vectors (4 values per quad, and interleaved x, y with optional constant z and homogeneous h), `quad_matrix_vb` returns the matrix form.

### R reference implementations

`ib_index()` and `vb_vertex()` in `R/quad-Rcode.R` are pure-R versions of the index and vertex generators, kept as the executable specification - the tests pin the compiled path to them.