# Class: CameraEgoMCtrl

### LuxModule: luxinialuacore

Uses Mouse mostly. This controller modifies camera like a first person spectator. Rotation is done with leftmouse drag, while translation with rightmouse (forward/side) and right+left or middle (up/side).

## Hierarchy

    o-+ CameraCtrl
      o-+ CameraEgoMCtrl

## Methods:

### Method overview:

- addWindowResizeListener
- checkargtable
- freelook
- picktest
- removeWindowResizeListener
- serialize
- simplerenderqueue

addWindowResizeListener (function)
  returns: ()
  will call function after window was resized (directly after window.update or with a few milliseconds delay if thru window.resizemode > 0.
checkargtable (table)
  returns: (table)

  This function provides a system to check table keys for values. This is useful if a functions is taking a table containing various "named" function arguments. The return value of this function is a table which provides sophisticated functionalities. If the table is called with a string as argument, it expects that a key in the table is to be checked and returns a table with possible value checking functions:

  1. type: checks if the value of this key is of a certain type
  2. optional: if the value is nil, the passed optional value is returned (may be nil)
  3. translate: expects an table to be passed. That table contains values that substitue the value of the key. A 2nd optional value is used if no value was found
  4. oneofthis: like translate, but doesn't substitute the original value

  If the field "finish" is called, the collected arguments will be returned in the order they've been checked

        local x,y,vx,vy,type = UtilFunctions.checkargtable(info)
          "x":type "number"
          "y":type "number"
          "vx":optional(0)
          "vy":optional(0)
          "type":oneofthis{["player"]=true, ["AI"]=true}
          :finish()

freelook (boolean,Component guicomp)
  returns: (boolean)
  enables/disables freelook of current default l3dcamera. Useful for debugging, FreeLook.invert .movemulti .shiftmulti let you modify behavior. Controls are WASD,C,SPACE + Mouse. Optionally installed as drag listener into guicomp.
picktest (dspace space,[x=mousex],[y=mousey],[maxlength=1000000],[l3dcamera camera = l3dcamera.default])
  returns: ([geom,{x,y,z},{nx,ny,nz}])

  This function will test the given space with a ray and returns, if a hit was generated, the geom, the coordinate of the nearest hit and the hitnormal. The ray is in line with the x,y pair (or the mouse coordinates if not given) on the camera projection plane and through the last known camera worldposition (this worldposition can be one frame behind, so you might have to call camera:forceupdate() to update to the currently set position if this is important, which is not in most cases). The maxlength can be optionally set and is per default set to 1000000. If no camera is specified, the default camera is used.

  This function handles also orthogonal camera fovs, which requires a different raysetting code.

  ## Example:

       UtilFunctions.simplerenderqueue() input.showmouse(true) -- so we can see the mouse
       space = dspacehash.new() -- our space with our objects
       box = actornode.new("box")  -- our box location
       box.geom = dgeombox.new(1,1,1,space) -- the geom, placed in 0,0,0
       box.geom.l3d = l3dprimitive.newbox("box",1,1,1) -- the l3d for our box
       box.geom.l3d:linkinterface(box) -- link it
       cam = actornode.new("cam",5,4,3) -- our cameranode so we can view
       l3dcamera.default():linkinterface(cam) -- link it with defaultcamera
       cam:lookat(0,0,0,0,0,1) -- and look at 0,0,0 (the box location) highlight = actornode.new("highlight") -- a simple highlighter
       highlight.l3d = l3dprimitive.newsphere("hightlight",0.05)
       highlight.l3d:color(1,0,0,1) -- make sphere red
       highlight.l3d:linkinterface(highlight) -- link it local function test () -- our testing function
       	 local g,pos = UtilFunctions.picktest(space)  -- test it
       	 highlight.l3d:rfNodraw(not pos) -- don't highlight if no hit 	 if pos then  -- if we have a hit
           highlight:pos(pos[1],pos[2],pos[3]) -- move the highlighter
           g.l3d:color(1,math.sin(os.clock()*5)/2+.5,1,1)
           	-- ^^ make the hit object do something
       	 end
       end
       Timer.set("picker", test,20) -- run the test every 20ms

removeWindowResizeListener (function)
  returns: ()
  removes the given function from being called on window resize events
serialize (table input)
  returns: (string serialized)

  Serializes a given table into a string that allows the reconstruction of the given table. It returns a string that describes the table's content with lua code. To deserialize the string, it must only be executed:

       mytable = {1,2,3}
       serial = UtilFunctions.serialize(mytable)

       mytable = nil
       reconstructed = loadstring(serial)()

       for i,v in ipairs(reconstructed) do print(v) end
        -- prints out 1,2,3 - converted first to string and then
        -- to a table again successfully

  The table may contain self cycles:

       mytable = {1,2,3}
       mytable.self = mytable
       mytable[mytable] = "self index"
       serial = UtilFunctions.serialize(mytable)

       mytable = nil
       reconstructed = loadstring(serial)()

       print(reconstructed[reconstructed])
       for i,v in ipairs(reconstructed.self) do print(v) end
         -- prints out "self index" \n 1,2,3

  If the table contains function, the serilizing function will try to compile the function in its binary representation using string.dump - which may fail if the function is using local values from outside.

  If the table has a metatable function entry named __serialize, this function is being called and the return value is further serialized if it is a table value. However, if the function returns a string, the string is directly written in the place where the serialisation takes place! You can inject lua code this way:

       mytable = {}
       setmetatable(mytable, {__serialize =
         function (self, idx)
           return "function () return true end"
         end
       end
       })

       print (UtilFunctions.serialize({ mytable }))

  Output result:

       local refs = {}
       local fns = {}
       for i=1,1 do refs[i] = {} end

       refs[1][1] = function () return true end

       return refs[1]

  Important: don't serialize tables with __serialize metatables directly! Include them in a table instead, like in the example above.

  The serialisation function receives two arguments: the own table as argument 1 and an index value as argument 2. The indexvalue represents the id where the table data is stored (the refs table includes all required values and other values must reference them as well, building the cyclic tables and so on). The serialize function can return a second value which tells the serializer how many reference table you require - i.e. if you return 1 as second argument, an additional table is stored in refs.

  You could also return a table, which is then serialized too, or a string of a serialisation included in a function that is executed:

       (function () UtilFunctions.serialize({1,2,3}) end)()
        -- creates a table {1,2,3}

  Since you can modify the output result, you can write inject any code you want to save, meaning loops, functions and so on.

  The way the serialisation is stored is given in the output result above: A list of tables stored in refs is used to fill the data of the tables one after another without breaking the consistence due to cyclic references. The fns table contains functions that are created with the string.dump functions. The loop creates all required tables so we can easily use them later. After this initialisation, the tables in refs are filled with all values. At last, the first table value (which was passed to the serialize function) is returned. You can either write this string in a file or make a lua function of it by prepending "function serializedstuff () " and adding "end" to the string returned by the serializing function.

simplerenderqueue ([l3dview],[boolean noempty],[tab ignorelayers])
  returns: (l3dview)

  sets up a standard renderqueue for the view (which is also returned). The l3dview has equivalent rcmds in its table. The order is:

  1. rClear
  2. rDepth
  3. rDrawbg
  4. rLayers[1..16]
     - stencil
     - drawlayer
     - drawprt
  5. rDrawdebug

  Each rLayer contains: stencil,drawlayer,drawprt for the equivalent l3dlayerids-1. Sorting is enabled and material-based.
  ignorelayers should contain 'true' at layer+1 field. Ie {true,true} will disable layer 0 & 1.

## Inherited Methods:

### From CameraCtrl

addListener, createML, new, removeListener, runListeners, runThink