kitgit

tirbofish/dropbear · commit

39245f24435f938d5c3cfd3080f626f183cb133e

feature: outline shaders (incomplete) merging back to main and dealing with this another time.

Unverified

tk <4tkbytes@pm.me> · 2025-10-30 21:14

view full diff

diff --git a/Cargo.toml b/Cargo.toml
index 925138b..090d228 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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"
diff --git a/LICENSE.md b/LICENSE.md
deleted file mode 100644
index e578386..0000000
--- a/LICENSE.md
+++ /dev/null
@@ -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.
diff --git a/README.md b/README.md
index debd5bf..c3526be 100644
--- a/README.md
+++ b/README.md
@@ -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. 
diff --git a/dropbear-engine/Cargo.toml b/dropbear-engine/Cargo.toml
index 7734c38..78ec532 100644
--- a/dropbear-engine/Cargo.toml
+++ b/dropbear-engine/Cargo.toml
@@ -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]
diff --git a/dropbear-engine/src/graphics.rs b/dropbear-engine/src/graphics.rs
index 77898dd..5270140 100644
--- a/dropbear-engine/src/graphics.rs
+++ b/dropbear-engine/src/graphics.rs
@@ -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 {
diff --git a/dropbear-engine/src/lib.rs b/dropbear-engine/src/lib.rs
index 1b46611..0e987bb 100644
--- a/dropbear-engine/src/lib.rs
+++ b/dropbear-engine/src/lib.rs
@@ -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 {
diff --git a/dropbear-engine/src/lighting.rs b/dropbear-engine/src/lighting.rs
index 50c26ed..0f03345 100644
--- a/dropbear-engine/src/lighting.rs
+++ b/dropbear-engine/src/lighting.rs
@@ -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);
 
diff --git a/dropbear-engine/src/shader.rs b/dropbear-engine/src/shader.rs
new file mode 100644
index 0000000..5f453bc
--- /dev/null
+++ b/dropbear-engine/src/shader.rs
@@ -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,
+        }
+    }
+}
\ No newline at end of file
diff --git a/dropbear-shader/Cargo.toml b/dropbear-shader/Cargo.toml
new file mode 100644
index 0000000..b0b862b
--- /dev/null
+++ b/dropbear-shader/Cargo.toml
@@ -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"] }
diff --git a/dropbear-shader/README.md b/dropbear-shader/README.md
new file mode 100644
index 0000000..cdafabf
--- /dev/null
+++ b/dropbear-shader/README.md
@@ -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. 
\ No newline at end of file
diff --git a/dropbear-shader/build.rs b/dropbear-shader/build.rs
new file mode 100644
index 0000000..d22804f
--- /dev/null
+++ b/dropbear-shader/build.rs
@@ -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");
+}
\ No newline at end of file
diff --git a/dropbear-shader/src/lib.rs b/dropbear-shader/src/lib.rs
new file mode 100644
index 0000000..ea37992
--- /dev/null
+++ b/dropbear-shader/src/lib.rs
@@ -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");
\ No newline at end of file
diff --git a/dropbear-shader/src/shaders/config.wesl b/dropbear-shader/src/shaders/config.wesl
new file mode 100644
index 0000000..3779838
--- /dev/null
+++ b/dropbear-shader/src/shaders/config.wesl
@@ -0,0 +1 @@
+const MAX_LIGHTS: u32 = 8;
diff --git a/dropbear-shader/src/shaders/input.wesl b/dropbear-shader/src/shaders/input.wesl
new file mode 100644
index 0000000..eebe221
--- /dev/null
+++ b/dropbear-shader/src/shaders/input.wesl
@@ -0,0 +1,27 @@
+import package::config;
+
+struct CameraUniform {
+    view_pos: vec4<f32>,
+    view_proj: mat4x4<f32>,
+};
+
+struct OutlineUniform {
+    outline_width: f32,
+    outline_color: vec4<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,
+}
\ No newline at end of file
diff --git a/dropbear-shader/src/shaders/light.wesl b/dropbear-shader/src/shaders/light.wesl
new file mode 100644
index 0000000..dca5467
--- /dev/null
+++ b/dropbear-shader/src/shaders/light.wesl
@@ -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);
+}
\ No newline at end of file
diff --git a/dropbear-shader/src/shaders/outline.wesl b/dropbear-shader/src/shaders/outline.wesl
new file mode 100644
index 0000000..9f004cf
--- /dev/null
+++ b/dropbear-shader/src/shaders/outline.wesl
@@ -0,0 +1,65 @@
+// outline.wgsl
+import package::input::CameraUniform;
+import package::input::OutlineUniform;
+
+@group(1) @binding(0)
+var<uniform> camera: CameraUniform;
+
+@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>, // unused, but must match vertex layout
+    @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,
+    );
+
+    // Transform normal to world space
+    let world_normal = normalize(normal_matrix * model.normal);
+
+    // Extrude position in WORLD SPACE
+    let world_position = (model_matrix * vec4<f32>(model.position, 1.0)).xyz;
+    let expanded_world_position = world_position + world_normal * outline.outline_width;
+
+    var out: VertexOutput;
+    out.clip_position = camera.view_proj * vec4<f32>(expanded_world_position, 1.0);
+    return out;
+}
+
+@fragment
+fn fs_main() -> @location(0) vec4<f32> {
+    return outline.outline_color; // Use the uniform color!
+}
\ No newline at end of file
diff --git a/dropbear-shader/src/shaders/shader.wesl b/dropbear-shader/src/shaders/shader.wesl
new file mode 100644
index 0000000..c301a97
--- /dev/null
+++ b/dropbear-shader/src/shaders/shader.wesl
@@ -0,0 +1,193 @@
+// Main shader for standard objects.
+import package::config::MAX_LIGHTS;
+
+import package::input::{
+    CameraUniform,
+    Light,
+    LightArray,
+};
+
+@group(0) @binding(0)
+var t_diffuse: texture_2d<f32>;
+@group(0) @binding(1)
+var s_diffuse: sampler;
+
+@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;
+}
+
+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 {
+            // dir
+            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 {
+            // spot
+            final_color += spot_light(light, in.world_position, world_normal, view_dir, tex_color.xyz);
+        }
+    }
+
+    final_color = (total_ambient * tex_color.xyz) + final_color;
+
+    return vec4<f32>(final_color, tex_color.a);
+}
\ No newline at end of file
diff --git a/eucalyptus-core/Cargo.toml b/eucalyptus-core/Cargo.toml
index 7ec1797..e5b0f7c 100644
--- a/eucalyptus-core/Cargo.toml
+++ b/eucalyptus-core/Cargo.toml
@@ -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"
 
