mirror of
https://github.com/aljazceru/notedeck.git
synced 2025-12-18 09:04:21 +01:00
evolve dave into a swarm
Signed-off-by: William Casarin <jb55@jb55.com>
This commit is contained in:
@@ -58,11 +58,65 @@ fn matrix_multiply(a: &[f32; 16], b: &[f32; 16]) -> [f32; 16] {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn lerp3(a: [f32; 3], b: [f32; 3], t: f32) -> [f32; 3] {
|
||||||
|
[
|
||||||
|
a[0] + (b[0] - a[0]) * t,
|
||||||
|
a[1] + (b[1] - a[1]) * t,
|
||||||
|
a[2] + (b[2] - a[2]) * t,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_dave_instances(instance_count: u32) -> Vec<mesh::Instance> {
|
||||||
|
let mut rng = rand::rng();
|
||||||
|
let mut instances = Vec::with_capacity(instance_count as usize);
|
||||||
|
|
||||||
|
// Logo gradient endpoints (0–1 range)
|
||||||
|
const C0: [f32; 3] = [53.0 / 255.0, 77.0 / 255.0, 235.0 / 255.0]; // rgb(53, 77, 235)
|
||||||
|
const C1: [f32; 3] = [229.0 / 255.0, 20.0 / 255.0, 205.0 / 255.0]; // rgb(229, 20, 205)
|
||||||
|
let golden_angle = std::f32::consts::PI * (3.0 - 5.0_f32.sqrt());
|
||||||
|
|
||||||
|
for i in 0..instance_count {
|
||||||
|
let i_f = (i as f32) + 0.5;
|
||||||
|
let n = instance_count as f32;
|
||||||
|
|
||||||
|
// Fibonacci sphere (unit directions)
|
||||||
|
let z = 1.0 - (2.0 * i_f) / n;
|
||||||
|
let r = (1.0 - z * z).sqrt();
|
||||||
|
let theta = golden_angle * i_f;
|
||||||
|
|
||||||
|
// Use base_pos as *direction*; shader will normalize/scale anyway
|
||||||
|
let base_pos = [r * theta.cos(), z, r * theta.sin()];
|
||||||
|
|
||||||
|
let scale = 0.03;
|
||||||
|
|
||||||
|
//let scale = scale + scale_var + rng.random::<f32>() * scale; // slightly smaller cubes
|
||||||
|
let seed = rng.random::<f32>() * 1000.0;
|
||||||
|
|
||||||
|
// damus logo gradient
|
||||||
|
let t_base = (z + 1.0) * 0.5; // 0..1
|
||||||
|
let t_jitter = (rng.random::<f32>() - 0.5) * 0.06; // ±0.03
|
||||||
|
let t = (t_base + t_jitter).clamp(0.0, 1.0);
|
||||||
|
let color = lerp3(C0, C1, t);
|
||||||
|
|
||||||
|
instances.push(mesh::Instance {
|
||||||
|
base_pos,
|
||||||
|
scale,
|
||||||
|
seed,
|
||||||
|
color,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
instances
|
||||||
|
}
|
||||||
|
|
||||||
impl DaveAvatar {
|
impl DaveAvatar {
|
||||||
pub fn new(wgpu_render_state: &egui_wgpu::RenderState) -> Self {
|
pub fn new(wgpu_render_state: &egui_wgpu::RenderState) -> Self {
|
||||||
let device = &wgpu_render_state.device;
|
|
||||||
const BINDING_SIZE: u64 = 256;
|
const BINDING_SIZE: u64 = 256;
|
||||||
|
|
||||||
|
let device = &wgpu_render_state.device;
|
||||||
|
let instance_count: u32 = 256;
|
||||||
|
let instances = generate_dave_instances(instance_count);
|
||||||
|
|
||||||
// Create shader module with improved shader code
|
// Create shader module with improved shader code
|
||||||
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||||
label: Some("cube_shader"),
|
label: Some("cube_shader"),
|
||||||
@@ -115,6 +169,12 @@ impl DaveAvatar {
|
|||||||
usage: wgpu::BufferUsages::VERTEX,
|
usage: wgpu::BufferUsages::VERTEX,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let instance_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
|
label: Some("cube_instances"),
|
||||||
|
contents: bytemuck::cast_slice(&instances),
|
||||||
|
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
|
||||||
|
});
|
||||||
|
|
||||||
let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
label: Some("cube_indices"),
|
label: Some("cube_indices"),
|
||||||
contents: bytemuck::cast_slice(&mesh::CUBE_INDICES),
|
contents: bytemuck::cast_slice(&mesh::CUBE_INDICES),
|
||||||
@@ -128,7 +188,7 @@ impl DaveAvatar {
|
|||||||
vertex: wgpu::VertexState {
|
vertex: wgpu::VertexState {
|
||||||
module: &shader,
|
module: &shader,
|
||||||
entry_point: Some("vs_main"),
|
entry_point: Some("vs_main"),
|
||||||
buffers: &[mesh::Vertex::LAYOUT],
|
buffers: &[mesh::Vertex::LAYOUT, mesh::Instance::LAYOUT],
|
||||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||||
},
|
},
|
||||||
fragment: Some(wgpu::FragmentState {
|
fragment: Some(wgpu::FragmentState {
|
||||||
@@ -171,8 +231,10 @@ impl DaveAvatar {
|
|||||||
pipeline,
|
pipeline,
|
||||||
bind_group,
|
bind_group,
|
||||||
uniform_buffer,
|
uniform_buffer,
|
||||||
|
instance_buffer,
|
||||||
vertex_buffer,
|
vertex_buffer,
|
||||||
index_buffer,
|
index_buffer,
|
||||||
|
instance_count,
|
||||||
});
|
});
|
||||||
|
|
||||||
let initial_rot = {
|
let initial_rot = {
|
||||||
@@ -182,6 +244,7 @@ impl DaveAvatar {
|
|||||||
// Apply rotations (order matters)
|
// Apply rotations (order matters)
|
||||||
y_rotation.multiply(&x_rotation)
|
y_rotation.multiply(&x_rotation)
|
||||||
};
|
};
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
rotation: initial_rot,
|
rotation: initial_rot,
|
||||||
rot_dir: Vec3::new(0.0, 0.0, 0.0),
|
rot_dir: Vec3::new(0.0, 0.0, 0.0),
|
||||||
@@ -271,10 +334,10 @@ impl DaveAvatar {
|
|||||||
let projection = perspective_matrix(std::f32::consts::PI / 4.0, aspect, 0.1, 100.0);
|
let projection = perspective_matrix(std::f32::consts::PI / 4.0, aspect, 0.1, 100.0);
|
||||||
|
|
||||||
// Create view matrix (move camera back a bit)
|
// Create view matrix (move camera back a bit)
|
||||||
let camera_pos = [0.0, 0.0, 3.0, 0.0];
|
let camera_pos = [0.0, 0.0, 1.5];
|
||||||
|
|
||||||
// Right-handed look-at at origin; view is a translate by -camera_pos
|
// Right-handed look-at at origin; view is a translate by -camera_pos
|
||||||
let [cx, cy, cz, _] = camera_pos;
|
let [cx, cy, cz] = camera_pos;
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
let view = [
|
let view = [
|
||||||
@@ -285,6 +348,11 @@ impl DaveAvatar {
|
|||||||
];
|
];
|
||||||
|
|
||||||
let view_proj = matrix_multiply(&projection, &view);
|
let view_proj = matrix_multiply(&projection, &view);
|
||||||
|
let is_light = if ui.ctx().theme() == egui::Theme::Light {
|
||||||
|
1.0
|
||||||
|
} else {
|
||||||
|
-1.0
|
||||||
|
};
|
||||||
|
|
||||||
// Add paint callback
|
// Add paint callback
|
||||||
ui.painter().add(egui_wgpu::Callback::new_paint_callback(
|
ui.painter().add(egui_wgpu::Callback::new_paint_callback(
|
||||||
@@ -293,6 +361,8 @@ impl DaveAvatar {
|
|||||||
view_proj,
|
view_proj,
|
||||||
model,
|
model,
|
||||||
camera_pos,
|
camera_pos,
|
||||||
|
time: ui.ctx().input(|i| i.time as f32),
|
||||||
|
is_light: [is_light, 0.0, 0.0, 0.0],
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
|
|
||||||
@@ -306,7 +376,9 @@ impl DaveAvatar {
|
|||||||
struct GpuData {
|
struct GpuData {
|
||||||
view_proj: [f32; 16], // Model-View-Projection matrix
|
view_proj: [f32; 16], // Model-View-Projection matrix
|
||||||
model: [f32; 16], // Model matrix for lighting calculations
|
model: [f32; 16], // Model matrix for lighting calculations
|
||||||
camera_pos: [f32; 4], // xyz + pad
|
camera_pos: [f32; 3], // xyz
|
||||||
|
time: f32,
|
||||||
|
is_light: [f32; 4],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl egui_wgpu::CallbackTrait for GpuData {
|
impl egui_wgpu::CallbackTrait for GpuData {
|
||||||
@@ -337,8 +409,13 @@ impl egui_wgpu::CallbackTrait for GpuData {
|
|||||||
render_pass.set_pipeline(&resources.pipeline);
|
render_pass.set_pipeline(&resources.pipeline);
|
||||||
render_pass.set_bind_group(0, &resources.bind_group, &[]);
|
render_pass.set_bind_group(0, &resources.bind_group, &[]);
|
||||||
render_pass.set_vertex_buffer(0, resources.vertex_buffer.slice(..));
|
render_pass.set_vertex_buffer(0, resources.vertex_buffer.slice(..));
|
||||||
|
render_pass.set_vertex_buffer(1, resources.instance_buffer.slice(..));
|
||||||
render_pass.set_index_buffer(resources.index_buffer.slice(..), wgpu::IndexFormat::Uint16);
|
render_pass.set_index_buffer(resources.index_buffer.slice(..), wgpu::IndexFormat::Uint16);
|
||||||
render_pass.draw_indexed(0..mesh::CUBE_INDICES.len() as u32, 0, 0..1); // 36 vertices for a cube (6 faces * 2 triangles * 3 vertices)
|
render_pass.draw_indexed(
|
||||||
|
0..mesh::CUBE_INDICES.len() as u32,
|
||||||
|
0,
|
||||||
|
0..resources.instance_count,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,6 +424,8 @@ struct CubeRenderResources {
|
|||||||
pipeline: wgpu::RenderPipeline,
|
pipeline: wgpu::RenderPipeline,
|
||||||
bind_group: wgpu::BindGroup,
|
bind_group: wgpu::BindGroup,
|
||||||
uniform_buffer: wgpu::Buffer,
|
uniform_buffer: wgpu::Buffer,
|
||||||
|
instance_buffer: wgpu::Buffer,
|
||||||
vertex_buffer: wgpu::Buffer,
|
vertex_buffer: wgpu::Buffer,
|
||||||
index_buffer: wgpu::Buffer,
|
index_buffer: wgpu::Buffer,
|
||||||
|
instance_count: u32,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
|
|
||||||
struct Uniforms {
|
struct Uniforms {
|
||||||
view_proj: mat4x4<f32>,
|
view_proj: mat4x4<f32>,
|
||||||
model: mat4x4<f32>,
|
model: mat4x4<f32>,
|
||||||
camera_pos: vec4<f32>, // world-space camera position
|
camera_pos: vec3<f32>,
|
||||||
|
time: f32,
|
||||||
|
is_light: vec4<f32>,
|
||||||
};
|
};
|
||||||
|
|
||||||
@group(0) @binding(0)
|
@group(0) @binding(0)
|
||||||
@@ -12,40 +13,85 @@ struct VSOut {
|
|||||||
@builtin(position) position: vec4<f32>,
|
@builtin(position) position: vec4<f32>,
|
||||||
@location(0) normal: vec3<f32>,
|
@location(0) normal: vec3<f32>,
|
||||||
@location(1) world_pos: vec3<f32>,
|
@location(1) world_pos: vec3<f32>,
|
||||||
|
@location(2) color: vec3<f32>,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Vertex inputs
|
||||||
@vertex
|
@vertex
|
||||||
fn vs_main(
|
fn vs_main(
|
||||||
@location(0) in_pos: vec3<f32>,
|
@location(0) in_pos: vec3<f32>,
|
||||||
@location(1) in_normal: vec3<f32>
|
@location(1) in_normal: vec3<f32>,
|
||||||
|
@location(2) base_pos: vec3<f32>,
|
||||||
|
@location(3) scale: f32,
|
||||||
|
@location(4) seed: f32,
|
||||||
|
@location(5) color: vec3<f32>,
|
||||||
) -> VSOut {
|
) -> VSOut {
|
||||||
var out: VSOut;
|
var out: VSOut;
|
||||||
let world = uniforms.model * vec4<f32>(in_pos, 1.0);
|
|
||||||
|
let t = uniforms.time;
|
||||||
|
|
||||||
|
// --- Coherent spherical layout ---
|
||||||
|
let dir = normalize(base_pos + vec3<f32>(1e-6, 0.0, 0.0)); // avoid NaN if zero
|
||||||
|
let radius = 0.4;
|
||||||
|
|
||||||
|
// Gentle, coherent drift so it breathes
|
||||||
|
let drift = vec3<f32>(
|
||||||
|
0.06 * sin(0.9 * t + seed * 1.3),
|
||||||
|
0.05 * sin(1.1 * t + seed * 2.1),
|
||||||
|
0.06 * cos(0.7 * t + seed * 0.7)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Final instance position on/near the sphere
|
||||||
|
//let loose = 0.2 * base_pos + drift;
|
||||||
|
let tight = dir * radius + drift;
|
||||||
|
//let tight = dir * radius;
|
||||||
|
//let coherence = 0.8; // [0..1], or pass as a uniform
|
||||||
|
//let pos_ws = mix(loose, tight, coherence);
|
||||||
|
let pos_ws = tight;
|
||||||
|
|
||||||
|
// --- Orient cube so its local +Z points outward (along dir) ---
|
||||||
|
// Build a stable tangent basis
|
||||||
|
var up = vec3<f32>(0.0, 1.0, 0.0);
|
||||||
|
if (abs(dot(dir, up)) > 0.92) {
|
||||||
|
up = vec3<f32>(1.0, 0.0, 0.0);
|
||||||
|
}
|
||||||
|
let tangent = normalize(cross(up, dir));
|
||||||
|
let bitangent = cross(dir, tangent);
|
||||||
|
|
||||||
|
// Optional tiny spin around outward axis for sparkle
|
||||||
|
let spin = 0.9 * t + seed * 0.9;
|
||||||
|
let cs = cos(spin);
|
||||||
|
let sn = sin(spin);
|
||||||
|
let rot_tangent = cs * tangent + sn * bitangent;
|
||||||
|
let rot_bitangent = -sn * tangent + cs * bitangent;
|
||||||
|
|
||||||
|
// Rotation matrix whose columns are the local basis
|
||||||
|
let R = mat3x3<f32>(rot_tangent, rot_bitangent, dir);
|
||||||
|
|
||||||
|
// Scale + orient local vertex + place at spherical position
|
||||||
|
let local = R * (in_pos * scale);
|
||||||
|
let world_vec4 = uniforms.model * vec4<f32>(local, 1.0);
|
||||||
|
let world = world_vec4 + vec4<f32>(pos_ws, 0.0);
|
||||||
|
|
||||||
out.position = uniforms.view_proj * world;
|
out.position = uniforms.view_proj * world;
|
||||||
|
|
||||||
// normal = (model rotation) * in_normal
|
// Normal from model rotation only (ignoring per-instance rotation for now)
|
||||||
let nmat = mat3x3<f32>(
|
let nmat = mat3x3<f32>(
|
||||||
uniforms.model[0].xyz,
|
uniforms.model[0].xyz,
|
||||||
uniforms.model[1].xyz,
|
uniforms.model[1].xyz,
|
||||||
uniforms.model[2].xyz
|
uniforms.model[2].xyz
|
||||||
);
|
);
|
||||||
//out.normal = normalize(transpose(inverse(nmat)) * in_normal);
|
|
||||||
out.normal = normalize(nmat * in_normal);
|
out.normal = normalize(nmat * in_normal);
|
||||||
out.world_pos = world.xyz;
|
out.world_pos = world.xyz;
|
||||||
|
out.color = color;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@fragment
|
|
||||||
fn fs_main_debug(in: VSOut) -> @location(0) vec4<f32> {
|
|
||||||
let g = normalize(cross(dpdx(in.world_pos), dpdy(in.world_pos)));
|
|
||||||
let n = normalize(in.normal);
|
|
||||||
let shown = 0.5 * (n + vec3<f32>(1.0,1.0,1.0));
|
|
||||||
return vec4<f32>(shown, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@fragment
|
@fragment
|
||||||
fn fs_main(in: VSOut) -> @location(0) vec4<f32> {
|
fn fs_main(in: VSOut) -> @location(0) vec4<f32> {
|
||||||
let material_color = vec3<f32>(1.0, 1.0, 1.0);
|
// Same lighting as you had, but tint by per-instance color
|
||||||
|
let material_color = in.color;
|
||||||
|
|
||||||
let ambient_strength = 0.2;
|
let ambient_strength = 0.2;
|
||||||
let diffuse_strength = 0.7;
|
let diffuse_strength = 0.7;
|
||||||
let specular_strength = 0.2;
|
let specular_strength = 0.2;
|
||||||
@@ -53,20 +99,57 @@ fn fs_main(in: VSOut) -> @location(0) vec4<f32> {
|
|||||||
|
|
||||||
let light_pos = vec3<f32>(2.0, 2.0, 2.0);
|
let light_pos = vec3<f32>(2.0, 2.0, 2.0);
|
||||||
let light_color = vec3<f32>(1.0, 1.0, 1.0);
|
let light_color = vec3<f32>(1.0, 1.0, 1.0);
|
||||||
let view_pos = uniforms.camera_pos.xyz;
|
let view_pos = uniforms.camera_pos;
|
||||||
|
|
||||||
let ambient = ambient_strength * light_color;
|
|
||||||
|
|
||||||
let n = normalize(in.normal);
|
let n = normalize(in.normal);
|
||||||
let l = normalize(light_pos - in.world_pos);
|
let l = normalize(light_pos - in.world_pos);
|
||||||
let diff = max(dot(n, l), 0.0);
|
|
||||||
let diffuse = diffuse_strength * diff * light_color;
|
|
||||||
|
|
||||||
let v = normalize(view_pos - in.world_pos);
|
let v = normalize(view_pos - in.world_pos);
|
||||||
let r = reflect(-l, n);
|
let r = reflect(-l, n);
|
||||||
let spec = pow(max(dot(v, r), 0.0), shininess);
|
|
||||||
let specular = specular_strength * spec * light_color;
|
|
||||||
|
|
||||||
let result = (ambient + diffuse + specular) * material_color;
|
let ambient = ambient_strength * light_color;
|
||||||
return vec4<f32>(result, 1.0);
|
let diffuse = diffuse_strength * max(dot(n, l), 0.0) * light_color;
|
||||||
|
let specular = specular_strength * pow(max(dot(v, r), 0.0), shininess) * light_color;
|
||||||
|
|
||||||
|
let exposure = exp2(1.5);
|
||||||
|
var color = (ambient + diffuse + specular) * material_color;
|
||||||
|
|
||||||
|
// --- Distance-based factor (camera-space distance) ---
|
||||||
|
let dist = length(view_pos - in.world_pos);
|
||||||
|
let FADE_NEAR = 1.0; // start ramping here
|
||||||
|
let FADE_FAR = 2.2; // fully applied by here
|
||||||
|
let fade = smoothstep(FADE_NEAR, FADE_FAR, dist); // 0..1
|
||||||
|
|
||||||
|
// --- Exposure drift with distance (sign flips by mode) ---
|
||||||
|
// Dark mode target exposure at far: lower; Light mode target at far: higher.
|
||||||
|
let min_exp = 1.80; // far-end exposure multiplier in dark mode
|
||||||
|
let max_exp = 1.35; // far-end exposure multiplier in light mode
|
||||||
|
let darker = mix(1.0, min_exp, fade); // darkens with distance
|
||||||
|
let brighter = mix(1.0, max_exp, fade); // brightens with distance
|
||||||
|
let exp_factor = select(darker, brighter, uniforms.is_light.x > 0.0);
|
||||||
|
|
||||||
|
// Apply exposure + tonemap
|
||||||
|
let base_exposure = exp2(1.5);
|
||||||
|
color = aces_fitted(color * base_exposure * exp_factor);
|
||||||
|
|
||||||
|
// --- Optional: fade to background so distant points dissolve away ---
|
||||||
|
// Background: black in dark mode, white in light mode.
|
||||||
|
let bg = select(vec3<f32>(0.0), vec3<f32>(1.0), uniforms.is_light.x > 0.0);
|
||||||
|
// If you want white for BOTH modes instead, use:
|
||||||
|
// let bg = vec3<f32>(1.0);
|
||||||
|
|
||||||
|
color = mix(color, bg, fade);
|
||||||
|
|
||||||
|
return vec4<f32>(color, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ACES-fit tonemap (keeps highlights nicer than Reinhard)
|
||||||
|
fn aces_fitted(x: vec3<f32>) -> vec3<f32> {
|
||||||
|
let a = 2.51;
|
||||||
|
let b = 0.03;
|
||||||
|
let c = 2.43;
|
||||||
|
let d = 0.59;
|
||||||
|
let e = 0.14;
|
||||||
|
return clamp((x * (a * x + b)) / (x * (c * x + d) + e), vec3(0.0), vec3(1.0));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ pub use vec3::Vec3;
|
|||||||
|
|
||||||
mod avatar;
|
mod avatar;
|
||||||
mod config;
|
mod config;
|
||||||
mod mesh;
|
pub(crate) mod mesh;
|
||||||
mod messages;
|
mod messages;
|
||||||
mod quaternion;
|
mod quaternion;
|
||||||
mod tools;
|
mod tools;
|
||||||
@@ -180,6 +180,15 @@ You are an AI agent for the nostr protocol called Dave, created by Damus. nostr
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn ui(&mut self, app_ctx: &mut AppContext, ui: &mut egui::Ui) -> DaveResponse {
|
fn ui(&mut self, app_ctx: &mut AppContext, ui: &mut egui::Ui) -> DaveResponse {
|
||||||
|
/*
|
||||||
|
let rect = ui.available_rect_before_wrap();
|
||||||
|
if let Some(av) = self.avatar.as_mut() {
|
||||||
|
av.render(rect, ui);
|
||||||
|
ui.ctx().request_repaint();
|
||||||
|
}
|
||||||
|
DaveResponse::default()
|
||||||
|
*/
|
||||||
|
|
||||||
DaveUi::new(self.model_config.trial, &self.chat, &mut self.input).ui(
|
DaveUi::new(self.model_config.trial, &self.chat, &mut self.input).ui(
|
||||||
app_ctx,
|
app_ctx,
|
||||||
&mut self.jobs,
|
&mut self.jobs,
|
||||||
|
|||||||
@@ -19,6 +19,29 @@ impl Vertex {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]
|
||||||
|
pub struct Instance {
|
||||||
|
pub base_pos: [f32; 3],
|
||||||
|
pub scale: f32,
|
||||||
|
pub seed: f32,
|
||||||
|
pub color: [f32; 3],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Instance {
|
||||||
|
pub const ATTRS: [wgpu::VertexAttribute; 4] = wgpu::vertex_attr_array![
|
||||||
|
2 => Float32x3, // base_pos
|
||||||
|
3 => Float32, // scale
|
||||||
|
4 => Float32, // seed
|
||||||
|
5 => Float32x3 // color
|
||||||
|
];
|
||||||
|
pub const LAYOUT: wgpu::VertexBufferLayout<'static> = wgpu::VertexBufferLayout {
|
||||||
|
array_stride: std::mem::size_of::<Instance>() as wgpu::BufferAddress,
|
||||||
|
step_mode: wgpu::VertexStepMode::Instance,
|
||||||
|
attributes: &Self::ATTRS,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// 6 faces * 4 verts. Each face has a constant normal.
|
// 6 faces * 4 verts. Each face has a constant normal.
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
pub const CUBE_VERTICES: [Vertex; 24] = [
|
pub const CUBE_VERTICES: [Vertex; 24] = [
|
||||||
|
|||||||
Reference in New Issue
Block a user