make wasm work + cleaning + fix mouse
This commit is contained in:
parent
a07f0fee0f
commit
f49be0b90d
@ -1,6 +1,2 @@
|
|||||||
[target.wasm32-unknown-unknown]
|
[target.wasm32-unknown-unknown]
|
||||||
runner = "wasm-server-runner"
|
runner = "wasm-server-runner"
|
||||||
|
|
||||||
# [target.aarch64-unknown-linux-gnu]
|
|
||||||
# linker = "clang"
|
|
||||||
# rustflags = ["-C", "link-arg=-fuse-ld=/usr/bin/mold"]
|
|
68
Cargo.lock
generated
68
Cargo.lock
generated
@ -196,24 +196,6 @@ dependencies = [
|
|||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "arboard"
|
|
||||||
version = "3.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "df099ccb16cd014ff054ac1bf392c67feeef57164b05c42f037cd40f5d4357f4"
|
|
||||||
dependencies = [
|
|
||||||
"clipboard-win",
|
|
||||||
"core-graphics",
|
|
||||||
"image",
|
|
||||||
"log",
|
|
||||||
"objc2",
|
|
||||||
"objc2-app-kit",
|
|
||||||
"objc2-foundation",
|
|
||||||
"parking_lot",
|
|
||||||
"windows-sys 0.48.0",
|
|
||||||
"x11rb",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arrayref"
|
name = "arrayref"
|
||||||
version = "0.3.8"
|
version = "0.3.8"
|
||||||
@ -655,7 +637,6 @@ version = "0.31.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "954fbe8551af4b40767ea9390ec7d32fe1070a6ab55d524cf0868c17f8469a55"
|
checksum = "954fbe8551af4b40767ea9390ec7d32fe1070a6ab55d524cf0868c17f8469a55"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arboard",
|
|
||||||
"bevy_app",
|
"bevy_app",
|
||||||
"bevy_asset",
|
"bevy_asset",
|
||||||
"bevy_derive",
|
"bevy_derive",
|
||||||
@ -676,7 +657,6 @@ dependencies = [
|
|||||||
"encase",
|
"encase",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"log",
|
"log",
|
||||||
"thread_local",
|
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
@ -1605,15 +1585,6 @@ dependencies = [
|
|||||||
"libloading",
|
"libloading",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "clipboard-win"
|
|
||||||
version = "5.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "15efe7a882b08f34e38556b14f2fb3daa98769d06c7f0c1b076dfd0d983bc892"
|
|
||||||
dependencies = [
|
|
||||||
"error-code",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "codespan-reporting"
|
name = "codespan-reporting"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
@ -2161,12 +2132,6 @@ dependencies = [
|
|||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "error-code"
|
|
||||||
version = "3.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a5d9305ccc6942a704f4335694ecd3de2ea531b114ac2d51f5f843750787a92f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "euclid"
|
name = "euclid"
|
||||||
version = "0.22.11"
|
version = "0.22.11"
|
||||||
@ -2832,7 +2797,6 @@ dependencies = [
|
|||||||
"byteorder-lite",
|
"byteorder-lite",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"png",
|
"png",
|
||||||
"tiff",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2936,12 +2900,6 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "jpeg-decoder"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.76"
|
version = "0.3.76"
|
||||||
@ -4438,17 +4396,6 @@ dependencies = [
|
|||||||
"once_cell",
|
"once_cell",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tiff"
|
|
||||||
version = "0.9.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e"
|
|
||||||
dependencies = [
|
|
||||||
"flate2",
|
|
||||||
"jpeg-decoder",
|
|
||||||
"weezl",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tiny-keccak"
|
name = "tiny-keccak"
|
||||||
version = "2.0.2"
|
version = "2.0.2"
|
||||||
@ -5007,12 +4954,6 @@ dependencies = [
|
|||||||
"web-sys",
|
"web-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "weezl"
|
|
||||||
version = "0.1.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wgpu"
|
name = "wgpu"
|
||||||
version = "22.1.0"
|
version = "22.1.0"
|
||||||
@ -5427,15 +5368,6 @@ dependencies = [
|
|||||||
"windows-targets 0.42.2",
|
"windows-targets 0.42.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-sys"
|
|
||||||
version = "0.48.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
|
||||||
dependencies = [
|
|
||||||
"windows-targets 0.48.5",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.52.0"
|
version = "0.52.0"
|
||||||
|
24
Cargo.toml
24
Cargo.toml
@ -17,10 +17,6 @@ path = "src/lib.rs"
|
|||||||
name = "forestiles"
|
name = "forestiles"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# bevy = { version = "0.15", default-features = false, features = [
|
|
||||||
# "bevy_color","bevy_core_pipeline","bevy_render","bevy_winit","bevy_window","multi_threaded","wayland","bevy_sprite",
|
|
||||||
# "bevy_picking","bevy_mesh_picking_backend","bevy_ui_picking_backend","bevy_sprite_picking_backend"
|
|
||||||
# ]}
|
|
||||||
bevy = { version = "0.15", default-features = false, features = [
|
bevy = { version = "0.15", default-features = false, features = [
|
||||||
"android-native-activity",
|
"android-native-activity",
|
||||||
"android_shared_stdcxx",
|
"android_shared_stdcxx",
|
||||||
@ -57,20 +53,16 @@ bevy = { version = "0.15", default-features = false, features = [
|
|||||||
"webgl2",
|
"webgl2",
|
||||||
"wayland",
|
"wayland",
|
||||||
]}
|
]}
|
||||||
bevy-inspector-egui = { version = "0.28" }
|
bevy-inspector-egui = { version = "0.28", default-features = false, features = [
|
||||||
# winit = { version = "0.30", features = ["rwh_05", "android-native-activity"] }
|
"bevy_pbr",
|
||||||
# env_logger = "0.11"
|
"bevy_image",
|
||||||
|
"bevy_render",
|
||||||
|
"egui_open_url"
|
||||||
|
]}
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
# wgpu = "22.1"
|
|
||||||
# cfg-if = "1"
|
|
||||||
# pollster = "0.3"
|
|
||||||
# bytemuck = { version = "1.18", features = [ "derive" ] }
|
|
||||||
rand = { version = "0.8", features = ["small_rng"] }
|
rand = { version = "0.8", features = ["small_rng"] }
|
||||||
# nalgebra = "0.33"
|
|
||||||
voronoice = "0.2"
|
voronoice = "0.2"
|
||||||
noise = "0.9"
|
noise = "0.9"
|
||||||
# lazy_static = "1.5"
|
|
||||||
# image = { version = "0.25", default-features = false, features = ["rayon", "png"]}
|
|
||||||
|
|
||||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
console_error_panic_hook = "0.1.6"
|
console_error_panic_hook = "0.1.6"
|
||||||
@ -99,9 +91,9 @@ opt-level = 3
|
|||||||
[package.metadata.android]
|
[package.metadata.android]
|
||||||
package = "org.forestiles.example"
|
package = "org.forestiles.example"
|
||||||
apk_name = "forestiles"
|
apk_name = "forestiles"
|
||||||
# strip = "strip"
|
strip = "strip"
|
||||||
# see https://github.com/rust-mobile/cargo-apk
|
# see https://github.com/rust-mobile/cargo-apk
|
||||||
# assets = "assets"
|
assets = "assets"
|
||||||
build_targets = ["aarch64-linux-android", "armv7-linux-androideabi"]
|
build_targets = ["aarch64-linux-android", "armv7-linux-androideabi"]
|
||||||
|
|
||||||
[package.metadata.android.sdk]
|
[package.metadata.android.sdk]
|
||||||
|
@ -49,6 +49,7 @@ fn move_cam(
|
|||||||
// movement.y += delta.y*cam.scale.y/pressed_num as f32;
|
// movement.y += delta.y*cam.scale.y/pressed_num as f32;
|
||||||
// pointers.0.insert(**id, *new_pos);
|
// pointers.0.insert(**id, *new_pos);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
let old_midpoint = pressed_on_map.iter().fold(Vec2::ZERO, |acc, (_, _, old_pos, _, _)| {
|
let old_midpoint = pressed_on_map.iter().fold(Vec2::ZERO, |acc, (_, _, old_pos, _, _)| {
|
||||||
acc + (old_pos/pressed_on_map.len() as f32)
|
acc + (old_pos/pressed_on_map.len() as f32)
|
||||||
});
|
});
|
||||||
@ -70,4 +71,8 @@ fn move_cam(
|
|||||||
cam.scale.x /= zoom;
|
cam.scale.x /= zoom;
|
||||||
cam.scale.y /= zoom;
|
cam.scale.y /= zoom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (_, new_pos, _, id, _) in ps {
|
||||||
|
pointers.0.insert(*id, new_pos);
|
||||||
|
}
|
||||||
}
|
}
|
331
src/graphics.rs
331
src/graphics.rs
@ -1,331 +0,0 @@
|
|||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use bytemuck::{Pod, Zeroable};
|
|
||||||
use wgpu::{include_wgsl, util::DeviceExt, BindGroup, Buffer, Device, Queue, RenderPipeline, Surface, SurfaceConfiguration, VertexBufferLayout};
|
|
||||||
use winit::{event::WindowEvent, window::Window};
|
|
||||||
|
|
||||||
use crate::state::State;
|
|
||||||
|
|
||||||
mod texture;
|
|
||||||
use texture::{Texture, TEXTURE_DIMENSIONS};
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Clone, Copy, Zeroable, Pod, Debug)]
|
|
||||||
pub struct Vertex {
|
|
||||||
pub pos: [f32; 2],
|
|
||||||
/// Rgba color by default but if texture flag is not set.
|
|
||||||
/// Else the first 2 f32 are texture coordinates and the 2 last are not used
|
|
||||||
pub color: [f32; 4],
|
|
||||||
/// Each bit is used as a flag :
|
|
||||||
///
|
|
||||||
/// 1: Scaled and moved according to camera
|
|
||||||
///
|
|
||||||
/// 2: Grayscale
|
|
||||||
///
|
|
||||||
/// 4: Texture instead of color
|
|
||||||
///
|
|
||||||
/// For example 0b001 corresponds to Scaled and 0b011 to Scaled and Grayscale
|
|
||||||
pub effect: u32,
|
|
||||||
}
|
|
||||||
impl Vertex {
|
|
||||||
const DESC: VertexBufferLayout<'static> = VertexBufferLayout {
|
|
||||||
array_stride: std::mem::size_of::<Vertex>() as wgpu::BufferAddress,
|
|
||||||
step_mode: wgpu::VertexStepMode::Vertex,
|
|
||||||
attributes: &wgpu::vertex_attr_array![0 => Float32x2, 1 => Float32x4, 2 => Uint32],
|
|
||||||
};
|
|
||||||
pub const fn new_col(pos: [f32; 2], color: [f32; 4], effect: u32) -> Self {
|
|
||||||
Self {
|
|
||||||
pos,
|
|
||||||
color,
|
|
||||||
effect
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub const fn new_tex(pos: [f32; 2], tex_pos: [u16; 2], effect: u32) -> Self {
|
|
||||||
Self {
|
|
||||||
pos,
|
|
||||||
color: [tex_pos[0] as f32/TEXTURE_DIMENSIONS[0] as f32, tex_pos[1] as f32/TEXTURE_DIMENSIONS[1] as f32, 0., 0.],
|
|
||||||
effect: effect | 0b100
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Clone, Copy, Zeroable, Pod, Debug)]
|
|
||||||
pub struct Uniforms {
|
|
||||||
pub camera: [f32; 2],
|
|
||||||
pub zooms: [f32; 2]
|
|
||||||
}
|
|
||||||
impl Default for Uniforms {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
camera: [0., 0.],
|
|
||||||
zooms: [1., 1.]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Graphics<'a> {
|
|
||||||
// window: &'a Window,
|
|
||||||
pub surface_config: SurfaceConfiguration,
|
|
||||||
surface: Surface<'a>,
|
|
||||||
device: Device,
|
|
||||||
render_pipeline: RenderPipeline,
|
|
||||||
queue: Queue,
|
|
||||||
vertex_buf: Buffer,
|
|
||||||
index_buf: Buffer,
|
|
||||||
uniforms_buf: Buffer,
|
|
||||||
uniforms_bind_group: BindGroup,
|
|
||||||
diffuse_bind_group: BindGroup,
|
|
||||||
}
|
|
||||||
impl<'a> Graphics<'a> {
|
|
||||||
pub async fn init(state: &State, window: Arc<Window>) -> Self {
|
|
||||||
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
|
||||||
backends: wgpu::Backends::PRIMARY,
|
|
||||||
dx12_shader_compiler: Default::default(),
|
|
||||||
..Default::default()
|
|
||||||
});
|
|
||||||
|
|
||||||
let surface = instance.create_surface(window).unwrap();
|
|
||||||
let adapter = instance
|
|
||||||
.request_adapter(&wgpu::RequestAdapterOptions {
|
|
||||||
power_preference: wgpu::PowerPreference::default(),
|
|
||||||
force_fallback_adapter: false,
|
|
||||||
// Request an adapter which can render to our surface
|
|
||||||
compatible_surface: Some(&surface),
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
.expect("Failed to find an appropriate adapter");
|
|
||||||
|
|
||||||
// Create the logical device and command queue
|
|
||||||
let (device, queue) = adapter
|
|
||||||
.request_device(
|
|
||||||
&wgpu::DeviceDescriptor {
|
|
||||||
label: None,
|
|
||||||
required_features: wgpu::Features::empty(),
|
|
||||||
// Make sure we use the texture resolution limits from the adapter, so we can support images the size of the swapchain.
|
|
||||||
required_limits: wgpu::Limits::default()
|
|
||||||
.using_resolution(adapter.limits()),
|
|
||||||
memory_hints: wgpu::MemoryHints::MemoryUsage,
|
|
||||||
},
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.expect("Failed to create device");
|
|
||||||
|
|
||||||
let vertex_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
|
||||||
label: Some("Vertex Buffer"),
|
|
||||||
contents: &[bytemuck::cast_slice::<Vertex, _>(&state.vertices), &[0; 100000]].concat(),
|
|
||||||
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
|
|
||||||
});
|
|
||||||
|
|
||||||
let index_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
|
||||||
label: Some("Index Buffer"),
|
|
||||||
contents: &[bytemuck::cast_slice::<u32, _>(&state.indices), &[0; 100000]].concat(),
|
|
||||||
usage: wgpu::BufferUsages::INDEX | wgpu::BufferUsages::COPY_DST,
|
|
||||||
});
|
|
||||||
|
|
||||||
let uniforms_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
|
||||||
label: Some("Uniforms Buffer"),
|
|
||||||
contents: bytemuck::cast_slice(&[state.uniforms]),
|
|
||||||
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
|
||||||
});
|
|
||||||
let uniforms_bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
|
||||||
entries: &[
|
|
||||||
wgpu::BindGroupLayoutEntry {
|
|
||||||
binding: 0,
|
|
||||||
visibility: wgpu::ShaderStages::VERTEX,
|
|
||||||
ty: wgpu::BindingType::Buffer {
|
|
||||||
ty: wgpu::BufferBindingType::Uniform,
|
|
||||||
has_dynamic_offset: false,
|
|
||||||
min_binding_size: None,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
}
|
|
||||||
],
|
|
||||||
label: Some("Uniforms Bind Group Layout"),
|
|
||||||
});
|
|
||||||
let uniforms_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
|
||||||
layout: &uniforms_bind_group_layout,
|
|
||||||
entries: &[
|
|
||||||
wgpu::BindGroupEntry {
|
|
||||||
binding: 0,
|
|
||||||
resource: uniforms_buf.as_entire_binding(),
|
|
||||||
}
|
|
||||||
],
|
|
||||||
label: Some("Uniforms Bind Group"),
|
|
||||||
});
|
|
||||||
let texture_bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
|
||||||
entries: &[
|
|
||||||
wgpu::BindGroupLayoutEntry {
|
|
||||||
binding: 0,
|
|
||||||
visibility: wgpu::ShaderStages::FRAGMENT,
|
|
||||||
ty: wgpu::BindingType::Texture {
|
|
||||||
multisampled: false,
|
|
||||||
view_dimension: wgpu::TextureViewDimension::D2,
|
|
||||||
sample_type: wgpu::TextureSampleType::Float { filterable: true },
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
wgpu::BindGroupLayoutEntry {
|
|
||||||
binding: 1,
|
|
||||||
visibility: wgpu::ShaderStages::FRAGMENT,
|
|
||||||
// This should match the filterable field of the
|
|
||||||
// corresponding Texture entry above.
|
|
||||||
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
label: Some("texture_bind_group_layout"),
|
|
||||||
});
|
|
||||||
|
|
||||||
// Load the shaders from disk
|
|
||||||
let shader = device.create_shader_module(include_wgsl!("shader.wgsl"));
|
|
||||||
|
|
||||||
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
|
||||||
label: None,
|
|
||||||
bind_group_layouts: &[
|
|
||||||
&uniforms_bind_group_layout,
|
|
||||||
&texture_bind_group_layout
|
|
||||||
],
|
|
||||||
push_constant_ranges: &[],
|
|
||||||
});
|
|
||||||
|
|
||||||
let swapchain_capabilities = surface.get_capabilities(&adapter);
|
|
||||||
let swapchain_format = swapchain_capabilities.formats[0];
|
|
||||||
|
|
||||||
let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
|
||||||
label: None,
|
|
||||||
layout: Some(&pipeline_layout),
|
|
||||||
vertex: wgpu::VertexState {
|
|
||||||
module: &shader,
|
|
||||||
entry_point: "vs_main",
|
|
||||||
buffers: &[
|
|
||||||
Vertex::DESC
|
|
||||||
],
|
|
||||||
compilation_options: Default::default(),
|
|
||||||
},
|
|
||||||
fragment: Some(wgpu::FragmentState {
|
|
||||||
module: &shader,
|
|
||||||
entry_point: "fs_main",
|
|
||||||
compilation_options: Default::default(),
|
|
||||||
targets: &[Some(wgpu::ColorTargetState {
|
|
||||||
format: swapchain_format,
|
|
||||||
blend: Some(wgpu::BlendState {
|
|
||||||
color: wgpu::BlendComponent {
|
|
||||||
src_factor: wgpu::BlendFactor::SrcAlpha,
|
|
||||||
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
|
|
||||||
operation: wgpu::BlendOperation::Add
|
|
||||||
},
|
|
||||||
alpha: wgpu::BlendComponent {
|
|
||||||
src_factor: wgpu::BlendFactor::One,
|
|
||||||
dst_factor: wgpu::BlendFactor::One,
|
|
||||||
operation: wgpu::BlendOperation::Add
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
write_mask: wgpu::ColorWrites::ALL,
|
|
||||||
})],
|
|
||||||
}),
|
|
||||||
primitive: wgpu::PrimitiveState::default(),
|
|
||||||
depth_stencil: None,
|
|
||||||
multisample: wgpu::MultisampleState::default(),
|
|
||||||
multiview: None,
|
|
||||||
cache: None,
|
|
||||||
});
|
|
||||||
|
|
||||||
let surface_config = surface
|
|
||||||
.get_default_config(&adapter, 1, 1)
|
|
||||||
.unwrap();
|
|
||||||
surface.configure(&device, &surface_config);
|
|
||||||
|
|
||||||
let diffuse_bytes = include_bytes!("../assets/texture.png");
|
|
||||||
let diffuse_texture = Texture::from_bytes(&device, &queue, diffuse_bytes, "happy-tree.png");
|
|
||||||
let diffuse_bind_group = device.create_bind_group(
|
|
||||||
&wgpu::BindGroupDescriptor {
|
|
||||||
layout: &texture_bind_group_layout,
|
|
||||||
entries: &[
|
|
||||||
wgpu::BindGroupEntry {
|
|
||||||
binding: 0,
|
|
||||||
resource: wgpu::BindingResource::TextureView(&diffuse_texture.view),
|
|
||||||
},
|
|
||||||
wgpu::BindGroupEntry {
|
|
||||||
binding: 1,
|
|
||||||
resource: wgpu::BindingResource::Sampler(&diffuse_texture.sampler),
|
|
||||||
}
|
|
||||||
],
|
|
||||||
label: Some("diffuse_bind_group"),
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
Self {
|
|
||||||
// window,
|
|
||||||
surface_config,
|
|
||||||
surface,
|
|
||||||
device,
|
|
||||||
render_pipeline,
|
|
||||||
queue,
|
|
||||||
vertex_buf,
|
|
||||||
index_buf,
|
|
||||||
uniforms_buf,
|
|
||||||
uniforms_bind_group,
|
|
||||||
diffuse_bind_group
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn window_event(&mut self, event: &WindowEvent, window: &Window) {
|
|
||||||
match event {
|
|
||||||
WindowEvent::Resized(new_size) => {
|
|
||||||
// Reconfigure the surface with the new size
|
|
||||||
self.surface_config.width = new_size.width;
|
|
||||||
self.surface_config.height = new_size.height;
|
|
||||||
self.surface.configure(&self.device, &self.surface_config);
|
|
||||||
// On macos the window needs to be redrawn manually after resizing
|
|
||||||
window.request_redraw();
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn render(&self, state: &State) {
|
|
||||||
let frame = self.surface
|
|
||||||
.get_current_texture()
|
|
||||||
.expect("Failed to acquire next swap chain texture");
|
|
||||||
let view = frame
|
|
||||||
.texture
|
|
||||||
.create_view(&wgpu::TextureViewDescriptor::default());
|
|
||||||
let mut encoder =
|
|
||||||
self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
|
||||||
label: None,
|
|
||||||
});
|
|
||||||
{
|
|
||||||
let mut rpass =
|
|
||||||
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
|
||||||
label: None,
|
|
||||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
|
||||||
view: &view,
|
|
||||||
resolve_target: None,
|
|
||||||
ops: wgpu::Operations {
|
|
||||||
load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
|
|
||||||
store: wgpu::StoreOp::Store,
|
|
||||||
},
|
|
||||||
})],
|
|
||||||
depth_stencil_attachment: None,
|
|
||||||
timestamp_writes: None,
|
|
||||||
occlusion_query_set: None,
|
|
||||||
});
|
|
||||||
rpass.set_pipeline(&self.render_pipeline);
|
|
||||||
rpass.set_bind_group(0, &self.uniforms_bind_group, &[]);
|
|
||||||
rpass.set_bind_group(1, &self.diffuse_bind_group, &[]);
|
|
||||||
rpass.set_vertex_buffer(0, self.vertex_buf.slice(..));
|
|
||||||
rpass.set_index_buffer(self.index_buf.slice(..), wgpu::IndexFormat::Uint32);
|
|
||||||
rpass.draw_indexed(0..state.indices.len() as u32, 0, 0..1);
|
|
||||||
// rpass.draw(0..self.state.vertices.len() as u32, 0..1);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.queue.submit(Some(encoder.finish()));
|
|
||||||
frame.present();
|
|
||||||
}
|
|
||||||
pub fn update(&mut self, state: &State) {
|
|
||||||
self.queue.write_buffer(&self.vertex_buf, 0, bytemuck::cast_slice(&state.vertices));
|
|
||||||
self.queue.write_buffer(&self.index_buf, 0, bytemuck::cast_slice(&state.indices));
|
|
||||||
self.queue.write_buffer(&self.uniforms_buf, 0, bytemuck::cast_slice(&[state.uniforms]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,80 +0,0 @@
|
|||||||
use image::GenericImageView;
|
|
||||||
|
|
||||||
pub const TEXTURE_DIMENSIONS: [usize; 2] = [64, 64];
|
|
||||||
|
|
||||||
pub struct Texture {
|
|
||||||
pub texture: wgpu::Texture,
|
|
||||||
pub view: wgpu::TextureView,
|
|
||||||
pub sampler: wgpu::Sampler,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Texture {
|
|
||||||
pub fn from_bytes(
|
|
||||||
device: &wgpu::Device,
|
|
||||||
queue: &wgpu::Queue,
|
|
||||||
bytes: &[u8],
|
|
||||||
label: &str
|
|
||||||
) -> Self {
|
|
||||||
let img = image::load_from_memory(bytes).unwrap();
|
|
||||||
Self::from_image(device, queue, &img, Some(label))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_image(
|
|
||||||
device: &wgpu::Device,
|
|
||||||
queue: &wgpu::Queue,
|
|
||||||
img: &image::DynamicImage,
|
|
||||||
label: Option<&str>
|
|
||||||
) -> Self {
|
|
||||||
let rgba = img.to_rgba8();
|
|
||||||
let dimensions = img.dimensions();
|
|
||||||
|
|
||||||
let size = wgpu::Extent3d {
|
|
||||||
width: dimensions.0,
|
|
||||||
height: dimensions.1,
|
|
||||||
depth_or_array_layers: 1,
|
|
||||||
};
|
|
||||||
let texture = device.create_texture(
|
|
||||||
&wgpu::TextureDescriptor {
|
|
||||||
label,
|
|
||||||
size,
|
|
||||||
mip_level_count: 1,
|
|
||||||
sample_count: 1,
|
|
||||||
dimension: wgpu::TextureDimension::D2,
|
|
||||||
format: wgpu::TextureFormat::Rgba8UnormSrgb,
|
|
||||||
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
|
|
||||||
view_formats: &[],
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
queue.write_texture(
|
|
||||||
wgpu::ImageCopyTexture {
|
|
||||||
aspect: wgpu::TextureAspect::All,
|
|
||||||
texture: &texture,
|
|
||||||
mip_level: 0,
|
|
||||||
origin: wgpu::Origin3d::ZERO,
|
|
||||||
},
|
|
||||||
&rgba,
|
|
||||||
wgpu::ImageDataLayout {
|
|
||||||
offset: 0,
|
|
||||||
bytes_per_row: Some(4 * dimensions.0),
|
|
||||||
rows_per_image: Some(dimensions.1),
|
|
||||||
},
|
|
||||||
size,
|
|
||||||
);
|
|
||||||
|
|
||||||
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
|
|
||||||
let sampler = device.create_sampler(
|
|
||||||
&wgpu::SamplerDescriptor {
|
|
||||||
address_mode_u: wgpu::AddressMode::ClampToEdge,
|
|
||||||
address_mode_v: wgpu::AddressMode::ClampToEdge,
|
|
||||||
address_mode_w: wgpu::AddressMode::ClampToEdge,
|
|
||||||
mag_filter: wgpu::FilterMode::Nearest,
|
|
||||||
min_filter: wgpu::FilterMode::Nearest,
|
|
||||||
mipmap_filter: wgpu::FilterMode::Nearest,
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
Self { texture, view, sampler }
|
|
||||||
}
|
|
||||||
}
|
|
127
src/lib.rs
127
src/lib.rs
@ -1,109 +1,12 @@
|
|||||||
// mod graphics;
|
use bevy::{prelude::*, diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}};
|
||||||
// mod state;
|
use bevy_inspector_egui::quick::WorldInspectorPlugin;
|
||||||
|
|
||||||
pub mod map;
|
pub mod map;
|
||||||
pub mod camera;
|
pub mod camera;
|
||||||
pub mod ui;
|
pub mod ui;
|
||||||
|
|
||||||
use std::{fmt::Debug, sync::Arc};
|
|
||||||
|
|
||||||
use log::debug;
|
|
||||||
// use state::State;
|
|
||||||
// use graphics::Graphics;
|
|
||||||
// use winit::{application::ApplicationHandler, dpi::PhysicalSize, event::{Event, WindowEvent}, event_loop::EventLoop, window::{Window, WindowAttributes}};
|
|
||||||
use bevy::{prelude::*, diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}};
|
|
||||||
use bevy_inspector_egui::quick::WorldInspectorPlugin;
|
|
||||||
|
|
||||||
pub fn dbg<V: Debug>(v: V) -> V {
|
|
||||||
debug!(target: "app", "{:?}", v);
|
|
||||||
v
|
|
||||||
}
|
|
||||||
|
|
||||||
// struct App<'a> {
|
|
||||||
// // event_loop: EventLoop<()>,
|
|
||||||
// window: Option<Arc<Window>>,
|
|
||||||
// graphics: Option<Graphics<'a>>,
|
|
||||||
// state: State
|
|
||||||
// }
|
|
||||||
// impl App<'_> {
|
|
||||||
// fn new() -> Self {
|
|
||||||
// Self {
|
|
||||||
// window: None,
|
|
||||||
// graphics: None,
|
|
||||||
// state: State::new()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// impl ApplicationHandler for App<'_> {
|
|
||||||
// fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
|
|
||||||
// #[cfg(not(any(target_family = "wasm", target_os = "android")))]
|
|
||||||
// let window = event_loop.create_window(
|
|
||||||
// WindowAttributes::default()
|
|
||||||
// .with_inner_size(PhysicalSize::new(1080*2/5, 2000*2/5))
|
|
||||||
// ).unwrap();
|
|
||||||
// #[cfg(target_os = "android")]
|
|
||||||
// let window = event_loop.create_window(
|
|
||||||
// WindowAttributes::default()
|
|
||||||
// // .with_inner_size(PhysicalSize::new(1080*2/5, 2000*2/5))
|
|
||||||
// ).unwrap();
|
|
||||||
// self.window = Some(Arc::new(window));
|
|
||||||
// self.graphics = Some(pollster::block_on(Graphics::init(&self.state, self.window.clone().unwrap())));
|
|
||||||
// }
|
|
||||||
// fn window_event(
|
|
||||||
// &mut self,
|
|
||||||
// event_loop: &winit::event_loop::ActiveEventLoop,
|
|
||||||
// window_id: winit::window::WindowId,
|
|
||||||
// event: WindowEvent,
|
|
||||||
// ) {
|
|
||||||
// match &event {
|
|
||||||
// WindowEvent::CloseRequested => event_loop.exit(),
|
|
||||||
// WindowEvent::RedrawRequested => {
|
|
||||||
// if let Some(g) = &mut self.graphics {
|
|
||||||
// self.state.update_if_needed();
|
|
||||||
// self.state.render(self.window.as_ref().unwrap().inner_size());
|
|
||||||
// g.update(&self.state);
|
|
||||||
// g.render(&self.state);
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// WindowEvent::MouseWheel { delta, .. } => {
|
|
||||||
// dbg!(delta);
|
|
||||||
// },
|
|
||||||
// _ => {}
|
|
||||||
// }
|
|
||||||
// self.graphics.as_mut().unwrap().window_event(&event, &self.window.as_ref().unwrap());
|
|
||||||
// self.state.window_event(&event, &self.window.as_ref().unwrap());
|
|
||||||
// }
|
|
||||||
// fn about_to_wait(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
|
|
||||||
// if let Some(window) = self.window.as_ref() {
|
|
||||||
// window.request_redraw();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[cfg(not(target_os = "android"))]
|
|
||||||
#[bevy_main]
|
#[bevy_main]
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
|
|
||||||
// #[cfg(target_family = "wasm")]
|
|
||||||
// let (event_loop, window) = {
|
|
||||||
// use winit::platform::web::WindowExtWebSys;
|
|
||||||
// std::panic::set_hook(Box::new(console_error_panic_hook::hook));
|
|
||||||
// console_log::init().expect("could not initialize logger");
|
|
||||||
|
|
||||||
// let event_loop = winit::event_loop::EventLoop::new().unwrap();
|
|
||||||
// let window = winit::window::WindowBuilder::new().build(&event_loop).unwrap();
|
|
||||||
|
|
||||||
// web_sys::window()
|
|
||||||
// .unwrap()
|
|
||||||
// .document()
|
|
||||||
// .unwrap()
|
|
||||||
// .body()
|
|
||||||
// .unwrap()
|
|
||||||
// .append_child(&window.canvas().unwrap())
|
|
||||||
// .unwrap();
|
|
||||||
// (event_loop, window)
|
|
||||||
// };
|
|
||||||
|
|
||||||
App::new()
|
App::new()
|
||||||
.add_plugins((
|
.add_plugins((
|
||||||
DefaultPlugins,
|
DefaultPlugins,
|
||||||
@ -118,26 +21,4 @@ pub fn main() {
|
|||||||
}
|
}
|
||||||
))
|
))
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[cfg(target_os = "android")]
|
|
||||||
// #[no_mangle]
|
|
||||||
// fn android_main(app: winit::platform::android::activity::AndroidApp) {
|
|
||||||
// println!("test");
|
|
||||||
// // use winit::platform::android::{EventLoopBuilderExtAndroid, activity::WindowManagerFlags};
|
|
||||||
|
|
||||||
// // android_logger::init_once(
|
|
||||||
// // android_logger::Config::default()
|
|
||||||
// // .with_max_level(log::LevelFilter::Debug)
|
|
||||||
// // .with_filter(android_logger::FilterBuilder::new().parse("app").build())
|
|
||||||
// // );
|
|
||||||
|
|
||||||
// // app.set_window_flags(WindowManagerFlags::KEEP_SCREEN_ON | WindowManagerFlags::FULLSCREEN, WindowManagerFlags::empty());
|
|
||||||
|
|
||||||
// // let event_loop = winit::event_loop::EventLoopBuilder::new()
|
|
||||||
// // .with_android_app(app)
|
|
||||||
// // .build()
|
|
||||||
// // .unwrap();
|
|
||||||
|
|
||||||
// // event_loop.run_app(&mut App::new()).unwrap();
|
|
||||||
// }
|
|
@ -85,8 +85,8 @@ fn setup(
|
|||||||
let mut colors = Vec::new();
|
let mut colors = Vec::new();
|
||||||
let mut indices = Vec::new();
|
let mut indices = Vec::new();
|
||||||
|
|
||||||
for (c, mut cd) in voronoi.iter_cells().zip(cells_data.iter_mut()).filter(|(_,cd)| cd.kind != CellKind::Forest) {
|
for (c, cd) in voronoi.iter_cells().zip(cells_data.iter_mut()).filter(|(_,cd)| cd.kind != CellKind::Forest) {
|
||||||
let mut color = cd.color();
|
let color = cd.color();
|
||||||
// if c.site() == selected_tile {
|
// if c.site() == selected_tile {
|
||||||
// color[0] = (color[0]+0.4).clamp(0., 1.);
|
// color[0] = (color[0]+0.4).clamp(0., 1.);
|
||||||
// color[1] = (color[1]+0.4).clamp(0., 1.);
|
// color[1] = (color[1]+0.4).clamp(0., 1.);
|
||||||
|
@ -1,52 +0,0 @@
|
|||||||
struct Uniforms {
|
|
||||||
camera: vec2f,
|
|
||||||
zooms: vec2f
|
|
||||||
}
|
|
||||||
@group(0) @binding(0) var<uniform> uniforms : Uniforms;
|
|
||||||
|
|
||||||
struct VertexOutput {
|
|
||||||
@location(0) color: vec4f,
|
|
||||||
@location(1) effect: u32,
|
|
||||||
@builtin(position) pos: vec4f
|
|
||||||
}
|
|
||||||
|
|
||||||
@vertex
|
|
||||||
fn vs_main(
|
|
||||||
@location(0) pos: vec2f,
|
|
||||||
@location(1) color: vec4f,
|
|
||||||
@location(2) effect: u32
|
|
||||||
) -> VertexOutput {
|
|
||||||
var screen_pos: vec4f;
|
|
||||||
if (effect & 1) == 0 {
|
|
||||||
screen_pos = vec4f(pos, 0, 1);
|
|
||||||
} else {
|
|
||||||
screen_pos = vec4f((pos - uniforms.camera) * uniforms.zooms, 0, 1);
|
|
||||||
}
|
|
||||||
var out = VertexOutput(
|
|
||||||
color,
|
|
||||||
effect,
|
|
||||||
screen_pos
|
|
||||||
);
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
@group(1) @binding(0)
|
|
||||||
var t_diffuse: texture_2d<f32>;
|
|
||||||
@group(1) @binding(1)
|
|
||||||
var s_diffuse: sampler;
|
|
||||||
|
|
||||||
@fragment
|
|
||||||
fn fs_main(in: VertexOutput) -> @location(0) vec4f {
|
|
||||||
var color: vec4f;
|
|
||||||
if (in.effect & 4) == 0 {
|
|
||||||
color = in.color;
|
|
||||||
} else {
|
|
||||||
color = textureSample(t_diffuse, s_diffuse, in.color.xy);
|
|
||||||
}
|
|
||||||
// Grayscale
|
|
||||||
if (in.effect & 2) != 0 {
|
|
||||||
var v = (color.r*0.299) + (color.g*0.587) + (color.b*0.114);
|
|
||||||
color = vec4f(v, v, v, color.a);
|
|
||||||
}
|
|
||||||
return color;
|
|
||||||
}
|
|
368
src/state.rs
368
src/state.rs
@ -1,368 +0,0 @@
|
|||||||
use std::{collections::{BTreeMap, HashMap}, time::{Duration, Instant}};
|
|
||||||
use log::{debug, trace};
|
|
||||||
use map::{CellKind, Map};
|
|
||||||
use rand::prelude::*;
|
|
||||||
use voronoice::Point;
|
|
||||||
use winit::{dpi::{PhysicalPosition, PhysicalSize}, event::{DeviceEvent, Event, KeyEvent, MouseButton, MouseScrollDelta, Touch as WTouch, TouchPhase, WindowEvent}, keyboard::{KeyCode, PhysicalKey}, window::Window};
|
|
||||||
|
|
||||||
use crate::{dbg, graphics::{Uniforms, Vertex}};
|
|
||||||
|
|
||||||
mod entity;
|
|
||||||
mod map;
|
|
||||||
mod ui;
|
|
||||||
use entity::{Entity, EntityKind, ExternOp};
|
|
||||||
use ui::{Kind, UI};
|
|
||||||
|
|
||||||
fn rgba_to_grayscale(c: [f32; 4]) -> [f32; 4] {
|
|
||||||
let v = (c[0]*0.299) + (c[1]*0.587) + (c[2]*0.114);
|
|
||||||
[v, v, v, c[3]]
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Touch {
|
|
||||||
pub pos: PhysicalPosition<f64>,
|
|
||||||
/// id=1000 is for mouse
|
|
||||||
pub id: u64,
|
|
||||||
pub start: Instant
|
|
||||||
}
|
|
||||||
impl PartialEq for Touch {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.id == other.id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<WTouch> for Touch {
|
|
||||||
fn from(value: WTouch) -> Self {
|
|
||||||
Self::new(value.location, value.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Touch {
|
|
||||||
pub fn new(pos: PhysicalPosition<f64>, id: u64) -> Self {
|
|
||||||
Self {
|
|
||||||
pos,
|
|
||||||
id,
|
|
||||||
start: Instant::now()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct State {
|
|
||||||
pub vertices: Vec<Vertex>,
|
|
||||||
pub indices: Vec<u32>,
|
|
||||||
pub uniforms: Uniforms,
|
|
||||||
zoom: f32,
|
|
||||||
map: Map,
|
|
||||||
ui: UI,
|
|
||||||
start: Instant,
|
|
||||||
last_frame: Instant,
|
|
||||||
t: usize, // Time in frames
|
|
||||||
selected_tile: usize,
|
|
||||||
framerate: f32, // Update per second
|
|
||||||
pub entities: BTreeMap<usize, Entity>, // entity id --> Entities
|
|
||||||
next_eid: usize,
|
|
||||||
pub cells_entities: HashMap<usize, Vec<usize>>, // cell id --> entities id
|
|
||||||
/// Also acount for mouse
|
|
||||||
touches: Vec<Touch>,
|
|
||||||
mouse_pos: Option<PhysicalPosition<f64>>
|
|
||||||
}
|
|
||||||
impl State {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
let mut s = Self {
|
|
||||||
vertices: vec![],
|
|
||||||
indices: vec![],
|
|
||||||
uniforms: Uniforms::default(),
|
|
||||||
zoom: 1.,
|
|
||||||
start: Instant::now(),
|
|
||||||
last_frame: Instant::now(),
|
|
||||||
t: 0,
|
|
||||||
map: Map::new(0, 0),
|
|
||||||
ui: UI::new(),
|
|
||||||
selected_tile: 0,
|
|
||||||
framerate: 1.,
|
|
||||||
entities: BTreeMap::new(),
|
|
||||||
next_eid: 0,
|
|
||||||
cells_entities: HashMap::new(),
|
|
||||||
touches: Vec::new(),
|
|
||||||
mouse_pos: None
|
|
||||||
};
|
|
||||||
// Create vertices / indices to estimate vertex / index buffer size
|
|
||||||
s.render(PhysicalSize::new(1, 1));
|
|
||||||
s
|
|
||||||
}
|
|
||||||
fn set_zoom(&mut self, v: f32) {
|
|
||||||
self.zoom = v.clamp(1., 10.);
|
|
||||||
}
|
|
||||||
fn update_zooms(&mut self, screen_size: PhysicalSize<u32>) {
|
|
||||||
self.uniforms.zooms = [
|
|
||||||
(screen_size.height as f32 / screen_size.width as f32).max(1.) * self.zoom,
|
|
||||||
(screen_size.width as f32 / screen_size.height as f32).max(1.) * self.zoom
|
|
||||||
];
|
|
||||||
}
|
|
||||||
fn handle_click(&mut self, window: &Window, pos: &PhysicalPosition<f64>) {
|
|
||||||
|
|
||||||
}
|
|
||||||
pub fn window_event(&mut self, event: &WindowEvent, window: &Window) {
|
|
||||||
match event {
|
|
||||||
WindowEvent::Touch(touch) => {
|
|
||||||
match touch.phase {
|
|
||||||
TouchPhase::Started => {
|
|
||||||
self.touches.push((*touch).into());
|
|
||||||
},
|
|
||||||
TouchPhase::Moved => {
|
|
||||||
let w_size = window.inner_size();
|
|
||||||
let old_touch_n = self.touches.iter().position(|t| t.id == touch.id).unwrap();
|
|
||||||
let old_touch = &self.touches[old_touch_n];
|
|
||||||
let t = [
|
|
||||||
touch.location.x as f32/w_size.width as f32 * Map::WIDTH / self.uniforms.zooms[0],
|
|
||||||
touch.location.y as f32/w_size.height as f32 * Map::HEIGHT / self.uniforms.zooms[1]
|
|
||||||
];
|
|
||||||
let old_t = [
|
|
||||||
old_touch.pos.x as f32/w_size.width as f32 * Map::WIDTH / self.uniforms.zooms[0],
|
|
||||||
old_touch.pos.y as f32/w_size.height as f32 * Map::HEIGHT / self.uniforms.zooms[1]
|
|
||||||
];
|
|
||||||
// Handle pinch zoom
|
|
||||||
if self.touches.len() == 2 {
|
|
||||||
let old_touch2 = &self.touches[if old_touch_n == 0 {1} else {0}];
|
|
||||||
let old_t2 = [
|
|
||||||
old_touch2.pos.x as f32/w_size.width as f32 * Map::WIDTH / self.uniforms.zooms[0],
|
|
||||||
old_touch2.pos.y as f32/w_size.height as f32 * Map::HEIGHT / self.uniforms.zooms[1]
|
|
||||||
];
|
|
||||||
self.set_zoom(self.zoom + (((((t[0]-old_t2[0])*self.zoom).powi(2)+((t[0]-old_t2[0])*self.zoom).powi(2)).sqrt() - (((old_t[0]-old_t2[0])*self.zoom).powi(2)+((old_t[0]-old_t2[0])*self.zoom).powi(2)).sqrt())*4.));
|
|
||||||
}
|
|
||||||
self.uniforms.camera[0] -= (t[0] - old_t[0]) / self.touches.len() as f32;
|
|
||||||
self.uniforms.camera[1] += (t[1] - old_t[1]) / self.touches.len() as f32;
|
|
||||||
dbg(&self.uniforms.camera);
|
|
||||||
self.touches[old_touch_n].pos = touch.location;
|
|
||||||
},
|
|
||||||
TouchPhase::Ended => {
|
|
||||||
let old_touch_n = self.touches.iter().position(|t| t.id == touch.id).unwrap();
|
|
||||||
let old_touch = &self.touches[old_touch_n];
|
|
||||||
if old_touch.start.elapsed() < Duration::from_millis(500) {
|
|
||||||
self.handle_click(window, &touch.location);
|
|
||||||
}
|
|
||||||
self.touches.remove(self.touches.iter().position(|t| t.id == touch.id).unwrap());
|
|
||||||
},
|
|
||||||
TouchPhase::Cancelled => {
|
|
||||||
self.touches.remove(self.touches.iter().position(|t| t.id == touch.id).unwrap());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
WindowEvent::MouseInput { state, button, ..} => {
|
|
||||||
if state.is_pressed() {
|
|
||||||
match button {
|
|
||||||
MouseButton::Left => {
|
|
||||||
if !self.touches.iter().any(|t| t.id == 1000) {
|
|
||||||
if let Some(pos) = self.mouse_pos {
|
|
||||||
self.touches.push(Touch::new(pos, 1000));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
MouseButton::Right => {
|
|
||||||
self.spawn_entity(self.selected_tile, Entity::new(EntityKind::Horse, self.selected_tile));
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
match button {
|
|
||||||
MouseButton::Left => {
|
|
||||||
if let Some(i) = self.touches.iter().position(|t| t.id == 1000) {
|
|
||||||
self.touches.remove(i);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
WindowEvent::CursorLeft { .. } => {
|
|
||||||
self.mouse_pos = None;
|
|
||||||
if let Some(i) = self.touches.iter().position(|t| t.id == 1000) {
|
|
||||||
self.touches.remove(i);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
WindowEvent::CursorMoved { position, .. } => {
|
|
||||||
self.mouse_pos = Some(*position);
|
|
||||||
let w_size = window.inner_size();
|
|
||||||
self.update_zooms(w_size);
|
|
||||||
let pos = Point {
|
|
||||||
x: (((position.x / w_size.width as f64)*2.)-1.)/(self.uniforms.zooms[0] as f64) + self.uniforms.camera[0] as f64,
|
|
||||||
y: -(((position.y / w_size.height as f64)*2.)-1.)/(self.uniforms.zooms[1] as f64) + self.uniforms.camera[1] as f64
|
|
||||||
};
|
|
||||||
let c = self.map.voronoi.cell(self.selected_tile);
|
|
||||||
if let Some(i) = self.touches.iter().position(|t| t.id == 1000) {
|
|
||||||
self.touches[i].pos = *position;
|
|
||||||
for i in c.iter_path(pos.clone()) {
|
|
||||||
self.selected_tile = i;
|
|
||||||
let cd = &mut self.map.cells_data[self.selected_tile];
|
|
||||||
if let CellKind::Dirt = cd.kind {
|
|
||||||
cd.kind = CellKind::Forest;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.selected_tile = c.iter_path(pos).last().unwrap();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
WindowEvent::KeyboardInput { event: KeyEvent { physical_key: PhysicalKey::Code(kc), state, .. }, .. } => {
|
|
||||||
if state.is_pressed() {
|
|
||||||
match kc {
|
|
||||||
KeyCode::KeyW => {
|
|
||||||
self.uniforms.camera[1] += 0.1 * self.zoom;
|
|
||||||
},
|
|
||||||
KeyCode::KeyS => {
|
|
||||||
self.uniforms.camera[1] -= 0.1 / self.zoom;
|
|
||||||
},
|
|
||||||
KeyCode::KeyA => {
|
|
||||||
self.uniforms.camera[0] -= 0.1 / self.zoom;
|
|
||||||
},
|
|
||||||
KeyCode::KeyD => {
|
|
||||||
self.uniforms.camera[0] += 0.1 / self.zoom;
|
|
||||||
},
|
|
||||||
KeyCode::KeyR => {
|
|
||||||
self.set_zoom(self.zoom + 0.1);
|
|
||||||
},
|
|
||||||
KeyCode::KeyF => {
|
|
||||||
self.set_zoom(self.zoom - 0.1);
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
self.update_zooms(window.inner_size());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
WindowEvent::MouseWheel { delta, .. } => {
|
|
||||||
self.framerate -= match delta {
|
|
||||||
MouseScrollDelta::PixelDelta(pos) => pos.y as f32,
|
|
||||||
MouseScrollDelta::LineDelta(_, y) => *y
|
|
||||||
} * 0.1;
|
|
||||||
self.framerate = self.framerate.max(0.);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn render(&mut self, screen_size: PhysicalSize<u32>) {
|
|
||||||
trace!("render");
|
|
||||||
self.update_zooms(screen_size);
|
|
||||||
self.vertices = Vec::new();
|
|
||||||
self.indices = Vec::new();
|
|
||||||
|
|
||||||
for (c, cd) in self.map.voronoi.iter_cells().zip(self.map.cells_data.iter()).filter(|(_,cd)| cd.kind != CellKind::Forest) {
|
|
||||||
let mut color = cd.color();
|
|
||||||
if c.site() == self.selected_tile {
|
|
||||||
color[0] = (color[0]+0.4).clamp(0., 1.);
|
|
||||||
color[1] = (color[1]+0.4).clamp(0., 1.);
|
|
||||||
color[2] = (color[2]+0.4).clamp(0., 1.);
|
|
||||||
}
|
|
||||||
let vs = c.iter_vertices().collect::<Vec<_>>();
|
|
||||||
let i = self.vertices.len() as u32;
|
|
||||||
for v in vs.iter() {
|
|
||||||
self.vertices.push(Vertex::new_col([v.x as f32, v.y as f32], color, 1));
|
|
||||||
}
|
|
||||||
for v in 1..(vs.len()-1) as u32 {
|
|
||||||
self.indices.push(i);
|
|
||||||
self.indices.push(i+v);
|
|
||||||
self.indices.push(i+v+1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for e in self.entities.values() {
|
|
||||||
e.render(&mut self.vertices, &mut self.indices, &self.map, );
|
|
||||||
}
|
|
||||||
|
|
||||||
for (c, cd) in self.map.voronoi.iter_cells().zip(self.map.cells_data.iter()).filter(|(_,cd)| cd.kind == CellKind::Forest) {
|
|
||||||
let mut color = cd.color();
|
|
||||||
if c.site() == self.selected_tile {
|
|
||||||
color[0] = (color[0]+0.4).clamp(0., 1.);
|
|
||||||
color[1] = (color[1]+0.4).clamp(0., 1.);
|
|
||||||
color[2] = (color[2]+0.4).clamp(0., 1.);
|
|
||||||
}
|
|
||||||
let vs = c.iter_vertices().collect::<Vec<_>>();
|
|
||||||
let i = self.vertices.len() as u32;
|
|
||||||
for v in vs.iter() {
|
|
||||||
self.vertices.push(Vertex::new_col([v.x as f32, v.y as f32], color, 1));
|
|
||||||
}
|
|
||||||
for v in 1..(vs.len()-1) as u32 {
|
|
||||||
self.indices.push(i);
|
|
||||||
self.indices.push(i+v);
|
|
||||||
self.indices.push(i+v+1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.ui.render(&mut self.vertices, &mut self.indices, screen_size);
|
|
||||||
}
|
|
||||||
pub fn update_if_needed(&mut self) {
|
|
||||||
while self.last_frame.elapsed().as_secs_f32() > 1. / self.framerate {
|
|
||||||
self.update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn update(&mut self) {
|
|
||||||
trace!("update");
|
|
||||||
|
|
||||||
self.last_frame = Instant::now();
|
|
||||||
let mut rng = thread_rng();
|
|
||||||
let mut new_kind = Vec::new();
|
|
||||||
for cd in self.map.cells_data.iter_mut() {
|
|
||||||
cd.update();
|
|
||||||
}
|
|
||||||
for cd in self.map.cells_data.iter() {
|
|
||||||
if cd.kind == CellKind::Forest || cd.kind == CellKind::Grass {
|
|
||||||
let r = rng.gen::<f32>();
|
|
||||||
if r < (0.035*cd.moisture) {
|
|
||||||
let c = self.map.voronoi.cell(cd.cid);
|
|
||||||
let n = c.iter_neighbors().choose(&mut rng).unwrap();
|
|
||||||
let k = if r < (0.005*cd.moisture) && (self.map.cells_data[n].kind == CellKind::Dirt || self.map.cells_data[n].kind == CellKind::Grass) && cd.kind == CellKind::Forest {
|
|
||||||
Some(CellKind::Forest)
|
|
||||||
} else if self.map.cells_data[n].kind == CellKind::Dirt {
|
|
||||||
Some(CellKind::Grass)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
if let Some(k) = k {
|
|
||||||
new_kind.push((n, k));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (n, k) in new_kind {
|
|
||||||
let cd = &mut self.map.cells_data[n];
|
|
||||||
cd.kind = k;
|
|
||||||
cd.resource = 1.;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if Option is None remove the entity
|
|
||||||
let mut entities_to_move: Vec<(usize, Option<usize>)> = Vec::new();
|
|
||||||
for (eid, e) in self.entities.iter_mut() {
|
|
||||||
match e.update(&mut self.map, self.t, &mut rng) {
|
|
||||||
Some(ExternOp::Move(cid)) => {
|
|
||||||
entities_to_move.push((*eid, Some(cid)));
|
|
||||||
},
|
|
||||||
Some(ExternOp::Remove) => {
|
|
||||||
entities_to_move.push((*eid, None));
|
|
||||||
},
|
|
||||||
None => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (eid, new_cid) in entities_to_move {
|
|
||||||
let entity = self.entities.get_mut(&eid).unwrap();
|
|
||||||
let cell_entities = self.cells_entities.get_mut(&entity.cid).unwrap();
|
|
||||||
cell_entities.remove(cell_entities.iter().position(|e| *e == eid).unwrap());
|
|
||||||
match new_cid {
|
|
||||||
Some(new_cid) => {
|
|
||||||
entity.cid = new_cid;
|
|
||||||
match self.cells_entities.get_mut(&new_cid) {
|
|
||||||
Some(v) => v.push(eid),
|
|
||||||
None => {self.cells_entities.insert(new_cid, vec![eid]);}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
None => {self.entities.remove(&eid);}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.t += 1;
|
|
||||||
}
|
|
||||||
pub fn spawn_entity(&mut self, cid: usize, e: Entity) {
|
|
||||||
let eid = self.next_eid;
|
|
||||||
self.next_eid += 1;
|
|
||||||
self.entities.insert(eid, e);
|
|
||||||
if let Some(v) = self.cells_entities.get_mut(&cid) {
|
|
||||||
v.push(eid);
|
|
||||||
} else {
|
|
||||||
self.cells_entities.insert(cid, vec![eid]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,221 +0,0 @@
|
|||||||
use std::time::Instant;
|
|
||||||
|
|
||||||
use rand::{rngs::ThreadRng, seq::IteratorRandom, Rng};
|
|
||||||
|
|
||||||
use crate::graphics::Vertex;
|
|
||||||
|
|
||||||
use super::{map::CellKind, Map};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
pub enum EntityKind {
|
|
||||||
Horse
|
|
||||||
}
|
|
||||||
impl EntityKind {
|
|
||||||
const fn is_herbivore(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
Self::Horse => true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
pub enum EntityState {
|
|
||||||
Walking(Instant), // Start of walk
|
|
||||||
Resting
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum ExternOp {
|
|
||||||
Remove,
|
|
||||||
Move(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Entity {
|
|
||||||
pub cid: usize,
|
|
||||||
kind: EntityKind,
|
|
||||||
start: Instant,
|
|
||||||
state: EntityState,
|
|
||||||
health: f32 // between 0 and 1
|
|
||||||
}
|
|
||||||
impl Entity {
|
|
||||||
pub fn new(kind: EntityKind, cid: usize, ) -> Self {
|
|
||||||
Self {
|
|
||||||
cid,
|
|
||||||
kind,
|
|
||||||
start: Instant::now(),
|
|
||||||
state: EntityState::Walking(Instant::now()),
|
|
||||||
health: 1.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn set_health(&mut self, val: f32) {
|
|
||||||
self.health = val.clamp(0., 1.);
|
|
||||||
}
|
|
||||||
pub fn render(&self, vertices: &mut Vec<Vertex>, indices: &mut Vec<u32>, map: &Map) {
|
|
||||||
let pos = &map.voronoi.sites()[self.cid];
|
|
||||||
match self.kind {
|
|
||||||
EntityKind::Horse => {
|
|
||||||
let color = [171./255. * self.health, 122./255. * self.health, 50./255. * self.health, 1.];
|
|
||||||
let dark = [color[0]-0.3, color[1]-0.3, color[2]-0.3, 1.];
|
|
||||||
let (vs, is) = match self.state {
|
|
||||||
EntityState::Walking(now) => {
|
|
||||||
let now = now.elapsed().as_secs_f32()*5.;
|
|
||||||
(
|
|
||||||
[
|
|
||||||
// back left leg
|
|
||||||
Vertex::new_col([-0.5, 0.3], dark, 1),
|
|
||||||
Vertex::new_col([-0.4 + (now.sin()*0.1), -0.7 + (now.cos().max(-0.5)*0.1)], dark, 1),
|
|
||||||
Vertex::new_col([-0.25, 0.1], dark, 1),
|
|
||||||
|
|
||||||
// back right leg
|
|
||||||
Vertex::new_col([-0.5, 0.3], color, 1),
|
|
||||||
Vertex::new_col([-0.4 + ((now + 1.).sin()*0.1), -0.7 + ((now + 1.).cos().max(-0.5)*0.1)], color, 1),
|
|
||||||
Vertex::new_col([-0.25, 0.1], color, 1),
|
|
||||||
|
|
||||||
// front left leg
|
|
||||||
Vertex::new_col([0.3, 0.2], dark, 1),
|
|
||||||
Vertex::new_col([0.4 + ((now-1.).sin()*0.1), -0.7 + ((now-1.).cos().max(-0.5)*0.1)], dark, 1),
|
|
||||||
Vertex::new_col([0.5, 0.3], dark, 1),
|
|
||||||
|
|
||||||
// front right leg
|
|
||||||
Vertex::new_col([0.3, 0.2], color, 1),
|
|
||||||
Vertex::new_col([0.4 + ((now-2.).sin()*0.1), -0.7 + ((now-2.).cos().max(-0.5)*0.1)], color, 1),
|
|
||||||
Vertex::new_col([0.5, 0.3], color, 1),
|
|
||||||
|
|
||||||
// body
|
|
||||||
// 3
|
|
||||||
Vertex::new_col([-0.3, 0.], color, 1),
|
|
||||||
Vertex::new_col([0.4, -0.1], color, 1),
|
|
||||||
// 11
|
|
||||||
Vertex::new_col([0.3, 0.4], color, 1),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
0,1,2,
|
|
||||||
3,4,5,
|
|
||||||
6,7,8,
|
|
||||||
9,10,11,
|
|
||||||
3,12,13,
|
|
||||||
3,13,11,
|
|
||||||
3,11,14
|
|
||||||
]
|
|
||||||
)
|
|
||||||
},
|
|
||||||
EntityState::Resting => {
|
|
||||||
(
|
|
||||||
[
|
|
||||||
// back left leg
|
|
||||||
Vertex::new_col([-0.5, 0.3], dark, 1),
|
|
||||||
Vertex::new_col([-0.4, -0.75], dark, 1),
|
|
||||||
Vertex::new_col([-0.25, 0.1], dark, 1),
|
|
||||||
|
|
||||||
// back right leg
|
|
||||||
Vertex::new_col([-0.5, 0.3], color, 1),
|
|
||||||
Vertex::new_col([-0.4, -0.75], color, 1),
|
|
||||||
Vertex::new_col([-0.25, 0.1], color, 1),
|
|
||||||
|
|
||||||
// front left leg
|
|
||||||
Vertex::new_col([0.3, 0.2], dark, 1),
|
|
||||||
Vertex::new_col([0.4, -0.75], dark, 1),
|
|
||||||
Vertex::new_col([0.5, 0.3], dark, 1),
|
|
||||||
|
|
||||||
// front right leg
|
|
||||||
Vertex::new_col([0.3, 0.2], color, 1),
|
|
||||||
Vertex::new_col([0.4, -0.75], color, 1),
|
|
||||||
Vertex::new_col([0.5, 0.3], color, 1),
|
|
||||||
|
|
||||||
// body
|
|
||||||
// 3
|
|
||||||
Vertex::new_col([-0.3, 0.], color, 1),
|
|
||||||
Vertex::new_col([0.4, -0.1], color, 1),
|
|
||||||
// 11
|
|
||||||
Vertex::new_col([0.3, 0.4], color, 1),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
0,1,2,
|
|
||||||
3,4,5,
|
|
||||||
6,7,8,
|
|
||||||
9,10,11,
|
|
||||||
3,12,13,
|
|
||||||
3,13,11,
|
|
||||||
3,11,14
|
|
||||||
]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
vertices.reserve(vs.len());
|
|
||||||
let base = vertices.len() as u32;
|
|
||||||
for mut v in vs {
|
|
||||||
v.pos[0] = v.pos[0]/50. + pos.x as f32;
|
|
||||||
v.pos[1] = (v.pos[1] + 0.75)/50. + pos.y as f32;
|
|
||||||
vertices.push(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
indices.reserve(is.len());
|
|
||||||
for i in is {
|
|
||||||
indices.push(base + i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// Returns new cell if entity moves
|
|
||||||
pub fn update(&mut self, map: &mut Map, t: usize, rng: &mut ThreadRng) -> Option<ExternOp> {
|
|
||||||
// Let’s take 0.57 kg of grass / m2
|
|
||||||
// Let’s take 7.5 kg of food / day for a horse
|
|
||||||
// Let’s say that a horse can survive up to 20 days without food
|
|
||||||
let cd = &mut map.cells_data[self.cid];
|
|
||||||
if self.kind.is_herbivore() {
|
|
||||||
let food_needed: f32 = match self.kind {
|
|
||||||
EntityKind::Horse => 7.5 / (0.57 * Map::CELL_AREA)
|
|
||||||
}; // in cell resource fraction
|
|
||||||
match cd.kind {
|
|
||||||
CellKind::Forest => {}, // Infinite food in forests
|
|
||||||
CellKind::Grass => {
|
|
||||||
let food_eaten = food_needed.min(cd.resource);
|
|
||||||
self.set_health(self.health - ((((food_needed - food_eaten)/food_needed)-0.5)/20.));
|
|
||||||
cd.set_resource(cd.resource-food_eaten, t);
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
self.set_health(self.health - 1./20.);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.health == 0. {
|
|
||||||
return Some(ExternOp::Remove);
|
|
||||||
}
|
|
||||||
|
|
||||||
let r = cd.resource;
|
|
||||||
if cd.kind != CellKind::Grass {
|
|
||||||
map.voronoi.cell(cd.cid).iter_neighbors().filter(|n| {
|
|
||||||
let cd = &map.cells_data[*n];
|
|
||||||
cd.kind == CellKind::Grass
|
|
||||||
}).choose(rng).map(|c| ExternOp::Move(c))
|
|
||||||
} else if r < 0.5 {
|
|
||||||
let cd = &map.cells_data[self.cid];
|
|
||||||
Some(ExternOp::Move(
|
|
||||||
map.voronoi.cell(cd.cid)
|
|
||||||
.iter_neighbors()
|
|
||||||
.filter(|n| map.cells_data[*n].kind == CellKind::Grass)
|
|
||||||
.fold(cd, |acc, c| {
|
|
||||||
let cd = &map.cells_data[c];
|
|
||||||
if acc.kind != CellKind::Grass {
|
|
||||||
cd
|
|
||||||
} else if cd.kind != CellKind::Grass {
|
|
||||||
acc
|
|
||||||
} else if acc.resource > cd.resource {
|
|
||||||
acc
|
|
||||||
} else if acc.resource < cd.resource {
|
|
||||||
cd
|
|
||||||
} else if rng.gen_bool(0.5) {
|
|
||||||
cd
|
|
||||||
} else {
|
|
||||||
acc
|
|
||||||
}
|
|
||||||
}).cid
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,48 +0,0 @@
|
|||||||
use winit::{dpi::PhysicalSize, event::{Touch, TouchPhase, WindowEvent}};
|
|
||||||
use crate::graphics::Vertex;
|
|
||||||
|
|
||||||
const SECONDARY_COLOR: [f32; 4] = [84./255., 33./255., 32./255., 1.];
|
|
||||||
const KIND_BUTTON_SIZE: f32 = 0.2;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
pub enum Kind {
|
|
||||||
None,
|
|
||||||
Terrain,
|
|
||||||
Entities
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct UI {
|
|
||||||
pub kind_selected: Kind
|
|
||||||
}
|
|
||||||
impl UI {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
kind_selected: Kind::Entities
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn render(&self, vertices: &mut Vec<Vertex>, indices: &mut Vec<u32>, screen_size: PhysicalSize<u32>) {
|
|
||||||
let ratio = screen_size.height as f32/screen_size.width as f32;
|
|
||||||
let vs = [
|
|
||||||
// Terrain
|
|
||||||
Vertex::new_tex([-1. + (0.02*ratio), -1. + (0.02+KIND_BUTTON_SIZE)], [0, 1], 0),
|
|
||||||
Vertex::new_tex([-1. + (0.02*ratio), -1. + 0.02], [0, 13], 0),
|
|
||||||
Vertex::new_tex([-1. + ((0.02+KIND_BUTTON_SIZE)*ratio), -1. + 0.02], [12, 13], 0),
|
|
||||||
Vertex::new_tex([-1. + ((0.02+KIND_BUTTON_SIZE)*ratio), -1. + (0.02+KIND_BUTTON_SIZE)], [12, 1], 0),
|
|
||||||
|
|
||||||
// Entities
|
|
||||||
Vertex::new_tex([-1. + ((0.02+KIND_BUTTON_SIZE)*ratio)+(0.02*ratio), -1. + (0.02+KIND_BUTTON_SIZE)], [12, 1], 0),
|
|
||||||
Vertex::new_tex([-1. + ((0.02+KIND_BUTTON_SIZE)*ratio)+(0.02*ratio), -1. + 0.02], [12, 13], 0),
|
|
||||||
Vertex::new_tex([-1. + ((0.02+KIND_BUTTON_SIZE)*ratio)+((0.02+KIND_BUTTON_SIZE)*ratio), -1. + 0.02], [24, 13], 0),
|
|
||||||
Vertex::new_tex([-1. + ((0.02+KIND_BUTTON_SIZE)*ratio)+((0.02+KIND_BUTTON_SIZE)*ratio), -1. + (0.02+KIND_BUTTON_SIZE)], [24, 1], 0),
|
|
||||||
];
|
|
||||||
let ids = [
|
|
||||||
0,1,2,
|
|
||||||
2,3,0,
|
|
||||||
4,5,6,
|
|
||||||
6,7,4
|
|
||||||
];
|
|
||||||
let i = vertices.len() as u32;
|
|
||||||
vertices.extend_from_slice(&vs);
|
|
||||||
indices.extend_from_slice(&ids.map(|id| id+i));
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user