bjorn 7 years ago
parent
commit
8295b71740
84 changed files with 2518 additions and 865 deletions
  1. 647 588
      api/init.lua
  2. 14 0
      api/lovr/callbacks/conf.lua
  3. 0 19
      api/lovr/filesystem/exists.lua
  4. 1 1
      api/lovr/filesystem/mount.lua
  5. 29 0
      api/lovr/graphics/Animator/getAlpha.lua
  6. 15 0
      api/lovr/graphics/Animator/getAnimationCount.lua
  7. 31 0
      api/lovr/graphics/Animator/getAnimationNames.lua
  8. 22 0
      api/lovr/graphics/Animator/getDuration.lua
  9. 33 0
      api/lovr/graphics/Animator/getPriority.lua
  10. 28 0
      api/lovr/graphics/Animator/getSpeed.lua
  11. 28 0
      api/lovr/graphics/Animator/init.lua
  12. 18 0
      api/lovr/graphics/Animator/isLooping.lua
  13. 18 0
      api/lovr/graphics/Animator/isPlaying.lua
  14. 19 0
      api/lovr/graphics/Animator/pause.lua
  15. 21 0
      api/lovr/graphics/Animator/play.lua
  16. 11 0
      api/lovr/graphics/Animator/reset.lua
  17. 21 0
      api/lovr/graphics/Animator/resume.lua
  18. 28 0
      api/lovr/graphics/Animator/seek.lua
  19. 28 0
      api/lovr/graphics/Animator/setAlpha.lua
  20. 17 0
      api/lovr/graphics/Animator/setLooping.lua
  21. 32 0
      api/lovr/graphics/Animator/setPriority.lua
  22. 27 0
      api/lovr/graphics/Animator/setSpeed.lua
  23. 20 0
      api/lovr/graphics/Animator/stop.lua
  24. 23 0
      api/lovr/graphics/Animator/tell.lua
  25. 12 0
      api/lovr/graphics/Animator/update.lua
  26. 20 0
      api/lovr/graphics/ArcMode.lua
  27. 42 0
      api/lovr/graphics/Material/getColor.lua
  28. 25 0
      api/lovr/graphics/Material/getTexture.lua
  29. 9 0
      api/lovr/graphics/Material/init.lua
  30. 47 0
      api/lovr/graphics/Material/setColor.lua
  31. 33 0
      api/lovr/graphics/Material/setTexture.lua
  32. 16 0
      api/lovr/graphics/MaterialColor.lua
  33. 20 0
      api/lovr/graphics/MaterialTexture.lua
  34. 76 0
      api/lovr/graphics/Mesh/drawInstanced.lua
  35. 12 0
      api/lovr/graphics/Mesh/getMaterial.lua
  36. 0 12
      api/lovr/graphics/Mesh/getTexture.lua
  37. 1 0
      api/lovr/graphics/Mesh/init.lua
  38. 15 0
      api/lovr/graphics/Mesh/setMaterial.lua
  39. 0 12
      api/lovr/graphics/Mesh/setTexture.lua
  40. 14 0
      api/lovr/graphics/MeshDrawMode.lua
  41. 75 0
      api/lovr/graphics/Model/drawInstanced.lua
  42. 18 0
      api/lovr/graphics/Model/getAnimator.lua
  43. 12 0
      api/lovr/graphics/Model/getMaterial.lua
  44. 15 0
      api/lovr/graphics/Model/getMesh.lua
  45. 0 12
      api/lovr/graphics/Model/getTexture.lua
  46. 2 1
      api/lovr/graphics/Model/init.lua
  47. 18 0
      api/lovr/graphics/Model/setAnimator.lua
  48. 17 0
      api/lovr/graphics/Model/setMaterial.lua
  49. 0 12
      api/lovr/graphics/Model/setTexture.lua
  50. 22 0
      api/lovr/graphics/Shader/hasUniform.lua
  51. 11 2
      api/lovr/graphics/Shader/init.lua
  52. 2 1
      api/lovr/graphics/Shader/send.lua
  53. 0 31
      api/lovr/graphics/Skybox/draw.lua
  54. 0 35
      api/lovr/graphics/Skybox/init.lua
  55. 2 2
      api/lovr/graphics/Texture/init.lua
  56. 121 0
      api/lovr/graphics/arc.lua
  57. 5 5
      api/lovr/graphics/box.lua
  58. 82 0
      api/lovr/graphics/circle.lua
  59. 5 5
      api/lovr/graphics/cube.lua
  60. 1 1
      api/lovr/graphics/getBackgroundColor.lua
  61. 2 2
      api/lovr/graphics/getColor.lua
  62. 24 0
      api/lovr/graphics/isGammaCorrect.lua
  63. 25 0
      api/lovr/graphics/newAnimator.lua
  64. 55 0
      api/lovr/graphics/newMaterial.lua
  65. 6 9
      api/lovr/graphics/newModel.lua
  66. 0 60
      api/lovr/graphics/newSkybox.lua
  67. 62 3
      api/lovr/graphics/newTexture.lua
  68. 7 3
      api/lovr/graphics/plane.lua
  69. 2 2
      api/lovr/graphics/setBackgroundColor.lua
  70. 3 3
      api/lovr/graphics/setColor.lua
  71. 56 0
      api/lovr/graphics/skybox.lua
  72. 24 20
      api/lovr/graphics/triangle.lua
  73. 71 0
      api/lovr/math/Transform/getMatrix.lua
  74. 86 0
      api/lovr/math/Transform/setMatrix.lua
  75. 64 0
      api/lovr/math/gammaToLinear.lua
  76. 64 0
      api/lovr/math/linearToGamma.lua
  77. 63 0
      api/lovr/math/orientationToDirection.lua
  78. 1 0
      examples/Lighting/conf.lua
  79. 0 1
      examples/Lighting/main.lua
  80. 2 2
      examples/Panorama/main.lua
  81. 3 3
      examples/Physics/main.lua
  82. 11 11
      examples/Primitives/main.lua
  83. 6 6
      guides/Callbacks_and_Modules.md
  84. 0 1
      guides/Libraries.md

File diff suppressed because it is too large
+ 647 - 588
api/init.lua


+ 14 - 0
api/lovr/callbacks/conf.lua

@@ -22,6 +22,11 @@ return {
           type = 'table',
           type = 'table',
           description = 'Configuration for the headset.',
           description = 'Configuration for the headset.',
           table = {
           table = {
+            {
+              name = 'drivers',
+              type = 'table',
+              description = 'An ordered list of preferred headset drivers.'
+            },
             {
             {
               name = 'mirrored',
               name = 'mirrored',
               type = 'boolean',
               type = 'boolean',
@@ -83,6 +88,11 @@ return {
             }
             }
           }
           }
         },
         },
