initial commit
This commit is contained in:
		
						commit
						ff9d8ffab6
					
				
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,4 @@
 | 
			
		||||
/target
 | 
			
		||||
/dist
 | 
			
		||||
/.idea
 | 
			
		||||
Cargo.lock
 | 
			
		||||
							
								
								
									
										15
									
								
								Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								Cargo.toml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
			
		||||
[package]
 | 
			
		||||
name = "dreamsincode"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
edition = "2021"
 | 
			
		||||
 | 
			
		||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
bevy = { version = "0.8.1" }
 | 
			
		||||
web-sys = { version = "0.3.60" }
 | 
			
		||||
gloo-events = { version = "0.1.2" }
 | 
			
		||||
console_error_panic_hook = { version = "0.1.7" }
 | 
			
		||||
 | 
			
		||||
[profile.release]
 | 
			
		||||
opt-level = "z"
 | 
			
		||||
							
								
								
									
										35
									
								
								Trunk.release.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								Trunk.release.toml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,35 @@
 | 
			
		||||
# An example Trunk.toml with all possible fields along with their defaults.
 | 
			
		||||
 | 
			
		||||
[build]
 | 
			
		||||
# The index HTML file to drive the bundling process.
 | 
			
		||||
target = "index.html"
 | 
			
		||||
# Build in release mode.
 | 
			
		||||
release = true
 | 
			
		||||
# The output dir for all final assets.
 | 
			
		||||
dist = "dist/release"
 | 
			
		||||
# The public URL from which assets are to be served.
 | 
			
		||||
public_url = "/"
 | 
			
		||||
# Whether to include hash values in the output file names.
 | 
			
		||||
filehash = true
 | 
			
		||||
 | 
			
		||||
[watch]
 | 
			
		||||
# Paths to watch. The `build.target`'s parent folder is watched by default.
 | 
			
		||||
watch = []
 | 
			
		||||
# Paths to ignore.
 | 
			
		||||
ignore = ["."]
 | 
			
		||||
 | 
			
		||||
[serve]
 | 
			
		||||
# The address to serve on.
 | 
			
		||||
addr = "127.0.0.1"
 | 
			
		||||
# The port to serve on.
 | 
			
		||||
port = 8080
 | 
			
		||||
# Open a browser tab once the initial build is complete.
 | 
			
		||||
open = true
 | 
			
		||||
# Disable auto-reload of the web app.
 | 
			
		||||
no_autoreload = true
 | 
			
		||||
 | 
			
		||||
[clean]
 | 
			
		||||
# The output dir for all final assets.
 | 
			
		||||
dist = "dist"
 | 
			
		||||
# Optionally perform a cargo clean.
 | 
			
		||||
cargo = true
 | 
			
		||||
							
								
								
									
										35
									
								
								Trunk.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								Trunk.toml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,35 @@
 | 
			
		||||
# An example Trunk.toml with all possible fields along with their defaults.
 | 
			
		||||
 | 
			
		||||
[build]
 | 
			
		||||
# The index HTML file to drive the bundling process.
 | 
			
		||||
target = "index.html"
 | 
			
		||||
# Build in release mode.
 | 
			
		||||
release = false
 | 
			
		||||
# The output dir for all final assets.
 | 
			
		||||
dist = "dist/debug"
 | 
			
		||||
# The public URL from which assets are to be served.
 | 
			
		||||
public_url = "/"
 | 
			
		||||
# Whether to include hash values in the output file names.
 | 
			
		||||
filehash = true
 | 
			
		||||
 | 
			
		||||
[watch]
 | 
			
		||||
# Paths to watch. The `build.target`'s parent folder is watched by default.
 | 
			
		||||
watch = []
 | 
			
		||||
# Paths to ignore.
 | 
			
		||||
ignore = []
 | 
			
		||||
 | 
			
		||||
[serve]
 | 
			
		||||
# The address to serve on.
 | 
			
		||||
addr = "127.0.0.1"
 | 
			
		||||
# The port to serve on.
 | 
			
		||||
port = 8080
 | 
			
		||||
# Open a browser tab once the initial build is complete.
 | 
			
		||||
open = true
 | 
			
		||||
# Disable auto-reload of the web app.
 | 
			
		||||
no_autoreload = false
 | 
			
		||||
 | 
			
		||||
[clean]
 | 
			
		||||
# The output dir for all final assets.
 | 
			
		||||
dist = "debug"
 | 
			
		||||
# Optionally perform a cargo clean.
 | 
			
		||||
cargo = false
 | 
			
		||||
							
								
								
									
										11
									
								
								assets/shaders/custom_material.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								assets/shaders/custom_material.frag
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
			
		||||
#version 450
 | 
			
		||||
 | 
			
		||||