diff --git a/eucalyptus-core/src/scripting.rs b/eucalyptus-core/src/scripting.rs
index 3d882a3..fdfeef9 100644
--- a/eucalyptus-core/src/scripting.rs
+++ b/eucalyptus-core/src/scripting.rs
@@ -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 {
diff --git a/eucalyptus-editor/Cargo.toml b/eucalyptus-editor/Cargo.toml
index 0b00577..4671451 100644
--- a/eucalyptus-editor/Cargo.toml
+++ b/eucalyptus-editor/Cargo.toml
@@ -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"
diff --git a/eucalyptus-editor/src/editor/dock.rs b/eucalyptus-editor/src/editor/dock.rs
index 4baf656..121fcc9 100644
--- a/eucalyptus-editor/src/editor/dock.rs
+++ b/eucalyptus-editor/src/editor/dock.rs
@@ -26,13 +26,13 @@ pub struct EditorTabViewer<'a> {
     pub tex_size: Extent3d,
     pub gizmo: &'a mut Gizmo,
     pub world: &'a mut World,
-    pub selected_entity: &'a mut Option<hecs::Entity>,
+    pub selected_entity: &'a mut Option<Entity>,
     pub viewport_mode: &'a mut ViewportMode,
     pub undo_stack: &'a mut Vec<UndoableAction>,
     pub signal: &'a mut Signal,
     pub gizmo_mode: &'a mut EnumSet<GizmoMode>,
     pub editor_mode: &'a mut EditorState,
-    pub active_camera: &'a mut Arc<Mutex<Option<hecs::Entity>>>,
+    pub active_camera: &'a mut Arc<Mutex<Option<Entity>>>,
     pub plugin_registry: &'a mut PluginRegistry,
     // "wah wah its unsafe, its using raw pointers" shut the fuck up if it breaks i will know
     pub editor: *mut Editor,
@@ -511,7 +511,9 @@ impl<'a> TabViewer for EditorTabViewer<'a> {
                                                             "Model thumbnail [{}] does not exist, generating one now",
                                                             name
                                                         );
-                                                        let mut model = match model_to_image::ModelToImageBuilder::new(path)
+                                                        let project_path = { PROJECT.read().project_path.clone() };
+                                                        let path = ResourceReference::from_path(path).unwrap().to_project_path(project_path).unwrap();
+                                                        let mut model = match model_to_image::ModelToImageBuilder::new(&path)
                                                             .with_size((600, 600))
                                                             .build() {
                                                             Ok(v) => v,
diff --git a/eucalyptus-editor/src/editor/mod.rs b/eucalyptus-editor/src/editor/mod.rs
index 6032aaf..4add870 100644
--- a/eucalyptus-editor/src/editor/mod.rs
+++ b/eucalyptus-editor/src/editor/mod.rs
@@ -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: {:?}",
diff --git a/eucalyptus-editor/src/editor/scene.rs b/eucalyptus-editor/src/editor/scene.rs
index a3cf0e6..a648746 100644
--- a/eucalyptus-editor/src/editor/scene.rs
+++ b/eucalyptus-editor/src/editor/scene.rs
@@ -359,6 +359,19 @@ impl Scene for Editor {
                                         usage: wgpu::BufferUsages::VERTEX,
                                     });
 
+                                { // normal model rendering
+                                    let mut render_pass = graphics.continue_pass();
+                                    render_pass.set_pipeline(pipeline);
+
+                                    render_pass.set_vertex_buffer(1, instance_buffer.slice(..));
+                                    render_pass.draw_model_instanced(
+                                        &model,
+                                        0..instances.len() as u32,
+                                        camera.bind_group(),
+                                        self.light_manager.bind_group(),
+                                    );
+                                }
+
                                 // outline rendering
                                 let has_selected = entities.iter()
                                     .any(|e| e.model.id == model_ptr && e.is_selected);
@@ -386,19 +399,6 @@ impl Scene for Editor {
                                         );
                                     }
                                 }
