Implementing garbage collector, tables, renderer and virtual machine.

This commit is contained in:
paladin 2026-08-16 12:06:30 +01:00
parent eba41e4330
commit 35cf269781
10 changed files with 683 additions and 1327 deletions

107
Cargo.lock generated
View file

@ -18,6 +18,12 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618"
[[package]]
name = "adler2"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
[[package]]
name = "ahash"
version = "0.8.12"
@ -246,6 +252,12 @@ dependencies = [
"syn",
]
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "bytes"
version = "1.11.1"
@ -313,6 +325,12 @@ dependencies = [
"unicode-width",
]
[[package]]
name = "color_quant"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
[[package]]
name = "colorchoice"
version = "1.0.5"
@ -398,6 +416,15 @@ dependencies = [
"libc",
]
[[package]]
name = "crc32fast"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
dependencies = [
"cfg-if",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.21"
@ -501,12 +528,31 @@ dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "fdeflate"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c"
dependencies = [
"simd-adler32",
]
[[package]]
name = "find-msvc-tools"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
[[package]]
name = "flate2"
version = "1.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c"
dependencies = [
"crc32fast",
"miniz_oxide",
]
[[package]]
name = "foldhash"
version = "0.1.5"
@ -575,9 +621,12 @@ name = "game"
version = "0.1.0"
dependencies = [
"anyhow",
"bytemuck",
"console_error_panic_hook",
"console_log",
"env_logger",
"glam",
"image",
"log",
"pollster",
"wasm-bindgen",
@ -620,6 +669,15 @@ dependencies = [
"xml-rs",
]
[[package]]
name = "glam"
version = "0.33.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7360bd2cd76e0cd9032d42cf2922155cecea2685b0cfa4630c3246df030bcfd6"
dependencies = [
"bytemuck",
]
[[package]]
name = "glow"
version = "0.17.0"
@ -725,6 +783,20 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
[[package]]
name = "image"
version = "0.24.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d"
dependencies = [
"bytemuck",
"byteorder",
"color_quant",
"jpeg-decoder",
"num-traits",
"png",
]
[[package]]
name = "indexmap"
version = "2.14.0"
@ -833,6 +905,12 @@ dependencies = [
"libc",
]
[[package]]
name = "jpeg-decoder"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00810f1d8b74be64b13dbf3db89ac67740615d6c891f0e7b6179326533011a07"
[[package]]
name = "js-sys"
version = "0.3.98"
@ -944,6 +1022,16 @@ dependencies = [
"libc",
]
[[package]]
name = "miniz_oxide"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
dependencies = [
"adler2",
"simd-adler32",
]
[[package]]
name = "naga"
version = "29.0.3"
@ -1398,6 +1486,19 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
[[package]]
name = "png"
version = "0.17.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526"
dependencies = [
"bitflags 1.3.2",
"crc32fast",
"fdeflate",
"flate2",
"miniz_oxide",
]
[[package]]
name = "polling"
version = "3.11.0"
@ -1696,6 +1797,12 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "simd-adler32"
version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea"
[[package]]
name = "simd_cesu8"
version = "1.1.1"

View file

@ -18,7 +18,10 @@ env_logger = "0.11.10"
log = "0.4"
wgpu = "29.0.3"
pollster = "0.4.0"
glam = { version = "0.33.3", features = [ "bytemuck" ] }
console_error_panic_hook = "0.1.7"
bytemuck = { version = "1.25.0", features = [ "derive" ]}
image = { version = "0.24", default-features = false, features = ["png", "jpeg"]}
[target.'cfg(target_arch = "wasm32")'.dependencies]
console_error_panic_hook = "0.1.6"

View file

@ -1,19 +1,35 @@
// Vertex shader
@group(1) @binding(0)
var<uniform> view: mat4x4<f32>;
struct VertexInput {
@location(0) position: vec3<f32>,
@location(1) tex_coords: vec2<f32>,
}
struct VertexOutput {
@builtin(position) clip_position: vec4<f32>,
};
@location(0) tex_coords: vec2<f32>,
}
@vertex
fn vs_main(
@builtin(vertex_index) in_vertex_index: u32,
model: VertexInput,
) -> VertexOutput {
var out: VertexOutput;
let x = f32(1 - i32(in_vertex_index)) * 0.5;
let y = f32(i32(in_vertex_index & 1u) * 2 - 1) * 0.5;
out.clip_position = vec4<f32>(x, y, 0.0, 1.0);
out.tex_coords = model.tex_coords;
out.clip_position = view * vec4<f32>(model.position, 1.0);
return out;
}
// Fragment shader
@group(0) @binding(0)
var t_diffuse: texture_2d<f32>;
@group(0) @binding(1)
var s_diffuse: sampler;
@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
return vec4<f32>(0.3, 0.2, 0.1, 1.0);
return textureSample(t_diffuse, s_diffuse, in.tex_coords);
}

