├── .cargo └── config.toml ├── .gitattributes ├── .github └── workflows │ ├── cd_android_gh-pages.yml │ ├── cd_wasm_gh-pages.yml │ └── ci.yml ├── .gitignore ├── .gitmodules ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── CONTRIBUTING.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── assets ├── 8k.md ├── 8k_earth_clouds.jpg ├── 8k_earth_daymap.jpg ├── 8k_moon.jpg ├── 8k_stars.jpg ├── bs_galactica1.glb ├── compass.md └── compass.png ├── build.rs ├── examples └── main.rs ├── favicon.ico ├── icon.png ├── icon.svg ├── manifest.yaml ├── notes_OSMeta.txt ├── notes_mail.txt ├── src ├── big_space.rs ├── big_space │ ├── debug.rs │ ├── grid_cell.rs │ ├── precision.rs │ ├── propagation.rs │ └── world_query.rs ├── bin │ └── demo.rs ├── compass.rs ├── f4control.rs ├── flycontrol.rs ├── geocoord.rs ├── geoview.rs ├── http_assets.rs ├── lib.rs ├── player.rs ├── sky.rs ├── tilemap.rs ├── tilemap │ ├── coord.rs │ └── index.rs └── xr.rs └── web └── index.html /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [target.wasm32-unknown-unknown] 2 | runner = "wasm-server-runner" 3 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/workflows/cd_android_gh-pages.yml: -------------------------------------------------------------------------------- 1 | name: deploy android/quest apk to gh-pages 2 | on: 3 | workflow_run: 4 | branches: [main] 5 | workflows: [CI] 6 | types: [completed] 7 | 8 | jobs: 9 | release: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout sources 13 | uses: actions/checkout@v4 14 | - name: Cache 15 | uses: actions/cache@v3 16 | with: 17 | path: | 18 | ~/.cargo/bin/ 19 | ~/.cargo/registry/index/ 20 | ~/.cargo/registry/cache/ 21 | ~/.cargo/git/db/ 22 | target/ 23 | key: ${{ runner.os }}-android 24 | 25 | - run: mkdir dist 26 | - run: cp target/x/release/android/osmeta.apk dist/osmeta.apk 27 | 28 | - uses: peaceiris/actions-gh-pages@v3 29 | if: github.ref == 'refs/heads/main' 30 | with: 31 | github_token: ${{ secrets.GITHUB_TOKEN }} 32 | publish_dir: ./dist 33 | keep_files: true 34 | -------------------------------------------------------------------------------- /.github/workflows/cd_wasm_gh-pages.yml: -------------------------------------------------------------------------------- 1 | name: deploy wasm to gh-pages 2 | on: 3 | workflow_run: 4 | branches: [main] 5 | workflows: [CI] 6 | types: [completed] 7 | 8 | jobs: 9 | release: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout sources 13 | uses: actions/checkout@v4 14 | - name: Cache 15 | uses: actions/cache@v3 16 | with: 17 | path: | 18 | ~/.cargo/bin/ 19 | ~/.cargo/registry/index/ 20 | ~/.cargo/registry/cache/ 21 | ~/.cargo/git/db/ 22 | target/ 23 | key: ${{ runner.os }}-wasm 24 | 25 | - name: Install wasm libcore/libstd 26 | run: rustup target install wasm32-unknown-unknown 27 | - name: Install wasm-bindgen 28 | run: wasm-bindgen --version || cargo install wasm-bindgen-cli 29 | - name: Build wasm 30 | run: cargo build --release --target wasm32-unknown-unknown --bin demo && wasm-bindgen --out-dir ./web/ --target web ./target/wasm32-unknown-unknown/release/demo.wasm 31 | 32 | - uses: peaceiris/actions-gh-pages@v3 33 | if: github.ref == 'refs/heads/main' 34 | with: 35 | github_token: ${{ secrets.GITHUB_TOKEN }} 36 | publish_dir: ./web 37 | keep_files: true 38 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | # Run cargo test 14 | test: 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | os: [ubuntu-latest, macos-latest, windows-latest] 19 | name: Test `cargo test` on ${{ matrix.os }} 20 | runs-on: ${{ matrix.os }} 21 | timeout-minutes: 30 22 | steps: 23 | - name: Checkout sources 24 | uses: actions/checkout@v4 25 | - name: Cache 26 | uses: actions/cache@v3 27 | with: 28 | path: | 29 | ~/.cargo/bin/ 30 | ~/.cargo/registry/index/ 31 | ~/.cargo/registry/cache/ 32 | ~/.cargo/git/db/ 33 | target/ 34 | key: ${{ matrix.os }}-cargo-test 35 | - name: Install stable toolchain 36 | uses: dtolnay/rust-toolchain@stable 37 | - name: Install Dependencies 38 | if: matrix.os == 'ubuntu-latest' 39 | run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev libopenxr-loader1 libopenxr-dev 40 | - name: Run cargo test 41 | if: matrix.os == 'ubuntu-latest' 42 | run: cargo test 43 | - name: Run cargo check 44 | if: matrix.os != 'ubuntu-latest' 45 | run: cargo check 46 | 47 | # Run cargo clippy -- -D warnings 48 | clippy: 49 | name: Clippy 50 | runs-on: ubuntu-latest 51 | timeout-minutes: 30 52 | steps: 53 | - name: Checkout sources 54 | uses: actions/checkout@v4 55 | - name: Cache 56 | uses: actions/cache@v3 57 | with: 58 | path: | 59 | ~/.cargo/bin/ 60 | ~/.cargo/registry/index/ 61 | ~/.cargo/registry/cache/ 62 | ~/.cargo/git/db/ 63 | target/ 64 | key: ${{ runner.os }}-cargo-clippy 65 | - name: Add clippy to rustup 66 | run: rustup component add clippy 67 | - name: Install Dependencies 68 | run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev 69 | - name: Run clippy 70 | run: cargo clippy -- -D warnings 71 | 72 | # Run cargo fmt --all -- --check 73 | format: 74 | name: Format 75 | runs-on: ubuntu-latest 76 | timeout-minutes: 30 77 | steps: 78 | - name: Checkout sources 79 | uses: actions/checkout@v4 80 | - name: Add rustfmt to rustup 81 | run: rustup component add rustfmt 82 | - name: Run cargo fmt 83 | run: cargo fmt --all -- --check 84 | 85 | android: 86 | runs-on: ubuntu-latest 87 | timeout-minutes: 40 88 | steps: 89 | - name: Install Dependencies 90 | run: sudo apt-get update; sudo apt-get install pkg-config libx11-dev libasound2-dev libudev-dev lld llvm 91 | - uses: actions/checkout@v4 92 | - run: git submodule update --init 93 | - name: Cache 94 | uses: actions/cache@v3 95 | with: 96 | path: | 97 | ~/.cargo/bin/ 98 | ~/.cargo/registry/index/ 99 | ~/.cargo/registry/cache/ 100 | ~/.cargo/git/db/ 101 | target/ 102 | key: ${{ runner.os }}-android 103 | - uses: dtolnay/rust-toolchain@stable 104 | - name: Add Android targets 105 | run: rustup target add aarch64-linux-android armv7-linux-androideabi 106 | - name: Install cargo-binstall 107 | run: curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash 108 | - name: Install xbuild 109 | run: cargo binstall --git https://github.com/NiklasEi/xbuild --bin-dir x xbuild -y 110 | - name: show deps 111 | run: x doctor 112 | - name: Build app bundle 113 | run: x build --release --platform android --format apk --arch arm64 114 | 115 | 116 | wasm: 117 | runs-on: ubuntu-latest 118 | timeout-minutes: 40 119 | steps: 120 | - name: Install Dependencies 121 | run: sudo apt-get update; sudo apt-get install pkg-config libx11-dev libasound2-dev libudev-dev lld llvm 122 | - uses: actions/checkout@v4 123 | - run: git submodule update --init 124 | - name: Cache 125 | uses: actions/cache@v3 126 | with: 127 | path: | 128 | ~/.cargo/bin/ 129 | ~/.cargo/registry/index/ 130 | ~/.cargo/registry/cache/ 131 | ~/.cargo/git/db/ 132 | target/ 133 | key: ${{ runner.os }}-wasm 134 | - uses: dtolnay/rust-toolchain@stable 135 | 136 | - name: Install wasm libcore/libstd 137 | run: rustup target install wasm32-unknown-unknown 138 | - name: Install wasm-bindgen 139 | run: wasm-bindgen --version || cargo install wasm-bindgen-cli 140 | - name: Build wasm 141 | run: cargo build --release --target wasm32-unknown-unknown --bin demo && wasm-bindgen --out-dir ./web/ --target web ./target/wasm32-unknown-unknown/release/demo.wasm 142 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/.DS_Store 2 | /target 3 | /z_Usefull 4 | /web/* 5 | examples/main.rs 6 | Cargo.lock 7 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "runtime_libs"] 2 | path = runtime_libs 3 | url = https://github.com/DerKarlos/OSMeta.git 4 | branch = binaries 5 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "lldb", 9 | "request": "launch", 10 | "name": "Debug unit tests in library 'osmeta'", 11 | "cargo": { 12 | "args": [ 13 | "test", 14 | "--no-run", 15 | "--lib", 16 | "--package=osmeta" 17 | ], 18 | "filter": { 19 | "name": "osmeta", 20 | "kind": "lib" 21 | } 22 | }, 23 | "args": [], 24 | "cwd": "${workspaceFolder}" 25 | }, 26 | { 27 | "type": "lldb", 28 | "request": "launch", 29 | "name": "Debug executable 'demo'", 30 | "cargo": { 31 | "args": [ 32 | "build", 33 | "--bin=demo", 34 | "--package=osmeta" 35 | ], 36 | "filter": { 37 | "name": "demo", 38 | "kind": "bin" 39 | } 40 | }, 41 | "args": [], 42 | "cwd": "${workspaceFolder}" 43 | }, 44 | { 45 | "type": "lldb", 46 | "request": "launch", 47 | "name": "Debug unit tests in executable 'demo'", 48 | "cargo": { 49 | "args": [ 50 | "test", 51 | "--no-run", 52 | "--bin=demo", 53 | "--package=osmeta" 54 | ], 55 | "filter": { 56 | "name": "demo", 57 | "kind": "bin" 58 | } 59 | }, 60 | "args": [], 61 | "cwd": "${workspaceFolder}" 62 | } 63 | ] 64 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "rust-analyzer.showUnlinkedFileNotification": false 3 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "example-main", 8 | "type": "shell", 9 | "command": "cargo run --example main", 10 | "problemMatcher": [], 11 | "group": "build" 12 | }, 13 | { 14 | "label": "run", 15 | "type": "shell", 16 | "command": "cargo run", 17 | "problemMatcher": [], 18 | "group": { 19 | "kind": "build", 20 | "isDefault": true 21 | } 22 | }, 23 | { 24 | "label": "run LOG=Debug", 25 | "type": "shell", 26 | "command": "RUST_LOG=debug cargo run", 27 | "problemMatcher": [], 28 | "group": { 29 | "kind": "build" 30 | } 31 | }, 32 | { 33 | "label": "run WASM", 34 | "type": "shell", 35 | "command": "cargo run --target wasm32-unknown-unknown", 36 | "problemMatcher": [], 37 | "group": { 38 | "kind": "build" 39 | } 40 | }, 41 | { 42 | "label": "run release", 43 | "type": "shell", 44 | "command": "cargo run --release", 45 | "problemMatcher": [], 46 | "group": "build" 47 | }, 48 | { 49 | "label": "build", 50 | "type": "shell", 51 | "command": "cargo build", 52 | "problemMatcher": [], 53 | "group": { 54 | "kind": "build" 55 | } 56 | }, 57 | { 58 | "label": "fmt", 59 | "type": "shell", 60 | "command": "cargo fmt --all -- --check", 61 | "problemMatcher": [], 62 | "group": { 63 | "kind": "test" 64 | } 65 | }, 66 | { 67 | "label": "clippy", 68 | "type": "shell", 69 | "command": "cargo clippy --fix", 70 | "problemMatcher": [], 71 | "group": { 72 | "kind": "test" 73 | } 74 | }, 75 | { 76 | "type": "cargo", 77 | "command": "test", 78 | "problemMatcher": [ 79 | "$rustc" 80 | ], 81 | "group": "test", 82 | "label": "rust: cargo test" 83 | } 84 | ] 85 | } -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Build for android 2 | 3 | On windows hosts, install `llvm` (contains `clang`) from https://github.com/llvm/llvm-project/releases/ 4 | 5 | ``` 6 | cargo install --git https://github.com/NiklasEi/xbuild 7 | ``` 8 | 9 | run `x doctor` to see what else you need to install for android, then run 10 | 11 | ``` 12 | x build --release --platform android --format apk --arch arm64 13 | ``` 14 | ## wasm 15 | 16 | To run the project in the browser locally, you need to do the following setup: 17 | 18 | ```bash 19 | rustup target install wasm32-unknown-unknown 20 | cargo install wasm-server-runner 21 | cargo run --target wasm32-unknown-unknown 22 | ``` 23 | 24 | ## Build for windows (on Mac/Linux) 25 | 26 | brew install mingw-w64 27 | rustup target add x86_64-pc-windows-gnu 28 | cargo clippy --fix --allow-dirty --allow-staged --target x86_64-pc-windows-gnu 29 | cargo fmt 30 | cargo check --target x86_64-pc-windows-gnu 31 | cargo build --target x86_64-pc-windows-gnu 32 | error: linking with `x86_64-w64-mingw32-gcc` failed: exit status: 1 33 | cargo run --target x86_64-pc-windows-gnu (realy?) 34 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "osmeta" 3 | version = "0.1.0" 4 | edition = "2021" 5 | links = "openxr_loader" 6 | build = "build.rs" 7 | 8 | # Enable a small amount of optimization in debug mode 9 | [profile.dev] 10 | opt-level = 1 11 | 12 | # Enable high optimizations for dependencies (incl. Bevy), but not for our code: 13 | [profile.dev.package."*"] 14 | opt-level = 3 15 | 16 | 17 | [dependencies] 18 | bevy = { version = "0.13", features = ["jpeg"] } 19 | flate2 = "1.0.28" 20 | futures-core = "0.3.29" 21 | futures-io = "0.3.29" 22 | bevy_screen_diagnostics = { git = "https://github.com/oli-obk/bevy_screen_diagnostics.git" } 23 | globe-rs = "0.1.8" 24 | directories = "5.0.1" 25 | async-fs = "2.1.0" 26 | bevy_web_asset = { git = "https://github.com/oli-obk/bevy_web_asset.git", branch = "user-agent" } 27 | bevy_embedded_assets = "0.10" 28 | bevy_panorbit_camera = "0.16" 29 | 30 | [target.'cfg(target_arch = "wasm32")'.dependencies] 31 | web-sys = { version = "0.3.22", default-features = false, features = [ 32 | "Location", 33 | ] } 34 | 35 | [target.'cfg(not(any(target_os="macos", target_arch = "wasm32")))'.dependencies] 36 | bevy_oxr = { git = "https://github.com/awtterpip/bevy_oxr", optional = true } 37 | 38 | [features] 39 | xr = ["dep:bevy_oxr"] 40 | default = ["xr"] 41 | 42 | 43 | # we need to split our crate into a lib and a binary, because android targets don't want a binary. 44 | # our binary is now just a tiny dummy thing that invokes the library's main function. 45 | [lib] 46 | name = "osmeta" 47 | crate-type = ["staticlib", "cdylib", "lib"] 48 | 49 | [lints.clippy] 50 | type_complexity = "allow" 51 | too_many_arguments = "allow" 52 | 53 | 54 | [[example]] 55 | name = "main" 56 | path = "examples/main.rs" 57 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is open source 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## OSMeta 2 | **OpenStreetMap-Metaverse** 3 | 4 | 5 | * Programming langue: Rust / wasm 6 | * Render engine: Bevy and others (also wgpu) 7 | * Runtimes: Native desktop. Intended: iOS, Android and Web-App (using wasm) 8 | 9 | 10 | The main goal of this project is, to offer a Rust crate to render the OSM data in 3D. 11 | An OSM vector map like maplibre-rs could add it like Googles street-view. 12 | 13 | Actually the new GLB 3D tiles from OSM2World are used. 14 | There are several other OSM 3D renderer and their ideas could be integrated too. 15 | 16 | Not only a bird view but also a street-level view is provided. 17 | So the crate could be used to create a wheel-chair or a hot air balloon simulation. 18 | As Bevy is a game engine, even gamifications like car races are easy to build. 19 | 20 | The “Meta” in “OSMeta” is partly a joke against the intended “free and open” Metaverse of “Facebook". 21 | But a multiuser mode will get added. Also the Metaverse features, as far as Bevy engine offers them, to immerse OSM as a virtual world. 22 | 23 | 24 | *This texts are written in English by a German, so please gratefully correct my errors and nonsense. -karlos-* 25 | 26 | 27 | 28 | 29 | ## The long History: 30 | 31 | After the Big Bang, hydrogen collapsed to ignite the first generation of stars. 32 | They soon ended in supernovae to breed “metallic" matter for planet building. 33 | After cooling down live and mankind raised and build roads. 34 | 35 | A student in London could not find map data and started to collect them and made OpenStreetMap. 36 | Pokémon used the data and generated 3D views. 37 | After creating Science Fiction 3D things, I (karlos) thought: 38 | That’s not wizarding, I could do it too and have some gamification for OSM. 39 | So I started “OSM-GO”. See www.osm.org/wiki/osm_go and https://www.openstreetmap.org/user/-karlos-/diary 40 | Just mimicking Pokémon extended to show all OSM tagging, but not a realistic visualisation like F4map.com. 41 | 42 | I got in contact with Tobias and we started a Web-Frontend for https://wiki.openstreetmap.org/wiki/OSM2World. 43 | The render Engine changed from Three-JS to Babylon-JS, JavaScript to TypeScript. 44 | The frontend is not gone public yet, because of some missing features, errors and providing more but D-A-CH. 45 | Reasendly we changed from a propertarry tile file format ot standard GLB. 46 | 47 | Meanwhile I got enthusiastic about WASM and Rust too. Just to challenge myself, I transcoded parts of the frontend. 48 | The used render engine changed from “tree-d” to “rend3” and now Bevy it is. 49 | As there is a Maplibre-RS now, this project could be used there to. 50 | 51 | The future idea is, to make a render engine agnostic core crate. 52 | You call it for a GPS coordinate and by a wrapper for the actually used renderer, 53 | it will load GLB tiles, needed to fill the camera view (frustrum). 54 | This will be done by a Rust module and later, the core-crate. The “mod.rs” serves as the wrapper. 55 | Next there may be crates for different renderer. 56 | Only the control or the gamification is added by the user to get an application. 57 | 58 | -------------------------- 59 | 60 | There is an not up to date http://www.osmgo.org/OSMeta/demo.mov 61 | You may be able to run it here: https://derkarlos.github.io/OSMeta/ 62 | 63 | -------------------------- 64 | 65 | ## Concepts: 66 | 67 | Todo 68 | -------------------------------------------------------------------------------- /assets/8k.md: -------------------------------------------------------------------------------- 1 | Source: https://www.solarsystemscope.com/textures/ 2 | -------------------------------------------------------------------------------- /assets/8k_earth_clouds.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DerKarlos/OSMeta/10c085917770090372efe330b9cb560db7c5b346/assets/8k_earth_clouds.jpg -------------------------------------------------------------------------------- /assets/8k_earth_daymap.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DerKarlos/OSMeta/10c085917770090372efe330b9cb560db7c5b346/assets/8k_earth_daymap.jpg -------------------------------------------------------------------------------- /assets/8k_moon.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DerKarlos/OSMeta/10c085917770090372efe330b9cb560db7c5b346/assets/8k_moon.jpg -------------------------------------------------------------------------------- /assets/8k_stars.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DerKarlos/OSMeta/10c085917770090372efe330b9cb560db7c5b346/assets/8k_stars.jpg -------------------------------------------------------------------------------- /assets/bs_galactica1.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DerKarlos/OSMeta/10c085917770090372efe330b9cb560db7c5b346/assets/bs_galactica1.glb -------------------------------------------------------------------------------- /assets/compass.md: -------------------------------------------------------------------------------- 1 | Source: https://openclipart.org/detail/233063/compass-rose-2 2 | -------------------------------------------------------------------------------- /assets/compass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DerKarlos/OSMeta/10c085917770090372efe330b9cb560db7c5b346/assets/compass.png -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("cargo:rerun-if-changed=build.rs"); 3 | if std::env::var("TARGET").unwrap() == "aarch64-linux-android" { 4 | println!("cargo:rustc-link-search=runtime_libs/arm64-v8a"); 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /examples/main.rs: -------------------------------------------------------------------------------- 1 | /* 2 | https://bevy-cheatbook.github.io/fundamentals/coords.html 3 | https://de.wikipedia.org/wiki/Kugelkoordinaten#Übliche_Konvention 4 | https://en.wikipedia.org/wiki/Spherical_coordinate_system 5 | */ 6 | 7 | use bevy::{prelude::*, utils::petgraph::matrix_graph::Zero}; 8 | use bevy_panorbit_camera::*; // https://docs.rs/bevy_panorbit_camera/latest/bevy_panorbit_camera/ 9 | use globe_rs::{CartesianPoint, GeographicPoint}; 10 | 11 | use bevy::math::DVec3; 12 | 13 | const EARTH_RADIUS: f32 = 1.0; 14 | 15 | const LAT: f32 = 0.; // 48.1408; 16 | const LON: f32 = 0.; // 11.5577; 17 | const ELEVATION: f32 = 0.7; 18 | 19 | const DIRECTION: f32 = 0.0; 20 | const UP_VIEW: f32 = -90.0; 21 | const DISTANCE: f32 = 0.7; 22 | 23 | const SECTORS: usize = 32; 24 | 25 | #[derive(Component)] 26 | pub struct CamControl; 27 | 28 | #[derive(Resource, Default)] 29 | pub struct CamData { 30 | pub lat: f32, 31 | pub lon: f32, 32 | pub direction: f32, 33 | } 34 | 35 | // Trolley Angle Marker 36 | #[derive(Component)] 37 | pub struct Join; 38 | 39 | #[bevy_main] 40 | fn main() { 41 | App::new() 42 | .insert_resource(ClearColor(Color::ANTIQUE_WHITE)) 43 | .insert_resource(CamData { 44 | lat: LAT, 45 | lon: LON, 46 | direction: DIRECTION, 47 | }) 48 | .add_plugins(DefaultPlugins) 49 | .add_plugins(PanOrbitCameraPlugin) 50 | .add_systems(Startup, setup) 51 | .add_systems(Update, move_join) 52 | .add_systems(Update, move_camera) 53 | .run(); 54 | } 55 | 56 | fn setup( 57 | mut commands: Commands, 58 | mut materials: ResMut>, 59 | mut meshes: ResMut>, 60 | asset_server: Res, 61 | ) { 62 | // Camera-Meshes (body and lense) 63 | let cube = meshes.add(Cuboid::new(1.0, 1.0, 1.0).mesh()); 64 | 65 | let camera_box = commands 66 | .spawn(( 67 | PbrBundle { 68 | mesh: cube.clone(), 69 | // box, visualisizing a camera in Bevy coordiantes/rotatons 70 | transform: Transform::from_xyz(0.0, 0.0, 0.0).with_scale(Vec3::new(0.3, 0.5, 0.4)), 71 | material: materials.add(StandardMaterial { 72 | base_color: Color::GRAY, 73 | ..default() 74 | }), 75 | ..default() 76 | }, 77 | CamControl, 78 | )) 79 | .id(); 80 | 81 | let lense = commands 82 | .spawn((PbrBundle { 83 | mesh: cube.clone(), 84 | // place lense in front of the box (-z) a bit up (+y) in Bevy coordinates 85 | transform: Transform::from_xyz(0.0, 0.15, -0.6).with_scale(Vec3::new(0.25, 0.25, 0.25)), 86 | ..default() 87 | },)) 88 | .id(); 89 | 90 | commands.entity(camera_box).push_children(&[lense]); 91 | 92 | //////////////////////////////////////////////////////// 93 | // Earth with equator and greewich meridian and markers 94 | let sphere = meshes.add(Sphere::new(EARTH_RADIUS).mesh().uv(SECTORS, SECTORS / 2)); 95 | //.ico(SECTORS).unwrap()); 96 | 97 | let image = asset_server.load("8k_earth_daymap.jpg"); 98 | 99 | commands.spawn((PbrBundle { 100 | mesh: sphere, 101 | 102 | material: materials.add(StandardMaterial { 103 | base_color_texture: Some(image.clone()), 104 | base_color: Color::WHITE, 105 | unlit: true, 106 | cull_mode: None, 107 | perceptual_roughness: 1.0, 108 | fog_enabled: false, 109 | ..default() 110 | }), 111 | 112 | // material: materials.add(StandardMaterial { 113 | // base_color: Color::BLUE, 114 | // ..default() 115 | // }), 116 | ..default() 117 | },)); 118 | 119 | let disk = meshes.add(Cylinder::new(1.02, 0.05).mesh().resolution(16)); 120 | 121 | // Equator: 0 latitude 122 | commands.spawn((PbrBundle { 123 | mesh: disk.clone(), 124 | material: materials.add(StandardMaterial { 125 | base_color: Color::GREEN, 126 | ..default() 127 | }), 128 | ..default() 129 | },)); 130 | 131 | // 0 longditure 132 | commands.spawn(PbrBundle { 133 | mesh: disk, 134 | transform: Transform::from_rotation(Quat::from_rotation_x(std::f32::consts::FRAC_PI_2)), 135 | ..default() 136 | }); 137 | 138 | // Null-Island 139 | commands.spawn((PbrBundle { 140 | mesh: cube.clone(), 141 | transform: Transform::from_translation(calc_geographic_translation(0., 0., 0., 0., 0.)) 142 | .with_scale(Vec3::new(0.1, 0.1, 0.1)), 143 | ..default() 144 | },)); 145 | 146 | // Greenwich 147 | commands.spawn((PbrBundle { 148 | mesh: cube.clone(), 149 | material: materials.add(StandardMaterial { 150 | base_color: Color::GREEN, 151 | ..default() 152 | }), 153 | transform: Transform::from_translation(calc_geographic_translation(51.84, 0., 0., 0., 0.)) 154 | .with_scale(Vec3::new(0.1, 0.1, 0.1)), 155 | ..default() 156 | },)); 157 | 158 | // Northpole 159 | commands.spawn((PbrBundle { 160 | mesh: cube.clone(), 161 | material: materials.add(StandardMaterial { 162 | base_color: Color::WHITE, 163 | ..default() 164 | }), 165 | transform: Transform::from_translation(calc_geographic_translation(90., 0., 0., 0., 0.)) 166 | .with_scale(Vec3::new(0.1, 0.1, 0.1)), 167 | ..default() 168 | },)); 169 | 170 | // Munich, Germany 171 | commands.spawn((PbrBundle { 172 | mesh: cube.clone(), 173 | material: materials.add(StandardMaterial { 174 | base_color: Color::ALICE_BLUE, 175 | ..default() 176 | }), 177 | transform: Transform::from_translation(calc_geographic_translation( 178 | 48.1408, 11.5577, 0., 0., 0., 179 | )) 180 | .with_scale(Vec3::new(0.1, 0.1, 0.1)), 181 | ..default() 182 | },)); 183 | 184 | // Join 185 | commands.spawn(( 186 | PbrBundle { 187 | mesh: cube.clone(), 188 | material: materials.add(StandardMaterial { 189 | base_color: Color::YELLOW, 190 | ..default() 191 | }), 192 | transform: Transform::from_translation(calc_geographic_translation(0., 0., 0., 0., 0.)) 193 | .with_scale(Vec3::new(0.1, 0.1, 0.1)), 194 | ..default() 195 | }, 196 | Join, 197 | )); 198 | 199 | // commands.spawn(SceneBundle { 200 | // scene: asset_server.load("bs_galactica1.glb#Scene0"), // xwing bs_galactica1 1701A2 201 | // ..default() 202 | // }); 203 | 204 | ///// Camera & Light ///////////////////////////////////////////////////// 205 | 206 | // bevy-camera 207 | commands.spawn(( 208 | Camera3dBundle { 209 | //transform: Transform::from_xyz(0., 10., 0.), 210 | ..default() 211 | }, 212 | //CamControl, 213 | PanOrbitCamera { 214 | //alpha: Some((-90.0_f32).to_radians()), 215 | //beta: Some((0.0_f32).to_radians()), 216 | radius: Some(6.0_f32), 217 | ..default() 218 | }, 219 | )); 220 | 221 | // light 222 | commands.spawn(PointLightBundle { 223 | point_light: PointLight { 224 | intensity: 1500.0, 225 | shadows_enabled: true, 226 | ..default() 227 | }, 228 | transform: Transform::from_xyz(4000.0, 8000.0, 4000.0), 229 | ..default() 230 | }); 231 | } 232 | 233 | fn move_join( 234 | mut transform_query: Query<&mut Transform, With>, // 235 | cam_data: Res, 236 | ) { 237 | for mut transform in transform_query.iter_mut() { 238 | let translation = 239 | calc_geographic_translation(cam_data.lat, cam_data.lon, ELEVATION, 0., 0.); 240 | 241 | transform.translation = translation; 242 | } 243 | } 244 | 245 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 246 | ////// Learning rotation, quaternion, transformation ///////////////////////////////////////////////////////////////////// 247 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 248 | fn move_camera( 249 | mut cam_transform_query: Query<&mut Transform, With>, // 250 | cam_data: ResMut, 251 | _time: Res