Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 57 additions & 5 deletions MODS.md
Original file line number Diff line number Diff line change
Expand Up @@ -1546,7 +1546,7 @@ objects: [

The simulator spawns the glTF at the track pose plus offset, rotation and height,
floating-origin safe like the signal models; an unknown object name gets a placeholder
block and a warning. In the route editor the **object tool** (key 5) picks an object kind
block and a warning. In the route editor the **object tool** (key 3 in the equipment box) picks an object kind
and drops it on the nearest track; the selection panel edits position, lateral offset,
rotation and height, and the rule check flags placements outside their track or naming an
object no installed mod has. **Repeat in a row** stamps copies of the selected instance
Expand All @@ -1563,6 +1563,58 @@ editor's selection panel has the checkbox, and both programs resolve the height
way: an object is placed by the terrain tile it stands on, so it streams in and out with
that tile and its feet meet the ground the tile actually has.

### Parametric buildings

The route editor's **building tool** places an editable building recipe, not a reference
to a glTF. Static houses under `objects:` remain supported and are the right choice for a
specific landmark. A generated building is stored under `buildings:`:

```ron
buildings: [
(
edge: 0,
s: 540.0,
lateral_offset: -18.0,
yaw_deg: 90.0,
snap_to_terrain: true,
spec: (
use_kind: Residential,
width: 12.0,
length: 10.0,
floors: 3,
floor_height: 2.9,
roof_style: Gable,
roof_height: 3.2,
facade: Plaster,
facade_color: (0.82, 0.72, 0.58),
roof: ClayTile,
window_spacing: 2.6,
window_width: 1.25,
window_height: 1.45,
lit_window_share: 0.38,
balconies: true,
balcony_every: 2,
balcony_depth: 1.4,
seed: 1384,
),
),
],
```

`use_kind` is `Residential`, `Commercial` or `Industrial`; roofs are `Gable`, `Hip`,
`Flat`, `Shed` and `Mansard`. Facades use `Plaster`, `RedBrick`, `YellowBrick`,
`Concrete` or `MetalPanel`, and roofs use `ClayTile`, `Slate`, `StandingSeam` or
`Bitumen`. The editor constrains dimensions to valid ranges and exposes the same values
after placement. Copy/paste clones the complete recipe, including `seed`, so the copy has
the same design and lit-window pattern.

The simulator receives only the normalised, tile-local recipe. It reuses one generated
three-level mesh set for every identical recipe and global PBR materials for every
building; it does not carry the editor's selection or authoring state. LOD0 includes
window surrounds and balconies, LOD1 retains the facade rhythm, and LOD2 is the silhouette.
The emissive share is selected deterministically from `seed` and switched by the normal
day/night system, so loading the route never rearranges illuminated apartments.

**Levels of detail** work as for vehicles and signals: nodes named `<name>_LOD0`,
`_LOD1`, … are shown by camera distance. A model without the suffix is one level, drawn
up to the cull distance. This matters most for trees: every tree of a wood is drawn as an
Expand Down Expand Up @@ -1811,14 +1863,14 @@ can be moved, rescaled or deleted on its own afterwards. Trees stream in and out
their terrain tile and share meshes per species, so even a big wood renders as instanced
draws.

In the route editor the **tree tool** (key 6) plants one tree per click. The **forest
brush** (key 7) outlines an area — Enter or right-click **bakes** it into single trees
In the route editor the **tree tool** (key 2 in the vegetation box) plants one tree per click. The **forest
brush** (key 3) outlines an area — Enter or right-click **bakes** it into single trees
(one per `area per tree` m², species from the tool options, clear of the track strip).
**File ▸ Import forest…** reads an Overpass JSON extract (`landuse=forest` /
`natural=wood` ways, same download path as the track import) and bakes each polygon the
same way — an optional aid: whoever wants every tree hand-set simply never uses it, and
an imported wood is thinned out or cleared exactly like a painted one. For bulk edits the
**marking brush** (key 8) sweeps over the map and marks every tree and object under the
**marking brush** (key 6) sweeps over the map and marks every tree, object or parametric building under the
circle; Delete (or the panel button) removes them together in one undo step.

### Fields
Expand Down Expand Up @@ -2340,7 +2392,7 @@ deletes the whole layer. Retyping the layer in the selection panel moves a singl
into another one. Hiding is session state; the markers themselves travel with the line,
so the next session still has them.

The **marker tool** (key 9) sets one per click into the layer named in the tool options.
The **marker tool** (key 5 in the equipment box) sets one per click into the layer named in the tool options.
**File ▸ Import reference markers…** reads an Overpass JSON extract and turns the tags it
knows into markers, each in the layer of its tag: `level-crossing`, `platform`,
`station`, `signal`, `switch`, `buffer-stop`, `kilometre-mark`, `bridge`, `tunnel`,
Expand Down
17 changes: 14 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,16 @@ builder is shared read-only, the DGM sheets keep their own short lock. Terrain,
vegetation and track objects live in `world-render` and therefore look the same in the
simulator and in the route editor.

Parametric buildings use the same streamed terrain path without replacing static scenery.
Their route entry keeps an editable recipe (residential, commercial or industrial use,
width, length, floor count and height, five roof shapes, facade/roof material, colour,
window rhythm, balconies and a stable variation seed). The terrain compiler normalises and
bakes that recipe into a compact placement; `world-render` caches one three-level LOD mesh
set per distinct recipe and shares a global PBR library of plaster, red/yellow brick,
concrete, metal panels, clay tile, slate, standing seam and bitumen. Window illumination is
chosen deterministically from the seed and appears only at night. Copy/paste preserves the
whole recipe and seed, while all fields remain editable in the module editor.

**Fields** lie on that ground: the outline and the crop are line content, and what a field
looks like on the day is a function of the crop, the date and the field's own seed — winter
wheat is blue-green in April, gold in the last week of July and stubble in August, and no
Expand Down Expand Up @@ -781,7 +791,7 @@ be laid, which never touches one already lying there.
| Tool | What a click does |
|---|---|
| **Every category** | |
| `1` Select | In every category: pick whatever stands on the map and edit its fields; `Delete` removes it. `Ctrl`+click gathers devices, objects, trees and markers into a multi-selection (a second `Ctrl`+click takes one out again); a press on empty ground dragged open selects everything inside the circle — `Ctrl` adds it to what is gathered, `Delete` removes the lot in one step |
| `1` Select | In every category: pick whatever stands on the map and edit its fields; `Delete` removes it. `Ctrl`+click gathers devices, objects, parametric buildings, trees and markers into a multi-selection (a second `Ctrl`+click takes one out again); a press on empty ground dragged open selects everything inside the circle — `Ctrl` adds it to what is gathered, `Delete` removes the lot in one step |
| **Track** | |
| `2` Lay track | Press and drag sets the standing end and its heading — on an open end it continues that track, on a track's middle it starts the branch of a turnout (drag along the track = facing, against it = trailing). Every further click appends the arc that leaves the alignment tangentially and hits the point — G1-continuous by construction — or a straight while `Ctrl` is held; the running end snaps onto open ends and closes the gap with two tangent arcs. The status bar reads out length and radius. `Enter` or right-click finishes, `Esc` cancels. The *Tool* section sets what the piece is laid as: track type, speed, gradient, electrification, parallel tracks at a spacing; the toolbox's toggle box snaps radii onto the standard series, lays easements — a curve then goes down as clothoid – arc – clothoid with the rulebook's cant for the piece's speed, ramped over the transitions — and snaps the piece to the terrain: sampled ground heights become its gradient profile, a free start drops onto the surface, an end joined onto other track keeps that track's height |
| `3` Split track | Cuts the track at the click — two tracks on one joint |
Expand All @@ -793,11 +803,12 @@ be laid, which never touches one already lying there.
| **Lineside equipment** | |
| `2` Place device | Puts the chosen device kind (signal, magnet, LZB, platform, …) on the clicked track |
| `3` Place object | Drops a mod's 3D object at its predefined offset and rotation; the toolbox's terrain-snap toggle bases it on the ground instead of the rail plane |
| `4` Place marker | A reference marker in a named layer — a drawing aid, nothing in the simulation reads it |
| `4` Parametric building | Places an editable residential, commercial or industrial building. Its properties panel controls dimensions, floors and total height, facade colour/material, five roof shapes, windows, stable night lighting and balconies; `Ctrl+C` / `Ctrl+V` preserves the complete recipe |
| `5` Place marker | A reference marker in a named layer — a drawing aid, nothing in the simulation reads it |
| **Vegetation** | |
| `2` / `3` Tree / forest | One tree per click, or an outlined area baked into single trees — each one stays editable |
| `4` Field | Clicks outline a piece of farmland, Enter or right-click closes it, the crop comes from the tool options. The usual way to get fields is **File ▸ Import fields…**, which fetches them from the state agricultural registers |
| `5` Marking brush | Sweep to mark trees and objects in bulk and delete them together |
| `6` Marking brush | Sweep to mark trees, objects and parametric buildings in bulk and delete them together |
| **Terrain** | |
| `2` Raise ground | One lifting stroke per click, by the set amount and radius. The track keeps its height, cutting and embankment are laid over the strokes afterwards |
| `3` Lower ground | The same stroke downward — a hollow, a pond bed, a pit |
Expand Down
7 changes: 6 additions & 1 deletion crates/app/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ use bevy::prelude::*;
use bevy::render::view::screenshot::{Screenshot, save_to_disk};
use content::import::dgm::TerrainSource;
use content::terrain::{
Scenery, TerrainBuilder, TerrainEdits, TerrainOptions, TerrainStats, Vegetation,
Buildings, Scenery, TerrainBuilder, TerrainEdits, TerrainOptions, TerrainStats, Vegetation,
};
use content::vehicles::passenger_coach;
use mod_runtime::ModRuntime;
Expand Down Expand Up @@ -1030,6 +1030,11 @@ fn setup(
&sim.net,
terrain_options.zone,
))
.with_buildings(Buildings::from_line(
&line_source,
&sim.net,
terrain_options.zone,
))
.with_crowd(crowd)
.with_fields(farmland)
.with_waters(waters)
Expand Down
2 changes: 2 additions & 0 deletions crates/app/src/streaming.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ impl TerrainStreamer {
pub fn stream_terrain(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut building_assets: ResMut<world_render::BuildingAssets>,
mut streamer: ResMut<TerrainStreamer>,
mut info: ResMut<TerrainInfo>,
sim: Res<SimResource>,
Expand Down Expand Up @@ -255,6 +256,7 @@ pub fn stream_terrain(
let entity = render::spawn_terrain_tile(
&mut commands,
&mut meshes,
&mut building_assets,
&streamer.material,
&streamer.catalog,
&tile,
Expand Down
Loading
Loading