View file

@ -1,5 +1,74 @@
use std::collections::HashMap;
// Credit of most code to https://sotrh.github.io/learn-wgpu/ since I'm not familiar with wgpu
use std::sync::Arc;
use glam::camera::lh::proj::directx::perspective;
use wgpu::util::DeviceExt;
use glam::prelude::*;
struct Controller {
buttons: HashMap<MouseButton,bool>,
keys: HashMap<KeyCode,bool>,
mouse: Vec2,
}
impl Controller {
fn new() -> Controller {
Controller {
buttons: Default::default(),
keys: HashMap::new(),
mouse: Vec2::new(0.0,0.0),
}
}
}
struct Camera {
frame: Affine3A,
aspect_ratio: f32,
z_near: f32,
z_far: f32,
fov_y: f32,
}
impl Camera {
fn view(&self) -> Mat4 {
let projection = perspective(self.fov_y, self.aspect_ratio, self.z_near, self.z_far);
projection * self.frame.inverse()
}
fn new(window: &Arc<Window>) -> Camera {
Camera {
aspect_ratio: window.inner_size().width as f32 / window.inner_size().height as f32,
frame: Affine3A::IDENTITY,
fov_y: 90.0,
z_near: 0.1,
z_far: 1000.0
}
}
fn resize(&mut self, window: &Arc<Window>) {
self.aspect_ratio = window.inner_size().width as f32 / window.inner_size().height as f32
}
fn control(&mut self, delta: Vec3) {
self.frame = self.frame * Affine3A::from_translation(delta);
}
fn rotate(&mut self, yaw: f32, pitch: f32) {
let (mut y,mut x,z) = self.frame.matrix3.to_euler(EulerRot::YXZ);
x = (x + pitch * 0.005).clamp(-1.4,1.4);
y = y + yaw * 0.005;
self.frame.matrix3 = Mat3A::from_euler(EulerRot::YXZ,y,x,z);
}
}
const VERTICES: &[Vertex] = &[
// Changed
Vertex { position: [-0.5,-0.5,-0.5], tex_coords: [0,0]}
];
const INDICES: &[u16] = &[
0, 1, 4,
1, 2, 4,
2, 3, 4,
];
#[cfg(target_arch = "wasm32")]
use wasm_bindgen::prelude::*;
@ -14,17 +83,83 @@ use winit::{
window::Window,
};
// This will store the state of our game
pub struct State {
surface: wgpu::Surface<'static>,
type Kt<K,V> = HashMap<K,Vec<V>>;
struct Renderer {
surface: (wgpu::Surface<'static>,bool),
config: wgpu::SurfaceConfiguration,
device: wgpu::Device,
queue: wgpu::Queue,
config: wgpu::SurfaceConfiguration,
is_surface_configured: bool,
camera: Camera,
clear_color: wgpu::Color,
}
struct UniformPlan {
bind_group: wgpu::BindGroup,
buffer: wgpu::Buffer,
}
struct TexturePlan {
bind_group: wgpu::BindGroup,
texture: wgpu::Texture,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
struct SimpleVertex {
pos: [f32; 3],
uv: [f32; 2],
norm: [f32; 3],
}
impl SimpleVertex {
fn desc() -> wgpu::VertexBufferLayout<'static> {
wgpu::VertexBufferLayout {
array_stride: std::mem::size_of::<SimpleVertex>() as wgpu::BufferAddress,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: &[
wgpu::VertexAttribute {
offset: 0,
shader_location: 0,
format: wgpu::VertexFormat::Float32x3,
},
wgpu::VertexAttribute {
offset: std::mem::size_of::<[f32; 3]>() as wgpu::BufferAddress,
shader_location: 1,
format: wgpu::VertexFormat::Float32x2,
},
wgpu::VertexAttribute {
offset: std::mem::size_of::<[f32; 5]>() as wgpu::BufferAddress,
shader_location: 2,
format: wgpu::VertexFormat::Float32x3,
}
]
}
}
}
struct SimpleMesh {
vertex_buffer: wgpu::Buffer,
index_buffer: wgpu::Buffer,
indices_count: u32,
}
struct SimpleMaterial {
albedo: TexturePlan,
normal: Option<TexturePlan>,
specular: Option<TexturePlan>,
}
struct SimpleRenderPlan {
pipeline: wgpu::RenderPipeline,
clients: Kt<SimpleMesh,Kt<SimpleMaterial,Affine3A>>
}
pub struct State {
renderer: Renderer,
controller: Controller,
window: Arc<Window>,
render_pipeline1: wgpu::RenderPipeline,
render_pipeline2: wgpu::RenderPipeline,
other_pipeline: bool,
diffuse_bind_group: wgpu::BindGroup,
sky: wgpu::Color,
}
@ -47,7 +182,7 @@ impl State {
display: None,
});
let surface = instance.create_surface(window.clone()).unwrap();
let surface = instance.create_surface(window.clone())?;
let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions {
@ -95,22 +230,205 @@ impl State {
desired_maximum_frame_latency: 2,
};
let diffuse_bytes = include_bytes!("assets/test.png");
let diffuse_image = image::load_from_memory(diffuse_bytes)?;
let diffuse_rgba = diffuse_image.to_rgba8();
use image::GenericImageView;
let dimensions = diffuse_image.dimensions();
println!("{:?}",dimensions);
let texture_size = wgpu::Extent3d {
width: dimensions.0,
height: dimensions.1,
// All textures are stored as 3D, we represent our 2D texture
// by setting depth to 1.
depth_or_array_layers: 1,
};
let diffuse_texture = device.create_texture(
&wgpu::TextureDescriptor {
size: texture_size,
mip_level_count: 1, // We'll talk about this a little later
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
// Most images are stored using sRGB, so we need to reflect that here.
format: wgpu::TextureFormat::Rgba8UnormSrgb,
// TEXTURE_BINDING tells wgpu that we want to use this texture in shaders
// COPY_DST means that we want to copy data to this texture
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
label: Some("diffuse_texture"),
// This is the same as with the SurfaceConfig. It
// specifies what texture formats can be used to
// create TextureViews for this texture. The base
// texture format (Rgba8UnormSrgb in this case) is
// always supported. Note that using a different
// texture format is not supported on the WebGL2
// backend.
view_formats: &[],
}
);
queue.write_texture(
// Tells wgpu where to copy the pixel data
wgpu::TexelCopyTextureInfo {
texture: &diffuse_texture,
mip_level: 0,
origin: wgpu::Origin3d::ZERO,
aspect: wgpu::TextureAspect::All,
},
// The actual pixel data
&diffuse_rgba,
// The layout of the texture
wgpu::TexelCopyBufferLayout {
offset: 0,
bytes_per_row: Some(4 * dimensions.0),
rows_per_image: Some(dimensions.1),
},
texture_size,
);
let diffuse_texture_view = diffuse_texture.create_view(&wgpu::TextureViewDescriptor::default());
let diffuse_sampler = device.create_sampler(&wgpu::SamplerDescriptor {
address_mode_u: wgpu::AddressMode::Repeat,
address_mode_v: wgpu::AddressMode::Repeat,
address_mode_w: wgpu::AddressMode::Repeat,
mag_filter: wgpu::FilterMode::Linear,
min_filter: wgpu::FilterMode::Linear,
mipmap_filter: wgpu::MipmapFilterMode::Nearest,
..Default::default()
});
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"),
});
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_sampler),
}
],
label: Some("diffuse_bind_group"),
}
);
let camera = Camera::new(&window);
let camera_buffer = device.create_buffer_init(
&wgpu::util::BufferInitDescriptor {
label: Some("Camera Buffer"),
contents: bytemuck::cast_slice(&[camera.view()]),
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
}
);
let camera_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("camera_bind_group_layout"),
});
let camera_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
layout: &camera_bind_group_layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: camera_buffer.as_entire_binding(),
}
],
label: Some("camera_bind_group"),
});
let vertex_buffer = device.create_buffer_init(
&wgpu::util::BufferInitDescriptor {
label: Some("Vertex Buffer"),
contents: bytemuck::cast_slice(VERTICES),
usage: wgpu::BufferUsages::VERTEX,
}
);
let index_buffer = device.create_buffer_init(
&wgpu::util::BufferInitDescriptor {
label: Some("Index Buffer"),
contents: bytemuck::cast_slice(INDICES),
usage: wgpu::BufferUsages::INDEX,
}
);
let num_indices = INDICES.len() as u32;
let shader1 = device.create_shader_module(wgpu::include_wgsl!("assets/shader.wgsl"));
let render_pipeline_layout1 =
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("Render Pipeline Layout"),
bind_group_layouts: &[],
bind_group_layouts: &[
Some(&texture_bind_group_layout),
Some(&camera_bind_group_layout),
],
immediate_size: 0,
});
/*let water_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Water Pipeline"),
layout: Some(&water_pipeline_layout),
vertex: wgpu::VertexState {
module: &shader1,
entry_point: Some("vs_main"),
buffers: &[
],
compilation_options: wgpu::PipelineCompilationOptions::default();
}
});*/
let render_pipeline1 = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Render Pipeline"),
layout: Some(&render_pipeline_layout1),
vertex: wgpu::VertexState {
module: &shader1,
entry_point: Some("vs_main"), // 1.
buffers: &[], // 2.
entry_point: Some("vs_main"),
buffers: &[
Vertex::desc(),
],
compilation_options: wgpu::PipelineCompilationOptions::default(),
},
fragment: Some(wgpu::FragmentState {
@ -147,74 +465,28 @@ impl State {
cache: None, // 6.
});
let shader2 = device.create_shader_module(wgpu::include_wgsl!("assets/shader2.wgsl"));
let render_pipeline_layout2 =
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("Render Pipeline Layout"),
bind_group_layouts: &[],
immediate_size: 0,
});
let render_pipeline2 = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Render Pipeline"),
layout: Some(&render_pipeline_layout2),
vertex: wgpu::VertexState {
module: &shader2,
entry_point: Some("vs_main"), // 1.
buffers: &[], // 2.
compilation_options: wgpu::PipelineCompilationOptions::default(),
},
fragment: Some(wgpu::FragmentState {
// 3.
module: &shader2,
entry_point: Some("fs_main"),
targets: &[Some(wgpu::ColorTargetState {
// 4.
format: config.format,
blend: Some(wgpu::BlendState::REPLACE),
write_mask: wgpu::ColorWrites::ALL,
})],
compilation_options: wgpu::PipelineCompilationOptions::default(),
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList, // 1.
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw, // 2.
cull_mode: Some(wgpu::Face::Back),
// Setting this to anything other than Fill requires Features::NON_FILL_POLYGON_MODE
polygon_mode: wgpu::PolygonMode::Fill,
// Requires Features::DEPTH_CLIP_CONTROL
unclipped_depth: false,
// Requires Features::CONSERVATIVE_RASTERIZATION
conservative: false,
},
depth_stencil: None, // 1.
multisample: wgpu::MultisampleState {
count: 1, // 2.
mask: !0, // 3.
alpha_to_coverage_enabled: false, // 4.
},
multiview_mask: None, // 5.
cache: None, // 6.
});
Ok(Self {
surface,
camera_buffer,
camera_bind_group,
diffuse_bind_group,
index_buffer,
vertex_buffer,
controller: Controller::new(),
device,
queue,
config,
is_surface_configured: false,
window,
render_pipeline1,
render_pipeline2,
other_pipeline: false,
num_indices,
render_pipeline: render_pipeline1,
sky: wgpu::Color {
r: 0.1,
g: 0.2,
b: 0.3,
a: 1.0,
},
camera,
})
}
@ -224,6 +496,7 @@ impl State {
self.config.width = width.min(max);
self.config.height = height.min(max);
self.surface.configure(&self.device, &self.config);
self.camera.resize(&self.window);
self.is_surface_configured = true;
}
}
@ -288,12 +561,47 @@ impl State {
multiview_mask: None,
});
if self.other_pipeline {
render_pass.set_pipeline(&self.render_pipeline1);
} else {
render_pass.set_pipeline(&self.render_pipeline2);
let mut movement = Vec3::new(0.0,0.0,0.0);
let pressed = |keycode: KeyCode| {
if let Some(true) = self.controller.keys.get(&keycode) {
true
} else {
false
}
};
if pressed(KeyCode::KeyA) {
movement.x -= 1.0;
}
render_pass.draw(0..3, 0..1); // 3.
if pressed(KeyCode::KeyD) {
movement.x += 1.0;
}
if pressed(KeyCode::KeyW) {
movement.z += 1.0;
}
if pressed(KeyCode::KeyS) {
movement.z -= 1.0;
}
if pressed(KeyCode::KeyE) {
movement.y += 1.0;
}
if pressed(KeyCode::KeyQ) {
movement.y -= 1.0;
}
println!("{:?} {:?} {:?}",movement,self.camera.frame.translation,self.camera.frame.matrix3.to_euler(EulerRot::YXZ));
self.camera.control(movement * 0.1);
self.queue.write_buffer(&self.camera_buffer,0,bytemuck::cast_slice(&[self.camera.view()]));
render_pass.set_pipeline(&self.render_pipeline);
render_pass.set_bind_group(1, &self.camera_bind_group, &[]);
render_pass.set_bind_group(0, &self.diffuse_bind_group, &[]);
render_pass.set_vertex_buffer(0, self.vertex_buffer.slice(..));
render_pass.set_index_buffer(self.index_buffer.slice(..), wgpu::IndexFormat::Uint16);
render_pass.draw_indexed(0..self.num_indices, 0, 0..1);
}
// submit will accept anything that implements IntoIter
@ -306,11 +614,13 @@ impl State {
fn handle_key(&mut self, event_loop: &ActiveEventLoop, code: KeyCode, is_pressed: bool) {
match (code, is_pressed) {
(KeyCode::Escape, true) => event_loop.exit(),
(KeyCode::Space, true) => {
self.other_pipeline = !self.other_pipeline;
(KeyCode::Space, true) => {},
(KeyCode::KeyR, true) => {
self.camera.frame = Affine3A::IDENTITY
}
_ => {}
}
self.controller.keys.insert(code, is_pressed);
}
fn handle_mouse_moved(&mut self, position: PhysicalPosition<f64>) {
@ -319,7 +629,15 @@ impl State {
g: position.x / 1000.0,
b: position.y / 1000.0,
a: 1.0,
};
if let Some(true) = self.controller.buttons.get(&MouseButton::Right) {
self.camera.rotate(position.x as f32 - self.controller.mouse.x, position.y as f32 - self.controller.mouse.y);
}
self.controller.mouse = Vec2::new(position.x as f32, position.y as f32);
}
fn handle_mouse_button(&mut self, button: MouseButton, state: ElementState ) {
self.controller.buttons.insert(button,state.is_pressed());
}
}
@ -428,6 +746,7 @@ impl ApplicationHandler<State> for App {
}
}
}
WindowEvent::MouseInput { button, state: element, .. } => state.handle_mouse_button(button,element),
WindowEvent::CursorMoved { position: pos, .. } => state.handle_mouse_moved(pos),
WindowEvent::KeyboardInput {
event:

File diff suppressed because it is too large Load diff

108
src/lang/src/gc.rs Normal file
View file

@ -0,0 +1,108 @@
use std::alloc::{alloc, dealloc, Layout};
use std::any::Any;
use std::cell::{Ref, RefCell, RefMut};
use std::fmt::Debug;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
#[derive(Debug)]
pub struct Gc<T: ?Sized + Traverse> {
it: *mut RefCell<Header<T>>
}
impl<T: ?Sized + Traverse> Clone for Gc<T> {
fn clone(&self) -> Self {
Gc { it: self.it }
}
}
impl<T: ?Sized + Traverse> Traverse for Gc<T> {
fn traverse(&self) {
self.borrow().traverse()
}
}
impl<T: ?Sized + Traverse> PartialEq for Gc<T> {
fn eq(&self, other: &Gc<T>) -> bool {
self.it == other.it
}
}
impl<T: ?Sized + Traverse> Gc<T> {
pub(crate) fn borrow(&self) -> impl Deref<Target=T> {
Ref::map(unsafe { // ???
(*self.it).borrow()
},|it| &it.data)
}
pub(crate) fn borrow_mut(&self) -> impl DerefMut<Target=T> {
RefMut::map(unsafe {
(*self.it).borrow_mut()
},|it| &mut it.data)
}
}
#[derive(Clone, Debug, Copy)]
enum Color {
White,
Black,
}
#[repr(C)] // Trying to access everything but `item: T` while not knowing what T is...
struct Header<T: ?Sized + Traverse> {
layout: Layout,
color: Color, // NOT for incremental tri-color right now; white == mark-free, black == mark-keep
data: T
}
pub struct Allocator {
objects: Vec<Option<*mut RefCell<Header<dyn Traverse>>>>,
}
impl Allocator {
pub fn new() -> Allocator {
Allocator {
objects: Vec::new(),
}
}
pub fn alloc<T: Traverse + 'static>(&mut self, it: T) -> Gc<T> {
let layout = Layout::new::<RefCell<Header<T>>>();
let pointer = unsafe { alloc(layout) as *mut RefCell<Header<T>> };
let mut header = unsafe { pointer.as_mut() }.unwrap().borrow_mut();
header.layout = layout;
header.color = Color::Black;
header.data = it;
self.objects.push(Some(pointer as *mut RefCell<Header<dyn Traverse>>));
Gc {
it: pointer,
}
}
fn mark_white(&mut self) {
for i in 0..self.objects.len() {
if let Some(object) = self.objects[i] {
unsafe { (*object).borrow_mut().color = Color::White };
}
}
}
fn collect(&mut self) {
self.objects.retain(|object| {
if let Some(object) = object {
let header = unsafe { (**object).borrow_mut() };
match header.color {
Color::White => {
unsafe { dealloc(*object as *mut u8,header.layout); }
true
}
Color::Black => false
}
} else {
false
}
});
}
}
pub trait Traverse: Any + Debug {
fn traverse(&self) { // mark or grey
()
}
}

