There's a bug where arguments start at 0 instead of 1 in fused mode.
In fused mode, we aren't going to consume one of the command line
arguments for the project path like we normally do, so in order to
provide that argument to the lovr project at index 1, shift them all up
by one in boot.lua. We can only do this after the filesystem module is
loaded, so it can't go in main.c with all the other arg stuff.
The zero'th argument in fused mode is now the source path, just like how
it works in non-fused mode. This means the executable path is in the
arg table twice, which is sensible since in fused mode both the
interpreter and the interpreter's source are the same file.
Notes:
- We can actually use a single Activity.java file for oculus/pico now
- We can unconditionally compile os_android.c on Android
- No need for including extra jars in build system
- Headset rendering is guaranteed synchronous now, no need to ref L
- Add an "android flavor" build setting to differentiate between oculus
and pico devices, since they both use OpenXR.
- Update the pico manifest to reflect their OpenXR sample
- Remove some OpenGL hacks that aren't necessary anymore
This adds the ability to load and animate a mesh for hand tracking on
the Oculus Quest. It is more or less identical to the current
functionality on the vrapi driver.
One key part of this change is that getPose in OpenXR will see if action
spaces are active before locating their spaces. This is due to some
behavior observed on the Oculus Quest with hand tracking where pose
actions for controllers would return invalid data with all of the
location flags erroneously set. The only way to detect and work around
this is to check the pose action state. When this happens, we fall back
to returning the pose of the wrist joint, which is where the Oculus hand
mesh wants to be drawn. In the event that both controllers and hand
tracking are active, the controller pose will be returned by getPose but
the wrist joint can still be accessed using getSkeleton.
Note that this does not yet include support for properly scaling the
hand mesh.
There are numerous opportunities for optimization here that may be
investigated in the future, though performance is well within an
acceptable range right now.
The notdef glyph will get rendered instead, which is slightly better.
Note that the default font does not have a notdef glyph (bug).
Note that notdef will be rasterized multiple times right now.
Currently there is a single allocator function used in arr_t. Its
behavior depends on the values for the pointer and size arguments:
- If pointer is NULL, it should allocate new memory.
- If pointer is non-NULL and size is positive, it should resize memory.
- If size is zero, it should free memory.
All instances of arr_t use realloc for this right now. The problem
is that realloc's behavior is undefined when the size argument is zero.
On Windows and Linux, realloc will free the pointer, but on macOS this
isn't the case. This means that arr_t leaks memory on macOS.
It's best to not rely on undefined behavior like this, so let's instead
use a helper function that behaves the way we want.
The VrApi implementation now checks that X, Y, A, B buttons exist on that
specific controller. X,Y are on left; A,B on the right controller. That
mapping covers Quest Touch and Quest 2 controllers.
Functions to calculate the angle between two vectors. Angle is always
positive. Implementations give the same result as this Lua code:
```lua
local function lua_angle(v1, v2)
return math.acos(v1:dot(v2) / (v1:length() * v2:length()))
end
```
If either vector is zero-length, the pi/2 value is returned.
These functions read an unsigned 32 bit integer from the Lua stack
and error if the value is negative or too big. Currently converting
Lua numbers to integers will silently wrap or invoke undefined behavior
when they are outside of the acceptable range.
For projects that don't want the overhead of type/bounds checks, the
supercharge build option (LOVR_UNCHECKED) can now be used to skip all
type/bounds checks.
Correcting the order of stack operations to fetch RGB components from
the table and to put in conversion the results.
Before the fix these two calls produced different results:
`lovr.math.gammaToLinear( 0.1, 0.2, 0.3 )`
`lovr.math.gammaToLinear( {0.1, 0.2, 0.3} )`
The current flag did not work because float shader flags are not
supported. It was also not very useful because it was per-shader
and did not use the alpha cutoff property of glTF materials.
Instead, let's turn the shader flag into an enable/disable boolean,
and add a scalar material property named "alphacutoff" that gets
read by the glTF importer.
When the alphaCutoff flag is enabled, the material property will be
compared against the pixel's alpha value to decide whether it should
get discarded.
- When calling lovr.graphics.stencil, the color mask is initially
disabled, and gets restored to its initial state afterwards.
- However, when it's restored, it uses lovrGraphicsSetColorMask, which
just sets shadow state that doesn't make it all the way to GL until
another draw is done.
- The consequence of this is that if you call .stencil and then don't do
a draw, any clears that happen will use the old (disabled) color mask,
preventing the color buffer from being cleared.
- The solution here is to lower the color mask change down into opengl.c
where it can directly hit OpenGL.
Vector methods are extended to receive vectors as individual numbers
for each of x,y,z,w component. The vector objects are still supported
as well.
Previously only single value scalar was supported. This change maintains
backward compatibility.
```
v = vec3():add( 1, 2, 3 ) -- both do the same
v = vec3():add( vec3(1, 2, 3) ) _/
v = vec4():mul( 2 ) -- x component is a default for y, z
v = vec4():mul( 2, 2, 2, 2 ) _/
v = vec2():lerp( 2, 2, 0.5 ) -- in lerp, dot, cross, distance
v = vec2():lerp( vec2(2, 2), 0.5 ) _/ all components are mandatory
```
- You were able to write a Blob to a ShaderBlock
- Using ShaderBlock:send(Blob, offset, size)
- It was not flexible enough and it was broken
- The data was read from `offset` bytes into the Blob.
- The data was written to the beginning of the Buffer.
- The Buffer was flushed at `offset` bytes into the Buffer.
- This commit changes the signature of the variant
- to ShaderBlock:send(Blob, srcOffset, dstOffset, size)
- and hopefully fixes the behavior.
- Also why is this entire commit description a bulleted list
If you create and destroy objects quickly (using :release), malloc
might give you the same pointer. When we look up this pointer in
the userdata cache, it'll give you an invalid Proxy/pointer, which
throws an error like "Calling 'fn' on bad self".
When collecting objects, remove them from the userdata cache.
Start is mainly used for setting up graphics-related stuff, since it
was created to perform setup after the window/graphics module is
initialized. Since the display driver is the only one doing rendering,
it makes sense to only call start on the display driver.
...also fixes a bug where start is getting called twice.
- We need some headset initialization to happen upfront
- But we still want some delayed initialization for when graphics is ready
- Go back to headset initialization happening when module is required
- Add lovr.headset.start that can be used for post-graphics init
lovrCheck is a new way of performing runtime assertions.
It's identical to lovrAssert, except it's compiled out if
LOVR_UNCHECKED is defined.
It is meant to be used for non-mission-critical validation, for
example proper usage of types passed to the Lua API. lovrAssert
should still be used to check return values from platform APIs.
- Use incoming depth settings to determine whether depth test should be
enabled or disabled (wtf)
- Always track state.depthTest, even if depth test is disabled
- Previously, animate was converting from oculus basis to lovr basis.
- Not all hand models are animated.
- Instead, apply the compensation in newModel.
- This means that both animated and non-animated models have correct orientation.
- Verified that regular getPose is returning correct rotation as well.
- Previously, animate was converting from oculus basis to lovr basis.
- Not all hand models are animated.
- Instead, apply the compensation in newModel.
- This means that both animated and non-animated models have correct orientation.
- Verified that regular getPose is returning correct rotation as well.
If a Texture is created from a handle, that means someone else created
it, so we expect them to destroy it. We were always destroying handles,
and I guess this was usually okay because glDeleteTextures is idempotent.
However, we're seeing a crash in the Oculus driver when OVR is torn
down. Presumably it is trying to access its swapchain textures after we
destroyed them. Not sure why this wasn't an observable issue before,
maybe it's a new regression. Still, it makes sense to only delete the
GL texture handle if we were the one that created it.
We don't need to check this for the renderbuffer since we always own those.