-
-                                { // normal model rendering
-                                    let mut render_pass = graphics.continue_pass();
-                                    render_pass.set_pipeline(pipeline);
-
-                                    render_pass.set_vertex_buffer(1, instance_buffer.slice(..));
-                                    render_pass.draw_model_instanced(
-                                        &model,
-                                        0..instances.len() as u32,
-                                        camera.bind_group(),
-                                        self.light_manager.bind_group(),
-                                    );
-                                }
                                 log_once::debug_once!("Rendered {:?}", model_ptr);
                             } else {
                                 log_once::error_once!("No such MODEL as {:?}", model_ptr);
diff --git a/eucalyptus-editor/src/graphics.rs b/eucalyptus-editor/src/graphics.rs
index 6d6b240..6afda4c 100644
--- a/eucalyptus-editor/src/graphics.rs
+++ b/eucalyptus-editor/src/graphics.rs
@@ -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 =
diff --git a/magna-carta/Cargo.toml b/magna-carta/Cargo.toml
index 6826fc3..a19a9b9 100644
--- a/magna-carta/Cargo.toml
+++ b/magna-carta/Cargo.toml
@@ -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"
\ No newline at end of file
diff --git a/resources/dependencies/hotswap-agent-2.0.0.jar b/resources/dependencies/hotswap-agent-2.0.0.jar
deleted file mode 100644
index cfd2326..0000000
Binary files a/resources/dependencies/hotswap-agent-2.0.0.jar and /dev/null differ
diff --git a/resources/scripting/kotlin/Template.kt b/resources/scripting/kotlin/Template.kt
deleted file mode 100644
index 97e2201..0000000
--- a/resources/scripting/kotlin/Template.kt
+++ /dev/null
@@ -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")
-    }
-}
\ No newline at end of file
diff --git a/resources/shaders/light.wgsl b/resources/shaders/light.wgsl
deleted file mode 100644
index 57bedfa..0000000
--- a/resources/shaders/light.wgsl
+++ /dev/null
@@ -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);
-}
\ No newline at end of file
diff --git a/resources/shaders/outline.wgsl b/resources/shaders/outline.wgsl
deleted file mode 100644
index a71f445..0000000
--- a/resources/shaders/outline.wgsl
+++ /dev/null
@@ -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;
-}
\ No newline at end of file
diff --git a/resources/shaders/shader.wgsl b/resources/shaders/shader.wgsl
deleted file mode 100644
index 91402fa..0000000
--- a/resources/shaders/shader.wgsl
+++ /dev/null
@@ -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);
-}
\ No newline at end of file