e2r 0.10.0

experimental rendering engine in rust
Documentation
///interface for game logic as well as some default implementations

use std::fmt::Debug;

use interface::i_scheduler::IScheduler;

pub trait IGameLogic
{
    type EventInput : Debug;
    type EventRender;
    type GameState : Default + Clone + From< (Self::GameState, Self::GameStateChangeApply) >;
    type GameStateChangePending : Default + Clone;
    type GameStateChangeApply : Default + Clone + From< Self::ComputeUnit >;
    type ComputeUnit;
    type ComputeSchedule : IScheduler< Item = Self::ComputeUnit > + Iterator<Item = Vec<Self::ComputeUnit> >;

    /// transform a high level renderobj representation into render commands / elements
    type RenderObj : Into< Vec< Self::EventRender > >;
    
    fn new() -> Self;
    
    fn run_init_hook( & mut self ) -> Result< (), & 'static str >;

    fn get_states( & mut self ) -> & Self::GameState;

    fn get_states_mut( & mut self ) -> & mut Self::GameState;
    
    ///computes changed game state given user inputs and current game state
    fn transition_states( & mut self, inputs: & [ Self::EventInput ], win_offset: (i32,i32), win_size: (u32,u32) ) -> Self::GameStateChangePending;

    ///compute constraints per cycle
    fn continue_compute( & mut self ) -> bool;

    fn set_continue_compute( & mut self, bool );

    ///get what to compute based on changed game state
    fn get_computations( & mut self, changed_game_state: & Self::GameStateChangePending ) -> Vec< Self::ComputeUnit >;

    ///schedule computations
    fn schedule_computes( & mut self, computes: Vec< Self::ComputeUnit > ) -> Vec< Self::ComputeSchedule >;

    ///get all renderable objects from current game state
    fn get_renderable_components( & mut self ) -> Vec< Self::RenderObj >;

    ///do optimization on renderable objects
    fn filter_renderables( & mut self, r: Vec< Self::RenderObj > ) -> Vec< Self::RenderObj >;

    fn should_exit( & mut self ) -> bool;

    // fn get_game_impl( & mut self ) -> & mut Self::GameImpl;

    ///default implementation
    fn process_input_events( & mut self, e: & [ Self::EventInput ], win_offset: (i32,i32), win_size: (u32,u32) ) -> ( Vec< Self::EventRender >, bool ) {

        //process input events
        if e.len() > 0 {
            trace!( "filtered_input: {:?}", e );
        }
        
        //get changed states pending for computations
        let changed_states_pending = self.transition_states( e, win_offset, win_size );

        let mut count_compute_cycle = 0;

        //perform computations via:
        //pending_changed_state -> computes -> compute schedule -> execute computes -> 
        //finished_compute -> apply to new state

        while self.continue_compute() { //compute flag accessed in game state by game logic

            count_compute_cycle += 1;
            
            //todo: transform changed game states to determine what to compute/update
            let computes = self.get_computations( & changed_states_pending );

            //compute a schedule, returning a vector of iterators of compute unit,
            //with no dependencies across different series of iterator in the vector
            let scheduler = Self::ComputeSchedule::new( computes.as_slice() );

            for i in scheduler { //todo: offload work to parallel threads
                i.into_iter()
                    //execute computation unit and map it back to a state change
                    .map( |compute_unit| Self::GameStateChangeApply::from(compute_unit) )
                    //apply the change back to the game state, possibly use fold instead
                    .for_each( |changes| {
                        //apply result of compute unit changes back into game state
                        //todo: optimize this
                        let game_state = self.get_states().clone();
                        let game_state_new = Self::GameState::from( ( game_state, changes ) );
                        *self.get_states_mut() = game_state_new;
                    });
            }

            trace!( "compute cycle(s): {}", count_compute_cycle );
        }

        //transform renderable objects to render events
        let render_objects = self.get_renderable_components();

        //do some spatial optimization here
        let render_objects_filtered = self.filter_renderables( render_objects );

        //do further render commands packaging here
        let render_events = render_objects_filtered
            .into_iter()
            //transformation of high level game object into render elements / commands
            .flat_map( |x| Self::RenderObj::into( x ) )
            .collect();
        
        let sig_exit = self.should_exit();
        
        ( render_events, sig_exit )
    }
}