Skip to main content

proof_engine/
lib.rs

1#![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)]
2
3//! # Proof Engine
4//!
5//! A mathematical rendering engine for Rust.
6//! Every visual is the output of a mathematical function.
7//! Every animation is a continuous function over time.
8//! Every particle follows a real equation.
9//!
10//! ## Philosophy
11//!
12//! Proof Engine does not render graphics. It renders mathematics.
13//!
14//! A traditional renderer draws shapes and colors that represent game state.
15//! Proof Engine computes mathematical functions and the visual IS the output.
16//! A Lorenz attractor looks like a Lorenz attractor because particles are
17//! following the actual differential equations in real time.
18//!
19//! ## Quick Start
20//!
21//! ```rust,no_run
22//! use proof_engine::prelude::*;
23//!
24//! let config = EngineConfig::default();
25//! let mut engine = ProofEngine::new(config);
26//! engine.run(|engine, _dt| {
27//!     // game logic
28//! });
29//! ```
30
31pub mod math;
32pub mod glyph;
33pub mod entity;
34pub mod particle;
35pub mod scene;
36pub mod render;
37pub mod audio;
38pub mod integration;
39pub mod input;
40pub mod config;
41pub mod tween;
42pub mod debug;
43pub mod ui;
44pub mod timeline;
45pub mod procedural;
46pub mod physics;
47pub mod combat;
48pub mod spatial;
49pub mod effects;
50pub mod anim;
51pub mod animation;
52pub mod ai;
53pub mod networking;
54pub mod replay;
55pub mod scripting;
56pub mod terrain;
57pub mod ecs;
58pub mod editor;
59pub mod asset;
60pub mod save;
61pub mod character;
62pub mod dsp;
63pub mod game;
64pub mod profiler;
65pub mod vfx;
66pub mod netcode;
67pub mod network;
68pub mod world;
69pub mod crafting;
70pub mod pathfinding;
71pub mod economy;
72pub mod behavior;
73pub mod weather;
74pub mod deferred;
75pub mod shader_graph;
76pub mod surfaces;
77pub mod rendergraph;
78pub mod compute;
79pub mod lighting;
80pub mod number_theory;
81pub mod graph;
82pub mod topology;
83pub mod stochastic;
84pub mod ml;
85pub mod wgpu_backend;
86pub mod geometry;
87pub mod symbolic;
88pub mod solver;
89pub mod fractal;
90pub mod worldgen;
91pub mod ecology;
92pub mod narrative;
93pub mod electromagnetic;
94pub mod relativistic;
95pub mod quantum;
96
97pub use config::EngineConfig;
98pub use math::{MathFunction, ForceField, Falloff, AttractorType};
99pub use glyph::{Glyph, RenderLayer, BlendMode};
100pub use entity::AmorphousEntity;
101pub use particle::{MathParticle, ParticleInteraction};
102pub use scene::SceneGraph;
103pub use render::camera::ProofCamera;
104pub use input::{InputState, Key};
105pub use render::pipeline::FrameStats;
106pub use audio::AudioEvent;
107
108/// The main engine struct. Create once, run forever.
109pub struct ProofEngine {
110    pub config: EngineConfig,
111    pub scene: SceneGraph,
112    pub camera: ProofCamera,
113    pub input: InputState,
114    /// Optional audio engine — None if no output device is available.
115    pub audio: Option<audio::AudioEngine>,
116    // Internal render pipeline (initialized lazily when run() is called)
117    pipeline: Option<render::Pipeline>,
118}
119
120impl ProofEngine {
121    pub fn new(config: EngineConfig) -> Self {
122        let audio = if config.audio.enabled {
123            audio::AudioEngine::try_new()
124        } else {
125            None
126        };
127        Self {
128            camera: ProofCamera::new(&config),
129            scene: SceneGraph::new(),
130            input: InputState::new(),
131            audio,
132            config,
133            pipeline: None,
134        }
135    }
136
137    /// Send an audio event. No-op if audio is unavailable.
138    pub fn emit_audio(&self, event: audio::AudioEvent) {
139        if let Some(ref a) = self.audio {
140            a.emit(event);
141        }
142    }
143
144    /// Run the engine. Calls `update` every frame with elapsed seconds.
145    /// Blocks until the window is closed.
146    pub fn run<F>(&mut self, mut update: F)
147    where
148        F: FnMut(&mut ProofEngine, f32),
149    {
150        self.run_with_overlay(move |engine, dt, _gl| {
151            update(engine, dt);
152        });
153    }
154
155    /// Run the engine with an overlay callback.
156    /// The overlay callback receives the glow GL context reference and is called
157    /// AFTER scene rendering but BEFORE buffer swap — perfect for egui.
158    pub fn run_with_overlay<F>(&mut self, mut update: F)
159    where
160        F: FnMut(&mut ProofEngine, f32, &glow::Context),
161    {
162        let pipeline = render::Pipeline::init(&self.config);
163        self.pipeline = Some(pipeline);
164
165        let mut last = std::time::Instant::now();
166        loop {
167            let now = std::time::Instant::now();
168            let dt = now.duration_since(last).as_secs_f32().min(0.1);
169            last = now;
170
171            // Poll input
172            if let Some(ref mut p) = self.pipeline {
173                if !p.poll_events(&mut self.input) {
174                    break;
175                }
176            }
177
178            // Step force fields and physics
179            self.scene.tick(dt);
180
181            // User update (logic only — no GL calls here)
182            // We pass a dummy gl ref for the logic phase; the real painting
183            // happens after the scene render.
184            let gl_ptr = self.pipeline.as_ref().map(|p| p.gl() as *const glow::Context);
185
186            // Render scene first
187            if let Some(ref mut p) = self.pipeline {
188                p.render(&self.scene, &self.camera);
189            }
190
191            // NOW paint the overlay (egui) on top of the rendered scene
192            if let Some(ptr) = gl_ptr {
193                let gl_ref = unsafe { &*ptr };
194                update(self, dt, gl_ref);
195            }
196
197            // Swap
198            if let Some(ref mut p) = self.pipeline {
199                if !p.swap() {
200                    break;
201                }
202            }
203        }
204    }
205
206    /// Add a force field to the scene.
207    pub fn add_field(&mut self, field: ForceField) -> scene::FieldId {
208        self.scene.add_field(field)
209    }
210
211    /// Remove a force field.
212    pub fn remove_field(&mut self, id: scene::FieldId) {
213        self.scene.remove_field(id)
214    }
215
216    /// Spawn a glyph into the scene.
217    pub fn spawn_glyph(&mut self, glyph: Glyph) -> glyph::GlyphId {
218        self.scene.spawn_glyph(glyph)
219    }
220
221    /// Spawn an amorphous entity, creating its formation glyphs.
222    pub fn spawn_entity(&mut self, mut entity: AmorphousEntity) -> entity::EntityId {
223        // If no formation was specified, generate a default diamond
224        if entity.formation.is_empty() {
225            use entity::formation::Formation;
226            let f = Formation::diamond(2);
227            entity.formation = f.positions;
228            entity.formation_chars = f.chars;
229        }
230        // Ensure colors are filled (white if unspecified)
231        while entity.formation_colors.len() < entity.formation.len() {
232            entity.formation_colors.push(glam::Vec4::ONE);
233        }
234        // Spawn one glyph per formation slot
235        for i in 0..entity.formation.len() {
236            let offset = entity.formation[i];
237            let ch = entity.formation_chars.get(i).copied().unwrap_or('◆');
238            let color = entity.formation_colors.get(i).copied().unwrap_or(glam::Vec4::ONE);
239            let id = self.scene.spawn_glyph(Glyph {
240                character: ch,
241                position: entity.position + offset,
242                color,
243                emission: 0.8,
244                glow_color: glam::Vec3::new(color.x, color.y, color.z),
245                glow_radius: 1.2,
246                mass: entity.entity_mass / entity.formation.len().max(1) as f32,
247                layer: RenderLayer::Entity,
248                ..Default::default()
249            });
250            entity.glyph_ids.push(id);
251        }
252        self.scene.spawn_entity(entity)
253    }
254
255    /// Emit a burst of particles at a position.
256    pub fn emit_particles(&mut self, emitter: particle::EmitterPreset, origin: glam::Vec3) {
257        particle::emit(&mut self.scene, emitter, origin);
258    }
259
260    /// Apply trauma (screen shake). 0.0 = none, 1.0 = maximum.
261    pub fn add_trauma(&mut self, amount: f32) {
262        self.camera.add_trauma(amount);
263    }
264}
265
266/// Request quit on next frame.
267impl ProofEngine {
268    pub fn request_quit(&mut self) {
269        self.input.quit_requested = true;
270    }
271
272    /// Get a reference to the glow GL context (for egui integration).
273    /// Returns None if the pipeline hasn't been initialized yet.
274    pub fn gl(&self) -> Option<&glow::Context> {
275        self.pipeline.as_ref().map(|p| p.gl())
276    }
277
278    /// Get the window reference (for egui-winit event processing).
279    pub fn window(&self) -> Option<&winit::window::Window> {
280        self.pipeline.as_ref().map(|p| p.window())
281    }
282
283    /// Get the current window size in pixels.
284    pub fn window_size(&self) -> (u32, u32) {
285        self.pipeline.as_ref().map(|p| p.window_size()).unwrap_or((1600, 1000))
286    }
287}
288
289/// Common imports for using Proof Engine.
290pub mod prelude {
291    pub use crate::{
292        ProofEngine, EngineConfig,
293        MathFunction, ForceField, Falloff, AttractorType,
294        Glyph, RenderLayer, BlendMode,
295        AmorphousEntity,
296        MathParticle, ParticleInteraction,
297        AudioEvent,
298        particle::EmitterPreset,
299        render::camera::ProofCamera,
300        input::{InputState, Key},
301        scene::{SceneGraph, FieldId},
302        audio::MusicVibe,
303        tween::{Tween, Easing, TweenState, Tweens, AnimationGroup},
304        tween::easing::Easing as EasingFn,
305        tween::keyframe::{KeyframeTrack, Keyframe, CameraPath, ExtrapolateMode},
306        tween::sequence::{TweenSequence, TweenTimeline, SequenceBuilder},
307        debug::DebugOverlay,
308        render::pipeline::FrameStats,
309    };
310    pub use glam::{Vec2, Vec3, Vec4};
311}