#![allow(dead_code, unused_variables, unused_imports, unused_mut, unused_parens, non_snake_case, unreachable_patterns, unused_assignments, unused_labels, unused_doc_comments, private_interfaces, clippy::all)]
pub mod math;
pub mod glyph;
pub mod entity;
pub mod particle;
pub mod scene;
pub mod render;
pub mod audio;
pub mod integration;
pub mod input;
pub mod config;
pub mod tween;
pub mod debug;
pub mod ui;
pub mod timeline;
pub mod procedural;
pub mod physics;
pub mod combat;
pub mod spatial;
pub mod effects;
pub mod anim;
pub mod animation;
pub mod ai;
pub mod networking;
pub mod replay;
pub mod scripting;
pub mod terrain;
pub mod ecs;
pub mod editor;
pub mod asset;
pub mod save;
pub mod character;
pub mod dsp;
pub mod game;
pub mod profiler;
pub mod vfx;
pub mod netcode;
pub mod network;
pub mod world;
pub mod crafting;
pub mod pathfinding;
pub mod economy;
pub mod behavior;
pub mod weather;
pub mod deferred;
pub mod shader_graph;
pub mod surfaces;
pub mod rendergraph;
pub mod compute;
pub mod lighting;
pub mod number_theory;
pub mod graph;
pub mod topology;
pub mod stochastic;
pub mod ml;
pub mod wgpu_backend;
pub mod geometry;
pub mod symbolic;
pub mod solver;
pub mod fractal;
pub mod metaball;
pub mod worldgen;
pub mod ecology;
pub mod narrative;
pub mod electromagnetic;
pub mod relativistic;
pub mod quantum;
pub mod svogi;
pub mod curves;
pub mod nishita_sky;
pub mod volumetric_fog;
pub mod tiled_lighting;
mod capture;
pub use config::EngineConfig;
pub use math::{MathFunction, ForceField, Falloff, AttractorType};
pub use glyph::{Glyph, RenderLayer, BlendMode};
pub use entity::AmorphousEntity;
pub use particle::{MathParticle, ParticleInteraction};
pub use scene::SceneGraph;
pub use render::camera::ProofCamera;
pub use input::{InputState, Key};
pub use render::pipeline::FrameStats;
pub use audio::AudioEvent;
pub struct ProofEngine {
pub config: EngineConfig,
pub scene: SceneGraph,
pub camera: ProofCamera,
pub input: InputState,
pub ui: render::ui_layer::UiLayer,
pub fx: render::screen_fx::ScreenFx,
density_queue: Vec<particle::gpu_density::GpuDensityEntityData>,
density_budget: u32,
pub audio: Option<audio::AudioEngine>,
pipeline: Option<render::Pipeline>,
}
impl ProofEngine {
pub fn new(mut config: EngineConfig) -> Self {
if let Some((w, h)) = capture::window_size() {
config.window_width = w;
config.window_height = h;
}
let audio = if config.audio.enabled {
audio::AudioEngine::try_new()
} else {
None
};
Self {
camera: ProofCamera::new(&config),
scene: SceneGraph::new(),
input: InputState::new(),
ui: render::ui_layer::UiLayer::new(
config.window_width as f32,
config.window_height as f32,
),
fx: render::screen_fx::ScreenFx::new(),
density_queue: Vec::new(),
density_budget: 0,
audio,
config,
pipeline: None,
}
}
pub fn init_gpu_density(&mut self, particles: u32) {
let cap = particle::gpu_density::MAX_PARTICLES_PER_ENTITY;
if particles > cap {
log::info!("gpu density: {particles} particles requested, drawing {cap} per entity");
}
self.density_budget = particles.min(cap);
}
pub fn queue_gpu_density_entity(&mut self, entity: particle::gpu_density::GpuDensityEntityData) {
self.density_queue.push(entity);
}
pub fn emit_audio(&self, event: audio::AudioEvent) {
if let Some(ref a) = self.audio {
a.emit(event);
}
}
pub fn run<F>(&mut self, mut update: F)
where
F: FnMut(&mut ProofEngine, f32),
{
self.run_with_overlay(move |engine, dt, _gl| {
update(engine, dt);
});
}
pub fn run_with_overlay<F>(&mut self, mut update: F)
where
F: FnMut(&mut ProofEngine, f32, &glow::Context),
{
let pipeline = render::Pipeline::init(&self.config);
self.pipeline = Some(pipeline);
let mut capture = capture::Capture::from_env();
let fixed_dt = capture::fixed_dt();
let mut last = std::time::Instant::now();
loop {
let now = std::time::Instant::now();
let dt = fixed_dt.unwrap_or_else(|| now.duration_since(last).as_secs_f32().min(0.1));
last = now;
if let Some(ref mut p) = self.pipeline {
if !p.poll_events(&mut self.input) {
break;
}
}
self.scene.tick(dt);
let gl_ptr = self.pipeline.as_ref().map(|p| p.gl() as *const glow::Context);
if let Some(ref mut p) = self.pipeline {
p.update_render_config(&self.config.render);
}
if let Some(ref mut p) = self.pipeline {
p.set_density_entities(&self.density_queue, self.density_budget);
p.render(&self.scene, &self.camera);
}
self.density_queue.clear();
self.fx.lights.clear();
if let Some(ptr) = gl_ptr {
let gl_ref = unsafe { &*ptr };
update(self, dt, gl_ref);
}
if let Some(ref mut c) = capture {
if c.after_draw(self) {
break;
}
}
if self.input.quit_requested {
break;
}
if let Some(ref mut p) = self.pipeline {
if !p.swap() {
break;
}
}
}
}
pub fn run_ui<F>(&mut self, mut update: F)
where
F: FnMut(&mut ProofEngine, f32),
{
let pipeline = render::Pipeline::init(&self.config);
self.pipeline = Some(pipeline);
let (w, h) = self.render_size();
self.ui.resize(w as f32, h as f32);
let mut capture = capture::Capture::from_env();
let fixed_dt = capture::fixed_dt();
let mut last = std::time::Instant::now();
let mut last_size = (w, h);
loop {
let now = std::time::Instant::now();
let dt = fixed_dt.unwrap_or_else(|| now.duration_since(last).as_secs_f32().min(0.1));
last = now;
if let Some(ref mut p) = self.pipeline {
if !p.poll_events(&mut self.input) {
break;
}
}
let size = self.render_size();
if size != last_size {
last_size = size;
self.ui.resize(size.0 as f32, size.1 as f32);
}
self.scene.tick(dt);
self.ui.begin_frame();
update(self, dt);
if self.input.quit_requested {
break;
}
self.camera.shake.tick(dt);
self.fx.tick(dt);
if let Some(ref mut p) = self.pipeline {
p.update_render_config(&self.config.render);
p.set_density_entities(&self.density_queue, self.density_budget);
p.render_frame(&self.scene, &self.camera, Some(&self.ui), &self.fx);
p.render_ui(&self.ui);
}
self.density_queue.clear();
self.fx.lights.clear();
if let Some(ref mut c) = capture {
if c.after_draw(self) {
break;
}
}
if let Some(ref mut p) = self.pipeline {
if !p.swap() {
break;
}
}
}
}
pub fn add_field(&mut self, field: ForceField) -> scene::FieldId {
self.scene.add_field(field)
}
pub fn remove_field(&mut self, id: scene::FieldId) {
self.scene.remove_field(id)
}
pub fn spawn_glyph(&mut self, glyph: Glyph) -> glyph::GlyphId {
self.scene.spawn_glyph(glyph)
}
pub fn spawn_entity(&mut self, mut entity: AmorphousEntity) -> entity::EntityId {
if entity.formation.is_empty() {
use entity::formation::Formation;
let f = Formation::diamond(2);
entity.formation = f.positions;
entity.formation_chars = f.chars;
}
while entity.formation_colors.len() < entity.formation.len() {
entity.formation_colors.push(glam::Vec4::ONE);
}
for i in 0..entity.formation.len() {
let offset = entity.formation[i];
let ch = entity.formation_chars.get(i).copied().unwrap_or('◆');
let color = entity.formation_colors.get(i).copied().unwrap_or(glam::Vec4::ONE);
let id = self.scene.spawn_glyph(Glyph {
character: ch,
position: entity.position + offset,
color,
emission: 0.8,
glow_color: glam::Vec3::new(color.x, color.y, color.z),
glow_radius: 1.2,
mass: entity.entity_mass / entity.formation.len().max(1) as f32,
layer: RenderLayer::Entity,
..Default::default()
});
entity.glyph_ids.push(id);
}
self.scene.spawn_entity(entity)
}
pub fn emit_particles(&mut self, emitter: particle::EmitterPreset, origin: glam::Vec3) {
particle::emit(&mut self.scene, emitter, origin);
}
pub fn add_trauma(&mut self, amount: f32) {
self.camera.add_trauma(amount);
}
}
impl ProofEngine {
pub fn request_quit(&mut self) {
self.input.quit_requested = true;
}
pub fn gl(&self) -> Option<&glow::Context> {
self.pipeline.as_ref().map(|p| p.gl())
}
pub fn window(&self) -> Option<&winit::window::Window> {
self.pipeline.as_ref().map(|p| p.window())
}
pub fn window_size(&self) -> (u32, u32) {
self.pipeline.as_ref().map(|p| p.window_size()).unwrap_or((1600, 1000))
}
pub fn render_size(&self) -> (u32, u32) {
self.pipeline.as_ref().map(|p| p.render_size()).unwrap_or((1600, 1000))
}
pub fn save_frame(&self, path: &str) -> std::io::Result<()> {
use std::io::Write;
let Some(p) = self.pipeline.as_ref() else {
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
"no pipeline to read from",
));
};
let (w, h, rgba) = p.read_frame();
if w == 0 || h == 0 {
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
"empty framebuffer",
));
}
let stride = ((w as usize * 3) + 3) & !3;
let pixels = stride * h as usize;
let mut out = Vec::with_capacity(54 + pixels);
out.extend_from_slice(b"BM");
out.extend_from_slice(&((54 + pixels) as u32).to_le_bytes());
out.extend_from_slice(&0u32.to_le_bytes());
out.extend_from_slice(&54u32.to_le_bytes());
out.extend_from_slice(&40u32.to_le_bytes());
out.extend_from_slice(&(w as i32).to_le_bytes());
out.extend_from_slice(&(h as i32).to_le_bytes());
out.extend_from_slice(&1u16.to_le_bytes());
out.extend_from_slice(&24u16.to_le_bytes());
for _ in 0..6 {
out.extend_from_slice(&0u32.to_le_bytes());
}
for y in 0..h as usize {
let row = y * w as usize * 4;
for x in 0..w as usize {
let i = row + x * 4;
out.push(rgba[i + 2]);
out.push(rgba[i + 1]);
out.push(rgba[i]);
}
for _ in 0..(stride - w as usize * 3) {
out.push(0);
}
}
let mut f = std::fs::File::create(path)?;
f.write_all(&out)
}
}
pub mod prelude {
pub use crate::{
ProofEngine, EngineConfig,
MathFunction, ForceField, Falloff, AttractorType,
Glyph, RenderLayer, BlendMode,
AmorphousEntity,
MathParticle, ParticleInteraction,
AudioEvent,
particle::EmitterPreset,
render::camera::ProofCamera,
input::{InputState, Key},
scene::{SceneGraph, FieldId},
audio::MusicVibe,
tween::{Tween, Easing, TweenState, Tweens, AnimationGroup},
tween::easing::Easing as EasingFn,
tween::keyframe::{KeyframeTrack, Keyframe, CameraPath, ExtrapolateMode},
tween::sequence::{TweenSequence, TweenTimeline, SequenceBuilder},
debug::DebugOverlay,
render::pipeline::FrameStats,
render::screen_fx::{ScreenFx, ScreenLight, Shockwave},
render::ui_layer::UiPass,
};
pub use glam::{Mat4, Quat, Vec2, Vec3, Vec4};
}