layout(location = 0) out vec4 o_Target;
 | 
			
		||||
 | 
			
		||||
layout(set = 1, binding = 0) uniform CustomMaterial {
 | 
			
		||||
    vec4 Color;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void main() {
 | 
			
		||||
    o_Target = Color;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								assets/shaders/custom_material.vert
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								assets/shaders/custom_material.vert
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
			
		||||
#version 450
 | 
			
		||||
 | 
			
		||||
layout(location = 0) in vec3 Vertex_Position;
 | 
			
		||||
layout(location = 1) in vec3 Vertex_Normal;
 | 
			
		||||
layout(location = 2) in vec2 Vertex_Uv;
 | 
			
		||||
 | 
			
		||||
layout(set = 0, binding = 0) uniform CameraViewProj {
 | 
			
		||||
    mat4 ViewProj;
 | 
			
		||||
    mat4 View;
 | 
			
		||||
    mat4 InverseView;
 | 
			
		||||
    mat4 Projection;
 | 
			
		||||
    vec3 WorldPosition;
 | 
			
		||||
    float near;
 | 
			
		||||
    float far;
 | 
			
		||||
    float width;
 | 
			
		||||
    float height;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
layout(set = 2, binding = 0) uniform Mesh {
 | 
			
		||||
    mat4 Model;
 | 
			
		||||
    mat4 InverseTransposeModel;
 | 
			
		||||
    uint flags;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void main() {
 | 
			
		||||
    gl_Position = ViewProj * Model * vec4(Vertex_Position, 1.0);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								assets/sounds/bg.ogg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/sounds/bg.ogg
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										16
									
								
								index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								index.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html lang="en">
 | 
			
		||||
    <head>
 | 
			
		||||
        <meta charset="utf-8">
 | 
			
		||||
        <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"/>
 | 
			
		||||
        <title>dreamsinco.de</title>
 | 
			
		||||
        <meta name="description" content="dreamsinco.de">
 | 
			
		||||
        <meta name="author" content="vance">
 | 
			
		||||
        <link data-trunk rel="copy-dir" href="assets"/>
 | 
			
		||||
        <link data-trunk rel="inline" href="web/index.css" />
 | 
			
		||||
        <link data-trunk rel="rust" data-wasm-opt="z" />
 | 
			
		||||
    </head>
 | 
			
		||||
    <body>
 | 
			
		||||
        <link data-trunk rel="inline" href="web/sound.js" />
 | 
			
		||||
    </body>
 | 
			
		||||
</html>
 | 
			
		||||
							
								
								
									
										64
									
								
								src/fullviewport.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								src/fullviewport.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,64 @@
 | 
			
		||||
use bevy::{
 | 
			
		||||
    prelude::{App, Plugin, Res, ResMut},
 | 
			
		||||
    window::Windows,
 | 
			
		||||
};
 | 
			
		||||
use std::sync::{
 | 
			
		||||
    mpsc::{Receiver, Sender},
 | 
			
		||||
    Mutex,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
type OnResizeSender = Sender<()>;
 | 
			
		||||
type OnResizeReceiver = Receiver<()>;
 | 
			
		||||
 | 
			
		||||
pub struct FullViewportPlugin;
 | 
			
		||||
 | 
			
		||||
impl Plugin for FullViewportPlugin {
 | 
			
		||||
    fn build(&self, app: &mut App) {
 | 
			
		||||
        let channel = std::sync::mpsc::channel();
 | 
			
		||||
        let resize_sender: OnResizeSender = channel.0;
 | 
			
		||||
        let resize_receiver: OnResizeReceiver = channel.1;
 | 
			
		||||
 | 
			
		||||
        app.insert_resource(Mutex::new(resize_sender))
 | 
			
		||||
            .insert_resource(Mutex::new(resize_receiver))
 | 
			
		||||
            .add_startup_system(setup_viewport_resize_system)
 | 
			
		||||
            .add_system(viewport_resize_system);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn get_viewport_size() -> (f32, f32) {
 | 
			
		||||
    let web_window = web_sys::window().expect("could not get window");
 | 
			
		||||
    let document_element = web_window
 | 
			
		||||
        .document()
 | 
			
		||||
        .expect("could not get document")
 | 
			
		||||
        .document_element()
 | 
			
		||||
        .expect("could not get document element");
 | 
			
		||||
 | 
			
		||||
    let width = document_element.client_width();
 | 
			
		||||
    let height = document_element.client_height();
 | 
			
		||||
 | 
			
		||||
    (width as f32, height as f32)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn setup_viewport_resize_system(resize_sender: Res<Mutex<OnResizeSender>>) {
 | 
			
		||||
    let web_window = web_sys::window().expect("could not get window");
 | 
			
		||||
    let local_sender = resize_sender.lock().unwrap().clone();
 | 
			
		||||
 | 
			
		||||
    local_sender.send(()).unwrap();
 | 
			
		||||
 | 
			
		||||
    gloo_events::EventListener::new(&web_window, "resize", move |_event| {
 | 
			
		||||
        local_sender.send(()).unwrap();
 | 
			
		||||
    })
 | 
			
		||||
    .forget();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn viewport_resize_system(
 | 
			
		||||
    mut windows: ResMut<Windows>,
 | 
			
		||||
    resize_receiver: Res<Mutex<OnResizeReceiver>>,
 | 
			
		||||
) {
 | 
			
		||||
    if resize_receiver.lock().unwrap().try_recv().is_ok() {
 | 
			
		||||
        if let Some(window) = windows.get_primary_mut() {
 | 
			
		||||
            let size = get_viewport_size();
 | 
			
		||||
            window.set_resolution(size.0, size.1);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										104
									
								
								src/main.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								src/main.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,104 @@
 | 
			
		||||
use bevy::prelude::*;
 | 
			
		||||
 | 
			
		||||
#[cfg(target_family = "wasm")]
 | 
			
		||||
mod fullviewport;
 | 
			
		||||
#[cfg(target_family = "wasm")]
 | 
			
		||||
use fullviewport::FullViewportPlugin;
 | 
			
		||||
 | 
			
		||||
fn main() {
 | 
			
		||||
    #[cfg(all(target_family = "wasm", debug_assertions))]
 | 
			
		||||
    console_error_panic_hook::set_once();
 | 
			
		||||
 | 
			
		||||
    let mut app = App::new();
 | 
			
		||||
 | 
			
		||||
    #[cfg(target_family = "wasm")]
 | 
			
		||||
    app.add_plugin(FullViewportPlugin);
 | 
			
		||||
 | 
			
		||||
    app.add_plugins(DefaultPlugins)
 | 
			
		||||
        .add_startup_system(setup)
 | 
			
		||||
        .add_startup_system(start_background_audio)
 | 
			
		||||
        .add_system(rotate)
 | 
			
		||||
        .run();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Component)]
 | 
			
		||||
struct Rotatable {
 | 
			
		||||
    speed: f32,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn setup(
 | 
			
		||||
    mut commands: Commands,
 | 
			
		||||
    mut meshes: ResMut<Assets<Mesh>>,
 | 
			
		||||
    mut materials: ResMut<Assets<StandardMaterial>>,
 | 
			
		||||
) {
 | 
			
		||||
    commands.insert_resource(ClearColor(Color::BLACK));
 | 
			
		||||
    commands.insert_resource(AmbientLight {
 | 
			
		||||
        color: Color::VIOLET,
 | 
			
		||||
        brightness: 0.05,
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    commands.spawn_bundle(Camera3dBundle {
 | 
			
		||||
        transform: Transform::from_xyz(0.0, 25.0, 50.0).looking_at(Vec3::ZERO, Vec3::Y),
 | 
			
		||||
        ..Default::default()
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    commands.spawn_bundle(PbrBundle {
 | 
			
		||||
        mesh: meshes.add(Mesh::from(shape::Plane { size: 1000.0 })),
 | 
			
		||||
        material: materials.add(StandardMaterial {
 | 
			
		||||
            base_color: Color::BLACK,
 | 
			
		||||
            //metallic: 1.0,
 | 
			
		||||
            reflectance: 1.0,
 | 
			
		||||
            //perceptual_roughness: 0.0,
 | 
			
		||||
            ..Default::default()
 | 
			
		||||
        }),
 | 
			
		||||
        ..Default::default()
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    commands
 | 
			
		||||
        .spawn_bundle(PbrBundle {
 | 
			
		||||
            mesh: meshes.add(Mesh::from(shape::Cube { size: 4.0 })),
 | 
			
		||||
            material: materials.add(StandardMaterial {
 | 
			
		||||
                base_color: Color::BLACK,
 | 
			
		||||
                metallic: 1.0,
 | 
			
		||||
                //reflectance: 1.0,
 | 
			
		||||
                //perceptual_roughness: 0.0,
 | 
			
		||||
                double_sided: true,
 | 
			
		||||
                ..Default::default()
 | 
			
		||||
            }),
 | 
			
		||||
            transform: Transform::from_translation(Vec3::new(0.0, 8.0, 0.0)),
 | 
			
		||||
            ..Default::default()
 | 
			
		||||
        })
 | 
			
		||||
        .insert(Rotatable { speed: 0.1 });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    commands.spawn_bundle(DirectionalLightBundle {
 | 
			
		||||
        directional_light: DirectionalLight {
 | 
			
		||||
            color: Color::PINK,
 | 
			
		||||
            illuminance: 100000.0,
 | 
			
		||||
            shadows_enabled: true,
 | 
			
		||||
            ..Default::default()
 | 
			
		||||
        },
 | 
			
		||||
        transform: Transform {
 | 
			
		||||
            translation: Vec3::new(0.0, 16.0, 0.0),
 | 
			
		||||
            rotation: Quat::from_rotation_x(-std::f32::consts::PI),
 | 
			
		||||
            ..Default::default()
 | 
			
		||||
        },
 | 
			
		||||
        ..Default::default()
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn start_background_audio(asset_server: Res<AssetServer>, audio: Res<Audio>) {
 | 
			
		||||
    audio.play_with_settings(asset_server.load("sounds/bg.ogg"), PlaybackSettings::LOOP);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn rotate(mut rotatables: Query<(&mut Transform, &Rotatable)>, timer: Res<Time>) {
 | 
			
		||||
    for (mut transform, rotatable) in rotatables.iter_mut() {
 | 
			
		||||
        let rotation = 2.0 * std::f32::consts::PI * timer.delta_seconds();
 | 
			
		||||
        let rotation_change = Quat::from_scaled_axis(Vec3::new(
 | 
			
		||||
            rotation * rotatable.speed,
 | 
			
		||||
            rotation * rotatable.speed * -2.,
 | 
			
		||||
            rotation * rotatable.speed,
 | 
			
		||||
        ));
 | 
			
		||||
        transform.rotate(rotation_change);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										8
									
								
								web/index.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								web/index.css
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
			
		||||
body {
 | 
			
		||||
    margin: 0;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
canvas {
 | 
			
		||||
    touch-action: none;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										62
									
								
								web/sound.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								web/sound.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,62 @@
 | 
			
		||||
// Insert hack to make sound autoplay on Chrome as soon as the user interacts with the tab:
 | 
			
		||||
// https://developers.google.com/web/updates/2018/11/web-audio-autoplay#moving-forward
 | 
			
		||||
 | 
			
		||||
// the following function keeps track of all AudioContexts and resumes them on the first user
 | 
			
		||||
// interaction with the page. If the function is called and all contexts are already running,
 | 
			
		||||
// it will remove itself from all event listeners.
 | 
			
		||||
(function () {
 | 
			
		||||
    // An array of all contexts to resume on the page
 | 
			
		||||
    const audioContextList = [];
 | 
			
		||||
 | 
			
		||||
    // An array of various user interaction events we should listen for
 | 
			
		||||
    const userInputEventNames = [
 | 
			
		||||
        "click",
 | 
			
		||||
        "contextmenu",
 | 
			
		||||
        "auxclick",
 | 
			
		||||
        "dblclick",
 | 
			
		||||
        "mousedown",
 | 
			
		||||
        "mouseup",
 | 
			
		||||
        "pointerup",
 | 
			
		||||
        "touchend",
 | 
			
		||||
        "keydown",
 | 
			
		||||
        "keyup",
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    // A proxy object to intercept AudioContexts and
 | 
			
		||||
    // add them to the array for tracking and resuming later
 | 
			
		||||
    self.AudioContext = new Proxy(self.AudioContext, {
 | 
			
		||||
        construct(target, args) {
 | 
			
		||||
            const result = new target(...args);
 | 
			
		||||
            audioContextList.push(result);
 | 
			
		||||
            return result;
 | 
			
		||||
        },
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // To resume all AudioContexts being tracked
 | 
			
		||||
    function resumeAllContexts(_event) {
 | 
			
		||||
        let count = 0;
 | 
			
		||||
 | 
			
		||||
        audioContextList.forEach((context) => {
 | 
			
		||||
            if (context.state !== "running") {
 | 
			
		||||
                context.resume();
 | 
			
		||||
            } else {
 | 
			
		||||
                count++;
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // If all the AudioContexts have now resumed then we unbind all
 | 
			
		||||
        // the event listeners from the page to prevent unnecessary resume attempts
 | 
			
		||||
        // Checking count > 0 ensures that the user interaction happens AFTER the game started up
 | 
			
		||||
        if (count > 0 && count === audioContextList.length) {
 | 
			
		||||
            userInputEventNames.forEach((eventName) => {
 | 
			
		||||
                document.removeEventListener(eventName, resumeAllContexts);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // We bind the resume function for each user interaction
 | 
			
		||||
    // event on the page
 | 
			
		||||
    userInputEventNames.forEach((eventName) => {
 | 
			
		||||
        document.addEventListener(eventName, resumeAllContexts);
 | 
			
		||||
    });
 | 
			
		||||
})();
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user