Import Oxide engine (Stages 0–10) under MIT license

Full project snapshot migrated to new Gitea remote without history:
engine, editor, physics, script, examples, tests, docs, and assets.
Relicensed from GPLv3 to MIT and updated repo URLs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Homer Simpson
2026-07-05 20:41:02 +02:00
parent 2afb56b329
commit f56a1eea3b
128 changed files with 40493 additions and 2 deletions
+69
View File
@@ -0,0 +1,69 @@
// Stage 4 forward lit shader: a single directional light with Lambert diffuse,
// ambient, and a Blinn-Phong specular term scaled by material roughness/metallic
// (PBR-lite). Output is linear color; an sRGB surface format converts on write.
struct Globals {
view_proj: mat4x4<f32>,
camera_pos: vec4<f32>, // xyz world-space camera position
light_dir: vec4<f32>, // xyz unit vector pointing TOWARD the light
light_color: vec4<f32>, // rgb light color * intensity
ambient: vec4<f32>, // rgb ambient term
};
struct ObjectData {
model: mat4x4<f32>,
normal_mtx: mat4x4<f32>, // inverse-transpose of model (3x3 in a 4x4)
albedo: vec4<f32>,
mr: vec4<f32>, // x = metallic, y = roughness
};
@group(0) @binding(0) var<uniform> globals: Globals;
@group(1) @binding(0) var<uniform> obj: ObjectData;
struct VsOut {
@builtin(position) clip_pos: vec4<f32>,
@location(0) world_pos: vec3<f32>,
@location(1) world_normal: vec3<f32>,
@location(2) uv: vec2<f32>,
};
@vertex
fn vs_main(
@location(0) position: vec3<f32>,
@location(1) normal: vec3<f32>,
@location(2) uv: vec2<f32>,
) -> VsOut {
let world = obj.model * vec4<f32>(position, 1.0);
var out: VsOut;
out.world_pos = world.xyz;
out.world_normal = (obj.normal_mtx * vec4<f32>(normal, 0.0)).xyz;
out.uv = uv;
out.clip_pos = globals.view_proj * world;
return out;
}
@fragment
fn fs_main(in: VsOut) -> @location(0) vec4<f32> {
let n = normalize(in.world_normal);
let l = normalize(globals.light_dir.xyz);
let v = normalize(globals.camera_pos.xyz - in.world_pos);
let h = normalize(l + v);
let albedo = obj.albedo.rgb;
let metallic = obj.mr.x;
let roughness = clamp(obj.mr.y, 0.04, 1.0);
let ndl = max(dot(n, l), 0.0);
let ndh = max(dot(n, h), 0.0);
// Metals have no diffuse; dielectrics get a fixed 0.04 specular, metals
// tint their specular by the albedo.
let diffuse = albedo * (1.0 - metallic);
let spec_color = mix(vec3<f32>(0.04), albedo, metallic);
let spec_power = mix(8.0, 256.0, 1.0 - roughness);
let spec = spec_color * pow(ndh, spec_power) * select(0.0, 1.0, ndl > 0.0);
let direct = (diffuse * ndl + spec) * globals.light_color.rgb;
let ambient = albedo * globals.ambient.rgb;
return vec4<f32>(ambient + direct, obj.albedo.a);
}
+47
View File
@@ -0,0 +1,47 @@
// Oxide Stage-8 UI overlay shader.
//
// One vertex format covers both solid quads and glyph quads: the sentinel UV
// `(-1, -1)` marks "solid color, do not sample the atlas". This avoids
// branching on a separate flag attribute and keeps the vertex stride tight
// (32 bytes — pos2 + uv2 + color4).
struct Uniforms {
mvp: mat4x4<f32>,
};
@group(0) @binding(0) var<uniform> u: Uniforms;
@group(0) @binding(1) var atlas: texture_2d<f32>;
@group(0) @binding(2) var atlas_sampler: sampler;
struct VsIn {
@location(0) position: vec2<f32>,
@location(1) uv: vec2<f32>,
@location(2) color: vec4<f32>,
};
struct VsOut {
@builtin(position) clip_pos: vec4<f32>,
@location(0) uv: vec2<f32>,
@location(1) color: vec4<f32>,
};
@vertex
fn vs_main(in: VsIn) -> VsOut {
var out: VsOut;
out.clip_pos = u.mvp * vec4<f32>(in.position, 0.0, 1.0);
out.uv = in.uv;
out.color = in.color;
return out;
}
@fragment
fn fs_main(in: VsOut) -> @location(0) vec4<f32> {
// Solid quads use the sentinel UV (-1, -1). Sampling out-of-range would
// be clamped or wrapped depending on the sampler, but we cheaply detect
// it instead so a single texture binding serves every primitive.
if (in.uv.x < 0.0) {
return in.color;
}
let alpha = textureSample(atlas, atlas_sampler, in.uv).r;
return vec4<f32>(in.color.rgb, in.color.a * alpha);
}