+        {
+          name = 'gammacorrect',
+          type = 'boolean',
+          description = 'Whether colors are gamma corrected.'
+        },
         {
         {
           name = 'window',
           name = 'window',
           type = 'table',
           type = 'table',
@@ -148,6 +158,7 @@ return {
           t.identity = 'default'
           t.identity = 'default'
 
 
           -- Headset settings
           -- Headset settings
+          t.headset.drivers = { 'openvr', 'webvr', 'fake' }
           t.headset.mirror = true
           t.headset.mirror = true
           t.headset.offset = 1.7
           t.headset.offset = 1.7
 
 
@@ -160,6 +171,9 @@ return {
           t.modules.physics = true
           t.modules.physics = true
           t.modules.timer = true
           t.modules.timer = true
 
 
+          -- Configure gamma correction
+          t.gammacorrect = false
+
           -- Configure the desktop window
           -- Configure the desktop window
           t.window.width = 800
           t.window.width = 800
           t.window.height = 600
           t.window.height = 600

+ 0 - 19
api/lovr/filesystem/exists.lua

@@ -1,19 +0,0 @@
-return {
-  summary = 'Check whether a file exists.',
-  description = 'Determine if a file exists.',
-  arguments = {
-    {
-      name = 'path',
-      type = 'string',
-      description = 'The path to check.'
-    }
-  },
-  returns = {
-    {
-      name = 'exists',
-      type = 'boolean',
-      description = 'Whether the path is a file or directory.'
-    }
-  },
-  notes = 'This function checks both the source directory and the save directory.'
-}

+ 1 - 1
api/lovr/filesystem/mount.lua

@@ -34,7 +34,7 @@ return {
     description = 'Mount `data.zip` with a file `images/background.png`:',
     description = 'Mount `data.zip` with a file `images/background.png`:',
     code = [[
     code = [[
       lovr.filesystem.mount('data.zip', 'assets')
       lovr.filesystem.mount('data.zip', 'assets')
-      print(lovr.filesystem.exists('assets/images/background.png')) -- true
+      print(lovr.filesystem.isFile('assets/images/background.png')) -- true
     ]]
     ]]
   },
   },
   related = {
   related = {

+ 29 - 0
api/lovr/graphics/Animator/getAlpha.lua

@@ -0,0 +1,29 @@
+return {
+  summary = 'Get the alpha (weight) of an animation.',
+  description = 'Returns the current alpha factor of an animation.',
+  arguments = {
+    {
+      name = 'name',
+      type = 'string',
+      description = 'The name of the animation.'
+    }
+  },
+  returns = {
+    {
+      name = 'alpha',
+      type = 'number',
+      description = 'The alpha of the animation.'
+    }
+  },
+  notes = [[
+    The alpha is a number between 0 and 1 indicating how the animation's pose is blended with other
+    animations.  An alpha of 1 means the animation's pose will completely overwrite the existing
+    pose, whereas an alpha of .5 would blend half of the animation's pose with half of the existing
+    pose.  This, combined with the animation's priority, allows for fine grained control over how
+    multiple playing animations get blended together.
+  ]],
+  related = {
+    'Animator:getPriority',
+    'Animator:setPriority'
+  }
+}

+ 15 - 0
api/lovr/graphics/Animator/getAnimationCount.lua

@@ -0,0 +1,15 @@
+return {
+  summary = 'Get the number of animations the Animator can play.',
+  description = 'Returns the number of animations the Animator can play.',
+  arguments = {},
+  returns = {
+    {
+      name = 'count',
+      type = 'number',
+      description = 'The number of animations.'
+    }
+  },
+  related = {
+    'Animator:getAnimationNames'
+  }
+}

+ 31 - 0
api/lovr/graphics/Animator/getAnimationNames.lua

@@ -0,0 +1,31 @@
+return {
+  summary = 'Get the a table containing all animation names.',
+  description = [[
+    Returns a table containing the names of all animations supported by this Animator.
+  ]],
+  arguments = {
+    t = {
+      type = 'table',
+      description = 'A table to fill with the animation names.'
+    }
+  },
+  returns = {
+    names = {
+      type = 'table',
+      description = 'The list of animation names as strings.'
+    }
+  },
+  variants = {
+    {
+      arguments = {},
+      returns = { 'names' }
+    },
+    {
+      arguments = { 't' },
+      returns = {}
+    }
+  },
+  related = {
+    'Animator:getAnimationCount'
+  }
+}

+ 22 - 0
api/lovr/graphics/Animator/getDuration.lua

@@ -0,0 +1,22 @@
+return {
+  summary = 'Get the duration of an animation.',
+  description = 'Returns the duration of an animation.',
+  arguments = {
+    {
+      name = 'name',
+      type = 'string',
+      description = 'The name of the animation.'
+    }
+  },
+  returns = {
+    {
+      name = 'duration',
+      type = 'number',
+      description = 'The duration of the animation at its normal speed, in seconds.'
+    }
+  },
+  related = {
+    'Animator:seek',
+    'Animator:tell'
+  }
+}

+ 33 - 0
api/lovr/graphics/Animator/getPriority.lua

@@ -0,0 +1,33 @@
+return {
+  summary = 'Get the priority of an animation, used for mixing.',
+  description = 'Returns the priority of an animation.',
+  arguments = {
+    {
+      name = 'name',
+      type = 'string',
+      description = 'The name of the animation.'
+    }
+  },
+  returns = {
+    {
+      name = 'priority',
+      type = 'number',
+      description = 'The priority of the animation.'
+    }
+  },
+  notes = [[
+    The priority controls the order that multiple playing animations get blended together.
+    Animations with a lower priority will get applied first, and animations with higher priority
+    will get layered on top afterwards.  If two or more animations have the same priority, they
+    could get applied in any order.  All animations start with a priority of 1.
+
+    You can use priority and alpha to control how different animations blend together.  For
+    instance, if you have a character with "throw" and "walk" animations and both of them key the
+    bones in the arm, you could have the character walk and throw at the same time by giving the
+    "throw" animation a higher priority and playing it over the walk animation.
+  ]],
+  related = {
+    'Animator:getAlpha',
+    'Animator:setAlpha'
+  }
+}

+ 28 - 0
api/lovr/graphics/Animator/getSpeed.lua

@@ -0,0 +1,28 @@
+return {
+  summary = 'Get the speed of an animation.',
+  description = 'Returns the speed factor for an animation or the Animator\'s global speed factor.',
+  arguments = {
+    name = {
+      type = 'string',
+      description = 'The name of the animation.'
+    }
+  },
+  returns = {
+    speed = {
+      type = 'number',
+      description = 'The current speed multiplier.'
+    }
+  },
+  variants = {
+    {
+      description = 'Get the speed of a specific animation.',
+      arguments = { 'name' },
+      returns = { 'speed' }
+    },
+    {
+      description = 'Get the global speed multiplier for the Animator.',
+      arguments = {},
+      returns = { 'speed' }
+    }
+  }
+}

+ 28 - 0
api/lovr/graphics/Animator/init.lua

@@ -0,0 +1,28 @@
+return {
+  summary = 'An object that plays and mixes animations.',
+  description = [[
+    An animator is an object that controls the playback of skeletal animations.  Animators can be
+    attached to models using `Model:setAnimator`.  Once attached, the Model will render using the
+    animator's pose instead of the default pose.  Don't forget to update the animator in
+    `lovr.update` using `Animator:update`!
+  ]],
+  constructors = {
+    'lovr.graphics.newAnimator'
+  },
+  example = [[
+    function lovr.load()
+      model = lovr.graphics.newModel('model.fbx')
+      animator = lovr.graphics.newAnimator(model)
+      animator:play(animator:getAnimationNames()[1])
+      model:setAnimator(animator)
+    end
+
+    function lovr.update(dt)
+      animator:update(dt)
+    end
+
+    function lovr.draw()
+      model:draw()
+    end
+  ]]
+}

+ 18 - 0
api/lovr/graphics/Animator/isLooping.lua

@@ -0,0 +1,18 @@
+return {
+  summary = 'Check if an animation is looping.',
+  description = 'Returns whether an animation is looping.',
+  arguments = {
+    {
+      name = 'animation',
+      type = 'string',
+      description = 'The name of the animation.'
+    }
+  },
+  returns = {
+    {
+      name = 'looping',
+      type = 'boolean',
+      description = 'Whether or not the animation is looping.'
+    }
+  }
+}

+ 18 - 0
api/lovr/graphics/Animator/isPlaying.lua

@@ -0,0 +1,18 @@
+return {
+  summary = 'Check if an animation is playing.',
+  description = 'Returns whether an animation is currently playing.',
+  arguments = {
+    {
+      name = 'animation',
+      type = 'string',
+      description = 'The name of the animation.'
+    }
+  },
+  returns = {
+    {
+      name = 'playing',
+      type = 'boolean',
+      description = 'Whether or not the animation is playing.'
+    }
+  }
+}

+ 19 - 0
api/lovr/graphics/Animator/pause.lua

@@ -0,0 +1,19 @@
+return {
+  summary = 'Pause an animation.',
+  description = 'Pauses an animation.  This will stop the animation without resetting its time.',
+  arguments = {
+    {
+      name = 'name',
+      type = 'string',
+      description = 'The animation to pause.'
+    }
+  },
+  returns = {},
+  related = {
+    'Animator:play',
+    'Animator:stop',
+    'Animator:resume',
+    'Animator:isPlaying',
+    'Animator:getAnimationNames'
+  }
+}

+ 21 - 0
api/lovr/graphics/Animator/play.lua

@@ -0,0 +1,21 @@
+return {
+  summary = 'Start playing an animation.',
+  description = [[
+    Plays an animation.  If the animation is already playing, it will start over at the beginning.
+  ]],
+  arguments = {
+    {
+      name = 'name',
+      type = 'string',
+      description = 'The name of the animation to play.'
+    }
+  },
+  returns = {},
+  related = {
+    'Animator:stop',
+    'Animator:pause',
+    'Animator:resume',
+    'Animator:isPlaying',
+    'Animator:getAnimationNames'
+  }
+}

+ 11 - 0
api/lovr/graphics/Animator/reset.lua

@@ -0,0 +1,11 @@
+return {
+  summary = 'Stop all animations.',
+  description = [[
+    Resets the Animator to its initial state. All animations will be stopped, their speed will be
+    reset to `1.0`, their looping state will be reset, and the Animator's global speed will be reset
+    to `1.0`.
+  ]],
+  arguments = {},
+  returns = {},
+  related = {}
+}

+ 21 - 0
api/lovr/graphics/Animator/resume.lua

@@ -0,0 +1,21 @@
+return {
+  summary = 'Resume a paused animation.',
+  description = [[
+    Resumes an animation. This will play an animation without starting it over at the beginning.
+  ]],
+  arguments = {
+    {
+      name = 'name',
+      type = 'string',
+      description = 'The animation to resume.'
+    }
+  },
+  returns = {},
+  related = {
+    'Animator:pause',
+    'Animator:play',
+    'Animator:stop',
+    'Animator:isPlaying',
+    'Animator:getAnimationNames'
+  }
+}

+ 28 - 0
api/lovr/graphics/Animator/seek.lua

@@ -0,0 +1,28 @@
+return {
+  summary = 'Seek to a specific time in an animation.',
+  description = 'Seeks to a specific time in an animation.',
+  arguments = {
+    {
+      name = 'name',
+      type = 'string',
+      description = 'The name of the animation to seek.'
+    },
+    {
+      name = 'time',
+      type = 'number',
+      description = 'The time to seek to, in seconds.'
+    }
+  },
+  returns = {},
+  notes = [[
+    If the time is greater than the duration of the animation, the animation will stop if it isn't
+    currently looping.  Negative time values are supported for animations (regardless of looping
+    state) and will seek backwards from the animation's end time.
+
+    Seeking an animation does not stop or play the animation.
+  ]],
+  related = {
+    'Animator:tell',
+    'Animator:getDuration'
+  }
+}

+ 28 - 0
api/lovr/graphics/Animator/setAlpha.lua

@@ -0,0 +1,28 @@
+return {
+  summary = 'Set the alpha (weight) of an animation.',
+  description = 'Sets the current alpha factor of an animation.',
+  arguments = {
+    {
+      name = 'name',
+      type = 'string',
+      description = 'The name of the animation.'
+    },
+    {
+      name = 'alpha',
+      type = 'number',
+      description = 'The alpha of the animation.'
+    }
+  },
+  returns = {},
+  notes = [[
+    The alpha is a number between 0 and 1 indicating how the animation's pose is blended with other
+    animations.  An alpha of 1 means the animation's pose will completely overwrite the existing
+    pose, whereas an alpha of .5 would blend half of the animation's pose with half of the existing
+    pose.  This, combined with the animation's priority, allows for fine grained control over how
+    multiple playing animations get blended together.
+  ]],
+  related = {
+    'Animator:getPriority',
+    'Animator:setPriority'
+  }
+}

+ 17 - 0
api/lovr/graphics/Animator/setLooping.lua

@@ -0,0 +1,17 @@
+return {
+  summary = 'Set whether an animation should loop.',
+  description = 'Sets whether an animation loops.',
+  arguments = {
+    {
+      name = 'animation',
+      type = 'string',
+      description = 'The name of the animation.'
+    },
+    {
+      name = 'loop',
+      type = 'boolean',
+      description = 'Whether the animation should loop.'
+    }
+  },
+  returns = {}
+}

+ 32 - 0
api/lovr/graphics/Animator/setPriority.lua

@@ -0,0 +1,32 @@
+return {
+  summary = 'Set the priority of an animation, used for mixing.',
+  description = 'Sets the priority of an animation.',
+  arguments = {
+    {
+      name = 'name',
+      type = 'string',
+      description = 'The name of the animation.'
+    },
+    {
+      name = 'priority',
+      type = 'number',
+      description = 'The new priority for the animation.'
+    }
+  },
+  returns = {},
+  notes = [[
+    The priority controls the order that multiple playing animations get blended together.
+    Animations with a lower priority will get applied first, and animations with higher priority
+    will get layered on top afterwards.  If two or more animations have the same priority, they
+    could get applied in any order.  All animations start with a priority of 1.
+
+    You can use priority and alpha to control how different animations blend together.  For
+    instance, if you have a character with "throw" and "walk" animations and both of them key the
+    bones in the arm, you could have the character walk and throw at the same time by giving the
+    "throw" animation a higher priority and playing it over the walk animation.
+  ]],
+  related = {
+    'Animator:getAlpha',
+    'Animator:setAlpha'
+  }
+}

+ 27 - 0
api/lovr/graphics/Animator/setSpeed.lua

@@ -0,0 +1,27 @@
+return {
+  summary = 'Set the speed of an animation.',
+  description = 'Sets the speed factor for an animation or the Animator\'s global speed factor.',
+  arguments = {
+    name = {
+      type = 'string',
+      description = 'The name of the animation.'
+    },
+    speed = {
+      type = 'number',
+      description = 'The new speed multiplier.'
+    }
+  },
+  returns = {},
+  variants = {
+    {
+      description = 'Set the speed of a specific animation.',
+      arguments = { 'name', 'speed' },
+      returns = {}
+    },
+    {
+      description = 'Set the global speed multiplier for the Animator.',
+      arguments = { 'speed' },
+      returns = {}
+    }
+  }
+}

+ 20 - 0
api/lovr/graphics/Animator/stop.lua

@@ -0,0 +1,20 @@
+return {
+  summary = 'Stop an animation.',
+  description = 'Stops an animation.',
+  arguments = {
+    {
+      name = 'name',
+      type = 'string',
+      description = 'The animation to stop.'
+    }
+  },
+  returns = {},
+  related = {
+    'Animator:play',
+    'Animator:reset',
+    'Animator:pause',
+    'Animator:resume',
+    'Animator:isPlaying',
+    'Animator:getAnimationNames'
+  }
+}

+ 23 - 0
api/lovr/graphics/Animator/tell.lua

@@ -0,0 +1,23 @@
+return {
+  summary = 'Get the current time of an animation.',
+  description = 'Returns the current playback time of an animation.',
+  arguments = {
+    {
+      name = 'name',
+      type = 'string',
+      description = 'The name of the animation.'
+    }
+  },
+  returns = {
+    {
+      name = 'time',
+      type = 'number',
+      description = 'The current time the animation is at, in seconds.'
+    }
+  },
+  notes = 'This will always be between 0 and the animation\'s duration.',
+  related = {
+    'Animator:seek',
+    'Animator:getDuration'
+  }
+}

+ 12 - 0
api/lovr/graphics/Animator/update.lua

@@ -0,0 +1,12 @@
+return {
+  summary = 'Advance the Animator\'s clock.',
+  description = 'Updates the Animator\'s clock, advancing all playing animations by the time step.',
+  arguments = {
+    {
+      name = 'dt',
+      type = 'number',
+      description = 'The amount of time to advance.'
+    }
+  },
+  returns = {}
+}

+ 20 - 0
api/lovr/graphics/ArcMode.lua

@@ -0,0 +1,20 @@
+return {
+  summary = 'Different ways arcs can be drawn.',
+  description = 'Different ways arcs can be drawn with `lovr.graphics.arc`.',
+  values = {
+    {
+      name = 'pie',
+      description = [[
+        The arc is drawn with the center of its circle included in the list of points (default).
+      ]]
+    },
+    {
+      name = 'open',
+      description = 'The curve of the arc is drawn as a single line.'
+    },
+    {
+      name = 'closed',
+      description = 'The starting and ending points of the arc\'s curve are connected.'
+    }
+  }
+}

+ 42 - 0
api/lovr/graphics/Material/getColor.lua

@@ -0,0 +1,42 @@
+return {
+  summary = 'Get a color property of the Material.',
+  description = [[
+    Returns a color property for a Material.  Different types of colors are supported for different
+    lighting parameters.  Colors default to white and are gamma corrected as necessary, see
+    `lovr.graphics.isGammaCorrect` for more info on that.
+  ]],
+  arguments = {
+    {
+      name = 'colorType',
+      type = 'MaterialColor',
+      default = [['diffuse']],
+      description = 'The type of color to get.'
+    }
+  },
+  returns = {
+    {
+      name = 'r',
+      type = 'number',
+      description = 'The red component of the color.'
+    },
+    {
+      name = 'g',
+      type = 'number',
+      description = 'The green component of the color.'
+    },
+    {
+      name = 'b',
+      type = 'number',
+      description = 'The blue component of the color.'
+    },
+    {
+      name = 'a',
+      type = 'number',
+      description = 'The alpha component of the color.'
+    }
+  },
+  related = {
+    'MaterialColor',
+    'lovr.graphics.setColor'
+  }
+}

+ 25 - 0
api/lovr/graphics/Material/getTexture.lua

@@ -0,0 +1,25 @@
+return {
+  summary = 'Get a texture for the Material.',
+  description = [[
+    Returns a texture for a Material.  Different types of textures are supported for different
+    lighting parameters.  If unset, textures default to a blank white texture.
+  ]],
+  arguments = {
+    {
+      name = 'textureType',
+      type = 'MaterialTexture',
+      default = [['diffuse']],
+      description = 'The type of texture to get.'
+    }
+  },
+  returns = {
+    {
+      name = 'texture',
+      type = 'Texture',
+      description = 'The texture that is set, or nil if no texture is set.'
+    }
+  },
+  related = {
+    'MaterialTexture'
+  }
+}

+ 9 - 0
api/lovr/graphics/Material/init.lua

@@ -0,0 +1,9 @@
+return {
+  summary = 'An object that controls texturing and shading.',
+  description = [[
+    A Material is an object used to control how objects appear, through coloring, texturing, and
+    shading.  The Material itself holds sets of colors, textures, and other parameters that are made
+    available to Shaders.
+  ]],
+  constructor = 'lovr.graphics.newMaterial'
+}

+ 47 - 0
api/lovr/graphics/Material/setColor.lua

@@ -0,0 +1,47 @@
+return {
+  summary = 'Set a color property of the Material.',
+  description = [[
+    Sets a color property for a Material.  Different types of colors are supported for different
+    lighting parameters.  Color channels should be from 0.0 to 1.0. Colors default to white and are
+    gamma corrected as necessary, see `lovr.graphics.isGammaCorrect` for more info on that.
+  ]],
+  arguments = {
+    colorType = {
+      type = 'MaterialColor',
+      default = [['diffuse']],
+      description = 'The type of color to get.'
+    },
+    r = {
+      type = 'number',
+      description = 'The red component of the color.'
+    },
+    g = {
+      type = 'number',
+      description = 'The green component of the color.'
+    },
+    b = {
+      type = 'number',
+      description = 'The blue component of the color.'
+    },
+    a = {
+      type = 'number',
+      default = '1.0',
+      description = 'The alpha component of the color.'
+    }
+  },
+  returns = {},
+  variants = {
+    {
+      arguments = { 'colorType', 'r', 'g', 'b', 'a' },
+      returns = {}
+    },
+    {
+      arguments = { 'r', 'g', 'b', 'a' },
+      returns = {}
+    }
+  },
+  related = {
+    'MaterialColor',
+    'lovr.graphics.setColor'
+  }
+}

+ 33 - 0
api/lovr/graphics/Material/setTexture.lua

@@ -0,0 +1,33 @@
+return {
+  summary = 'Set a texture for the Material.',
+  description = [[
+    Sets a texture for a Material.  Different types of textures are supported for different
+    lighting parameters.  If set to `nil`, textures default to a blank white texture.
+  ]],
+  arguments = {
+    textureType = {
+      type = 'MaterialTexture',
+      default = [['diffuse']],
+      description = 'The type of texture to get.'
+    },
+    texture = {
+      type = 'Texture',
+      description = 'The texture to apply, or nil to use the default.'
+    }
+  },
+  returns = {},
+  variants = {
+    {
+      arguments = { 'textureType', 'texture' },
+      returns = {}
+    },
+    {
+      arguments = { 'texture' },
+      returns = {}
+    }
+  },
+  related = {
+    'MaterialTexture',
+    'lovr.graphics.newTexture'
+  }
+}

+ 16 - 0
api/lovr/graphics/MaterialColor.lua

@@ -0,0 +1,16 @@
+return {
+  summary = 'Different material color parameters.',
+  description = 'The different types of color parameters `Material`s can hold.',
+  values = {
+    {
+      name = 'diffuse',
+      description = 'The diffuse color.'
+    }
+  },
+  related = {
+    'Material:getColor',
+    'Material:setColor',
+    'MaterialTexture',
+    'Material'
+  }
+}

+ 20 - 0
api/lovr/graphics/MaterialTexture.lua

@@ -0,0 +1,20 @@
+return {
+  summary = 'Different material texture parameters.',
+  description = 'The different types of texture parameters `Material`s can hold.',
+  values = {
+    {
+      name = 'diffuse',
+      description = 'The diffuse texture.'
+    },
+    {
+      name = 'environment',
+      description = 'The environment map, should be specified as a cubemap texture.'
+    }
+  },
+  related = {
+    'Material:getTexture',
+    'Material:setTexture',
+    'MaterialColor',
+    'Material'
+  }
+}

+ 76 - 0
api/lovr/graphics/Mesh/drawInstanced.lua

@@ -0,0 +1,76 @@
+return {
+  summary = 'Draw multiple copies of the Mesh in an optimized way.',
+  description = [[
+    Draw a Mesh multiple times.  This is much faster than calling `Mesh:draw` more than once.
+  ]],
+  arguments = {
+    instances = {
+      type = 'number',
+      default = '1',
+      description = 'The number of copies of the mesh to draw.'
+    },
+    x = {
+      type = 'number',
+      default = '0',
+      description = 'The x coordinate to draw the Mesh at.'
+    },
+    y = {
+      type = 'number',
+      default = '0',
+      description = 'The y coordinate to draw the Mesh at.'
+    },
+    z = {
+      type = 'number',
+      default = '0',
+      description = 'The z coordinate to draw the Mesh at.'
+    },
+    scale = {
+      type = 'number',
+      default = '1',
+      description = 'The scale to draw the Mesh at.'
+    },
+    angle = {
+      type = 'number',
+      default = '0',
+      description = 'The angle to rotate the Mesh around its axis of rotation.'
+    },
+    ax = {
+      type = 'number',
+      default = '0',
+      description = 'The x component of the axis of rotation.'
+    },
+    ay = {
+      type = 'number',
+      default = '1',
+      description = 'The y component of the axis of rotation.'
+    },
+    az = {
+      type = 'number',
+      default = '0',
+      description = 'The z component of the axis of rotation.'
+    },
+    transform = {
+      type = 'Transform',
+      description = 'The transform to apply before drawing.'
+    }
+  },
+  returns = {},
+  variants = {
+    {
+      arguments = { 'instances', 'x', 'y', 'z', 'scale', 'angle', 'ax', 'ay', 'az' },
+      returns = {}
+    },
+    {
+      arguments = { 'instances', 'transform' },
+      returns = {}
+    }
+  },
+  notes = [[
+    By default, the Meshes will all be drawn on top of each other.  To get the drawn copies to
+    appear in different places, you can use the `gl_InstanceID` variable in a `Shader`.  The first
+    instance will pass 0 as the instance ID, the second instance will pass 1 as the instance ID,
+    etc.  You can use an array of mat4 variables and access the array using the supplied instance ID
+    to specify a list of positions to draw the instances at, or use custom logic to position each
+    instance.
+  ]]
+}

+ 12 - 0
api/lovr/graphics/Mesh/getMaterial.lua

@@ -0,0 +1,12 @@
+return {
+  summary = 'Get the Material applied to the Mesh.',
+  description = 'Get the Material applied to the Mesh.',
+  arguments = {},
+  returns = {
+    {
+      name = 'material',
+      type = 'Material',
+      description = 'The current material applied to the Mesh.'
+    }
+  }
+}

+ 0 - 12
api/lovr/graphics/Mesh/getTexture.lua

@@ -1,12 +0,0 @@
-return {
-  summary = 'Get the Texture applied to the Mesh.',
-  description = 'Get the Texture applied to the Mesh.',
-  arguments = {},
-  returns = {
-    {
-      name = 'texture',
-      type = 'Texture',
-      description = 'The current texture applied to the Mesh.'
-    }
-  }
-}

+ 1 - 0
api/lovr/graphics/Mesh/init.lua

@@ -38,6 +38,7 @@ return {
           { 'lovrPosition', 'float', 3 },
           { 'lovrPosition', 'float', 3 },
           { 'lovrNormal',   'float', 3 },
           { 'lovrNormal',   'float', 3 },
           { 'lovrTexCoord', 'float', 2 }
           { 'lovrTexCoord', 'float', 2 }
+          { 'lovrVertexColor', 'byte', 4 }
         }
         }
 
 
     Great, so why do we go through the trouble of naming everything in our vertex and saying what
     Great, so why do we go through the trouble of naming everything in our vertex and saying what

+ 15 - 0
api/lovr/graphics/Mesh/setMaterial.lua

@@ -0,0 +1,15 @@
+return {
+  summary = 'Apply a Material to the Mesh.',
+  description = [[
+    Applies a Material to the Mesh.  This will cause it to use the Material's properties whenever it
+    is rendered.
+  ]],
+  arguments = {
+    {
+      name = 'material',
+      type = 'Material',
+      description = 'The Material to apply.'
+    }
+  },
+  returns = {}
+}

+ 0 - 12
api/lovr/graphics/Mesh/setTexture.lua

@@ -1,12 +0,0 @@
-return {
-  summary = 'Apply a Texture to the Mesh.',
-  description = 'Applies a Texture to the Mesh.',
-  arguments = {
-    {
-      name = 'texture',
-      type = 'Texture',
-      description = 'The new texture.'
-    }
-  },
-  returns = {}
-}

+ 14 - 0
api/lovr/graphics/MeshDrawMode.lua

@@ -9,6 +9,20 @@ return {
       name = 'points',
       name = 'points',
       description = 'Draw each vertex as a single point.'
       description = 'Draw each vertex as a single point.'
     },
     },
+    {
+      name = 'lines',
+      description = [[
+        The vertices represent a list of line segments. Each pair of vertices will have a line drawn
+        between them.
+      ]]
+    },
+    {
+      name = 'linestrip',
+      description = [[
+        The first two vertices have a line drawn between them, and each vertex after that will be
+        connected to the previous vertex with a line.
+      ]]
+    },
     {
     {
       name = 'strip',
       name = 'strip',
       description = [[
       description = [[

+ 75 - 0
api/lovr/graphics/Model/drawInstanced.lua

@@ -0,0 +1,75 @@
+return {
+  summary = 'Draw multiple copies of a Model in an optimized way.',
+  description = [[
+    Draws a model multiple times.  This is much faster than drawing `Model:draw` more than once.
+  ]],
+  arguments = {
+    instances = {
+      type = 'number',
+      default = '1',
+      description = 'The number of copies to draw.'
+    },
+    x = {
+      type = 'number',
+      default = '0',
+      description = 'The x coordinate to draw the Model at.'
+    },
+    y = {
+      type = 'number',
+      default = '0',
+      description = 'The y coordinate to draw the Model at.'
+    },
+    z = {
+      type = 'number',
+      default = '0',
+      description = 'The z coordinate to draw the Model at.'
+    },
+    scale = {
+      type = 'number',
+      default = '1',
+      description = 'The scale to draw the Model at.'
+    },
+    angle = {
+      type = 'number',
+      default = '0',
+      description = 'The angle to rotate the Model around its axis of rotation.'
+    },
+    ax = {
+      type = 'number',
+      default = '0',
+      description = 'The x component of the axis of rotation.'
+    },
+    ay = {
+      type = 'number',
+      default = '1',
+      description = 'The y component of the axis of rotation.'
+    },
+    az = {
+      type = 'number',
+      default = '0',
+      description = 'The z component of the axis of rotation.'
+    },
+    transform = {
+      type = 'Transform',
+      description = 'The transform to apply before drawing.'
+    }
+  },
+  returns = {},
+  variants = {
+    {
+      arguments = { 'instances', 'x', 'y', 'z', 'scale', 'angle', 'ax', 'ay', 'az' },
+      returns = {}
+    },
+    {
+      arguments = { 'instances', 'transform' },
+      returns = {}
+    }
+  },
+  notes = [[
+    By default, the Models will all be drawn on top of each other.  To get the drawn copies to
+    appear in different places, you can use the `gl_InstanceID` variable in a `Shader`.  The first
+    instance will pass 0 as the instance ID, the second instance will pass 1 as the instance ID,
+    etc.  You can use an array of mat4 variables and access the array using the supplied instance ID
+    to specify a list of positions to draw the instances at.
+  ]]
+}

+ 18 - 0
api/lovr/graphics/Model/getAnimator.lua

@@ -0,0 +1,18 @@
+return {
+  summary = 'Get the Animator attached to the Model.',
+  description = [[
+    Returns the `Animator` attached to the Model.  When attached, the animator will alter the pose
+    of the bones of the model based on the set of playing animations.
+  ]],
+  arguments = {},
+  returns = {
+    {
+      name = 'animator',
+      type = 'Animator',
+      description = 'The Animator attached to the Model, or nil if none is set.'
+    }
+  },
+  related = {
+    'lovr.graphics.newAnimator'
+  }
+}

+ 12 - 0
api/lovr/graphics/Model/getMaterial.lua

@@ -0,0 +1,12 @@
+return {
+  summary = 'Get the Material applied to the Model.',
+  description = 'Returns the Material applied to the Model.',
+  arguments = {},
+  returns = {
+    {
+      name = 'material',
+      type = 'Material',
+      description = 'The current material applied to the Model.'
+    }
+  }
+}

+ 15 - 0
api/lovr/graphics/Model/getMesh.lua

@@ -0,0 +1,15 @@
+return {
+  summary = 'Get the Model\'s underlying Mesh object.',
+  description = 'Returns the underlying `Mesh` object for the Model.',
+  arguments = {},
+  returns = {
+    {
+      name = 'mesh',
+      type = 'Mesh',
+      description = 'The Mesh object for the model, containing all of the raw vertex data.'
+    }
+  },
+  related = {
+    'Mesh'
+  }
+}

+ 0 - 12
api/lovr/graphics/Model/getTexture.lua

@@ -1,12 +0,0 @@
-return {
-  summary = 'Get the Texture applied to the Model.',
-  description = 'Get the Texture applied to the Model.',
-  arguments = {},
-  returns = {
-    {
-      name = 'texture',
-      type = 'Texture',
-      description = 'The current texture applied to the Model.'
-    }
-  }
-}

+ 2 - 1
api/lovr/graphics/Model/init.lua

@@ -2,7 +2,8 @@ return {
   summary = 'An asset imported from a 3D model file.',
   summary = 'An asset imported from a 3D model file.',
   description = [[
   description = [[
     A Model is a drawable object loaded from a 3D file format.  The supported 3D file formats are
     A Model is a drawable object loaded from a 3D file format.  The supported 3D file formats are
-    `obj`, `fbx`, and collada.  Models will use normals and texture coordinates, if provided.
+    `obj`, `fbx`, `gltf`, and collada.  Models will use normals and texture coordinates, if
+    provided.
 
 
     The following advanced features are not supported yet: animations, materials, and vertex colors.
     The following advanced features are not supported yet: animations, materials, and vertex colors.
   ]],
   ]],

+ 18 - 0
api/lovr/graphics/Model/setAnimator.lua

@@ -0,0 +1,18 @@
+return {
+  summary = 'Attach an Animator to the Model.',
+  description = [[
+    Attaches an `Animator` to the Model.  When attached, the animator will alter the pose of the bones
+    of the model based on the set of playing animations.
+  ]],
+  arguments = {
+    {
+      name = 'animator',
+      type = 'Animator',
+      description = 'The Animator to attach.'
+    }
+  },
+  returns = {},
+  related = {
+    'lovr.graphics.newAnimator'
+  }
+}

+ 17 - 0
api/lovr/graphics/Model/setMaterial.lua

@@ -0,0 +1,17 @@
+return {
+  summary = 'Apply a Material to the Model.',
+  description = 'Applies a Material to the Model.',
+  arguments = {
+    {
+      name = 'material',
+      type = 'Material',
+      description = 'The material to apply to the Model.'
+    }
+  },
+  returns = {},
+  notes = [[
+    A model's Material will be used when drawing every part of the model.  It will override any
+    materials included in the model file.  It isn't currently possible to apply multiple materials
+    to different pieces of the Model.
+  ]]
+}

+ 0 - 12
api/lovr/graphics/Model/setTexture.lua

@@ -1,12 +0,0 @@
-return {
-  summary = 'Apply a Texture to the Model.',
-  description = 'Apply a Texture to the Model.',
-  arguments = {
-    {
-      name = 'texture',
-      type = 'Texture',
-      description = 'The texture to apply to the Model.'
-    }
-  },
-  returns = {}
-}

+ 22 - 0
api/lovr/graphics/Shader/hasUniform.lua

@@ -0,0 +1,22 @@
+return {
+  summary = 'Check if a Shader has a uniform variable.',
+  description = 'Returns whether a Shader has a particular uniform variable.',
+  arguments = {
+    {
+      name = 'uniform',
+      type = 'string',
+      description = 'The name of the uniform variable.'
+    }
+  },
+  returns = {
+    {
+      name = 'present',
+      type = 'boolean',
+      description = 'Whether the shader has the specified uniform.'
+    }
+  },
+  notes = [[
+    If a uniform variable is defined but unused in the shader, the shader compiler will optimize it
+    out and the uniform will not report itself as present.
+  ]]
+}

+ 11 - 2
api/lovr/graphics/Shader/init.lua

@@ -18,7 +18,7 @@ return {
     The default fragment shader:
     The default fragment shader:
 
 
         vec4 color(vec4 graphicsColor, sampler2D image, vec2 uv) {
         vec4 color(vec4 graphicsColor, sampler2D image, vec2 uv) {
-          return graphicsColor * texture(image, uv);
+          return graphicsColor * lovrDiffuseColor * vertexColor * texture(image, uv);
         }
         }
 
 
     Additionally, the following headers are prepended to the shader source, giving you convenient
     Additionally, the following headers are prepended to the shader source, giving you convenient
@@ -31,16 +31,25 @@ return {
         uniform mat4 lovrTransform;
         uniform mat4 lovrTransform;
         uniform mat4 lovrNormalMatrix;
         uniform mat4 lovrNormalMatrix;
         uniform mat4 lovrProjection;
         uniform mat4 lovrProjection;
+        uniform float lovrPointSize;
+        uniform mat4 lovrPose[48];
         in vec3 lovrPosition;
         in vec3 lovrPosition;
         in vec3 lovrNormal;
         in vec3 lovrNormal;
         in vec2 lovrTexCoord;
         in vec2 lovrTexCoord;
+        in vec4 lovrVertexColor;
+        in ivec4 lovrBones;
+        in vec4 lovrBoneWeights;
         out vec2 texCoord;
         out vec2 texCoord;
+        out vec4 vertexColor;
 
 
     Fragment shader header:
     Fragment shader header:
 
 
         uniform vec4 lovrColor;
         uniform vec4 lovrColor;
-        uniform sampler2D lovrTexture;
+        uniform vec4 lovrDiffuseColor;
+        uniform sampler2D lovrDiffuseTexture;
+        uniform samplerCube lovrEnvironmentTexture;
         in vec2 texCoord;
         in vec2 texCoord;
+        in vec4 vertexColor;
         in vec4 gl_FragCoord;
         in vec4 gl_FragCoord;
         out vec4 lovrFragColor;
         out vec4 lovrFragColor;
   ]],
   ]],

+ 2 - 1
api/lovr/graphics/Shader/send.lua

@@ -17,7 +17,8 @@ return {
   notes = [[
   notes = [[
     The shader does not need to be active to update its uniforms.  However, the types must match up.
     The shader does not need to be active to update its uniforms.  However, the types must match up.
     Uniform variables declared as `float`s must be sent a single number, whereas uniforms declared
     Uniform variables declared as `float`s must be sent a single number, whereas uniforms declared
-    as `vec4`s must be sent a table containing 4 numbers, etc.
+    as `vec4`s must be sent a table containing 4 numbers, etc.  Note that uniforms declared as mat4s
+    can be sent a `Transform` object.
 
 
     An error is thrown if the uniform does not exist or is not used in the shader.
     An error is thrown if the uniform does not exist or is not used in the shader.
   ]],
   ]],

+ 0 - 31
api/lovr/graphics/Skybox/draw.lua

@@ -1,31 +0,0 @@
-return {
-  summary = 'Draw the Skybox.',
-  description = 'Draws the Skybox at a specified angle.',
-  arguments = {
-    {
-      name = 'angle',
-      type = 'number',
-      description = 'The number of radians to rotate the skybox around its axis of rotation'
-    },
-    {
-      name = 'ax',
-      type = 'number',
-      description = 'The x component of the axis of rotation.'
-    },
-    {
-      name = 'ay',
-      type = 'number',
-      description = 'The y component of the axis of rotation.'
-    },
-    {
-      name = 'az',
-      type = 'number',
-      description = 'The z component of the axis of rotation.'
-    }
-  },
-  returns = {},
-  notes = [[
-    To prevent problems with the depth test, make sure you draw Skyboxes before drawing other
-    things, or disable the depth test while drawing them.
-  ]]
-}

+ 0 - 35
api/lovr/graphics/Skybox/init.lua

@@ -1,35 +0,0 @@
-return {
-  summary = 'A cube wrapped around the camera, used as a 3D background.',
-  description = [[
-    A Skybox is a collection of six images used to apply a background to a three dimensional scene.
-    Each image is used to texture the face of a cube, and the cube is drawn around the camera,
-    giving an illusion of a 360-degree background.
-  ]],
-  constructor = 'lovr.graphics.newSkybox',
-  notes = [[
-    To prevent problems with the depth test, make sure you draw Skyboxes before drawing other
-    things, or disable the depth test while drawing them.
-  ]],
-  example = {
-    description = 'Drawing a Skybox in VR:',
-    code = [[
-      function lovr.load()
-        skybox = lovr.graphics.newSkybox({
-          '1.png',
-          '2.png',
-          '3.png',
-          '4.png',
-          '5.png',
-          '6.png'
-        })
-      end
-
-      function lovr.draw()
-        lovr.graphics.setColor(255, 255, 255)
-        skybox:draw(lovr.headset.getOrientation())
-
-        -- Draw everything else
-      end
-    ]]
-  }
-}

+ 2 - 2
api/lovr/graphics/Texture/init.lua

@@ -1,7 +1,7 @@
 return {
 return {
-  summary = 'An image that can be applied to Meshes and Models.',
+  summary = 'An image that can be applied to Materials.',
   description = [[
   description = [[
-    A Texture is an image that can be applied to `Model`s and `Mesh`s.  Supported file formats
+    A Texture is an image that can be applied to `Material`s.  Supported file formats
     include `.png`, `.jpg`, `.tga`, and `.bmp`.  Additionally, three compressed formats are
     include `.png`, `.jpg`, `.tga`, and `.bmp`.  Additionally, three compressed formats are
     supported: DXT1, DXT3, and DXT5 (all have the `.dds` extension).  Compressed textures are
     supported: DXT1, DXT3, and DXT5 (all have the `.dds` extension).  Compressed textures are
     generally recommended as they use less video memory and usually improve performance.
     generally recommended as they use less video memory and usually improve performance.

+ 121 - 0
api/lovr/graphics/arc.lua

@@ -0,0 +1,121 @@
+return {
+  tag = 'graphicsPrimitives',
+  summary = 'Draw an arc.',
+  description = 'Draws an arc.',
+  arguments = {
+    mode = {
+      type = 'DrawMode',
+      description = 'Whether the arc is filled or outlined.'
+    },
+    arcmode = {
+      type = 'ArcMode',
+      default = [['pie']],
+      description = 'How to draw the arc.'
+    },
+    material = {
+      type = 'Material',
+      description = 'The Material to apply to the arc.'
+    },
+    transform = {
+      type = 'Transform',
+      description = 'The arc\'s transform.'
+    },
+    x = {
+      type = 'number',
+      default = '0',
+      description = 'The x coordinate of the center of the arc.'
+    },
+    y = {
+      type = 'number',
+      default = '0',
+      description = 'The y coordinate of the center of the arc.'
+    },
+    z = {
+      type = 'number',
+      default = '0',
+      description = 'The z coordinate of the center of the arc.'
+    },
+    radius = {
+      type = 'number',
+      default = '1',
+      description = 'The radius of the arc, in meters.'
+    },
+    angle = {
+      type = 'number',
+      default = '0',
+      description = 'The rotation of the arc around its rotation axis, in radians.'
+    },
+    ax = {
+      type = 'number',
+      default = '0',
+      description = 'The x coordinate of the arc\'s axis of rotation.'
+    },
+    ay = {
+      type = 'number',
+      default = '1',
+      description = 'The y coordinate of the arc\'s axis of rotation.'
+    },
+    az = {
+      type = 'number',
+      default = '0',
+      description = 'The z coordinate of the arc\'s axis of rotation.'
+    },
+    start = {
+      type = 'number',
+      default = '0',
+      description = 'The starting angle of the arc, in radians.'
+    },
+    ['end'] = {
+      type = 'number',
+      default = '2 * math.pi',
+      description = 'The ending angle of the arc, in radians.'
+    },
+    segments = {
+      type = 'number',
+      default = '32',
+      description = [[
+        The number of segments to use for the full circle. A smaller number of segments will be
+        used, depending on how long the arc is.
+      ]]
+    }
+  },
+  returns = {},
+  variants = {
+    {
+      arguments = { 'mode', 'x', 'y', 'z', 'radius', 'angle', 'ax', 'ay', 'az', 'start', 'end', 'segments' },
+      returns = {}
+    },
+    {
+      arguments = { 'material', 'x', 'y', 'z', 'radius', 'angle', 'ax', 'ay', 'az', 'start', 'end', 'segments' },
+      returns = {}
+    },
+    {
+      arguments = { 'mode', 'transform', 'start', 'end', 'segments' },
+      returns = {}
+    },
+    {
+      arguments = { 'material', 'transform', 'start', 'end', 'segments' },
+      returns = {}
+    },
+    {
+      arguments = { 'mode', 'arcmode', 'x', 'y', 'z', 'radius', 'angle', 'ax', 'ay', 'az', 'start', 'end', 'segments' },
+      returns = {}
+    },
+    {
+      arguments = { 'material', 'arcmode', 'x', 'y', 'z', 'radius', 'angle', 'ax', 'ay', 'az', 'start', 'end', 'segments' },
+      returns = {}
+    },
+    {
+      arguments = { 'mode', 'arcmode', 'transform', 'start', 'end', 'segments' },
+      returns = {}
+    },
+    {
+      arguments = { 'material', 'arcmode', 'transform', 'start', 'end', 'segments' },
+      returns = {}
+    }
+  },
+  notes = 'The local normal vector of the circle is `(0, 0, 1)`.',
+  related = {
+    'lovr.graphics.arc'
+  }
+}

+ 5 - 5
api/lovr/graphics/box.lua

@@ -6,9 +6,9 @@ return {
     the width, height, and depth of the box.
     the width, height, and depth of the box.
   ]],
   ]],
   arguments = {
   arguments = {
-    texture = {
-      type = 'Texture',
-      description = 'The Texture to apply to the box.'
+    material = {
+      type = 'Material',
+      description = 'The Material to apply to the box.'
     },
     },
     mode = {
     mode = {
       type = 'DrawMode',
       type = 'DrawMode',
@@ -76,7 +76,7 @@ return {
       returns = {}
       returns = {}
     },
     },
     {
     {
-      arguments = { 'texture', 'x', 'y', 'z', 'width', 'height', 'depth', 'angle', 'ax', 'ay', 'az' },
+      arguments = { 'material', 'x', 'y', 'z', 'width', 'height', 'depth', 'angle', 'ax', 'ay', 'az' },
       returns = {}
       returns = {}
     },
     },
     {
     {
@@ -84,7 +84,7 @@ return {
       returns = {}
       returns = {}
     },
     },
     {
     {
-      arguments = { 'texture', 'transform' },
+      arguments = { 'material', 'transform' },
       returns = {}
       returns = {}
     }
     }
   }
   }

+ 82 - 0
api/lovr/graphics/circle.lua

@@ -0,0 +1,82 @@
+return {
+  tag = 'graphicsPrimitives',
+  summary = 'Draw a 2D circle.',
+  description = 'Draws a 2D circle.',
+  arguments = {
+    mode = {
+      type = 'DrawMode',
+      description = 'Whether the circle is filled or outlined.'
+    },
+    material = {
+      type = 'Material',
+      description = 'The Material to apply to the circle.'
+    },
+    transform = {
+      type = 'Transform',
+      description = 'The circle\'s transform.'
+    },
+    x = {
+      type = 'number',
+      default = '0',
+      description = 'The x coordinate of the center of the circle.'
+    },
+    y = {
+      type = 'number',
+      default = '0',
+      description = 'The y coordinate of the center of the circle.'
+    },
+    z = {
+      type = 'number',
+      default = '0',
+      description = 'The z coordinate of the center of the circle.'
+    },
+    radius = {
+      type = 'number',
+      default = '1',
+      description = 'The radius of the circle, in meters.'
+    },
+    angle = {
+      type = 'number',
+      default = '0',
+      description = 'The rotation of the circle around its rotation axis, in radians.'
+    },
+    ax = {
+      type = 'number',
+      default = '0',
+      description = 'The x coordinate of the circle\'s axis of rotation.'
+    },
+    ay = {
+      type = 'number',
+      default = '1',
+      description = 'The y coordinate of the circle\'s axis of rotation.'
+    },
+    az = {
+      type = 'number',
+      default = '0',
+      description = 'The z coordinate of the circle\'s axis of rotation.'
+    }
+  },
+  returns = {},
+  variants = {
+    {
+      arguments = { 'mode', 'x', 'y', 'z', 'radius', 'angle', 'ax', 'ay', 'az' },
+      returns = {}
+    },
+    {
+      arguments = { 'material', 'x', 'y', 'z', 'radius', 'angle', 'ax', 'ay', 'az' },
+      returns = {}
+    },
+    {
+      arguments = { 'mode', 'transform' },
+      returns = {}
+    },
+    {
+      arguments = { 'material', 'transform' },
+      returns = {}
+    }
+  },
+  notes = 'The local normal vector of the circle is `(0, 0, 1)`.',
+  related = {
+    'lovr.graphics.arc'
+  }
+}

+ 5 - 5
api/lovr/graphics/cube.lua

@@ -3,9 +3,9 @@ return {
   summary = 'Draw a cube.',
   summary = 'Draw a cube.',
   description = 'Draws a cube.',
   description = 'Draws a cube.',
   arguments = {
   arguments = {
-    texture = {
-      type = 'Texture',
-      description = 'The Texture to apply to the cube faces.'
+    material = {
+      type = 'Material',
+      description = 'The Material to apply to the cube faces.'
     },
     },
     mode = {
     mode = {
       type = 'DrawMode',
       type = 'DrawMode',
@@ -63,7 +63,7 @@ return {
       returns = {}
       returns = {}
     },
     },
     {
     {
-      arguments = { 'texture', 'x', 'y', 'z', 'size', 'angle', 'ax', 'ay', 'az' },
+      arguments = { 'material', 'x', 'y', 'z', 'size', 'angle', 'ax', 'ay', 'az' },
       returns = {}
       returns = {}
     },
     },
     {
     {
@@ -71,7 +71,7 @@ return {
       returns = {}
       returns = {}
     },
     },
     {
     {
-      arguments = { 'texture', 'transform' },
+      arguments = { 'material', 'transform' },
       returns = {}
       returns = {}
     }
     }
   }
   }

+ 1 - 1
api/lovr/graphics/getBackgroundColor.lua

@@ -2,7 +2,7 @@ return {
   tag = 'graphicsState',
   tag = 'graphicsState',
   summary = 'Get the background color.',
   summary = 'Get the background color.',
   description = [[
   description = [[
-    Returns the current background color.  Color components are from 0 to 255.
+    Returns the current background color.  Color components are from 0.0 to 1.0.
   ]],
   ]],
   arguments = {},
   arguments = {},
   returns = {
   returns = {

+ 2 - 2
api/lovr/graphics/getColor.lua

@@ -2,8 +2,8 @@ return {
   tag = 'graphicsState',
   tag = 'graphicsState',
   summary = 'Get the global color factor.',
   summary = 'Get the global color factor.',
   description = [[
   description = [[
-    Returns the current global color factor.  Color components are from 0 to 255.  Every pixel drawn
-    will be multiplied (i.e. tinted) by this color.
+    Returns the current global color factor.  Color components are from 0.0 to 1.0.  Every pixel
+    drawn will be multiplied (i.e. tinted) by this color.
   ]],
   ]],
   arguments = {},
   arguments = {},
   returns = {
   returns = {

+ 24 - 0
api/lovr/graphics/isGammaCorrect.lua

@@ -0,0 +1,24 @@
+return {
+  tag = 'graphicsState',
+  summary = 'Get whether wireframe mode is enabled.',
+  description = [[
+    Get whether or not gamma correct rendering is supported and enabled.  When enabled, lovr will
+    automatically perform gamma correction on colors set via `lovr.graphics.setColor`,
+    `lovr.graphics.setBackgroundColor`, `Material:setColor`, and textures created without the linear
+    flag set.  Gamma correction will subtly improve lighting quality, especially in darker regions.
+  ]],
+  arguments = {},
+  returns = {
+    {
+      name = 'isGammaCorrect',
+      type = 'boolean',
+      description = 'Whether or not gamma correction is applied to colors.'
+    }
+  },
+  notes = 'Gamma correction must first be enabled in `lovr.conf`.',
+  related = {
+    'lovr.conf',
+    'lovr.math.gammaToLinear',
+    'lovr.math.linearToGamma'
+  }
+}

+ 25 - 0
api/lovr/graphics/newAnimator.lua

@@ -0,0 +1,25 @@
+return {
+  tag = 'graphicsObjects',
+  summary = 'Create a new Animator.',
+  description = 'Creates a new `Animator` by reading animations from a `Model`.',
+  arguments = {
+    {
+      name = 'model',
+      type = 'Model',
+      description = 'The model to read animations from.'
+    }
+  },
+  returns = {
+    {
+      name = 'animator',
+      type = 'Animator',
+      description = 'The new Animator.'
+    }
+  },
+  notes = [[
+    You can attach an animator to a Model with `Model:setAnimator`.
+  ]],
+  related = {
+    'Model:setAnimator'
+  }
+}

+ 55 - 0
api/lovr/graphics/newMaterial.lua

@@ -0,0 +1,55 @@
+return {
+  tag = 'graphicsObjects',
+  summary = 'Create a new Material.',
+  description = [[
+    Creates a new Material.  Materials are sets of colors, textures, and other parameters that
+    affect the appearance of objects.  They can be applied to `Model`s, `Mesh`es, and most graphics
+    primitives accept a Material as an optional first argument.
+  ]],
+  arguments = {
+    texture = {
+      type = 'Texture',
+      description = 'The diffuse texture.'
+    },
+    r = {
+      type = 'number',
+      default = '1',
+      description = 'The red component of the diffuse color.'
+    },
+    g = {
+      type = 'number',
+      default = '1',
+      description = 'The green component of the diffuse color.'
+    },
+    b = {
+      type = 'number',
+      default = '1',
+      description = 'The blue component of the diffuse color.'
+    },
+    a = {
+      type = 'number',
+      default = '1',
+      description = 'The alpha component of the diffuse color.'
+    }
+  },
+  returns = {
+    material = {
+      type = 'Material',
+      description = 'The new Material.'
+    }
+  },
+  variants = {
+    {
+      arguments = {},
+      returns = { 'material' }
+    },
+    {
+      arguments = { 'texture', 'r', 'g', 'b', 'a' },
+      returns = { 'material' }
+    },
+    {
+      arguments = { 'r', 'g', 'b', 'a' },
+      returns = { 'material' }
+    }
+  }
+}

+ 6 - 9
api/lovr/graphics/newModel.lua

@@ -2,8 +2,8 @@ return {
   tag = 'graphicsObjects',
   tag = 'graphicsObjects',
   summary = 'Create a new Model.',
   summary = 'Create a new Model.',
   description = [[
   description = [[
-    Creates a new Model from a file.  The supported 3D file formats are `obj`, `fbx`, and collada.
-    Models use normals and texture coordinates, if provided.
+    Creates a new Model from a file.  The supported 3D file formats are `obj`, `fbx`, `gltf`, and
+    collada.  Models use normals and texture coordinates, if provided.
 
 
     The following features are not supported yet: animations, materials, vertex colors.
     The following features are not supported yet: animations, materials, vertex colors.
   ]],
   ]],
@@ -12,12 +12,6 @@ return {
       name = 'filename',
       name = 'filename',
       type = 'string',
       type = 'string',
       description = 'The filename of the model to load.'
       description = 'The filename of the model to load.'
-    },
-    {
-      name = 'texture',
-      type = 'string',
-      default = 'nil',
-      description = 'A filename for a texture to apply to the Model, or `nil` for no texture.'
     }
     }
   },
   },
   returns = {
   returns = {
@@ -26,5 +20,8 @@ return {
       type = 'Model',
       type = 'Model',
       description = 'The new Model.'
       description = 'The new Model.'
     }
     }
-  }
+  },
+  notes = [[
+    Models loaded from glTF files do not currently import animations properly.
+  ]]
 }
 }

+ 0 - 60
api/lovr/graphics/newSkybox.lua

@@ -1,60 +0,0 @@
-return {
-  tag = 'graphicsObjects',
-  summary = 'Create a new Skybox.',
-  description = 'Creates a new Skybox from a set of 6 images.',
-  arguments = {
-    right = {
-      type = 'string',
-      description = 'The filename of the image for the right face of the skybox.'
-    },
-    left = {
-      type = 'string',
-      description = 'The filename of the image for the left face of the skybox.'
-    },
-    top = {
-      type = 'string',
-      description = 'The filename of the image for the top face of the skybox.'
-    },
-    bottom = {
-      type = 'string',
-      description = 'The filename of the image for the bottom face of the skybox.'
-    },
-    back = {
-      type = 'string',
-      description = 'The filename of the image for the back face of the skybox.'
-    },
-    front = {
-      type = 'string',
-      description = 'The filename of the image for the front face of the skybox.'
-    },
-    images = {
-      type = 'table',
-      description = 'A table containing 6 images, as described above.'
-    },
-    image = {
-      type = 'string',
-      description = 'A filename for an equirectangular image to load.'
-    }
-  },
-  returns = {
-    skybox = {
-      type = 'Skybox',
-      description = 'The new Skybox.'
-    }
-  },
-  variants = {
-    {
-      arguments = { 'right', 'left', 'top', 'bottom', 'back', 'front' },
-      returns = { 'skybox' }
-    },
-    {
-      arguments = { 'images' },
-      returns = { 'skybox' }
-    },
-    {
-      description = 'Creates a Skybox from a single equirectangular image.',
-      arguments = { 'image' },
-      returns = { 'skybox' }
-    }
-  }
-}

+ 62 - 3
api/lovr/graphics/newTexture.lua

@@ -7,6 +7,47 @@ return {
       type = 'string',
       type = 'string',
       description = 'The filename of the image to load.'
       description = 'The filename of the image to load.'
     },
     },
+    right = {
+      type = 'string',
+      description = 'The filename of the image for the positive x direction.'
+    },
+    left = {
+      type = 'string',
+      description = 'The filename of the image for the negative x direction.'
+    },
+    top = {
+      type = 'string',
+      description = 'The filename of the image for the positive y direction.'
+    },
+    bottom = {
+      type = 'string',
+      description = 'The filename of the image for the negative y direction.'
+    },
+    back = {
+      type = 'string',
+      description = 'The filename of the image for the positive z direction.'
+    },
+    front = {
+      type = 'string',
+      description = 'The filename of the image for the negative z direction.'
+    },
+    images = {
+      type = 'table',
+      description = 'The table of image filenames.  Either 1 or 6 can be provided, as above.'
+    },
+    flags = {
+      type = 'table',
+      default = '{}',
+      description = 'Optional settings for the texture.',
+      table = {
+        {
+          name = 'linear',
+          type = 'boolean',
+          default = 'false',
+          description = 'Whether the texture is in linear color space instead of sRGB.'
+        }
+      }
+    },
     width = {
     width = {
       type = 'number',
       type = 'number',
       description = 'The width of the Texture, in pixels.'
       description = 'The width of the Texture, in pixels.'
@@ -21,7 +62,6 @@ return {
     },
     },
     msaa = {
     msaa = {
       type = 'number',
       type = 'number',
-      default = '0',
       description = 'The number of samples to use for multisample antialiasing.'
       description = 'The number of samples to use for multisample antialiasing.'
     }
     }
   },
   },
@@ -34,12 +74,31 @@ return {
   },
   },
   variants = {
   variants = {
     {
     {
-      arguments = { 'filename' },
+      arguments = { 'filename', 'flags' },
+      returns = { 'texture' }
+    },
+    {
+      description = [[
+        Creates a new cubemap texture from 6 images.  It can be used as a skybox using
+        `lovr.graphics.skybox`.
+      ]],
+      arguments = { 'right', 'left', 'top', 'bottom', 'back', 'front', 'flags' },
       returns = { 'texture' }
       returns = { 'texture' }
     },
     },
     {
     {
+      description = 'Create a new texture from a table of images.',
+      arguments = { 'images', 'flags' },
+      returns = { 'texture' }
+    },
+    {
+      description = 'Create a render texture (also called a "framebuffer" or a "canvas").',
       arguments = { 'width', 'height', 'projection', 'msaa' },
       arguments = { 'width', 'height', 'projection', 'msaa' },
       returns = { 'texture' }
       returns = { 'texture' }
     }
     }
-  }
+  },
+  notes = [[
+    The "linear" flag should be set to true for textures that don't contain color information, such
+    as normal maps.  It is ignored if gamma correct rendering is disabled.  See
+    `lovr.graphics.isGammaCorrect` for more info.
+  ]]
 }
 }

+ 7 - 3
api/lovr/graphics/plane.lua

@@ -5,7 +5,11 @@ return {
   arguments = {
   arguments = {
     texture = {
     texture = {
       type = 'Texture',
       type = 'Texture',
-      description = 'The texture to apply to the plane.'
+      description = 'The texture to use.'
+    },
+    material = {
+      type = 'Material',
+      description = 'The material to apply to the plane.'
     },
     },
     mode = {
     mode = {
       type = 'DrawMode',
       type = 'DrawMode',
@@ -60,8 +64,8 @@ return {
       returns = {}
       returns = {}
     },
     },
     {
     {
-      description = 'Draw a textured plane.',
-      arguments = { 'texture', 'x', 'y', 'z', 'size', 'angle', 'ax', 'ay', 'az' },
+      description = 'Draw a plane with a custom material.',
+      arguments = { 'material', 'x', 'y', 'z', 'size', 'angle', 'ax', 'ay', 'az' },
       returns = {}
       returns = {}
     },
     },
     {
     {

+ 2 - 2
api/lovr/graphics/setBackgroundColor.lua

@@ -2,7 +2,7 @@ return {
   tag = 'graphicsState',
   tag = 'graphicsState',
   summary = 'Set the background color.',
   summary = 'Set the background color.',
   description = [[
   description = [[
-    Sets the background color used to clear the screen.  Color components are from 0 to 255.
+    Sets the background color used to clear the screen.  Color components are from 0.0 to 1.0.
   ]],
   ]],
   arguments = {
   arguments = {
     {
     {
@@ -23,7 +23,7 @@ return {
     {
     {
       name = 'a',
       name = 'a',
       type = 'number',
       type = 'number',
-      default = '255',
+      default = '1.0',
       description = 'The alpha component of the background color.'
       description = 'The alpha component of the background color.'
     }
     }
   },
   },

+ 3 - 3
api/lovr/graphics/setColor.lua

@@ -2,7 +2,7 @@ return {
   tag = 'graphicsState',
   tag = 'graphicsState',
   summary = 'Set the global color factor.',
   summary = 'Set the global color factor.',
   description = [[
   description = [[
-    Sets the color used for drawing objects.  Color components are from 0 to 255.  Every pixel drawn
+    Sets the color used for drawing objects.  Color components are from 0.0 to 1.0.  Every pixel drawn
     will be multiplied (i.e. tinted) by this color.  This is a global setting, so it will affect all
     will be multiplied (i.e. tinted) by this color.  This is a global setting, so it will affect all
     subsequent drawing operations.
     subsequent drawing operations.
   ]],
   ]],
@@ -21,7 +21,7 @@ return {
     },
     },
     a = {
     a = {
       type = 'number',
       type = 'number',
-      default = '255',
+      default = '1.0',
       description = 'The alpha component of the color.'
       description = 'The alpha component of the color.'
     },
     },
     color = {
     color = {
@@ -45,7 +45,7 @@ return {
     description = 'Draw a red cube.',
     description = 'Draw a red cube.',
     code = [[
     code = [[
       function lovr.draw()
       function lovr.draw()
-        lovr.graphics.setColor(255, 0, 0)
+        lovr.graphics.setColor(1.0, 0, 0)
         lovr.graphics.cube('fill', 0, 1.7, -1, .5, lovr.timer.getTime())
         lovr.graphics.cube('fill', 0, 1.7, -1, .5, lovr.timer.getTime())
       end
       end
     ]]
     ]]

+ 56 - 0
api/lovr/graphics/skybox.lua

@@ -0,0 +1,56 @@
+return {
+  tag = 'graphicsPrimitives',
+  summary = 'Render a skybox.',
+  description = [[
+    Render a skybox from a texture.  Two common kinds of skybox textures are supported: A rectangular
+    texture with an equirectangular projection can be used, or a "cubemap" texture created from 6
+    images.
+  ]],
+  arguments = {
+    {
+      name = 'texture',
+      type = 'Texture',
+      description = 'The texture to use.'
+    },
+    angle = {
+      type = 'number',
+      default = '0',
+      description = 'How much to rotate the skybox around its axis of rotation.'
+    },
+    ax = {
+      type = 'number',
+      default = '0',
+      description = 'The x coordinate of the axis of rotation.'
+    },
+    ay = {
+      type = 'number',
+      default = '1',
+      description = 'The y coordinate of the axis of rotation.'
+    },
+    az = {
+      type = 'number',
+      default = '0',
+      description = 'The z coordinate of the axis of rotation.'
+    }
+  },
+  returns = {},
+  example = [[
+    function lovr.load()
+      skybox = lovr.graphics.newTexture(
+        'right.png',
+        'left.png',
+        'up.png',
+        'down.png',
+        'back.png',
+        'front.png'
+      )
+
+      -- or skybox = lovr.graphics.newTexture('equirectangular.png')
+    end
+
+    function lovr.draw()
+      local angle, ax, ay, az = lovr.headset.getOrientation()
+      lovr.graphics.skybox(skybox, -angle, ax, ay, az)
+    end
+  ]]
+}

+ 24 - 20
api/lovr/graphics/triangle.lua

@@ -3,57 +3,61 @@ return {
   summary = 'Draw a triangle.',
   summary = 'Draw a triangle.',
   description = 'Draws a triangle from three points.',
   description = 'Draws a triangle from three points.',
   arguments = {
   arguments = {
-    {
-      name = 'mode',
+    mode = {
       type = 'DrawMode',
       type = 'DrawMode',
       description = 'How to draw the triangle.'
       description = 'How to draw the triangle.'
     },
     },
-    {
-      name = 'x1',
+    material = {
+      type = 'Material',
+      description = 'The Material to apply.'
+    },
+    x1 = {
       type = 'number',
       type = 'number',
       description = 'The x coordinate of the first point.'
       description = 'The x coordinate of the first point.'
     },
     },
-    {
-      name = 'y1',
+    y1 = {
       type = 'number',
       type = 'number',
       description = 'The y coordinate of the first point.'
       description = 'The y coordinate of the first point.'
     },
     },
-    {
-      name = 'z1',
+    z1 = {
       type = 'number',
       type = 'number',
       description = 'The z coordinate of the first point.'
       description = 'The z coordinate of the first point.'
     },
     },
-    {
-      name = 'x2',
+    x2 = {
       type = 'number',
       type = 'number',
       description = 'The x coordinate of the second point.'
       description = 'The x coordinate of the second point.'
     },
     },
-    {
-      name = 'y2',
+    y2 = {
       type = 'number',
       type = 'number',
       description = 'The y coordinate of the second point.'
       description = 'The y coordinate of the second point.'
     },
     },
-    {
-      name = 'z2',
+    z2 = {
       type = 'number',
       type = 'number',
       description = 'The z coordinate of the second point.'
       description = 'The z coordinate of the second point.'
     },
     },
-    {
-      name = 'x3',
+    x3 = {
       type = 'number',
       type = 'number',
       description = 'The x coordinate of the third point.'
       description = 'The x coordinate of the third point.'
     },
     },
-    {
-      name = 'y3',
+    y3 = {
       type = 'number',
       type = 'number',
       description = 'The y coordinate of the third point.'
       description = 'The y coordinate of the third point.'
     },
     },
-    {
-      name = 'z3',
+    z3 = {
       type = 'number',
       type = 'number',
       description = 'The z coordinate of the third point.'
       description = 'The z coordinate of the third point.'
     }
     }
   },
   },
   returns = {},
   returns = {},
+  variants = {
+    {
+      arguments = { 'mode', 'x1', 'y1', 'z1', 'x2', 'y2', 'z2', 'x3', 'y3', 'z3' },
+      returns = {}
+    },
+    {
+      arguments = { 'material', 'x1', 'y1', 'z1', 'x2', 'y2', 'z2', 'x3', 'y3', 'z3' },
+      returns = {}
+    }
+  },
   notes = 'Unlike some of the other primitives, exactly 3 points are required here.'
   notes = 'Unlike some of the other primitives, exactly 3 points are required here.'
 }
 }

+ 71 - 0
api/lovr/math/Transform/getMatrix.lua

@@ -0,0 +1,71 @@
+return {
+  summary = 'Get the Transform\'s matrix.',
+  description = 'Returns the individual matrix components of a Transform, in column-major order.',
+  arguments = {},
+  returns = {
+    {
+      name = 'm11',
+      type = 'number'
+    },
+    {
+      name = 'm21',
+      type = 'number'
+    },
+    {
+      name = 'm31',
+      type = 'number'
+    },
+    {
+      name = 'm41',
+      type = 'number'
+    },
+    {
+      name = 'm12',
+      type = 'number'
+    },
+    {
+      name = 'm22',
+      type = 'number'
+    },
+    {
+      name = 'm32',
+      type = 'number'
+    },
+    {
+      name = 'm42',
+      type = 'number'
+    },
+    {
+      name = 'm13',
+      type = 'number'
+    },
+    {
+      name = 'm23',
+      type = 'number'
+    },
+    {
+      name = 'm33',
+      type = 'number'
+    },
+    {
+      name = 'm43',
+      type = 'number'
+    },
+    {
+      name = 'm14',
+      type = 'number'
+    },
+    {
+      name = 'm24',
+      type = 'number'
+    },
+    {
+      name = 'm34',
+      type = 'number'
+    },
+    {
+      name = 'm44',
+      type = 'number'
+    }
+  }
+}

+ 86 - 0
api/lovr/math/Transform/setMatrix.lua

@@ -0,0 +1,86 @@
+return {
+  summary = 'Set the Transform\'s matrix.',
+  description = 'Sets the individual matrix components of a Transform, in column-major order.',
+  arguments = {
+    m11 = {
+      type = 'number'
+    },
+    m21 = {
+      type = 'number'
+    },
+    m31 = {
+      type = 'number'
+    },
+    m41 = {
+      type = 'number'
+    },
+    m12 = {
+      type = 'number'
+    },
+    m22 = {
+      type = 'number'
+    },
+    m32 = {
+      type = 'number'
+    },
+    m42 = {
+      type = 'number'
+    },
+    m13 = {
+      type = 'number'
+    },
+    m23 = {
+      type = 'number'
+    },
+    m33 = {
+      type = 'number'
+    },
+    m43 = {
+      type = 'number'
+    },
+    m14 = {
+      type = 'number'
+    },
+    m24 = {
+      type = 'number'
+    },
+    m34 = {
+      type = 'number'
+    },
+    m44 = {
+      type = 'number'
+    },
+    m = {
+      type = 'table',
+      description = 'A table containing the matrix values, as above.'
+    }
+  },
+  returns = {},
+  variants = {
+    {
+      arguments = {
+        'm11',
+        'm21',
+        'm31',
+        'm41',
+        'm12',
+        'm22',
+        'm32',
+        'm42',
+        'm13',
+        'm23',
+        'm33',
+        'm43',
+        'm14',
+        'm24',
+        'm34',
+        'm44'
+      },
+      returns = {}
+    },
+    {
+      arguments = { 'm' },
+      returns = {}
+    }
+  }
+}

+ 64 - 0
api/lovr/math/gammaToLinear.lua

@@ -0,0 +1,64 @@
+return {
+  summary = '	Convert a color from gamma space to linear space.',
+  description = 'Converts a color from gamma space to linear space.',
+  arguments = {
+    gr = {
+      type = 'number',
+      description = 'The red component of the gamma-space color.'
+    },
+    gg = {
+      type = 'number',
+      description = 'The green component of the gamma-space color.'
+    },
+    gb = {
+      type = 'number',
+      description = 'The blue component of the gamma-space color.'
+    },
+    color = {
+      type = 'table',
+      description = 'A table containing the components of a gamma-space color.'
+    },
+    x = {
+      type = 'number',
+      description = 'The color channel to convert.'
+    }
+  },
+  returns = {
+    lr = {
+      type = 'number',
+      description = 'The red component of the resulting linear-space color.'
+    },
+    lg = {
+      type = 'number',
+      description = 'The green component of the resulting linear-space color.'
+    },
+    lb = {
+      type = 'number',
+      description = 'The blue component of the resulting linear-space color.'
+    },
+    y = {
+      type = 'number',
+      description = 'The converted color channel.'
+    }
+  },
+  variants = {
+    {
+      arguments = { 'gr', 'gg', 'gb' },
+      returns = { 'lr', 'lg', 'lb' }
+    },
+    {
+      description = 'A table can also be used.',
+      arguments = { 'color' },
+      returns = { 'lr', 'lg', 'lb' }
+    },
+    {
+      description = 'Convert a single color channel.',
+      arguments = { 'x' },
+      returns = { 'y' }
+    }
+  },
+  related = {
+    'lovr.math.linearToGamma',
+    'lovr.graphics.isGammaCorrect'
+  }
+}

+ 64 - 0
api/lovr/math/linearToGamma.lua

@@ -0,0 +1,64 @@
+return {
+  summary = '	Convert a color from linear space to gamma space.',
+  description = 'Converts a color from linear space to gamma space.',
+  arguments = {
+    lr = {
+      type = 'number',
+      description = 'The red component of the linear-space color.'
+    },
+    lg = {
+      type = 'number',
+      description = 'The green component of the linear-space color.'
+    },
+    lb = {
+      type = 'number',
+      description = 'The blue component of the linear-space color.'
+    },
+    color = {
+      type = 'table',
+      description = 'A table containing the components of a linear-space color.'
+    },
+    x = {
+      type = 'number',
+      description = 'The color channel to convert.'
+    }
+  },
+  returns = {
+    gr = {
+      type = 'number',
+      description = 'The red component of the resulting gamma-space color.'
+    },
+    gg = {
+      type = 'number',
+      description = 'The green component of the resulting gamma-space color.'
+    },
+    gb = {
+      type = 'number',
+      description = 'The blue component of the resulting gamma-space color.'
+    },
+    y = {
+      type = 'number',
+      description = 'The converted color channel.'
+    }
+  },
+  variants = {
+    {
+      arguments = { 'lr', 'lg', 'lb' },
+      returns = { 'gr', 'gg', 'gb' }
+    },
+    {
+      description = 'A table can also be used.',
+      arguments = { 'color' },
+      returns = { 'gr', 'gg', 'gb' }
+    },
+    {
+      description = 'Convert a single color channel.',
+      arguments = { 'x' },
+      returns = { 'y' }
+    }
+  },
+  related = {
+    'lovr.math.gammaToLinear',
+    'lovr.graphics.isGammaCorrect'
+  }
+}

+ 63 - 0
api/lovr/math/orientationToDirection.lua

@@ -0,0 +1,63 @@
+return {
+  summary = 'Convert an angle/axis orientation to a direction vector.',
+  description = 'Converts a rotation in angle/axis representation into a direction vector.',
+  arguments = {
+    {
+      name = 'angle',
+      type = 'number',
+      description = 'The angle (in radians).'
+    },
+    {
+      name = 'ax',
+      type = 'number',
+      default = '0',
+      description = 'The x component of the axis of rotation.'
+    },
+    {
+      name = 'ay',
+      type = 'number',
+      default = '1',
+      description = 'The y component of the axis of rotation.'
+    },
+    {
+      name = 'az',
+      type = 'number',
+      default = '0',
+      description = 'The z component of the axis of rotation.'
+    }
+  },
+  returns = {
+    {
+      name = 'x',
+      type = 'number',
+      description = 'The x component of the direction vector.'
+    },
+    {
+      name = 'y',
+      type = 'number',
+      description = 'The y component of the direction vector.'
+    },
+    {
+      name = 'z',
+      type = 'number',
+      description = 'The z component of the direction vector.'
+    }
+  },
+  example = {
+    description = 'Give Controllers laser beams.',
+    code = [[
+      function lovr.draw()
+        for i, controller in ipairs(lovr.headset.getControllers()) do
+          local x, y, z = controller:getPosition()
+          local angle, ax, ay, az = controller:getOrientation()
+          local dx, dy, dz = lovr.math.orientationToDirection(angle, ax, ay, az)
+          local length = 2
+          lovr.graphics.line(x, y, z, x + dx * length, y + dy * length, z + dz * length)
+        end
+      end
+    ]]
+  },
+  related = {
+    'lovr.math.lookAt'
+  }
+}

+ 1 - 0
examples/Lighting/conf.lua

@@ -1,3 +1,4 @@
 function lovr.conf(t)
 function lovr.conf(t)
   t.window.msaa = 4
   t.window.msaa = 4
+  t.gammacorrect = true
 end
 end

+ 0 - 1
examples/Lighting/main.lua

@@ -36,7 +36,6 @@ function lovr.load()
 
 
       vec3 cFinal = vec3(diffuse) * cDiffuse + vec3(specular) * cSpecular;
       vec3 cFinal = vec3(diffuse) * cDiffuse + vec3(specular) * cSpecular;
       cFinal = clamp(cFinal, cAmbient, vec3(1.));
       cFinal = clamp(cFinal, cAmbient, vec3(1.));
-      cFinal = pow(cFinal, vec3(.4545));
       return vec4(cFinal, 1.) * graphicsColor * texture(image, uv);
       return vec4(cFinal, 1.) * graphicsColor * texture(image, uv);
     }
     }
   ]])
   ]])

+ 2 - 2
examples/Panorama/main.lua

@@ -1,10 +1,10 @@
 local skybox
 local skybox
 
 
 function lovr.load()
 function lovr.load()
-  skybox = lovr.graphics.newSkybox('equirectangular.jpg')
+  skybox = lovr.graphics.newTexture('equirectangular.jpg')
 end
 end
 
 
 function lovr.draw()
 function lovr.draw()
   local angle, x, y, z = lovr.headset.getOrientation()
   local angle, x, y, z = lovr.headset.getOrientation()
-  skybox:draw(-angle, x, y, z)
+  lovr.graphics.skybox(skybox, -angle, x, y, z)
 end
 end

+ 3 - 3
examples/Physics/main.lua

@@ -39,15 +39,15 @@ function drawBox(box)
 end
 end
 
 
 function lovr.draw()
 function lovr.draw()
-  lovr.graphics.setBackgroundColor(200, 200, 200)
+  lovr.graphics.setBackgroundColor(.8, .8, .8)
   lovr.graphics.setShader(shader)
   lovr.graphics.setShader(shader)
 
 
-  lovr.graphics.setColor(255, 0, 0)
+  lovr.graphics.setColor(1, 0, 0)
   for i, box in ipairs(boxes) do
   for i, box in ipairs(boxes) do
     drawBox(box)
     drawBox(box)
   end
   end
 
 
-  lovr.graphics.setColor(0, 0, 255)
+  lovr.graphics.setColor(0, 0, 1)
   for i, box in ipairs(controllerBoxes) do
   for i, box in ipairs(controllerBoxes) do
     drawBox(box)
     drawBox(box)
   end
   end

+ 11 - 11
examples/Primitives/main.lua

@@ -1,12 +1,12 @@
 shader = require 'shader'
 shader = require 'shader'
 
 
 local function drawLabel(str, x, y, z)
 local function drawLabel(str, x, y, z)
-  lovr.graphics.setColor(255, 255, 255)
+  lovr.graphics.setColor(1, 1, 1)
   lovr.graphics.print(str, x, y, z, .1)
   lovr.graphics.print(str, x, y, z, .1)
 end
 end
 
 
 function lovr.draw()
 function lovr.draw()
-  lovr.graphics.setBackgroundColor(30, 30, 30)
+  lovr.graphics.setBackgroundColor(.1, .1, .1)
   lovr.graphics.setShader(shader)
   lovr.graphics.setShader(shader)
 
 
   local hx, hy, hz = lovr.headset.getPosition()
   local hx, hy, hz = lovr.headset.getPosition()
@@ -15,7 +15,7 @@ function lovr.draw()
   -- Point
   -- Point
   x, y, z = -.6, 1.1, -1
   x, y, z = -.6, 1.1, -1
   lovr.graphics.setPointSize(5)
   lovr.graphics.setPointSize(5)
-  lovr.graphics.setColor(255, 255, 255)
+  lovr.graphics.setColor(1, 1, 1)
   lovr.graphics.points(x, y, z)
   lovr.graphics.points(x, y, z)
 
 
   -- Line
   -- Line
@@ -24,7 +24,7 @@ function lovr.draw()
     x - .1, y, z,
     x - .1, y, z,
     x + .1, y, z
     x + .1, y, z
   }
   }
-  lovr.graphics.setColor(255, 255, 255)
+  lovr.graphics.setColor(1, 1, 1)
   lovr.graphics.line(points)
   lovr.graphics.line(points)
 
 
   -- Triangle
   -- Triangle
@@ -32,37 +32,37 @@ function lovr.draw()
   local p1 = { x, y + .2, z }
   local p1 = { x, y + .2, z }
   local p2 = { x - .2, y - .2, z }
   local p2 = { x - .2, y - .2, z }
   local p3 = { x + .2, y - .2, z }
   local p3 = { x + .2, y - .2, z }
-  lovr.graphics.setColor(92, 107, 192)
+  lovr.graphics.setColor(.36, .41, .75)
   lovr.graphics.triangle('fill', p1[1], p1[2], p1[3], p2[1], p2[2], p2[3], p3[1], p3[2], p3[3])
   lovr.graphics.triangle('fill', p1[1], p1[2], p1[3], p2[1], p2[2], p2[3], p3[1], p3[2], p3[3])
 
 
   -- Plane
   -- Plane
   local x, y, z = -.6, 1.7, -1.5
   local x, y, z = -.6, 1.7, -1.5
-  lovr.graphics.setColor(239, 83, 80)
+  lovr.graphics.setColor(.94, .33, .31)
   lovr.graphics.plane('fill', x, y, z, .4, lovr.timer.getTime())
   lovr.graphics.plane('fill', x, y, z, .4, lovr.timer.getTime())
 
 
   -- Cube
   -- Cube
   local x, y, z = 0, 1.7, -1.5
   local x, y, z = 0, 1.7, -1.5
-  lovr.graphics.setColor(126, 87, 194)
+  lovr.graphics.setColor(.49, .34, .76)
   lovr.graphics.cube('fill', x, y, z, .3, lovr.timer.getTime())
   lovr.graphics.cube('fill', x, y, z, .3, lovr.timer.getTime())
 
 
   -- Box
   -- Box
   local x, y, z = .6, 1.7, -1.5
   local x, y, z = .6, 1.7, -1.5
-  lovr.graphics.setColor(255, 167, 45)
+  lovr.graphics.setColor(1, .65, .18)
   lovr.graphics.box('fill', x, y, z, .4, .2, .3, lovr.timer.getTime())
   lovr.graphics.box('fill', x, y, z, .4, .2, .3, lovr.timer.getTime())
 
 
   -- Cylinder
   -- Cylinder
   local x, y, z = -.6, 2.4, -2
   local x, y, z = -.6, 2.4, -2
-  lovr.graphics.setColor(102, 187, 106)
+  lovr.graphics.setColor(.4, .73, .42)
   lovr.graphics.cylinder(x - .2, y, z, x + .2, y, z, .1, .1)
   lovr.graphics.cylinder(x - .2, y, z, x + .2, y, z, .1, .1)
 
 
   -- Cone
   -- Cone
   local x, y, z = 0, 2.4, -2
   local x, y, z = 0, 2.4, -2
-  lovr.graphics.setColor(255, 241, 118)
+  lovr.graphics.setColor(1, .95, .46)
   lovr.graphics.cylinder(x, y + .2, z, x, y - .2, z, 0, .18)
   lovr.graphics.cylinder(x, y + .2, z, x, y - .2, z, 0, .18)
 
 
   -- Sphere
   -- Sphere
   local x, y, z = .6, 2.4, -2
   local x, y, z = .6, 2.4, -2
-  lovr.graphics.setColor(77, 208, 255)
+  lovr.graphics.setColor(.3, .82, 1)
   lovr.graphics.sphere(x, y, z, .2)
   lovr.graphics.sphere(x, y, z, .2)
 
 
   lovr.graphics.setShader()
   lovr.graphics.setShader()

+ 6 - 6
guides/Callbacks_and_Modules.md

@@ -79,7 +79,7 @@ The graphics module is the most exciting module, and is also the largest.  Most
 These can be used to quickly prototype a scene without needing to create or load assets.
 These can be used to quickly prototype a scene without needing to create or load assets.
 
 
 There are lots of different rendering-related objects that can be created using `lovr.graphics`,
 There are lots of different rendering-related objects that can be created using `lovr.graphics`,
-such as `Model`, `Texture`, `Font`, `Shader`, `Skybox`, and more.  Every function to create a new
+such as `Model`, `Texture`, `Font`, `Shader`, and more.  Every function to create a new
 object is prefixed with `new`, so to create a 3D model object you can use `lovr.graphics.newModel`.
 object is prefixed with `new`, so to create a 3D model object you can use `lovr.graphics.newModel`.
 
 
 > Note: Creating graphics objects uses memory and can slow things down if done every frame.  For
 > Note: Creating graphics objects uses memory and can slow things down if done every frame.  For
@@ -107,14 +107,14 @@ end
 
 
 function lovr.draw()
 function lovr.draw()
   -- Use a dark grey background
   -- Use a dark grey background
-  lovr.graphics.setBackgroundColor(50, 50, 50)
+  lovr.graphics.setBackgroundColor(.2, .2, .2)
 
 
   -- Draw the model
   -- Draw the model
-  lovr.graphics.setColor(255, 255, 255)
+  lovr.graphics.setColor(1.0, 1.0, 1.0)
   model:draw(-.5, 1, -3)
   model:draw(-.5, 1, -3)
 
 
   -- Draw a red cube using the "cube" primitive
   -- Draw a red cube using the "cube" primitive
-  lovr.graphics.setColor(255, 0, 0)
+  lovr.graphics.setColor(1.0, 0, 0)
   lovr.graphics.cube('fill', .5, 1, -3, .5, lovr.timer.getTime())
   lovr.graphics.cube('fill', .5, 1, -3, .5, lovr.timer.getTime())
 end
 end
 ```
 ```
@@ -229,12 +229,12 @@ function drawBox(box)
 end
 end
 
 
 function lovr.draw()
 function lovr.draw()
-  lovr.graphics.setColor(255, 0, 0)
+  lovr.graphics.setColor(1.0, 0, 0)
   for i, box in ipairs(boxes) do
   for i, box in ipairs(boxes) do
     drawBox(box)
     drawBox(box)
   end
   end
 
 
-  lovr.graphics.setColor(0, 0, 255)
+  lovr.graphics.setColor(0, 0, 1.0)
   for i, box in ipairs(controllerBoxes) do
   for i, box in ipairs(controllerBoxes) do
     drawBox(box)
     drawBox(box)
   end
   end

+ 0 - 1
guides/Libraries.md

@@ -26,7 +26,6 @@ List of Libraries
 - [flux](https://github.com/rxi/flux) - A tweening library for Lua.
 - [flux](https://github.com/rxi/flux) - A tweening library for Lua.
 - [handy](https://github.com/bjornbytes/handy) - Helper utilities for managing controllers.
 - [handy](https://github.com/bjornbytes/handy) - Helper utilities for managing controllers.
 - [knife](https://github.com/airstruck/knife) - A collection of useful micromodules for Lua.
 - [knife](https://github.com/airstruck/knife) - A collection of useful micromodules for Lua.
-- [lovr-circle](https://github.com/bjornbytes/lovr-circle) - Create circle geometry.
 - [lovr-icosphere](https://github.com/bjornbytes/lovr-icosphere) - A library to create icospheres.
 - [lovr-icosphere](https://github.com/bjornbytes/lovr-icosphere) - A library to create icospheres.
 - [lovr-grid](https://github.com/bjornbytes/lovr-grid) - A library for drawing grids.
 - [lovr-grid](https://github.com/bjornbytes/lovr-grid) - A library for drawing grids.
 - [lovr-lighting](https://github.com/bjornbytes/lovr-lighting) - Simple lighting shaders to add to
 - [lovr-lighting](https://github.com/bjornbytes/lovr-lighting) - Simple lighting shaders to add to

Some files were not shown because too many files changed in this diff