0xABADCAFE / php-demo-engine

MIT License
42 stars 4 forks source link

                  ______                            __
          __     /\\\\\\\\_                        /\\\
         /\\\  /\\\//////\\\_                      \/\\\
       /\\\//  \///     \//\\\    ________       ___\/\\\         _______
     /\\\//               /\\\   /\\\\\\\\\_    /\\\\\\\\\       /\\\\\\\\_
   /\\\//_              /\\\\/   /\\\/////\\\   /\\\////\\\     /\\\/////\\\
   \////\\\ __          /\\\/    \/\\\   \/\\\  \/\\\  \/\\\    /\\\\\\\\\\\
       \////\\\ __      \///_     \/\\\___\/\\\  \/\\\__\/\\\   \//\\\//////_
           \////\\\       /\\\     \/\\\\\\\\\\   \//\\\\\\\\\    \//\\\\\\\\\
               \///       \///      \/\\\//////     \/////////      \/////////
                                     \/\\\
                                      \///

                        /P(?:ointless|ortable|HP) Demo Engine/

PDE: The Pointless|Portable|PHP Demo Engine

A bit of fun. An ASCII/ANSI terminal display with stackable routines, sequenced and controlled from a simple text file.

Examples

First Demo Raytracing Tunnels Audio

Requirements

Notes

Usage

Natively

Execute ./display <path to json file>

Via Docker

$ docker build -t php-demo-engine .

$ docker run php-demo-engine php display

Structure

Displays

Displays provide the render target. For now this is limited to basic ASCII output.

Routines

Routines provide the effects. Routines are classes that implement the IRoutine interface which mandates how they are created, rendered and parameterised. Routines can be stacked, meaning more than one routine is rendered per frame, in a given priority order.

Implementing a new Routine

Pretty simples. Implement the IRoutine interface directly or extend the Routine\Base class which handles a lot of the lower level drudgery already:


namespace ABadCafe\PDE\Routine;
use ABadCafe\PDE;

/**
 * MyRoutine. Does something cool. Probably.
 */
class MyRoutine extends Base {

    const DEFAULT_PARAMETERS = [
        // These are the parameter names that can be set from the demo file and their initial value/types.
        // Define these as you need them. They will populate a member oParameters tuple at runtime.
        'iMyIntParameter'    => 0,
        'fMyFloatParamter'   => 1.5,
        'sMyStringParameter' => 'pde',
        'aMyArrayParameter'  => []
    ];

    /**
     * @inheritDoc
     *
     * Whenever the display changes, this is invoked. It is always called before render() in any given frame.
     */
    public function setDisplay(PDE\IDisplay $oDisplay) : self {
        // Be prepared here to check if this display is suitable for your routine.
        $this->oDisplay = $oDisplay;
        return $this;
    }

    /**
     * @inheritDoc
     *
     * Do your thing. It is expected that your routine will render a single frame. The parameters provide the
     * current frame number and the current time in seconds since the demo began execution.
     */
    public function render(int $iFrameNumber, float $fTimeIndex) : self {
        // Your magic here...
        // You have access to:
        //    $this->oParameters for the current parameter values
        //    $this->oDisplay for the current render target
        return $this;
    }

    /**
     * @inheritDoc
     */
    protected function parameterChange() {
        // This is called after the an update event in the demo file if any of our parameters change.
    }
}

Once your routine is implemented, it must be added to the Routine\Factory types array so that it can be found and instantiated by the loader:

namespace ABadCafe\PDE\Routine;

class Factory {

    const TYPES = [
        'MyRoutine' => MyRoutine::class,
    ];

    // ... snip
}

Any time you add new code, you should run the provided createclassmap script. This isn't PSR autoloading.

Loaders

Loaders import definition files which describe the components and timeline of a demo. Loaders are classes that implement the ILoader interface. A JSON model is provided by default, but adding other formats should be trivial.