48
src/lang/src/table.rs Normal file
View file

@ -0,0 +1,48 @@
use std::alloc::{alloc, Layout};
use std::collections::HashMap;
use std::ptr::null_mut;
use crate::gc::{Gc, Traverse};
use crate::Value;
#[derive(Debug, Clone)]
pub struct Table {
table: (*mut [(Value, Value)],usize,usize),
array: (*mut [Value],usize,usize),
meta: Option<Gc<Table>>
}
impl Traverse for Table {
fn traverse(&self) {
unsafe {
if let Some(table) = self.table.0.as_ref() {
for (index,item) in table.iter() {
if !matches!(index,Value::Nil) {
index.traverse();
item.traverse();
}
}
}
if let Some(array) = self.array.0.as_ref() {
for item in array.iter() {
item.traverse();
}
}
}
}
}
impl Table {
pub fn set(index: Value, item: Value) {
}
pub fn get(index: Value) {
}
pub fn new() -> Self {
Table {
table: (null_mut::<[(Value,Value)]>().into(),0,0),
array: (null_mut().into(),0,0),
meta: None
}
}
}

View file

@ -1,3 +1,2 @@
#![recursion_limit = "256"]
pub mod engine;
pub mod lang;
pub mod engine;

View file

@ -3,6 +3,5 @@
use game::*;
fn main() {
//engine::run().unwrap();
engine::run().unwrap();
}