bjorn 2 rokov pred
rodič
commit
a451bfdb62

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 1087 - 891
api/init.lua


+ 1 - 1
api/lovr/callbacks/conf.lua

@@ -296,7 +296,7 @@ return {
           t.graphics.shadercache = true
 
           -- Headset settings
-          t.headset.drivers = { 'openxr', 'webxr', 'desktop' }
+          t.headset.drivers = { 'openxr', 'desktop' }
           t.headset.supersample = false
           t.headset.offset = 1.7
           t.headset.antialias = true

+ 9 - 19
api/lovr/callbacks/mirror.lua

@@ -4,43 +4,33 @@ return {
   description = [[
     This callback is called every frame after rendering to the headset and is usually used to render
     a mirror of the headset display onto the desktop window.  It can be overridden for custom
-    mirroring behavior.  For example, you could render a single eye instead of a stereo view, apply
-    postprocessing effects, add 2D UI, or render the scene from an entirely different viewpoint for
-    a third person camera.
+    mirroring behavior.  For example, a stereo view could be drawn instead of a single eye or a 2D
+    HUD could be rendered.
   ]],
   arguments = {},
   returns = {},
-  notes = [[
-    When this callback is called, the camera is located at `(0, 0, 0)` and is looking down the
-    negative-z axis.
-
-    Note that the usual graphics state applies while `lovr.mirror` is invoked, so you may need to
-    reset graphics state at the end of `lovr.draw` to get the result you want.
-  ]],
   example = {
     description = [[
       The default `lovr.mirror` implementation draws the headset mirror texture to the window if
       the headset is active, or just calls `lovr.draw` if there isn't a headset.
     ]],
     code = [[
-      function lovr.mirror()
+      function lovr.mirror(pass)
         if lovr.headset then
-          local texture = lovr.headset.getMirrorTexture()
+          local texture = lovr.headset.getTexture()
           if texture then
-            lovr.graphics.fill(texture)
+            pass:fill(texture)
+          else
+            return true
           end
         else
-          lovr.graphics.clear()
-          lovr.draw()
+          return lovr.draw and lovr.draw(pass)
         end
       end
     ]]
   },
   related = {
-    'lovr.headset.renderTo',
-    'lovr.headset.getMirrorTexture',
-    'lovr.graphics.createWindow',
-    'lovr.graphics.setProjection',
+    'lovr.system.openWindow',
     'lovr.draw'
   }
 }

+ 10 - 9
api/lovr/graphics/Pass/compute.lua

@@ -2,9 +2,9 @@ return {
   tag = 'compute',
   summary = 'Run a compute shader.',
   description = [[
-    Runs a compute shader.  Compute shaders are run in 3D grids of workgroups.  Each workgroup is
-    itself a 3D grid of threads, declared using `local_size_x`, `local_size_y`, and `local_size_z`
-    in the shader code.
+    Runs a compute shader.  Compute shaders are run in 3D grids of workgroups.  Each local workgroup
+    is itself a 3D grid of invocations, declared using `local_size_x`, `local_size_y`, and
+    `local_size_z` in the shader code.
   ]],
   arguments = {
      x = {
@@ -48,11 +48,12 @@ return {
     }
   },
   notes = [[
-    All these 3D grids can get confusing, but the basic idea is to make the local size a small block
-    of e.g. 8x8 pixels or 4x4x4 voxels, and then dispatch however many workgroups are needed to
-    cover an image or voxel field.  The reason to do it this way is that the GPU runs threads in
-    little bundles called subgroups.  Subgroups usually have 32 or 64 threads in them (the exact
-    size is given by the `subgroupSize` property of `lovr.graphics.getDevice`).  If the local size
-    was `1x1x1`, then the GPU would only run 1 thread per subgroup and waste the other 31 or 63.
+    All these 3D grids can get confusing, but the basic idea is to make the local workgroup size a
+    small block of e.g. 8x8 pixels or 4x4x4 voxels, and then dispatch however many global workgroups
+    are needed to cover an image or voxel field.  The reason to do it this way is that the GPU runs
+    invocations in bundles called subgroups.  Subgroups are usually 32 or 64 invocations (the exact
+    size is given by the `subgroupSize` property of `lovr.graphics.getDevice`).  If the local
+    workgroup size was `1x1x1`, then the GPU would only run 1 invocation per subgroup and waste the
+    other 31 or 63.
   ]]
 }

+ 36 - 2
api/lovr/graphics/Pass/send.lua

@@ -1,7 +1,10 @@
 return {
   tag = 'shader-inputs',
   summary = 'Set the value of a shader variable.',
-  description = 'TODO',
+  description = [[
+    Sends a value to a variable in the Pass's active `Shader`.  The active shader is changed using
+    using `Pass:setShader`.
+  ]],
   arguments = {
     name = {
       type = 'string',
@@ -59,5 +62,36 @@ return {
       returns = {}
     }
   },
-  notes = 'TODO'
+  notes = [[
+    Shader variables can be in different "sets".  Variables changed by this function must be in set
+    #2, because LÖVR uses set #0 and set #1 internally.
+
+    The new value will persist until a new shader is set that uses a different "type" for the
+    binding number of the variable.  See `Pass:setShader` for more details.
+  ]],
+  example = [=[
+    function lovr.load()
+      shader = lovr.graphics.newShader([[
+        layout(set = 2, binding = 0) uniform sampler mySampler;
+        layout(set = 2, binding = 1) uniform Colors { vec4 colors[256]; };
+        layout(set = 2, binding = 2) uniform texture2D rocks;
+
+        vec4 lovrmain() {
+          return DefaultPosition;
+        }
+      ]], 'unlit')
+
+      clampler = lovr.graphics.newSampler({ wrap = 'clamp' })
+      colorBuffer = lovr.graphics.newBuffer(256, 'vec4')
+      rockTexture = lovr.graphics.newTexture('rocks.jpg')
+    end
+
+    function lovr.draw(pass)
+      pass:setShader(shader)
+      pass:send('mySampler', clampler)
+      pass:send('Colors', colorBuffer)
+      pass:send('rocks', rockTexture)
+      -- Draw
+    end
+  ]=]
 }

+ 5 - 1
api/lovr/graphics/Pass/setAlphaToCoverage.lua

@@ -1,7 +1,11 @@
 return {
   tag = 'pipeline',
   summary = 'Enable or disable alpha to coverage.',
-  description = 'TODO',
+  description = [[
+    Sets whether alpha to coverage is enabled.  Alpha to coverage factors the alpha of a pixel into
+    antialiasing calculations.  It can be used to get antialiased edges on textures with
+    transparency.  It's often used for foliage.
+  ]],
   arguments = {
     enable = {
       type = 'boolean',

+ 2 - 2
api/lovr/graphics/Pass/setBlendMode.lua

@@ -1,7 +1,7 @@
 return {
   tag = 'pipeline',
   summary = 'Set the blend mode.',
-  description = 'TODO',
+  description = 'Sets the blend mode.',
   arguments = {
     blend = {
       type = 'BlendMode',
@@ -9,7 +9,7 @@ return {
     },
     alphaBlend = {
       type = 'BlendAlphaMode',
-      description = 'The alpha blend mode.'
+      description = 'The alpha blend mode, used to control premultiplied alpha.'
     }
   },
   returns = {},

+ 28 - 2
api/lovr/graphics/Pass/setShader.lua

@@ -1,11 +1,14 @@
 return {
   tag = 'pipeline',
   summary = 'Set the active Shader.',
-  description = 'TODO',
+  description = [[
+    Sets the active shader.  In a render pass, the Shader will affect all drawing operations until
+    it is changed again.  In a compute pass, the Shader will be run when `Pass:compute` is called.
+  ]],
   arguments = {
     shader = {
       type = 'Shader',
-      description = 'A custom Shader object to use for rendering.'
+      description = 'The shader to use.'
     },
     default = {
       type = 'DefaultShader',
@@ -28,5 +31,28 @@ return {
       arguments = {},
       returns = {}
     }
+  },
+  notes = [[
+    Changing the shader will preserve resource bindings (the ones set using `Pass:send`) **unless**
+    the new shader declares a resource for a binding number using a different type than the current
+    shader.  In this case, the resource "type" means one of the following:
+
+    - Uniform buffer (`uniform`).
+    - Storage buffer (`buffer`).
+    - Sampled texture, (`uniform texture<type>`).
+    - Storage texture, (`uniform image<type>`).
+    - Sampler (`uniform sampler`).
+
+    If the new shader doesn't declare a resource in a particular binding number, any resource there
+    will be preserved.
+
+    If there's a clash in resource types like this, the variable will be "cleared".  Using a
+    buffer variable that has been cleared is not well-defined, and may return random data or even
+    crash the GPU.  For textures, white pixels will be returned.  Samplers will use `linear`
+    filtering and the `repeat` wrap mode.
+  ]],
+  related = {
+    'Pass:send',
+    'Pass:compute'
   }
 }

+ 1 - 1
api/lovr/graphics/Sampler/init.lua

@@ -4,7 +4,7 @@ return {
     Samplers are objects that control how pixels are read from a texture.  They can control whether
     the pixels are smoothed, whether the texture wraps at the edge of its UVs, and more.
 
-    Each has a default sampler that will be used by default, which can be changed using
+    Each `Pass` has a default sampler that will be used by default, which can be changed using
     `Pass:setSampler`.  Also, samplers can be declared in shaders using the following syntax:
 
         layout(set = 2, binding = X) uniform sampler mySampler;

+ 9 - 2
api/lovr/graphics/Shader/getWorkgroupSize.lua

@@ -1,6 +1,9 @@
 return {
   summary = 'Get the workgroup size of a compute shader.',
-  description = 'Returns the workgroup size of a compute shader.  TODO what is it.',
+  description = [[
+    Returns the workgroup size of a compute shader.  The workgroup size defines how many times a
+    compute shader is invoked for each workgroup dispatched by `Pass:compute`.
+  ]],
   arguments = {},
   returns = {
     x = {
@@ -21,5 +24,9 @@ return {
       arguments = {},
       returns = { 'x', 'y', 'z' }
     }
-  }
+  },
+  notes = [[
+    For example, if the workgroup size is `8x8x1` and `16x16x16` workgroups are dispatched, then the
+    compute shader will run `16 * 16 * 16 * (8 * 8 * 1) = 262144` times.
+  ]]
 }

+ 1 - 26
api/lovr/headset/HeadsetDriver.lua

@@ -4,41 +4,16 @@ return {
     These are all of the supported VR APIs that LÖVR can use to power the lovr.headset module.  You
     can change the order of headset drivers using `lovr.conf` to prefer or exclude specific VR APIs.
 
-    At startup, LÖVR searches through the list of drivers in order.  One headset driver will be used
-    for rendering to the VR display, and all supported headset drivers will be used for device
-    input.  The way this works is that when poses or button input is requested, the input drivers
-    are queried (in the order they appear in `conf.lua`) to see if any of them currently have data
-    for the specified device.  The first one that returns data will be used to provide the result.
-    This allows projects to support multiple types of hardware devices.
+    At startup, LÖVR searches through the list of drivers in order.
   ]],
   values = {
     {
       name = 'desktop',
       description = 'A VR simulator using keyboard/mouse.'
     },
-    {
-      name = 'oculus',
-      description = 'Oculus Desktop SDK.'
-    },
-    {
-      name = 'openvr',
-      description = 'OpenVR.'
-    },
     {
       name = 'openxr',
       description = 'OpenXR.'
-    },
-    {
-      name = 'vrapi',
-      description = 'Oculus Mobile SDK.'
-    },
-    {
-      name = 'pico',
-      description = 'Pico.'
-    },
-    {
-      name = 'webxr',
-      description = 'WebXR.'
     }
   }
 }

+ 4 - 4
api/lovr/headset/getClipDistance.lua

@@ -13,7 +13,9 @@ return {
     },
     far = {
       type = 'number',
-      description = 'The distance to the far clipping plane, in meters.'
+      description = [[
+        The distance to the far clipping plane, in meters, or 0 for an infinite far clipping plane.
+      ]]
     }
   },
   variants = {
@@ -23,8 +25,6 @@ return {
     }
   },
   notes = [[
-    The default near and far clipping planes are 0.1 meters and 100.0 meters.
-
-    This is not currently supported by the `vrapi` headset driver.
+    The default near and far clipping planes are 0.01 meters and 0.0 meters.
   ]]
 }

+ 1 - 5
api/lovr/headset/getMirrorTexture.lua

@@ -5,11 +5,7 @@ return {
     Returns a Texture that contains whatever is currently rendered to the headset.
 
     Sometimes this can be `nil` if the current headset driver doesn't have a mirror texture, which
-    can happen if the driver renders directly to the display.  Currently the `desktop`, `webxr`, and
-    `vrapi` drivers do not have a mirror texture.
-
-    It also isn't guaranteed that the same Texture will be returned by subsequent calls to this
-    function.  Currently, the `oculus` driver exhibits this behavior.
+    can happen if the driver renders directly to the display, like with the `desktop` driver.
   ]],
   arguments = {},
   returns = {

+ 1 - 40
api/lovr/headset/getName.lua

@@ -18,44 +18,5 @@ return {
       returns = { 'name' }
     }
   },
-  notes = [[
-    <table>
-      <thead>
-        <tr>
-          <td>driver</td>
-          <td>name</td>
-        </tr>
-      </thead>
-      <tbody>
-        <tr>
-          <td>desktop</td>
-          <td><code>Simulator</code></td>
-        </tr>
-        <tr>
-          <td>openvr</td>
-          <td>varies</td>
-        </tr>
-        <tr>
-          <td>openxr</td>
-          <td>varies</td>
-        </tr>
-        <tr>
-          <td>vrapi</td>
-          <td><code>Oculus Quest</code> or <code>Oculus Quest 2</code></td>
-        </tr>
-        <tr>
-          <td>webxr</td>
-          <td>always nil</td>
-        </tr>
-        <tr>
-          <td>oculus</td>
-          <td>varies</td>
-        </tr>
-        <tr>
-          <td>pico</td>
-          <td><code>Pico</code></td>
-        </tr>
-      </tbody>
-    </table>
-  ]]
+  notes = 'The desktop driver name will always be `Simulator`.'
 }

+ 14 - 12
api/lovr/headset/getSkeleton.lua

@@ -1,9 +1,9 @@
 return {
   tag = 'input',
-  summary = 'Get skeletal joint poses tracked by a device.',
+  summary = 'Get skeletal joint transforms tracked by a device.',
   description = [[
-    Returns a list of joint poses tracked by a device.  Currently, only hand devices are able to
-    track joints.
+    Returns a list of joint transforms tracked by a device.  Currently, only hand devices are able
+    to track joints.
   ]],
   arguments = {
     device = {
@@ -12,30 +12,32 @@ return {
     },
     t = {
       type = 'table',
-      description = 'A table to fill with the joint poses, instead of allocating a new one.'
+      description = 'A table to fill with the joint transforms, instead of allocating a new one.'
     }
   },
   returns = {
-    poses = {
+    transforms = {
       type = 'table',
       description = [[
-        A list of joint poses for the device.  Each pose is a table with 3 numbers for the position
-        of the joint followed by 4 numbers for the angle/axis orientation of the joint.
+        A list of joint transforms for the device.  Each transform is a table with 3 numbers for the
+        position of the joint, 1 number for the joint radius (in meters), and 4 numbers for the
+        angle/axis orientation of the joint.
       ]]
     }
   },
   variants = {
     {
       arguments = { 'device' },
-      returns = { 'poses' }
+      returns = { 'transforms' }
     },
     {
       arguments = { 'device', 't' },
-      returns = { 'poses' }
+      returns = { 'transforms' }
     }
   },
   notes = [[
-    If the Device does not support tracking joints or the poses are unavailable, `nil` is returned.
+    If the Device does not support tracking joints or the transforms are unavailable, `nil` is
+    returned.
 
     The joint orientation is similar to the graphics coordinate system: -Z is the forwards
     direction, pointing towards the fingertips.  The +Y direction is "up", pointing out of the back
@@ -164,10 +166,10 @@ return {
     </table>
   ]],
   example = [[
-    function lovr.draw()
+    function lovr.draw(pass)
       for _, hand in ipairs({ 'left', 'right' }) do
         for _, joint in ipairs(lovr.headset.getSkeleton(hand) or {}) do
-          lovr.graphics.points(unpack(joint, 1, 3))
+          pass:points(unpack(joint, 1, 3))
         end
       end
     end

+ 0 - 3
api/lovr/headset/renderTo.lua

@@ -36,9 +36,6 @@ return {
     }
   },
   notes = [[
-    When using the `pico` headset driver, headset rendering is asynchronous and the callback passed
-    to `lovr.headset.renderTo` will not be called immediately.
-
     At the beginning of the callback, the display is cleared to the background color.  The
     background color can be changed using `lovr.graphics.setBackgroundColor`.
 

+ 1 - 9
api/lovr/headset/vibrate.lua

@@ -37,13 +37,5 @@ return {
       arguments = { 'device', 'strength', 'duration', 'frequency' },
       returns = { 'vibrated' }
     }
-  },
-  notes = [[
-    When using the `openvr` headset driver on an HTC Vive, the value for the `duration` currently
-    must be less than .004 seconds.  Call this function several frames in a row for stronger or
-    prolonged vibration patterns.
-
-    On the Oculus Quest, devices can only be vibrated once per frame.  Any attempts after the first
-    will return `false`.
-  ]]
+  }
 }

+ 2 - 3
api/lovr/math/noise.lua

@@ -1,9 +1,8 @@
 return {
   tag = 'random',
-  summary = 'Generate perlin noise.',
+  summary = 'Generate simplex noise.',
   description = [[
-    Returns a 1D, 2D, 3D, or 4D perlin noise value.  The number will be between 0 and 1, and it will
-    always be 0.5 when the inputs are integers.
+    Returns a 1D, 2D, 3D, or 4D simplex noise value.  The number will be between 0 and 1.
   ]],
   arguments = {
     x = {

+ 2 - 0
api/main.lua

@@ -277,10 +277,12 @@ local function validateFunction(fn)
   for _, variant in ipairs(fn.variants) do
     for _, arg in ipairs(variant.arguments) do
       warnIf(not arg or not arg.name, 'Invalid argument for variant of %s', fn.key)
+      warnIf(not arg.type or (arg.type:match('^[A-Z]') and not lookup[arg.type]), 'Invalid or missing argument type %s in %s', arg.type, fn.key)
     end
 
     for _, ret in ipairs(variant.returns) do
       warnIf(not ret or not ret.name, 'Invalid return for variant of %s', fn.key)
+      warnIf(not ret.type or (ret.type:match('^[A-Z]') and not lookup[ret.type]), 'Invalid or missing return type %s for %s variant', ret.type, fn.key)
     end
   end
 

+ 2 - 2
examples/UI/Window_HUD/main.lua

@@ -6,8 +6,8 @@
 local shader = require 'shader'
 
 -- In order for lovr.mouse to work, and therefore for this example to work,
--- we must be using LuaJIT and we must be using GLFW (ie: we can't be on Oculus Mobile)
-if type(jit) == 'table' and lovr.headset.getDriver() ~= "vrapi" then
+-- we must be using LuaJIT and we must be using GLFW (ie: we can't be on Android)
+if type(jit) == 'table' and lovr.system.getOS() ~= "android" then
 	lovr.mouse = require 'mouse'
 end
 

+ 0 - 46
guides/Compiling.md

@@ -95,52 +95,6 @@ the command:
 $ LD_PRELOAD='/usr/$LIB/libstdc++.so.6 /usr/$LIB/libgcc_s.so.1' ~/.steam/steam/ubuntu12_32/steam-runtime/run.sh lovr
 ```
 
-WebXR
----
-
-First, [install the Emscripten SDK](https://emscripten.org/docs/getting_started/downloads.html).
-
-Unix:
-
-```
-$ mkdir build
-$ cd build
-$ emcmake cmake ..
-$ emmake make -j2
-```
-
-Windows (from a Visual Studio Command Prompt, make sure the Emscripten SDK is on PATH):
-
-```
-$ mkdir build
-$ cd build
-$ emcmake cmake -G "NMake Makefiles" ..
-$ emmake nmake
-```
-
-The above commands will output `lovr.js`, `lovr.wasm`, and `lovr.html`.  The easiest way to run LÖVR
-from here is to use `emrun`:
-
-```
-$ emrun --browser firefox lovr.html
-```
-
-To add a project, create a .zip of its contents and serve it alongside the HTML and JS files.  The
-following JS can be added to the page to download the zip file, add it to the emscripten virtual
-filesystem, and add it as a command line argument:
-
-```
-var filename = 'game.zip';
-var url = '/game.zip';
-Module.arguments.push(filename);
-Module.preRun.push(function() {
-  Module.FS_createPreloadedFile('/', filename, url, true, false);
-});
-```
-
-See `lovr.html` (or `src/resources/lovr.html`) for a full example page, including a button that
-can be used to enter/exit immersive mode.
-
 Android
 ---
 

+ 5 - 8
guides/Contributing.md

@@ -43,14 +43,11 @@ Organization
 
 An overview of the folder structure:
 
-- `deps` contains submodules for external dependencies.  Some smaller dependencies are also included
-in the `src/lib` folder.
-- `src/api` contains Lua bindings.  There's a file for each module and a file for each object.
+- `deps` contains submodules for external dependencies.
+- `etc` is a sort of "junk drawer" containing shaders, icons, scripts, etc.
+- `src/api` contains Lua bindings.  There's a file for each module and object.
 - `src/core` contains shared engine code.  It's usually lower-level and not specific to LÖVR.
 - `src/lib` contains smaller third party libraries.
-- `src/modules` has a folder for each module in the project.  It's good to keep them separated as
-  much as possible, there's inevitably some overlap.
-- `src/resources` is a sort of "junk drawer" containing helper files like shaders, icons, scripts,
-  etc. often included in builds for various platforms.
+- `src/modules` has a folder for each module.
 
-Branches other than master can be force-pushed during development to organize commit history.
+Branches other than master and dev may be force-pushed during development to keep commits clean.

+ 4 - 4
guides/FAQ.md

@@ -40,7 +40,7 @@ runtime.
 
 > Does LÖVR support AR?
 
-LÖVR does not currently support the Magic Leap or "magic window" style AR on phones.  There are some
-ways to experiment with AR on LÖVR using passthrough devices like the North Star or SteamVR's Room
-View 3D.  LÖVR's direction is guided by the community, and as more AR hardware comes out there will
-likely be future demand and development on AR support.
+LÖVR does not currently support Magic Leap, HoloLens, or "magic window" style AR on phones.  There
+are some ways to experiment with AR on LÖVR using passthrough devices like the North Star or
+SteamVR's Room View 3D.  LÖVR's direction is guided by the community, and as more AR hardware comes
+out there will likely be future demand and development on AR support.

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov