text:
-- GLMatrix --------------------------------------------------------------------
local ffi = require('ffi')
local libphx = require('ffi.libphx').lib
local GLMatrix

do -- C Definitions
  ffi.cdef [[
    void    GLMatrix_Clear       ();
    void    GLMatrix_LookAt      (Vec3d const* eye, Vec3d const* at, Vec3d const* up);
    void    GLMatrix_Load        (Matrix* matrix);
    void    GLMatrix_ModeP       ();
    void    GLMatrix_ModeWV      ();
    Matrix* GLMatrix_Get         ();
    void    GLMatrix_Mult        (Matrix* matrix);
    void    GLMatrix_Perspective (double degreesFovY, double aspect, double zNear, double zFar);
    void    GLMatrix_Pop         ();
    void    GLMatrix_Push        ();
    void    GLMatrix_PushClear   ();
    void    GLMatrix_RotateX     (double rads);
    void    GLMatrix_RotateY     (double rads);
    void    GLMatrix_RotateZ     (double rads);
    void    GLMatrix_Scale       (double x, double y, double z);
    void    GLMatrix_Translate   (double x, double y, double z);
  ]]
end

do -- Global Symbol Table
  GLMatrix = {
    Clear       = libphx.GLMatrix_Clear,
    LookAt      = libphx.GLMatrix_LookAt,
    Load        = libphx.GLMatrix_Load,
    ModeP       = libphx.GLMatrix_ModeP,
    ModeWV      = libphx.GLMatrix_ModeWV,
    Get         = libphx.GLMatrix_Get,
    Mult        = libphx.GLMatrix_Mult,
    Perspective = libphx.GLMatrix_Perspective,
    Pop         = libphx.GLMatrix_Pop,
    Push        = libphx.GLMatrix_Push,
    PushClear   = libphx.GLMatrix_PushClear,
    RotateX     = libphx.GLMatrix_RotateX,
    RotateY     = libphx.GLMatrix_RotateY,
    RotateZ     = libphx.GLMatrix_RotateZ,
    Scale       = libphx.GLMatrix_Scale,
    Translate   = libphx.GLMatrix_Translate,
  }

  if onDef_GLMatrix then onDef_GLMatrix(GLMatrix, mt) end
  GLMatrix = setmetatable(GLMatrix, mt)
end

return GLMatrix


text:
-- Engine ----------------------------------------------------------------------
local ffi = require('ffi')
local libphx = require('ffi.libphx').lib
local Engine

do -- C Definitions
  ffi.cdef [[
    void   Engine_Init          (int glVersionMajor, int glVersionMinor);
    void   Engine_Free          ();
    void   Engine_Abort         ();
    int    Engine_GetBits       ();
    double Engine_GetTime       ();
    cstr   Engine_GetVersion    ();
    bool   Engine_IsInitialized ();
    void   Engine_Terminate     ();
    void   Engine_Update        ();
  ]]
end

do -- Global Symbol Table
  Engine = {
    Init          = libphx.Engine_Init,
    Free          = libphx.Engine_Free,
    Abort         = libphx.Engine_Abort,
    GetBits       = libphx.Engine_GetBits,
    GetTime       = libphx.Engine_GetTime,
    GetVersion    = libphx.Engine_GetVersion,
    IsInitialized = libphx.Engine_IsInitialized,
    Terminate     = libphx.Engine_Terminate,
    Update        = libphx.Engine_Update,
  }

  if onDef_Engine then onDef_Engine(Engine, mt) end
  Engine = setmetatable(Engine, mt)
end

return Engine

repo_name: JoshParnell/libphx

repo_language: C

mime_type: text/x-c++


text:
-- Tex3D -----------------------------------------------------------------------
local ffi = require('ffi')
local libphx = require('ffi.libphx').lib
local Tex3D

do -- C Definitions
  ffi.cdef [[
    Tex3D*    Tex3D_Create       (int sx, int sy, int sz, TexFormat);
    void      Tex3D_Acquire      (Tex3D*);
    void      Tex3D_Free         (Tex3D*);
    void      Tex3D_Pop          (Tex3D*);
    void      Tex3D_Push         (Tex3D*, int layer);
    void      Tex3D_PushLevel    (Tex3D*, int layer, int level);
    void      Tex3D_Draw         (Tex3D* self, int layer, float x, float y, float xs, float ys);
    void      Tex3D_GenMipmap    (Tex3D*);
    void      Tex3D_GetData      (Tex3D*, void*, PixelFormat, DataFormat);
    Bytes*    Tex3D_GetDataBytes (Tex3D*, PixelFormat, DataFormat);
    TexFormat Tex3D_GetFormat    (Tex3D*);
    uint      Tex3D_GetHandle    (Tex3D*);
    void      Tex3D_GetSize      (Tex3D*, Vec3i* out);
    void      Tex3D_GetSizeLevel (Tex3D*, Vec3i* out, int level);
    void      Tex3D_SetData      (Tex3D*, void const*, PixelFormat, DataFormat);
    void      Tex3D_SetDataBytes (Tex3D*, Bytes*, PixelFormat, DataFormat);
    void      Tex3D_SetMagFilter (Tex3D*, TexFilter);
    void      Tex3D_SetMinFilter (Tex3D*, TexFilter);
    void      Tex3D_SetWrapMode  (Tex3D*, TexWrapMode);
  ]]
end

do -- Global Symbol Table
  Tex3D = {
    Create       = libphx.Tex3D_Create,
    Acquire      = libphx.Tex3D_Acquire,
    Free         = libphx.Tex3D_Free,
    Pop          = libphx.Tex3D_Pop,
    Push         = libphx.Tex3D_Push,
    PushLevel    = libphx.Tex3D_PushLevel,
    Draw         = libphx.Tex3D_Draw,
    GenMipmap    = libphx.Tex3D_GenMipmap,
    GetData      = libphx.Tex3D_GetData,
    GetDataBytes = libphx.Tex3D_GetDataBytes,
    GetFormat    = libphx.Tex3D_GetFormat,
    GetHandle    = libphx.Tex3D_GetHandle,
    GetSize      = libphx.Tex3D_GetSize,
    GetSizeLevel = libphx.Tex3D_GetSizeLevel,
    SetData      = libphx.Tex3D_SetData,
    SetDataBytes = libphx.Tex3D_SetDataBytes,
    SetMagFilter = libphx.Tex3D_SetMagFilter,
    SetMinFilter = libphx.Tex3D_SetMinFilter,
    SetWrapMode  = libphx.Tex3D_SetWrapMode,
  }

  if onDef_Tex3D then onDef_Tex3D(Tex3D, mt) end
  Tex3D = setmetatable(Tex3D, mt)
end

do -- Metatype for class instances
  local t  = ffi.typeof('Tex3D')
  local mt = {
    __index = {
      managed      = function (self) return ffi.gc(self, libphx.Tex3D_Free) end,
      acquire      = libphx.Tex3D_Acquire,
      free         = libphx.Tex3D_Free,
      pop          = libphx.Tex3D_Pop,
      push         = libphx.Tex3D_Push,
      pushLevel    = libphx.Tex3D_PushLevel,
      draw         = libphx.Tex3D_Draw,
      genMipmap    = libphx.Tex3D_GenMipmap,
      getData      = libphx.Tex3D_GetData,
      getDataBytes = libphx.Tex3D_GetDataBytes,
      getFormat    = libphx.Tex3D_GetFormat,
      getHandle    = libphx.Tex3D_GetHandle,
      getSize      = libphx.Tex3D_GetSize,
      getSizeLevel = libphx.Tex3D_GetSizeLevel,
      setData      = libphx.Tex3D_SetData,
      setDataBytes = libphx.Tex3D_SetDataBytes,
      setMagFilter = libphx.Tex3D_SetMagFilter,
      setMinFilter = libphx.Tex3D_SetMinFilter,
      setWrapMode  = libphx.Tex3D_SetWrapMode,
    },
  }

  if onDef_Tex3D_t then onDef_Tex3D_t(t, mt) end
  Tex3D_t = ffi.metatype(t, mt)
end

return Tex3D


text:
-- RayCastResult ---------------------------------------------------------------
local ffi = require('ffi')
local libphx = require('ffi.libphx').lib
local RayCastResult

do -- Global Symbol Table
  RayCastResult = {
  }

  local mt = {
    __call  = function (t, ...) return RayCastResult_t(...) end,
  }

  if onDef_RayCastResult then onDef_RayCastResult(RayCastResult, mt) end
  RayCastResult = setmetatable(RayCastResult, mt)
end

do -- Metatype for class instances
  local t  = ffi.typeof('RayCastResult')
  local mt = {
    __index = {
      clone = function (x) return RayCastResult_t(x) end,
    },
  }

  if onDef_RayCastResult_t then onDef_RayCastResult_t(t, mt) end
  RayCastResult_t = ffi.metatype(t, mt)
end

return RayCastResult


text:
-- BSP -------------------------------------------------------------------------
local ffi = require('ffi')
local libphx = require('ffi.libphx').lib
local BSP

do -- C Definitions
  ffi.cdef [[
    BSP* BSP_Create               (Mesh*);
    void BSP_Free                 (BSP*);
    bool BSP_IntersectRay         (BSP*, Ray const*, float* tHit);
    bool BSP_IntersectLineSegment (BSP*, LineSegment const*, Vec3f* pHit);
    bool BSP_IntersectSphere      (BSP*, Sphere const*, Vec3f* pHit);
  ]]
end

do -- Global Symbol Table
  BSP = {
    Create               = libphx.BSP_Create,
    Free                 = libphx.BSP_Free,
    IntersectRay         = libphx.BSP_IntersectRay,
    IntersectLineSegment = libphx.BSP_IntersectLineSegment,
    IntersectSphere      = libphx.BSP_IntersectSphere,
  }

  if onDef_BSP then onDef_BSP(BSP, mt) end
  BSP = setmetatable(BSP, mt)
end

do -- Metatype for class instances
  local t  = ffi.typeof('BSP')
  local mt = {
    __index = {
      managed              = function (self) return ffi.gc(self, libphx.BSP_Free) end,
      free                 = libphx.BSP_Free,
      intersectRay         = libphx.BSP_IntersectRay,
      intersectLineSegment = libphx.BSP_IntersectLineSegment,
      intersectSphere      = libphx.BSP_IntersectSphere,
    },
  }

  if onDef_BSP_t then onDef_BSP_t(t, mt) end
  BSP_t = ffi.metatype(t, mt)
end

return BSP


text:
-- GUID ------------------------------------------------------------------------
local ffi = require('ffi')
local libphx = require('ffi.libphx').lib
local GUID

do -- C Definitions
  ffi.cdef [[
    uint64 GUID_Create ();
    bool   GUID_Exists (uint64);
    void   GUID_Reset  ();
  ]]
end

do -- Global Symbol Table
  GUID = {
    Create = libphx.GUID_Create,
    Exists = libphx.GUID_Exists,
    Reset  = libphx.GUID_Reset,
  }

  if onDef_GUID then onDef_GUID(GUID, mt) end
  GUID = setmetatable(GUID, mt)
end

return GUID


text:
-- ResourceType ----------------------------------------------------------------
local ffi = require('ffi')
local libphx = require('ffi.libphx').lib
local ResourceType

do -- C Definitions
  ffi.cdef [[
    cstr         ResourceType_ToString (ResourceType);
    ResourceType ResourceType_Font;
    ResourceType ResourceType_Mesh;
    ResourceType ResourceType_Other;
    ResourceType ResourceType_Script;
    ResourceType ResourceType_Shader;
    ResourceType ResourceType_Sound;
    ResourceType ResourceType_Tex1D;
    ResourceType ResourceType_Tex2D;
    ResourceType ResourceType_Tex3D;
    ResourceType ResourceType_TexCube;
  ]]
end

do -- Global Symbol Table
  ResourceType = {
    Font    = libphx.ResourceType_Font,
    Mesh    = libphx.ResourceType_Mesh,
    Other   = libphx.ResourceType_Other,
    Script  = libphx.ResourceType_Script,
    Shader  = libphx.ResourceType_Shader,
    Sound   = libphx.ResourceType_Sound,
    Tex1D   = libphx.ResourceType_Tex1D,
    Tex2D   = libphx.ResourceType_Tex2D,
    Tex3D   = libphx.ResourceType_Tex3D,
    TexCube = libphx.ResourceType_TexCube,
    COUNT   = 0xA,
    ToString = libphx.ResourceType_ToString,
  }

  if onDef_ResourceType then onDef_ResourceType(ResourceType, mt) end
  ResourceType = setmetatable(ResourceType, mt)
end

return ResourceType


text:
-- BoxMesh ---------------------------------------------------------------------
local ffi = require('ffi')
local libphx = require('ffi.libphx').lib
local BoxMesh

do -- C Definitions
  ffi.cdef [[
    BoxMesh* BoxMesh_Create  ();
    void     BoxMesh_Free    (BoxMesh*);
    void     BoxMesh_Add     (BoxMesh*, float px, float py, float pz, float sx, float sy, float sz, float rx, float ry, float rz, float bx, float by, float bz);
    Mesh*    BoxMesh_GetMesh (BoxMesh*, int res);
  ]]
end

do -- Global Symbol Table
  BoxMesh = {
    Create  = libphx.BoxMesh_Create,
    Free    = libphx.BoxMesh_Free,
    Add     = libphx.BoxMesh_Add,
    GetMesh = libphx.BoxMesh_GetMesh,
  }

  if onDef_BoxMesh then onDef_BoxMesh(BoxMesh, mt) end
  BoxMesh = setmetatable(BoxMesh, mt)
end

do -- Metatype for class instances
  local t  = ffi.typeof('BoxMesh')
  local mt = {
    __index = {
      managed = function (self) return ffi.gc(self, libphx.BoxMesh_Free) end,
      free    = libphx.BoxMesh_Free,
      add     = libphx.BoxMesh_Add,
      getMesh = libphx.BoxMesh_GetMesh,
    },
  }

  if onDef_BoxMesh_t then onDef_BoxMesh_t(t, mt) end
  BoxMesh_t = ffi.metatype(t, mt)
end

return BoxMesh


text:
-- Bit -------------------------------------------------------------------------
local ffi = require('ffi')
local libphx = require('ffi.libphx').lib
local Bit

do -- C Definitions
  ffi.cdef [[
    uint32 Bit_And32 (uint32 x, uint32 y);
    uint32 Bit_Or32  (uint32 x, uint32 y);
    uint32 Bit_Xor32 (uint32 x, uint32 y);
    bool   Bit_Has32 (uint32 x, uint32 y);
    uint64 Bit_And64 (uint64 x, uint64 y);
    uint64 Bit_Or64  (uint64 x, uint64 y);
    uint64 Bit_Xor64 (uint64 x, uint64 y);
    bool   Bit_Has64 (uint64 x, uint64 y);
  ]]
end

do -- Global Symbol Table
  Bit = {
    And32 = libphx.Bit_And32,
    Or32  = libphx.Bit_Or32,
    Xor32 = libphx.Bit_Xor32,
    Has32 = libphx.Bit_Has32,
    And64 = libphx.Bit_And64,
    Or64  = libphx.Bit_Or64,
    Xor64 = libphx.Bit_Xor64,
    Has64 = libphx.Bit_Has64,
  }

  if onDef_Bit then onDef_Bit(Bit, mt) end
  Bit = setmetatable(Bit, mt)
end

return Bit


text:
-- Metric ----------------------------------------------------------------------
local ffi = require('ffi')
local libphx = require('ffi.libphx').lib
local Metric

do -- C Definitions
  ffi.cdef [[
    int32 Metric_Get     (Metric);
    cstr  Metric_GetName (Metric);
  ]]
end

do -- Global Symbol Table
  Metric = {
    None       = 0x0,
    DrawCalls  = 0x1,
    Immediate  = 0x2,
    PolysDrawn = 0x3,
    TrisDrawn  = 0x4,
    VertsDrawn = 0x5,
    Flush      = 0x6,
    FBOSwap    = 0x7,
    SIZE       = 0x7,
    Get     = libphx.Metric_Get,
    GetName = libphx.Metric_GetName,
  }

  if onDef_Metric then onDef_Metric(Metric, mt) end
  Metric = setmetatable(Metric, mt)
end

return Metric


text:
-- Modifier --------------------------------------------------------------------
local ffi = require('ffi')
local libphx = require('ffi.libphx').lib
local Modifier

do -- C Definitions
  ffi.cdef [[
    cstr     Modifier_ToString (Modifier);
    Modifier Modifier_Null;
    Modifier Modifier_Alt;
    Modifier Modifier_Ctrl;
    Modifier Modifier_Shift;
  ]]
end

do -- Global Symbol Table
  Modifier = {
    Null  = libphx.Modifier_Null,
    Alt   = libphx.Modifier_Alt,
    Ctrl  = libphx.Modifier_Ctrl,
    Shift = libphx.Modifier_Shift,
    ToString = libphx.Modifier_ToString,
  }

  if onDef_Modifier then onDef_Modifier(Modifier, mt) end
  Modifier = setmetatable(Modifier, mt)
end

return Modifier


text:
-- BSPNodeRel ------------------------------------------------------------------
local ffi = require('ffi')
local libphx = require('ffi.libphx').lib
local BSPNodeRel

do -- C Definitions
  ffi.cdef [[
    BSPNodeRel BSPNodeRel_Parent;
    BSPNodeRel BSPNodeRel_Back;
    BSPNodeRel BSPNodeRel_Front;
  ]]
end

do -- Global Symbol Table
  BSPNodeRel = {
    Parent = libphx.BSPNodeRel_Parent,
    Back   = libphx.BSPNodeRel_Back,
    Front  = libphx.BSPNodeRel_Front,
  }

  if onDef_BSPNodeRel then onDef_BSPNodeRel(BSPNodeRel, mt) end
  BSPNodeRel = setmetatable(BSPNodeRel, mt)
end

return BSPNodeRel


text:
-- Socket ----------------------------------------------------------------------
local ffi = require('ffi')
local libphx = require('ffi.libphx').lib
local Socket

do -- C Definitions
  ffi.cdef [[
    Socket* Socket_Create      (SocketType);
    void    Socket_Free        (Socket*);
    void    Socket_Bind        (Socket*, int port);
    cstr    Socket_Read        (Socket*);
    Bytes*  Socket_ReadBytes   (Socket*);
    void    Socket_Write       (Socket*, cstr);
    void    Socket_WriteBytes  (Socket*, Bytes*);
    Socket* Socket_Accept      (Socket*);
    void    Socket_Listen      (Socket*);
    int     Socket_ReceiveFrom (Socket*, void* data, size_t len);
    cstr    Socket_GetAddress  (Socket*);
    void    Socket_SetAddress  (Socket*, cstr addr);
    int     Socket_SendTo      (Socket*, void const* data, size_t len);
  ]]
end

do -- Global Symbol Table
  Socket = {
    Create      = libphx.Socket_Create,
    Free        = libphx.Socket_Free,
    Bind        = libphx.Socket_Bind,
    Read        = libphx.Socket_Read,
    ReadBytes   = libphx.Socket_ReadBytes,
    Write       = libphx.Socket_Write,
    WriteBytes  = libphx.Socket_WriteBytes,
    Accept      = libphx.Socket_Accept,
    Listen      = libphx.Socket_Listen,
    ReceiveFrom = libphx.Socket_ReceiveFrom,
    GetAddress  = libphx.Socket_GetAddress,
    SetAddress  = libphx.Socket_SetAddress,
    SendTo      = libphx.Socket_SendTo,
  }

  if onDef_Socket then onDef_Socket(Socket, mt) end
  Socket = setmetatable(Socket, mt)
end

do -- Metatype for class instances
  local t  = ffi.typeof('Socket')
  local mt = {
    __index = {
      managed     = function (self) return ffi.gc(self, libphx.Socket_Free) end,
      create      = libphx.Socket_Create,
      free        = libphx.Socket_Free,
      bind        = libphx.Socket_Bind,
      read        = libphx.Socket_Read,
      readBytes   = libphx.Socket_ReadBytes,
      write       = libphx.Socket_Write,
      writeBytes  = libphx.Socket_WriteBytes,
      accept      = libphx.Socket_Accept,
      listen      = libphx.Socket_Listen,
      receiveFrom = libphx.Socket_ReceiveFrom,
      getAddress  = libphx.Socket_GetAddress,
      setAddress  = libphx.Socket_SetAddress,
      sendTo      = libphx.Socket_SendTo,
    },
  }

  if onDef_Socket_t then onDef_Socket_t(t, mt) end
  Socket_t = ffi.metatype(t, mt)
end

return Socket


text:
-- InputEvent ------------------------------------------------------------------
local ffi = require('ffi')
local libphx = require('ffi.libphx').lib
local InputEvent

do -- C Definitions
  ffi.cdef [[
    cstr InputEvent_ToString (InputEvent*);
  ]]
end

do -- Global Symbol Table
  InputEvent = {
    ToString = libphx.InputEvent_ToString,
  }

  local mt = {
    __call  = function (t, ...) return InputEvent_t(...) end,
  }

  if onDef_InputEvent then onDef_InputEvent(InputEvent, mt) end
  InputEvent = setmetatable(InputEvent, mt)
end

do -- Metatype for class instances
  local t  = ffi.typeof('InputEvent')
  local mt = {
    __tostring = function (self) return ffi.string(libphx.InputEvent_ToString(self)) end,
    __index = {
      clone    = function (x) return InputEvent_t(x) end,
      toString = libphx.InputEvent_ToString,
    },
  }

  if onDef_InputEvent_t then onDef_InputEvent_t(t, mt) end
  InputEvent_t = ffi.metatype(t, mt)
end

return InputEvent


text:
-- PointClassification ---------------------------------------------------------
local ffi = require('ffi')
local libphx = require('ffi.libphx').lib
local PointClassification

do -- Global Symbol Table
  PointClassification = {
    InFront  = 1,
    Behind   = 2,
    Coplanar = 3,
  }

  if onDef_PointClassification then onDef_PointClassification(PointClassification, mt) end
  PointClassification = setmetatable(PointClassification, mt)
end

return PointClassification


text:
-- Vec4f -----------------------------------------------------------------------
local ffi = require('ffi')
local libphx = require('ffi.libphx').lib
local Vec4f

do -- Global Symbol Table
  Vec4f = {
  }

  local mt = {
    __call  = function (t, ...) return Vec4f_t(...) end,
  }

  if onDef_Vec4f then onDef_Vec4f(Vec4f, mt) end
  Vec4f = setmetatable(Vec4f, mt)
end

do -- Metatype for class instances
  local t  = ffi.typeof('Vec4f')
  local mt = {
    __index = {
      clone = function (x) return Vec4f_t(x) end,
    },
  }

  if onDef_Vec4f_t then onDef_Vec4f_t(t, mt) end
  Vec4f_t = ffi.metatype(t, mt)
end

return Vec4f


text:
-- Box3d -----------------------------------------------------------------------
local ffi = require('ffi')
local libphx = require('ffi.libphx').lib
local Box3d

do -- Global Symbol Table
  Box3d = {
  }

  local mt = {
    __call  = function (t, ...) return Box3d_t(...) end,
  }

  if onDef_Box3d then onDef_Box3d(Box3d, mt) end
  Box3d = setmetatable(Box3d, mt)
end

do -- Metatype for class instances
  local t  = ffi.typeof('Box3d')
  local mt = {
    __index = {
      clone = function (x) return Box3d_t(x) end,
    },
  }

  if onDef_Box3d_t then onDef_Box3d_t(t, mt) end
  Box3d_t = ffi.metatype(t, mt)
end

return Box3d


text:
-- IntersectSphereProfiling ----------------------------------------------------
local ffi = require('ffi')
local libphx = require('ffi.libphx').lib
local IntersectSphereProfiling

do -- Global Symbol Table
  IntersectSphereProfiling = {
  }

  local mt = {
    __call  = function (t, ...) return IntersectSphereProfiling_t(...) end,
  }

  if onDef_IntersectSphereProfiling then onDef_IntersectSphereProfiling(IntersectSphereProfiling, mt) end
  IntersectSphereProfiling = setmetatable(IntersectSphereProfiling, mt)
end

do -- Metatype for class instances
  local t  = ffi.typeof('IntersectSphereProfiling')
  local mt = {
    __index = {
      clone = function (x) return IntersectSphereProfiling_t(x) end,
    },
  }

  if onDef_IntersectSphereProfiling_t then onDef_IntersectSphereProfiling_t(t, mt) end
  IntersectSphereProfiling_t = ffi.metatype(t, mt)
end

return IntersectSphereProfiling


text:
-- RigidBody -------------------------------------------------------------------
local ffi = require('ffi')
local libphx = require('ffi.libphx').lib
local RigidBody

do -- C Definitions
  ffi.cdef [[
    RigidBody* RigidBody_CreateBox                   ();
    RigidBody* RigidBody_CreateBoxFromMesh           (Mesh*);
    RigidBody* RigidBody_CreateSphere                ();
    RigidBody* RigidBody_CreateSphereFromMesh        (Mesh*);
    RigidBody* RigidBody_CreateHullFromMesh          (Mesh*);
    void       RigidBody_Free                        (RigidBody*);
    void       RigidBody_ApplyForce                  (RigidBody*, Vec3f*);
    void       RigidBody_ApplyTorque                 (RigidBody*, Vec3f*);
    void       RigidBody_Attach                      (RigidBody*, RigidBody* other, Vec3f*, Quat*);
    void       RigidBody_Detach                      (RigidBody*, RigidBody* other);
    void       RigidBody_GetBoundingBox              (RigidBody*, Box3f*);
    void       RigidBody_GetBoundingBoxCompound      (RigidBody*, Box3f*);
    void       RigidBody_GetBoundingBoxLocal         (RigidBody*, Box3f*);
    void       RigidBody_GetBoundingBoxLocalCompound (RigidBody*, Box3f*);
    float      RigidBody_GetBoundingRadius           (RigidBody*);
    float      RigidBody_GetBoundingRadiusCompound   (RigidBody*);
    RigidBody* RigidBody_GetParentBody               (RigidBody*);
    float      RigidBody_GetSpeed                    (RigidBody*);
    Matrix*    RigidBody_GetToLocalMatrix            (RigidBody*);
    Matrix*    RigidBody_GetToWorldMatrix            (RigidBody*);
    void       RigidBody_GetVelocity                 (RigidBody*, Vec3f*);
    void       RigidBody_GetVelocityA                (RigidBody*, Vec3f*);
    void       RigidBody_SetCollidable               (RigidBody*, bool);
    void       RigidBody_SetCollisionGroup           (RigidBody*, int);
    void       RigidBody_SetCollisionMask            (RigidBody*, int);
    void       RigidBody_SetDrag                     (RigidBody*, float linear, float angular);
    void       RigidBody_SetFriction                 (RigidBody*, float);
    void       RigidBody_SetKinematic                (RigidBody*, bool);
    void       RigidBody_SetRestitution              (RigidBody*, float);
    void       RigidBody_SetSleepThreshold           (RigidBody*, float linear, float angular);
    float      RigidBody_GetMass                     (RigidBody*);
    void       RigidBody_SetMass                     (RigidBody*, float);
    void       RigidBody_GetPos                      (RigidBody*, Vec3f*);
    void       RigidBody_GetPosLocal                 (RigidBody*, Vec3f*);
    void       RigidBody_SetPos                      (RigidBody*, Vec3f*);
    void       RigidBody_SetPosLocal                 (RigidBody*, Vec3f*);
    void       RigidBody_GetRot                      (RigidBody*, Quat*);
    void       RigidBody_GetRotLocal                 (RigidBody*, Quat*);
    void       RigidBody_SetRot                      (RigidBody*, Quat*);
    void       RigidBody_SetRotLocal                 (RigidBody*, Quat*);
    float      RigidBody_GetScale                    (RigidBody*);
    void       RigidBody_SetScale                    (RigidBody*, float);
  ]]
