tirbofish/dropbear · commit
21162277b96b70d4b80d5fe606164c711a3e4383
changed license from custom DEL 1.2 to MIT OR Apache 2.0. added support for wesl shader compilation (for dropbear only, not for users). also did some resource cleaning up...
start of new branch! this branch will deal with the outline shaders.
Signature present but could not be verified.
Unverified
@@ -1,12 +1,12 @@ [workspace] package.version = "0.1.2" package.edition = "2024" -package.license-file = "LICENSE.md" +package.license = "MIT OR Apache-2.0" package.repository = "https://github.com/4tkbytes/dropbear" package.readme = "README.md" resolver = "3" -members = [ "dropbear-engine", "dropbear_future-queue", "eucalyptus-core", "eucalyptus-editor", "magna-carta", "redback-runtime"] +members = [ "dropbear-engine", "dropbear-shader", "dropbear_future-queue", "eucalyptus-core", "eucalyptus-editor", "magna-carta", "redback-runtime"] [workspace.dependencies] @@ -38,7 +38,6 @@ log = "0.4" log-once = "0.4" model_to_image = "0.1.1" once_cell = "1.21" -open = "5" parking_lot = {version = "0.12", features = ["deadlock_detection"] } rfd = "0.15.4" ron = "0.11" @@ -51,7 +50,6 @@ winit = { version = "0.30", features = [] } zip = "5.1" walkdir = "2.3" rayon = "1.11" -reqwest = { version = "0.11", features = ["stream"] } backtrace = "0.3" gltf = "1" os_info = "3.12" @@ -61,10 +59,8 @@ tree-sitter = "0.22" tree-sitter-kotlin = "0.3.8" libloading = "0.8" indexmap = "2.11" -rand = "0.9" -num_enum = "0.7" sha2 = "0.10" -stdext = "0.3" +wesl = "0.2" [workspace.dependencies.image] version = "0.25" @@ -1,35 +0,0 @@ -dropbear Engine License – Version 1.2 - -Copyright (c) 2025 4tkbytes (tk) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software ("dropbear-engine") and associated components (including eucalyptus-editor, -and redback-runtime), to use, copy, modify, and integrate -them into their own projects, subject to the following conditions: - -1. Attribution - - Any project that uses the engine must give visible credit to "dropbear-engine", - and "eucalyptus-editor" in documentation, credits, - or about sections. - - For redback-runtime, credit must also be given, even if it is renamed per project. - -2. No Rebranding - - You may not distribute the dropbear-engine or the eucalyptus-editor - itself under a different name, or claim ownership of them. - - **Exception:** redback-runtime may be renamed to match the project name if necessary for execution, - provided credit to "redback-runtime" is included. - -3. Derivative Works - - You may create your own projects, libraries, or engines based on the engine. - - These projects may be licensed under any license you choose, as long as they - respect sections 1 and 2 above. - -4. Distribution - - You may distribute modified or unmodified projects built on top of the engine - as long as attribution and no-rebranding rules are followed. - -5. Disclaimer - - THE ENGINE AND ALL COMPONENTS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. - - THE AUTHOR SHALL NOT BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY. - -By using the engine or its components, you agree to abide by this license. @@ -9,6 +9,7 @@ If you might have not realised, all the crates/projects names are after Australi ## Projects - [dropbear-engine](https://github.com/4tkbytes/dropbear/tree/main/dropbear-engine) is the rendering engine that uses wgpu and the main name of the project. +- [dropbear-shader](https://github.com/4tkbytes/dropbear/tree/main/dropbear-shader) contains WESL shaders for users to import - [eucalyptus-editor](https://github.com/4tkbytes/dropbear/tree/main/eucalyptus-editor) is the visual editor used to create games visually, taking inspiration from Unity, Unreal, Roblox Studio and other engines. - [eucalyptus-core](https://github.com/4tkbytes/dropbear/tree/main/eucalyptus-core) is the library used by both `redback-runtime` and `eucalyptus-editor` to share configs and metadata between each other. - [redback-runtime](https://github.com/4tkbytes/dropbear/tree/main/redback-runtime) is the runtime used to load .eupak files and run the game loaded on them. @@ -104,7 +105,7 @@ Yeah, yeah, go ahead and contribute. Make sure it works, and its not spam, and a # Licensing -In the case someone actually makes something with my engine and distributes it, the projects (meaning **dropbear-engine**, -**eucalyptus** and **redback-runtime**) must abide by the license in [LICENSE.md](LICENSE.md). +All projects made in this repository is under the license of MIT or Apache 2.0 depending on your choice. -The **dropbear_future-queue** rust library is available under the `MIT` license, which can be used by anyone. +It is recommended that you give us (the engine) credit, as it allows for more community support. This could be +in the form of a credit scene or in the splash screen. @@ -4,12 +4,14 @@ description = "A game engine made by 4tkbytes. Thats really it..." version.workspace = true edition.workspace = true -license-file.workspace = true +license.workspace = true repository.workspace = true readme.workspace = true [dependencies] dropbear_future-queue = { path = "../dropbear_future-queue" } +dropbear-shader = { path = "../dropbear-shader" } + anyhow.workspace = true app_dirs2.workspace = true bytemuck.workspace = true @@ -36,7 +38,6 @@ rayon.workspace = true backtrace.workspace = true os_info.workspace = true rustc_version_runtime.workspace = true -crossbeam-channel.workspace = true ron.workspace = true [target.'cfg(not(target_os = "android"))'.dependencies] @@ -1,7 +1,7 @@ use crate::{ - State, egui_renderer::EguiRenderer, model::{self, Vertex}, + State, }; use dropbear_future_queue::FutureQueue; use egui::{Context, TextureId}; @@ -10,14 +10,15 @@ use image::GenericImageView; use parking_lot::Mutex; use std::{fs, path::PathBuf, sync::Arc, time::Instant}; use wgpu::{ - BindGroup, BindGroupLayout, Buffer, BufferAddress, BufferUsages, Color, CommandEncoder, - CompareFunction, DepthBiasState, Device, Extent3d, LoadOp, Operations, Queue, RenderPass, - RenderPassDepthStencilAttachment, RenderPipeline, Sampler, ShaderModule, StencilState, - SurfaceConfiguration, TextureDescriptor, TextureFormat, TextureUsages, TextureView, - TextureViewDescriptor, VertexBufferLayout, - util::{BufferInitDescriptor, DeviceExt}, + util::{BufferInitDescriptor, DeviceExt}, BindGroup, BindGroupLayout, Buffer, BufferAddress, BufferUsages, Color, + CommandEncoder, CompareFunction, DepthBiasState, Device, Extent3d, LoadOp, Operations, Queue, + RenderPass, RenderPassDepthStencilAttachment, RenderPipeline, Sampler, + StencilState, SurfaceConfiguration, TextureDescriptor, TextureFormat, TextureUsages, + TextureView, TextureViewDescriptor, + VertexBufferLayout, }; use winit::window::Window; +use crate::shader::Shader; pub const NO_TEXTURE: &[u8] = include_bytes!("../../resources/textures/no-texture.png"); pub const NO_MODEL: &[u8] = include_bytes!("../../resources/models/error.glb"); @@ -242,37 +243,6 @@ impl<'a> RenderContext<'a> { } } -/// A nice little struct that stored basic information about a WGPU shader. -pub struct Shader { - pub label: String, - pub module: ShaderModule, -} - -impl Shader { - pub fn new( - graphics: Arc<SharedGraphicsContext>, - shader_file_contents: &str, - label: Option<&str>, - ) -> Self { - let module = graphics - .device - .create_shader_module(wgpu::ShaderModuleDescriptor { - label, - source: wgpu::ShaderSource::Wgsl(shader_file_contents.into()), - }); - - log::debug!("Created new shader under the label: {:?}", label); - - Self { - label: match label { - Some(label) => label.into(), - None => "shader".into(), - }, - module, - } - } -} - #[derive(Clone)] /// Describes a texture, like an image of some sort. Can be a normal texture on a model or a viewport or depth texture. pub struct Texture { @@ -13,6 +13,7 @@ pub mod resources; pub mod scene; pub mod utils; pub mod colour; +pub mod shader; use app_dirs2::{AppDataType, AppInfo}; use bytemuck::Contiguous; @@ -45,18 +46,19 @@ use winit::{ keyboard::{KeyCode, PhysicalKey}, window::Window, }; +use dropbear_future_queue::FutureQueue; +use log::LevelFilter; +use ron::ser::PrettyConfig; +use serde::{Deserialize, Serialize}; +use winit::event::{DeviceEvent, DeviceId}; use crate::{egui_renderer::EguiRenderer, graphics::Texture}; pub use dropbear_future_queue as future; -use dropbear_future_queue::FutureQueue; pub use gilrs; -use log::LevelFilter; -use ron::ser::PrettyConfig; -use serde::{Deserialize, Serialize}; pub use wgpu; pub use winit; -use winit::event::{DeviceEvent, DeviceId}; + /// The backend information, such as the device, queue, config, surface, renderer, window and more. pub struct State { @@ -2,8 +2,8 @@ use glam::{DMat4, DQuat, DVec3}; use std::fmt::{Display, Formatter}; use std::sync::Arc; use wgpu::{ - BindGroup, BindGroupLayout, Buffer, BufferAddress, CompareFunction, DepthBiasState, - RenderPipeline, StencilState, VertexBufferLayout, util::DeviceExt, + util::DeviceExt, BindGroup, BindGroupLayout, Buffer, BufferAddress, CompareFunction, + DepthBiasState, RenderPipeline, StencilState, VertexBufferLayout, }; use crate::attenuation::{Attenuation, RANGE_50}; @@ -12,9 +12,9 @@ use crate::model::{LazyModel, LazyType}; use crate::{ camera::Camera, entity::Transform, - graphics::Shader, model::{self, Model, Vertex}, }; +use crate::shader::Shader; pub const MAX_LIGHTS: usize = 8; @@ -584,7 +584,7 @@ impl LightManager { camera: &Camera, label: Option<&str>, ) { - use crate::graphics::Shader; + use crate::shader::Shader; let shader = Shader::new(graphics.clone(), shader_contents, label); @@ -0,0 +1,38 @@ +//! Deals with shaders, including WESL shaders +use std::sync::Arc; +use wgpu::ShaderModule; +use crate::graphics::SharedGraphicsContext; + +pub use dropbear_shader as shader_wesl; + +/// A nice little struct that stored basic information about a WGPU shader. +pub struct Shader { + pub label: String, + pub module: ShaderModule, +} + +impl Shader { + /// Creates a new [`ShaderModule`] from its file contents. + pub fn new( + graphics: Arc<SharedGraphicsContext>, + shader_file_contents: &str, + label: Option<&str>, + ) -> Self { + let module = graphics + .device + .create_shader_module(wgpu::ShaderModuleDescriptor { + label, + source: wgpu::ShaderSource::Wgsl(shader_file_contents.into()), + }); + + log::debug!("Created new shader under the label: {:?}", label); + + Self { + label: match label { + Some(label) => label.into(), + None => "shader".into(), + }, + module, + } + } +} @@ -0,0 +1,13 @@ +[package] +name = "dropbear-shader" +version.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true +readme.workspace = true + +[dependencies] +wesl = { workspace = true } + +[build-dependencies] +wesl = { workspace = true, features = ["package"] } @@ -0,0 +1,10 @@ +# dropbear-shader + +This crate is used for shaders created with the WESL language, such as rendering models and generating +mipmaps. It also provides templates for users to create their own shaders for their own +projects with the WESL language. + +## What is WESL? + +WESL (or WebGPU Extension Shader Language) is a shader language that is fully compatible with WGPU shaders, and +adds extension features such as import statements and rust-like #[cfg] functions. @@ -0,0 +1,31 @@ +use std::fs; +use std::path::Path; + +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + + let shader_dir = Path::new("src/shaders"); + + println!("cargo:rerun-if-changed={}", shader_dir.display()); + if let Ok(entries) = fs::read_dir(shader_dir) { + for entry in entries.flatten() { + let path = entry.path(); + if path.is_file() { + println!("cargo:rerun-if-changed={}", path.display()); + } + } + } + + wesl::PkgBuilder::new("dropbear") + .scan_root("src/shaders") + .expect("failed to scan for dropbear wesl shaders") + .validate() + .map_err(|e| eprintln!("{e}")) + .expect("validation error") + .build_artifact() + .expect("failed to build artifact"); + + wesl::Wesl::new("src/shaders").build_artifact(&"package::light".parse().unwrap(), "dropbear_light"); + wesl::Wesl::new("src/shaders").build_artifact(&"package::shader".parse().unwrap(), "dropbear_shader"); + wesl::Wesl::new("src/shaders").build_artifact(&"package::outline".parse().unwrap(), "dropbear_outline"); +} @@ -0,0 +1,7 @@ +use wesl::include_wesl; + +wesl::wesl_pkg!(dropbear); + +pub const LIGHT_SHADER: &str = include_wesl!("dropbear_light"); +pub const SHADER_SHADER: &str = include_wesl!("dropbear_shader"); +pub const OUTLINE_SHADER: &str = include_wesl!("dropbear_outline"); @@ -0,0 +1 @@ +const MAX_LIGHTS: u32 = 8; @@ -0,0 +1,28 @@ +import package::config; + +struct CameraUniform { + view_pos: vec4<f32>, + view_proj: mat4x4<f32>, +}; + +struct OutlineUniform { + outline_width: f32, + outline_color: vec4<f32>, +// _padding: vec3<f32>, +}; + +struct Light { + position: vec4<f32>, + direction: vec4<f32>, // x, y, z, outer_cutoff_angle + color: vec4<f32>, // r, g, b, light_type (0, 1, 2) + constant: f32, + lin: f32, + quadratic: f32, + cutoff: f32, +} + +struct LightArray { + _lights: array<Light, config::MAX_LIGHTS>, + light_count: u32, + ambient_strength: f32, +} @@ -0,0 +1,52 @@ +// Shader for rendering the white cube for lighting (or diff depending on colour) + +import package::input::{ + CameraUniform, + Light, +}; + +@group(0) @binding(0) +var<uniform> camera: CameraUniform; + +@group(1) @binding(0) +var<uniform> light: Light; + +struct InstanceInput { + @location(5) model_matrix_0: vec4<f32>, + @location(6) model_matrix_1: vec4<f32>, + @location(7) model_matrix_2: vec4<f32>, + @location(8) model_matrix_3: vec4<f32>, +} + +struct VertexInput { + @location(0) position: vec3<f32>, +}; + +struct VertexOutput { + @builtin(position) clip_position: vec4<f32>, + @location(0) color: vec3<f32>, +}; + +@vertex +fn vs_main( + model: VertexInput, + instance: InstanceInput, +) -> VertexOutput { + let model_matrix = mat4x4<f32>( + instance.model_matrix_0, + instance.model_matrix_1, + instance.model_matrix_2, + instance.model_matrix_3, + ); + var out: VertexOutput; + out.clip_position = camera.view_proj * model_matrix * vec4<f32>(model.position, 1.0); + out.color = light.color.xyz; + return out; +} + +// Fragment shader + +@fragment +fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> { + return vec4<f32>(in.color, 1.0); +} @@ -0,0 +1,58 @@ +@group(1) @binding(0) +var<uniform> camera: package::input::CameraUniform; + +@group(0) @binding(0) +var<uniform> outline: package::input::OutlineUniform; + +struct InstanceInput { + @location(5) model_matrix_0: vec4<f32>, + @location(6) model_matrix_1: vec4<f32>, + @location(7) model_matrix_2: vec4<f32>, + @location(8) model_matrix_3: vec4<f32>, + + @location(9) normal_matrix_0: vec3<f32>, + @location(10) normal_matrix_1: vec3<f32>, + @location(11) normal_matrix_2: vec3<f32>, +}; + +struct VertexInput { + @location(0) position: vec3<f32>, + @location(1) tex_coords: vec2<f32>, + @location(2) normal: vec3<f32>, +}; + +struct VertexOutput { + @builtin(position) clip_position: vec4<f32>, +}; + +@vertex +fn vs_main( + model: VertexInput, + instance: InstanceInput, +) -> VertexOutput { + let model_matrix = mat4x4<f32>( + instance.model_matrix_0, + instance.model_matrix_1, + instance.model_matrix_2, + instance.model_matrix_3, + ); + let normal_matrix = mat3x3<f32>( + instance.normal_matrix_0, + instance.normal_matrix_1, + instance.normal_matrix_2, + ); + + let world_normal = normalize(normal_matrix * model.normal); + let expanded_position = model.position + model.normal * outline.outline_width; + let world_position = model_matrix * vec4<f32>(expanded_position, 1.0); + + var out: VertexOutput; + out.clip_position = camera.view_proj * world_position; + + return out; +} + +@fragment +fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> { + return outline.outline_color; +} @@ -0,0 +1,192 @@ +// Main shader for standard objects. +import package::config::MAX_LIGHTS; + +import package::input::{ + CameraUniform, + Light, + LightArray, +}; + +@group(1) @binding(0) +var<uniform> camera: CameraUniform; + +@group(2) @binding(0) +var<uniform> light_array: LightArray; + +struct InstanceInput { + @location(5) model_matrix_0: vec4<f32>, + @location(6) model_matrix_1: vec4<f32>, + @location(7) model_matrix_2: vec4<f32>, + @location(8) model_matrix_3: vec4<f32>, + + @location(9) normal_matrix_0: vec3<f32>, + @location(10) normal_matrix_1: vec3<f32>, + @location(11) normal_matrix_2: vec3<f32>, +}; + +struct VertexInput { + @location(0) position: vec3<f32>, + @location(1) tex_coords: vec2<f32>, + @location(2) normal: vec3<f32>, +}; + +struct VertexOutput { + @builtin(position) clip_position: vec4<f32>, + @location(0) tex_coords: vec2<f32>, + @location(1) world_normal: vec3<f32>, + @location(2) world_position: vec3<f32>, +}; + +@vertex +fn vs_main( + model: VertexInput, + instance: InstanceInput, +) -> VertexOutput { + let model_matrix = mat4x4<f32>( + instance.model_matrix_0, + instance.model_matrix_1, + instance.model_matrix_2, + instance.model_matrix_3, + ); + let normal_matrix = mat3x3<f32>( + instance.normal_matrix_0, + instance.normal_matrix_1, + instance.normal_matrix_2, + ); + var out: VertexOutput; + out.tex_coords = model.tex_coords; + out.world_normal = normal_matrix * model.normal; + var world_position: vec4<f32> = model_matrix * vec4<f32>(model.position, 1.0); + out.world_position = world_position.xyz; + out.clip_position = camera.view_proj * world_position; + return out; +} + +@group(0) @binding(0) +var t_diffuse: texture_2d<f32>; +@group(0) @binding(1) +var s_diffuse: sampler; + +fn calculate_light(light: Light, world_pos: vec3<f32>, world_normal: vec3<f32>, view_dir: vec3<f32>) -> vec3<f32> { + let light_dir = normalize(light.position.xyz - world_pos); + + // dihfuse + let diffuse_strength = max(dot(world_normal, light_dir), 0.0); + let diffuse_color = light.color.xyz * diffuse_strength; + + // specular + let half_dir = normalize(view_dir + light_dir); + let specular_strength = pow(max(dot(world_normal, half_dir), 0.0), 32.0); + let specular_color = specular_strength * light.color.xyz; + + return diffuse_color + specular_color; +} + +fn directional_light( + light: Light, + world_normal: vec3<f32>, + view_dir: vec3<f32>, + tex_color: vec3<f32> +) -> vec3<f32> { + let light_dir = normalize(-light.direction.xyz); + + let ambient = light.color.xyz * light_array.ambient_strength * tex_color; + + let diff = max(dot(world_normal, light_dir), 0.0); + let diffuse = light.color.xyz * diff * tex_color; + + let reflect_dir = reflect(-light_dir, world_normal); + let spec = pow(max(dot(view_dir, reflect_dir), 0.0), 32.0); + let specular = light.color.xyz * spec * tex_color; + + return ambient + diffuse + specular; +} + +// https://learnopengl.com/code_viewer_gh.php?code=src/2.lighting/5.2.light_casters_point/5.2.light_casters.fs +// deal with later. current issue: it is showing only yellow and white in point light (weird...) +// note: fixed, forgot to push attenuation values to gpu lol +fn point_light(light: Light, world_pos: vec3<f32>, world_normal: vec3<f32>, view_dir: vec3<f32>, tex_color: vec3<f32>) -> vec3<f32> { + let norm = normalize(world_normal); + let light_dir = normalize(light.position.xyz - world_pos); + let diff = max(dot(norm, light_dir), 0.0); + let diffuse = light.color.xyz * diff * tex_color; + + let shininess = 32.0; + let reflect_dir = reflect(-light_dir, norm); + let spec = pow(max(dot(view_dir, reflect_dir), 0.0), shininess); + let specular = light.color.xyz * spec * tex_color; + + let distance = length(light.position.xyz - world_pos); + let attenuation = 1.0 / (light.constant + (light.lin * distance) + (light.quadratic * (distance * distance))); + + return (diffuse + specular) * attenuation; +} + +fn spot_light(light: Light, world_pos: vec3<f32>, world_normal: vec3<f32>, view_dir: vec3<f32>, tex_color: vec3<f32>) -> vec3<f32> { + let outer_cutoff = light.direction.w; + let ambient = light.color.xyz * light_array.ambient_strength * tex_color; + + let norm = normalize(world_normal); + let light_dir = normalize(light.position.xyz - world_pos); + let diff = max(dot(norm, light_dir), 0.0); + var diffuse = light.color.xyz * diff * tex_color; + + let shininess = 32.0; + let reflect_dir = reflect(-light_dir, norm); + let spec = pow(max(dot(view_dir, reflect_dir), 0.0), shininess); + var specular = light.color.xyz * spec * tex_color; + + let theta = dot(light_dir, normalize(-light.direction.xyz)); + let epsilon = light.cutoff - outer_cutoff; + let intensity = clamp((theta - outer_cutoff) / epsilon, 0.0, 1.0); + + diffuse *= intensity; + specular *= intensity; + + let distance = length(light.position.xyz - world_pos); + let attenuation = 1.0 / (light.constant + (light.lin * distance) + (light.quadratic * (distance * distance))); + + let ambient_attenuated = ambient * attenuation; + let diffuse_attenuated = diffuse * attenuation; + let specular_attenuated = specular * attenuation; + + return ambient_attenuated + diffuse_attenuated + specular_attenuated; +} + +@fragment +fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> { + var tex_color = textureSample(t_diffuse, s_diffuse, in.tex_coords); + if (tex_color.a < 0.1) { + discard; + } + + let view_dir = normalize(camera.view_pos.xyz - in.world_position); + let world_normal = normalize(in.world_normal); + + var final_color = vec3<f32>(0.0); + + var total_ambient = vec3<f32>(0.0); + for (var i: u32 = 0u; i < light_array.light_count; i = i + 1u) { + let light = light_array._lights[i]; + total_ambient += light.color.xyz * light_array.ambient_strength; + } + + for (var i: u32 = 0u; i < light_array.light_count; i = i + 1u) { + let light = light_array._lights[i]; + + // light type is color.w + if light.color.w == 0.0 { + final_color += directional_light(light, world_normal, view_dir, tex_color.xyz); + } else if light.color.w == 1.0 { + // point + final_color += point_light(light, in.world_position, world_normal, view_dir, tex_color.xyz); + } else if light.color.w == 2.0 { + final_color += spot_light(light, in.world_position, world_normal, view_dir, tex_color.xyz); + } + } + + // Combine ambient and lighting + final_color = (total_ambient * tex_color.xyz) + final_color; + + return vec4<f32>(final_color, tex_color.a); +} @@ -2,7 +2,7 @@ name = "eucalyptus-core" version.workspace = true edition.workspace = true -license-file.workspace = true +license.workspace = true repository.workspace = true readme = "README.md" @@ -14,9 +14,6 @@ use std::path::{Path, PathBuf}; use tokio::io::{AsyncBufReadExt, BufReader}; use tokio::process::Command; -// why tf do you exist? oh well :shrug: -pub const TEMPLATE_SCRIPT: &str = include_str!("../../resources/scripting/kotlin/Template.kt"); - /// The target of the script. This can be either a JVM or a native library. #[derive(Default, Clone)] pub enum ScriptTarget { @@ -2,7 +2,7 @@ name = "eucalyptus-editor" version.workspace = true edition.workspace = true -license-file.workspace = true +license.workspace = true repository.workspace = true default-run = "eucalyptus-editor" readme = "README.md" @@ -13,26 +13,26 @@ use crossbeam_channel::Receiver; use dropbear_engine::{ camera::Camera, entity::{AdoptedEntity, Transform}, - graphics::{RenderContext, Shader, SharedGraphicsContext}, + future::FutureHandle, + graphics::{RenderContext, SharedGraphicsContext}, lighting::{Light, LightManager}, - scene::SceneCommand, model::ModelId, - future::FutureHandle, + scene::SceneCommand, }; use egui::{self, Context}; use egui_dock_fork::{DockArea, DockState, NodeIndex, Style}; use eucalyptus_core::{ - fatal, info, states, success, warn, success_without_console, - camera::{CameraComponent, CameraType, DebugCamera}, - window::GRAPHICS_COMMAND, - utils::ViewportMode, + camera::{CameraComponent, CameraType, DebugCamera}, fatal, info, input::InputState, ptr::{GraphicsPtr, InputStatePtr, WorldPtr}, scripting::{BuildStatus, ScriptManager, ScriptTarget}, + states, states::{ - CameraConfig, EditorTab, EntityNode, LightConfig, ModelProperties, PROJECT, SCENES, - SceneEntity, ScriptComponent, WorldLoadingStatus, + CameraConfig, EditorTab, EntityNode, LightConfig, ModelProperties, SceneEntity, ScriptComponent, + WorldLoadingStatus, PROJECT, SCENES, }, - scripting::{BuildStatus, ScriptManager, ScriptTarget}, - ptr::{GraphicsPtr, InputStatePtr, WorldPtr}, - input::InputState + success, + success_without_console, + utils::ViewportMode, + warn, + window::GRAPHICS_COMMAND }; use hecs::{Entity, World}; use parking_lot::Mutex; @@ -49,6 +49,7 @@ use transform_gizmo_egui::{EnumSet, Gizmo, GizmoMode}; use wgpu::{Color, Extent3d, RenderPipeline}; use winit::window::CursorGrabMode; use winit::{keyboard::KeyCode, window::Window}; +use dropbear_engine::shader::Shader; use crate::graphics::OutlineShader; pub struct Editor { @@ -838,9 +839,10 @@ impl Editor { /// /// **Note**: To be ran AFTER [`Editor::load_project_config`] pub fn load_wgpu_nerdy_stuff<'a>(&mut self, graphics: &mut RenderContext<'a>) { + log::debug!("Contents of viewport shader: \n{:#?}", dropbear_engine::shader::shader_wesl::SHADER_SHADER); let shader = Shader::new( graphics.shared.clone(), - include_str!("../../../resources/shaders/shader.wgsl"), + dropbear_engine::shader::shader_wesl::SHADER_SHADER, Some("viewport_shader"), ); @@ -864,16 +866,17 @@ impl Editor { ); self.render_pipeline = Some(pipeline); + log::debug!("Contents of light shader: \n{:#?}", dropbear_engine::shader::shader_wesl::LIGHT_SHADER); self.light_manager.create_render_pipeline( graphics.shared.clone(), - include_str!("../../../resources/shaders/light.wgsl"), + dropbear_engine::shader::shader_wesl::LIGHT_SHADER, camera, Some("Light Pipeline"), ); + log::debug!("Contents of outline shader: \n{:#?}", dropbear_engine::shader::shader_wesl::OUTLINE_SHADER); let outline_shader = OutlineShader::init(graphics.shared.clone(), camera.layout()); self.outline_pipeline = Some(outline_shader); - } else { log_once::warn_once!( "Unable to fetch the query result of camera: {:?}", @@ -2,10 +2,9 @@ use std::sync::Arc; use dropbear_engine::colour::Colour; -use dropbear_engine::graphics::{InstanceRaw, Shader, SharedGraphicsContext, Texture}; +use dropbear_engine::graphics::{InstanceRaw, SharedGraphicsContext, Texture}; use dropbear_engine::model::{ModelVertex, Vertex}; - -pub const OUTLINE_SHADER: &str = include_str!("../../resources/shaders/outline.wgsl"); +use dropbear_engine::shader::Shader; #[repr(C)] #[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] @@ -34,7 +33,7 @@ pub struct OutlineShader { impl OutlineShader { pub fn init(graphics: Arc<SharedGraphicsContext>, camera_layout: &wgpu::BindGroupLayout) -> Self { - let shader = Shader::new(graphics.clone(), OUTLINE_SHADER, Some("outline_shader")); + let shader = Shader::new(graphics.clone(), dropbear_engine::shader::shader_wesl::OUTLINE_SHADER, Some("outline_shader")); log::trace!("Created outline shader"); let bind_group_layout = @@ -2,7 +2,7 @@ name = "magna-carta" version.workspace = true edition.workspace = true -license = "MIT" +license.workspace = true repository.workspace = true readme = "README.md" @@ -11,6 +11,4 @@ anyhow.workspace = true tree-sitter.workspace = true tree-sitter-kotlin.workspace = true clap = { version = "4.0", features = ["derive"] } -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" chrono = "0.4" Binary files a/resources/dependencies/hotswap-agent-2.0.0.jar and /dev/null differ @@ -1,11 +0,0 @@ -import com.dropbear - -class Example(override var engine: DropbearEngine) : RunnableScript { - override fun load() { - TODO("Not yet implemented") - } - - override fun update() { - TODO("Not yet implemented") - } -} @@ -1,61 +0,0 @@ -// Shader for rendering the white cube for lighting (or diff depending on colour) - -struct Camera { - view_pos: vec4<f32>, - view_proj: mat4x4<f32>, -} -@group(0) @binding(0) -var<uniform> camera: Camera; - -struct Light { - position: vec4<f32>, - direction: vec4<f32>, // x, y, z, outer_cutoff_angle - color: vec4<f32>, // r, g, b, light_type (0, 1, 2) - constant: f32, - lin: f32, - quadratic: f32, - cutoff: f32, -} - -@group(1) @binding(0) -var<uniform> light: Light; - -struct InstanceInput { - @location(5) model_matrix_0: vec4<f32>, - @location(6) model_matrix_1: vec4<f32>, - @location(7) model_matrix_2: vec4<f32>, - @location(8) model_matrix_3: vec4<f32>, -} - -struct VertexInput { - @location(0) position: vec3<f32>, -}; - -struct VertexOutput { - @builtin(position) clip_position: vec4<f32>, - @location(0) color: vec3<f32>, -}; - -@vertex -fn vs_main( - model: VertexInput, - instance: InstanceInput, -) -> VertexOutput { - let model_matrix = mat4x4<f32>( - instance.model_matrix_0, - instance.model_matrix_1, - instance.model_matrix_2, - instance.model_matrix_3, - ); - var out: VertexOutput; - out.clip_position = camera.view_proj * model_matrix * vec4<f32>(model.position, 1.0); - out.color = light.color.xyz; - return out; -} - -// Fragment shader - -@fragment -fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> { - return vec4<f32>(in.color, 1.0); -} @@ -1,69 +0,0 @@ -struct CameraUniform { - view_pos: vec4<f32>, - view_proj: mat4x4<f32>, -}; - -@group(1) @binding(0) -var<uniform> camera: CameraUniform; - -struct OutlineUniform { - outline_width: f32, - outline_color: vec4<f32>, -// _padding: vec3<f32>, -}; - -@group(0) @binding(0) -var<uniform> outline: OutlineUniform; - -struct InstanceInput { - @location(5) model_matrix_0: vec4<f32>, - @location(6) model_matrix_1: vec4<f32>, - @location(7) model_matrix_2: vec4<f32>, - @location(8) model_matrix_3: vec4<f32>, - - @location(9) normal_matrix_0: vec3<f32>, - @location(10) normal_matrix_1: vec3<f32>, - @location(11) normal_matrix_2: vec3<f32>, -}; - -struct VertexInput { - @location(0) position: vec3<f32>, - @location(1) tex_coords: vec2<f32>, - @location(2) normal: vec3<f32>, -}; - -struct VertexOutput { - @builtin(position) clip_position: vec4<f32>, -}; - -@vertex -fn vs_main( - model: VertexInput, - instance: InstanceInput, -) -> VertexOutput { - let model_matrix = mat4x4<f32>( - instance.model_matrix_0, - instance.model_matrix_1, - instance.model_matrix_2, - instance.model_matrix_3, - ); - let normal_matrix = mat3x3<f32>( - instance.normal_matrix_0, - instance.normal_matrix_1, - instance.normal_matrix_2, - ); - - let world_normal = normalize(normal_matrix * model.normal); - let expanded_position = model.position + model.normal * outline.outline_width; - let world_position = model_matrix * vec4<f32>(expanded_position, 1.0); - - var out: VertexOutput; - out.clip_position = camera.view_proj * world_position; - - return out; -} - -@fragment -fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> { - return outline.outline_color; -} @@ -1,206 +0,0 @@ -// Main shader for standard objects. -const MAX_LIGHTS: u32 = 8; - -struct CameraUniform { - view_pos: vec4<f32>, - view_proj: mat4x4<f32>, -}; -@group(1) @binding(0) -var<uniform> camera: CameraUniform; - -struct Light { - position: vec4<f32>, // x, y, z, unused - direction: vec4<f32>, // x, y, z, unused - color: vec4<f32>, // r, g, b, light_type (0, 1, 2) - constant: f32, - lin: f32, // linear - quadratic: f32, - cutoff: f32, -} - -struct LightArray { - _lights: array<Light, MAX_LIGHTS>, - light_count: u32, - ambient_strength: f32, -} - -@group(2) @binding(0) -var<uniform> light_array: LightArray; - -struct InstanceInput { - @location(5) model_matrix_0: vec4<f32>, - @location(6) model_matrix_1: vec4<f32>, - @location(7) model_matrix_2: vec4<f32>, - @location(8) model_matrix_3: vec4<f32>, - - @location(9) normal_matrix_0: vec3<f32>, - @location(10) normal_matrix_1: vec3<f32>, - @location(11) normal_matrix_2: vec3<f32>, -}; - -struct VertexInput { - @location(0) position: vec3<f32>, - @location(1) tex_coords: vec2<f32>, - @location(2) normal: vec3<f32>, -}; - -struct VertexOutput { - @builtin(position) clip_position: vec4<f32>, - @location(0) tex_coords: vec2<f32>, - @location(1) world_normal: vec3<f32>, - @location(2) world_position: vec3<f32>, -}; - -@vertex -fn vs_main( - model: VertexInput, - instance: InstanceInput, -) -> VertexOutput { - let model_matrix = mat4x4<f32>( - instance.model_matrix_0, - instance.model_matrix_1, - instance.model_matrix_2, - instance.model_matrix_3, - ); - let normal_matrix = mat3x3<f32>( - instance.normal_matrix_0, - instance.normal_matrix_1, - instance.normal_matrix_2, - ); - var out: VertexOutput; - out.tex_coords = model.tex_coords; - out.world_normal = normal_matrix * model.normal; - var world_position: vec4<f32> = model_matrix * vec4<f32>(model.position, 1.0); - out.world_position = world_position.xyz; - out.clip_position = camera.view_proj * world_position; - return out; -} - -@group(0) @binding(0) -var t_diffuse: texture_2d<f32>; -@group(0) @binding(1) -var s_diffuse: sampler; - -fn calculate_light(light: Light, world_pos: vec3<f32>, world_normal: vec3<f32>, view_dir: vec3<f32>) -> vec3<f32> { - let light_dir = normalize(light.position.xyz - world_pos); - - // dihfuse - let diffuse_strength = max(dot(world_normal, light_dir), 0.0); - let diffuse_color = light.color.xyz * diffuse_strength; - - // specular - let half_dir = normalize(view_dir + light_dir); - let specular_strength = pow(max(dot(world_normal, half_dir), 0.0), 32.0); - let specular_color = specular_strength * light.color.xyz; - - return diffuse_color + specular_color; -} - -fn directional_light( - light: Light, - world_normal: vec3<f32>, - view_dir: vec3<f32>, - tex_color: vec3<f32> -) -> vec3<f32> { - let light_dir = normalize(-light.direction.xyz); - - let ambient = light.color.xyz * light_array.ambient_strength * tex_color; - - let diff = max(dot(world_normal, light_dir), 0.0); - let diffuse = light.color.xyz * diff * tex_color; - - let reflect_dir = reflect(-light_dir, world_normal); - let spec = pow(max(dot(view_dir, reflect_dir), 0.0), 32.0); - let specular = light.color.xyz * spec * tex_color; - - return ambient + diffuse + specular; -} - -// https://learnopengl.com/code_viewer_gh.php?code=src/2.lighting/5.2.light_casters_point/5.2.light_casters.fs -// deal with later. current issue: it is showing only yellow and white in point light (weird...) -// note: fixed, forgot to push attenuation values to gpu lol -fn point_light(light: Light, world_pos: vec3<f32>, world_normal: vec3<f32>, view_dir: vec3<f32>, tex_color: vec3<f32>) -> vec3<f32> { - let norm = normalize(world_normal); - let light_dir = normalize(light.position.xyz - world_pos); - let diff = max(dot(norm, light_dir), 0.0); - let diffuse = light.color.xyz * diff * tex_color; - - let shininess = 32.0; - let reflect_dir = reflect(-light_dir, norm); - let spec = pow(max(dot(view_dir, reflect_dir), 0.0), shininess); - let specular = light.color.xyz * spec * tex_color; - - let distance = length(light.position.xyz - world_pos); - let attenuation = 1.0 / (light.constant + (light.lin * distance) + (light.quadratic * (distance * distance))); - - return (diffuse + specular) * attenuation; -} - -fn spot_light(light: Light, world_pos: vec3<f32>, world_normal: vec3<f32>, view_dir: vec3<f32>, tex_color: vec3<f32>) -> vec3<f32> { - let outer_cutoff = light.direction.w; - let ambient = light.color.xyz * light_array.ambient_strength * tex_color; - - let norm = normalize(world_normal); - let light_dir = normalize(light.position.xyz - world_pos); - let diff = max(dot(norm, light_dir), 0.0); - var diffuse = light.color.xyz * diff * tex_color; - - let shininess = 32.0; - let reflect_dir = reflect(-light_dir, norm); - let spec = pow(max(dot(view_dir, reflect_dir), 0.0), shininess); - var specular = light.color.xyz * spec * tex_color; - - let theta = dot(light_dir, normalize(-light.direction.xyz)); - let epsilon = light.cutoff - outer_cutoff; - let intensity = clamp((theta - outer_cutoff) / epsilon, 0.0, 1.0); - - diffuse *= intensity; - specular *= intensity; - - let distance = length(light.position.xyz - world_pos); - let attenuation = 1.0 / (light.constant + (light.lin * distance) + (light.quadratic * (distance * distance))); - - let ambient_attenuated = ambient * attenuation; - let diffuse_attenuated = diffuse * attenuation; - let specular_attenuated = specular * attenuation; - - return ambient_attenuated + diffuse_attenuated + specular_attenuated; -} - -@fragment -fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> { - var tex_color = textureSample(t_diffuse, s_diffuse, in.tex_coords); - if (tex_color.a < 0.1) { - discard; - } - - let view_dir = normalize(camera.view_pos.xyz - in.world_position); - let world_normal = normalize(in.world_normal); - - var final_color = vec3<f32>(0.0); - - var total_ambient = vec3<f32>(0.0); - for (var i: u32 = 0u; i < light_array.light_count; i = i + 1u) { - let light = light_array._lights[i]; - total_ambient += light.color.xyz * light_array.ambient_strength; - } - - for (var i: u32 = 0u; i < light_array.light_count; i = i + 1u) { - let light = light_array._lights[i]; - - // light type is color.w - if light.color.w == 0.0 { - final_color += directional_light(light, world_normal, view_dir, tex_color.xyz); - } else if light.color.w == 1.0 { - // point - final_color += point_light(light, in.world_position, world_normal, view_dir, tex_color.xyz); - } else if light.color.w == 2.0 { - final_color += spot_light(light, in.world_position, world_normal, view_dir, tex_color.xyz); - } - } - - // Combine ambient and lighting - final_color = (total_ambient * tex_color.xyz) + final_color; - - return vec4<f32>(final_color, tex_color.a); -}