Using Controls

Let's now add some mouse/keyboard interaction, in this example using OrbitControler. You will need to import this module:

```
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls.js';
```

Before creating the controller, we need to setup the DOM element used by the renderer:
```
  renderer.domElement.ownerDocument = document;
  renderer.domElement.clientWidth = width;
  renderer.domElement.clientHeight = height;
```

We need to provide DOM event interface to Three.js. First we do this on the document object, and provide info for UI event (client width and height):

```
document.on_mouse_move = null;
document.on_mouse_up = null;
document.on_key_down = null;
document.addEventListener = function(evt_name, callback, use_capture) { 
  if (evt_name==='pointerup') this.on_mouse_up = callback;
  else if (evt_name==='pointermove') this.on_mouse_move = callback;
  else if (evt_name==='keydown') this.on_key_down = callback;
  else print('document.addEventListener unhandled event ' + evt_name); 
};
document.removeEventListener = function(evt_name, callback, use_capture) {
  if (evt_name==='pointerup') this.on_mouse_up = null;
  else if (evt_name==='pointermove') this.on_mouse_move = null;
  else if (evt_name==='keydown') this.on_key_down = null;
};
document.clientWidth = width;
document.clientHeight = height;

```

Then we provide DOM event interface on our canvas element, since Three.js registers listener to both document and canvas:

```
  canvas.on_mouse_move=null;
  canvas.on_mouse_down=null;
  canvas.on_mouse_up=null;
  canvas.on_mouse_wheel=null;
  canvas.addEventListener = function(evt_name, callback, use_capture)
  {
    if (evt_name==='pointerdown') this.on_mouse_down = callback;
    else if (evt_name==='pointercancel') this.on_mouse_up = callback;
    else if (evt_name==='wheel') this.on_mouse_wheel = callback;
    else print('Canvas.addEventListener unhandled event ' + evt_name); 
  };

  canvas.removeEventListener = function(evt_name, callback, use_capture)
  {
    print('Canvas.removeEventListener: ' + evt_name); 
    if (evt_name==='pointerdown') this.on_mouse_down = null;
    else if (evt_name==='pointercancel') this.on_mouse_up = null;
    else if (evt_name==='wheel') this.on_mouse_wheel = null;
  };

```

We can now create our controls:
```
  controls = new OrbitControls( camera, renderer.domElement );
  controls.enableDamping = true;
  controls.listenToKeyEvents(document); 
```

Since we enable inertia, you will need to call `controls.update();` before rendering the scene.


We will also some utility functions to translate GPAC events into DOM API:

```

let dom_evt = {};
dom_evt.button = 0;
dom_evt.clientX = 0;
dom_evt.clientY = 0;
dom_evt.pageX = 0;
dom_evt.pageY = 0;
dom_evt.code = 0;
dom_evt.preventDefault = function() {};

function make_dom_mouse_event(evt, is_down)
{
  if (is_down)
      dom_evt.button = evt.button;
  dom_evt.clientX = evt.mouse_x;
  dom_evt.clientY = evt.mouse_y;
  dom_evt.pageX = dom_evt.clientX;
  dom_evt.pageY = dom_evt.clientY;

  return dom_evt;
}

function make_dom_key_event(evt, is_down)
{
  let mods = evt.keymods;

  dom_evt.ctrlKey = (mods & GF_KEY_MOD_CTRL) ? true : false;
  dom_evt.metaKey = (mods & GF_KEY_MOD_ALT) ? true : false;
  dom_evt.shiftKey = (mods & GF_KEY_MOD_SHIFT) ? true : false;

  if (evt.keyname=="Left")  dom_evt.code = "ArrowLeft";
  else if (evt.keyname=="Right")  dom_evt.code = "ArrowRight";
  else if (evt.keyname=="Up")  dom_evt.code = "ArrowUp";
  else if (evt.keyname=="Down")  dom_evt.code = "ArrowDown";
  else dom_evt.code = evt.keyname;

  return dom_evt;
}
```

The final step is to catch GPAC events and forward them to the registered listeners. We use the `process_event` filter callback for this:

```
filter.process_event = function(pid, evt)
{
  if (evt.type != GF_FEVT_USER) {
    return;
  } 
  if (!canvas) return;

  if ((evt.ui_type == GF_EVENT_MOUSEDOWN) && canvas.on_mouse_down) {
      canvas.on_mouse_down( make_dom_mouse_event(evt, true)  );
  }
  if ((evt.ui_type == GF_EVENT_MOUSEUP)) {
      if (document.on_mouse_up)
        document.on_mouse_up( make_dom_mouse_event(evt, false)  );
      if (canvas.on_mouse_up)
        canvas.on_mouse_up( make_dom_mouse_event(evt, false)  );
  }

  if ((evt.ui_type == GF_EVENT_MOUSEMOVE) && document.on_mouse_move) {
    document.on_mouse_move( make_dom_mouse_event(evt, false)  );
  }

  if ((evt.ui_type == GF_EVENT_KEYDOWN) && document.on_key_down) {
    document.on_key_down( make_dom_key_event(evt, true) );
  }
  if (evt.ui_type == GF_EVENT_KEYUP) {
    dom_evt.ctrlKey = false;
    dom_evt.metaKey = false;
    dom_evt.shiftKey = false;
  }
}
```


You can now pan/rotate your models !

The complete code for this example is [here](examples/three/ex5.js).