end

do -- Global Symbol Table
  RigidBody = {
    CreateBox                   = libphx.RigidBody_CreateBox,
    CreateBoxFromMesh           = libphx.RigidBody_CreateBoxFromMesh,
    CreateSphere                = libphx.RigidBody_CreateSphere,
    CreateSphereFromMesh        = libphx.RigidBody_CreateSphereFromMesh,
    CreateHullFromMesh          = libphx.RigidBody_CreateHullFromMesh,
    Free                        = libphx.RigidBody_Free,
    ApplyForce                  = libphx.RigidBody_ApplyForce,
    ApplyTorque                 = libphx.RigidBody_ApplyTorque,
    Attach                      = libphx.RigidBody_Attach,
    Detach                      = libphx.RigidBody_Detach,
    GetBoundingBox              = libphx.RigidBody_GetBoundingBox,
    GetBoundingBoxCompound      = libphx.RigidBody_GetBoundingBoxCompound,
    GetBoundingBoxLocal         = libphx.RigidBody_GetBoundingBoxLocal,
    GetBoundingBoxLocalCompound = libphx.RigidBody_GetBoundingBoxLocalCompound,
    GetBoundingRadius           = libphx.RigidBody_GetBoundingRadius,
    GetBoundingRadiusCompound   = libphx.RigidBody_GetBoundingRadiusCompound,
    GetParentBody               = libphx.RigidBody_GetParentBody,
    GetSpeed                    = libphx.RigidBody_GetSpeed,
    GetToLocalMatrix            = libphx.RigidBody_GetToLocalMatrix,
    GetToWorldMatrix            = libphx.RigidBody_GetToWorldMatrix,
    GetVelocity                 = libphx.RigidBody_GetVelocity,
    GetVelocityA                = libphx.RigidBody_GetVelocityA,
    SetCollidable               = libphx.RigidBody_SetCollidable,
    SetCollisionGroup           = libphx.RigidBody_SetCollisionGroup,
    SetCollisionMask            = libphx.RigidBody_SetCollisionMask,
    SetDrag                     = libphx.RigidBody_SetDrag,
    SetFriction                 = libphx.RigidBody_SetFriction,
    SetKinematic                = libphx.RigidBody_SetKinematic,
    SetRestitution              = libphx.RigidBody_SetRestitution,
    SetSleepThreshold           = libphx.RigidBody_SetSleepThreshold,
    GetMass                     = libphx.RigidBody_GetMass,
    SetMass                     = libphx.RigidBody_SetMass,
    GetPos                      = libphx.RigidBody_GetPos,
    GetPosLocal                 = libphx.RigidBody_GetPosLocal,
    SetPos                      = libphx.RigidBody_SetPos,
    SetPosLocal                 = libphx.RigidBody_SetPosLocal,
    GetRot                      = libphx.RigidBody_GetRot,
    GetRotLocal                 = libphx.RigidBody_GetRotLocal,
    SetRot                      = libphx.RigidBody_SetRot,
    SetRotLocal                 = libphx.RigidBody_SetRotLocal,
    GetScale                    = libphx.RigidBody_GetScale,
    SetScale                    = libphx.RigidBody_SetScale,
  }

  if onDef_RigidBody then onDef_RigidBody(RigidBody, mt) end
  RigidBody = setmetatable(RigidBody, mt)
end

do -- Metatype for class instances
  local t  = ffi.typeof('RigidBody')
  local mt = {
    __index = {
      managed                     = function (self) return ffi.gc(self, libphx.RigidBody_Free) end,
      free                        = libphx.RigidBody_Free,
      applyForce                  = libphx.RigidBody_ApplyForce,
      applyTorque                 = libphx.RigidBody_ApplyTorque,
      attach                      = libphx.RigidBody_Attach,
      detach                      = libphx.RigidBody_Detach,
      getBoundingBox              = libphx.RigidBody_GetBoundingBox,
      getBoundingBoxCompound      = libphx.RigidBody_GetBoundingBoxCompound,
      getBoundingBoxLocal         = libphx.RigidBody_GetBoundingBoxLocal,
      getBoundingBoxLocalCompound = libphx.RigidBody_GetBoundingBoxLocalCompound,
      getBoundingRadius           = libphx.RigidBody_GetBoundingRadius,
      getBoundingRadiusCompound   = libphx.RigidBody_GetBoundingRadiusCompound,
      getParentBody               = libphx.RigidBody_GetParentBody,
      getSpeed                    = libphx.RigidBody_GetSpeed,
      getToLocalMatrix            = libphx.RigidBody_GetToLocalMatrix,
      getToWorldMatrix            = libphx.RigidBody_GetToWorldMatrix,
      getVelocity                 = libphx.RigidBody_GetVelocity,
      getVelocityA                = libphx.RigidBody_GetVelocityA,
      setCollidable               = libphx.RigidBody_SetCollidable,
      setCollisionGroup           = libphx.RigidBody_SetCollisionGroup,
      setCollisionMask            = libphx.RigidBody_SetCollisionMask,
      setDrag                     = libphx.RigidBody_SetDrag,
      setFriction                 = libphx.RigidBody_SetFriction,
      setKinematic                = libphx.RigidBody_SetKinematic,
      setRestitution              = libphx.RigidBody_SetRestitution,
      setSleepThreshold           = libphx.RigidBody_SetSleepThreshold,
      getMass                     = libphx.RigidBody_GetMass,
      setMass                     = libphx.RigidBody_SetMass,
      getPos                      = libphx.RigidBody_GetPos,
      getPosLocal                 = libphx.RigidBody_GetPosLocal,
      setPos                      = libphx.RigidBody_SetPos,
      setPosLocal                 = libphx.RigidBody_SetPosLocal,
      getRot                      = libphx.RigidBody_GetRot,
      getRotLocal                 = libphx.RigidBody_GetRotLocal,
      setRot                      = libphx.RigidBody_SetRot,
      setRotLocal                 = libphx.RigidBody_SetRotLocal,
      getScale                    = libphx.RigidBody_GetScale,
      setScale                    = libphx.RigidBody_SetScale,
    },
  }

  if onDef_RigidBody_t then onDef_RigidBody_t(t, mt) end
  RigidBody_t = ffi.metatype(t, mt)
end

return RigidBody


text:
#!/usr/local/bin/luajit

local LIBPATH = arg[1]
local LIBNAME = arg[2]
local OUTPATH = arg[3]
local VERBOSE = arg[4]

local insert = table.insert
local remove = table.remove
local join   = table.concat

local function format (str, ...)
  local index, args = 0, { ... }
  local function replaceStar (match)
    index = index + 1
    return match:gsub('%*', function (star)
      return remove(args, index)
    end)
  end

  -- NOTE : %d*%*? should be %d*|%*? but Lua doesn't support |
  str = str:gsub('%%[-+ #0]?%d*%*?%.?%d*%*?', replaceStar)
  return string.format(str, unpack(args))
end

local function appendf(t, fmt, ...) insert(t, format(fmt, ...)) end
local function logf(fmt, ...) if VERBOSE then print('  '..format(fmt, ...)) end end
local function warnf(fmt, ...) print('  Warning: '..format(fmt, ...)) end
local function errorf(fmt, ...) error(format(fmt, ...)) end

function listdir (root, recurse)
  local root = root:gsub('/$','')
  local files = {}
  local recurse = recurse or true
  for file in lfs.dir(root) do
    if file ~= '.' and file ~= '..' then
      local path = root .. '/' .. file
      local mode = lfs.attributes(path, 'mode')
      if mode == 'file' then
        files[#files + 1] = path
      elseif recurse and mode == 'directory' then
        local result = listdir(path, recurse)
        for i = 1, #result do files[#files + 1] = result[i] end
      end
    end
  end
  table.sort(files)
  return files
end

local isenum = {}
local isopaque = {}
local isstruct = {}

local scopes = {}
local enums = {}
local opaques = {}
local structs = {}
local typedefs = {}
local funcPtrs = {}

local maxScope = 0
local maxOpaque = 0
local maxTypedef = 0
local maxFuncPtr = 0
local maxFuncPtrRet = 0

local function getScope (name)
  for _, scope in ipairs(scopes) do
    if scope.name == name then
      return scope
    end
  end

  insert(scopes, {
    name = name,
    elems = {},
    enums = {},
    maxName = 0,
    maxSymbol = 0,
    maxType = 0,
  })
  maxScope = math.max(maxScope, #name)
  return scopes[#scopes]
end

local function getEnumScope (name, enums)
  for _, enum in ipairs(enums) do
    if enum.name == name then
      return enum
     end
  end

  insert(enums, {
    name = name,
    keys = {},
    subscopes = {},
    maxKey = 0,
  })
  return enums[#enums]
end

local function getStruct(name)
  for _, struct in ipairs(structs) do
    if struct.name == name then
      return struct
    end
  end

  insert(structs, {
    name = name,
    fields = {},
    dependencies = {},
    maxFieldType = 0,
    nPreprocessor = 0,
  })
  return structs[#structs]
end

local function parseOpaque (symbol)
  if not isopaque[symbol] then
    isopaque[symbol] = true
    insert(opaques, symbol)
    maxOpaque = math.max(maxOpaque, #symbol)
  end
end

local function parseStructDef (name)
  if not isstruct[name] then
    isstruct[name] = true
    getStruct(name)
    getScope(name)
  end
end

local function parseStructField (struct, line)
  local pType, fPtr, fName, fArray = line:match('([%w_]+)([%s%*]*)([%w_]+) ?(%[? ?%d*% ?]?)')
  fArray = fArray:gsub('%s', '')
  fPtr = fPtr:gsub('%s', '')

  local fType = pType..fPtr
  insert(struct.fields, {
    name = fName..fArray,
    type = fType,
    pType = pType,
    isPtr = fPtr ~= '',
    isArray = fArray ~= '',
  })
end

local function parseStructMacro (struct, macro, args)
  if macro == 'ArrayList' then
    local fType, fName = args:match('(%g+) ?, ?(%g+)')
    parseStructField(struct, format('int32 %s_size;', fName))
    parseStructField(struct, format('int32 %s_capacity;', fName))
    parseStructField(struct, format('%s* %s_data;', fType, fName))

  else
    warnf('Unrecognized macro %s in transparent struct %s', macro, struct.name)
  end
end

local function parseStruct (name, body)
  --[[ NOTE : Struct parsing is super naive. Parsing is lexical, not syntactic.
              We don't handle anything funky like unions, nested structs, etc.
              Const pointers are not handled. Arrays of transparent structs are
              not expanded. ArrayList is special cased. ]]

  local struct = getStruct(name)

  -- Remove Preprocessor Directives
  body, n1 = body:gsub('#.-\n', '')
  body, n2 = body:gsub('#[^\n]*$', '')
  struct.nPreprocessor = n1 + n2

  -- Remove Extra Space
  body = body:gsub('%s+', ' ')

  for line in body:gmatch('.-;') do
    -- Expand Macros
    local macro, args = line:match('(%g+) ?%((.-)%) ?;')
    if macro then
      parseStructMacro(struct, macro, args)

    -- Expand Comma Separated Declarations
    elseif line:find(',') then
      local fType = line:match('^ ?([%w_]+)')
      local fields = line:gsub(',', format('; %s', fType))
      for subline in fields:gmatch('.-;') do
        parseStructField(struct, subline)
      end

    -- Regular Declaration
    else
      parseStructField(struct, line)
    end
  end
end

local function parseEnumDef (name)
  if not isenum[name] then
    isenum[name] = true
    local scope = getScope(name)
    local enumScope = getEnumScope(name, enums)
    insert(scope.enums, enumScope)
  end
end

local function parseEnum (type, symbol)
  local eName, eKey = symbol:match('^(%g-)_(%g+)$')
  if not eName or not eKey then return end
  local scope = getScope(eName)
  local enumScope = getEnumScope(eName, enums)
  insert(scope.elems, {
    name = eKey,
    kind = 'enum',
    type = type,
    symbol = symbol,
  })
  scope.maxSymbol = math.max(scope.maxSymbol, #symbol)
  scope.maxType = math.max(scope.maxType, #type)

  for eSubName2, eKey2 in eKey:gmatch('(%g-)_(%g+)$') do
    eSubName, eKey = eSubName2, eKey2
    enumScope = getEnumScope(eSubName, enumScope.subscopes)
  end

  insert(enumScope.keys, {
    name = eKey,
    symbol = symbol,
  })
  enumScope.maxKey = math.max(enumScope.maxKey, #eKey)
end

local function parseEnumConst (type, symbol, value)
  local eName, eKey = symbol:match('^(%g-)_(%g+)$')
  if not eName or not eKey then return end
  local enumScope = getEnumScope(eName, enums)

  for eSubName2, eKey2 in eKey:gmatch('(%g-)_(%g+)$') do
    eSubName, eKey = eSubName2, eKey2
    enumScope = getEnumScope(eSubName, enumScope.subscopes)
  end

  insert(enumScope.keys, {
    name = eKey,
    symbol = symbol,
    value = value,
  })
  enumScope.maxKey = math.max(enumScope.maxKey, #eKey)
end

local function parseMethod (retType, symbol, args)
  local sName, mName = symbol:match('^(%g-)_(%g+)$')
  if not sName or not mName then return end
  local scope = getScope(sName)
  insert(scope.elems, {
    name = mName,
    kind = 'method',
    type = retType,
    args = args:gsub('%s+', ' '),
    symbol = symbol,
  })
  scope.maxName = math.max(scope.maxName, #mName)
  scope.maxSymbol = math.max(scope.maxSymbol, #symbol)
  scope.maxType = math.max(scope.maxType, #retType)
end

local function parseTypedef (src, dst)
  maxTypedef = math.max(maxTypedef, #src)
  insert(typedefs, {
    src = src,
    dst = dst
  })
end

local function parseFuncPtr (retType, name, args)
  insert(funcPtrs, {
    name = name,
    retType = retType,
    args = args,
  })
  maxFuncPtr = math.max(maxFuncPtr, #name)
  maxFuncPtrRet = math.max(maxFuncPtrRet, #retType)
end

local function parseFile (path)
  local contents = io.open(path, 'rb'):read('*all')
  if contents:find('__FFI_IGNORE__') then return end

  -- Remove Comments
  contents = contents:gsub('//.-\n', '')
  contents = contents:gsub('/%*..-%*/', '')

  contents:gsub('PHX_API%s+(%g+)%s+(%g+)%s*%((.-)%);', parseMethod)
  contents:gsub('ENUM_T[%g ]- (%g+);', parseEnumDef)
  contents:gsub('PHX_API%s+const%s+(%g+)%s+(%g+);', parseEnum)
  contents:gsub('const%s+(%g+)%s+(%g+)%s+=%s+(%g+);', parseEnumConst)
  contents:gsub('OPAQUE_T%s+(%g+);', parseOpaque)
  contents:gsub('STRUCT_T%s+(%g+);', parseStructDef)
  contents:gsub('struct%s+(%g+)%s+{%s+(.-)%s+};', parseStruct)
  contents:gsub('typedef%s+([^%(%)]-)%s+(%g+)%s*;', parseTypedef)
  contents:gsub('typedef%s+(%g+)%s%(%*([%w_]+)%)%((.-)%)%s*;', parseFuncPtr)
end

local function flattenStruct (struct)
  local didFlatten = false
  for _, field in ipairs(struct.fields) do
    if isstruct[field.type] then
      didFlatten = true
      flattenStruct(getStruct(field.type))
    end
  end

  if didFlatten then
    local newFields = {}
    for _, field in ipairs(struct.fields) do
      if isstruct[field.type] and not field.isArray then
        local subFields = getStruct(field.type).fields
        for _, subField in ipairs(subFields) do
          insert(newFields, {
            name = field.name..subField.name,
            type = subField.type,
          })
        end
      else
        insert(newFields, field)
      end
    end
    struct.fields = newFields
  end
end

local function extraProcessing ()
  table.sort(structs, function (a, b) return a.name < b.name end)

  for name, _ in pairs(isstruct) do
    local struct = getStruct(name)
    -- HACK : I don't feel like rewriting RigidBody.lua
    if name ~= 'RigidBody' then
      flattenStruct(struct)
    end

    -- Issue Warnings
    if #struct.fields == 0 then
      warnf("Struct '%s' marked as transparent but no definition found.", struct.name)
    end
    if struct.nPreprocessor > 0 then
      warnf("Transparent struct '%s' contains preprocessor directives. "
        .."Cannot guarantee the Lua binding will be correct.", struct.name)
    end

    local function indexOf (t, predicateFn)
      for i = 1, #t do
        if predicateFn(t[i]) then return i end
      end
      return 0
    end

    -- Handle Dependencies
    for _, field in ipairs(struct.fields) do
      if isstruct[field.pType] then
        if field.isPtr then
          field.type = 'struct '..field.type
        else
          --[[ NOTE : Dependencies only occur when a field is an array of
                      another transparent struct. Later, if we flatten array
                      this can go away. ]]
          -- BUG : This should be done in a loop until no moves occur.
          insert(struct.dependencies, field.type)
          local iSelf = indexOf(structs, function (s) return s.name == struct.name end)
          local iDep  = indexOf(structs, function (s) return s.name == field.type end)
          if iDep > iSelf then insert(structs, iSelf, remove(structs, iDep)) end
        end
      end
      struct.maxFieldType = math.max(struct.maxFieldType, #field.type)
    end
  end
end

local function writeBindingsScope (scope)
  logf('Generating FFI bindings for %s...', scope.name)
  local file = io.open(format('%s/%s.lua', OUTPATH, scope.name), 'wb')
  assert(file)

  local lines = {}
  appendf(lines, [[-- %s %s]], scope.name, string.rep('-', 76 - #scope.name))
  appendf(lines, "local ffi = require('ffi')")
  appendf(lines, "local %s = require('ffi.%s').lib", LIBNAME, LIBNAME)
  appendf(lines, 'local %s\n', scope.name)

  do -- ffi cdefs
    if #scope.elems > 0 then
      appendf(lines, 'do -- C Definitions')
      appendf(lines, '  ffi.cdef [[')
      for _, elem in ipairs(scope.elems) do
        if elem.args then
          appendf(lines, '    %-*s %-*s (%s);',
            scope.maxType, elem.type, scope.maxSymbol, elem.symbol, elem.args)
        else
          appendf(lines, '    %-*s %s;',
            scope.maxType, elem.type, elem.symbol)
        end
      end
      appendf(lines, '  ]]')
      appendf(lines, 'end\n')
    end
  end

  local function appendAll(t1, t2)
    for i = 1, #t2 do insert(t1, t2[i]) end
  end

  do -- scope table
    appendf(lines, 'do -- Global Symbol Table')
    appendf(lines, '  %s = {', scope.name)

    -- enums
    local function appendEnumKeys (lines, indent, enumScope)
      for _, key in ipairs(enumScope.keys) do
        if key.value then
          appendf(lines, '%*s%-*s = %s,',
            2*indent, '', enumScope.maxKey, key.name, key.value)
        else
          appendf(lines, '%*s%-*s = %s.%s,',
            2*indent, '', enumScope.maxKey, key.name, LIBNAME, key.symbol)
        end
      end
    end
    local function appendEnumScope (lines, indent, enumScope)
      appendf(lines, '%*s%s = {', 2*indent, '', enumScope.name)
      appendEnumKeys(lines, indent + 1, enumScope)
      for _, subscope in ipairs(enumScope.subscopes) do
        appendEnumScope(lines, indent + 1, subscope)
      end
      appendf(lines, '%*s},', 2*indent, '')
    end

    for _, enumScope in ipairs(scope.enums) do
      if isenum[enumScope.name] then
        if enumScope.name == scope.name then
          appendEnumKeys(lines, 2, enumScope)
          for _, subscope in ipairs(enumScope.subscopes) do
            appendEnumScope(lines, 2, subscope)
          end
        else
          appendEnumScope(lines, 2, enumScope)
        end
      end
    end

    -- non-enums
    for _, elem in ipairs(scope.elems) do
      if elem.kind ~= 'enum' then
        appendf(lines, '    %-*s = %s.%s,',
          scope.maxName, elem.name, LIBNAME, elem.symbol)
        end
    end
    appendf(lines, '  }\n')

    if isstruct[scope.name] then
      appendf(lines, '  local mt = {')
      appendf(lines, '    __call  = function (t, ...) return %s_t(...) end,', scope.name)
      appendf(lines, '  }\n')
    end

    appendf(lines, '  if onDef_%s then onDef_%s(%s, mt) end',
      scope.name, scope.name, scope.name)
    appendf(lines, '  %s = setmetatable(%s, mt)', scope.name, scope.name)
    appendf(lines, 'end\n')
  end

  -- metatype
  if isopaque[scope.name] or isstruct[scope.name] then
    local function isMethod (elem, scopeName)
      -- NOTE : Matches functions that take the arg by value or by reference
      return elem.args and elem.args:find('^%s*' .. scopeName)
    end
    local function toMethodName (name)
      return name:sub(1, 1):lower() .. name:sub(2)
    end
    appendf(lines, 'do -- Metatype for class instances')
    appendf(lines, "  local t  = ffi.typeof('%s')", scope.name)
    appendf(lines, '  local mt = {')
    for _, elem in ipairs(scope.elems) do
      if elem.name == 'ToString' then
        appendf(lines, '    __tostring = function (self) return ffi.string(%s.%s(self)) end,', LIBNAME, elem.symbol)
      end
    end
    appendf(lines, '    __index = {')
    if isstruct[scope.name] then
      appendf(lines, '      %-*s = function (x) return %s_t(x) end,',
          scope.maxName, 'clone', scope.name)
    end
    for _, elem in ipairs(scope.elems) do
      if elem.name == 'Free' then
        appendf(lines, '      %-*s = function (self) return ffi.gc(self, %s.%s) end,',
          scope.maxName, 'managed', LIBNAME, elem.symbol)
      end
    end
    for _, elem in ipairs(scope.elems) do
      if isMethod(elem, scope.name) then
        appendf(lines, '      %-*s = %s.%s,',
          scope.maxName, toMethodName(elem.name), LIBNAME, elem.symbol)
      end
    end
    appendf(lines, '    },')
    appendf(lines, '  }\n')

    appendf(lines, '  if onDef_%s_t then onDef_%s_t(t, mt) end',
      scope.name, scope.name)
    appendf(lines, '  %s_t = ffi.metatype(t, mt)',
      scope.name, scope.name)
    appendf(lines, 'end\n')
  end

  appendf(lines, 'return %s\n', scope.name)

  lines = join(lines, '\n')
  file:write(lines)
  file:close()
end

local function writeBindingsInit ()
  local path = format('%s/%s.lua', OUTPATH, LIBNAME)
  local file = io.open(path, 'wb')
  if not file then errorf('Failed to open <%s> for writing', path) end

  local lines = {}
  appendf(lines, "local ffi = require('ffi')")
  appendf(lines, "local jit = require('jit')\n")
  appendf(lines, "local %s = {}", LIBNAME)

  do -- Typedefs
    appendf(lines, 'do -- Basic Typedefs')
    appendf(lines, '  ffi.cdef [[')
    for _, typedef in ipairs(typedefs) do
      appendf(lines, '    typedef %-*s %s;',
        maxTypedef, typedef.src, typedef.dst)
    end
    appendf(lines, '  ]]')
    appendf(lines, 'end\n')
  end

  do -- Function Pointers
    appendf(lines, 'do -- Function Pointer Typedefs')
    appendf(lines, '  ffi.cdef [[')
    for _, fPtr in ipairs(funcPtrs) do
      appendf(lines, '    typedef %-*s (*%-*s) (%s);',
        maxFuncPtrRet, fPtr.retType, maxFuncPtr, fPtr.name, fPtr.args)
    end
    appendf(lines, '  ]]')
    appendf(lines, 'end\n')
  end

  do -- Opaques
    appendf(lines, 'do -- Opaque Structs')
    appendf(lines, '  ffi.cdef [[')
    for _, opaque in ipairs(opaques) do
      appendf(lines, '    typedef struct %-*s {} %s;',
        maxOpaque, opaque, opaque)
    end
    appendf(lines, '  ]]\n')

    if true then -- Opaque List
      appendf(lines, '  %s.Opaques = {', LIBNAME)
      for _, opaque in ipairs(opaques) do
        appendf(lines, "    '%s',", opaque)
      end
      appendf(lines, '  }')
    end
    appendf(lines, 'end\n')
  end

  do -- Transparents
    appendf(lines, 'do -- Transparent Structs')
    appendf(lines, '  ffi.cdef [[')
    for i, struct in ipairs(structs) do
      if isstruct[struct.name] then
        appendf(lines, '    typedef struct %s {', struct.name)
        for _, field in ipairs(struct.fields) do
          appendf(lines, '      %-*s %s;',
            struct.maxFieldType, field.type, field.name)
        end
        appendf(lines, '    } %s;', struct.name)
        if i < #structs then appendf(lines, '') end
      end
    end
    appendf(lines, '  ]]\n')

    if true then -- Transparent List
      appendf(lines, '  %s.Structs = {', LIBNAME)
      for _, struct in ipairs(structs) do
        if isstruct[struct.name] then
          appendf(lines, "    '%s',", struct.name)
        end
      end
      appendf(lines, '  }')
    end

    appendf(lines, 'end\n')
  end

  do -- load dll
    appendf(lines, 'do -- Load Library')
    appendf(lines, "  local debug = __debug__ and 'd' or ''")
    appendf(lines, "  local arch = jit.arch == 'x86' and '32' or '64'")
    appendf(lines, "  local path = string.format('%s%%s%%s', arch, debug)", LIBNAME)
    appendf(lines, '  %s.lib = ffi.load(path, false)', LIBNAME)
    appendf(lines, "  assert(%s.lib, 'Failed to load %%s', path)", LIBNAME)
    -- appendf(lines, '  _G.%s = %s.lib', LIBNAME, LIBNAME)
    appendf(lines, 'end\n')
  end

  appendf(lines, 'return %s\n', LIBNAME)

  lines = join(lines, '\n')
  file:write(lines)
  file:close()
end

local function emptyDir (path)
  if lfs.attributes(path, 'mode') == 'directory' then
    local iter, dirObj = lfs.dir(path)
    while true do
      local fileName = iter(dirObj)
      if not fileName then break end
      if fileName:match('%.lua$') then
        os.remove(path..'/'..fileName)
      end
    end
  end
end

local function writeBindings ()
  lfs.mkdir(OUTPATH)
  emptyDir(OUTPATH)
  table.sort(scopes, function (a, b) return a.name < b.name end)
  table.sort(opaques)
  writeBindingsInit()
  for i = 1, #scopes do
    writeBindingsScope(scopes[i])
  end
end

local files = listdir(LIBPATH)
for i = 1, #files do parseFile(files[i]) end
extraProcessing()
writeBindings()

--[[ IMPORTANT
  TODO : Auto-wrap functions that take transparent structs by pointer (THIS WILL SAVE SO MUCH WORK IN BINDING EXTENSIONS)
  TODO : Flattening struct will introduce alignment issues if the alignment
         of the struct is not the same as the alignment of the first field
         within it.
  TODO : Better const* handling (robust parsing in struct fields and argument lists)
  TODO : Think about what to do with arrays of structs
--]]

-- TODO : Emit operators for *_Mul, Div, Add, and Sub
-- TODO : Don't interpret functions with a single out parameter as methods (e.g. Quat_Identity)
-- TODO : Can/should we build automatic ToString methods for structs?
-- TODO : Don't emit bindings for empty scopes (and warn?)
-- TODO : Use Log.Warning/Error? (Also LTEdit)
-- TODO : Parse normal typedefs and enums separately
-- TODO : Find some way to associate a metatype with typedefs of primitives
-- TODO : It would be better to parse the preprocessed files
-- TODO : Silent failure when it doesn't find libphx
-- TODO : Better verbose option
-- TODO : Success/failure output
-- TODO : Better indent handling

--[[ NOTE : It would be nice to define transparent structs in their respective
            binding files, rather than in libphx.ffi.lua, but we'd have to do
            extra work to ensure dependencies are loaded first. ]]

--[[ NOTE : Metatables associated with FFI metatypes are NOT modifiable once
            created. Extension scripts must be loaded before bindings are
            created and applied during creation. ]]


text:
#ifndef PHX_HashMap
#define PHX_HashMap

#include "Common.h"

/* --- API NOTES ---------------------------------------------------------------
 *
 *   HashMap provides (amortized) O(1) value lookups for arbitrary key types.
 *   Since key length must be provided at creation time, any given HashMap is
 *   essentially parametrized by a single key type (HashMap<T>).
 *
 *   WARNING : This HashMap API is designed for speed rather than guaranteed
 *             accuracy. It does not store the key, but rather a 64-bit hash
 *             thereof. This trade-off allows for extreme speed and compactness
 *             compared to non-lossy maps. However, it also introduces a non-
 *             negligible probability of collision events causing the map to
 *             incorrectly return a false positive or to replace an element
 *             with another that has a different (hash-colliding) key. One can
 *             expect such an error to occur roughly once per 2^32 mappings.
 *
 *   NOTE : Remove is not yet implemented. It is very difficult to implement
 *          efficiently :) Besides, this map is so fast that you probably
 *          should just create and tear a new one down every time you need it.
 *
 * ---------------------------------------------------------------------------*/

typedef void (*ValueForeach)(void* value, void* userData);

PHX_API HashMap*  HashMap_Create   (uint32 keySize, uint32 capacity);
PHX_API void      HashMap_Free     (HashMap*);

PHX_API void      HashMap_Foreach  (HashMap*, ValueForeach, void* userData);
PHX_API void*     HashMap_Get      (HashMap*, void const* key);
PHX_API void*     HashMap_GetRaw   (HashMap*, uint64 keyHash);
PHX_API void      HashMap_Resize   (HashMap*, uint32 capacity);
PHX_API void      HashMap_Set      (HashMap*, void const* key, void* value);
PHX_API void      HashMap_SetRaw   (HashMap*, uint64 keyHash, void* value);

#endif


text:
#ifndef PHX_String
#define PHX_String

#include "Common.h"

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

inline char*   StrAlloc     (size_t len);
inline void    StrFree      (cstr s);
inline cstr    StrAdd       (cstr a, cstr b);
inline cstr    StrAdd3      (cstr a, cstr b, cstr c);
inline cstr    StrAdd4      (cstr a, cstr b, cstr c, cstr d);
inline cstr    StrAppend    (cstr a, cstr b);
inline bool    StrBegins    (cstr s, cstr prefix);
inline int     StrCount     (cstr s, cstr sub);
inline bool    StrContains  (cstr s, cstr sub);
inline void    StrCpy       (cstr dst, cstr src);
inline cstr    StrDup       (cstr s);
inline bool    StrEqual     (cstr a, cstr b);
inline cstr    StrFind      (cstr s, cstr sub);
inline cstr    StrFormat    (cstr fmt, ...);
inline size_t  StrLen       (cstr s);
inline cstr    StrLower     (cstr s);
inline bool    StrMatch     (cstr s, cstr pattern);
inline cstr    StrReplace   (cstr s, cstr search, cstr replace);
inline int     StrSplit     (cstr s, cstr delim, cstr** out);
inline cstr    StrSub       (cstr s, cstr begin, cstr end, cstr replace);
inline cstr    StrSubStr    (cstr begin, cstr end);
inline cstr    StrUpper     (cstr s);

/* -------------------------------------------------------------------------- */

inline char* StrAlloc (size_t len) {
  return (char*)malloc(len);
}

inline void StrFree (cstr s) {
  free((void*)s);
}

inline cstr StrAdd (cstr a, cstr b) {
  char* buf = StrAlloc(StrLen(a) + StrLen(b) + 1);
  char* cur = buf;
  while (*a) *cur++ = *a++;
  while (*b) *cur++ = *b++;
  *cur = 0;
  return buf;
}

inline cstr StrAdd3 (cstr a, cstr b, cstr c) {
  char* buf = StrAlloc(StrLen(a) + StrLen(b) + StrLen(c) + 1);
  char* cur = buf;
  while (*a) *cur++ = *a++;
  while (*b) *cur++ = *b++;
  while (*c) *cur++ = *c++;
  *cur = 0;
  return buf;
}

inline cstr StrAdd4 (cstr a, cstr b, cstr c, cstr d) {
  char* buf = StrAlloc(StrLen(a) + StrLen(b) + StrLen(c) + StrLen(d) + 1);
  char* cur = buf;
  while (*a) *cur++ = *a++;
  while (*b) *cur++ = *b++;
  while (*c) *cur++ = *c++;
  while (*d) *cur++ = *d++;
  *cur = 0;
  return buf;
}

/* NOTE: Consumes a. */
inline cstr StrAppend (cstr a, cstr b) {
  cstr c = StrAdd(a, b);
  StrFree(a);
  return c;
}

inline bool StrBegins (cstr s, cstr prefix) {
  for (; ; s++, prefix++)
    if (!*prefix)
      return true;
    else if (*s != *prefix)
      return false;
}

inline int StrCount (cstr s, cstr sub) {
  size_t n = StrLen(sub);
  int count;
  for (count = 0; (s = strstr(s, sub)); ++count) s += n;
  return count;
}

inline bool StrContains (cstr s, cstr sub) {
  return strstr(s, sub) != 0;
}

inline void StrCpy (cstr pDst, cstr src) {
  char* dst = (char*)pDst;
  while (*src)
    *dst++ = *src++;
  *dst = 0;
}

inline cstr StrDup (cstr s) {
  if (!s) return 0;
  size_t len = StrLen(s) + 1;
  char* buf = StrAlloc(len);
  memcpy(buf, s, len);
  return buf;
}

inline bool StrEqual (cstr a, cstr b) {
  return strcmp(a, b) == 0;
}

inline cstr StrFind (cstr s, cstr sub) {
  return strstr(s, sub);
}

inline cstr StrFormat (cstr fmt, ...) {
  va_list args;
  va_start(args, fmt);
  size_t len = vsnprintf(0, 0, fmt, args) + 1;
  va_end(args);
  char* buf = StrAlloc(len);
  va_start(args, fmt);
  vsnprintf(buf, len, fmt, args);
  va_end(args);
  return buf;
}

inline size_t StrLen (cstr s) {
  if (!s) return 0;
  cstr begin = s;
  while (*s)
    ++s;
  return s - begin;
}

inline cstr StrLower (cstr ps) {
  char* s = (char*)ps;
  for (size_t i = 0, n = StrLen(s); i < n; ++i)
    if (isupper(s[i]))
      s[i] |= 0x20;
  return s;
}

inline bool StrMatch (cstr s, cstr p) {
  /* NOTE: An empty p will only match an empty string.
   *       Wildcards can match zero characters.
   *       Wildcards are non-greedy, but will grow as necessary.
   *       There is no way to match a literal '*' or '?'.
   *       If the parameters are swapped, this will fail somewhat silently.
   *
   *       This is not guaranteed to work for complex, multi-asterisk patterns.
   *       I believe it will produce false negatives in some (rare) cases.
   *       https://leetcode.com/problems/wildcard-matching/#/solutions (first one)
   *       http://yucoding.blogspot.com/2013/02/leetcode-question-123-wildcard-matching.html
   *
   *       If this ends up being insufficient, I believe a non-deterministic finite
   *       automata is the next step up.
   *       https://swtch.com/~rsc/regexp/regexp1.html */

  if (!s || !p) return false;

  const char* star = 0;
  const char* ss   = s;

  while (*s) {
    if ((*p == '?') || (*p == *s)) { s++; p++;               continue; }
    if (*p == '*')                 { star = p++; ss = s;     continue; }
    if (star)                      { p = star + 1; s = ++ss; continue; }

    return false;
  }

  while (*p == '*') p++;
  return !*p;
}

inline cstr StrReplace (cstr s, cstr search, cstr replace) {
  char *result, *ins, *tmp;
  size_t len_search, len_replace, len_front, count;

  if (!s || !search) return 0;
  len_search = StrLen(search);
  if (len_search == 0) return 0;
  if (!replace) replace = "";
  len_replace = StrLen(replace);

  ins = (char*)s;
  for (count = 0; (tmp = strstr(ins, search)); ++count)
    ins = tmp + len_search;
  tmp = result = StrAlloc(StrLen(s) + (len_replace - len_search) * count + 1);

  while (count--) {
    ins = (char*)strstr(s, search);
    len_front = ins - s;
    tmp = strncpy(tmp, s, len_front) + len_front;
    tmp = strcpy(tmp, replace) + len_replace;
    s += len_front + len_search;
  }
  strcpy(tmp, s);
  return result;
}

inline int StrSplit (cstr s, cstr delim, cstr** out) {
  size_t len_orig = StrLen(s);
  int count = StrCount(s, delim);
  if (count == 0)
    return 0;

  *out = (cstr*)StrAlloc(sizeof(cstr) * (count + 1));
  size_t len_delim = StrLen(delim);
  cstr next;
  size_t i;
  for (i = 0; (next = strstr(s, delim)); ++i) {
    size_t sz = next - s;
    (*out)[i] = StrAlloc(sz + 1);
    memcpy((char*)(*out)[i], s, sz);
    ((char*)((*out)[i]))[sz] = 0;
    s = next + len_delim;
  }

  size_t remaining = len_orig - i;
  (*out)[count] = StrAlloc(remaining + 1);
  memcpy((char*)(*out)[count], s, remaining);
  ((char*)((*out)[count]))[remaining] = 0;
  return count + 1;
}

inline cstr StrSub (cstr s, cstr begin, cstr end, cstr replace) {
  size_t len = StrLen(s) + StrLen(replace) + begin - end;
  char* result = StrAlloc(len + 1);
  char* pResult = result;
  while (s != begin)
    *pResult++ = *s++;
  while (*replace)
    *pResult++ = *replace++;
  while (*end)
    *pResult++ = *end++;
  *pResult = 0;
  return result;
}

inline cstr StrSubStr (cstr begin, cstr end) {
  size_t len = (end - begin);
  char* result = StrAlloc(len + 1);
  char* pResult = result;
  while (begin != end)
    *pResult++ = *begin++;
  result[len] = 0;
  return result;
}

inline cstr StrUpper (cstr ps) {
  char* s = (char*)ps;
  for (size_t i = 0, n = StrLen(s); i < n; ++i)
    if (islower(s[i]))
      s[i] &= ~0x20;
  return s;
}

#endif


text:
#ifndef PHX_DeviceType
#define PHX_DeviceType

#include "Common.h"

PHX_API const DeviceType DeviceType_Null;
PHX_API const DeviceType DeviceType_Mouse;
PHX_API const DeviceType DeviceType_Keyboard;
PHX_API const DeviceType DeviceType_Gamepad;
const DeviceType DeviceType_COUNT = 4;

PHX_API DeviceType  DeviceType_FromButton  (Button);
PHX_API cstr        DeviceType_ToString    (DeviceType);

#endif


text:
#ifndef PHX_SoundDesc
#define PHX_SoundDesc

#include "Common.h"

/* --- Private API ---------------------------------------------------------- */

PRIVATE SoundDesc*  SoundDesc_Load         (cstr name, bool immediate, bool isLooped, bool is3D);
PRIVATE void        SoundDesc_FinishLoad   (SoundDesc*, cstr func);
PRIVATE void        SoundDesc_Acquire      (SoundDesc*);
PRIVATE void        SoundDesc_Free         (SoundDesc*);

PRIVATE float       SoundDesc_GetDuration  (SoundDesc*);
PRIVATE cstr        SoundDesc_GetName      (SoundDesc*);
PRIVATE cstr        SoundDesc_GetPath      (SoundDesc*);
PRIVATE void        SoundDesc_ToFile       (SoundDesc*, cstr);

#endif


text:
#ifndef PHX_BoxTree
#define PHX_BoxTree

#include "Common.h"
#include "Box3.h"

PHX_API BoxTree*  BoxTree_Create        ();
PHX_API BoxTree*  BoxTree_FromMesh      (Mesh*);
PHX_API void      BoxTree_Free          (BoxTree*);

PHX_API void      BoxTree_Add           (BoxTree*, Box3f bound, void* data);
PHX_API void      BoxTree_Draw          (BoxTree*, int maxDepth);
PHX_API int       BoxTree_GetMemory     (BoxTree*);
PHX_API bool      BoxTree_IntersectRay  (BoxTree*, Matrix*, Vec3f const* ro, Vec3f const* rd);

#endif


text:
#ifndef PHX_Box3
#define PHX_Box3

#include "Common.h"
#include "Vec3.h"

struct Box3i { Vec3i lower, upper; };
struct Box3f { Vec3f lower, upper; };
struct Box3d { Vec3d lower, upper; };

#define Box3_Create(T, sub) inline T T##_Create(sub lower, sub upper) { \
  T result = { lower, upper }; return result; }

Box3_Create(Box3i, Vec3i)
Box3_Create(Box3f, Vec3f)
Box3_Create(Box3d, Vec3d)

#define Box3_Add(T, sub) inline void T##_Add(T* NO_ALIAS self, sub point) { \
  self->lower = sub##_Min(self->lower, point); \
  self->upper = sub##_Max(self->upper, point); }

Box3_Add(Box3i, Vec3i)
Box3_Add(Box3f, Vec3f)
Box3_Add(Box3d, Vec3d)

#define Box3_Center(T, sub) inline sub T##_Center(T self) { \
  sub center = { \
    (self.lower.x + self.upper.x) / 2, \
    (self.lower.y + self.upper.y) / 2, \
    (self.lower.z + self.upper.z) / 2 }; return center; }

Box3_Center(Box3f, Vec3f)
Box3_Center(Box3d, Vec3d)

#define Box3_ContainsBox(T) inline bool T##_ContainsBox(T a, T b) { \
  return a.lower.x <= b.lower.x && a.upper.x >= b.upper.x && \
         a.lower.y <= b.lower.y && a.upper.y >= b.upper.y && \
         a.lower.z <= b.lower.z && a.upper.z >= b.upper.z; }

Box3_ContainsBox(Box3i)
Box3_ContainsBox(Box3f)
Box3_ContainsBox(Box3d)

#define Box3_Extents(T, TVec) inline TVec T##_Extents(T self) { \
  return TVec##_Abs(TVec##_Sub(self.upper, self.lower)); }
Box3_Extents(Box3i, Vec3i)
Box3_Extents(Box3f, Vec3f)
Box3_Extents(Box3d, Vec3d)

#define Box3_HalfExtents(T, TVec) inline TVec T##_HalfExtents(T self) { \
  return TVec##_Muls(TVec##_Abs(TVec##_Sub(self.upper, self.lower)), 0.5f); }
//Box3_HalfExtents(Box3i, Vec3i)
Box3_HalfExtents(Box3f, Vec3f)
Box3_HalfExtents(Box3d, Vec3d)

#define Box3_Intersection(T) inline T T##_Intersection(T a, T b) { \
  T self = { \
    { Max(a.lower.x, b.lower.x), Max(a.lower.y, b.lower.y), Max(a.lower.z, b.lower.z) }, \
    { Min(a.upper.x, b.upper.x), Min(a.upper.y, b.upper.y), Min(a.upper.z, b.upper.z) }, \
  }; return self; }

Box3_Intersection(Box3i)
Box3_Intersection(Box3f)
Box3_Intersection(Box3d)

#define Box3_IntersectsBox(T) inline bool T##_IntersectsBox(T a, T b) { \
  if (a.lower.x > b.upper.x || a.upper.x < b.lower.x) return false; \
  if (a.lower.y > b.upper.y || a.upper.y < b.lower.y) return false; \
  if (a.lower.z > b.upper.z || a.upper.z < b.lower.z) return false; \
  return true; }

Box3_IntersectsBox(Box3i)
Box3_IntersectsBox(Box3f)
Box3_IntersectsBox(Box3d)

#define Box3_IntersectsRay(T, sub) inline bool T##_IntersectsRay(T self, sub ro, sub rdi) { \
  double t1 = rdi.x * (self.lower.x - ro.x); \
  double t2 = rdi.x * (self.upper.x - ro.x); \
  double tMin = Min(t1, t2); \
  double tMax = Max(t1, t2); \
  t1 = rdi.y * (self.lower.y - ro.y); \
  t2 = rdi.y * (self.upper.y - ro.y); \
  tMin = Max(tMin, Min(t1, t2)); \
  tMax = Min(tMax, Max(t1, t2)); \
  t1 = rdi.z * (self.lower.z - ro.z); \
  t2 = rdi.z * (self.upper.z - ro.z); \
  tMin = Max(tMin, Min(t1, t2)); \
  tMax = Min(tMax, Max(t1, t2)); \
  return tMax >= tMin && tMax > 0; }

Box3_IntersectsRay(Box3f, Vec3f)
Box3_IntersectsRay(Box3d, Vec3d)

#define Box3_Surface(T, sub) inline sub T##_Surface(T self) { \
  sub sx = self.upper.x - self.lower.x; \
  sub sy = self.upper.y - self.lower.y; \
  sub sz = self.upper.z - self.lower.z; \
  return 2 * (sx * sy + sx * sz + sy * sz); }

Box3_Surface(Box3i, int)
Box3_Surface(Box3f, float)
Box3_Surface(Box3d, double)

#define Box3_Union(T) inline T T##_Union(T a, T b) { \
  T self = { \
    { Min(a.lower.x, b.lower.x), Min(a.lower.y, b.lower.y), Min(a.lower.z, b.lower.z) }, \
    { Max(a.upper.x, b.upper.x), Max(a.upper.y, b.upper.y), Max(a.upper.z, b.upper.z) }, \
  }; return self; }

Box3_Union(Box3i)
Box3_Union(Box3f)
Box3_Union(Box3d)

#define Box3_Volume(T, sub) inline sub T##_Volume(T self) { \
  return (self.upper.x - self.lower.x) * \
         (self.upper.y - self.lower.y) * \
         (self.upper.z - self.lower.z); }

Box3_Volume(Box3i, int)
Box3_Volume(Box3f, float)
Box3_Volume(Box3d, double)

#endif


text:
#ifndef PHX_RenderState
#define PHX_RenderState

#include "Common.h"

/* WARNING : Per the OpenGL specs, DepthWritable is irrelevant if DepthTest is
 *           off. Specifically, turning DepthTest off and DepthWritable on does
 *           NOT function as a 'depth overwrite' mode as might be expected! */

PHX_API void  RenderState_PushAllDefaults    ();
PHX_API void  RenderState_PushBlendMode      (BlendMode);
PHX_API void  RenderState_PushCullFace       (CullFace);
PHX_API void  RenderState_PushDepthTest      (bool);
PHX_API void  RenderState_PushDepthWritable  (bool);
PHX_API void  RenderState_PushWireframe      (bool);

PHX_API void  RenderState_PopAll             ();
PHX_API void  RenderState_PopBlendMode       ();
PHX_API void  RenderState_PopCullFace        ();
PHX_API void  RenderState_PopDepthTest       ();
PHX_API void  RenderState_PopDepthWritable   ();
PHX_API void  RenderState_PopWireframe       ();

#endif


text:
#ifndef PHX_Midi
#define PHX_Midi

#include "Common.h"
#include "Vec2.h"

PHX_API int          MidiDevice_GetCount        ();
PHX_API MidiDevice*  MidiDevice_Open            (int index);
PHX_API void         MidiDevice_Close           (MidiDevice*);

PHX_API cstr         MidiDevice_GetNameByIndex  (int index);
PHX_API bool         MidiDevice_HasMessage      (MidiDevice*);
PHX_API Vec2i        MidiDevice_PopMessage      (MidiDevice*);

#endif


text:
#ifndef PHX_Macro
#define PHX_Macro

/* For the brave only. I am not proud of what I have done here. But surely, it
 * is better than template metaprogramming. */

#define  ARGC(...) _ARGC("", __VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define _ARGC(_0, _1, _2, _3, _4, _5, _6, _7, _8, N, ...) N

#define  CAT(A, B) _CAT(A, B)
#define _CAT(A, B) A ## B

#define  MACRO_STR(X) MACRO_STR1(X)
#define MACRO_STR1(X) MACRO_STR2(X)
#define MACRO_STR2(X) #X

#define  MACRO_ARG1(...) _MACRO_TAIL(1, 2, 3, 4, 5, 6, 7, __VA_ARGS__, 0)
#define  MACRO_ARG2(...) _MACRO_TAIL(1, 2, 3, 4, 5, 6, __VA_ARGS__, 0, 0)
#define  MACRO_ARG3(...) _MACRO_TAIL(1, 2, 3, 4, 5, __VA_ARGS__, 0, 0, 0)
#define  MACRO_ARG4(...) _MACRO_TAIL(1, 2, 3, 4, __VA_ARGS__, 0, 0, 0, 0)
#define  MACRO_ARG5(...) _MACRO_TAIL(1, 2, 3, __VA_ARGS__, 0, 0, 0, 0, 0)
#define  MACRO_ARG6(...) _MACRO_TAIL(1, 2, __VA_ARGS__, 0, 0, 0, 0, 0, 0)
#define  MACRO_ARG7(...) _MACRO_TAIL(1, __VA_ARGS__, 0, 0, 0, 0, 0, 0, 0)
#define  MACRO_ARG8(...) _MACRO_TAIL(__VA_ARGS__, 0, 0, 0, 0, 0, 0, 0, 0)
#define _MACRO_TAIL(_1, _2, _3, _4, _5, _6, _7, _8, ...) _8

#define MACRO_CALL1(F) F()
#define MACRO_CALL2(F, _1) F(_1)
#define MACRO_CALL3(F, _1, _2) F(_1, _2)
#define MACRO_CALL4(F, _1, _2, _3) F(_1, _2, _3)
#define MACRO_CALL5(F, _1, _2, _3, _4) F(_1, _2, _3, _4)
#define MACRO_CALL6(F, _1, _2, _3, _4, _5) F(_1, _2, _3, _4, _5)
#define MACRO_CALL7(F, _1, _2, _3, _4, _5, _6) F(_1, _2, _3, _4, _5, _6)
#define MACRO_CALL8(F, _1, _2, _3, _4, _5, _6, _7) F(_1, _2, _3, _4, _5, _6, _7)

#define MACRO_CALL(...) CAT(MACRO_CALL, ARGC(__VA_ARGS__)(__VA_ARGS__))

#endif


text:
#ifndef PHX_MatrixDef
#define PHX_MatrixDef

#include "Common.h"

/* 0   1   2   3      00  01  02  03
   4   5   6   7      10  11  12  13
   8   9  10  11      20  21  22  23
  12  13  14  15      30  31  32  33  */

struct Matrix {
  float m[16];
};

#endif


text:
#ifndef PHX_Meshes
#define PHX_Meshes

#include "Common.h"
#include "Vec3.h"

PHX_API Mesh*  Mesh_Box        (int res);
PHX_API Mesh*  Mesh_BoxSphere  (int res);
PHX_API Mesh*  Mesh_Plane      (Vec3f origin, Vec3f du, Vec3f dv, int resU, int resV);

#endif


text:
#ifndef PHX_Socket
#define PHX_Socket

#include "Common.h"

PHX_API Socket*  Socket_Create       (SocketType);
PHX_API void     Socket_Free         (Socket*);

PHX_API void     Socket_Bind         (Socket*, int port);
PHX_API cstr     Socket_Read         (Socket*);
PHX_API Bytes*   Socket_ReadBytes    (Socket*);
PHX_API void     Socket_Write        (Socket*, cstr);
PHX_API void     Socket_WriteBytes   (Socket*, Bytes*);

/* TCP-specific. */
PHX_API Socket*  Socket_Accept       (Socket*);
PHX_API void     Socket_Listen       (Socket*);

/* UDP-specific. */
PHX_API int      Socket_ReceiveFrom  (Socket*, void* data, size_t len);
PHX_API cstr     Socket_GetAddress   (Socket*);
PHX_API void     Socket_SetAddress   (Socket*, cstr addr);
PHX_API int      Socket_SendTo       (Socket*, void const* data, size_t len);

#endif


text:
#ifndef PHX_Bytes
#define PHX_Bytes

#include "Common.h"

/* --- Bytes -------------------------------------------------------------------
 *
 *   A generic memory buffer for reading/writing. Limited to 32-bit capacity.
 *   Bytes* is a contiguous header + raw memory pair, not a header +
 *   pointer-to-memory (i.e., it is 'inline').
 *
 *   Bytes_FromData : Equivalent to Create(len) -> Write(data, len) -> Rewind()
 *                  : Client is still responsible for freeing data; Bytes
 *                    makes a copy, it does not take ownership of existing
 *                    data
 *   Bytes_Rewind   : Equivalent to SetCursor(0)
 *   Bytes_Read*    : Reads in binary
 *                  : Advances internal cursor by size of type being read
 *   Bytes_Write*   : Writes in binary
 *                  : Advances internal cursor by size of type being written
 *   Bytes_WriteStr : Does not write null-terminator
 *                  : Advances internal cursor by strlen(data)
 *
 * -------------------------------------------------------------------------- */

PHX_API Bytes*  Bytes_Create       (uint32 len);
PHX_API Bytes*  Bytes_FromData     (void const* data, uint32 len);
PHX_API Bytes*  Bytes_Load         (cstr path);
PHX_API void    Bytes_Free         (Bytes*);

PHX_API void*   Bytes_GetData      (Bytes*);
PHX_API uint32  Bytes_GetSize      (Bytes*);

PHX_API Bytes*  Bytes_Compress     (Bytes*);
PHX_API Bytes*  Bytes_Decompress   (Bytes*);

PHX_API uint32  Bytes_GetCursor    (Bytes*);
PHX_API void    Bytes_Rewind       (Bytes*);
PHX_API void    Bytes_SetCursor    (Bytes*, uint32);

PHX_API void    Bytes_Read         (Bytes*, void* data, uint32 len);
PHX_API uint8   Bytes_ReadU8       (Bytes*);
PHX_API uint16  Bytes_ReadU16      (Bytes*);
PHX_API uint32  Bytes_ReadU32      (Bytes*);
PHX_API uint64  Bytes_ReadU64      (Bytes*);
PHX_API int8    Bytes_ReadI8       (Bytes*);
PHX_API int16   Bytes_ReadI16      (Bytes*);
PHX_API int32   Bytes_ReadI32      (Bytes*);
PHX_API int64   Bytes_ReadI64      (Bytes*);
PHX_API float   Bytes_ReadF32      (Bytes*);
PHX_API double  Bytes_ReadF64      (Bytes*);

PHX_API void    Bytes_Write        (Bytes*, void const* data, uint32 len);
PHX_API void    Bytes_WriteStr     (Bytes*, cstr data);
PHX_API void    Bytes_WriteU8      (Bytes*, uint8);
PHX_API void    Bytes_WriteU16     (Bytes*, uint16);
PHX_API void    Bytes_WriteU32     (Bytes*, uint32);
PHX_API void    Bytes_WriteU64     (Bytes*, uint64);
PHX_API void    Bytes_WriteI8      (Bytes*, int8);
PHX_API void    Bytes_WriteI16     (Bytes*, int16);
PHX_API void    Bytes_WriteI32     (Bytes*, int32);
PHX_API void    Bytes_WriteI64     (Bytes*, int64);
PHX_API void    Bytes_WriteF32     (Bytes*, float);
PHX_API void    Bytes_WriteF64     (Bytes*, double);

PHX_API void    Bytes_Print        (Bytes*);
PHX_API void    Bytes_Save         (Bytes*, cstr path);

#endif


text:
#ifndef PHX_TimeStamp
#define PHX_TimeStamp

#include "Common.h"

PHX_API TimeStamp  TimeStamp_Get            ();
PHX_API double     TimeStamp_GetDifference  (TimeStamp start, TimeStamp end);
PHX_API double     TimeStamp_GetElapsed     (TimeStamp start);
PHX_API double     TimeStamp_GetElapsedMs   (TimeStamp start);
PHX_API TimeStamp  TimeStamp_GetFuture      (double seconds);
PHX_API TimeStamp  TimeStamp_GetRelative    (TimeStamp start, double seconds);
PHX_API double     TimeStamp_ToDouble       (TimeStamp);

#endif


text:
#ifndef PHX_Keyboard
#define PHX_Keyboard

/* TODO DEPRECATED : Remove this API */
#define __FFI_IGNORE__

#include "Common.h"

PHX_API bool    Keyboard_Down         (Key);
PHX_API bool    Keyboard_Pressed      (Key);
PHX_API bool    Keyboard_Released     (Key);
PHX_API double  Keyboard_GetIdleTime  ();

PHX_API bool    KeyMod_Alt            ();
PHX_API bool    KeyMod_Ctrl           ();
PHX_API bool    KeyMod_Shift          ();

PRIVATE void Keyboard_Init       ();
PRIVATE void Keyboard_Free       ();
PRIVATE void Keyboard_UpdatePre  ();
PRIVATE void Keyboard_UpdatePost ();

#endif


text:
#ifndef PHX_List
#define PHX_List

#define List_Free(head, T, FreeFn)                                             \
  {                                                                            \
    T* curr = (head);                                                          \
    while (curr) {                                                             \
      T* next = curr->next;                                                    \
      FreeFn(curr);                                                            \
      curr = next;                                                             \
    }                                                                          \
  }

#define List_Iterate_Begin(head, T)                                            \
  {                                                                            \
    T* curr = (head);                                                          \
    T** prev = &(head);                                                        \
    while (curr) {                                                             \
      T* next = curr->next;

#define List_Iterate_End                                                       \
      curr = next;                                                             \
    }                                                                          \
  }

#endif


text:
#ifndef PHX_Error
#define PHX_Error

#include "Common.h"

/* --- Error -------------------------------------------------------------------
 *
 *   A compact error status encoding.
 *
 *    high <---                                               ---> low
 *
 *           2 bytes               byte               byte
 *     [ operand location ]  [ operand type ]   [ failure type ]
 *
 *
 *   For example:
 *     0x00000101 -> received null pointer
 *     0x00080102 -> received invalid path
 *     0x00040404 -> output buffer overflow
 *     0x00000220 -> NaN detected in intermediate computation
 *     0x00200120 -> NaN detected in vertex normal of input
 *
 *   TODO : Do this in a better way, such that error information can still be
 *          concatenated/built-up from sub-functions and subjected to partial
 *          queries, but without the limitations of a bitfield.
 *
 * -------------------------------------------------------------------------- */

const Error Error_None         = 0x00000000;

const Error Error_Null         = 0x00000001;
const Error Error_Invalid      = 0x00000002;
const Error Error_Overflow     = 0x00000004;
const Error Error_Underflow    = 0x00000008;
const Error Error_Empty        = 0x00000010;
const Error Error_NaN          = 0x00000020;
const Error Error_Degenerate   = 0x00000040;
const Error Error_BadCount     = 0x00000080;

const Error Error_Input        = 0x00000100;
const Error Error_Intermediate = 0x00000200;
const Error Error_Output       = 0x00000400;

const Error Error_Stack        = 0x00010000;
const Error Error_Heap         = 0x00020000;
const Error Error_Buffer       = 0x00040000;
const Error Error_Path         = 0x00080000;
const Error Error_Index        = 0x00100000;
const Error Error_Vertex       = 0x00200000;
const Error Error_VertPos      = 0x00400000;
const Error Error_VertNorm     = 0x00800000;
const Error Error_VertUV       = 0x01000000;

PHX_API void  Error_Print  (Error);

#endif


text:
#ifndef PHX_BlendMode
#define PHX_BlendMode

#include "Common.h"

const BlendMode BlendMode_Additive     = 0;
const BlendMode BlendMode_Alpha        = 1;
const BlendMode BlendMode_Disabled     = 2;
const BlendMode BlendMode_PreMultAlpha = 3;

PHX_API void  BlendMode_Pop               ();
PHX_API void  BlendMode_Push              (BlendMode);
PHX_API void  BlendMode_PushAdditive      ();
PHX_API void  BlendMode_PushAlpha         ();
PHX_API void  BlendMode_PushDisabled      ();
PHX_API void  BlendMode_PushPreMultAlpha  ();

#endif


text:
#ifndef PHX_ResourceType
#define PHX_ResourceType

#include "Common.h"

PHX_API const ResourceType ResourceType_Font;
PHX_API const ResourceType ResourceType_Mesh;
PHX_API const ResourceType ResourceType_Other;
PHX_API const ResourceType ResourceType_Script;
PHX_API const ResourceType ResourceType_Shader;
PHX_API const ResourceType ResourceType_Sound;
PHX_API const ResourceType ResourceType_Tex1D;
PHX_API const ResourceType ResourceType_Tex2D;
PHX_API const ResourceType ResourceType_Tex3D;
PHX_API const ResourceType ResourceType_TexCube;
const ResourceType ResourceType_COUNT = 0xA;

PHX_API cstr  ResourceType_ToString  (ResourceType);

#endif


text:
#ifndef PHX_File
#define PHX_File

#include "Common.h"

/* --- File --------------------------------------------------------------------
 *
 *   File_Create   : Overwrites existing file if present
 *   File_Open     : Appends to existing file if present
 *   File_Read     : Returns 0 if opening file fails
 *                 : Returns 0 if file is empty
 *                 : Throws Fatal if filesize exceeds 2^32 - 1
 *                   (Bytes* does not support 64-bit capacities.)
 *   File_Size     : Returns -1 if opening file fails
 *   File_Write*   : Write binary data, not ascii
 *   File_WriteStr : Does NOT write null-terminator
 *
 * -------------------------------------------------------------------------- */

PHX_API File*   File_Create     (cstr path);
PHX_API File*   File_Open       (cstr path);
PHX_API void    File_Close      (File*);

PHX_API bool    File_Exists     (cstr path);
PHX_API bool    File_IsDir      (cstr path);
PHX_API Bytes*  File_ReadBytes  (cstr path);
PHX_API cstr    File_ReadCstr   (cstr path);
PHX_API int64   File_Size       (cstr path);

PHX_API void    File_Read       (File*, void* data, uint32 len);
PHX_API uint8   File_ReadU8     (File*);
PHX_API uint16  File_ReadU16    (File*);
PHX_API uint32  File_ReadU32    (File*);
PHX_API uint64  File_ReadU64    (File*);
PHX_API int8    File_ReadI8     (File*);
PHX_API int16   File_ReadI16    (File*);
PHX_API int32   File_ReadI32    (File*);
PHX_API int64   File_ReadI64    (File*);
PHX_API float   File_ReadF32    (File*);
PHX_API double  File_ReadF64    (File*);

PHX_API void    File_Write      (File*, void const* data, uint32 len);
PHX_API void    File_WriteStr   (File*, cstr);
PHX_API void    File_WriteU8    (File*, uint8);
PHX_API void    File_WriteU16   (File*, uint16);
PHX_API void    File_WriteU32   (File*, uint32);
PHX_API void    File_WriteU64   (File*, uint64);
PHX_API void    File_WriteI8    (File*, int8);
PHX_API void    File_WriteI16   (File*, int16);
PHX_API void    File_WriteI32   (File*, int32);
PHX_API void    File_WriteI64   (File*, int64);
PHX_API void    File_WriteF32   (File*, float);
PHX_API void    File_WriteF64   (File*, double);

#endif


text:
#ifndef PHX_Trigger
#define PHX_Trigger

#include "Common.h"

/* --- Trigger -----------------------------------------------------------------
 *
 *   Trigger_Attach      : When attached to a RigidBody Triggers will have 1
 *                         frame of latency in their position. The transform of
 *                         the RigidBody is copied to the Trigger at the
 *                         beginning of each Physics_Update. This will include
 *                         manual RigidBody_SetPos, but will not not include the
 *                         pending kinematics update.
 *
 *   Trigger_GetContents : Will only include the parent object when a compound
 *                         is within the trigger.
 *
 * -------------------------------------------------------------------------- */

PHX_API Trigger*    Trigger_CreateBox         (Vec3f* halfExtents);
PHX_API void        Trigger_Free              (Trigger*);

PHX_API void        Trigger_Attach            (Trigger*, RigidBody*, Vec3f*);
PHX_API void        Trigger_Detach            (Trigger*, RigidBody*);

PHX_API void        Trigger_GetBoundingBox    (Trigger*, Box3f*);
PHX_API int         Trigger_GetContentsCount  (Trigger*);
PHX_API RigidBody*  Trigger_GetContents       (Trigger*, int);
PHX_API void        Trigger_SetCollisionMask  (Trigger*, int);

PHX_API void        Trigger_SetPos            (Trigger*, Vec3f*);
PHX_API void        Trigger_SetPosLocal       (Trigger*, Vec3f*);

PRIVATE RigidBody*  Trigger_GetParent  (Trigger*);
PRIVATE void        Trigger_Update     (Trigger*);

#endif


text:
#ifndef PHX_OpenGL
#define PHX_OpenGL

#include "Common.h"
#include "GL/glew.h"

void  OpenGL_Init       ();
void  OpenGL_CheckError (cstr file, int line);

/* WARNING - Calling glGetError between glBegin / glEnd IS ITSELF an error.
 *           Hence, only the glEnd call of an immediate-mode draw sequence
 *           should be wrapped in GLCALL. */
#if ENABLE_GLCHECK
  #define GLCALL(x) { x; OpenGL_CheckError(__FILE__, __LINE__); }
#else
  #define GLCALL(x) x;
#endif

#endif


text:
#ifndef PHX_ThreadPool
#define PHX_ThreadPool

#include "Common.h"

typedef int (*ThreadPoolFn)(int threadIndex, int threadCount, void* data);

PHX_API ThreadPool*  ThreadPool_Create  (int threads);
PHX_API void         ThreadPool_Free    (ThreadPool*);

PHX_API void         ThreadPool_Launch  (ThreadPool*, ThreadPoolFn, void* data);
PHX_API void         ThreadPool_Wait    (ThreadPool*);

#endif


text:
#ifndef PHX_HmGui
#define PHX_HmGui

#include "Common.h"

PHX_API void  HmGui_Begin (float sx, float sy);
PHX_API void  HmGui_End   ();
PHX_API void  HmGui_Draw  ();

PHX_API void  HmGui_BeginGroupX      ();
PHX_API void  HmGui_BeginGroupY      ();
PHX_API void  HmGui_BeginGroupStack  ();
PHX_API void  HmGui_EndGroup         ();

PHX_API void  HmGui_BeginScroll (float maxSize);
PHX_API void  HmGui_EndScroll   ();

PHX_API void  HmGui_BeginWindow (cstr title);
PHX_API void  HmGui_EndWindow   ();

PHX_API bool  HmGui_Button   (cstr);
PHX_API bool  HmGui_Checkbox (cstr label, bool value);
PHX_API float HmGui_Slider   (float lower, float upper, float value);

PHX_API void  HmGui_Rect        (float sx, float sy, float r, float g, float b, float a);
PHX_API void  HmGui_Image       (Tex2D*);
PHX_API void  HmGui_Text        (cstr text);
PHX_API void  HmGui_TextColored (cstr text, float r, float g, float b, float a);
PHX_API void  HmGui_TextEx      (Font* font, cstr text, float r, float g, float b, float a);

PHX_API void  HmGui_SetAlign         (float ax, float ay);
PHX_API void  HmGui_SetPadding       (float px, float py);
PHX_API void  HmGui_SetPaddingEx     (float left, float top, float right, float bottom);
PHX_API void  HmGui_SetPaddingLeft   (float);
PHX_API void  HmGui_SetPaddingTop    (float);
PHX_API void  HmGui_SetPaddingRight  (float);
PHX_API void  HmGui_SetPaddingBottom (float);
PHX_API void  HmGui_SetSpacing       (float);
PHX_API void  HmGui_SetStretch       (float x, float y);

PHX_API bool  HmGui_GroupHasFocus (int type);

PHX_API void  HmGui_PushStyle     ();
PHX_API void  HmGui_PushFont      (Font*);
PHX_API void  HmGui_PushTextColor (float r, float g, float b, float a);
PHX_API void  HmGui_PopStyle      (int depth);

#endif


text:
#ifndef PHX_Sphere
#define PHX_Sphere

#include "Common.h"
#include "Vec3.h"

struct Sphere {
  Vec3f p;
  float r;
};

#endif


text:
#ifndef PHX_TexFormat
#define PHX_TexFormat

#include "Common.h"

PHX_API const TexFormat TexFormat_R8;
PHX_API const TexFormat TexFormat_R16;
PHX_API const TexFormat TexFormat_R16F;
PHX_API const TexFormat TexFormat_R32F;
PHX_API const TexFormat TexFormat_RG8;
PHX_API const TexFormat TexFormat_RG16;
PHX_API const TexFormat TexFormat_RG16F;
PHX_API const TexFormat TexFormat_RG32F;
PHX_API const TexFormat TexFormat_RGB8;
PHX_API const TexFormat TexFormat_RGBA8;
PHX_API const TexFormat TexFormat_RGBA16;
PHX_API const TexFormat TexFormat_RGBA16F;
PHX_API const TexFormat TexFormat_RGBA32F;

PHX_API const TexFormat TexFormat_Depth16;
PHX_API const TexFormat TexFormat_Depth24;
PHX_API const TexFormat TexFormat_Depth32F;

PHX_API int   TexFormat_Components  (TexFormat);
PHX_API int   TexFormat_GetSize     (TexFormat);
PHX_API bool  TexFormat_IsColor     (TexFormat);
PHX_API bool  TexFormat_IsDepth     (TexFormat);
PHX_API bool  TexFormat_IsValid     (TexFormat);

#endif


text:
#ifndef PHX_Signal
#define PHX_Signal
#define __FFI_IGNORE__

#include "Common.h"

#ifdef WINDOWS
  #define SIGCALL __CRTDECL
#else
  #define SIGCALL
#endif

typedef int Signal;
typedef void (SIGCALL *SignalHandler)(Signal);

PHX_API const Signal Signal_Int;
PHX_API const Signal Signal_Ill;
PHX_API const Signal Signal_Fpe;
PHX_API const Signal Signal_Segv;
PHX_API const Signal Signal_Term;
PHX_API const Signal Signal_Abrt;

PHX_API void  Signal_Init              ();
PHX_API void  Signal_Free              ();

PHX_API void  Signal_AddHandler        (Signal, SignalHandler);
PHX_API void  Signal_AddHandlerAll     (SignalHandler);
PHX_API void  Signal_RemoveHandler     (Signal, SignalHandler);
PHX_API void  Signal_RemoveHandlerAll  (SignalHandler);
PHX_API cstr  Signal_ToString          (Signal);

/* NOTE : For use only from *within* a handler! */
PHX_API void  Signal_IgnoreDefault     ();

#endif


text:
#ifndef PHX_Tex3D
#define PHX_Tex3D

#include "Common.h"

/* --- API NOTES ---------------------------------------------------------------
 *
 *   This type is REFERENCE-COUNTED. See ../doc/RefCounted.txt for details.
 *
 * -------------------------------------------------------------------------- */

PHX_API Tex3D*     Tex3D_Create        (int sx, int sy, int sz, TexFormat);
PHX_API void       Tex3D_Acquire       (Tex3D*);
PHX_API void       Tex3D_Free          (Tex3D*);

PHX_API void       Tex3D_Pop            (Tex3D*);
PHX_API void       Tex3D_Push           (Tex3D*, int layer);
PHX_API void       Tex3D_PushLevel      (Tex3D*, int layer, int level);

PHX_API void       Tex3D_Draw          (Tex3D* self, int layer, float x, float y, float xs, float ys);
PHX_API void       Tex3D_GenMipmap     (Tex3D*);
PHX_API void       Tex3D_GetData       (Tex3D*, void*, PixelFormat, DataFormat);
PHX_API Bytes*     Tex3D_GetDataBytes  (Tex3D*, PixelFormat, DataFormat);
PHX_API TexFormat  Tex3D_GetFormat     (Tex3D*);
PHX_API uint       Tex3D_GetHandle     (Tex3D*);
PHX_API void       Tex3D_GetSize       (Tex3D*, Vec3i* out);
PHX_API void       Tex3D_GetSizeLevel  (Tex3D*, Vec3i* out, int level);
PHX_API void       Tex3D_SetData       (Tex3D*, void const*, PixelFormat, DataFormat);
PHX_API void       Tex3D_SetDataBytes  (Tex3D*, Bytes*, PixelFormat, DataFormat);
PHX_API void       Tex3D_SetMagFilter  (Tex3D*, TexFilter);
PHX_API void       Tex3D_SetMinFilter  (Tex3D*, TexFilter);
PHX_API void       Tex3D_SetWrapMode   (Tex3D*, TexWrapMode);

#endif


text:
#ifndef PHX_ShaderVarType
#define PHX_ShaderVarType

#include "Common.h"

const ShaderVarType ShaderVarType_None    = 0x0;
const ShaderVarType ShaderVarType_BEGIN   = 0x1;
const ShaderVarType ShaderVarType_Float   = 0x1;
const ShaderVarType ShaderVarType_Float2  = 0x2;
const ShaderVarType ShaderVarType_Float3  = 0x3;
const ShaderVarType ShaderVarType_Float4  = 0x4;
const ShaderVarType ShaderVarType_Int     = 0x5;
const ShaderVarType ShaderVarType_Int2    = 0x6;
const ShaderVarType ShaderVarType_Int3    = 0x7;
const ShaderVarType ShaderVarType_Int4    = 0x8;
const ShaderVarType ShaderVarType_Matrix  = 0x9;
const ShaderVarType ShaderVarType_Tex1D   = 0xA;
const ShaderVarType ShaderVarType_Tex2D   = 0xB;
const ShaderVarType ShaderVarType_Tex3D   = 0xC;
const ShaderVarType ShaderVarType_TexCube = 0xD;
const ShaderVarType ShaderVarType_END     = 0xD;
const ShaderVarType ShaderVarType_SIZE    = 0xD;

PHX_API ShaderVarType  ShaderVarType_FromStr      (cstr);
PHX_API cstr           ShaderVarType_GetGLSLName  (ShaderVarType);
PHX_API cstr           ShaderVarType_GetName      (ShaderVarType);
PHX_API int            ShaderVarType_GetSize      (ShaderVarType);

#endif


text:
#ifndef PHX_Polygon
#define PHX_Polygon

#include "ArrayList.h"
#include "Common.h"
#include "Vec3.h"

struct Polygon {
  ArrayList(Vec3f, vertices);
};

PHX_API void   Polygon_ToPlane            (Polygon*, Plane*);
PHX_API void   Polygon_ToPlaneFast        (Polygon*, Plane*);
PHX_API void   Polygon_Split              (Polygon*, Plane splitPlane, Polygon* back, Polygon* front);
PHX_API void   Polygon_SplitSafe          (Polygon*, Plane splitPlane, Polygon* back, Polygon* front);
PHX_API void   Polygon_GetCentroid        (Polygon*, Vec3f*);
PHX_API void   Polygon_ConvexToTriangles  (Polygon*, int32* triangles_capacity, int32* triangles_size, Triangle** triangles_data);
PHX_API Error  Polygon_Validate           (Polygon*);

#endif


text:
#ifndef PHX_SDF
#define PHX_SDF

#include "Common.h"

PHX_API SDF*   SDF_Create          (int sx, int sy, int sz);
PHX_API SDF*   SDF_FromTex3D       (Tex3D*);
PHX_API void   SDF_Free            (SDF*);
PHX_API Mesh*  SDF_ToMesh          (SDF*);

PHX_API void   SDF_Clear           (SDF*, float value);
PHX_API void   SDF_ComputeNormals  (SDF*);
PHX_API void   SDF_Set             (SDF*, int x, int y, int z, float value);
PHX_API void   SDF_SetNormal       (SDF*, int x, int y, int z, Vec3f const* normal);

#endif


text:
#ifndef PHX_OS
#define PHX_OS

#include "Common.h"

PHX_API cstr  OS_GetClipboard    ();
PHX_API int   OS_GetCPUCount     ();
PHX_API cstr  OS_GetVideoDriver  ();
PHX_API void  OS_SetClipboard    (cstr text);

#endif


text:
#ifndef PHX_BoxMesh
#define PHX_BoxMesh

#include "Common.h"

PHX_API BoxMesh*  BoxMesh_Create   ();
PHX_API void      BoxMesh_Free     (BoxMesh*);

PHX_API void      BoxMesh_Add      (BoxMesh*, float px, float py, float pz,
                                              float sx, float sy, float sz,
                                              float rx, float ry, float rz,
                                              float bx, float by, float bz);
PHX_API Mesh*     BoxMesh_GetMesh  (BoxMesh*, int res);

#endif


text:
#ifndef PHX_InputBindings
#define PHX_InputBindings
#define __FFI_IGNORE__

#include "Common.h"
#include "Vec2.h"

PHX_API void           InputBindings_Init                    ();
PHX_API void           InputBindings_Free                    ();

PHX_API void           InputBindings_Update                  ();

//PHX_API void           InputBindings_Register                (cstr name, InputBinding* bindings, int count);
//PHX_API void           InputBindings_Unregister              (cstr name, InputBinding* bindings, int count);

PHX_API bool           InputBinding_GetPressed              (InputBinding*);
PHX_API bool           InputBinding_GetDown                 (InputBinding*);
PHX_API bool           InputBinding_GetReleased             (InputBinding*);
PHX_API float          InputBinding_GetValue                (InputBinding*);
PHX_API Vec2f          InputBinding_GetVecValue             (InputBinding*);

PHX_API float          InputBinding_GetXValue               (InputBinding*);
PHX_API float          InputBinding_GetYValue               (InputBinding*);

PHX_API bool           InputBinding_GetXPosPressed          (InputBinding*);
PHX_API bool           InputBinding_GetXPosDown             (InputBinding*);
PHX_API bool           InputBinding_GetXPosReleased         (InputBinding*);
PHX_API bool           InputBinding_GetXNegPressed          (InputBinding*);
PHX_API bool           InputBinding_GetXNegDown             (InputBinding*);
PHX_API bool           InputBinding_GetXNegReleased         (InputBinding*);
PHX_API bool           InputBinding_GetYPosPressed          (InputBinding*);
PHX_API bool           InputBinding_GetYPosDown             (InputBinding*);
PHX_API bool           InputBinding_GetYPosReleased         (InputBinding*);
PHX_API bool           InputBinding_GetYNegPressed          (InputBinding*);
PHX_API bool           InputBinding_GetYNegDown             (InputBinding*);
PHX_API bool           InputBinding_GetYNegReleased         (InputBinding*);

/* --- Convenience API ------------------------------------------------------ */

PHX_API const float    InputBindings_DefaultPressThreshold;
PHX_API const float    InputBindings_DefaultReleaseThreshold;
PHX_API const float    InputBindings_DefaultExponent;
PHX_API const float    InputBindings_DefaultDeadzone;
PHX_API const float    InputBindings_DefaultMinValue;
PHX_API const float    InputBindings_DefaultMaxValue;

//PHX_API InputBinding*  InputBinding_CreateButton             (Button);
//PHX_API InputBinding*  InputBinding_CreateButtonFromAxis     (Button);
//PHX_API InputBinding*  InputBinding_CreateAxis               (Button);
//PHX_API InputBinding*  InputBinding_CreateAxisFromButtons    (Button pos, Button neg);
//PHX_API InputBinding*  InputBinding_CreateAxis2DFromAxes     (Button x, Button y);
//PHX_API InputBinding*  InputBinding_CreateAxis2DFromButtons  (Button xPos, Button xNeg, Button yPos, Button yNeg);
//PHX_API InputBinding*  InputBinding_Clone                    (InputBinding*);
//PHX_API void           InputBinding_Free                     (InputBinding*);

//PHX_API void           InputBinding_SetActive                (InputBinding*, bool);

/* --- Convenience API  (Fluent Interface) ---------------------------------- */

PHX_API InputBinding*  InputBinding_SetDeadzone              (InputBinding*, float);
PHX_API InputBinding*  InputBinding_SetExponent              (InputBinding*, float);
PHX_API InputBinding*  InputBinding_SetInvertX               (InputBinding*, bool);
PHX_API InputBinding*  InputBinding_SetInvertY               (InputBinding*, bool);
PHX_API InputBinding*  InputBinding_SetRange                 (InputBinding*, float min, float max);
PHX_API InputBinding*  InputBinding_SetThresholds            (InputBinding*, float press, float release);

#endif


text:
#ifndef PHX_MemPool
#define PHX_MemPool

#include "Common.h"

PHX_API MemPool*  MemPool_Create      (uint32 cellSize, uint32 blockSize);
PHX_API MemPool*  MemPool_CreateAuto  (uint32 elemSize);
PHX_API void      MemPool_Free        (MemPool*);

PHX_API void*     MemPool_Alloc       (MemPool*);
PHX_API void      MemPool_Clear       (MemPool*);
PHX_API void      MemPool_Dealloc     (MemPool*, void*);

PHX_API uint32    MemPool_GetCapacity (MemPool*);
PHX_API uint32    MemPool_GetSize     (MemPool*);

#endif