mirror of https://github.com/bjornbytes/lovr.git
Compare commits
192 Commits
c1b9c11b20
...
bdeee99953
Author | SHA1 | Date |
---|---|---|
bjorn | bdeee99953 | |
bjorn | aef71192ac | |
bjorn | f1ba4d1a1e | |
bjorn | 5df8405af3 | |
bjorn | 2952ed764d | |
bjorn | 985ba6bd13 | |
bjorn | 15649802c8 | |
Bjorn | e3b42fe24b | |
bjorn | 060e72c525 | |
bjorn | 47dec01772 | |
bjorn | 582ee1625f | |
bjorn | e36374c4cf | |
bjorn | 98601b3425 | |
bjorn | 2ac0d6946e | |
bjorn | b589cec975 | |
bjorn | 8bdab9f2d4 | |
bjorn | 5751068728 | |
bjorn | 481a9dafa2 | |
bjorn | 95cc6c2753 | |
bjorn | f35cda7db8 | |
bjorn | 907d89c913 | |
bjorn | ff0f39fc7b | |
bjorn | b809db1d83 | |
bjorn | 051266f8ea | |
bjorn | 930e713079 | |
bjorn | 4f26182595 | |
bjorn | 8cbdda00f3 | |
bjorn | 10f965d69e | |
bjorn | a7bf4ca2a4 | |
bjorn | c27694fd8e | |
bjorn | b3e9e55b8a | |
bjorn | 6f0b6391df | |
bjorn | ce58619094 | |
bjorn | 9b6f58ac1e | |
bjorn | f4d1161a3d | |
bjorn | f4d5c0d758 | |
bjorn | 38a68dc4e5 | |
bjorn | 5e521b7698 | |
bjorn | fb6b402034 | |
bjorn | e9fe088521 | |
bjorn | 01194a80c7 | |
bjorn | ffc23497a9 | |
bjorn | d756cc2b1d | |
bjorn | 77abad4e21 | |
bjorn | 40879f383a | |
bjorn | 8596bb06a0 | |
bjorn | 3dd641c02d | |
bjorn | 01a0df37cc | |
bjorn | ecbd331552 | |
bjorn | fdba60214c | |
bjorn | 243b6ae21a | |
bjorn | 1c070990de | |
bjorn | 458e7b176c | |
bjorn | cdecc1bae7 | |
bjorn | 67e228125b | |
bjorn | c37cd3852f | |
bjorn | b7e1b5111e | |
bjorn | c5d6bb6b48 | |
bjorn | 87cd13d95c | |
bjorn | 822eb94993 | |
bjorn | cfd2374449 | |
bjorn | 55f0da97ce | |
bjorn | e7d0764e49 | |
bjorn | f4553075cb | |
bjorn | fd7fe08055 | |
bjorn | 8ec7a18c28 | |
bjorn | 7373bb6b83 | |
bjorn | abd2eddf0d | |
bjorn | 70e4b9fd7b | |
bjorn | 8fc5d4fd24 | |
bjorn | ef8d1abf87 | |
bjorn | cc4567652e | |
bjorn | d50f661ce6 | |
bjorn | 26d17fc402 | |
Bjorn | 27c59de5dc | |
Ilya | 994f623c5d | |
bjorn | 9c2c4f6906 | |
bjorn | 2b218d09d0 | |
bjorn | 66f6ee9bb9 | |
bjorn | 38f05b9f01 | |
Josip Miskovic | a84385a030 | |
bjorn | c17abe4f24 | |
bjorn | 053893f3f6 | |
bjorn | b09d612e6b | |
bjorn | 561b20699a | |
bjorn | aff97b7a30 | |
bjorn | 1f6904c04b | |
Josip Miskovic | 8c3c0f8136 | |
bjorn | 1e02de6cda | |
bjorn | 24c13e88d3 | |
bjorn | 5611a6130b | |
bjorn | 35228f1838 | |
Josip Miskovic | 0e9171e2dd | |
bjorn | ae1edd95e7 | |
bjorn | d097d9819d | |
bjorn | 2d7b636a90 | |
bjorn | 0d8d6f579b | |
bjorn | aa79822edb | |
bjorn | 1cda2d59a7 | |
bjorn | f93fb0c0c7 | |
bjorn | 4719dbdd10 | |
bjorn | 9068c8daee | |
bjorn | f9cfc4e76e | |
bjorn | dc643ad166 | |
Bjorn | 600a8c372e | |
Josip Miskovic | 8a5b88e851 | |
Bjorn | b3b523cdbf | |
Ilya | 4139f0f180 | |
bjorn | 1ec0a41bb8 | |
bjorn | c3d81debe8 | |
bjorn | 80b596daf6 | |
bjorn | 79e28eb7e3 | |
Bjorn | fd331090c9 | |
Ilya | f77a8f6cb2 | |
Bjorn | 6c7ca1e275 | |
bjorn | 224b6a495d | |
bjorn | 901dd268f2 | |
bjorn | f6af859984 | |
bjorn | b32ac1c5a5 | |
bjorn | 1701409763 | |
bjorn | a4c1d9fce6 | |
bjorn | d017ca0fac | |
bjorn | 35b5693a19 | |
bjorn | e8dc1484d3 | |
bjorn | 98e2e94ea8 | |
bjorn | 4a175c4cf8 | |
bjorn | 6347114030 | |
Bjorn | 73eae189ae | |
bjorn | 792fd75204 | |
bjorn | ec380e0cfd | |
bjorn | fa8ea6732b | |
bjorn | 466a052ded | |
bjorn | 2fe5ba8f3b | |
bjorn | ae19b7aad3 | |
bjorn | 652a074677 | |
bjorn | bd83ad6eb4 | |
bjorn | 48e484ed8a | |
Bjorn | f3cae5f80e | |
Bjorn | bad3d8b78a | |
Bjorn | f1158b2159 | |
bjorn | 114109ab54 | |
bjorn | b65fa0d1f6 | |
bjorn | b63ec6e137 | |
bjorn | 6a669bd967 | |
bjorn | ada33c6620 | |
bjorn | cbc9312716 | |
bjorn | 728b166d69 | |
bjorn | 64e253a8ef | |
bjorn | 81ef58d032 | |
bjorn | 875a7f8237 | |
bjorn | 8b78a4d3b5 | |
bjorn | d4e2736e0b | |
bjorn | 45eba2fe85 | |
bjorn | 93348499e9 | |
bjorn | 035d359133 | |
bjorn | f7c1d4cccb | |
bjorn | eecd201f57 | |
bjorn | c6f010a572 | |
Bjorn | 10b0c81209 | |
Josip Miskovic | 37fdb39e73 | |
bjorn | 555d97afbe | |
Bjorn | f2bcfee8be | |
bjorn | 0bf09ca108 | |
Bjorn | 2770ab270a | |
Josip Miskovic | 7229a93f11 | |
Josip Miskovic | 47c9b20542 | |
Josip Miskovic | 0b8546fd62 | |
Josip Miskovic | 431062c345 | |
bjorn | 41deb706ce | |
bjorn | 7b39a30600 | |
bjorn | 78586c3770 | |
bjorn | da5a6cec10 | |
bjorn | bf97a55fcb | |
bjorn | df3544e5f3 | |
Bjorn | d23164235b | |
bjorn | 215e042e05 | |
Josip Miskovic | 1ad8f23fb8 | |
bjorn | 06bfbbaa6b | |
bjorn | 5bd48f16f5 | |
bjorn | 287769f1f2 | |
bjorn | 6516cca39d | |
bjorn | 3712bc3fba | |
bjorn | 35f97f08f3 | |
bjorn | 2b351fa145 | |
bjorn | 1ede3ef012 | |
bjorn | dacc17e1b7 | |
bjorn | f8158744f9 | |
Bjorn | 30cb0c19a0 | |
xiejiangzhi | 45a6333afb | |
bjorn | a90c4092f8 | |
bjorn | 40d85c6a16 | |
bjorn | 5434dd6add |
|
@ -107,7 +107,7 @@ jobs:
|
|||
steps:
|
||||
- name: Install Wulkan
|
||||
env:
|
||||
VKV: 1.3.231.1
|
||||
VKV: 1.3.275.0
|
||||
run: |
|
||||
curl -sOL https://sdk.lunarg.com/sdk/download/$VKV/mac/vulkansdk-macos-$VKV.dmg?Human=true
|
||||
hdiutil attach vulkansdk-macos-$VKV.dmg
|
||||
|
@ -125,11 +125,11 @@ jobs:
|
|||
run: cmake --build build
|
||||
- name: Package
|
||||
run: >
|
||||
cp $VULKAN_SDK/lib/libvulkan.1.3.231.dylib build/lovr.app/Contents/MacOS/libvulkan.1.dylib &&
|
||||
cp $VULKAN_SDK/../MoltenVK/dylib/macOS/libMoltenVK.dylib build/lovr.app/Contents/MacOS &&
|
||||
cp $VULKAN_SDK/lib/libvulkan.1.3.275.dylib build/lovr.app/Contents/MacOS/libvulkan.1.dylib &&
|
||||
cp $VULKAN_SDK/lib/libMoltenVK.dylib build/lovr.app/Contents/MacOS &&
|
||||
mkdir -p build/lovr.app/Contents/Resources/vulkan/icd.d &&
|
||||
cp $VULKAN_SDK/../MoltenVK/dylib/macOS/MoltenVK_icd.json build/lovr.app/Contents/Resources/vulkan/icd.d &&
|
||||
sed -i '' 's|./libMoltenVK.dylib|../../../MacOS/libMoltenVK.dylib|' build/lovr.app/Contents/Resources/vulkan/icd.d/MoltenVK_icd.json &&
|
||||
cp $VULKAN_SDK/share/vulkan/icd.d/MoltenVK_icd.json build/lovr.app/Contents/Resources/vulkan/icd.d &&
|
||||
sed -i '' 's|../../../lib/libMoltenVK.dylib|../../../MacOS/libMoltenVK.dylib|' build/lovr.app/Contents/Resources/vulkan/icd.d/MoltenVK_icd.json &&
|
||||
ditto -c -k --keepParent build/lovr.app lovr.zip
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v3
|
||||
|
|
|
@ -31,3 +31,9 @@
|
|||
[submodule "plugins/lovr-http"]
|
||||
path = plugins/lovr-http
|
||||
url = https://github.com/bjornbytes/lovr-http
|
||||
[submodule "deps/jolt-physics-sharp"]
|
||||
path = deps/jolt-physics-sharp
|
||||
url = https://github.com/amerkoleci/JoltPhysicsSharp
|
||||
[submodule "deps/tracy"]
|
||||
path = deps/tracy
|
||||
url = https://github.com/wolfpld/tracy
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,4 +1,4 @@
|
|||
cmake_minimum_required(VERSION 3.3.0)
|
||||
cmake_minimum_required(VERSION 3.5.0)
|
||||
cmake_policy(SET CMP0063 NEW)
|
||||
cmake_policy(SET CMP0079 NEW)
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "11.0" CACHE STRING "Minimum macOS deployment version")
|
||||
|
@ -29,7 +29,9 @@ option(LOVR_USE_WEBXR "Enable the WebXR backend for the headset module" OFF)
|
|||
option(LOVR_USE_SIMULATOR "Enable the keyboard/mouse backend for the headset module" ON)
|
||||
option(LOVR_USE_STEAM_AUDIO "Enable the Steam Audio spatializer (be sure to also set LOVR_STEAM_AUDIO_PATH)" OFF)
|
||||
option(LOVR_USE_OCULUS_AUDIO "Enable the Oculus Audio spatializer (be sure to also set LOVR_OCULUS_AUDIO_PATH)" OFF)
|
||||
|
||||
option(LOVR_SANITIZE "Enable Address Sanitizer" OFF)
|
||||
option(LOVR_PROFILE "Enable Tracy integration" OFF)
|
||||
|
||||
option(LOVR_SYSTEM_GLFW "Use the system-provided glfw" OFF)
|
||||
option(LOVR_SYSTEM_LUA "Use the system-provided Lua" OFF)
|
||||
|
@ -41,6 +43,9 @@ option(LOVR_BUILD_SHARED "Build a shared library (takes precedence over LOVR_BUI
|
|||
option(LOVR_BUILD_BUNDLE "On macOS, build a .app bundle instead of a raw program" OFF)
|
||||
option(LOVR_BUILD_WITH_SYMBOLS "Build with C function symbols exposed" OFF)
|
||||
|
||||
set(LOVR_PHYSICS_LIBRARY "ODE" CACHE STRING "Physics library to use")
|
||||
set_property(CACHE LOVR_PHYSICS_LIBRARY PROPERTY STRINGS ODE JOLT)
|
||||
|
||||
# Setup
|
||||
if(EMSCRIPTEN)
|
||||
string(CONCAT EMSCRIPTEN_LINKER_FLAGS
|
||||
|
@ -158,27 +163,34 @@ endif()
|
|||
|
||||
# ODE
|
||||
if(LOVR_ENABLE_PHYSICS)
|
||||
if(LOVR_SYSTEM_ODE)
|
||||
pkg_search_module(ODE REQUIRED ode)
|
||||
pkg_search_module(CCD REQUIRED ccd)
|
||||
include_directories(${ODE_INCLUDE_DIRS} ${CCD_INCLUDE_DIRS})
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lstdc++")
|
||||
set(LOVR_ODE ode ccd)
|
||||
else()
|
||||
if(EMSCRIPTEN)
|
||||
set(ODE_BUILD_SHARED OFF CACHE BOOL "")
|
||||
if(LOVR_PHYSICS_LIBRARY STREQUAL "ODE")
|
||||
if(LOVR_SYSTEM_ODE)
|
||||
pkg_search_module(ODE REQUIRED ode)
|
||||
pkg_search_module(CCD REQUIRED ccd)
|
||||
include_directories(${ODE_INCLUDE_DIRS} ${CCD_INCLUDE_DIRS})
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lstdc++")
|
||||
set(LOVR_PHYSICS_LIB ode ccd)
|
||||
else()
|
||||
set(ODE_BUILD_SHARED ON CACHE BOOL "")
|
||||
if(EMSCRIPTEN)
|
||||
set(ODE_BUILD_SHARED OFF CACHE BOOL "")
|
||||
else()
|
||||
set(ODE_BUILD_SHARED ON CACHE BOOL "")
|
||||
endif()
|
||||
add_subdirectory(deps/ode ode)
|
||||
if(MSVC)
|
||||
set_target_properties(ode PROPERTIES COMPILE_FLAGS "/wd4244 /wd4267")
|
||||
target_compile_definitions(ode PRIVATE _CRT_SECURE_NO_WARNINGS)
|
||||
else()
|
||||
set_target_properties(ode PROPERTIES COMPILE_FLAGS "-Wno-unused-volatile-lvalue -Wno-array-bounds -Wno-undefined-var-template")
|
||||
endif()
|
||||
include_directories(deps/ode/include "${CMAKE_CURRENT_BINARY_DIR}/ode/include")
|
||||
set(LOVR_PHYSICS_LIB ode)
|
||||
endif()
|
||||
add_subdirectory(deps/ode ode)
|
||||
if(MSVC)
|
||||
set_target_properties(ode PROPERTIES COMPILE_FLAGS "/wd4244 /wd4267")
|
||||
target_compile_definitions(ode PRIVATE _CRT_SECURE_NO_WARNINGS)
|
||||
else()
|
||||
set_target_properties(ode PROPERTIES COMPILE_FLAGS "-Wno-unused-volatile-lvalue -Wno-array-bounds -Wno-undefined-var-template")
|
||||
endif()
|
||||
include_directories(deps/ode/include "${CMAKE_CURRENT_BINARY_DIR}/ode/include")
|
||||
set(LOVR_ODE ode)
|
||||
elseif(LOVR_PHYSICS_LIBRARY STREQUAL "JOLT")
|
||||
set(DEBUG_RENDERER_IN_DEBUG_AND_RELEASE OFF CACHE BOOL "")
|
||||
set(PROFILER_IN_DEBUG_AND_RELEASE OFF CACHE BOOL "")
|
||||
add_subdirectory(deps/jolt-physics-sharp jolt)
|
||||
set(LOVR_PHYSICS_LIB joltc)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
@ -212,6 +224,7 @@ if(LOVR_ENABLE_HEADSET AND LOVR_USE_OPENXR)
|
|||
set(LOVR_OPENXR ${OPENXR_LIBRARIES})
|
||||
else()
|
||||
set(DYNAMIC_LOADER ON CACHE BOOL "")
|
||||
set(BUILD_WITH_WAYLAND_HEADERS OFF CACHE BOOL "")
|
||||
include_directories(deps/openxr/include)
|
||||
add_subdirectory(deps/openxr openxr)
|
||||
set(LOVR_OPENXR openxr_loader)
|
||||
|
@ -336,7 +349,7 @@ target_link_libraries(lovr
|
|||
${LOVR_GLFW}
|
||||
${LOVR_LUA}
|
||||
${LOVR_MSDF}
|
||||
${LOVR_ODE}
|
||||
${LOVR_PHYSICS_LIB}
|
||||
${LOVR_GLSLANG}
|
||||
${LOVR_OPENXR}
|
||||
${LOVR_OCULUS_AUDIO}
|
||||
|
@ -350,6 +363,17 @@ if(LOVR_SANITIZE)
|
|||
target_link_options(lovr PRIVATE ${LOVR_SANITIZE_FLAGS})
|
||||
endif()
|
||||
|
||||
if(LOVR_PROFILE)
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
message(FATAL_ERROR "You probably want to build in release mode when Tracy is enabled")
|
||||
endif()
|
||||
option(TRACY_ENABLE "" ON)
|
||||
add_subdirectory(deps/tracy)
|
||||
target_compile_definitions(lovr PRIVATE LOVR_PROFILE)
|
||||
target_link_libraries(lovr Tracy::TracyClient)
|
||||
target_include_directories(lovr PRIVATE deps/tracy/public/tracy)
|
||||
endif()
|
||||
|
||||
if(LOVR_ENABLE_AUDIO OR LOVR_ENABLE_DATA)
|
||||
target_sources(lovr PRIVATE
|
||||
src/lib/miniaudio/miniaudio.c
|
||||
|
@ -478,6 +502,7 @@ if(LOVR_ENABLE_GRAPHICS)
|
|||
COMMAND
|
||||
${GLSLANG_VALIDATOR}
|
||||
--quiet
|
||||
$<$<CONFIG:Debug>:-gVS>
|
||||
--target-env vulkan1.1
|
||||
--vn lovr_shader_${shader}_${ARGV0}
|
||||
-o ${shader_file}.h
|
||||
|
@ -532,13 +557,17 @@ endif()
|
|||
|
||||
if(LOVR_ENABLE_PHYSICS)
|
||||
target_sources(lovr PRIVATE
|
||||
src/modules/physics/physics.c
|
||||
src/api/l_physics.c
|
||||
src/api/l_physics_collider.c
|
||||
src/api/l_physics_joints.c
|
||||
src/api/l_physics_shapes.c
|
||||
src/api/l_physics_world.c
|
||||
)
|
||||
if(LOVR_PHYSICS_LIBRARY STREQUAL "ODE")
|
||||
target_sources(lovr PRIVATE src/modules/physics/physics_ode.c)
|
||||
elseif(LOVR_PHYSICS_LIBRARY STREQUAL "JOLT")
|
||||
target_sources(lovr PRIVATE src/modules/physics/physics_jolt.c)
|
||||
endif()
|
||||
else()
|
||||
target_compile_definitions(lovr PRIVATE LOVR_DISABLE_PHYSICS)
|
||||
endif()
|
||||
|
@ -558,6 +587,7 @@ endif()
|
|||
|
||||
if(LOVR_ENABLE_THREAD)
|
||||
target_sources(lovr PRIVATE
|
||||
src/core/job.c
|
||||
src/modules/thread/thread.c
|
||||
src/api/l_thread.c
|
||||
src/api/l_thread_channel.c
|
||||
|
@ -638,7 +668,7 @@ if(NOT ANDROID)
|
|||
add_custom_command(TARGET lovr POST_BUILD
|
||||
DEPENDS "etc/nogame"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/etc/nogame"
|
||||
COMMAND ${CMAKE_COMMAND} -E tar c "${CMAKE_CURRENT_BINARY_DIR}/nogame.zip" --format=zip arg.lua conf.lua main.lua
|
||||
COMMAND ${CMAKE_COMMAND} -E tar c "${CMAKE_CURRENT_BINARY_DIR}/nogame.zip" --format=zip .
|
||||
COMMAND ${CMAKE_COMMAND} -E cat "${CMAKE_CURRENT_BINARY_DIR}/nogame.zip" >> ${NOGAME_BUNDLE}
|
||||
)
|
||||
endif()
|
||||
|
@ -692,7 +722,7 @@ if(WIN32)
|
|||
|
||||
move_dll(${LOVR_GLFW})
|
||||
move_dll(${LOVR_LUA})
|
||||
move_dll(${LOVR_ODE})
|
||||
move_dll(${LOVR_PHYSICS_LIB})
|
||||
move_dll(${LOVR_MSDF})
|
||||
move_dll(${LOVR_OCULUS_AUDIO})
|
||||
move_dll(${LOVR_PHONON})
|
||||
|
@ -743,7 +773,7 @@ elseif(APPLE)
|
|||
endfunction()
|
||||
move_lib(${LOVR_GLFW})
|
||||
move_lib(${LOVR_LUA})
|
||||
move_lib(${LOVR_ODE})
|
||||
move_lib(${LOVR_PHYSICS_LIB})
|
||||
move_lib(${LOVR_MSDF})
|
||||
move_lib(${LOVR_OCULUS_AUDIO})
|
||||
move_lib(${LOVR_PHONON})
|
||||
|
@ -771,7 +801,7 @@ elseif(ANDROID)
|
|||
# Dynamically linked targets output libraries in raw/lib/<ABI> for easy including in apk with aapt
|
||||
set_target_properties(
|
||||
lovr
|
||||
${LOVR_ODE}
|
||||
${LOVR_PHYSICS_LIB}
|
||||
${LOVR_MSDF}
|
||||
PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/raw/lib/${ANDROID_ABI}"
|
||||
)
|
||||
|
@ -894,7 +924,7 @@ elseif(UNIX)
|
|||
endfunction()
|
||||
move_lib(${LOVR_GLFW})
|
||||
move_lib(${LOVR_LUA})
|
||||
move_lib(${LOVR_ODE})
|
||||
move_lib(${LOVR_PHYSICS_LIB})
|
||||
move_lib(${LOVR_MSDF})
|
||||
move_lib(${LOVR_OPENXR})
|
||||
move_lib(${LOVR_OCULUS_AUDIO})
|
||||
|
|
19
Tupfile.lua
19
Tupfile.lua
|
@ -8,6 +8,7 @@ config = {
|
|||
glfw = true,
|
||||
luajit = false,
|
||||
glslang = true,
|
||||
physics = 'ode',
|
||||
utf8 = true,
|
||||
modules = {
|
||||
audio = true,
|
||||
|
@ -96,7 +97,7 @@ flags = {
|
|||
|
||||
cflags = {
|
||||
'-std=c11 -pedantic',
|
||||
'-Wall -Wextra -Wno-unused-parameter',
|
||||
'-Wall -Wextra -Wno-unused-parameter -Wno-strict-prototypes',
|
||||
config.strict and '-Werror' or '',
|
||||
config.optimize and '-fdata-sections -ffunction-sections' or '',
|
||||
'-fdiagnostics-color=always',
|
||||
|
@ -207,7 +208,7 @@ if config.luajit then
|
|||
end
|
||||
cflags += '-Ideps/luajit/src'
|
||||
lflags += '-L' .. config.luajit
|
||||
lflags += '-lluajit'
|
||||
lflags += '-lluajit-5.1'
|
||||
else
|
||||
cflags += '-Ideps/lua'
|
||||
lflags += '-llua'
|
||||
|
@ -260,7 +261,6 @@ if config.modules.graphics and config.glslang then
|
|||
glslang_cflags += '-fno-rtti'
|
||||
glslang_cflags += '-Ideps/glslang'
|
||||
glslang_lflags += '-shared'
|
||||
glslang_src += 'deps/glslang/OGLCompilersDLL/*.cpp'
|
||||
glslang_src += 'deps/glslang/glslang/CInterface/*.cpp'
|
||||
glslang_src += 'deps/glslang/glslang/MachineIndependent/*.cpp'
|
||||
glslang_src += 'deps/glslang/glslang/MachineIndependent/preprocessor/*.cpp'
|
||||
|
@ -406,7 +406,11 @@ src = {
|
|||
|
||||
for module, enabled in pairs(config.modules) do
|
||||
if enabled then
|
||||
override = { audio = 'src/modules/audio/audio.c', headset = 'src/modules/headset/headset.c' } -- TODO
|
||||
override = {
|
||||
audio = 'src/modules/audio/audio.c',
|
||||
headset = 'src/modules/headset/headset.c',
|
||||
physics = ('src/modules/physics/physics_%s.c'):format(config.physics)
|
||||
}
|
||||
src += override[module] or ('src/modules/%s/*.c'):format(module)
|
||||
src += ('src/api/l_%s*.c'):format(module)
|
||||
else
|
||||
|
@ -447,6 +451,7 @@ src += (config.modules.audio or config.modules.data) and 'src/lib/miniaudio/*.c'
|
|||
src += config.modules.data and 'src/lib/jsmn/*.c' or nil
|
||||
src += config.modules.data and 'src/lib/minimp3/*.c' or nil
|
||||
src += config.modules.math and 'src/lib/noise/*.c' or nil
|
||||
src += config.modules.thread and 'src/core/job.c' or nil
|
||||
|
||||
-- embed resource files with xxd
|
||||
|
||||
|
@ -463,9 +468,13 @@ vert = 'etc/shaders/*.vert'
|
|||
frag = 'etc/shaders/*.frag'
|
||||
comp = 'etc/shaders/*.comp'
|
||||
|
||||
glslang_flags += '--quiet'
|
||||
glslang_flags += config.debug and '-gVS' or ''
|
||||
glslang_flags += '--target-env vulkan1.1'
|
||||
|
||||
function compileShaders(stage)
|
||||
pattern = 'etc/shaders/*.' .. stage
|
||||
tup.foreach_rule(pattern, 'glslangValidator --quiet --target-env vulkan1.1 --vn lovr_shader_%B_' .. stage .. ' -o %o %f', '%f.h')
|
||||
tup.foreach_rule(pattern, 'glslangValidator $(glslang_flags) --vn lovr_shader_%B_' .. stage .. ' -o %o %f', '%f.h')
|
||||
end
|
||||
|
||||
compileShaders('vert')
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit e7d1279bc02891585c96479987c0f3a11cc042b9
|
||||
Subproject commit 5edafd3006723e9b4680d1cc03920a535460fed5
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 2cda386d71174bec355888539679f7a4f7be1c2a
|
|
@ -1 +1 @@
|
|||
Subproject commit 55224479ab13db8ebc8ab1e3d49197bce6201b0b
|
||||
Subproject commit 288d3a7ebc1ad959f62d51da75baa3d27438c499
|
|
@ -0,0 +1 @@
|
|||
Subproject commit a9288cd7594caced17899dda208b0d376b20d892
|
|
@ -13,7 +13,7 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>v0.17.0</string>
|
||||
<string>v0.17.1</string>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<true/>
|
||||
</dict>
|
||||
|
|
11
etc/boot.lua
11
etc/boot.lua
|
@ -3,7 +3,7 @@ lovr = require 'lovr'
|
|||
local lovr = lovr
|
||||
|
||||
local conf = {
|
||||
version = '0.17.0',
|
||||
version = '0.17.1',
|
||||
identity = 'default',
|
||||
saveprecedence = true,
|
||||
modules = {
|
||||
|
@ -41,6 +41,9 @@ local conf = {
|
|||
math = {
|
||||
globals = true
|
||||
},
|
||||
thread = {
|
||||
workers = -1
|
||||
},
|
||||
window = {
|
||||
width = 720,
|
||||
height = 800,
|
||||
|
@ -73,7 +76,7 @@ function lovr.boot()
|
|||
'usage: lovr <source>',
|
||||
'<source> can be a Lua file, a folder with a main.lua file, or a zip archive'
|
||||
}, '\n'))
|
||||
return 1
|
||||
return 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -194,7 +197,7 @@ local function formatTraceback(s)
|
|||
end
|
||||
|
||||
function lovr.errhand(message)
|
||||
message = 'Error:\n\n' .. tostring(message) .. formatTraceback(debug.traceback('', 4))
|
||||
message = 'Error:\n\n' .. tostring(message) .. formatTraceback(debug and debug.traceback('', 4) or '')
|
||||
|
||||
print(message)
|
||||
|
||||
|
@ -289,7 +292,7 @@ lovr.handlers = setmetatable({}, { __index = lovr })
|
|||
return coroutine.create(function()
|
||||
local function onerror(...)
|
||||
onerror = function(...)
|
||||
print('Error:\n\n' .. tostring(...) .. formatTraceback(debug.traceback('', 1)))
|
||||
print('Error:\n\n' .. tostring(...) .. formatTraceback(debug and debug.traceback('', 1) or ''))
|
||||
return function() return 1 end
|
||||
end
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#extension GL_EXT_multiview : require
|
||||
#extension GL_GOOGLE_include_directive : require
|
||||
|
||||
#include "lovr.glsl"
|
||||
#include "shaders/lovr.glsl"
|
||||
|
||||
vec4 lovrmain() {
|
||||
float y = UV.y;
|
|
@ -6,5 +6,4 @@ function lovr.conf(t)
|
|||
t.headset.supersample = true
|
||||
t.modules.audio = false
|
||||
t.modules.physics = false
|
||||
t.modules.thread = false
|
||||
end
|
||||
|
|
Binary file not shown.
|
@ -9,7 +9,7 @@ function lovr.load()
|
|||
lovr.graphics.setBackgroundColor(0x20232c)
|
||||
end
|
||||
|
||||
logo = lovr.graphics.newShader('unlit', 'logo')
|
||||
logo = lovr.graphics.newShader('unlit', 'logo.spv')
|
||||
end
|
||||
|
||||
function lovr.draw(pass)
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include "shaders/animator.comp.h"
|
||||
#include "shaders/blender.comp.h"
|
||||
#include "shaders/tallymerge.comp.h"
|
||||
#include "shaders/logo.frag.h"
|
||||
|
||||
#include "shaders/lovr.glsl.h"
|
||||
|
||||
|
@ -19,3 +18,5 @@
|
|||
#define LOCATION_UV 12
|
||||
#define LOCATION_COLOR 13
|
||||
#define LOCATION_TANGENT 14
|
||||
|
||||
#define LAST_BUILTIN_BINDING 3
|
||||
|
|
|
@ -12,10 +12,10 @@ layout(push_constant) uniform PushConstants {
|
|||
|
||||
struct ModelVertex {
|
||||
float x, y, z;
|
||||
float nx, ny, nz;
|
||||
uint normal;
|
||||
float u, v;
|
||||
uint color;
|
||||
float tx, ty, tz, tw;
|
||||
uint tangent;
|
||||
};
|
||||
|
||||
struct SkinVertex {
|
||||
|
@ -54,9 +54,6 @@ void lovrmain() {
|
|||
vertexOut[vertexIndex].y = skinned.y;
|
||||
vertexOut[vertexIndex].z = skinned.z;
|
||||
|
||||
vec3 normal = vec3(vertexIn[vertexIndex].nx, vertexIn[vertexIndex].ny, vertexIn[vertexIndex].nz);
|
||||
vec3 skinnedNormal = mat3(matrix) * normal;
|
||||
vertexOut[vertexIndex].nx = skinnedNormal.x;
|
||||
vertexOut[vertexIndex].ny = skinnedNormal.y;
|
||||
vertexOut[vertexIndex].nz = skinnedNormal.z;
|
||||
vec3 normal = mat3(matrix) * normalize(unpackSnorm10x3(vertexIn[vertexIndex].normal).xyz);
|
||||
vertexOut[vertexIndex].normal = packSnorm10x3(vec4(normal, 0.));
|
||||
}
|
||||
|
|
|
@ -15,10 +15,10 @@ layout(push_constant) uniform PushConstants {
|
|||
|
||||
struct ModelVertex {
|
||||
float px, py, pz;
|
||||
float nx, ny, nz;
|
||||
uint normal;
|
||||
float u, v;
|
||||
uint color;
|
||||
float tx, ty, tz, tw;
|
||||
uint tangent;
|
||||
};
|
||||
|
||||
struct BlendVertex {
|
||||
|
@ -39,6 +39,9 @@ void lovrmain() {
|
|||
|
||||
ModelVertex vertex = first ? rawVertices[vertexIndex] : vertices[vertexIndex];
|
||||
|
||||
vec4 normal = unpackSnorm10x3(vertex.normal);
|
||||
vec4 tangent = unpackSnorm10x3(vertex.tangent);
|
||||
|
||||
for (uint i = 0; i < blendShapeCount; i++, blendVertexIndex += vertexCount) {
|
||||
float weight = weights[i / 4][i % 4];
|
||||
|
||||
|
@ -52,14 +55,17 @@ void lovrmain() {
|
|||
vertex.py += blendShape.py * weight;
|
||||
vertex.pz += blendShape.pz * weight;
|
||||
|
||||
vertex.nx += blendShape.nx * weight;
|
||||
vertex.ny += blendShape.ny * weight;
|
||||
vertex.nz += blendShape.nz * weight;
|
||||
normal.x += blendShape.nx * weight;
|
||||
normal.y += blendShape.ny * weight;
|
||||
normal.z += blendShape.nz * weight;
|
||||
|
||||
vertex.tx += blendShape.tx * weight;
|
||||
vertex.ty += blendShape.ty * weight;
|
||||
vertex.tz += blendShape.tz * weight;
|
||||
tangent.x += blendShape.tx * weight;
|
||||
tangent.y += blendShape.ty * weight;
|
||||
tangent.z += blendShape.tz * weight;
|
||||
}
|
||||
|
||||
vertex.normal = packSnorm10x3(normal);
|
||||
vertex.tangent = packSnorm10x3(tangent);
|
||||
|
||||
vertices[vertexIndex] = vertex;
|
||||
}
|
||||
|
|
|
@ -63,6 +63,10 @@ layout(set = 1, binding = 4) uniform texture2D RoughnessTexture;
|
|||
layout(set = 1, binding = 5) uniform texture2D ClearcoatTexture;
|
||||
layout(set = 1, binding = 6) uniform texture2D OcclusionTexture;
|
||||
layout(set = 1, binding = 7) uniform texture2D NormalTexture;
|
||||
|
||||
layout(push_constant) uniform PushConstants {
|
||||
uint DrawID;
|
||||
};
|
||||
#endif
|
||||
|
||||
// Attributes
|
||||
|
@ -116,7 +120,7 @@ layout(location = 14) in vec4 Tangent;
|
|||
#define BaseInstance gl_BaseInstance
|
||||
#define BaseVertex gl_BaseVertex
|
||||
#define DrawIndex gl_DrawIndex
|
||||
#define InstanceIndex (gl_InstanceIndex - gl_BaseInstance)
|
||||
#define InstanceIndex gl_InstanceIndex
|
||||
#define PointSize gl_PointSize
|
||||
#define Position gl_Position
|
||||
#define VertexIndex gl_VertexIndex
|
||||
|
@ -140,12 +144,7 @@ layout(location = 14) in vec4 Tangent;
|
|||
|
||||
// Helpers
|
||||
|
||||
#define Constants layout(push_constant) uniform PushConstants
|
||||
#ifdef GL_COMPUTE_SHADER
|
||||
#define var(x) layout(set = 0, binding = x)
|
||||
#else
|
||||
#define var(x) layout(set = 2, binding = x)
|
||||
#endif
|
||||
#define Constants uniform DefaultUniformBlock
|
||||
|
||||
#ifndef GL_COMPUTE_SHADER
|
||||
#define Projection Cameras[ViewIndex].projection
|
||||
|
@ -156,7 +155,6 @@ layout(location = 14) in vec4 Tangent;
|
|||
#endif
|
||||
|
||||
#ifdef GL_VERTEX_SHADER
|
||||
#define DrawID gl_BaseInstance
|
||||
#define Transform mat4(Draws[DrawID].transform)
|
||||
#define NormalMatrix (cofactor3(Draws[DrawID].transform))
|
||||
#define PassColor Draws[DrawID].color
|
||||
|
@ -444,6 +442,24 @@ vec3 linearToGamma(vec3 color) {
|
|||
return mix(1.055 * pow(color, vec3(1. / 2.4)) - .055, color * 12.92, lessThanEqual(color, vec3(.0031308)));
|
||||
}
|
||||
|
||||
uint packSnorm10x3(vec4 v) {
|
||||
return
|
||||
((int(v.x * 511.) & 0x3ff) << 0) |
|
||||
((int(v.y * 511.) & 0x3ff) << 10) |
|
||||
((int(v.z * 511.) & 0x3ff) << 20) |
|
||||
((int(v.w * 2.) & 0x3) << 30);
|
||||
}
|
||||
|
||||
// The weird 22 bit shift basically does sign-extension of a 10-bit value stored in a 32-bit int
|
||||
vec4 unpackSnorm10x3(uint n) {
|
||||
return vec4(
|
||||
max((int((n >> 0) & 0x3ff) << 22 >> 22) / 511., -1.),
|
||||
max((int((n >> 10) & 0x3ff) << 22 >> 22) / 511., -1.),
|
||||
max((int((n >> 20) & 0x3ff) << 22 >> 22) / 511., -1.),
|
||||
max(float((n >> 30) & 0x3), -1.)
|
||||
);
|
||||
}
|
||||
|
||||
// Entrypoints
|
||||
#ifndef NO_DEFAULT_MAIN
|
||||
#ifdef GL_VERTEX_SHADER
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 69906e40f571bcbdda00fe2e6f504c3487f93d56
|
||||
Subproject commit c18a947289a8df0903d52786e6a535d3dad85d65
|
|
@ -1 +1 @@
|
|||
Subproject commit daaee4ef0056958c33b204a83a97c770ff0a2cbc
|
||||
Subproject commit 2be3778e3f2447df079212f69d56a49cd9185f3d
|
|
@ -152,6 +152,10 @@ void _luax_registertype(lua_State* L, const char* name, const luaL_Reg* function
|
|||
lua_pushcfunction(L, luax_meta__gc);
|
||||
lua_setfield(L, -2, "__gc");
|
||||
|
||||
// m.__close = gc
|
||||
lua_pushcfunction(L, luax_meta__gc);
|
||||
lua_setfield(L, -2, "__close");
|
||||
|
||||
// m.__tostring
|
||||
lua_pushcfunction(L, luax_meta__tostring);
|
||||
lua_setfield(L, -2, "__tostring");
|
||||
|
@ -382,7 +386,7 @@ void luax_pushconf(lua_State* L) {
|
|||
|
||||
int luax_setconf(lua_State* L) {
|
||||
luax_pushconf(L);
|
||||
lovrAssert(lua_isnil(L, -1), "Unable to set lovr.conf multiple times");
|
||||
lovrCheck(lua_isnil(L, -1), "Unable to set lovr.conf multiple times");
|
||||
lua_pop(L, 1);
|
||||
lua_setfield(L, LUA_REGISTRYINDEX, "_lovrconf");
|
||||
return 0;
|
||||
|
@ -511,19 +515,13 @@ void luax_optcolor(lua_State* L, int index, float color[4]) {
|
|||
|
||||
int luax_readmesh(lua_State* L, int index, float** vertices, uint32_t* vertexCount, uint32_t** indices, uint32_t* indexCount, bool* shouldFree) {
|
||||
if (lua_istable(L, index)) {
|
||||
luaL_checktype(L, index + 1, LUA_TTABLE);
|
||||
lua_rawgeti(L, index, 1);
|
||||
bool nested = lua_type(L, -1) == LUA_TTABLE;
|
||||
lua_pop(L, 1);
|
||||
|
||||
*vertexCount = luax_len(L, index) / (nested ? 1 : 3);
|
||||
*indexCount = luax_len(L, index + 1);
|
||||
lovrAssert(*vertexCount > 0, "Invalid mesh data: vertex count is zero");
|
||||
lovrAssert(*indexCount > 0, "Invalid mesh data: index count is zero");
|
||||
lovrAssert(*indexCount % 3 == 0, "Index count must be a multiple of 3");
|
||||
*vertices = malloc(sizeof(float) * *vertexCount * 3);
|
||||
*indices = malloc(sizeof(uint32_t) * *indexCount);
|
||||
lovrAssert(vertices && indices, "Out of memory");
|
||||
lovrCheck(*vertexCount > 0, "Invalid mesh data: vertex count is zero");
|
||||
*vertices = lovrMalloc(sizeof(float) * *vertexCount * 3);
|
||||
*shouldFree = true;
|
||||
|
||||
if (nested) {
|
||||
|
@ -545,17 +543,33 @@ int luax_readmesh(lua_State* L, int index, float** vertices, uint32_t* vertexCou
|
|||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < *indexCount; i++) {
|
||||
lua_rawgeti(L, index + 1, i + 1);
|
||||
uint32_t index = luaL_checkinteger(L, -1) - 1;
|
||||
lovrAssert(index < *vertexCount, "Invalid vertex index %d (expected [%d, %d])", index + 1, 1, *vertexCount);
|
||||
(*indices)[i] = index;
|
||||
lua_pop(L, 1);
|
||||
if (indices) {
|
||||
luaL_checktype(L, index + 1, LUA_TTABLE);
|
||||
*indexCount = luax_len(L, index + 1);
|
||||
lovrCheck(*indexCount > 0, "Invalid mesh data: index count is zero");
|
||||
lovrCheck(*indexCount % 3 == 0, "Index count must be a multiple of 3");
|
||||
*indices = lovrMalloc(sizeof(uint32_t) * *indexCount);
|
||||
|
||||
for (uint32_t i = 0; i < *indexCount; i++) {
|
||||
lua_rawgeti(L, index + 1, i + 1);
|
||||
uint32_t index = luaL_checkinteger(L, -1) - 1;
|
||||
lovrCheck(index < *vertexCount, "Invalid vertex index %d (expected [%d, %d])", index + 1, 1, *vertexCount);
|
||||
(*indices)[i] = index;
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return index + 2;
|
||||
}
|
||||
|
||||
ModelData* modelData = luax_totype(L, index, ModelData);
|
||||
|
||||
if (modelData) {
|
||||
lovrModelDataGetTriangles(modelData, vertices, indices, vertexCount, indexCount);
|
||||
*shouldFree = false;
|
||||
return index + 1;
|
||||
}
|
||||
|
||||
#ifndef LOVR_DISABLE_GRAPHICS
|
||||
Model* model = luax_totype(L, index, Model);
|
||||
|
||||
|
@ -573,7 +587,9 @@ int luax_readmesh(lua_State* L, int index, float** vertices, uint32_t* vertexCou
|
|||
*shouldFree = true;
|
||||
return index + 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return luaL_argerror(L, index, "table, Mesh, or Model");
|
||||
return luaL_argerror(L, index, "table, ModelData, Model, or Mesh expected");
|
||||
#else
|
||||
return luaL_argerror(L, index, "table or ModelData expected");
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@ extern StringEntry lovrPassType[];
|
|||
extern StringEntry lovrPermission[];
|
||||
extern StringEntry lovrSampleFormat[];
|
||||
extern StringEntry lovrShaderStage[];
|
||||
extern StringEntry lovrShaderType[];
|
||||
extern StringEntry lovrShapeType[];
|
||||
extern StringEntry lovrSmoothMode[];
|
||||
extern StringEntry lovrStackType[];
|
||||
|
@ -200,6 +201,8 @@ struct Shape* luax_newsphereshape(lua_State* L, int index);
|
|||
struct Shape* luax_newboxshape(lua_State* L, int index);
|
||||
struct Shape* luax_newcapsuleshape(lua_State* L, int index);
|
||||
struct Shape* luax_newcylindershape(lua_State* L, int index);
|
||||
struct Shape* luax_newconvexshape(lua_State* L, int index);
|
||||
struct Shape* luax_newmeshshape(lua_State* L, int index);
|
||||
struct Shape* luax_newterrainshape(lua_State* L, int index);
|
||||
struct Shape* luax_newcompoundshape(lua_State* L, int index);
|
||||
#endif
|
||||
|
|
|
@ -200,8 +200,8 @@ static int l_lovrAudioSetGeometry(lua_State* L) {
|
|||
AudioMaterial material = luax_checkenum(L, index, AudioMaterial, "generic");
|
||||
bool success = lovrAudioSetGeometry(vertices, indices, vertexCount, indexCount, material);
|
||||
if (shouldFree) {
|
||||
free(vertices);
|
||||
free(indices);
|
||||
lovrFree(vertices);
|
||||
lovrFree(indices);
|
||||
}
|
||||
lua_pushboolean(L, success);
|
||||
return 1;
|
||||
|
@ -256,7 +256,7 @@ static int l_lovrAudioNewSource(lua_State* L) {
|
|||
lua_getfield(L, 2, "effects");
|
||||
if (!lua_isnil(L, -1)) {
|
||||
effects = 0;
|
||||
lovrAssert(lua_istable(L, -1), "Source effects must be a table");
|
||||
lovrCheck(lua_istable(L, -1), "Source effects must be a table");
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, -2) != 0) {
|
||||
if (lua_type(L, -2) == LUA_TSTRING) {
|
||||
|
@ -277,18 +277,19 @@ static int l_lovrAudioNewSource(lua_State* L) {
|
|||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
uint32_t defer = lovrDeferPush();
|
||||
|
||||
if (!sound) {
|
||||
Blob* blob = luax_readblob(L, 1, "Source");
|
||||
lovrDeferRelease(blob, lovrBlobDestroy);
|
||||
sound = lovrSoundCreateFromFile(blob, decode);
|
||||
lovrRelease(blob, lovrBlobDestroy);
|
||||
} else {
|
||||
lovrRetain(sound);
|
||||
lovrDeferRelease(sound, lovrSoundDestroy);
|
||||
}
|
||||
|
||||
Source* source = lovrSourceCreate(sound, pitchable, spatial, effects);
|
||||
luax_pushtype(L, Source, source);
|
||||
lovrRelease(sound, lovrSoundDestroy);
|
||||
lovrRelease(source, lovrSourceDestroy);
|
||||
lovrDeferPop(defer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -64,8 +64,10 @@ Image* luax_checkimage(lua_State* L, int index) {
|
|||
lovrRetain(image);
|
||||
} else {
|
||||
Blob* blob = luax_readblob(L, index, "Image");
|
||||
uint32_t defer = lovrDeferPush();
|
||||
lovrDeferRelease(blob, lovrBlobDestroy);
|
||||
image = lovrImageCreateFromFile(blob);
|
||||
lovrRelease(blob, lovrBlobDestroy);
|
||||
lovrDeferPop(defer);
|
||||
}
|
||||
|
||||
return image;
|
||||
|
@ -77,21 +79,18 @@ static int l_lovrDataNewBlob(lua_State* L) {
|
|||
int type = lua_type(L, 1);
|
||||
if (type == LUA_TNUMBER) {
|
||||
int isize = lua_tonumber(L, 1);
|
||||
lovrAssert(isize > 0, "Blob size must be positive");
|
||||
lovrCheck(isize > 0, "Blob size must be positive");
|
||||
size = (size_t) isize;
|
||||
data = calloc(1, size);
|
||||
lovrAssert(data, "Out of memory");
|
||||
data = lovrCalloc(size);
|
||||
} else if (type == LUA_TSTRING) {
|
||||
const char* str = luaL_checklstring(L, 1, &size);
|
||||
data = malloc(size + 1);
|
||||
lovrAssert(data, "Out of memory");
|
||||
data = lovrMalloc(size + 1);
|
||||
memcpy(data, str, size);
|
||||
data[size] = '\0';
|
||||
} else {
|
||||
Blob* blob = luax_checktype(L, 1, Blob);
|
||||
size = blob->size;
|
||||
data = malloc(size);
|
||||
lovrAssert(data, "Out of memory");
|
||||
data = lovrMalloc(size);
|
||||
memcpy(data, blob->data, size);
|
||||
}
|
||||
const char* name = luaL_optstring(L, 2, "");
|
||||
|
@ -139,10 +138,12 @@ static int l_lovrDataNewImage(lua_State* L) {
|
|||
|
||||
static int l_lovrDataNewModelData(lua_State* L) {
|
||||
Blob* blob = luax_readblob(L, 1, "Model");
|
||||
uint32_t defer = lovrDeferPush();
|
||||
lovrDeferRelease(blob, lovrBlobDestroy);
|
||||
ModelData* modelData = lovrModelDataCreate(blob, luax_readfile);
|
||||
luax_pushtype(L, ModelData, modelData);
|
||||
lovrRelease(blob, lovrBlobDestroy);
|
||||
lovrRelease(modelData, lovrModelDataDestroy);
|
||||
lovrDeferPop(defer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -150,22 +151,26 @@ static int l_lovrDataNewRasterizer(lua_State* L) {
|
|||
Blob* blob = NULL;
|
||||
float size;
|
||||
|
||||
uint32_t defer = lovrDeferPush();
|
||||
|
||||
if (lua_type(L, 1) == LUA_TNUMBER || lua_isnoneornil(L, 1)) {
|
||||
size = luax_optfloat(L, 1, 32.f);
|
||||
} else {
|
||||
blob = luax_readblob(L, 1, "Font");
|
||||
size = luax_optfloat(L, 2, 32.f);
|
||||
lovrDeferRelease(blob, lovrBlobDestroy);
|
||||
}
|
||||
|
||||
Rasterizer* rasterizer = lovrRasterizerCreate(blob, size);
|
||||
luax_pushtype(L, Rasterizer, rasterizer);
|
||||
lovrRelease(blob, lovrBlobDestroy);
|
||||
lovrRelease(rasterizer, lovrRasterizerDestroy);
|
||||
lovrDeferPop(defer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrDataNewSound(lua_State* L) {
|
||||
int type = lua_type(L, 1);
|
||||
|
||||
if (type == LUA_TNUMBER) {
|
||||
uint32_t frames = luax_checku32(L, 1);
|
||||
SampleFormat format = luax_checkenum(L, 2, SampleFormat, "f32");
|
||||
|
@ -186,10 +191,13 @@ static int l_lovrDataNewSound(lua_State* L) {
|
|||
|
||||
Blob* blob = luax_readblob(L, 1, "Sound");
|
||||
bool decode = lua_toboolean(L, 2);
|
||||
|
||||
uint32_t defer = lovrDeferPush();
|
||||
lovrDeferRelease(blob, lovrBlobDestroy);
|
||||
Sound* sound = lovrSoundCreateFromFile(blob, decode);
|
||||
luax_pushtype(L, Sound, sound);
|
||||
lovrRelease(blob, lovrBlobDestroy);
|
||||
lovrRelease(sound, lovrSoundDestroy);
|
||||
lovrDeferPop(defer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ StringEntry lovrTextureFormat[] = {
|
|||
[FORMAT_RGB10A2] = ENTRY("rgb10a2"),
|
||||
[FORMAT_RG11B10F] = ENTRY("rg11b10f"),
|
||||
[FORMAT_D16] = ENTRY("d16"),
|
||||
[FORMAT_D24] = ENTRY("d24"),
|
||||
[FORMAT_D32F] = ENTRY("d32f"),
|
||||
[FORMAT_D24S8] = ENTRY("d24s8"),
|
||||
[FORMAT_D32FS8] = ENTRY("d32fs8"),
|
||||
|
|
|
@ -109,7 +109,7 @@ static int l_lovrSoundGetFrames(lua_State* L) {
|
|||
uint32_t dstOffset = luax_optu32(L, index + 2, 0);
|
||||
uint32_t srcOffset = luax_optu32(L, index + 1, 0);
|
||||
uint32_t count = luax_optu32(L, index, frameCount - srcOffset);
|
||||
lovrAssert(srcOffset + count <= frameCount, "Tried to read samples past the end of the Sound");
|
||||
lovrCheck(srcOffset + count <= frameCount, "Tried to read samples past the end of the Sound");
|
||||
lua_settop(L, 2);
|
||||
|
||||
switch (lua_type(L, 2)) {
|
||||
|
@ -151,7 +151,7 @@ static int l_lovrSoundGetFrames(lua_State* L) {
|
|||
Sound* other = luax_totype(L, 2, Sound);
|
||||
Blob* blob = luax_totype(L, 2, Blob);
|
||||
if (blob) {
|
||||
lovrAssert(dstOffset + count * stride <= blob->size, "This Blob can hold %d bytes, which is not enough space to hold %d bytes of audio data at the requested offset (%d)", blob->size, count * stride, dstOffset);
|
||||
lovrCheck(dstOffset + count * stride <= blob->size, "This Blob can hold %d bytes, which is not enough space to hold %d bytes of audio data at the requested offset (%d)", blob->size, count * stride, dstOffset);
|
||||
char* data = (char*) blob->data + dstOffset;
|
||||
uint32_t frames = 0;
|
||||
while (frames < count) {
|
||||
|
@ -215,7 +215,7 @@ static int l_lovrSoundSetFrames(lua_State* L) {
|
|||
uint32_t dstOffset = luax_optu32(L, 4, 0);
|
||||
uint32_t limit = MIN(frameCount - dstOffset, (length - srcOffset) / channels + 1);
|
||||
uint32_t count = luax_optu32(L, 3, limit);
|
||||
lovrAssert(count <= limit, "Tried to write too many frames (%d is over limit %d)", count, limit);
|
||||
lovrCheck(count <= limit, "Tried to write too many frames (%d is over limit %d)", count, limit);
|
||||
|
||||
uint32_t frames = 0;
|
||||
while (frames < count) {
|
||||
|
|
|
@ -55,8 +55,7 @@ void luax_checkvariant(lua_State* L, int index, Variant* variant) {
|
|||
memcpy(variant->value.ministring.data, string, length);
|
||||
} else {
|
||||
variant->type = TYPE_STRING;
|
||||
variant->value.string.pointer = malloc(length + 1);
|
||||
lovrAssert(variant->value.string.pointer, "Out of memory");
|
||||
variant->value.string.pointer = lovrMalloc(length + 1);
|
||||
memcpy(variant->value.string.pointer, string, length);
|
||||
variant->value.string.pointer[length] = '\0';
|
||||
variant->value.string.length = length;
|
||||
|
@ -92,8 +91,7 @@ void luax_checkvariant(lua_State* L, int index, Variant* variant) {
|
|||
if (v) {
|
||||
if (type == V_MAT4) {
|
||||
variant->type = TYPE_MATRIX;
|
||||
variant->value.matrix.data = malloc(16 * sizeof(float));
|
||||
lovrAssert(variant->value.matrix.data, "Out of memory");
|
||||
variant->value.matrix.data = lovrMalloc(16 * sizeof(float));
|
||||
memcpy(variant->value.matrix.data, v, 16 * sizeof(float));
|
||||
break;
|
||||
} else {
|
||||
|
@ -205,7 +203,7 @@ static int nextEvent(lua_State* L) {
|
|||
luax_pushtype(L, Thread, event.data.thread.thread);
|
||||
lua_pushstring(L, event.data.thread.error);
|
||||
lovrRelease(event.data.thread.thread, lovrThreadDestroy);
|
||||
free(event.data.thread.error);
|
||||
lovrFree(event.data.thread.error);
|
||||
return 3;
|
||||
#endif
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ static int luax_loadfile(lua_State* L, const char* path, const char* debug, cons
|
|||
return 2;
|
||||
}
|
||||
int status = luax_loadbufferx(L, buffer, size, debug, mode);
|
||||
free(buffer);
|
||||
lovrFree(buffer);
|
||||
switch (status) {
|
||||
case LUA_ERRMEM: return luaL_error(L, "Memory allocation error: %s", lua_tostring(L, -1));
|
||||
case LUA_ERRSYNTAX: return luaL_error(L, "Syntax error: %s", lua_tostring(L, -1));
|
||||
|
@ -315,7 +315,7 @@ static int l_lovrFilesystemRead(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
lua_pushlstring(L, data, size);
|
||||
free(data);
|
||||
lovrFree(data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,17 +41,18 @@ static int l_lovrFileRead(lua_State* L) {
|
|||
size = lovrFileGetSize(file) - lovrFileTell(file);
|
||||
}
|
||||
size_t count;
|
||||
void* data = malloc(size);
|
||||
lovrAssert(data, "Out of memory");
|
||||
void* data = lovrMalloc(size);
|
||||
uint32_t defer = lovrDeferPush();
|
||||
lovrDefer(lovrFree, data);
|
||||
bool success = lovrFileRead(file, data, size, &count);
|
||||
if (success) {
|
||||
lua_pushlstring(L, data, count);
|
||||
lua_pushnumber(L, count);
|
||||
free(data);
|
||||
lovrDeferPop(defer);
|
||||
return 2;
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
free(data);
|
||||
lovrDeferPop(defer);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,7 +58,6 @@ StringEntry lovrDefaultShader[] = {
|
|||
[SHADER_EQUIRECT] = ENTRY("equirect"),
|
||||
[SHADER_FILL_2D] = ENTRY("fill"),
|
||||
[SHADER_FILL_ARRAY] = ENTRY("fillarray"),
|
||||
[SHADER_LOGO] = ENTRY("logo"),
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
|
@ -80,6 +79,7 @@ StringEntry lovrDataType[] = {
|
|||
[TYPE_U8x4] = ENTRY("u8x4"),
|
||||
[TYPE_SN8x4] = ENTRY("sn8x4"),
|
||||
[TYPE_UN8x4] = ENTRY("un8x4"),
|
||||
[TYPE_SN10x3] = ENTRY("sn10x3"),
|
||||
[TYPE_UN10x3] = ENTRY("un10x3"),
|
||||
[TYPE_I16] = ENTRY("i16"),
|
||||
[TYPE_I16x2] = ENTRY("i16x2"),
|
||||
|
@ -145,6 +145,12 @@ StringEntry lovrShaderStage[] = {
|
|||
{ 0 }
|
||||
};
|
||||
|
||||
StringEntry lovrShaderType[] = {
|
||||
[SHADER_GRAPHICS] = ENTRY("graphics"),
|
||||
[SHADER_COMPUTE] = ENTRY("compute"),
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
StringEntry lovrStackType[] = {
|
||||
[STACK_TRANSFORM] = ENTRY("transform"),
|
||||
[STACK_STATE] = ENTRY("state"),
|
||||
|
@ -299,19 +305,14 @@ static void luax_writeshadercache(void) {
|
|||
return;
|
||||
}
|
||||
|
||||
void* data = malloc(size);
|
||||
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
void* data = lovrMalloc(size);
|
||||
lovrGraphicsGetShaderCache(data, &size);
|
||||
|
||||
if (size > 0) {
|
||||
luax_writefile(".lovrshadercache", data, size);
|
||||
}
|
||||
|
||||
free(data);
|
||||
lovrFree(data);
|
||||
}
|
||||
|
||||
static int l_lovrGraphicsInitialize(lua_State* L) {
|
||||
|
@ -349,8 +350,11 @@ static int l_lovrGraphicsInitialize(lua_State* L) {
|
|||
}
|
||||
lua_pop(L, 2);
|
||||
|
||||
uint32_t defer = lovrDeferPush();
|
||||
|
||||
if (shaderCache) {
|
||||
config.cacheData = luax_readfile(".lovrshadercache", &config.cacheSize);
|
||||
lovrDefer(lovrFree, config.cacheData);
|
||||
}
|
||||
|
||||
lovrGraphicsInit(&config);
|
||||
|
@ -360,7 +364,8 @@ static int l_lovrGraphicsInitialize(lua_State* L) {
|
|||
luax_atexit(L, luax_writeshadercache);
|
||||
}
|
||||
|
||||
free(config.cacheData);
|
||||
lovrDeferPop(defer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -388,8 +393,13 @@ static int l_lovrGraphicsSubmit(lua_State* L) {
|
|||
uint32_t count = 0;
|
||||
|
||||
Pass* stack[8];
|
||||
Pass** passes = (size_t) length > COUNTOF(stack) ? malloc(length * sizeof(Pass*)) : stack;
|
||||
lovrAssert(passes, "Out of memory");
|
||||
Pass** passes = stack;
|
||||
uint32_t defer = lovrDeferPush();
|
||||
|
||||
if ((size_t) length > COUNTOF(stack)) {
|
||||
passes = lovrMalloc(length * sizeof(Pass*));
|
||||
lovrDefer(lovrFree, passes);
|
||||
}
|
||||
|
||||
if (table) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
|
@ -408,8 +418,8 @@ static int l_lovrGraphicsSubmit(lua_State* L) {
|
|||
}
|
||||
|
||||
lovrGraphicsSubmit(passes, count);
|
||||
if (passes != stack) free(passes);
|
||||
lua_pushboolean(L, true);
|
||||
lovrDeferPop(defer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -719,13 +729,19 @@ static int l_lovrGraphicsNewBuffer(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void freeImages(void* arg) {
|
||||
TextureInfo* info = arg;
|
||||
for (uint32_t i = 0; i < info->imageCount; i++) {
|
||||
lovrRelease(info->images[i], lovrImageDestroy);
|
||||
}
|
||||
}
|
||||
|
||||
static int l_lovrGraphicsNewTexture(lua_State* L) {
|
||||
TextureInfo info = {
|
||||
.type = TEXTURE_2D,
|
||||
.format = FORMAT_RGBA8,
|
||||
.layers = 1,
|
||||
.mipmaps = ~0u,
|
||||
.samples = 1,
|
||||
.usage = TEXTURE_SAMPLE,
|
||||
.srgb = true
|
||||
};
|
||||
|
@ -733,6 +749,7 @@ static int l_lovrGraphicsNewTexture(lua_State* L) {
|
|||
int index = 1;
|
||||
Image* stack[6];
|
||||
Image** images = stack;
|
||||
uint32_t defer = lovrDeferPush();
|
||||
|
||||
if (lua_isnumber(L, 1)) {
|
||||
info.width = luax_checku32(L, index++);
|
||||
|
@ -744,13 +761,18 @@ static int l_lovrGraphicsNewTexture(lua_State* L) {
|
|||
info.usage |= TEXTURE_RENDER;
|
||||
info.mipmaps = 1;
|
||||
} else if (lua_istable(L, 1)) {
|
||||
info.imageCount = luax_len(L, index++);
|
||||
images = info.imageCount > COUNTOF(stack) ? malloc(info.imageCount * sizeof(Image*)) : stack;
|
||||
lovrAssert(images, "Out of memory");
|
||||
int tableLength = luax_len(L, index++);
|
||||
|
||||
if (info.imageCount == 0) {
|
||||
if ((size_t) tableLength > COUNTOF(stack)) {
|
||||
images = lovrMalloc(tableLength * sizeof(Image*));
|
||||
lovrDefer(lovrFree, images);
|
||||
}
|
||||
|
||||
info.images = images;
|
||||
lovrDefer(freeImages, &info);
|
||||
|
||||
if (tableLength == 0) {
|
||||
info.layers = 6;
|
||||
info.imageCount = 6;
|
||||
info.type = TEXTURE_CUBE;
|
||||
const char* faces[6] = { "right", "left", "top", "bottom", "back", "front" };
|
||||
const char* altFaces[6] = { "px", "nx", "py", "ny", "pz", "nz" };
|
||||
|
@ -762,13 +784,13 @@ static int l_lovrGraphicsNewTexture(lua_State* L) {
|
|||
lua_pushstring(L, altFaces[i]);
|
||||
lua_rawget(L, 1);
|
||||
}
|
||||
lovrAssert(!lua_isnil(L, -1), "No array texture layers given and cubemap face '%s' missing", faces[i]);
|
||||
images[i] = luax_checkimage(L, -1);
|
||||
lovrCheck(!lua_isnil(L, -1), "No array texture layers given and cubemap face '%s' missing", faces[i]);
|
||||
images[info.imageCount++] = luax_checkimage(L, -1);
|
||||
}
|
||||
} else {
|
||||
for (uint32_t i = 0; i < info.imageCount; i++) {
|
||||
for (int i = 0; i < tableLength; i++) {
|
||||
lua_rawgeti(L, 1, i + 1);
|
||||
images[i] = luax_checkimage(L, -1);
|
||||
images[info.imageCount++] = luax_checkimage(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
|
@ -787,7 +809,6 @@ static int l_lovrGraphicsNewTexture(lua_State* L) {
|
|||
}
|
||||
|
||||
if (info.imageCount > 0) {
|
||||
info.images = images;
|
||||
Image* image = images[0];
|
||||
uint32_t levels = lovrImageGetLevelCount(image);
|
||||
info.format = lovrImageGetFormat(image);
|
||||
|
@ -797,11 +818,11 @@ static int l_lovrGraphicsNewTexture(lua_State* L) {
|
|||
bool mipmappable = lovrGraphicsGetFormatSupport(info.format, TEXTURE_FEATURE_BLIT) & (1 << info.srgb);
|
||||
info.mipmaps = (levels == 1 && mipmappable) ? ~0u : levels;
|
||||
for (uint32_t i = 1; i < info.imageCount; i++) {
|
||||
lovrAssert(lovrImageGetWidth(images[0], 0) == lovrImageGetWidth(images[i], 0), "Image widths must match");
|
||||
lovrAssert(lovrImageGetHeight(images[0], 0) == lovrImageGetHeight(images[i], 0), "Image heights must match");
|
||||
lovrAssert(lovrImageGetFormat(images[0]) == lovrImageGetFormat(images[i]), "Image formats must match");
|
||||
lovrAssert(lovrImageGetLevelCount(images[0]) == lovrImageGetLevelCount(images[i]), "Image mipmap counts must match");
|
||||
lovrAssert(lovrImageGetLayerCount(images[i]) == 1, "When a list of images are provided, each must have a single layer");
|
||||
lovrCheck(lovrImageGetWidth(images[0], 0) == lovrImageGetWidth(images[i], 0), "Image widths must match");
|
||||
lovrCheck(lovrImageGetHeight(images[0], 0) == lovrImageGetHeight(images[i], 0), "Image heights must match");
|
||||
lovrCheck(lovrImageGetFormat(images[0]) == lovrImageGetFormat(images[i]), "Image formats must match");
|
||||
lovrCheck(lovrImageGetLevelCount(images[0]) == lovrImageGetLevelCount(images[i]), "Image mipmap counts must match");
|
||||
lovrCheck(lovrImageGetLayerCount(images[i]) == 1, "When a list of images are provided, each must have a single layer");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -814,10 +835,6 @@ static int l_lovrGraphicsNewTexture(lua_State* L) {
|
|||
lua_getfield(L, index, "format");
|
||||
info.format = lua_isnil(L, -1) ? info.format : (uint32_t) luax_checkenum(L, -1, TextureFormat, NULL);
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_getfield(L, index, "samples");
|
||||
info.samples = lua_isnil(L, -1) ? info.samples : luax_checku32(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
lua_getfield(L, index, "linear");
|
||||
|
@ -831,7 +848,7 @@ static int l_lovrGraphicsNewTexture(lua_State* L) {
|
|||
} else if (!lua_isnil(L, -1)) {
|
||||
info.mipmaps = lua_toboolean(L, -1) ? ~0u : 1;
|
||||
} else {
|
||||
info.mipmaps = (info.samples > 1 || info.imageCount == 0 || !mipmappable) ? 1 : ~0u;
|
||||
info.mipmaps = (info.imageCount == 0 || !mipmappable) ? 1 : ~0u;
|
||||
}
|
||||
lovrCheck(info.imageCount == 0 || info.mipmaps == 1 || mipmappable, "This texture format does not support blitting, which is required for mipmap generation");
|
||||
lua_pop(L, 1);
|
||||
|
@ -863,17 +880,46 @@ static int l_lovrGraphicsNewTexture(lua_State* L) {
|
|||
}
|
||||
|
||||
Texture* texture = lovrTextureCreate(&info);
|
||||
|
||||
for (uint32_t i = 0; i < info.imageCount; i++) {
|
||||
lovrRelease(images[i], lovrImageDestroy);
|
||||
}
|
||||
|
||||
if (images != stack) {
|
||||
free(images);
|
||||
}
|
||||
|
||||
luax_pushtype(L, Texture, texture);
|
||||
lovrRelease(texture, lovrTextureDestroy);
|
||||
lovrDeferPop(defer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrGraphicsNewTextureView(lua_State* L) {
|
||||
Texture* texture = luax_checktype(L, 1, Texture);
|
||||
const TextureInfo* base = lovrTextureGetInfo(texture);
|
||||
luaL_checktype(L, 2, LUA_TTABLE);
|
||||
|
||||
TextureViewInfo info = { 0 };
|
||||
|
||||
lua_getfield(L, 2, "type");
|
||||
info.type = lua_isnil(L, -1) ? base->type : luax_checkenum(L, -1, TextureType, NULL);
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_getfield(L, 2, "layer");
|
||||
info.layerIndex = lua_isnil(L, -1) ? 0 : luax_checku32(L, -1) - 1;
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_getfield(L, 2, "layercount");
|
||||
info.layerCount = lua_isnil(L, -1) ? ~0u : luax_checku32(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_getfield(L, 2, "mipmap");
|
||||
info.levelIndex = lua_isnil(L, -1) ? 0 : luax_checku32(L, -1) - 1;
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_getfield(L, 2, "mipmapcount");
|
||||
info.levelCount = lua_isnil(L, -1) ? ~0u : luax_checku32(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_getfield(L, 2, "label");
|
||||
info.label = lua_tostring(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
Texture* view = lovrTextureCreateView(texture, &info);
|
||||
luax_pushtype(L, Texture, view);
|
||||
lovrRelease(view, lovrTextureDestroy);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -930,7 +976,7 @@ static int l_lovrGraphicsNewSampler(lua_State* L) {
|
|||
|
||||
lua_getfield(L, 1, "mipmaprange");
|
||||
if (!lua_isnil(L, -1)) {
|
||||
lovrAssert(lua_istable(L, -1), "Sampler mipmap range must be nil or a table");
|
||||
lovrCheck(lua_istable(L, -1), "Sampler mipmap range must be nil or a table");
|
||||
lua_rawgeti(L, -1, 1);
|
||||
lua_rawgeti(L, -2, 2);
|
||||
info.range[0] = luax_checkfloat(L, -2);
|
||||
|
@ -945,96 +991,90 @@ static int l_lovrGraphicsNewSampler(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static ShaderSource luax_checkshadersource(lua_State* L, int index, ShaderStage stage, bool* allocated) {
|
||||
ShaderSource source;
|
||||
static ShaderSource luax_checkshadersource(lua_State* L, int index, ShaderStage stage, bool* shouldFree) {
|
||||
*shouldFree = false;
|
||||
|
||||
if (lua_isstring(L, index)) {
|
||||
size_t length;
|
||||
const char* string = lua_tolstring(L, index, &length);
|
||||
|
||||
if (memchr(string, '\n', MIN(256, length))) {
|
||||
source.code = string;
|
||||
source.size = length;
|
||||
*allocated = false;
|
||||
return (ShaderSource) { stage, string, length };
|
||||
} else {
|
||||
for (int i = 0; lovrDefaultShader[i].length; i++) {
|
||||
if (lovrDefaultShader[i].length == length && !memcmp(lovrDefaultShader[i].string, string, length)) {
|
||||
*allocated = false;
|
||||
return lovrGraphicsGetDefaultShaderSource(i, stage);
|
||||
}
|
||||
}
|
||||
|
||||
source.code = luax_readfile(string, &source.size);
|
||||
size_t size;
|
||||
void* code = luax_readfile(string, &size);
|
||||
|
||||
if (source.code) {
|
||||
*allocated = true;
|
||||
if (code) {
|
||||
*shouldFree = true;
|
||||
return (ShaderSource) { stage, code, size };
|
||||
} else {
|
||||
luaL_argerror(L, index, "single-line string was not filename or DefaultShader");
|
||||
}
|
||||
}
|
||||
} else if (lua_isuserdata(L, index)) {
|
||||
Blob* blob = luax_checktype(L, index, Blob);
|
||||
source.code = blob->data;
|
||||
source.size = blob->size;
|
||||
*allocated = false;
|
||||
return (ShaderSource) { stage, blob->data, blob->size };
|
||||
} else {
|
||||
*allocated = false;
|
||||
return lovrGraphicsGetDefaultShaderSource(SHADER_UNLIT, stage);
|
||||
luax_typeerror(L, index, "string, Blob, or DefaultShader");
|
||||
}
|
||||
|
||||
ShaderSource bytecode = lovrGraphicsCompileShader(stage, &source, luax_readfile);
|
||||
|
||||
if (bytecode.code != source.code) {
|
||||
if (*allocated) free((void*) source.code);
|
||||
*allocated = true;
|
||||
return bytecode;
|
||||
}
|
||||
|
||||
return source;
|
||||
return (ShaderSource) { 0 };
|
||||
}
|
||||
|
||||
static int l_lovrGraphicsCompileShader(lua_State* L) {
|
||||
ShaderStage stage = luax_checkenum(L, 1, ShaderStage, NULL);
|
||||
bool allocated;
|
||||
ShaderSource spirv = luax_checkshadersource(L, 2, stage, &allocated);
|
||||
Blob* blob = lovrBlobCreate((void*) spirv.code, spirv.size, "Compiled Shader Code");
|
||||
luax_pushtype(L, Blob, blob);
|
||||
lovrRelease(blob, lovrBlobDestroy);
|
||||
return 1;
|
||||
ShaderSource inputs[2], outputs[2];
|
||||
bool shouldFree[2];
|
||||
uint32_t count;
|
||||
|
||||
if (lua_gettop(L) == 1) {
|
||||
inputs[0] = luax_checkshadersource(L, 1, STAGE_COMPUTE, &shouldFree[0]);
|
||||
count = 1;
|
||||
} else {
|
||||
inputs[0] = luax_checkshadersource(L, 1, STAGE_VERTEX, &shouldFree[0]);
|
||||
inputs[1] = luax_checkshadersource(L, 2, STAGE_FRAGMENT, &shouldFree[1]);
|
||||
count = 2;
|
||||
}
|
||||
|
||||
lovrGraphicsCompileShader(inputs, outputs, count, luax_readfile);
|
||||
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
if (shouldFree[i] && outputs[i].code != inputs[i].code) lovrFree((void*) inputs[i].code);
|
||||
Blob* blob = lovrBlobCreate((void*) outputs[i].code, outputs[i].size, "Shader code");
|
||||
luax_pushtype(L, Blob, blob);
|
||||
lovrRelease(blob, lovrBlobDestroy);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int l_lovrGraphicsNewShader(lua_State* L) {
|
||||
ShaderInfo info = { 0 };
|
||||
bool allocated[2];
|
||||
ShaderSource source[2], compiled[2];
|
||||
ShaderInfo info = { .stages = compiled };
|
||||
bool shouldFree[2] = { 0 };
|
||||
int index;
|
||||
|
||||
// If there's only one source given, it could be a DefaultShader or a compute shader
|
||||
if (lua_gettop(L) == 1 || (lua_istable(L, 2) && luax_len(L, 2) == 0)) {
|
||||
if (lua_type(L, 1) == LUA_TSTRING) {
|
||||
size_t length;
|
||||
const char* string = lua_tolstring(L, 1, &length);
|
||||
for (int i = 0; lovrDefaultShader[i].length; i++) {
|
||||
if (lovrDefaultShader[i].length == length && !memcmp(lovrDefaultShader[i].string, string, length)) {
|
||||
info.source[STAGE_VERTEX] = lovrGraphicsGetDefaultShaderSource(i, STAGE_VERTEX);
|
||||
info.source[STAGE_FRAGMENT] = lovrGraphicsGetDefaultShaderSource(i, STAGE_FRAGMENT);
|
||||
allocated[0] = false;
|
||||
allocated[1] = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!info.source[0].code) {
|
||||
info.source[STAGE_COMPUTE] = luax_checkshadersource(L, 1, STAGE_COMPUTE, &allocated[0]);
|
||||
}
|
||||
|
||||
if (lua_gettop(L) == 1 || lua_istable(L, 2)) {
|
||||
info.type = SHADER_COMPUTE;
|
||||
source[0] = luax_checkshadersource(L, 1, STAGE_COMPUTE, &shouldFree[0]);
|
||||
info.stageCount = 1;
|
||||
index = 2;
|
||||
} else {
|
||||
info.source[STAGE_VERTEX] = luax_checkshadersource(L, 1, STAGE_VERTEX, &allocated[0]);
|
||||
info.source[STAGE_FRAGMENT] = luax_checkshadersource(L, 2, STAGE_FRAGMENT, &allocated[1]);
|
||||
info.type = SHADER_GRAPHICS;
|
||||
source[0] = luax_checkshadersource(L, 1, STAGE_VERTEX, &shouldFree[0]);
|
||||
source[1] = luax_checkshadersource(L, 2, STAGE_FRAGMENT, &shouldFree[1]);
|
||||
info.stageCount = 2;
|
||||
index = 3;
|
||||
}
|
||||
|
||||
lovrGraphicsCompileShader(source, compiled, info.stageCount, luax_readfile);
|
||||
|
||||
arr_t(ShaderFlag) flags;
|
||||
arr_init(&flags, realloc);
|
||||
arr_init(&flags);
|
||||
|
||||
if (lua_istable(L, index)) {
|
||||
lua_getfield(L, index, "flags");
|
||||
|
@ -1055,6 +1095,10 @@ static int l_lovrGraphicsNewShader(lua_State* L) {
|
|||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_getfield(L, index, "type");
|
||||
info.type = lua_isnil(L, -1) ? info.type : luax_checkenum(L, -1, ShaderType, NULL);
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_getfield(L, index, "label");
|
||||
info.label = lua_tostring(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
@ -1068,8 +1112,12 @@ static int l_lovrGraphicsNewShader(lua_State* L) {
|
|||
Shader* shader = lovrShaderCreate(&info);
|
||||
luax_pushtype(L, Shader, shader);
|
||||
lovrRelease(shader, lovrShaderDestroy);
|
||||
if (allocated[0]) free((void*) info.source[0].code);
|
||||
if (allocated[1]) free((void*) info.source[1].code);
|
||||
|
||||
for (uint32_t i = 0; i < info.stageCount; i++) {
|
||||
if (shouldFree[i]) lovrFree((void*) source[i].code);
|
||||
if (source[i].code != compiled[i].code) lovrFree((void*) compiled[i].code);
|
||||
}
|
||||
|
||||
arr_free(&flags);
|
||||
return 1;
|
||||
}
|
||||
|
@ -1091,15 +1139,16 @@ static Texture* luax_opttexture(lua_State* L, int index) {
|
|||
.height = lovrImageGetHeight(image, 0),
|
||||
.layers = 1,
|
||||
.mipmaps = ~0u,
|
||||
.samples = 1,
|
||||
.usage = TEXTURE_SAMPLE,
|
||||
.srgb = lovrImageIsSRGB(image),
|
||||
.imageCount = 1,
|
||||
.images = &image
|
||||
};
|
||||
|
||||
uint32_t defer = lovrDeferPush();
|
||||
lovrDeferRelease(image, lovrImageDestroy);
|
||||
texture = lovrTextureCreate(&info);
|
||||
lovrRelease(image, lovrImageDestroy);
|
||||
lovrDeferPop(defer);
|
||||
return texture;
|
||||
}
|
||||
|
||||
|
@ -1228,6 +1277,8 @@ static int l_lovrGraphicsNewFont(lua_State* L) {
|
|||
info.rasterizer = luax_totype(L, 1, Rasterizer);
|
||||
info.spread = 4.;
|
||||
|
||||
uint32_t defer = lovrDeferPush();
|
||||
|
||||
if (!info.rasterizer) {
|
||||
Blob* blob = NULL;
|
||||
float size;
|
||||
|
@ -1239,19 +1290,19 @@ static int l_lovrGraphicsNewFont(lua_State* L) {
|
|||
blob = luax_readblob(L, 1, "Font");
|
||||
size = luax_optfloat(L, 2, 32.);
|
||||
info.spread = luaL_optnumber(L, 3, info.spread);
|
||||
lovrDeferRelease(blob, lovrBlobDestroy);
|
||||
}
|
||||
|
||||
info.rasterizer = lovrRasterizerCreate(blob, size);
|
||||
lovrRelease(blob, lovrBlobDestroy);
|
||||
lovrDeferRelease(info.rasterizer, lovrRasterizerDestroy);
|
||||
} else {
|
||||
info.spread = luaL_optnumber(L, 2, info.spread);
|
||||
lovrRetain(info.rasterizer);
|
||||
}
|
||||
|
||||
Font* font = lovrFontCreate(&info);
|
||||
luax_pushtype(L, Font, font);
|
||||
lovrRelease(info.rasterizer, lovrRasterizerDestroy);
|
||||
lovrRelease(font, lovrFontDestroy);
|
||||
lovrDeferPop(defer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -1365,12 +1416,13 @@ static int l_lovrGraphicsNewModel(lua_State* L) {
|
|||
info.materials = true;
|
||||
info.mipmaps = true;
|
||||
|
||||
uint32_t defer = lovrDeferPush();
|
||||
|
||||
if (!info.data) {
|
||||
Blob* blob = luax_readblob(L, 1, "Model");
|
||||
lovrDeferRelease(blob, lovrBlobDestroy);
|
||||
info.data = lovrModelDataCreate(blob, luax_readfile);
|
||||
lovrRelease(blob, lovrBlobDestroy);
|
||||
} else {
|
||||
lovrRetain(info.data);
|
||||
lovrDeferRelease(info.data, lovrModelDataDestroy);
|
||||
}
|
||||
|
||||
if (lua_istable(L, 2)) {
|
||||
|
@ -1385,8 +1437,8 @@ static int l_lovrGraphicsNewModel(lua_State* L) {
|
|||
|
||||
Model* model = lovrModelCreate(&info);
|
||||
luax_pushtype(L, Model, model);
|
||||
lovrRelease(info.data, lovrModelDataDestroy);
|
||||
lovrRelease(model, lovrModelDestroy);
|
||||
lovrDeferPop(defer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -1420,6 +1472,7 @@ static const luaL_Reg lovrGraphics[] = {
|
|||
{ "getDefaultFont", l_lovrGraphicsGetDefaultFont },
|
||||
{ "newBuffer", l_lovrGraphicsNewBuffer },
|
||||
{ "newTexture", l_lovrGraphicsNewTexture },
|
||||
{ "newTextureView", l_lovrGraphicsNewTextureView },
|
||||
{ "newSampler", l_lovrGraphicsNewSampler },
|
||||
{ "compileShader", l_lovrGraphicsCompileShader },
|
||||
{ "newShader", l_lovrGraphicsNewShader },
|
||||
|
|
|
@ -10,6 +10,7 @@ static const uint32_t typeComponents[] = {
|
|||
[TYPE_U8x4] = 4,
|
||||
[TYPE_SN8x4] = 4,
|
||||
[TYPE_UN8x4] = 4,
|
||||
[TYPE_SN10x3] = 3,
|
||||
[TYPE_UN10x3] = 3,
|
||||
[TYPE_I16] = 1,
|
||||
[TYPE_I16x2] = 2,
|
||||
|
@ -70,7 +71,8 @@ void luax_checkfieldn(lua_State* L, int index, int type, void* data) {
|
|||
case TYPE_U8x4: p.u8[i] = (uint8_t) x; break;
|
||||
case TYPE_SN8x4: p.i8[i] = (int8_t) CLAMP(x, -1.f, 1.f) * INT8_MAX; break;
|
||||
case TYPE_UN8x4: p.u8[i] = (uint8_t) CLAMP(x, 0.f, 1.f) * UINT8_MAX; break;
|
||||
case TYPE_UN10x3: p.u32[0] |= (uint32_t) (CLAMP(x, 0.f, 1.f) * 1023.f) << (10 * (2 - i)); break;
|
||||
case TYPE_SN10x3: p.u32[0] |= (((uint32_t) (int32_t) (CLAMP(x, -1.f, 1.f) * 511.f)) & 0x3ff) << (10 * i); break;
|
||||
case TYPE_UN10x3: p.u32[0] |= (((uint32_t) (CLAMP(x, 0.f, 1.f) * 1023.f)) & 0x3ff) << (10 * i); break;
|
||||
case TYPE_I16: p.i16[i] = (int16_t) x; break;
|
||||
case TYPE_I16x2: p.i16[i] = (int16_t) x; break;
|
||||
case TYPE_I16x4: p.i16[i] = (int16_t) x; break;
|
||||
|
@ -122,7 +124,8 @@ void luax_checkfieldv(lua_State* L, int index, int type, void* data) {
|
|||
case TYPE_U8x4: for (int i = 0; i < 4; i++) p.u8[i] = (uint8_t) v[i]; break;
|
||||
case TYPE_SN8x4: for (int i = 0; i < 4; i++) p.i8[i] = (int8_t) CLAMP(v[i], -1.f, 1.f) * INT8_MAX; break;
|
||||
case TYPE_UN8x4: for (int i = 0; i < 4; i++) p.u8[i] = (uint8_t) CLAMP(v[i], 0.f, 1.f) * UINT8_MAX; break;
|
||||
case TYPE_UN10x3: for (int i = 0; i < 3; i++) p.u32[0] |= (uint32_t) (CLAMP(v[i], 0.f, 1.f) * 1023.f) << (10 * (2 - i)); break;
|
||||
case TYPE_SN10x3: for (int i = 0; i < 3; i++) p.u32[0] |= (((uint32_t) (int32_t) (CLAMP(v[i], -1.f, 1.f) * 511.f)) & 0x3ff) << (10 * i); break;
|
||||
case TYPE_UN10x3: for (int i = 0; i < 3; i++) p.u32[0] |= (((uint32_t) (CLAMP(v[i], 0.f, 1.f) * 1023.f)) & 0x3ff) << (10 * i); break;
|
||||
case TYPE_I16x2: for (int i = 0; i < 2; i++) p.i16[i] = (int16_t) v[i]; break;
|
||||
case TYPE_I16x4: for (int i = 0; i < 4; i++) p.i16[i] = (int16_t) v[i]; break;
|
||||
case TYPE_U16x2: for (int i = 0; i < 2; i++) p.u16[i] = (uint16_t) v[i]; break;
|
||||
|
@ -325,7 +328,8 @@ static int luax_pushcomponents(lua_State* L, DataType type, char* data) {
|
|||
case TYPE_U8x4: for (int i = 0; i < 4; i++) lua_pushinteger(L, p.u8[i]); return 4;
|
||||
case TYPE_SN8x4: for (int i = 0; i < 4; i++) lua_pushnumber(L, MAX((float) p.i8[i] / 127, -1.f)); return 4;
|
||||
case TYPE_UN8x4: for (int i = 0; i < 4; i++) lua_pushnumber(L, (float) p.u8[i] / 255); return 4;
|
||||
case TYPE_UN10x3: for (int i = 0; i < 3; i++) lua_pushnumber(L, (float) ((p.u32[0] >> (10 * (2 - i))) & 0x3ff) / 1023.f); return 3;
|
||||
case TYPE_SN10x3: for (int i = 0; i < 3; i++) lua_pushnumber(L, (float) ((p.i32[0] >> (10 * i)) & 0x3ff) / 511.f); return 3;
|
||||
case TYPE_UN10x3: for (int i = 0; i < 3; i++) lua_pushnumber(L, (float) ((p.u32[0] >> (10 * i)) & 0x3ff) / 1023.f); return 3;
|
||||
case TYPE_I16x2: for (int i = 0; i < 2; i++) lua_pushinteger(L, p.i16[i]); return 2;
|
||||
case TYPE_I16x4: for (int i = 0; i < 4; i++) lua_pushinteger(L, p.i16[i]); return 4;
|
||||
case TYPE_U16x2: for (int i = 0; i < 2; i++) lua_pushinteger(L, p.u16[i]); return 2;
|
||||
|
|
|
@ -7,8 +7,7 @@
|
|||
ColoredString* luax_checkcoloredstrings(lua_State* L, int index, uint32_t* count, ColoredString* stack) {
|
||||
if (lua_istable(L, index)) {
|
||||
*count = luax_len(L, index) / 2;
|
||||
ColoredString* strings = malloc(*count * sizeof(*strings));
|
||||
lovrAssert(strings, "Out of memory");
|
||||
ColoredString* strings = lovrMalloc(*count * sizeof(*strings));
|
||||
for (uint32_t i = 0; i < *count; i++) {
|
||||
lua_rawgeti(L, index, i * 2 + 1);
|
||||
lua_rawgeti(L, index, i * 2 + 2);
|
||||
|
@ -123,7 +122,7 @@ static int l_lovrFontGetLines(lua_State* L) {
|
|||
float wrap = luax_checkfloat(L, 3);
|
||||
lua_newtable(L);
|
||||
lovrFontGetLines(font, strings, 1, wrap, online, L);
|
||||
if (strings != &stack) free(strings);
|
||||
if (strings != &stack) lovrFree(strings);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -139,8 +138,7 @@ static int l_lovrFontGetVertices(lua_State* L) {
|
|||
for (uint32_t i = 0; i < count; i++) {
|
||||
totalLength += strings[i].length;
|
||||
}
|
||||
GlyphVertex* vertices = malloc(totalLength * 4 * sizeof(GlyphVertex));
|
||||
lovrAssert(vertices, "Out of memory");
|
||||
GlyphVertex* vertices = lovrMalloc(totalLength * 4 * sizeof(GlyphVertex));
|
||||
uint32_t glyphCount, lineCount;
|
||||
Material* material;
|
||||
lovrFontGetVertices(font, strings, count, wrap, halign, valign, vertices, &glyphCount, &lineCount, &material, false);
|
||||
|
@ -159,8 +157,8 @@ static int l_lovrFontGetVertices(lua_State* L) {
|
|||
lua_rawseti(L, -2, i + 1);
|
||||
}
|
||||
luax_pushtype(L, Material, material);
|
||||
if (strings != &stack) free(strings);
|
||||
free(vertices);
|
||||
if (strings != &stack) lovrFree(strings);
|
||||
lovrFree(vertices);
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
|
|
@ -340,7 +340,7 @@ static int l_lovrModelGetMeshCount(lua_State* L) {
|
|||
|
||||
static int l_lovrModelGetMesh(lua_State* L) {
|
||||
Model* model = luax_checktype(L, 1, Model);
|
||||
uint32_t index = luax_checku32(L, 3) - 1;
|
||||
uint32_t index = luax_checku32(L, 2) - 1;
|
||||
Mesh* mesh = lovrModelGetMesh(model, index);
|
||||
luax_pushtype(L, Mesh, mesh);
|
||||
return 1;
|
||||
|
|
|
@ -643,15 +643,9 @@ static int l_lovrPassSetWireframe(lua_State* L) {
|
|||
|
||||
static int l_lovrPassSend(lua_State* L) {
|
||||
Pass* pass = luax_checktype(L, 1, Pass);
|
||||
const char* name = NULL;
|
||||
size_t length = 0;
|
||||
uint32_t slot = ~0u;
|
||||
|
||||
switch (lua_type(L, 2)) {
|
||||
case LUA_TSTRING: name = lua_tolstring(L, 2, &length); break;
|
||||
case LUA_TNUMBER: slot = lua_tointeger(L, 2) - 1; break;
|
||||
default: return luax_typeerror(L, 2, "string or number");
|
||||
}
|
||||
size_t length;
|
||||
const char* name = lua_tolstring(L, 2, &length);
|
||||
|
||||
if (lua_isnoneornil(L, 3)) {
|
||||
return luax_typeerror(L, 3, "Buffer, Texture, Sampler, number, vector, table, or boolean");
|
||||
|
@ -662,27 +656,27 @@ static int l_lovrPassSend(lua_State* L) {
|
|||
if (buffer) {
|
||||
uint32_t offset = lua_tointeger(L, 4);
|
||||
uint32_t extent = lua_tointeger(L, 5);
|
||||
lovrPassSendBuffer(pass, name, length, slot, buffer, offset, extent);
|
||||
lovrPassSendBuffer(pass, name, length, buffer, offset, extent);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Texture* texture = luax_totype(L, 3, Texture);
|
||||
|
||||
if (texture) {
|
||||
lovrPassSendTexture(pass, name, length, slot, texture);
|
||||
lovrPassSendTexture(pass, name, length, texture);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Sampler* sampler = luax_totype(L, 3, Sampler);
|
||||
|
||||
if (sampler) {
|
||||
lovrPassSendSampler(pass, name, length, slot, sampler);
|
||||
lovrPassSendSampler(pass, name, length, sampler);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* pointer;
|
||||
DataField* format;
|
||||
lovrPassSendData(pass, name, length, slot, &pointer, &format);
|
||||
lovrPassSendData(pass, name, length, &pointer, &format);
|
||||
char* data = pointer;
|
||||
|
||||
// Coerce booleans since they aren't supported in buffer formats
|
||||
|
@ -869,7 +863,7 @@ static int l_lovrPassSphere(lua_State* L) {
|
|||
int index = luax_readmat4(L, 2, transform, 1);
|
||||
uint32_t segmentsH = luax_optu32(L, index++, 48);
|
||||
uint32_t segmentsV = luax_optu32(L, index++, segmentsH / 2);
|
||||
lovrAssert(segmentsH >= 2 && segmentsV >= 2, "Number of longitudes and latitudes must be >= 2");
|
||||
lovrCheck(segmentsH >= 2 && segmentsV >= 2, "Sphere segment count must be >= 2");
|
||||
lovrPassSphere(pass, transform, segmentsH, segmentsV);
|
||||
return 0;
|
||||
}
|
||||
|
@ -943,13 +937,15 @@ static int l_lovrPassText(lua_State* L) {
|
|||
uint32_t count;
|
||||
ColoredString stack;
|
||||
ColoredString* strings = luax_checkcoloredstrings(L, 2, &count, &stack);
|
||||
uint32_t defer = lovrDeferPush();
|
||||
if (strings != &stack) lovrDefer(lovrFree, strings);
|
||||
float transform[16];
|
||||
int index = luax_readmat4(L, 3, transform, 1);
|
||||
float wrap = luax_optfloat(L, index++, 0.);
|
||||
HorizontalAlign halign = luax_checkenum(L, index++, HorizontalAlign, "center");
|
||||
VerticalAlign valign = luax_checkenum(L, index++, VerticalAlign, "middle");
|
||||
lovrPassText(pass, strings, count, transform, wrap, halign, valign);
|
||||
if (strings != &stack) free(strings);
|
||||
lovrDeferPop(defer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ static int l_lovrShaderClone(lua_State* L) {
|
|||
lua_pushnil(L);
|
||||
|
||||
arr_t(ShaderFlag) flags;
|
||||
arr_init(&flags, realloc);
|
||||
arr_init(&flags);
|
||||
|
||||
while (lua_next(L, 2) != 0) {
|
||||
ShaderFlag flag = { 0 };
|
||||
|
@ -33,6 +33,13 @@ static int l_lovrShaderClone(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrShaderGetType(lua_State* L) {
|
||||
Shader* shader = luax_checktype(L, 1, Shader);
|
||||
const ShaderInfo* info = lovrShaderGetInfo(shader);
|
||||
luax_pushenum(L, ShaderType, info->type);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrShaderHasStage(lua_State* L) {
|
||||
Shader* shader = luax_checktype(L, 1, Shader);
|
||||
ShaderStage stage = luax_checkenum(L, 2, ShaderStage, NULL);
|
||||
|
@ -76,28 +83,34 @@ static int l_lovrShaderGetWorkgroupSize(lua_State* L) {
|
|||
static int l_lovrShaderGetBufferFormat(lua_State* L) {
|
||||
Shader* shader = luax_checktype(L, 1, Shader);
|
||||
const char* name = luaL_checkstring(L, 2);
|
||||
|
||||
uint32_t fieldCount;
|
||||
const DataField* format = lovrShaderGetBufferFormat(shader, name, &fieldCount);
|
||||
lovrCheck(format, "Shader has no Buffer named '%s'", name);
|
||||
|
||||
if (!format) {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
luax_pushbufferformat(L, format->fields, format->fieldCount);
|
||||
lua_pushinteger(L, format->stride);
|
||||
lua_setfield(L, -2, "stride");
|
||||
lua_pushinteger(L, MAX(format->length, 1));
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Deprecated
|
||||
static int l_lovrShaderGetType(lua_State* L) {
|
||||
lua_pushstring(L, lovrShaderHasStage(luax_checktype(L, 1, Shader), STAGE_COMPUTE) ? "compute" : "graphics");
|
||||
return 1;
|
||||
if (format->length == ~0u) {
|
||||
lua_pushnil(L);
|
||||
} else {
|
||||
lua_pushinteger(L, MAX(format->length, 1));
|
||||
}
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
const luaL_Reg lovrShader[] = {
|
||||
{ "clone", l_lovrShaderClone },
|
||||
{ "getType", l_lovrShaderGetType },
|
||||
{ "hasStage", l_lovrShaderHasStage },
|
||||
{ "hasAttribute", l_lovrShaderHasAttribute },
|
||||
{ "getWorkgroupSize", l_lovrShaderGetWorkgroupSize },
|
||||
{ "getBufferFormat", l_lovrShaderGetBufferFormat },
|
||||
{ "getType", l_lovrShaderGetType }, // Deprecated
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
|
|
@ -4,41 +4,6 @@
|
|||
#include "data/image.h"
|
||||
#include <string.h>
|
||||
|
||||
static int l_lovrTextureNewView(lua_State* L) {
|
||||
Texture* texture = luax_checktype(L, 1, Texture);
|
||||
TextureViewInfo info = { .parent = texture };
|
||||
if (lua_type(L, 2) == LUA_TNUMBER) {
|
||||
info.type = TEXTURE_2D;
|
||||
info.layerIndex = luax_checku32(L, 2) - 1;
|
||||
info.layerCount = 1;
|
||||
info.levelIndex = luax_optu32(L, 3, 1) - 1;
|
||||
info.levelCount = 1;
|
||||
} else if (lua_isstring(L, 2)) {
|
||||
info.type = luax_checkenum(L, 2, TextureType, NULL);
|
||||
info.layerIndex = luaL_optinteger(L, 3, 1) - 1;
|
||||
info.layerCount = luaL_optinteger(L, 4, 1);
|
||||
info.levelIndex = luaL_optinteger(L, 5, 1) - 1;
|
||||
info.levelCount = luaL_optinteger(L, 6, 0);
|
||||
}
|
||||
Texture* view = lovrTextureCreateView(&info);
|
||||
luax_pushtype(L, Texture, view);
|
||||
lovrRelease(view, lovrTextureDestroy);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrTextureIsView(lua_State* L) {
|
||||
Texture* texture = luax_checktype(L, 1, Texture);
|
||||
lua_pushboolean(L, !!lovrTextureGetInfo(texture)->parent);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrTextureGetParent(lua_State* L) {
|
||||
Texture* texture = luax_checktype(L, 1, Texture);
|
||||
const TextureInfo* info = lovrTextureGetInfo(texture);
|
||||
luax_pushtype(L, Texture, info->parent);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrTextureGetType(lua_State* L) {
|
||||
Texture* texture = luax_checktype(L, 1, Texture);
|
||||
const TextureInfo* info = lovrTextureGetInfo(texture);
|
||||
|
@ -91,10 +56,8 @@ static int l_lovrTextureGetMipmapCount(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrTextureGetSampleCount(lua_State* L) {
|
||||
Texture* texture = luax_checktype(L, 1, Texture);
|
||||
const TextureInfo* info = lovrTextureGetInfo(texture);
|
||||
lua_pushinteger(L, info->samples);
|
||||
static int l_lovrTextureGetSampleCount(lua_State* L) { // Deprecated
|
||||
lua_pushinteger(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -236,9 +199,6 @@ static int l_lovrTextureGenerateMipmaps(lua_State* L) {
|
|||
}
|
||||
|
||||
const luaL_Reg lovrTexture[] = {
|
||||
{ "newView", l_lovrTextureNewView },
|
||||
{ "isView", l_lovrTextureIsView },
|
||||
{ "getParent", l_lovrTextureGetParent },
|
||||
{ "getType", l_lovrTextureGetType },
|
||||
{ "getFormat", l_lovrTextureGetFormat },
|
||||
{ "getWidth", l_lovrTextureGetWidth },
|
||||
|
@ -246,7 +206,7 @@ const luaL_Reg lovrTexture[] = {
|
|||
{ "getLayerCount", l_lovrTextureGetLayerCount },
|
||||
{ "getDimensions", l_lovrTextureGetDimensions },
|
||||
{ "getMipmapCount", l_lovrTextureGetMipmapCount },
|
||||
{ "getSampleCount", l_lovrTextureGetSampleCount },
|
||||
{ "getSampleCount", l_lovrTextureGetSampleCount }, // Deprecated
|
||||
{ "hasUsage", l_lovrTextureHasUsage },
|
||||
{ "newReadback", l_lovrTextureNewReadback },
|
||||
{ "getPixels", l_lovrTextureGetPixels },
|
||||
|
|
|
@ -572,10 +572,12 @@ static int l_lovrHeadsetNewModel(lua_State* L) {
|
|||
|
||||
if (modelData) {
|
||||
ModelInfo info = { .data = modelData, .mipmaps = true };
|
||||
uint32_t defer = lovrDeferPush();
|
||||
lovrDeferRelease(info.data, lovrModelDataDestroy);
|
||||
Model* model = lovrModelCreate(&info);
|
||||
luax_pushtype(L, Model, model);
|
||||
lovrRelease(modelData, lovrModelDataDestroy);
|
||||
lovrRelease(model, lovrModelDestroy);
|
||||
lovrDeferPop(defer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -784,7 +786,7 @@ int luaopen_lovr_headset(lua_State* L) {
|
|||
for (int i = 0; i < n; i++) {
|
||||
lua_rawgeti(L, -1, i + 1);
|
||||
config.drivers[config.driverCount++] = luax_checkenum(L, -1, HeadsetDriver, NULL);
|
||||
lovrAssert(config.driverCount < COUNTOF(drivers), "Too many headset drivers specified in conf.lua");
|
||||
lovrCheck(config.driverCount < COUNTOF(drivers), "Too many headset drivers specified in conf.lua");
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
|
|
@ -32,13 +32,14 @@ extern const luaL_Reg lovrQuat[];
|
|||
extern const luaL_Reg lovrMat4[];
|
||||
|
||||
static LOVR_THREAD_LOCAL Pool* pool;
|
||||
static LOVR_THREAD_LOCAL int metaref[MAX_VECTOR_TYPES];
|
||||
|
||||
static struct { const char* name; lua_CFunction constructor, indexer; const luaL_Reg* api; int metaref; } lovrVectorInfo[] = {
|
||||
[V_VEC2] = { "vec2", l_lovrMathVec2, l_lovrVec2__metaindex, lovrVec2, LUA_REFNIL },
|
||||
[V_VEC3] = { "vec3", l_lovrMathVec3, l_lovrVec3__metaindex, lovrVec3, LUA_REFNIL },
|
||||
[V_VEC4] = { "vec4", l_lovrMathVec4, l_lovrVec4__metaindex, lovrVec4, LUA_REFNIL },
|
||||
[V_QUAT] = { "quat", l_lovrMathQuat, l_lovrQuat__metaindex, lovrQuat, LUA_REFNIL },
|
||||
[V_MAT4] = { "mat4", l_lovrMathMat4, l_lovrMat4__metaindex, lovrMat4, LUA_REFNIL }
|
||||
static struct { const char* name; lua_CFunction constructor, indexer; const luaL_Reg* api; } lovrVectorInfo[] = {
|
||||
[V_VEC2] = { "vec2", l_lovrMathVec2, l_lovrVec2__metaindex, lovrVec2 },
|
||||
[V_VEC3] = { "vec3", l_lovrMathVec3, l_lovrVec3__metaindex, lovrVec3 },
|
||||
[V_VEC4] = { "vec4", l_lovrMathVec4, l_lovrVec4__metaindex, lovrVec4 },
|
||||
[V_QUAT] = { "quat", l_lovrMathQuat, l_lovrQuat__metaindex, lovrQuat },
|
||||
[V_MAT4] = { "mat4", l_lovrMathMat4, l_lovrMat4__metaindex, lovrMat4 }
|
||||
};
|
||||
|
||||
static void luax_destroypool(void) {
|
||||
|
@ -78,7 +79,7 @@ float* luax_checkvector(lua_State* L, int index, VectorType type, const char* ex
|
|||
static float* luax_newvector(lua_State* L, VectorType type, size_t components) {
|
||||
VectorType* p = lua_newuserdata(L, sizeof(VectorType) + components * sizeof(float));
|
||||
*p = type;
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, lovrVectorInfo[type].metaref);
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, metaref[type]);
|
||||
lua_setmetatable(L, -2);
|
||||
return (float*) (p + 1);
|
||||
}
|
||||
|
@ -110,7 +111,7 @@ static int l_lovrMathNewCurve(lua_State* L) {
|
|||
} else if (top == 1 && lua_type(L, 1) == LUA_TNUMBER) {
|
||||
float point[4] = { 0.f };
|
||||
int count = lua_tonumber(L, 1);
|
||||
lovrAssert(count > 0, "Number of curve points must be positive");
|
||||
lovrCheck(count > 0, "Number of curve points must be positive");
|
||||
for (int i = 0; i < count; i++) {
|
||||
lovrCurveAddPoint(curve, point, i);
|
||||
}
|
||||
|
@ -302,7 +303,7 @@ static int l_lovrLightUserdata__index(lua_State* L) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, lovrVectorInfo[type].metaref);
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, metaref[type]);
|
||||
lua_pushvalue(L, 2);
|
||||
lua_rawget(L, -2);
|
||||
if (lua_isnil(L, -1)) {
|
||||
|
@ -334,7 +335,7 @@ static int l_lovrLightUserdataOp(lua_State* L) {
|
|||
return luaL_error(L, "Unsupported lightuserdata operator %q", lua_tostring(L, lua_upvalueindex(1)));
|
||||
}
|
||||
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, lovrVectorInfo[type].metaref);
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, metaref[type]);
|
||||
lua_pushvalue(L, lua_upvalueindex(1));
|
||||
lua_gettable(L, -2);
|
||||
lua_pushvalue(L, 1);
|
||||
|
@ -369,7 +370,7 @@ int luaopen_lovr_math(lua_State* L) {
|
|||
lua_settable(L, -4);
|
||||
|
||||
luax_register(L, lovrVectorInfo[i].api);
|
||||
lovrVectorInfo[i].metaref = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
metaref[i] = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
}
|
||||
|
||||
// Global lightuserdata metatable
|
||||
|
|
|
@ -64,7 +64,7 @@ static int l_lovrCurveGetPointCount(lua_State* L) {
|
|||
static int l_lovrCurveGetPoint(lua_State* L) {
|
||||
Curve* curve = luax_checktype(L, 1, Curve);
|
||||
size_t index = luaL_checkinteger(L, 2) - 1;
|
||||
lovrAssert(index < lovrCurveGetPointCount(curve), "Invalid Curve point index: %d", index + 1);
|
||||
lovrCheck(index < lovrCurveGetPointCount(curve), "Invalid Curve point index: %d", index + 1);
|
||||
float point[4];
|
||||
lovrCurveGetPoint(curve, index, point);
|
||||
lua_pushnumber(L, point[0]);
|
||||
|
@ -76,7 +76,7 @@ static int l_lovrCurveGetPoint(lua_State* L) {
|
|||
static int l_lovrCurveSetPoint(lua_State* L) {
|
||||
Curve* curve = luax_checktype(L, 1, Curve);
|
||||
size_t index = luaL_checkinteger(L, 2) - 1;
|
||||
lovrAssert(index < lovrCurveGetPointCount(curve), "Invalid Curve point index: %d", index + 1);
|
||||
lovrCheck(index < lovrCurveGetPointCount(curve), "Invalid Curve point index: %d", index + 1);
|
||||
float point[4];
|
||||
luax_readvec3(L, 3, point, NULL);
|
||||
lovrCurveSetPoint(curve, index, point);
|
||||
|
@ -88,7 +88,7 @@ static int l_lovrCurveAddPoint(lua_State* L) {
|
|||
float point[4];
|
||||
int i = luax_readvec3(L, 2, point, NULL);
|
||||
size_t index = lua_isnoneornil(L, i) ? lovrCurveGetPointCount(curve) : (size_t) luaL_checkinteger(L, i) - 1;
|
||||
lovrAssert(index <= lovrCurveGetPointCount(curve), "Invalid Curve point index: %d", index + 1);
|
||||
lovrCheck(index <= lovrCurveGetPointCount(curve), "Invalid Curve point index: %d", index + 1);
|
||||
lovrCurveAddPoint(curve, point, index);
|
||||
return 0;
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ static int l_lovrCurveAddPoint(lua_State* L) {
|
|||
static int l_lovrCurveRemovePoint(lua_State* L) {
|
||||
Curve* curve = luax_checktype(L, 1, Curve);
|
||||
size_t index = luaL_checkinteger(L, 2) - 1;
|
||||
lovrAssert(index < lovrCurveGetPointCount(curve), "Invalid Curve point index: %d", index + 1);
|
||||
lovrCheck(index < lovrCurveGetPointCount(curve), "Invalid Curve point index: %d", index + 1);
|
||||
lovrCurveRemovePoint(curve, index);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -7,8 +7,10 @@ StringEntry lovrShapeType[] = {
|
|||
[SHAPE_BOX] = ENTRY("box"),
|
||||
[SHAPE_CAPSULE] = ENTRY("capsule"),
|
||||
[SHAPE_CYLINDER] = ENTRY("cylinder"),
|
||||
[SHAPE_CONVEX] = ENTRY("convex"),
|
||||
[SHAPE_MESH] = ENTRY("mesh"),
|
||||
[SHAPE_TERRAIN] = ENTRY("terrain"),
|
||||
[SHAPE_COMPOUND] = ENTRY("compound"),
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
|
@ -21,27 +23,75 @@ StringEntry lovrJointType[] = {
|
|||
};
|
||||
|
||||
static int l_lovrPhysicsNewWorld(lua_State* L) {
|
||||
float xg = luax_optfloat(L, 1, 0.f);
|
||||
float yg = luax_optfloat(L, 2, -9.81f);
|
||||
float zg = luax_optfloat(L, 3, 0.f);
|
||||
bool allowSleep = lua_gettop(L) < 4 || lua_toboolean(L, 4);
|
||||
const char* tags[16];
|
||||
int tagCount;
|
||||
if (lua_type(L, 5) == LUA_TTABLE) {
|
||||
tagCount = luax_len(L, 5);
|
||||
for (int i = 0; i < tagCount; i++) {
|
||||
lua_rawgeti(L, -1, i + 1);
|
||||
if (lua_isstring(L, -1)) {
|
||||
tags[i] = lua_tostring(L, -1);
|
||||
} else {
|
||||
return luaL_error(L, "World tags must be a table of strings");
|
||||
WorldInfo info = {
|
||||
.maxColliders = 65536,
|
||||
.maxColliderPairs = 65536,
|
||||
.maxContacts = 16384,
|
||||
.allowSleep = true
|
||||
};
|
||||
|
||||
if (lua_istable(L, 1)) {
|
||||
lua_getfield(L, 1, "maxColliders");
|
||||
if (!lua_isnil(L, -1)) info.maxColliders = luax_checku32(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_getfield(L, 1, "maxColliderPairs");
|
||||
if (!lua_isnil(L, -1)) info.maxColliderPairs = luax_checku32(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_getfield(L, 1, "maxContacts");
|
||||
if (!lua_isnil(L, -1)) info.maxContacts = luax_checku32(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_getfield(L, 1, "allowSleep");
|
||||
if (!lua_isnil(L, -1)) info.allowSleep = lua_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_getfield(L, 1, "tags");
|
||||
if (!lua_isnil(L, -1)) {
|
||||
lovrCheck(lua_istable(L, -1), "World tag list should be a table");
|
||||
lovrCheck(info.tagCount <= MAX_TAGS, "Max number of world tags is %d", MAX_TAGS);
|
||||
info.tagCount = luax_len(L, 5);
|
||||
for (uint32_t i = 0; i < info.tagCount; i++) {
|
||||
lua_rawgeti(L, -1, (int) i + 1);
|
||||
if (lua_isstring(L, -1)) {
|
||||
info.tags[i] = lua_tostring(L, -1);
|
||||
} else {
|
||||
return luaL_error(L, "World tags must be a table of strings");
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
} else {
|
||||
tagCount = 0;
|
||||
lua_pop(L, 1);
|
||||
} else { // Deprecated
|
||||
info.allowSleep = lua_gettop(L) < 4 || lua_toboolean(L, 4);
|
||||
if (lua_type(L, 5) == LUA_TTABLE) {
|
||||
info.tagCount = luax_len(L, 5);
|
||||
lovrCheck(info.tagCount <= MAX_TAGS, "Max number of world tags is %d", MAX_TAGS);
|
||||
for (uint32_t i = 0; i < info.tagCount; i++) {
|
||||
lua_rawgeti(L, -1, (int) i + 1);
|
||||
if (lua_isstring(L, -1)) {
|
||||
info.tags[i] = lua_tostring(L, -1);
|
||||
} else {
|
||||
return luaL_error(L, "World tags must be a table of strings");
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
} else {
|
||||
info.tagCount = 0;
|
||||
}
|
||||
}
|
||||
World* world = lovrWorldCreate(xg, yg, zg, allowSleep, tags, tagCount);
|
||||
|
||||
World* world = lovrWorldCreate(&info);
|
||||
|
||||
if (!lua_istable(L, 1)) {
|
||||
float gravity[3];
|
||||
gravity[0] = luax_optfloat(L, 1, 0.f);
|
||||
gravity[1] = luax_optfloat(L, 2, -9.81f);
|
||||
gravity[2] = luax_optfloat(L, 3, 0.f);
|
||||
lovrWorldSetGravity(world, gravity);
|
||||
}
|
||||
|
||||
luax_pushtype(L, World, world);
|
||||
lovrRelease(world, lovrWorldDestroy);
|
||||
return 1;
|
||||
|
@ -72,6 +122,13 @@ static int l_lovrPhysicsNewCapsuleShape(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrPhysicsNewConvexShape(lua_State* L) {
|
||||
ConvexShape* convex = luax_newconvexshape(L, 1);
|
||||
luax_pushtype(L, ConvexShape, convex);
|
||||
lovrRelease(convex, lovrShapeDestroy);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrPhysicsNewCylinderShape(lua_State* L) {
|
||||
CylinderShape* cylinder = luax_newcylindershape(L, 1);
|
||||
luax_pushtype(L, CylinderShape, cylinder);
|
||||
|
@ -135,11 +192,19 @@ static int l_lovrPhysicsNewTerrainShape(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrPhysicsNewCompoundShape(lua_State* L) {
|
||||
CompoundShape* shape = luax_newcompoundshape(L, 1);
|
||||
luax_pushtype(L, CompoundShape, shape);
|
||||
lovrRelease(shape, lovrShapeDestroy);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const luaL_Reg lovrPhysics[] = {
|
||||
{ "newWorld", l_lovrPhysicsNewWorld },
|
||||
{ "newBallJoint", l_lovrPhysicsNewBallJoint },
|
||||
{ "newBoxShape", l_lovrPhysicsNewBoxShape },
|
||||
{ "newCapsuleShape", l_lovrPhysicsNewCapsuleShape },
|
||||
{ "newConvexShape", l_lovrPhysicsNewConvexShape },
|
||||
{ "newCylinderShape", l_lovrPhysicsNewCylinderShape },
|
||||
{ "newDistanceJoint", l_lovrPhysicsNewDistanceJoint },
|
||||
{ "newHingeJoint", l_lovrPhysicsNewHingeJoint },
|
||||
|
@ -147,6 +212,7 @@ static const luaL_Reg lovrPhysics[] = {
|
|||
{ "newSliderJoint", l_lovrPhysicsNewSliderJoint },
|
||||
{ "newSphereShape", l_lovrPhysicsNewSphereShape },
|
||||
{ "newTerrainShape", l_lovrPhysicsNewTerrainShape },
|
||||
{ "newCompoundShape", l_lovrPhysicsNewCompoundShape },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
|
@ -160,8 +226,10 @@ extern const luaL_Reg lovrSphereShape[];
|
|||
extern const luaL_Reg lovrBoxShape[];
|
||||
extern const luaL_Reg lovrCapsuleShape[];
|
||||
extern const luaL_Reg lovrCylinderShape[];
|
||||
extern const luaL_Reg lovrConvexShape[];
|
||||
extern const luaL_Reg lovrMeshShape[];
|
||||
extern const luaL_Reg lovrTerrainShape[];
|
||||
extern const luaL_Reg lovrCompoundShape[];
|
||||
|
||||
int luaopen_lovr_physics(lua_State* L) {
|
||||
lua_newtable(L);
|
||||
|
@ -176,8 +244,10 @@ int luaopen_lovr_physics(lua_State* L) {
|
|||
luax_registertype(L, BoxShape);
|
||||
luax_registertype(L, CapsuleShape);
|
||||
luax_registertype(L, CylinderShape);
|
||||
luax_registertype(L, ConvexShape);
|
||||
luax_registertype(L, MeshShape);
|
||||
luax_registertype(L, TerrainShape);
|
||||
luax_registertype(L, CompoundShape);
|
||||
lovrPhysicsInit();
|
||||
luax_atexit(L, lovrPhysicsDestroy);
|
||||
return 1;
|
||||
|
|
|
@ -17,6 +17,20 @@ static int l_lovrColliderIsDestroyed(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrColliderIsEnabled(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
bool enabled = lovrColliderIsEnabled(collider);
|
||||
lua_pushboolean(L, enabled);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrColliderSetEnabled(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
bool enable = lua_toboolean(L, 2);
|
||||
lovrColliderSetEnabled(collider, enable);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrColliderGetWorld(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
World* world = lovrColliderGetWorld(collider);
|
||||
|
@ -24,65 +38,94 @@ static int l_lovrColliderGetWorld(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrColliderAddShape(lua_State* L) {
|
||||
static int l_lovrColliderGetShape(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
Shape* shape = luax_checkshape(L, 2);
|
||||
lovrColliderAddShape(collider, shape);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrColliderRemoveShape(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
Shape* shape = luax_checkshape(L, 2);
|
||||
lovrColliderRemoveShape(collider, shape);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrColliderGetShapes(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
size_t count;
|
||||
Shape** shapes = lovrColliderGetShapes(collider, &count);
|
||||
lua_createtable(L, (int) count, 0);
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
luax_pushshape(L, shapes[i]);
|
||||
lua_rawseti(L, -2, (int) i + 1);
|
||||
uint32_t child = lua_gettop(L) == 1 ? ~0u : luax_checku32(L, 2) - 1;
|
||||
Shape* shape = lovrColliderGetShape(collider, child);
|
||||
if (shape) {
|
||||
luax_pushshape(L, shape);
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrColliderSetShape(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
Shape* shape = lua_isnoneornil(L, 2) ? NULL : luax_checkshape(L, 2);
|
||||
lovrColliderSetShape(collider, shape);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrColliderGetShapeOffset(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
float position[3], orientation[4], angle, ax, ay, az;
|
||||
lovrColliderGetShapeOffset(collider, position, orientation);
|
||||
quat_getAngleAxis(orientation, &angle, &ax, &ay, &az);
|
||||
lua_pushnumber(L, position[0]);
|
||||
lua_pushnumber(L, position[1]);
|
||||
lua_pushnumber(L, position[2]);
|
||||
lua_pushnumber(L, angle);
|
||||
lua_pushnumber(L, ax);
|
||||
lua_pushnumber(L, ay);
|
||||
lua_pushnumber(L, az);
|
||||
return 7;
|
||||
}
|
||||
|
||||
static int l_lovrColliderSetShapeOffset(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
int index = 2;
|
||||
float position[3], orientation[4];
|
||||
index = luax_readvec3(L, index, position, NULL);
|
||||
index = luax_readquat(L, index, orientation, NULL);
|
||||
lovrColliderSetShapeOffset(collider, position, orientation);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrColliderGetJoints(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
size_t count;
|
||||
Joint** joints = lovrColliderGetJoints(collider, &count);
|
||||
lua_createtable(L, (int) count, 0);
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
luax_pushjoint(L, joints[i]);
|
||||
lua_rawseti(L, -2, (int) i + 1);
|
||||
lua_newtable(L);
|
||||
int index = 1;
|
||||
Joint* joint = NULL;
|
||||
while ((joint = lovrColliderGetJoints(collider, joint)) != NULL) {
|
||||
luax_pushjoint(L, joint);
|
||||
lua_rawseti(L, -2, index++);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void luax_pushcolliderstash(lua_State* L) {
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, "_lovrcolliderstash");
|
||||
|
||||
if (lua_isnil(L, -1)) {
|
||||
lua_newtable(L);
|
||||
lua_replace(L, -2);
|
||||
|
||||
// metatable
|
||||
lua_newtable(L);
|
||||
lua_pushliteral(L, "k");
|
||||
lua_setfield(L, -2, "__mode");
|
||||
lua_setmetatable(L, -2);
|
||||
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, LUA_REGISTRYINDEX, "_lovrcolliderstash");
|
||||
}
|
||||
}
|
||||
|
||||
static int l_lovrColliderGetUserData(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
union { int i; void* p; } ref = { .p = lovrColliderGetUserData(collider) };
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, ref.i);
|
||||
luax_checktype(L, 1, Collider);
|
||||
luax_pushcolliderstash(L);
|
||||
lua_pushvalue(L, 1);
|
||||
lua_rawget(L, -2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrColliderSetUserData(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
union { int i; void* p; } ref = { .p = lovrColliderGetUserData(collider) };
|
||||
if (ref.i) {
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, ref.i);
|
||||
}
|
||||
|
||||
if (lua_gettop(L) < 2) {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
|
||||
lua_settop(L, 2);
|
||||
ref.i = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
lovrColliderSetUserData(collider, ref.p);
|
||||
luax_checktype(L, 1, Collider);
|
||||
luax_pushcolliderstash(L);
|
||||
lua_pushvalue(L, 1);
|
||||
lua_pushvalue(L, 2);
|
||||
lua_rawset(L, -3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -99,16 +142,44 @@ static int l_lovrColliderSetKinematic(lua_State* L) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrColliderIsGravityIgnored(lua_State* L) {
|
||||
static int l_lovrColliderIsSensor(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
lua_pushboolean(L, lovrColliderIsGravityIgnored(collider));
|
||||
lua_pushboolean(L, lovrColliderIsSensor(collider));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrColliderSetGravityIgnored(lua_State* L) {
|
||||
static int l_lovrColliderSetSensor(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
bool ignored = lua_toboolean(L, 2);
|
||||
lovrColliderSetGravityIgnored(collider, ignored);
|
||||
bool sensor = lua_toboolean(L, 2);
|
||||
lovrColliderSetSensor(collider, sensor);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrColliderIsContinuous(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
bool continuous = lovrColliderIsContinuous(collider);
|
||||
lua_pushboolean(L, continuous);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrColliderSetContinuous(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
bool continuous = lua_toboolean(L, 2);
|
||||
lovrColliderSetContinuous(collider, continuous);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrColliderGetGravityScale(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
float scale = lovrColliderGetGravityScale(collider);
|
||||
lua_pushnumber(L, scale);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrColliderSetGravityScale(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
float scale = luax_checkfloat(L, 2);
|
||||
lovrColliderSetGravityScale(collider, scale);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -153,12 +224,11 @@ static int l_lovrColliderSetMass(lua_State* L) {
|
|||
|
||||
static int l_lovrColliderGetMassData(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
float cx, cy, cz, mass;
|
||||
float inertia[6];
|
||||
lovrColliderGetMassData(collider, &cx, &cy, &cz, &mass, inertia);
|
||||
lua_pushnumber(L, cx);
|
||||
lua_pushnumber(L, cy);
|
||||
lua_pushnumber(L, cz);
|
||||
float centerOfMass[3], mass, inertia[6];
|
||||
lovrColliderGetMassData(collider, centerOfMass, &mass, inertia);
|
||||
lua_pushnumber(L, centerOfMass[0]);
|
||||
lua_pushnumber(L, centerOfMass[1]);
|
||||
lua_pushnumber(L, centerOfMass[2]);
|
||||
lua_pushnumber(L, mass);
|
||||
lua_newtable(L);
|
||||
for (int i = 0; i < 6; i++) {
|
||||
|
@ -170,14 +240,13 @@ static int l_lovrColliderGetMassData(lua_State* L) {
|
|||
|
||||
static int l_lovrColliderSetMassData(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
float cx = luax_checkfloat(L, 2);
|
||||
float cy = luax_checkfloat(L, 3);
|
||||
float cz = luax_checkfloat(L, 4);
|
||||
float mass = luax_checkfloat(L, 5);
|
||||
float centerOfMass[3];
|
||||
int index = luax_readvec3(L, 2, centerOfMass, NULL);
|
||||
float mass = luax_checkfloat(L, index++);
|
||||
float inertia[6];
|
||||
if (lua_istable(L, 6) && luax_len(L, 6) >= 6) {
|
||||
if (lua_istable(L, index) && luax_len(L, index) >= 6) {
|
||||
for (int i = 0; i < 6; i++) {
|
||||
lua_rawgeti(L, 6, i + 1);
|
||||
lua_rawgeti(L, index, i + 1);
|
||||
if (!lua_isnumber(L, -1)) {
|
||||
return luaL_argerror(L, 6, "Expected 6 numbers or a table with 6 numbers");
|
||||
}
|
||||
|
@ -186,25 +255,25 @@ static int l_lovrColliderSetMassData(lua_State* L) {
|
|||
lua_pop(L, 1);
|
||||
}
|
||||
} else {
|
||||
for (int i = 6; i < 12; i++) {
|
||||
for (int i = index; i < index + 6; i++) {
|
||||
if (lua_isnumber(L, i)) {
|
||||
inertia[i - 6] = lua_tonumber(L, i);
|
||||
inertia[i - index] = lua_tonumber(L, i);
|
||||
} else {
|
||||
return luaL_argerror(L, i, "Expected 6 numbers or a table with 6 numbers");
|
||||
}
|
||||
}
|
||||
}
|
||||
lovrColliderSetMassData(collider, cx, cy, cz, mass, inertia);
|
||||
lovrColliderSetMassData(collider, centerOfMass, mass, inertia);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrColliderGetPosition(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
float x, y, z;
|
||||
lovrColliderGetPosition(collider, &x, &y, &z);
|
||||
lua_pushnumber(L, x);
|
||||
lua_pushnumber(L, y);
|
||||
lua_pushnumber(L, z);
|
||||
float position[3];
|
||||
lovrColliderGetPosition(collider, position);
|
||||
lua_pushnumber(L, position[0]);
|
||||
lua_pushnumber(L, position[1]);
|
||||
lua_pushnumber(L, position[2]);
|
||||
return 3;
|
||||
}
|
||||
|
||||
|
@ -212,13 +281,13 @@ static int l_lovrColliderSetPosition(lua_State* L) {
|
|||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
float position[3];
|
||||
luax_readvec3(L, 2, position, NULL);
|
||||
lovrColliderSetPosition(collider, position[0], position[1], position[2]);
|
||||
lovrColliderSetPosition(collider, position);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrColliderGetOrientation(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
float angle, x, y, z, orientation[4];
|
||||
float orientation[4], angle, x, y, z;
|
||||
lovrColliderGetOrientation(collider, orientation);
|
||||
quat_getAngleAxis(orientation, &angle, &x, &y, &z);
|
||||
lua_pushnumber(L, angle);
|
||||
|
@ -238,13 +307,13 @@ static int l_lovrColliderSetOrientation(lua_State* L) {
|
|||
|
||||
static int l_lovrColliderGetPose(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
float x, y, z, angle, ax, ay, az, orientation[4];
|
||||
lovrColliderGetPosition(collider, &x, &y, &z);
|
||||
float position[3], orientation[4], angle, ax, ay, az;
|
||||
lovrColliderGetPosition(collider, position);
|
||||
lovrColliderGetOrientation(collider, orientation);
|
||||
quat_getAngleAxis(orientation, &angle, &ax, &ay, &az);
|
||||
lua_pushnumber(L, x);
|
||||
lua_pushnumber(L, y);
|
||||
lua_pushnumber(L, z);
|
||||
lua_pushnumber(L, position[0]);
|
||||
lua_pushnumber(L, position[1]);
|
||||
lua_pushnumber(L, position[2]);
|
||||
lua_pushnumber(L, angle);
|
||||
lua_pushnumber(L, ax);
|
||||
lua_pushnumber(L, ay);
|
||||
|
@ -257,18 +326,18 @@ static int l_lovrColliderSetPose(lua_State* L) {
|
|||
float position[3], orientation[4];
|
||||
int index = luax_readvec3(L, 2, position, NULL);
|
||||
luax_readquat(L, index, orientation, NULL);
|
||||
lovrColliderSetPosition(collider, position[0], position[1], position[2]);
|
||||
lovrColliderSetPosition(collider, position);
|
||||
lovrColliderSetOrientation(collider, orientation);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrColliderGetLinearVelocity(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
float x, y, z;
|
||||
lovrColliderGetLinearVelocity(collider, &x, &y, &z);
|
||||
lua_pushnumber(L, x);
|
||||
lua_pushnumber(L, y);
|
||||
lua_pushnumber(L, z);
|
||||
float velocity[3];
|
||||
lovrColliderGetLinearVelocity(collider, velocity);
|
||||
lua_pushnumber(L, velocity[0]);
|
||||
lua_pushnumber(L, velocity[1]);
|
||||
lua_pushnumber(L, velocity[2]);
|
||||
return 3;
|
||||
}
|
||||
|
||||
|
@ -276,17 +345,17 @@ static int l_lovrColliderSetLinearVelocity(lua_State* L) {
|
|||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
float velocity[3];
|
||||
luax_readvec3(L, 2, velocity, NULL);
|
||||
lovrColliderSetLinearVelocity(collider, velocity[0], velocity[1], velocity[2]);
|
||||
lovrColliderSetLinearVelocity(collider, velocity);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrColliderGetAngularVelocity(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
float x, y, z;
|
||||
lovrColliderGetAngularVelocity(collider, &x, &y, &z);
|
||||
lua_pushnumber(L, x);
|
||||
lua_pushnumber(L, y);
|
||||
lua_pushnumber(L, z);
|
||||
float velocity[3];
|
||||
lovrColliderGetAngularVelocity(collider, velocity);
|
||||
lua_pushnumber(L, velocity[0]);
|
||||
lua_pushnumber(L, velocity[1]);
|
||||
lua_pushnumber(L, velocity[2]);
|
||||
return 3;
|
||||
}
|
||||
|
||||
|
@ -294,7 +363,7 @@ static int l_lovrColliderSetAngularVelocity(lua_State* L) {
|
|||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
float velocity[3];
|
||||
luax_readvec3(L, 2, velocity, NULL);
|
||||
lovrColliderSetAngularVelocity(collider, velocity[0], velocity[1], velocity[2]);
|
||||
lovrColliderSetAngularVelocity(collider, velocity);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -340,10 +409,9 @@ static int l_lovrColliderApplyForce(lua_State* L) {
|
|||
if (lua_gettop(L) >= index) {
|
||||
float position[3];
|
||||
luax_readvec3(L, index, position, NULL);
|
||||
lovrColliderApplyForceAtPosition(collider, force[0], force[1], force[2],
|
||||
position[0], position[1], position[2]);
|
||||
lovrColliderApplyForceAtPosition(collider, force, position);
|
||||
} else {
|
||||
lovrColliderApplyForce(collider, force[0], force[1], force[2]);
|
||||
lovrColliderApplyForce(collider, force);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -351,91 +419,107 @@ static int l_lovrColliderApplyForce(lua_State* L) {
|
|||
|
||||
static int l_lovrColliderApplyTorque(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
float force[3];
|
||||
luax_readvec3(L, 2, force, NULL);
|
||||
lovrColliderApplyTorque(collider, force[0], force[1], force[2]);
|
||||
float torque[3];
|
||||
luax_readvec3(L, 2, torque, NULL);
|
||||
lovrColliderApplyTorque(collider, torque);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrColliderApplyLinearImpulse(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
float impulse[3];
|
||||
int index = luax_readvec3(L, 2, impulse, NULL);
|
||||
if (lua_gettop(L) >= index) {
|
||||
float position[3];
|
||||
luax_readvec3(L, index, position, NULL);
|
||||
lovrColliderApplyLinearImpulseAtPosition(collider, impulse, position);
|
||||
} else {
|
||||
lovrColliderApplyLinearImpulse(collider, impulse);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrColliderApplyAngularImpulse(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
float impulse[3];
|
||||
luax_readvec3(L, 2, impulse, NULL);
|
||||
lovrColliderApplyAngularImpulse(collider, impulse);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrColliderGetLocalCenter(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
float x, y, z;
|
||||
lovrColliderGetLocalCenter(collider, &x, &y, &z);
|
||||
lua_pushnumber(L, x);
|
||||
lua_pushnumber(L, y);
|
||||
lua_pushnumber(L, z);
|
||||
float center[3];
|
||||
lovrColliderGetLocalCenter(collider, center);
|
||||
lua_pushnumber(L, center[0]);
|
||||
lua_pushnumber(L, center[1]);
|
||||
lua_pushnumber(L, center[2]);
|
||||
return 3;
|
||||
}
|
||||
|
||||
static int l_lovrColliderGetLocalPoint(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
float world[3];
|
||||
float world[3], local[3];
|
||||
luax_readvec3(L, 2, world, NULL);
|
||||
float x, y, z;
|
||||
lovrColliderGetLocalPoint(collider, world[0], world[1], world[2], &x, &y, &z);
|
||||
lua_pushnumber(L, x);
|
||||
lua_pushnumber(L, y);
|
||||
lua_pushnumber(L, z);
|
||||
lovrColliderGetLocalPoint(collider, world, local);
|
||||
lua_pushnumber(L, local[0]);
|
||||
lua_pushnumber(L, local[1]);
|
||||
lua_pushnumber(L, local[2]);
|
||||
return 3;
|
||||
}
|
||||
|
||||
static int l_lovrColliderGetWorldPoint(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
float local[3];
|
||||
float local[3], world[3];
|
||||
luax_readvec3(L, 2, local, NULL);
|
||||
float wx, wy, wz;
|
||||
lovrColliderGetWorldPoint(collider, local[0], local[1], local[2], &wx, &wy, &wz);
|
||||
lua_pushnumber(L, wx);
|
||||
lua_pushnumber(L, wy);
|
||||
lua_pushnumber(L, wz);
|
||||
lovrColliderGetWorldPoint(collider, local, world);
|
||||
lua_pushnumber(L, world[0]);
|
||||
lua_pushnumber(L, world[1]);
|
||||
lua_pushnumber(L, world[2]);
|
||||
return 3;
|
||||
}
|
||||
|
||||
static int l_lovrColliderGetLocalVector(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
float world[3];
|
||||
float world[3], local[3];
|
||||
luax_readvec3(L, 2, world, NULL);
|
||||
float x, y, z;
|
||||
lovrColliderGetLocalVector(collider, world[0], world[1], world[2], &x, &y, &z);
|
||||
lua_pushnumber(L, x);
|
||||
lua_pushnumber(L, y);
|
||||
lua_pushnumber(L, z);
|
||||
lovrColliderGetLocalVector(collider, world, local);
|
||||
lua_pushnumber(L, local[0]);
|
||||
lua_pushnumber(L, local[1]);
|
||||
lua_pushnumber(L, local[2]);
|
||||
return 3;
|
||||
}
|
||||
|
||||
static int l_lovrColliderGetWorldVector(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
float local[3];
|
||||
float local[3], world[3];
|
||||
luax_readvec3(L, 2, local, NULL);
|
||||
float wx, wy, wz;
|
||||
lovrColliderGetWorldVector(collider, local[0], local[1], local[2], &wx, &wy, &wz);
|
||||
lua_pushnumber(L, wx);
|
||||
lua_pushnumber(L, wy);
|
||||
lua_pushnumber(L, wz);
|
||||
lovrColliderGetWorldVector(collider, local, world);
|
||||
lua_pushnumber(L, world[0]);
|
||||
lua_pushnumber(L, world[1]);
|
||||
lua_pushnumber(L, world[2]);
|
||||
return 3;
|
||||
}
|
||||
|
||||
static int l_lovrColliderGetLinearVelocityFromLocalPoint(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
float local[3];
|
||||
luax_readvec3(L, 2, local, NULL);
|
||||
float vx, vy, vz;
|
||||
lovrColliderGetLinearVelocityFromLocalPoint(collider, local[0], local[1], local[2], &vx, &vy, &vz);
|
||||
lua_pushnumber(L, vx);
|
||||
lua_pushnumber(L, vy);
|
||||
lua_pushnumber(L, vz);
|
||||
float point[3], velocity[3];
|
||||
luax_readvec3(L, 2, point, NULL);
|
||||
lovrColliderGetLinearVelocityFromLocalPoint(collider, point, velocity);
|
||||
lua_pushnumber(L, velocity[0]);
|
||||
lua_pushnumber(L, velocity[1]);
|
||||
lua_pushnumber(L, velocity[2]);
|
||||
return 3;
|
||||
}
|
||||
|
||||
static int l_lovrColliderGetLinearVelocityFromWorldPoint(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
float world[3];
|
||||
luax_readvec3(L, 2, world, NULL);
|
||||
float vx, vy, vz;
|
||||
lovrColliderGetLinearVelocityFromWorldPoint(collider, world[0], world[1], world[2], &vx, &vy, &vz);
|
||||
lua_pushnumber(L, vx);
|
||||
lua_pushnumber(L, vy);
|
||||
lua_pushnumber(L, vz);
|
||||
float point[3], velocity[3];
|
||||
luax_readvec3(L, 2, point, NULL);
|
||||
lovrColliderGetLinearVelocityFromWorldPoint(collider, point, velocity);
|
||||
lua_pushnumber(L, velocity[0]);
|
||||
lua_pushnumber(L, velocity[1]);
|
||||
lua_pushnumber(L, velocity[2]);
|
||||
return 3;
|
||||
}
|
||||
|
||||
|
@ -496,20 +580,52 @@ static int l_lovrColliderSetTag(lua_State* L) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Deprecated
|
||||
static int l_lovrColliderGetShapes(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
Shape* shape = lovrColliderGetShape(collider, ~0u);
|
||||
lua_createtable(L, 1, 0);
|
||||
luax_pushshape(L, shape);
|
||||
lua_rawseti(L, -2, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Deprecated
|
||||
static int l_lovrColliderIsGravityIgnored(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
lua_pushboolean(L, lovrColliderGetGravityScale(collider) == 0.f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Deprecated
|
||||
static int l_lovrColliderSetGravityIgnored(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
bool ignored = lua_toboolean(L, 2);
|
||||
lovrColliderSetGravityScale(collider, ignored ? 0.f : 1.f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const luaL_Reg lovrCollider[] = {
|
||||
{ "destroy", l_lovrColliderDestroy },
|
||||
{ "isDestroyed", l_lovrColliderIsDestroyed },
|
||||
{ "isEnabled", l_lovrColliderIsEnabled },
|
||||
{ "setEnabled", l_lovrColliderSetEnabled },
|
||||
{ "getWorld", l_lovrColliderGetWorld },
|
||||
{ "addShape", l_lovrColliderAddShape },
|
||||
{ "removeShape", l_lovrColliderRemoveShape },
|
||||
{ "getShapes", l_lovrColliderGetShapes },
|
||||
{ "getShape", l_lovrColliderGetShape },
|
||||
{ "setShape", l_lovrColliderSetShape },
|
||||
{ "getShapeOffset", l_lovrColliderGetShapeOffset },
|
||||
{ "setShapeOffset", l_lovrColliderSetShapeOffset },
|
||||
{ "getJoints", l_lovrColliderGetJoints },
|
||||
{ "getUserData", l_lovrColliderGetUserData },
|
||||
{ "setUserData", l_lovrColliderSetUserData },
|
||||
{ "isKinematic", l_lovrColliderIsKinematic },
|
||||
{ "setKinematic", l_lovrColliderSetKinematic },
|
||||
{ "isGravityIgnored", l_lovrColliderIsGravityIgnored },
|
||||
{ "setGravityIgnored", l_lovrColliderSetGravityIgnored },
|
||||
{ "isSensor", l_lovrColliderIsSensor },
|
||||
{ "setSensor", l_lovrColliderSetSensor },
|
||||
{ "isContinuous", l_lovrColliderIsContinuous },
|
||||
{ "setContinuous", l_lovrColliderSetContinuous },
|
||||
{ "getGravityScale", l_lovrColliderGetGravityScale },
|
||||
{ "setGravityScale", l_lovrColliderSetGravityScale },
|
||||
{ "isSleepingAllowed", l_lovrColliderIsSleepingAllowed },
|
||||
{ "setSleepingAllowed", l_lovrColliderSetSleepingAllowed },
|
||||
{ "isAwake", l_lovrColliderIsAwake },
|
||||
|
@ -534,6 +650,8 @@ const luaL_Reg lovrCollider[] = {
|
|||
{ "setAngularDamping", l_lovrColliderSetAngularDamping },
|
||||
{ "applyForce", l_lovrColliderApplyForce },
|
||||
{ "applyTorque", l_lovrColliderApplyTorque },
|
||||
{ "applyLinearImpulse", l_lovrColliderApplyLinearImpulse },
|
||||
{ "applyAngularImpulse", l_lovrColliderApplyAngularImpulse },
|
||||
{ "getLocalCenter", l_lovrColliderGetLocalCenter },
|
||||
{ "getLocalPoint", l_lovrColliderGetLocalPoint },
|
||||
{ "getWorldPoint", l_lovrColliderGetWorldPoint },
|
||||
|
@ -548,5 +666,11 @@ const luaL_Reg lovrCollider[] = {
|
|||
{ "setRestitution", l_lovrColliderSetRestitution },
|
||||
{ "getTag", l_lovrColliderGetTag },
|
||||
{ "setTag", l_lovrColliderSetTag },
|
||||
|
||||
// Deprecated
|
||||
{ "getShapes", l_lovrColliderGetShapes },
|
||||
{ "isGravityIgnored", l_lovrColliderIsGravityIgnored },
|
||||
{ "setGravityIgnored", l_lovrColliderSetGravityIgnored },
|
||||
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
|
|
@ -41,6 +41,13 @@ static int l_lovrJointDestroy(lua_State* L) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrJointIsDestroyed(lua_State* L) {
|
||||
Joint* joint = luax_checkjoint(L, 1);
|
||||
bool destroyed = lovrJointIsDestroyed(joint);
|
||||
lua_pushboolean(L, destroyed);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrJointGetType(lua_State* L) {
|
||||
Joint* joint = luax_checkjoint(L, 1);
|
||||
luax_pushenum(L, JointType, lovrJointGetType(joint));
|
||||
|
@ -49,35 +56,45 @@ static int l_lovrJointGetType(lua_State* L) {
|
|||
|
||||
static int l_lovrJointGetColliders(lua_State* L) {
|
||||
Joint* joint = luax_checkjoint(L, 1);
|
||||
Collider* a;
|
||||
Collider* b;
|
||||
lovrJointGetColliders(joint, &a, &b);
|
||||
Collider* a = lovrJointGetColliderA(joint);
|
||||
Collider* b = lovrJointGetColliderB(joint);
|
||||
luax_pushtype(L, Collider, a);
|
||||
luax_pushtype(L, Collider, b);
|
||||
return 2;
|
||||
}
|
||||
|
||||
static void luax_pushjointstash(lua_State* L) {
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, "_lovrjointstash");
|
||||
|
||||
if (lua_isnil(L, -1)) {
|
||||
lua_newtable(L);
|
||||
lua_replace(L, -2);
|
||||
|
||||
// metatable
|
||||
lua_newtable(L);
|
||||
lua_pushliteral(L, "k");
|
||||
lua_setfield(L, -2, "__mode");
|
||||
lua_setmetatable(L, -2);
|
||||
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, LUA_REGISTRYINDEX, "_lovrjointstash");
|
||||
}
|
||||
}
|
||||
|
||||
static int l_lovrJointGetUserData(lua_State* L) {
|
||||
Joint* joint = luax_checkjoint(L, 1);
|
||||
union { int i; void* p; } ref = { .p = lovrJointGetUserData(joint) };
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, ref.i);
|
||||
luax_checktype(L, 1, Joint);
|
||||
luax_pushjointstash(L);
|
||||
lua_pushvalue(L, 1);
|
||||
lua_rawget(L, -2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrJointSetUserData(lua_State* L) {
|
||||
Joint* joint = luax_checkjoint(L, 1);
|
||||
union { int i; void* p; } ref = { .p = lovrJointGetUserData(joint) };
|
||||
if (ref.i) {
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, ref.i);
|
||||
}
|
||||
|
||||
if (lua_gettop(L) < 2) {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
|
||||
lua_settop(L, 2);
|
||||
ref.i = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
lovrJointSetUserData(joint, ref.p);
|
||||
luax_checktype(L, 1, Joint);
|
||||
luax_pushjointstash(L);
|
||||
lua_pushvalue(L, 1);
|
||||
lua_pushvalue(L, 2);
|
||||
lua_rawset(L, -3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -96,6 +113,7 @@ static int l_lovrJointSetEnabled(lua_State* L) {
|
|||
|
||||
#define lovrJoint \
|
||||
{ "destroy", l_lovrJointDestroy }, \
|
||||
{ "isDestroyed", l_lovrJointIsDestroyed }, \
|
||||
{ "getType", l_lovrJointGetType }, \
|
||||
{ "getColliders", l_lovrJointGetColliders }, \
|
||||
{ "getUserData", l_lovrJointGetUserData }, \
|
||||
|
@ -134,7 +152,7 @@ static int l_lovrBallJointGetResponseTime(lua_State* L) {
|
|||
static int l_lovrBallJointSetResponseTime(lua_State* L) {
|
||||
Joint* joint = luax_checkjoint(L, 1);
|
||||
float responseTime = luax_checkfloat(L, 2);
|
||||
lovrAssert(responseTime >= 0, "Negative response time causes simulation instability");
|
||||
lovrCheck(responseTime >= 0, "Negative response time causes simulation instability");
|
||||
lovrBallJointSetResponseTime(joint, responseTime);
|
||||
return 0;
|
||||
}
|
||||
|
@ -149,7 +167,7 @@ static int l_lovrBallJointGetTightness(lua_State* L) {
|
|||
static int l_lovrBallJointSetTightness(lua_State* L) {
|
||||
Joint* joint = luax_checkjoint(L, 1);
|
||||
float tightness = luax_checkfloat(L, 2);
|
||||
lovrAssert(tightness >= 0, "Negative tightness factor causes simulation instability");
|
||||
lovrCheck(tightness >= 0, "Negative tightness factor causes simulation instability");
|
||||
lovrBallJointSetTightness(joint, tightness);
|
||||
return 0;
|
||||
}
|
||||
|
@ -210,7 +228,7 @@ static int l_lovrDistanceJointGetResponseTime(lua_State* L) {
|
|||
static int l_lovrDistanceJointSetResponseTime(lua_State* L) {
|
||||
Joint* joint = luax_checkjoint(L, 1);
|
||||
float responseTime = luax_checkfloat(L, 2);
|
||||
lovrAssert(responseTime >= 0, "Negative response time causes simulation instability");
|
||||
lovrCheck(responseTime >= 0, "Negative response time causes simulation instability");
|
||||
lovrDistanceJointSetResponseTime(joint, responseTime);
|
||||
return 0;
|
||||
}
|
||||
|
@ -225,7 +243,7 @@ static int l_lovrDistanceJointGetTightness(lua_State* L) {
|
|||
static int l_lovrDistanceJointSetTightness(lua_State* L) {
|
||||
Joint* joint = luax_checkjoint(L, 1);
|
||||
float tightness = luax_checkfloat(L, 2);
|
||||
lovrAssert(tightness >= 0, "Negative tightness factor causes simulation instability");
|
||||
lovrCheck(tightness >= 0, "Negative tightness factor causes simulation instability");
|
||||
lovrDistanceJointSetTightness(joint, tightness);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -12,8 +12,10 @@ void luax_pushshape(lua_State* L, Shape* shape) {
|
|||
case SHAPE_BOX: luax_pushtype(L, BoxShape, shape); break;
|
||||
case SHAPE_CAPSULE: luax_pushtype(L, CapsuleShape, shape); break;
|
||||
case SHAPE_CYLINDER: luax_pushtype(L, CylinderShape, shape); break;
|
||||
case SHAPE_CONVEX: luax_pushtype(L, ConvexShape, shape); break;
|
||||
case SHAPE_MESH: luax_pushtype(L, MeshShape, shape); break;
|
||||
case SHAPE_TERRAIN: luax_pushtype(L, TerrainShape, shape); break;
|
||||
case SHAPE_COMPOUND: luax_pushtype(L, CompoundShape, shape); break;
|
||||
default: lovrUnreachable();
|
||||
}
|
||||
}
|
||||
|
@ -27,8 +29,10 @@ Shape* luax_checkshape(lua_State* L, int index) {
|
|||
hash64("BoxShape", strlen("BoxShape")),
|
||||
hash64("CapsuleShape", strlen("CapsuleShape")),
|
||||
hash64("CylinderShape", strlen("CylinderShape")),
|
||||
hash64("ConvexShape", strlen("ConvexShape")),
|
||||
hash64("MeshShape", strlen("MeshShape")),
|
||||
hash64("TerrainShape", strlen("TerrainShape"))
|
||||
hash64("TerrainShape", strlen("TerrainShape")),
|
||||
hash64("CompoundShape", strlen("CompoundShape"))
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < COUNTOF(hashes); i++) {
|
||||
|
@ -50,7 +54,7 @@ Shape* luax_newsphereshape(lua_State* L, int index) {
|
|||
Shape* luax_newboxshape(lua_State* L, int index) {
|
||||
float size[3];
|
||||
luax_readscale(L, index, size, 3, NULL);
|
||||
return lovrBoxShapeCreate(size[0], size[1], size[2]);
|
||||
return lovrBoxShapeCreate(size);
|
||||
}
|
||||
|
||||
Shape* luax_newcapsuleshape(lua_State* L, int index) {
|
||||
|
@ -65,6 +69,16 @@ Shape* luax_newcylindershape(lua_State* L, int index) {
|
|||
return lovrCylinderShapeCreate(radius, length);
|
||||
}
|
||||
|
||||
Shape* luax_newconvexshape(lua_State* L, int index) {
|
||||
float* points;
|
||||
uint32_t count;
|
||||
bool shouldFree;
|
||||
luax_readmesh(L, index, &points, &count, NULL, NULL, &shouldFree);
|
||||
ConvexShape* shape = lovrConvexShapeCreate(points, count);
|
||||
if (shouldFree) lovrFree(points);
|
||||
return shape;
|
||||
}
|
||||
|
||||
Shape* luax_newmeshshape(lua_State* L, int index) {
|
||||
float* vertices;
|
||||
uint32_t* indices;
|
||||
|
@ -81,9 +95,8 @@ Shape* luax_newmeshshape(lua_State* L, int index) {
|
|||
if (!shouldFree) {
|
||||
float* v = vertices;
|
||||
uint32_t* i = indices;
|
||||
vertices = malloc(3 * vertexCount * sizeof(float));
|
||||
indices = malloc(indexCount * sizeof(uint32_t));
|
||||
lovrAssert(vertices && indices, "Out of memory");
|
||||
vertices = lovrMalloc(3 * vertexCount * sizeof(float));
|
||||
indices = lovrMalloc(indexCount * sizeof(uint32_t));
|
||||
memcpy(vertices, v, 3 * vertexCount * sizeof(float));
|
||||
memcpy(indices, i, indexCount * sizeof(uint32_t));
|
||||
}
|
||||
|
@ -92,18 +105,17 @@ Shape* luax_newmeshshape(lua_State* L, int index) {
|
|||
}
|
||||
|
||||
Shape* luax_newterrainshape(lua_State* L, int index) {
|
||||
float horizontalScale = luax_checkfloat(L, index++);
|
||||
float scaleXZ = luax_checkfloat(L, index++);
|
||||
int type = lua_type(L, index);
|
||||
if (type == LUA_TNIL || type == LUA_TNONE) {
|
||||
float vertices[4] = { 0.f };
|
||||
return lovrTerrainShapeCreate(vertices, 2, 2, horizontalScale, 1.f);
|
||||
return lovrTerrainShapeCreate(vertices, 2, scaleXZ, 1.f);
|
||||
} else if (type == LUA_TFUNCTION) {
|
||||
uint32_t samples = luax_optu32(L, index + 1, 100);
|
||||
float* vertices = malloc(sizeof(float) * samples * samples);
|
||||
lovrAssert(vertices, "Out of memory");
|
||||
for (uint32_t i = 0; i < samples * samples; i++) {
|
||||
float x = horizontalScale * (-.5f + ((float) (i % samples)) / samples);
|
||||
float z = horizontalScale * (-.5f + ((float) (i / samples)) / samples);
|
||||
uint32_t n = luax_optu32(L, index + 1, 100);
|
||||
float* vertices = lovrMalloc(sizeof(float) * n * n);
|
||||
for (uint32_t i = 0; i < n * n; i++) {
|
||||
float x = scaleXZ * (-.5f + ((float) (i % n)) / n);
|
||||
float z = scaleXZ * (-.5f + ((float) (i / n)) / n);
|
||||
lua_pushvalue(L, index);
|
||||
lua_pushnumber(L, x);
|
||||
lua_pushnumber(L, z);
|
||||
|
@ -112,25 +124,24 @@ Shape* luax_newterrainshape(lua_State* L, int index) {
|
|||
vertices[i] = luax_tofloat(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
TerrainShape* shape = lovrTerrainShapeCreate(vertices, samples, samples, horizontalScale, 1.f);
|
||||
free(vertices);
|
||||
TerrainShape* shape = lovrTerrainShapeCreate(vertices, n, scaleXZ, 1.f);
|
||||
lovrFree(vertices);
|
||||
return shape;
|
||||
} else if (type == LUA_TUSERDATA) {
|
||||
Image* image = luax_checktype(L, index, Image);
|
||||
uint32_t imageWidth = lovrImageGetWidth(image, 0);
|
||||
uint32_t imageHeight = lovrImageGetHeight(image, 0);
|
||||
float verticalScale = luax_optfloat(L, index + 1, 1.f);
|
||||
float* vertices = malloc(sizeof(float) * imageWidth * imageHeight);
|
||||
lovrAssert(vertices, "Out of memory");
|
||||
for (uint32_t y = 0; y < imageHeight; y++) {
|
||||
for (uint32_t x = 0; x < imageWidth; x++) {
|
||||
uint32_t n = lovrImageGetWidth(image, 0);
|
||||
lovrCheck(lovrImageGetHeight(image, 0) == n, "TerrainShape images must be square");
|
||||
float scaleY = luax_optfloat(L, index + 1, 1.f);
|
||||
float* vertices = lovrMalloc(sizeof(float) * n * n);
|
||||
for (uint32_t y = 0; y < n; y++) {
|
||||
for (uint32_t x = 0; x < n; x++) {
|
||||
float pixel[4];
|
||||
lovrImageGetPixel(image, x, y, pixel);
|
||||
vertices[x + y * imageWidth] = pixel[0];
|
||||
vertices[x + y * n] = pixel[0];
|
||||
}
|
||||
}
|
||||
TerrainShape* shape = lovrTerrainShapeCreate(vertices, imageWidth, imageHeight, horizontalScale, verticalScale);
|
||||
free(vertices);
|
||||
TerrainShape* shape = lovrTerrainShapeCreate(vertices, n, scaleXZ, scaleY);
|
||||
lovrFree(vertices);
|
||||
return shape;
|
||||
} else {
|
||||
luax_typeerror(L, index, "Image, number, or function");
|
||||
|
@ -138,6 +149,85 @@ Shape* luax_newterrainshape(lua_State* L, int index) {
|
|||
}
|
||||
}
|
||||
|
||||
Shape* luax_newcompoundshape(lua_State* L, int index) {
|
||||
if (lua_isnoneornil(L, index)) {
|
||||
return lovrCompoundShapeCreate(NULL, NULL, NULL, 0, false);
|
||||
}
|
||||
|
||||
luaL_checktype(L, index, LUA_TTABLE);
|
||||
int length = luax_len(L, index);
|
||||
|
||||
uint32_t defer = lovrDeferPush();
|
||||
Shape** shapes = lovrMalloc(length * sizeof(Shape*));
|
||||
float* positions = lovrMalloc(length * 3 * sizeof(float));
|
||||
float* orientations = lovrMalloc(length * 4 * sizeof(float));
|
||||
lovrDefer(lovrFree, shapes);
|
||||
lovrDefer(lovrFree, positions);
|
||||
lovrDefer(lovrFree, orientations);
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
lua_rawgeti(L, index, i + 1);
|
||||
lovrCheck(lua_istable(L, -1), "Expected table of tables for compound shape");
|
||||
|
||||
lua_rawgeti(L, -1, 1);
|
||||
shapes[i] = luax_checkshape(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
int index = 2;
|
||||
lua_rawgeti(L, -1, index);
|
||||
switch (lua_type(L, -1)) {
|
||||
case LUA_TNIL:
|
||||
vec3_set(&positions[3 * i], 0.f, 0.f, 0.f);
|
||||
lua_pop(L, 1);
|
||||
break;
|
||||
case LUA_TNUMBER:
|
||||
lua_rawgeti(L, -2, index + 1);
|
||||
lua_rawgeti(L, -3, index + 2);
|
||||
vec3_set(&positions[3 * i], luax_tofloat(L, -3), luax_tofloat(L, -2), luax_tofloat(L, -1));
|
||||
lua_pop(L, 3);
|
||||
index += 3;
|
||||
break;
|
||||
default: {
|
||||
float* v = luax_checkvector(L, -1, V_VEC3, "nil, number, or vec3");
|
||||
vec3_init(&positions[3 * i], v);
|
||||
lua_pop(L, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
lua_rawgeti(L, -1, index);
|
||||
switch (lua_type(L, -1)) {
|
||||
case LUA_TNIL:
|
||||
quat_identity(&orientations[4 * i]);
|
||||
lua_pop(L, 1);
|
||||
break;
|
||||
case LUA_TNUMBER:
|
||||
lua_rawgeti(L, -2, index);
|
||||
lua_rawgeti(L, -3, index);
|
||||
lua_rawgeti(L, -4, index);
|
||||
quat_set(&orientations[4 * i], luax_tofloat(L, -4), luax_tofloat(L, -3), luax_tofloat(L, -2), luax_tofloat(L, -1));
|
||||
lua_pop(L, 4);
|
||||
break;
|
||||
default: {
|
||||
float* q = luax_checkvector(L, -1, V_QUAT, "nil, number, or quat");
|
||||
quat_init(&positions[4 * i], q);
|
||||
lua_pop(L, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
lua_getfield(L, index, "freeze");
|
||||
bool freeze = lua_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
CompoundShape* shape = lovrCompoundShapeCreate(shapes, positions, orientations, length, freeze);
|
||||
lovrDeferPop(defer);
|
||||
return shape;
|
||||
}
|
||||
|
||||
static int l_lovrShapeDestroy(lua_State* L) {
|
||||
Shape* shape = luax_checkshape(L, 1);
|
||||
lovrShapeDestroyData(shape);
|
||||
|
@ -150,139 +240,49 @@ static int l_lovrShapeGetType(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrShapeGetCollider(lua_State* L) {
|
||||
Shape* shape = luax_checkshape(L, 1);
|
||||
luax_pushtype(L, Collider, lovrShapeGetCollider(shape));
|
||||
return 1;
|
||||
}
|
||||
static void luax_pushshapestash(lua_State* L) {
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, "_lovrshapestash");
|
||||
|
||||
static int l_lovrShapeIsEnabled(lua_State* L) {
|
||||
Shape* shape = luax_checkshape(L, 1);
|
||||
lua_pushboolean(L, lovrShapeIsEnabled(shape));
|
||||
return 1;
|
||||
}
|
||||
if (lua_isnil(L, -1)) {
|
||||
lua_newtable(L);
|
||||
lua_replace(L, -2);
|
||||
|
||||
static int l_lovrShapeSetEnabled(lua_State* L) {
|
||||
Shape* shape = luax_checkshape(L, 1);
|
||||
bool enabled = lua_toboolean(L, 2);
|
||||
lovrShapeSetEnabled(shape, enabled);
|
||||
return 0;
|
||||
}
|
||||
// metatable
|
||||
lua_newtable(L);
|
||||
lua_pushliteral(L, "k");
|
||||
lua_setfield(L, -2, "__mode");
|
||||
lua_setmetatable(L, -2);
|
||||
|
||||
static int l_lovrShapeIsSensor(lua_State* L) {
|
||||
Shape* shape = luax_checkshape(L, 1);
|
||||
lua_pushboolean(L, lovrShapeIsSensor(shape));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrShapeSetSensor(lua_State* L) {
|
||||
Shape* shape = luax_checkshape(L, 1);
|
||||
bool sensor = lua_toboolean(L, 2);
|
||||
lovrShapeSetSensor(shape, sensor);
|
||||
return 0;
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, LUA_REGISTRYINDEX, "_lovrshapestash");
|
||||
}
|
||||
}
|
||||
|
||||
static int l_lovrShapeGetUserData(lua_State* L) {
|
||||
Shape* shape = luax_checkshape(L, 1);
|
||||
union { int i; void* p; } ref = { .p = lovrShapeGetUserData(shape) };
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, ref.i);
|
||||
luax_checktype(L, 1, Shape);
|
||||
luax_pushshapestash(L);
|
||||
lua_pushvalue(L, 1);
|
||||
lua_rawget(L, -2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrShapeSetUserData(lua_State* L) {
|
||||
Shape* shape = luax_checkshape(L, 1);
|
||||
union { int i; void* p; } ref = { .p = lovrShapeGetUserData(shape) };
|
||||
if (ref.i) {
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, ref.i);
|
||||
}
|
||||
|
||||
if (lua_gettop(L) < 2) {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
|
||||
lua_settop(L, 2);
|
||||
ref.i = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
lovrShapeSetUserData(shape, ref.p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrShapeGetPosition(lua_State* L) {
|
||||
Shape* shape = luax_checkshape(L, 1);
|
||||
float x, y, z;
|
||||
lovrShapeGetPosition(shape, &x, &y, &z);
|
||||
lua_pushnumber(L, x);
|
||||
lua_pushnumber(L, y);
|
||||
lua_pushnumber(L, z);
|
||||
return 3;
|
||||
}
|
||||
|
||||
static int l_lovrShapeSetPosition(lua_State* L) {
|
||||
Shape* shape = luax_checkshape(L, 1);
|
||||
lovrAssert(lovrShapeGetCollider(shape) != NULL, "Shape must be attached to collider");
|
||||
float position[3];
|
||||
luax_readvec3(L, 2, position, NULL);
|
||||
lovrShapeSetPosition(shape, position[0], position[1], position[2]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrShapeGetOrientation(lua_State* L) {
|
||||
Shape* shape = luax_checkshape(L, 1);
|
||||
float angle, x, y, z, orientation[4];
|
||||
lovrShapeGetOrientation(shape, orientation);
|
||||
quat_getAngleAxis(orientation, &angle, &x, &y, &z);
|
||||
lua_pushnumber(L, angle);
|
||||
lua_pushnumber(L, x);
|
||||
lua_pushnumber(L, y);
|
||||
lua_pushnumber(L, z);
|
||||
return 4;
|
||||
}
|
||||
|
||||
static int l_lovrShapeSetOrientation(lua_State* L) {
|
||||
Shape* shape = luax_checkshape(L, 1);
|
||||
lovrAssert(lovrShapeGetCollider(shape) != NULL, "Shape must be attached to collider");
|
||||
float orientation[4];
|
||||
luax_readquat(L, 2, orientation, NULL);
|
||||
lovrShapeSetOrientation(shape, orientation);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrShapeGetPose(lua_State* L) {
|
||||
Shape* shape = luax_checkshape(L, 1);
|
||||
float x, y, z;
|
||||
lovrShapeGetPosition(shape, &x, &y, &z);
|
||||
float angle, ax, ay, az, orientation[4];
|
||||
lovrShapeGetOrientation(shape, orientation);
|
||||
quat_getAngleAxis(orientation, &angle, &ax, &ay, &az);
|
||||
lua_pushnumber(L, x);
|
||||
lua_pushnumber(L, y);
|
||||
lua_pushnumber(L, z);
|
||||
lua_pushnumber(L, angle);
|
||||
lua_pushnumber(L, ax);
|
||||
lua_pushnumber(L, ay);
|
||||
lua_pushnumber(L, az);
|
||||
return 7;
|
||||
}
|
||||
|
||||
static int l_lovrShapeSetPose(lua_State* L) {
|
||||
Shape* shape = luax_checkshape(L, 1);
|
||||
lovrAssert(lovrShapeGetCollider(shape) != NULL, "Shape must be attached to collider");
|
||||
float position[3], orientation[4];
|
||||
int index = luax_readvec3(L, 2, position, NULL);
|
||||
luax_readquat(L, index, orientation, NULL);
|
||||
lovrShapeSetPosition(shape, position[0], position[1], position[2]);
|
||||
lovrShapeSetOrientation(shape, orientation);
|
||||
luax_checktype(L, 1, Shape);
|
||||
luax_pushshapestash(L);
|
||||
lua_pushvalue(L, 1);
|
||||
lua_pushvalue(L, 2);
|
||||
lua_rawset(L, -3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrShapeGetMass(lua_State* L) {
|
||||
Shape* shape = luax_checkshape(L, 1);
|
||||
float density = luax_checkfloat(L, 2);
|
||||
float cx, cy, cz, mass;
|
||||
float inertia[6];
|
||||
lovrShapeGetMass(shape, density, &cx, &cy, &cz, &mass, inertia);
|
||||
lua_pushnumber(L, cx);
|
||||
lua_pushnumber(L, cy);
|
||||
lua_pushnumber(L, cz);
|
||||
float centerOfMass[3], mass, inertia[6];
|
||||
lovrShapeGetMass(shape, density, centerOfMass, &mass, inertia);
|
||||
lua_pushnumber(L, centerOfMass[0]);
|
||||
lua_pushnumber(L, centerOfMass[1]);
|
||||
lua_pushnumber(L, centerOfMass[2]);
|
||||
lua_pushnumber(L, mass);
|
||||
lua_newtable(L);
|
||||
for (int i = 0; i < 6; i++) {
|
||||
|
@ -294,8 +294,15 @@ static int l_lovrShapeGetMass(lua_State* L) {
|
|||
|
||||
static int l_lovrShapeGetAABB(lua_State* L) {
|
||||
Shape* shape = luax_checkshape(L, 1);
|
||||
float aabb[6];
|
||||
lovrShapeGetAABB(shape, aabb);
|
||||
float position[3], orientation[4], aabb[6];
|
||||
if (lua_gettop(L) >= 2) {
|
||||
int index = 2;
|
||||
index = luax_readvec3(L, index, position, NULL);
|
||||
index = luax_readquat(L, index, orientation, NULL);
|
||||
lovrShapeGetAABB(shape, position, orientation, aabb);
|
||||
} else {
|
||||
lovrShapeGetAABB(shape, NULL, NULL, aabb);
|
||||
}
|
||||
for (int i = 0; i < 6; i++) {
|
||||
lua_pushnumber(L, aabb[i]);
|
||||
}
|
||||
|
@ -305,19 +312,8 @@ static int l_lovrShapeGetAABB(lua_State* L) {
|
|||
#define lovrShape \
|
||||
{ "destroy", l_lovrShapeDestroy }, \
|
||||
{ "getType", l_lovrShapeGetType }, \
|
||||
{ "getCollider", l_lovrShapeGetCollider }, \
|
||||
{ "isEnabled", l_lovrShapeIsEnabled }, \
|
||||
{ "setEnabled", l_lovrShapeSetEnabled }, \
|
||||
{ "isSensor", l_lovrShapeIsSensor }, \
|
||||
{ "setSensor", l_lovrShapeSetSensor }, \
|
||||
{ "getUserData", l_lovrShapeGetUserData }, \
|
||||
{ "setUserData", l_lovrShapeSetUserData }, \
|
||||
{ "getPosition", l_lovrShapeGetPosition }, \
|
||||
{ "setPosition", l_lovrShapeSetPosition }, \
|
||||
{ "getOrientation", l_lovrShapeGetOrientation }, \
|
||||
{ "setOrientation", l_lovrShapeSetOrientation }, \
|
||||
{ "getPose", l_lovrShapeGetPose }, \
|
||||
{ "setPose", l_lovrShapeSetPose }, \
|
||||
{ "getMass", l_lovrShapeGetMass }, \
|
||||
{ "getAABB", l_lovrShapeGetAABB }
|
||||
|
||||
|
@ -327,42 +323,25 @@ static int l_lovrSphereShapeGetRadius(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrSphereShapeSetRadius(lua_State* L) {
|
||||
SphereShape* sphere = luax_checktype(L, 1, SphereShape);
|
||||
float radius = luax_checkfloat(L, 2);
|
||||
lovrSphereShapeSetRadius(sphere, radius);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const luaL_Reg lovrSphereShape[] = {
|
||||
lovrShape,
|
||||
{ "getRadius", l_lovrSphereShapeGetRadius },
|
||||
{ "setRadius", l_lovrSphereShapeSetRadius },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static int l_lovrBoxShapeGetDimensions(lua_State* L) {
|
||||
BoxShape* box = luax_checktype(L, 1, BoxShape);
|
||||
float w, h, d;
|
||||
lovrBoxShapeGetDimensions(box, &w, &h, &d);
|
||||
lua_pushnumber(L, w);
|
||||
lua_pushnumber(L, h);
|
||||
lua_pushnumber(L, d);
|
||||
float dimensions[3];
|
||||
lovrBoxShapeGetDimensions(box, dimensions);
|
||||
lua_pushnumber(L, dimensions[0]);
|
||||
lua_pushnumber(L, dimensions[1]);
|
||||
lua_pushnumber(L, dimensions[2]);
|
||||
return 3;
|
||||
}
|
||||
|
||||
static int l_lovrBoxShapeSetDimensions(lua_State* L) {
|
||||
BoxShape* box = luax_checktype(L, 1, BoxShape);
|
||||
float size[3];
|
||||
luax_readscale(L, 2, size, 3, NULL);
|
||||
lovrBoxShapeSetDimensions(box, size[0], size[1], size[2]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const luaL_Reg lovrBoxShape[] = {
|
||||
lovrShape,
|
||||
{ "getDimensions", l_lovrBoxShapeGetDimensions },
|
||||
{ "setDimensions", l_lovrBoxShapeSetDimensions },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
|
@ -372,32 +351,16 @@ static int l_lovrCapsuleShapeGetRadius(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrCapsuleShapeSetRadius(lua_State* L) {
|
||||
CapsuleShape* capsule = luax_checktype(L, 1, CapsuleShape);
|
||||
float radius = luax_checkfloat(L, 2);
|
||||
lovrCapsuleShapeSetRadius(capsule, radius);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrCapsuleShapeGetLength(lua_State* L) {
|
||||
CapsuleShape* capsule = luax_checktype(L, 1, CapsuleShape);
|
||||
lua_pushnumber(L, lovrCapsuleShapeGetLength(capsule));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrCapsuleShapeSetLength(lua_State* L) {
|
||||
CapsuleShape* capsule = luax_checktype(L, 1, CapsuleShape);
|
||||
float length = luax_checkfloat(L, 2);
|
||||
lovrCapsuleShapeSetLength(capsule, length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const luaL_Reg lovrCapsuleShape[] = {
|
||||
lovrShape,
|
||||
{ "getRadius", l_lovrCapsuleShapeGetRadius },
|
||||
{ "setRadius", l_lovrCapsuleShapeSetRadius },
|
||||
{ "getLength", l_lovrCapsuleShapeGetLength },
|
||||
{ "setLength", l_lovrCapsuleShapeSetLength },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
|
@ -407,32 +370,21 @@ static int l_lovrCylinderShapeGetRadius(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrCylinderShapeSetRadius(lua_State* L) {
|
||||
CylinderShape* cylinder = luax_checktype(L, 1, CylinderShape);
|
||||
float radius = luax_checkfloat(L, 2);
|
||||
lovrCylinderShapeSetRadius(cylinder, radius);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrCylinderShapeGetLength(lua_State* L) {
|
||||
CylinderShape* cylinder = luax_checktype(L, 1, CylinderShape);
|
||||
lua_pushnumber(L, lovrCylinderShapeGetLength(cylinder));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrCylinderShapeSetLength(lua_State* L) {
|
||||
CylinderShape* cylinder = luax_checktype(L, 1, CylinderShape);
|
||||
float length = luax_checkfloat(L, 2);
|
||||
lovrCylinderShapeSetLength(cylinder, length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const luaL_Reg lovrCylinderShape[] = {
|
||||
lovrShape,
|
||||
{ "getRadius", l_lovrCylinderShapeGetRadius },
|
||||
{ "setRadius", l_lovrCylinderShapeSetRadius },
|
||||
{ "getLength", l_lovrCylinderShapeGetLength },
|
||||
{ "setLength", l_lovrCylinderShapeSetLength },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
const luaL_Reg lovrConvexShape[] = {
|
||||
lovrShape,
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
|
@ -445,3 +397,109 @@ const luaL_Reg lovrTerrainShape[] = {
|
|||
lovrShape,
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static int l_lovrCompoundShapeIsFrozen(lua_State* L) {
|
||||
CompoundShape* shape = luax_checktype(L, 1, CompoundShape);
|
||||
bool frozen = lovrCompoundShapeIsFrozen(shape);
|
||||
lua_pushboolean(L, frozen);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrCompoundShapeAddChild(lua_State* L) {
|
||||
CompoundShape* shape = luax_checktype(L, 1, CompoundShape);
|
||||
Shape* child = luax_checkshape(L, 2);
|
||||
float position[3], orientation[4];
|
||||
int index = 3;
|
||||
index = luax_readvec3(L, index, position, NULL);
|
||||
index = luax_readquat(L, index, orientation, NULL);
|
||||
lovrCompoundShapeAddChild(shape, child, position, orientation);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrCompoundShapeReplaceChild(lua_State* L) {
|
||||
CompoundShape* shape = luax_checktype(L, 1, CompoundShape);
|
||||
uint32_t index = luax_checku32(L, 2) - 1;
|
||||
Shape* child = luax_checkshape(L, 3);
|
||||
float position[3], orientation[4];
|
||||
int i = 4;
|
||||
i = luax_readvec3(L, i, position, NULL);
|
||||
i = luax_readquat(L, i, orientation, NULL);
|
||||
lovrCompoundShapeReplaceChild(shape, index, child, position, orientation);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrCompoundShapeRemoveChild(lua_State* L) {
|
||||
CompoundShape* shape = luax_checktype(L, 1, CompoundShape);
|
||||
uint32_t index = luax_checku32(L, 2) - 1;
|
||||
lovrCompoundShapeRemoveChild(shape, index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrCompoundShapeGetChild(lua_State* L) {
|
||||
CompoundShape* shape = luax_checktype(L, 1, CompoundShape);
|
||||
uint32_t index = luax_checku32(L, 2) - 1;
|
||||
Shape* child = lovrCompoundShapeGetChild(shape, index);
|
||||
luax_pushshape(L, child);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrCompoundShapeGetChildren(lua_State* L) {
|
||||
CompoundShape* shape = luax_checktype(L, 1, CompoundShape);
|
||||
int count = (int) lovrCompoundShapeGetChildCount(shape);
|
||||
lua_createtable(L, count, 0);
|
||||
for (int i = 0; i < count; i++) {
|
||||
Shape* child = lovrCompoundShapeGetChild(shape, (uint32_t) i);
|
||||
luax_pushshape(L, child);
|
||||
lua_rawseti(L, -2, i + 1);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrCompoundShapeGetChildCount(lua_State* L) {
|
||||
CompoundShape* shape = luax_checktype(L, 1, CompoundShape);
|
||||
uint32_t count = lovrCompoundShapeGetChildCount(shape);
|
||||
lua_pushinteger(L, count);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrCompoundShapeGetChildOffset(lua_State* L) {
|
||||
CompoundShape* shape = luax_checktype(L, 1, CompoundShape);
|
||||
uint32_t index = luax_checku32(L, 2) - 1;
|
||||
float position[3], orientation[4], angle, ax, ay, az;
|
||||
lovrCompoundShapeGetChildOffset(shape, index, position, orientation);
|
||||
quat_getAngleAxis(orientation, &angle, &ax, &ay, &az);
|
||||
lua_pushnumber(L, position[0]);
|
||||
lua_pushnumber(L, position[1]);
|
||||
lua_pushnumber(L, position[2]);
|
||||
lua_pushnumber(L, angle);
|
||||
lua_pushnumber(L, ax);
|
||||
lua_pushnumber(L, ay);
|
||||
lua_pushnumber(L, az);
|
||||
return 7;
|
||||
}
|
||||
|
||||
static int l_lovrCompoundShapeSetChildOffset(lua_State* L) {
|
||||
CompoundShape* shape = luax_checktype(L, 1, CompoundShape);
|
||||
uint32_t index = luax_checku32(L, 2) - 1;
|
||||
float position[3], orientation[4];
|
||||
int i = 3;
|
||||
i = luax_readvec3(L, i, position, NULL);
|
||||
i = luax_readquat(L, i, orientation, NULL);
|
||||
lovrCompoundShapeSetChildOffset(shape, index, position, orientation);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const luaL_Reg lovrCompoundShape[] = {
|
||||
lovrShape,
|
||||
{ "isFrozen", l_lovrCompoundShapeIsFrozen },
|
||||
{ "addChild", l_lovrCompoundShapeAddChild },
|
||||
{ "replaceChild", l_lovrCompoundShapeReplaceChild },
|
||||
{ "removeChild", l_lovrCompoundShapeRemoveChild },
|
||||
{ "getChild", l_lovrCompoundShapeGetChild },
|
||||
{ "getChildren", l_lovrCompoundShapeGetChildren },
|
||||
{ "getChildCount", l_lovrCompoundShapeGetChildCount },
|
||||
{ "getChildOffset", l_lovrCompoundShapeGetChildOffset },
|
||||
{ "setChildOffset", l_lovrCompoundShapeSetChildOffset },
|
||||
{ "__len", l_lovrCompoundShapeGetChildCount }, // :)
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
|
|
@ -27,17 +27,18 @@ static int nextOverlap(lua_State* L) {
|
|||
}
|
||||
}
|
||||
|
||||
static bool raycastCallback(Shape* shape, float x, float y, float z, float nx, float ny, float nz, void* userdata) {
|
||||
static bool raycastCallback(Collider* collider, float position[3], float normal[3], uint32_t shape, void* userdata) {
|
||||
lua_State* L = userdata;
|
||||
lua_pushvalue(L, -1);
|
||||
luax_pushshape(L, shape);
|
||||
lua_pushnumber(L, x);
|
||||
lua_pushnumber(L, y);
|
||||
lua_pushnumber(L, z);
|
||||
lua_pushnumber(L, nx);
|
||||
lua_pushnumber(L, ny);
|
||||
lua_pushnumber(L, nz);
|
||||
lua_call(L, 7, 1);
|
||||
luax_pushtype(L, Collider, collider);
|
||||
lua_pushnumber(L, position[0]);
|
||||
lua_pushnumber(L, position[1]);
|
||||
lua_pushnumber(L, position[2]);
|
||||
lua_pushnumber(L, normal[0]);
|
||||
lua_pushnumber(L, normal[1]);
|
||||
lua_pushnumber(L, normal[2]);
|
||||
lua_pushinteger(L, shape + 1);
|
||||
lua_call(L, 8, 1);
|
||||
bool shouldStop = lua_type(L, -1) == LUA_TBOOLEAN && !lua_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
return shouldStop;
|
||||
|
@ -45,53 +46,55 @@ static bool raycastCallback(Shape* shape, float x, float y, float z, float nx, f
|
|||
|
||||
typedef struct {
|
||||
const char* tag;
|
||||
Shape* shape;
|
||||
Collider* collider;
|
||||
uint32_t shape;
|
||||
float distance;
|
||||
float origin[3];
|
||||
float position[3];
|
||||
float normal[3];
|
||||
} RaycastData;
|
||||
|
||||
static bool raycastAnyCallback(Shape* shape, float x, float y, float z, float nx, float ny, float nz, void* userdata) {
|
||||
static bool raycastAnyCallback(Collider* collider, float position[3], float normal[3], uint32_t shape, void* userdata) {
|
||||
RaycastData* data = userdata;
|
||||
if (data->tag) {
|
||||
const char* tag = lovrColliderGetTag(lovrShapeGetCollider(shape));
|
||||
const char* tag = lovrColliderGetTag(collider);
|
||||
if (!tag || strcmp(tag, data->tag)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
data->collider = collider;
|
||||
data->shape = shape;
|
||||
vec3_set(data->position, x, y, z);
|
||||
vec3_set(data->normal, nx, ny, nz);
|
||||
vec3_init(data->position, position);
|
||||
vec3_init(data->normal, normal);
|
||||
data->distance = vec3_distance(data->origin, data->position);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool raycastClosestCallback(Shape* shape, float x, float y, float z, float nx, float ny, float nz, void* userdata) {
|
||||
static bool raycastClosestCallback(Collider* collider, float position[3], float normal[3], uint32_t shape, void* userdata) {
|
||||
RaycastData* data = userdata;
|
||||
if (data->tag) {
|
||||
const char* tag = lovrColliderGetTag(lovrShapeGetCollider(shape));
|
||||
const char* tag = lovrColliderGetTag(collider);
|
||||
if (!tag || strcmp(tag, data->tag)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
float position[3];
|
||||
vec3_set(position, x, y, z);
|
||||
float distance = vec3_distance(data->origin, position);
|
||||
if (distance < data->distance) {
|
||||
vec3_init(data->position, position);
|
||||
vec3_set(data->normal, nx, ny, nz);
|
||||
vec3_init(data->normal, normal);
|
||||
data->distance = distance;
|
||||
data->collider = collider;
|
||||
data->shape = shape;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool queryCallback(Shape* shape, void* userdata) {
|
||||
static bool queryCallback(Collider* collider, uint32_t shape, void* userdata) {
|
||||
lua_State* L = userdata;
|
||||
lua_pushvalue(L, -1);
|
||||
luax_pushshape(L, shape);
|
||||
lua_call(L, 1, 1);
|
||||
luax_pushtype(L, Collider, collider);
|
||||
lua_pushinteger(L, shape + 1);
|
||||
lua_call(L, 2, 1);
|
||||
bool shouldStop = lua_type(L, -1) == LUA_TBOOLEAN && !lua_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
return shouldStop;
|
||||
|
@ -99,9 +102,10 @@ static bool queryCallback(Shape* shape, void* userdata) {
|
|||
|
||||
static int l_lovrWorldNewCollider(lua_State* L) {
|
||||
World* world = luax_checktype(L, 1, World);
|
||||
Shape* shape = luax_totype(L, 2, Shape);
|
||||
float position[3];
|
||||
luax_readvec3(L, 2, position, NULL);
|
||||
Collider* collider = lovrColliderCreate(world, position[0], position[1], position[2]);
|
||||
luax_readvec3(L, 2 + !!shape, position, NULL);
|
||||
Collider* collider = lovrColliderCreate(world, shape, position);
|
||||
luax_pushtype(L, Collider, collider);
|
||||
lovrRelease(collider, lovrColliderDestroy);
|
||||
return 1;
|
||||
|
@ -111,9 +115,8 @@ static int l_lovrWorldNewBoxCollider(lua_State* L) {
|
|||
World* world = luax_checktype(L, 1, World);
|
||||
float position[3];
|
||||
int index = luax_readvec3(L, 2, position, NULL);
|
||||
Collider* collider = lovrColliderCreate(world, position[0], position[1], position[2]);
|
||||
BoxShape* shape = luax_newboxshape(L, index);
|
||||
lovrColliderAddShape(collider, shape);
|
||||
Collider* collider = lovrColliderCreate(world, shape, position);
|
||||
lovrColliderInitInertia(collider, shape);
|
||||
luax_pushtype(L, Collider, collider);
|
||||
lovrRelease(collider, lovrColliderDestroy);
|
||||
|
@ -125,9 +128,8 @@ static int l_lovrWorldNewCapsuleCollider(lua_State* L) {
|
|||
World* world = luax_checktype(L, 1, World);
|
||||
float position[3];
|
||||
int index = luax_readvec3(L, 2, position, NULL);
|
||||
Collider* collider = lovrColliderCreate(world, position[0], position[1], position[2]);
|
||||
CapsuleShape* shape = luax_newcapsuleshape(L, index);
|
||||
lovrColliderAddShape(collider, shape);
|
||||
Collider* collider = lovrColliderCreate(world, shape, position);
|
||||
lovrColliderInitInertia(collider, shape);
|
||||
luax_pushtype(L, Collider, collider);
|
||||
lovrRelease(collider, lovrColliderDestroy);
|
||||
|
@ -139,9 +141,21 @@ static int l_lovrWorldNewCylinderCollider(lua_State* L) {
|
|||
World* world = luax_checktype(L, 1, World);
|
||||
float position[3];
|
||||
int index = luax_readvec3(L, 2, position, NULL);
|
||||
Collider* collider = lovrColliderCreate(world, position[0], position[1], position[2]);
|
||||
CylinderShape* shape = luax_newcylindershape(L, index);
|
||||
lovrColliderAddShape(collider, shape);
|
||||
Collider* collider = lovrColliderCreate(world, shape, position);
|
||||
lovrColliderInitInertia(collider, shape);
|
||||
luax_pushtype(L, Collider, collider);
|
||||
lovrRelease(collider, lovrColliderDestroy);
|
||||
lovrRelease(shape, lovrShapeDestroy);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrWorldNewConvexCollider(lua_State* L) {
|
||||
World* world = luax_checktype(L, 1, World);
|
||||
float position[3];
|
||||
int index = luax_readvec3(L, 2, position, NULL);
|
||||
ConvexShape* shape = luax_newconvexshape(L, index);
|
||||
Collider* collider = lovrColliderCreate(world, shape, position);
|
||||
lovrColliderInitInertia(collider, shape);
|
||||
luax_pushtype(L, Collider, collider);
|
||||
lovrRelease(collider, lovrColliderDestroy);
|
||||
|
@ -153,9 +167,8 @@ static int l_lovrWorldNewSphereCollider(lua_State* L) {
|
|||
World* world = luax_checktype(L, 1, World);
|
||||
float position[3];
|
||||
int index = luax_readvec3(L, 2, position, NULL);
|
||||
Collider* collider = lovrColliderCreate(world, position[0], position[1], position[2]);
|
||||
SphereShape* shape = luax_newsphereshape(L, index);
|
||||
lovrColliderAddShape(collider, shape);
|
||||
Collider* collider = lovrColliderCreate(world, shape, position);
|
||||
lovrColliderInitInertia(collider, shape);
|
||||
luax_pushtype(L, Collider, collider);
|
||||
lovrRelease(collider, lovrColliderDestroy);
|
||||
|
@ -165,9 +178,9 @@ static int l_lovrWorldNewSphereCollider(lua_State* L) {
|
|||
|
||||
static int l_lovrWorldNewMeshCollider(lua_State* L) {
|
||||
World* world = luax_checktype(L, 1, World);
|
||||
Collider* collider = lovrColliderCreate(world, 0.f, 0.f, 0.f);
|
||||
MeshShape* shape = luax_newmeshshape(L, 2);
|
||||
lovrColliderAddShape(collider, shape);
|
||||
float position[3] = { 0.f, 0.f, 0.f };
|
||||
Collider* collider = lovrColliderCreate(world, shape, position);
|
||||
lovrColliderInitInertia(collider, shape);
|
||||
luax_pushtype(L, Collider, collider);
|
||||
lovrRelease(collider, lovrColliderDestroy);
|
||||
|
@ -177,9 +190,9 @@ static int l_lovrWorldNewMeshCollider(lua_State* L) {
|
|||
|
||||
static int l_lovrWorldNewTerrainCollider(lua_State* L) {
|
||||
World* world = luax_checktype(L, 1, World);
|
||||
Collider* collider = lovrColliderCreate(world, 0.f, 0.f, 0.f);
|
||||
TerrainShape* shape = luax_newterrainshape(L, 2);
|
||||
lovrColliderAddShape(collider, shape);
|
||||
float position[3] = { 0.f, 0.f, 0.f };
|
||||
Collider* collider = lovrColliderCreate(world, shape, position);
|
||||
lovrColliderSetKinematic(collider, true);
|
||||
luax_pushtype(L, Collider, collider);
|
||||
lovrRelease(collider, lovrColliderDestroy);
|
||||
|
@ -187,25 +200,10 @@ static int l_lovrWorldNewTerrainCollider(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrWorldGetColliders(lua_State* L) {
|
||||
static int l_lovrWorldDestroy(lua_State* L) {
|
||||
World* world = luax_checktype(L, 1, World);
|
||||
|
||||
if (lua_istable(L, 2)) {
|
||||
lua_settop(L, 2);
|
||||
} else {
|
||||
lua_newtable(L);
|
||||
}
|
||||
|
||||
Collider* collider = lovrWorldGetFirstCollider(world);
|
||||
int index = 1;
|
||||
|
||||
while (collider) {
|
||||
luax_pushtype(L, Collider, collider);
|
||||
lua_rawseti(L, -2, index++);
|
||||
collider = lovrColliderGetNext(collider);
|
||||
}
|
||||
|
||||
return 1;
|
||||
lovrWorldDestroyData(world);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrWorldGetTags(lua_State* L) {
|
||||
|
@ -221,10 +219,42 @@ static int l_lovrWorldGetTags(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrWorldDestroy(lua_State* L) {
|
||||
static int l_lovrWorldGetColliderCount(lua_State* L) {
|
||||
World* world = luax_checktype(L, 1, World);
|
||||
lovrWorldDestroyData(world);
|
||||
return 0;
|
||||
uint32_t count = lovrWorldGetColliderCount(world);
|
||||
lua_pushinteger(L, count);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrWorldGetJointCount(lua_State* L) {
|
||||
World* world = luax_checktype(L, 1, World);
|
||||
uint32_t count = lovrWorldGetJointCount(world);
|
||||
lua_pushinteger(L, count);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrWorldGetColliders(lua_State* L) {
|
||||
World* world = luax_checktype(L, 1, World);
|
||||
int index = 1;
|
||||
Collider* collider = NULL;
|
||||
lua_createtable(L, (int) lovrWorldGetColliderCount(world), 0);
|
||||
while ((collider = lovrWorldGetColliders(world, collider)) != NULL) {
|
||||
luax_pushtype(L, Collider, collider);
|
||||
lua_rawseti(L, -2, index++);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrWorldGetJoints(lua_State* L) {
|
||||
World* world = luax_checktype(L, 1, World);
|
||||
int index = 1;
|
||||
Joint* joint = NULL;
|
||||
lua_createtable(L, (int) lovrWorldGetJointCount(world), 0);
|
||||
while ((joint = lovrWorldGetJoints(world, joint)) != NULL) {
|
||||
luax_pushjoint(L, joint);
|
||||
lua_rawseti(L, -2, index++);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrWorldUpdate(lua_State* L) {
|
||||
|
@ -296,7 +326,7 @@ static int l_lovrWorldRaycast(lua_State* L) {
|
|||
index = luax_readvec3(L, index, end, NULL);
|
||||
luaL_checktype(L, index, LUA_TFUNCTION);
|
||||
lua_settop(L, index);
|
||||
lovrWorldRaycast(world, start[0], start[1], start[2], end[0], end[1], end[2], raycastCallback, L);
|
||||
lovrWorldRaycast(world, start, end, raycastCallback, L);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -308,16 +338,17 @@ static int l_lovrWorldRaycastAny(lua_State* L) {
|
|||
index = luax_readvec3(L, index, end, NULL);
|
||||
RaycastData data = { 0 };
|
||||
data.tag = lua_tostring(L, index);
|
||||
lovrWorldRaycast(world, start[0], start[1], start[2], end[0], end[1], end[2], raycastAnyCallback, &data);
|
||||
if (data.shape) {
|
||||
luax_pushshape(L, data.shape);
|
||||
lovrWorldRaycast(world, start, end, raycastAnyCallback, &data);
|
||||
if (data.collider) {
|
||||
luax_pushtype(L, Collider, data.collider);
|
||||
lua_pushnumber(L, data.position[0]);
|
||||
lua_pushnumber(L, data.position[1]);
|
||||
lua_pushnumber(L, data.position[2]);
|
||||
lua_pushnumber(L, data.normal[0]);
|
||||
lua_pushnumber(L, data.normal[1]);
|
||||
lua_pushnumber(L, data.normal[2]);
|
||||
return 7;
|
||||
lua_pushinteger(L, data.shape + 1);
|
||||
return 8;
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
|
@ -332,16 +363,17 @@ static int l_lovrWorldRaycastClosest(lua_State* L) {
|
|||
index = luax_readvec3(L, index, end, NULL);
|
||||
RaycastData data = { .distance = FLT_MAX };
|
||||
data.tag = lua_tostring(L, index);
|
||||
lovrWorldRaycast(world, start[0], start[1], start[2], end[0], end[1], end[2], raycastClosestCallback, &data);
|
||||
lovrWorldRaycast(world, start, end, raycastClosestCallback, &data);
|
||||
if (data.shape) {
|
||||
luax_pushshape(L, data.shape);
|
||||
luax_pushtype(L, Collider, data.collider);
|
||||
lua_pushnumber(L, data.position[0]);
|
||||
lua_pushnumber(L, data.position[1]);
|
||||
lua_pushnumber(L, data.position[2]);
|
||||
lua_pushnumber(L, data.normal[0]);
|
||||
lua_pushnumber(L, data.normal[1]);
|
||||
lua_pushnumber(L, data.normal[2]);
|
||||
return 7;
|
||||
lua_pushinteger(L, data.shape + 1);
|
||||
return 8;
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
|
@ -375,11 +407,11 @@ static int l_lovrWorldQuerySphere(lua_State* L) {
|
|||
|
||||
static int l_lovrWorldGetGravity(lua_State* L) {
|
||||
World* world = luax_checktype(L, 1, World);
|
||||
float x, y, z;
|
||||
lovrWorldGetGravity(world, &x, &y, &z);
|
||||
lua_pushnumber(L, x);
|
||||
lua_pushnumber(L, y);
|
||||
lua_pushnumber(L, z);
|
||||
float gravity[3];
|
||||
lovrWorldGetGravity(world, gravity);
|
||||
lua_pushnumber(L, gravity[0]);
|
||||
lua_pushnumber(L, gravity[1]);
|
||||
lua_pushnumber(L, gravity[2]);
|
||||
return 3;
|
||||
}
|
||||
|
||||
|
@ -387,14 +419,14 @@ static int l_lovrWorldSetGravity(lua_State* L) {
|
|||
World* world = luax_checktype(L, 1, World);
|
||||
float gravity[3];
|
||||
luax_readvec3(L, 2, gravity, NULL);
|
||||
lovrWorldSetGravity(world, gravity[0], gravity[1], gravity[2]);
|
||||
lovrWorldSetGravity(world, gravity);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrWorldGetTightness(lua_State* L) {
|
||||
World* world = luax_checktype(L, 1, World);
|
||||
float tightness = lovrWorldGetTightness(world);
|
||||
lovrAssert(tightness >= 0, "Negative tightness factor causes simulation instability");
|
||||
lovrCheck(tightness >= 0, "Negative tightness factor causes simulation instability");
|
||||
lua_pushnumber(L, tightness);
|
||||
return 1;
|
||||
}
|
||||
|
@ -416,7 +448,7 @@ static int l_lovrWorldGetResponseTime(lua_State* L) {
|
|||
static int l_lovrWorldSetResponseTime(lua_State* L) {
|
||||
World* world = luax_checktype(L, 1, World);
|
||||
float responseTime = luax_checkfloat(L, 2);
|
||||
lovrAssert(responseTime >= 0, "Negative response time causes simulation instability");
|
||||
lovrCheck(responseTime >= 0, "Negative response time causes simulation instability");
|
||||
lovrWorldSetResponseTime(world, responseTime);
|
||||
return 0;
|
||||
}
|
||||
|
@ -511,12 +543,16 @@ const luaL_Reg lovrWorld[] = {
|
|||
{ "newBoxCollider", l_lovrWorldNewBoxCollider },
|
||||
{ "newCapsuleCollider", l_lovrWorldNewCapsuleCollider },
|
||||
{ "newCylinderCollider", l_lovrWorldNewCylinderCollider },
|
||||
{ "newConvexCollider", l_lovrWorldNewConvexCollider },
|
||||
{ "newSphereCollider", l_lovrWorldNewSphereCollider },
|
||||
{ "newMeshCollider", l_lovrWorldNewMeshCollider },
|
||||
{ "newTerrainCollider", l_lovrWorldNewTerrainCollider },
|
||||
{ "getColliders", l_lovrWorldGetColliders },
|
||||
{ "getTags", l_lovrWorldGetTags },
|
||||
{ "destroy", l_lovrWorldDestroy },
|
||||
{ "getTags", l_lovrWorldGetTags },
|
||||
{ "getColliderCount", l_lovrWorldGetColliderCount },
|
||||
{ "getJointCount", l_lovrWorldGetJointCount },
|
||||
{ "getColliders", l_lovrWorldGetColliders },
|
||||
{ "getJoints", l_lovrWorldGetJoints },
|
||||
{ "update", l_lovrWorldUpdate },
|
||||
{ "computeOverlaps", l_lovrWorldComputeOverlaps },
|
||||
{ "overlaps", l_lovrWorldOverlaps },
|
||||
|
@ -529,6 +565,11 @@ const luaL_Reg lovrWorld[] = {
|
|||
{ "querySphere", l_lovrWorldQuerySphere },
|
||||
{ "getGravity", l_lovrWorldGetGravity },
|
||||
{ "setGravity", l_lovrWorldSetGravity },
|
||||
{ "disableCollisionBetween", l_lovrWorldDisableCollisionBetween },
|
||||
{ "enableCollisionBetween", l_lovrWorldEnableCollisionBetween },
|
||||
{ "isCollisionEnabledBetween", l_lovrWorldIsCollisionEnabledBetween },
|
||||
|
||||
// Deprecated
|
||||
{ "getTightness", l_lovrWorldGetTightness },
|
||||
{ "setTightness", l_lovrWorldSetTightness },
|
||||
{ "getResponseTime", l_lovrWorldGetResponseTime },
|
||||
|
@ -539,10 +580,8 @@ const luaL_Reg lovrWorld[] = {
|
|||
{ "setAngularDamping", l_lovrWorldSetAngularDamping },
|
||||
{ "isSleepingAllowed", l_lovrWorldIsSleepingAllowed },
|
||||
{ "setSleepingAllowed", l_lovrWorldSetSleepingAllowed },
|
||||
{ "disableCollisionBetween", l_lovrWorldDisableCollisionBetween },
|
||||
{ "enableCollisionBetween", l_lovrWorldEnableCollisionBetween },
|
||||
{ "isCollisionEnabledBetween", l_lovrWorldIsCollisionEnabledBetween },
|
||||
{ "getStepCount", l_lovrWorldGetStepCount },
|
||||
{ "setStepCount", l_lovrWorldSetStepCount },
|
||||
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
|
|
@ -141,6 +141,8 @@ static int l_lovrSystemOpenWindow(lua_State* L) {
|
|||
os_window_config window;
|
||||
memset(&window, 0, sizeof(window));
|
||||
|
||||
uint32_t defer = lovrDeferPush();
|
||||
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
|
||||
lua_getfield(L, 1, "width");
|
||||
|
@ -170,11 +172,12 @@ static int l_lovrSystemOpenWindow(lua_State* L) {
|
|||
window.icon.data = lovrImageGetLayerData(image, 0, 0);
|
||||
window.icon.width = lovrImageGetWidth(image, 0);
|
||||
window.icon.height = lovrImageGetHeight(image, 0);
|
||||
lovrDeferRelease(image, lovrImageDestroy);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
lovrSystemOpenWindow(&window);
|
||||
lovrRelease(image, lovrImageDestroy);
|
||||
lovrDeferPop(defer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -309,6 +312,18 @@ static int l_lovrSystemWasMouseReleased(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrSystemGetClipboardText(lua_State* L) {
|
||||
const char* text = lovrSystemGetClipboardText();
|
||||
lua_pushstring(L, text);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrSystemSetClipboardText(lua_State* L) {
|
||||
const char* text = luaL_checkstring(L, 1);
|
||||
lovrSystemSetClipboardText(text);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const luaL_Reg lovrSystem[] = {
|
||||
{ "getOS", l_lovrSystemGetOS },
|
||||
{ "getCoreCount", l_lovrSystemGetCoreCount },
|
||||
|
@ -332,6 +347,8 @@ static const luaL_Reg lovrSystem[] = {
|
|||
{ "isMouseDown", l_lovrSystemIsMouseDown },
|
||||
{ "wasMousePressed", l_lovrSystemWasMousePressed },
|
||||
{ "wasMouseReleased", l_lovrSystemWasMouseReleased },
|
||||
{ "getClipboardText", l_lovrSystemGetClipboardText },
|
||||
{ "setClipboardText", l_lovrSystemSetClipboardText },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
|
|
|
@ -2,36 +2,45 @@
|
|||
#include "data/blob.h"
|
||||
#include "event/event.h"
|
||||
#include "thread/thread.h"
|
||||
#include "core/os.h"
|
||||
#include "util.h"
|
||||
#include <lualib.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static void threadRun(void* L) {
|
||||
int top = lua_gettop(L);
|
||||
int status = lua_pcall(L, top - 2, 0, 1);
|
||||
lua_pushinteger(L, status);
|
||||
}
|
||||
|
||||
static char* threadRunner(Thread* thread, Blob* body, Variant* arguments, uint32_t argumentCount) {
|
||||
lua_State* L = luaL_newstate();
|
||||
luaL_openlibs(L);
|
||||
luax_preload(L);
|
||||
lovrSetErrorCallback((errorFn*) luax_vthrow, L);
|
||||
|
||||
lua_pushcfunction(L, luax_getstack);
|
||||
int errhandler = lua_gettop(L);
|
||||
|
||||
if (!luaL_loadbuffer(L, body->data, body->size, "thread")) {
|
||||
for (uint32_t i = 0; i < argumentCount; i++) {
|
||||
luax_pushvariant(L, &arguments[i]);
|
||||
}
|
||||
|
||||
if (!lua_pcall(L, argumentCount, 0, errhandler)) {
|
||||
lovrTry(threadRun, L, luax_vthrow, L);
|
||||
|
||||
if (lua_tointeger(L, -1) == 0) {
|
||||
lua_close(L);
|
||||
return NULL;
|
||||
} else {
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Error handling
|
||||
size_t length;
|
||||
const char* message = lua_tolstring(L, -1, &length);
|
||||
char* error = message ? malloc(length + 1) : NULL;
|
||||
|
||||
if (error) {
|
||||
if (message) {
|
||||
char* error = lovrMalloc(length + 1);
|
||||
memcpy(error, message, length + 1);
|
||||
lua_close(L);
|
||||
return error;
|
||||
|
@ -42,13 +51,13 @@ static char* threadRunner(Thread* thread, Blob* body, Variant* arguments, uint32
|
|||
}
|
||||
|
||||
static int l_lovrThreadNewThread(lua_State* L) {
|
||||
uint32_t defer = lovrDeferPush();
|
||||
Blob* blob = luax_totype(L, 1, Blob);
|
||||
if (!blob) {
|
||||
size_t length;
|
||||
const char* str = luaL_checklstring(L, 1, &length);
|
||||
if (memchr(str, '\n', MIN(1024, length))) {
|
||||
void* data = malloc(length + 1);
|
||||
lovrAssert(data, "Out of memory");
|
||||
void* data = lovrMalloc(length + 1);
|
||||
memcpy(data, str, length + 1);
|
||||
blob = lovrBlobCreate(data, length, "thread code");
|
||||
} else {
|
||||
|
@ -56,13 +65,12 @@ static int l_lovrThreadNewThread(lua_State* L) {
|
|||
lovrAssert(code, "Could not read thread code from file '%s'", str);
|
||||
blob = lovrBlobCreate(code, length, str);
|
||||
}
|
||||
} else {
|
||||
lovrRetain(blob);
|
||||
lovrDeferRelease(blob, lovrBlobDestroy);
|
||||
}
|
||||
Thread* thread = lovrThreadCreate(threadRunner, blob);
|
||||
luax_pushtype(L, Thread, thread);
|
||||
lovrRelease(thread, lovrThreadDestroy);
|
||||
lovrRelease(blob, lovrBlobDestroy);
|
||||
lovrDeferPop(defer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -88,7 +96,24 @@ int luaopen_lovr_thread(lua_State* L) {
|
|||
luax_register(L, lovrThreadModule);
|
||||
luax_registertype(L, Thread);
|
||||
luax_registertype(L, Channel);
|
||||
lovrThreadModuleInit();
|
||||
|
||||
int32_t workers = -1;
|
||||
|
||||
luax_pushconf(L);
|
||||
if (lua_istable(L, -1)) {
|
||||
lua_getfield(L, -1, "thread");
|
||||
if (lua_istable(L, -1)) {
|
||||
lua_getfield(L, -1, "workers");
|
||||
if (lua_type(L, -1) == LUA_TNUMBER) {
|
||||
workers = lua_tointeger(L, -1);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
lovrThreadModuleInit(workers);
|
||||
luax_atexit(L, lovrThreadModuleDestroy);
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -82,6 +82,7 @@ typedef enum {
|
|||
GPU_FORMAT_RGB10A2,
|
||||
GPU_FORMAT_RG11B10F,
|
||||
GPU_FORMAT_D16,
|
||||
GPU_FORMAT_D24,
|
||||
GPU_FORMAT_D32F,
|
||||
GPU_FORMAT_D24S8,
|
||||
GPU_FORMAT_D32FS8,
|
||||
|
@ -122,6 +123,7 @@ typedef struct {
|
|||
uint32_t layerCount;
|
||||
uint32_t levelIndex;
|
||||
uint32_t levelCount;
|
||||
const char* label;
|
||||
} gpu_texture_view_info;
|
||||
|
||||
typedef struct {
|
||||
|
@ -245,16 +247,16 @@ void gpu_layout_destroy(gpu_layout* layout);
|
|||
// Shader
|
||||
|
||||
typedef struct {
|
||||
uint32_t stage;
|
||||
const void* code;
|
||||
size_t length;
|
||||
} gpu_shader_stage;
|
||||
} gpu_shader_source;
|
||||
|
||||
typedef struct {
|
||||
gpu_shader_stage vertex;
|
||||
gpu_shader_stage fragment;
|
||||
gpu_shader_stage compute;
|
||||
gpu_layout* layouts[4];
|
||||
uint32_t stageCount;
|
||||
gpu_shader_source* stages;
|
||||
uint32_t pushConstantSize;
|
||||
gpu_layout* layouts[4];
|
||||
const char* label;
|
||||
} gpu_shader_info;
|
||||
|
||||
|
@ -371,6 +373,7 @@ typedef enum {
|
|||
GPU_TYPE_U8x4,
|
||||
GPU_TYPE_SN8x4,
|
||||
GPU_TYPE_UN8x4,
|
||||
GPU_TYPE_SN10x3,
|
||||
GPU_TYPE_UN10x3,
|
||||
GPU_TYPE_I16,
|
||||
GPU_TYPE_I16x2,
|
||||
|
@ -577,8 +580,9 @@ typedef enum {
|
|||
GPU_PHASE_DEPTH_EARLY = (1 << 6),
|
||||
GPU_PHASE_DEPTH_LATE = (1 << 7),
|
||||
GPU_PHASE_COLOR = (1 << 8),
|
||||
GPU_PHASE_TRANSFER = (1 << 9),
|
||||
GPU_PHASE_ALL = (1 << 10)
|
||||
GPU_PHASE_COPY = (1 << 9),
|
||||
GPU_PHASE_CLEAR = (1 << 10),
|
||||
GPU_PHASE_BLIT = (1 << 11)
|
||||
} gpu_phase;
|
||||
|
||||
typedef enum {
|
||||
|
|
|
@ -106,11 +106,13 @@ typedef enum {
|
|||
GPU_MEMORY_BUFFER_DOWNLOAD,
|
||||
GPU_MEMORY_TEXTURE_COLOR,
|
||||
GPU_MEMORY_TEXTURE_D16,
|
||||
GPU_MEMORY_TEXTURE_D24,
|
||||
GPU_MEMORY_TEXTURE_D32F,
|
||||
GPU_MEMORY_TEXTURE_D24S8,
|
||||
GPU_MEMORY_TEXTURE_D32FS8,
|
||||
GPU_MEMORY_TEXTURE_LAZY_COLOR,
|
||||
GPU_MEMORY_TEXTURE_LAZY_D16,
|
||||
GPU_MEMORY_TEXTURE_LAZY_D24,
|
||||
GPU_MEMORY_TEXTURE_LAZY_D32F,
|
||||
GPU_MEMORY_TEXTURE_LAZY_D24S8,
|
||||
GPU_MEMORY_TEXTURE_LAZY_D32FS8,
|
||||
|
@ -184,7 +186,7 @@ static struct {
|
|||
VkDebugUtilsMessengerEXT messenger;
|
||||
gpu_allocator allocators[GPU_MEMORY_COUNT];
|
||||
uint8_t allocatorLookup[GPU_MEMORY_COUNT];
|
||||
gpu_memory memory[256];
|
||||
gpu_memory memory[1024];
|
||||
uint32_t streamCount;
|
||||
uint32_t tick[2];
|
||||
gpu_tick ticks[2];
|
||||
|
@ -213,11 +215,11 @@ static void expunge(void);
|
|||
static bool hasLayer(VkLayerProperties* layers, uint32_t count, const char* layer);
|
||||
static bool hasExtension(VkExtensionProperties* extensions, uint32_t count, const char* extension);
|
||||
static VkBufferUsageFlags getBufferUsage(gpu_buffer_type type);
|
||||
static bool transitionAttachment(gpu_texture* texture, bool begin, bool resolve, bool discard, VkImageMemoryBarrier* barrier);
|
||||
static bool transitionAttachment(gpu_texture* texture, bool begin, bool resolve, bool discard, VkImageMemoryBarrier2KHR* barrier);
|
||||
static VkImageLayout getNaturalLayout(uint32_t usage, VkImageAspectFlags aspect);
|
||||
static VkFormat convertFormat(gpu_texture_format format, int colorspace);
|
||||
static VkPipelineStageFlags convertPhase(gpu_phase phase, bool dst);
|
||||
static VkAccessFlags convertCache(gpu_cache cache);
|
||||
static VkPipelineStageFlags2 convertPhase(gpu_phase phase, bool dst);
|
||||
static VkAccessFlags2 convertCache(gpu_cache cache);
|
||||
static VkBool32 relay(VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagsEXT flags, const VkDebugUtilsMessengerCallbackDataEXT* data, void* userdata);
|
||||
static void nickname(void* object, VkObjectType type, const char* name);
|
||||
static bool vcheck(VkResult result, const char* message);
|
||||
|
@ -275,7 +277,7 @@ static bool check(bool condition, const char* message);
|
|||
X(vkWaitForFences)\
|
||||
X(vkCreateSemaphore)\
|
||||
X(vkDestroySemaphore)\
|
||||
X(vkCmdPipelineBarrier)\
|
||||
X(vkCmdPipelineBarrier2KHR)\
|
||||
X(vkCreateQueryPool)\
|
||||
X(vkDestroyQueryPool)\
|
||||
X(vkCmdResetQueryPool)\
|
||||
|
@ -412,6 +414,7 @@ bool gpu_texture_init(gpu_texture* texture, gpu_texture_info* info) {
|
|||
|
||||
switch (info->format) {
|
||||
case GPU_FORMAT_D16: texture->aspect = VK_IMAGE_ASPECT_DEPTH_BIT; break;
|
||||
case GPU_FORMAT_D24: texture->aspect = VK_IMAGE_ASPECT_DEPTH_BIT; break;
|
||||
case GPU_FORMAT_D32F: texture->aspect = VK_IMAGE_ASPECT_DEPTH_BIT; break;
|
||||
case GPU_FORMAT_D24S8: texture->aspect = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; break;
|
||||
case GPU_FORMAT_D32FS8: texture->aspect = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; break;
|
||||
|
@ -436,20 +439,22 @@ bool gpu_texture_init(gpu_texture* texture, gpu_texture_info* info) {
|
|||
return gpu_texture_init_view(texture, &viewInfo);
|
||||
}
|
||||
|
||||
bool mutableFormat = info->srgb && (info->usage & GPU_TEXTURE_STORAGE);
|
||||
|
||||
VkImageCreateInfo imageInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
||||
.flags =
|
||||
(info->type == GPU_TEXTURE_3D ? VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT : 0) |
|
||||
(info->type == GPU_TEXTURE_CUBE ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0) |
|
||||
(info->srgb ? VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT : 0),
|
||||
(mutableFormat ? (VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT) : 0),
|
||||
.imageType = imageTypes[info->type],
|
||||
.format = convertFormat(texture->format, LINEAR),
|
||||
.format = convertFormat(texture->format, info->srgb),
|
||||
.extent.width = info->size[0],
|
||||
.extent.height = info->size[1],
|
||||
.extent.depth = texture->layers ? 1 : info->size[2],
|
||||
.mipLevels = info->mipmaps,
|
||||
.arrayLayers = texture->layers ? texture->layers : 1,
|
||||
.samples = info->samples,
|
||||
.samples = info->samples ? info->samples : 1,
|
||||
.usage =
|
||||
(((info->usage & GPU_TEXTURE_RENDER) && texture->aspect == VK_IMAGE_ASPECT_COLOR_BIT) ? VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT : 0) |
|
||||
(((info->usage & GPU_TEXTURE_RENDER) && texture->aspect != VK_IMAGE_ASPECT_COLOR_BIT) ? VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT : 0) |
|
||||
|
@ -464,7 +469,7 @@ bool gpu_texture_init(gpu_texture* texture, gpu_texture_info* info) {
|
|||
|
||||
VkFormat formats[2];
|
||||
VkImageFormatListCreateInfo imageFormatList;
|
||||
if (info->srgb && state.extensions.formatList) {
|
||||
if (mutableFormat && state.extensions.formatList) {
|
||||
imageFormatList = (VkImageFormatListCreateInfo) {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO,
|
||||
.viewFormatCount = COUNTOF(formats),
|
||||
|
@ -472,12 +477,9 @@ bool gpu_texture_init(gpu_texture* texture, gpu_texture_info* info) {
|
|||
};
|
||||
|
||||
formats[0] = imageInfo.format;
|
||||
formats[1] = convertFormat(texture->format, SRGB);
|
||||
|
||||
if (formats[0] != formats[1]) {
|
||||
imageFormatList.pNext = imageInfo.pNext;
|
||||
imageInfo.pNext = &imageFormatList;
|
||||
}
|
||||
formats[1] = convertFormat(texture->format, LINEAR);
|
||||
imageFormatList.pNext = imageInfo.pNext;
|
||||
imageInfo.pNext = &imageFormatList;
|
||||
}
|
||||
|
||||
VK(vkCreateImage(state.device, &imageInfo, NULL, &texture->handle), "Could not create texture") return false;
|
||||
|
@ -488,6 +490,7 @@ bool gpu_texture_init(gpu_texture* texture, gpu_texture_info* info) {
|
|||
|
||||
switch (info->format) {
|
||||
case GPU_FORMAT_D16: memoryType = transient ? GPU_MEMORY_TEXTURE_LAZY_D16 : GPU_MEMORY_TEXTURE_D16; break;
|
||||
case GPU_FORMAT_D24: memoryType = transient ? GPU_MEMORY_TEXTURE_LAZY_D24 : GPU_MEMORY_TEXTURE_D24; break;
|
||||
case GPU_FORMAT_D32F: memoryType = transient ? GPU_MEMORY_TEXTURE_LAZY_D32F : GPU_MEMORY_TEXTURE_D32F; break;
|
||||
case GPU_FORMAT_D24S8: memoryType = transient ? GPU_MEMORY_TEXTURE_LAZY_D24S8 : GPU_MEMORY_TEXTURE_D24S8; break;
|
||||
case GPU_FORMAT_D32FS8: memoryType = transient ? GPU_MEMORY_TEXTURE_LAZY_D32FS8 : GPU_MEMORY_TEXTURE_D32FS8; break;
|
||||
|
@ -506,7 +509,6 @@ bool gpu_texture_init(gpu_texture* texture, gpu_texture_info* info) {
|
|||
}
|
||||
|
||||
bool needsView = info->usage & (GPU_TEXTURE_RENDER | GPU_TEXTURE_SAMPLE | GPU_TEXTURE_STORAGE);
|
||||
if (info->usage == GPU_TEXTURE_STORAGE && info->srgb) needsView = false;
|
||||
|
||||
if (needsView && !gpu_texture_init_view(texture, &viewInfo)) {
|
||||
vkDestroyImage(state.device, texture->handle, NULL);
|
||||
|
@ -520,11 +522,11 @@ bool gpu_texture_init(gpu_texture* texture, gpu_texture_info* info) {
|
|||
uint32_t levelCount = info->upload.levelCount;
|
||||
gpu_buffer* buffer = info->upload.buffer;
|
||||
|
||||
VkPipelineStageFlags prev, next;
|
||||
VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
VkImageMemoryBarrier transition = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
VkImageMemoryBarrier2KHR transition = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2_KHR,
|
||||
.image = image,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
.newLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
.subresourceRange.aspectMask = texture->aspect,
|
||||
.subresourceRange.baseMipLevel = 0,
|
||||
.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS,
|
||||
|
@ -532,10 +534,24 @@ bool gpu_texture_init(gpu_texture* texture, gpu_texture_info* info) {
|
|||
.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS
|
||||
};
|
||||
|
||||
VkDependencyInfoKHR barrier = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO_KHR,
|
||||
.pImageMemoryBarriers = &transition,
|
||||
.imageMemoryBarrierCount = 1
|
||||
};
|
||||
|
||||
if (levelCount > 0) {
|
||||
VkBufferImageCopy regions[16];
|
||||
transition.srcStageMask = VK_PIPELINE_STAGE_2_NONE_KHR;
|
||||
transition.dstStageMask = VK_PIPELINE_STAGE_2_COPY_BIT_KHR;
|
||||
transition.srcAccessMask = VK_ACCESS_2_NONE_KHR;
|
||||
transition.dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR;
|
||||
transition.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
transition.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
vkCmdPipelineBarrier2KHR(commands, &barrier);
|
||||
|
||||
VkBufferImageCopy copies[16];
|
||||
for (uint32_t i = 0; i < levelCount; i++) {
|
||||
regions[i] = (VkBufferImageCopy) {
|
||||
copies[i] = (VkBufferImageCopy) {
|
||||
.bufferOffset = info->upload.levelOffsets[i],
|
||||
.imageSubresource.aspectMask = texture->aspect,
|
||||
.imageSubresource.mipLevel = i,
|
||||
|
@ -547,27 +563,20 @@ bool gpu_texture_init(gpu_texture* texture, gpu_texture_info* info) {
|
|||
};
|
||||
}
|
||||
|
||||
// Upload initial contents
|
||||
prev = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
next = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
transition.srcAccessMask = 0;
|
||||
transition.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
transition.oldLayout = layout;
|
||||
transition.newLayout = layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
vkCmdPipelineBarrier(commands, prev, next, 0, 0, NULL, 0, NULL, 1, &transition);
|
||||
vkCmdCopyBufferToImage(commands, buffer->handle, image, layout, levelCount, regions);
|
||||
vkCmdCopyBufferToImage(commands, buffer->handle, image, transition.newLayout, levelCount, copies);
|
||||
|
||||
// Generate mipmaps
|
||||
if (info->upload.generateMipmaps) {
|
||||
prev = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
next = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
transition.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
transition.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
transition.srcStageMask = VK_PIPELINE_STAGE_2_COPY_BIT_KHR;
|
||||
transition.dstStageMask = VK_PIPELINE_STAGE_2_BLIT_BIT_KHR;
|
||||
transition.srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR;
|
||||
transition.dstAccessMask = VK_ACCESS_2_TRANSFER_READ_BIT_KHR;
|
||||
transition.oldLayout = transition.newLayout;
|
||||
transition.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
transition.subresourceRange.baseMipLevel = 0;
|
||||
transition.subresourceRange.levelCount = levelCount;
|
||||
transition.oldLayout = layout;
|
||||
transition.newLayout = layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
vkCmdPipelineBarrier(commands, prev, next, 0, 0, NULL, 0, NULL, 1, &transition);
|
||||
vkCmdPipelineBarrier2KHR(commands, &barrier);
|
||||
|
||||
for (uint32_t i = levelCount; i < info->mipmaps; i++) {
|
||||
VkImageBlit region = {
|
||||
.srcSubresource = {
|
||||
|
@ -584,25 +593,30 @@ bool gpu_texture_init(gpu_texture* texture, gpu_texture_info* info) {
|
|||
.dstOffsets[1] = { MAX(info->size[0] >> i, 1), MAX(info->size[1] >> i, 1), 1 }
|
||||
};
|
||||
vkCmdBlitImage(commands, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion, VK_FILTER_LINEAR);
|
||||
transition.subresourceRange.baseMipLevel = i;
|
||||
transition.subresourceRange.levelCount = 1;
|
||||
|
||||
transition.srcStageMask = VK_PIPELINE_STAGE_2_BLIT_BIT_KHR;
|
||||
transition.dstStageMask = VK_PIPELINE_STAGE_2_BLIT_BIT_KHR;
|
||||
transition.srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR;
|
||||
transition.dstAccessMask = VK_ACCESS_2_TRANSFER_READ_BIT_KHR;
|
||||
transition.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
transition.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
vkCmdPipelineBarrier(commands, prev, next, 0, 0, NULL, 0, NULL, 1, &transition);
|
||||
transition.subresourceRange.baseMipLevel = i;
|
||||
transition.subresourceRange.levelCount = 1;
|
||||
vkCmdPipelineBarrier2KHR(commands, &barrier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Transition to natural layout
|
||||
prev = levelCount > 0 ? VK_PIPELINE_STAGE_TRANSFER_BIT : VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||
next = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
transition.srcAccessMask = levelCount > 0 ? VK_ACCESS_TRANSFER_WRITE_BIT : 0;
|
||||
transition.dstAccessMask = 0;
|
||||
transition.oldLayout = layout;
|
||||
transition.srcStageMask = VK_PIPELINE_STAGE_2_COPY_BIT_KHR | VK_PIPELINE_STAGE_2_BLIT_BIT_KHR;
|
||||
transition.dstStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR;
|
||||
transition.srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR;
|
||||
transition.dstAccessMask = VK_ACCESS_2_MEMORY_READ_BIT_KHR | VK_ACCESS_2_MEMORY_WRITE_BIT_KHR;
|
||||
transition.oldLayout = transition.newLayout;
|
||||
transition.newLayout = texture->layout;
|
||||
transition.subresourceRange.baseMipLevel = 0;
|
||||
transition.subresourceRange.levelCount = info->mipmaps;
|
||||
vkCmdPipelineBarrier(commands, prev, next, 0, 0, NULL, 0, NULL, 1, &transition);
|
||||
vkCmdPipelineBarrier2KHR(commands, &barrier);
|
||||
}
|
||||
|
||||
texture->memory = memory - state.memory;
|
||||
|
@ -638,6 +652,11 @@ bool gpu_texture_init_view(gpu_texture* texture, gpu_texture_view_info* info) {
|
|||
((info->usage & GPU_TEXTURE_STORAGE) && !texture->srgb ? VK_IMAGE_USAGE_STORAGE_BIT : 0)
|
||||
};
|
||||
|
||||
if (usage.usage == 0) {
|
||||
texture->view = VK_NULL_HANDLE;
|
||||
return true;
|
||||
}
|
||||
|
||||
VkImageViewCreateInfo createInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
||||
.pNext = &usage,
|
||||
|
@ -657,6 +676,8 @@ bool gpu_texture_init_view(gpu_texture* texture, gpu_texture_view_info* info) {
|
|||
return false;
|
||||
}
|
||||
|
||||
nickname(texture->view, VK_OBJECT_TYPE_IMAGE_VIEW, info->label);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -976,31 +997,28 @@ void gpu_layout_destroy(gpu_layout* layout) {
|
|||
// Shader
|
||||
|
||||
bool gpu_shader_init(gpu_shader* shader, gpu_shader_info* info) {
|
||||
struct { VkShaderStageFlags flags; gpu_shader_stage* source; } stages[] = {
|
||||
{ VK_SHADER_STAGE_VERTEX_BIT, &info->vertex },
|
||||
{ VK_SHADER_STAGE_FRAGMENT_BIT, &info->fragment },
|
||||
{ VK_SHADER_STAGE_COMPUTE_BIT, &info->compute }
|
||||
};
|
||||
|
||||
uint32_t stageCount = 0;
|
||||
VkShaderStageFlags stageFlags = 0;
|
||||
for (uint32_t i = 0; i < COUNTOF(stages); i++) {
|
||||
if (!stages[i].source->code) continue;
|
||||
for (uint32_t i = 0; i < info->stageCount; i++) {
|
||||
switch (info->stages[i].stage) {
|
||||
case GPU_STAGE_VERTEX: stageFlags |= VK_SHADER_STAGE_VERTEX_BIT; break;
|
||||
case GPU_STAGE_FRAGMENT: stageFlags |= VK_SHADER_STAGE_FRAGMENT_BIT; break;
|
||||
case GPU_STAGE_COMPUTE: stageFlags |= VK_SHADER_STAGE_COMPUTE_BIT; break;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < info->stageCount; i++) {
|
||||
VkShaderModuleCreateInfo moduleInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
|
||||
.codeSize = stages[i].source->length,
|
||||
.pCode = stages[i].source->code
|
||||
.codeSize = info->stages[i].length,
|
||||
.pCode = info->stages[i].code
|
||||
};
|
||||
|
||||
VK(vkCreateShaderModule(state.device, &moduleInfo, NULL, &shader->handles[stageCount]), "Failed to load shader") {
|
||||
VK(vkCreateShaderModule(state.device, &moduleInfo, NULL, &shader->handles[i]), "Failed to load shader") {
|
||||
return false;
|
||||
}
|
||||
|
||||
nickname(shader->handles[i], VK_OBJECT_TYPE_SHADER_MODULE, info->label);
|
||||
|
||||
stageFlags |= stages[i].flags;
|
||||
stageCount++;
|
||||
}
|
||||
|
||||
VkDescriptorSetLayout layouts[4];
|
||||
|
@ -1215,7 +1233,7 @@ bool gpu_pass_init(gpu_pass* pass, gpu_pass_info* info) {
|
|||
for (uint32_t i = 0; i < info->colorCount; i++) {
|
||||
references[i] = (VkAttachmentReference2) {
|
||||
.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2,
|
||||
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
.layout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR,
|
||||
.attachment = i
|
||||
};
|
||||
|
||||
|
@ -1236,7 +1254,7 @@ bool gpu_pass_init(gpu_pass* pass, gpu_pass_info* info) {
|
|||
|
||||
references[index] = (VkAttachmentReference2) {
|
||||
.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2,
|
||||
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
.layout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR,
|
||||
.attachment = index
|
||||
};
|
||||
|
||||
|
@ -1259,7 +1277,7 @@ bool gpu_pass_init(gpu_pass* pass, gpu_pass_info* info) {
|
|||
|
||||
references[index] = (VkAttachmentReference2) {
|
||||
.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2,
|
||||
.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
||||
.layout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR,
|
||||
.attachment = index
|
||||
};
|
||||
|
||||
|
@ -1278,7 +1296,7 @@ bool gpu_pass_init(gpu_pass* pass, gpu_pass_info* info) {
|
|||
if (info->resolveDepth) {
|
||||
references[index + 1] = (VkAttachmentReference2) {
|
||||
.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2,
|
||||
.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
||||
.layout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR,
|
||||
.attachment = index + 1
|
||||
};
|
||||
|
||||
|
@ -1357,6 +1375,7 @@ bool gpu_pipeline_init_graphics(gpu_pipeline* pipeline, gpu_pipeline_info* info)
|
|||
[GPU_TYPE_U8x4] = VK_FORMAT_R8G8B8A8_UINT,
|
||||
[GPU_TYPE_SN8x4] = VK_FORMAT_R8G8B8A8_SNORM,
|
||||
[GPU_TYPE_UN8x4] = VK_FORMAT_R8G8B8A8_UNORM,
|
||||
[GPU_TYPE_SN10x3] = VK_FORMAT_A2B10G10R10_SNORM_PACK32,
|
||||
[GPU_TYPE_UN10x3] = VK_FORMAT_A2B10G10R10_UNORM_PACK32,
|
||||
[GPU_TYPE_I16] = VK_FORMAT_R16_SINT,
|
||||
[GPU_TYPE_I16x2] = VK_FORMAT_R16G16_SINT,
|
||||
|
@ -1578,7 +1597,7 @@ bool gpu_pipeline_init_graphics(gpu_pipeline* pipeline, gpu_pipeline_info* info)
|
|||
.pData = (const void*) constants
|
||||
};
|
||||
|
||||
uint32_t stageCount = info->shader->handles[1] && info->pass->colorCount > 0 ? 2 : 1;
|
||||
uint32_t stageCount = info->shader->handles[1] ? 2 : 1;
|
||||
|
||||
VkPipelineShaderStageCreateInfo shaders[2] = {
|
||||
{
|
||||
|
@ -1781,7 +1800,7 @@ void gpu_render_begin(gpu_stream* stream, gpu_canvas* canvas) {
|
|||
// Layout transitions
|
||||
|
||||
uint32_t barrierCount = 0;
|
||||
VkImageMemoryBarrier barriers[10];
|
||||
VkImageMemoryBarrier2KHR barriers[10];
|
||||
|
||||
bool BEGIN = true;
|
||||
bool RESOLVE = true;
|
||||
|
@ -1799,13 +1818,11 @@ void gpu_render_begin(gpu_stream* stream, gpu_canvas* canvas) {
|
|||
}
|
||||
|
||||
if (barrierCount > 0) {
|
||||
VkPipelineStageFlags srcStage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||
VkPipelineStageFlags dstStage =
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
|
||||
vkCmdPipelineBarrier(stream->commands, srcStage, dstStage, 0, 0, NULL, 0, NULL, barrierCount, barriers);
|
||||
vkCmdPipelineBarrier2KHR(stream->commands, &(VkDependencyInfoKHR) {
|
||||
.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO_KHR,
|
||||
.imageMemoryBarrierCount = barrierCount,
|
||||
.pImageMemoryBarriers = barriers
|
||||
});
|
||||
}
|
||||
|
||||
// Do it!
|
||||
|
@ -1834,7 +1851,7 @@ void gpu_render_end(gpu_stream* stream, gpu_canvas* canvas) {
|
|||
// Layout transitions
|
||||
|
||||
uint32_t barrierCount = 0;
|
||||
VkImageMemoryBarrier barriers[10];
|
||||
VkImageMemoryBarrier2KHR barriers[10];
|
||||
|
||||
bool BEGIN = true;
|
||||
bool RESOLVE = true;
|
||||
|
@ -1849,13 +1866,11 @@ void gpu_render_end(gpu_stream* stream, gpu_canvas* canvas) {
|
|||
barrierCount += transitionAttachment(canvas->depth.resolve, !BEGIN, RESOLVE, !DISCARD, &barriers[barrierCount]);
|
||||
|
||||
if (barrierCount > 0) {
|
||||
VkPipelineStageFlags srcStage =
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
VkPipelineStageFlags dstStage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||
|
||||
vkCmdPipelineBarrier(stream->commands, srcStage, dstStage, 0, 0, NULL, 0, NULL, barrierCount, barriers);
|
||||
vkCmdPipelineBarrier2KHR(stream->commands, &(VkDependencyInfoKHR) {
|
||||
.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO_KHR,
|
||||
.imageMemoryBarrierCount = barrierCount,
|
||||
.pImageMemoryBarriers = barriers
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2055,20 +2070,22 @@ void gpu_blit(gpu_stream* stream, gpu_texture* src, gpu_texture* dst, uint32_t s
|
|||
}
|
||||
|
||||
void gpu_sync(gpu_stream* stream, gpu_barrier* barriers, uint32_t count) {
|
||||
VkMemoryBarrier memoryBarrier = { .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER };
|
||||
VkPipelineStageFlags src = 0;
|
||||
VkPipelineStageFlags dst = 0;
|
||||
VkMemoryBarrier2KHR memoryBarrier = { .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2_KHR };
|
||||
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
gpu_barrier* barrier = &barriers[i];
|
||||
src |= convertPhase(barrier->prev, false);
|
||||
dst |= convertPhase(barrier->next, true);
|
||||
memoryBarrier.srcStageMask |= convertPhase(barrier->prev, false);
|
||||
memoryBarrier.dstStageMask |= convertPhase(barrier->next, true);
|
||||
memoryBarrier.srcAccessMask |= convertCache(barrier->flush);
|
||||
memoryBarrier.dstAccessMask |= convertCache(barrier->clear);
|
||||
}
|
||||
|
||||
if (src && dst) {
|
||||
vkCmdPipelineBarrier(stream->commands, src, dst, 0, 1, &memoryBarrier, 0, NULL, 0, NULL);
|
||||
if (memoryBarrier.srcStageMask && memoryBarrier.dstStageMask) {
|
||||
vkCmdPipelineBarrier2KHR(stream->commands, &(VkDependencyInfoKHR) {
|
||||
.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO_KHR,
|
||||
.pMemoryBarriers = &memoryBarrier,
|
||||
.memoryBarrierCount = 1
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2081,67 +2098,49 @@ void gpu_tally_finish(gpu_stream* stream, gpu_tally* tally, uint32_t index) {
|
|||
}
|
||||
|
||||
void gpu_tally_mark(gpu_stream* stream, gpu_tally* tally, uint32_t index) {
|
||||
vkCmdWriteTimestamp(stream->commands, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, tally->handle, index);
|
||||
vkCmdWriteTimestamp(stream->commands, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, tally->handle, index);
|
||||
}
|
||||
|
||||
// Acquires an OpenXR swapchain texture, transitioning it to the natural layout
|
||||
void gpu_xr_acquire(gpu_stream* stream, gpu_texture* texture) {
|
||||
VkImageLayout attachmentLayout = texture->aspect == VK_IMAGE_ASPECT_COLOR_BIT ?
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL :
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
|
||||
// If the texture only has the RENDER usage, its natural layout matches the layout that OpenXR
|
||||
// gives us the texture in, so no layout transition is needed.
|
||||
if (texture->layout == attachmentLayout) {
|
||||
return;
|
||||
}
|
||||
|
||||
VkImageMemoryBarrier transition = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.srcAccessMask = 0,
|
||||
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
|
||||
.oldLayout = attachmentLayout,
|
||||
.newLayout = texture->layout,
|
||||
.image = texture->handle,
|
||||
.subresourceRange.aspectMask = texture->aspect,
|
||||
.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS,
|
||||
.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS
|
||||
};
|
||||
|
||||
VkPipelineStageFlags prev = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
VkPipelineStageFlags next = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
|
||||
vkCmdPipelineBarrier(stream->commands, prev, next, 0, 0, NULL, 0, NULL, 1, &transition);
|
||||
vkCmdPipelineBarrier2KHR(stream->commands, &(VkDependencyInfoKHR) {
|
||||
.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO_KHR,
|
||||
.imageMemoryBarrierCount = 1,
|
||||
.pImageMemoryBarriers = &(VkImageMemoryBarrier2KHR) {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2_KHR,
|
||||
.srcStageMask = VK_PIPELINE_STAGE_2_NONE_KHR,
|
||||
.dstStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR,
|
||||
.srcAccessMask = VK_ACCESS_2_NONE_KHR,
|
||||
.dstAccessMask = VK_ACCESS_2_MEMORY_READ_BIT_KHR | VK_ACCESS_2_MEMORY_WRITE_BIT_KHR,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR,
|
||||
.newLayout = texture->layout,
|
||||
.image = texture->handle,
|
||||
.subresourceRange.aspectMask = texture->aspect,
|
||||
.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS,
|
||||
.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Releases an OpenXR swapchain texture, transitioning it back to the layout expected by OpenXR
|
||||
void gpu_xr_release(gpu_stream* stream, gpu_texture* texture) {
|
||||
VkImageLayout attachmentLayout = texture->aspect == VK_IMAGE_ASPECT_COLOR_BIT ?
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL :
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
|
||||
// If the texture only has the RENDER usage, its natural layout matches the layout that OpenXR
|
||||
// expects the texture to be in, so no layout transition is needed.
|
||||
if (texture->layout == attachmentLayout) {
|
||||
return;
|
||||
}
|
||||
|
||||
VkImageMemoryBarrier transition = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
|
||||
.dstAccessMask = 0,
|
||||
.oldLayout = texture->layout,
|
||||
.newLayout = attachmentLayout,
|
||||
.image = texture->handle,
|
||||
.subresourceRange.aspectMask = texture->aspect,
|
||||
.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS,
|
||||
.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS
|
||||
};
|
||||
|
||||
VkPipelineStageFlags prev = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||
VkPipelineStageFlags next = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||
|
||||
vkCmdPipelineBarrier(stream->commands, prev, next, 0, 0, NULL, 0, NULL, 1, &transition);
|
||||
vkCmdPipelineBarrier2KHR(stream->commands, &(VkDependencyInfoKHR) {
|
||||
.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO_KHR,
|
||||
.imageMemoryBarrierCount = 1,
|
||||
.pImageMemoryBarriers = &(VkImageMemoryBarrier2KHR) {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2_KHR,
|
||||
.srcStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR,
|
||||
.dstStageMask = VK_PIPELINE_STAGE_2_NONE_KHR,
|
||||
.srcAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT_KHR,
|
||||
.dstAccessMask = VK_ACCESS_2_NONE_KHR,
|
||||
.oldLayout = texture->layout,
|
||||
.newLayout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR,
|
||||
.image = texture->handle,
|
||||
.subresourceRange.aspectMask = texture->aspect,
|
||||
.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS,
|
||||
.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Entry
|
||||
|
@ -2208,7 +2207,6 @@ bool gpu_init(gpu_config* config) {
|
|||
{ "VK_KHR_portability_enumeration", true, &state.extensions.portability },
|
||||
{ "VK_EXT_debug_utils", config->debug, &state.extensions.debug },
|
||||
{ "VK_EXT_swapchain_colorspace", true, &state.extensions.colorspace },
|
||||
{ "VK_KHR_image_format_list", true, &state.extensions.formatList },
|
||||
{ "VK_KHR_surface", true, &state.extensions.surface },
|
||||
#if defined(_WIN32)
|
||||
{ "VK_KHR_win32_surface", true, &state.extensions.surfaceOS },
|
||||
|
@ -2344,8 +2342,14 @@ bool gpu_init(gpu_config* config) {
|
|||
config->limits->pointSize = limits->pointSizeRange[1];
|
||||
}
|
||||
|
||||
VkPhysicalDeviceSynchronization2FeaturesKHR synchronization2Features = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES_KHR,
|
||||
.synchronization2 = true
|
||||
};
|
||||
|
||||
VkPhysicalDeviceShaderDrawParameterFeatures shaderDrawParameterFeatures = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES,
|
||||
.pNext = &synchronization2Features
|
||||
};
|
||||
|
||||
VkPhysicalDeviceMultiviewFeatures multiviewFeatures = {
|
||||
|
@ -2368,6 +2372,7 @@ bool gpu_init(gpu_config* config) {
|
|||
enable->fullDrawIndexUint32 = true;
|
||||
enable->imageCubeArray = true;
|
||||
enable->independentBlend = true;
|
||||
synchronization2Features.synchronization2 = true;
|
||||
multiviewFeatures.multiview = true;
|
||||
shaderDrawParameterFeatures.shaderDrawParameters = true;
|
||||
|
||||
|
@ -2435,7 +2440,9 @@ bool gpu_init(gpu_config* config) {
|
|||
{ "VK_KHR_swapchain", true, &state.extensions.swapchain },
|
||||
{ "VK_KHR_portability_subset", true, &state.extensions.portability },
|
||||
{ "VK_KHR_depth_stencil_resolve", true, &state.extensions.depthResolve },
|
||||
{ "VK_KHR_shader_non_semantic_info", config->debug, &state.extensions.shaderDebug }
|
||||
{ "VK_KHR_shader_non_semantic_info", config->debug, &state.extensions.shaderDebug },
|
||||
{ "VK_KHR_image_format_list", true, &state.extensions.formatList },
|
||||
{ "VK_KHR_synchronization2", true, NULL }
|
||||
};
|
||||
|
||||
uint32_t extensionCount = 0;
|
||||
|
@ -2559,11 +2566,13 @@ bool gpu_init(gpu_config* config) {
|
|||
struct { VkFormat format; VkImageUsageFlags usage; } imageFlags[] = {
|
||||
[GPU_MEMORY_TEXTURE_COLOR] = { VK_FORMAT_R8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT },
|
||||
[GPU_MEMORY_TEXTURE_D16] = { VK_FORMAT_D16_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT },
|
||||
[GPU_MEMORY_TEXTURE_D24] = { VK_FORMAT_X8_D24_UNORM_PACK32, VK_IMAGE_USAGE_SAMPLED_BIT },
|
||||
[GPU_MEMORY_TEXTURE_D32F] = { VK_FORMAT_D32_SFLOAT, VK_IMAGE_USAGE_SAMPLED_BIT },
|
||||
[GPU_MEMORY_TEXTURE_D24S8] = { VK_FORMAT_D24_UNORM_S8_UINT, VK_IMAGE_USAGE_SAMPLED_BIT },
|
||||
[GPU_MEMORY_TEXTURE_D32FS8] = { VK_FORMAT_D32_SFLOAT_S8_UINT, VK_IMAGE_USAGE_SAMPLED_BIT },
|
||||
[GPU_MEMORY_TEXTURE_LAZY_COLOR] = { VK_FORMAT_R8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | transient },
|
||||
[GPU_MEMORY_TEXTURE_LAZY_D16] = { VK_FORMAT_D16_UNORM, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | transient },
|
||||
[GPU_MEMORY_TEXTURE_LAZY_D24] = { VK_FORMAT_X8_D24_UNORM_PACK32, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | transient },
|
||||
[GPU_MEMORY_TEXTURE_LAZY_D32F] = { VK_FORMAT_D32_SFLOAT, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | transient },
|
||||
[GPU_MEMORY_TEXTURE_LAZY_D24S8] = { VK_FORMAT_D24_UNORM_S8_UINT, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | transient },
|
||||
[GPU_MEMORY_TEXTURE_LAZY_D32FS8] = { VK_FORMAT_D32_SFLOAT_S8_UINT, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | transient }
|
||||
|
@ -2734,7 +2743,7 @@ void gpu_submit(gpu_stream** streams, uint32_t count) {
|
|||
commands[i] = streams[i]->commands;
|
||||
}
|
||||
|
||||
VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR;
|
||||
|
||||
VkSubmitInfo submit = {
|
||||
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||
|
@ -2766,6 +2775,7 @@ bool gpu_wait_tick(uint32_t tick) {
|
|||
|
||||
void gpu_wait_idle(void) {
|
||||
vkDeviceWaitIdle(state.device);
|
||||
state.tick[GPU] = state.tick[CPU];
|
||||
}
|
||||
|
||||
uintptr_t gpu_vk_get_instance(void) {
|
||||
|
@ -2796,11 +2806,13 @@ static gpu_memory* gpu_allocate(gpu_memory_type type, VkMemoryRequirements info,
|
|||
[GPU_MEMORY_BUFFER_DOWNLOAD] = 0,
|
||||
[GPU_MEMORY_TEXTURE_COLOR] = 1 << 28,
|
||||
[GPU_MEMORY_TEXTURE_D16] = 1 << 28,
|
||||
[GPU_MEMORY_TEXTURE_D24] = 1 << 28,
|
||||
[GPU_MEMORY_TEXTURE_D32F] = 1 << 28,
|
||||
[GPU_MEMORY_TEXTURE_D24S8] = 1 << 28,
|
||||
[GPU_MEMORY_TEXTURE_D32FS8] = 1 << 28,
|
||||
[GPU_MEMORY_TEXTURE_LAZY_COLOR] = 1 << 28,
|
||||
[GPU_MEMORY_TEXTURE_LAZY_D16] = 1 << 28,
|
||||
[GPU_MEMORY_TEXTURE_LAZY_D24] = 1 << 28,
|
||||
[GPU_MEMORY_TEXTURE_LAZY_D32F] = 1 << 28,
|
||||
[GPU_MEMORY_TEXTURE_LAZY_D24S8] = 1 << 28,
|
||||
[GPU_MEMORY_TEXTURE_LAZY_D32FS8] = 1 << 28
|
||||
|
@ -2954,43 +2966,43 @@ static VkBufferUsageFlags getBufferUsage(gpu_buffer_type type) {
|
|||
}
|
||||
}
|
||||
|
||||
static bool transitionAttachment(gpu_texture* texture, bool begin, bool resolve, bool discard, VkImageMemoryBarrier* barrier) {
|
||||
if (!texture) {
|
||||
static bool transitionAttachment(gpu_texture* texture, bool begin, bool resolve, bool discard, VkImageMemoryBarrier2KHR* barrier) {
|
||||
if (!texture || texture->layout == VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool depth = texture->aspect != VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
|
||||
VkImageLayout renderLayout = depth ?
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL :
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
VkPipelineStageFlags2 stage = depth ?
|
||||
(VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR | VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR ) :
|
||||
VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR;
|
||||
|
||||
VkAccessFlags access = (depth && !resolve) ?
|
||||
(VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT) :
|
||||
(VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT);
|
||||
|
||||
if (texture->layout == renderLayout) {
|
||||
return false;
|
||||
}
|
||||
VkAccessFlags2 access = (depth && !resolve) ?
|
||||
(VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT_KHR | VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT_KHR) :
|
||||
(VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT_KHR | VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT_KHR);
|
||||
|
||||
if (begin) {
|
||||
*barrier = (VkImageMemoryBarrier) {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.srcAccessMask = 0,
|
||||
*barrier = (VkImageMemoryBarrier2KHR) {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2_KHR,
|
||||
.srcStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR,
|
||||
.srcAccessMask = VK_ACCESS_2_NONE_KHR,
|
||||
.dstStageMask = stage,
|
||||
.dstAccessMask = access,
|
||||
.oldLayout = discard || resolve ? VK_IMAGE_LAYOUT_UNDEFINED : texture->layout,
|
||||
.newLayout = renderLayout,
|
||||
.newLayout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR,
|
||||
.image = texture->handle,
|
||||
.subresourceRange.aspectMask = texture->aspect,
|
||||
.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS,
|
||||
.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS
|
||||
};
|
||||
} else {
|
||||
*barrier = (VkImageMemoryBarrier) {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
*barrier = (VkImageMemoryBarrier2KHR) {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2_KHR,
|
||||
.srcStageMask = stage,
|
||||
.srcAccessMask = access,
|
||||
.dstAccessMask = 0,
|
||||
.oldLayout = renderLayout,
|
||||
.dstStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR,
|
||||
.dstAccessMask = VK_ACCESS_2_NONE_KHR,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR,
|
||||
.newLayout = texture->layout,
|
||||
.image = texture->handle,
|
||||
.subresourceRange.aspectMask = texture->aspect,
|
||||
|
@ -3006,13 +3018,9 @@ static VkImageLayout getNaturalLayout(uint32_t usage, VkImageAspectFlags aspect)
|
|||
if (usage & (GPU_TEXTURE_STORAGE | GPU_TEXTURE_COPY_SRC | GPU_TEXTURE_COPY_DST)) {
|
||||
return VK_IMAGE_LAYOUT_GENERAL;
|
||||
} else if (usage & GPU_TEXTURE_SAMPLE) {
|
||||
return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
return VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL_KHR;
|
||||
} else {
|
||||
if (aspect == VK_IMAGE_ASPECT_COLOR_BIT) {
|
||||
return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
} else {
|
||||
return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
}
|
||||
return VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR;
|
||||
}
|
||||
return VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
}
|
||||
|
@ -3036,6 +3044,7 @@ static VkFormat convertFormat(gpu_texture_format format, int colorspace) {
|
|||
[GPU_FORMAT_RGB10A2] = { VK_FORMAT_A2B10G10R10_UNORM_PACK32, VK_FORMAT_A2B10G10R10_UNORM_PACK32 },
|
||||
[GPU_FORMAT_RG11B10F] = { VK_FORMAT_B10G11R11_UFLOAT_PACK32, VK_FORMAT_B10G11R11_UFLOAT_PACK32 },
|
||||
[GPU_FORMAT_D16] = { VK_FORMAT_D16_UNORM, VK_FORMAT_D16_UNORM },
|
||||
[GPU_FORMAT_D24] = { VK_FORMAT_X8_D24_UNORM_PACK32, VK_FORMAT_X8_D24_UNORM_PACK32 },
|
||||
[GPU_FORMAT_D32F] = { VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT },
|
||||
[GPU_FORMAT_D24S8] = { VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT },
|
||||
[GPU_FORMAT_D32FS8] = { VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT },
|
||||
|
@ -3072,37 +3081,38 @@ static VkFormat convertFormat(gpu_texture_format format, int colorspace) {
|
|||
return formats[format][colorspace];
|
||||
}
|
||||
|
||||
static VkPipelineStageFlags convertPhase(gpu_phase phase, bool dst) {
|
||||
VkPipelineStageFlags flags = 0;
|
||||
if (phase & GPU_PHASE_INDIRECT) flags |= VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
|
||||
if (phase & GPU_PHASE_INPUT_INDEX) flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
|
||||
if (phase & GPU_PHASE_INPUT_VERTEX) flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
|
||||
if (phase & GPU_PHASE_SHADER_VERTEX) flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
|
||||
if (phase & GPU_PHASE_SHADER_FRAGMENT) flags |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
if (phase & GPU_PHASE_SHADER_COMPUTE) flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
|
||||
if (phase & GPU_PHASE_DEPTH_EARLY) flags |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
|
||||
if (phase & GPU_PHASE_DEPTH_LATE) flags |= VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
if (phase & GPU_PHASE_COLOR) flags |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
if (phase & GPU_PHASE_TRANSFER) flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
if (phase & GPU_PHASE_ALL) flags |= dst ? VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT : VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||
static VkPipelineStageFlags2 convertPhase(gpu_phase phase, bool dst) {
|
||||
VkPipelineStageFlags2 flags = 0;
|
||||
if (phase & GPU_PHASE_INDIRECT) flags |= VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT_KHR;
|
||||
if (phase & GPU_PHASE_INPUT_INDEX) flags |= VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT_KHR;
|
||||
if (phase & GPU_PHASE_INPUT_VERTEX) flags |= VK_PIPELINE_STAGE_2_VERTEX_ATTRIBUTE_INPUT_BIT_KHR;
|
||||
if (phase & GPU_PHASE_SHADER_VERTEX) flags |= VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT_KHR;
|
||||
if (phase & GPU_PHASE_SHADER_FRAGMENT) flags |= VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT_KHR;
|
||||
if (phase & GPU_PHASE_SHADER_COMPUTE) flags |= VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT_KHR;
|
||||
if (phase & GPU_PHASE_DEPTH_EARLY) flags |= VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR;
|
||||
if (phase & GPU_PHASE_DEPTH_LATE) flags |= VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR;
|
||||
if (phase & GPU_PHASE_COLOR) flags |= VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR;
|
||||
if (phase & GPU_PHASE_COPY) flags |= VK_PIPELINE_STAGE_2_COPY_BIT_KHR;
|
||||
if (phase & GPU_PHASE_CLEAR) flags |= VK_PIPELINE_STAGE_2_CLEAR_BIT_KHR;
|
||||
if (phase & GPU_PHASE_BLIT) flags |= VK_PIPELINE_STAGE_2_BLIT_BIT_KHR;
|
||||
return flags;
|
||||
}
|
||||
|
||||
static VkAccessFlags convertCache(gpu_cache cache) {
|
||||
VkAccessFlags flags = 0;
|
||||
if (cache & GPU_CACHE_INDIRECT) flags |= VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
|
||||
if (cache & GPU_CACHE_INDEX) flags |= VK_ACCESS_INDEX_READ_BIT;
|
||||
if (cache & GPU_CACHE_VERTEX) flags |= VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
|
||||
if (cache & GPU_CACHE_UNIFORM) flags |= VK_ACCESS_UNIFORM_READ_BIT;
|
||||
if (cache & GPU_CACHE_TEXTURE) flags |= VK_ACCESS_SHADER_READ_BIT;
|
||||
if (cache & GPU_CACHE_STORAGE_READ) flags |= VK_ACCESS_SHADER_READ_BIT;
|
||||
if (cache & GPU_CACHE_STORAGE_WRITE) flags |= VK_ACCESS_SHADER_WRITE_BIT;
|
||||
if (cache & GPU_CACHE_DEPTH_READ) flags |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
|
||||
if (cache & GPU_CACHE_DEPTH_WRITE) flags |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
if (cache & GPU_CACHE_COLOR_READ) flags |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
|
||||
if (cache & GPU_CACHE_COLOR_WRITE) flags |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
if (cache & GPU_CACHE_TRANSFER_READ) flags |= VK_ACCESS_TRANSFER_READ_BIT;
|
||||
if (cache & GPU_CACHE_TRANSFER_WRITE) flags |= VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
static VkAccessFlags2 convertCache(gpu_cache cache) {
|
||||
VkAccessFlags2 flags = 0;
|
||||
if (cache & GPU_CACHE_INDIRECT) flags |= VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT_KHR;
|
||||
if (cache & GPU_CACHE_INDEX) flags |= VK_ACCESS_2_INDEX_READ_BIT_KHR;
|
||||
if (cache & GPU_CACHE_VERTEX) flags |= VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT_KHR;
|
||||
if (cache & GPU_CACHE_UNIFORM) flags |= VK_ACCESS_2_UNIFORM_READ_BIT_KHR;
|
||||
if (cache & GPU_CACHE_TEXTURE) flags |= VK_ACCESS_2_SHADER_SAMPLED_READ_BIT_KHR;
|
||||
if (cache & GPU_CACHE_STORAGE_READ) flags |= VK_ACCESS_2_SHADER_STORAGE_READ_BIT_KHR;
|
||||
if (cache & GPU_CACHE_STORAGE_WRITE) flags |= VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT_KHR;
|
||||
if (cache & GPU_CACHE_DEPTH_READ) flags |= VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT_KHR;
|
||||
if (cache & GPU_CACHE_DEPTH_WRITE) flags |= VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT_KHR;
|
||||
if (cache & GPU_CACHE_COLOR_READ) flags |= VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT_KHR;
|
||||
if (cache & GPU_CACHE_COLOR_WRITE) flags |= VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT_KHR;
|
||||
if (cache & GPU_CACHE_TRANSFER_READ) flags |= VK_ACCESS_2_TRANSFER_READ_BIT_KHR;
|
||||
if (cache & GPU_CACHE_TRANSFER_WRITE) flags |= VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR;
|
||||
return flags;
|
||||
}
|
||||
|
||||
|
|
|
@ -305,6 +305,7 @@ bool gpu_pipeline_init_graphics(gpu_pipeline* pipeline, gpu_pipeline_info* info)
|
|||
[GPU_TYPE_U8x4] = WGPUVertexFormat_Uint8x4,
|
||||
[GPU_TYPE_SN8x4] = WGPUVertexFormat_Snorm8x4,
|
||||
[GPU_TYPE_UN8x4] = WGPUVertexFormat_Unorm8x4,
|
||||
[GPU_TYPE_SN10x3] = WGPUVertexFormat_Undefined,
|
||||
[GPU_TYPE_UN10x3] = WGPUVertexFormat_Undefined,
|
||||
[GPU_TYPE_I16] = WGPUVertexFormat_Undefined,
|
||||
[GPU_TYPE_I16x2] = WGPUVertexFormat_Sint16x2,
|
||||
|
@ -692,6 +693,7 @@ static WGPUTextureFormat convertFormat(gpu_texture_format format, bool srgb) {
|
|||
[GPU_FORMAT_RGB10A2] = {WGPUTextureFormat_RGB10A2Unorm, WGPUTextureFormat_RGB10A2Unorm },
|
||||
[GPU_FORMAT_RG11B10F] = { WGPUTextureFormat_RG11B10Ufloat, WGPUTextureFormat_RG11B10Ufloat },
|
||||
[GPU_FORMAT_D16] = { WGPUTextureFormat_Depth16Unorm, WGPUTextureFormat_Depth16Unorm },
|
||||
[GPU_FORMAT_D24] = { WGPUTextureFormat_Depth24Plus, WGPUTextureFormat_Depth24Plus },
|
||||
[GPU_FORMAT_D32F] = { WGPUTextureFormat_Depth32Float, WGPUTextureFormat_Depth32Float },
|
||||
[GPU_FORMAT_D24S8] = { WGPUTextureFormat_Depth24PlusStencil8, WGPUTextureFormat_Depth24PlusStencil8 },
|
||||
[GPU_FORMAT_D32FS8] = { WGPUTextureFormat_Depth32FloatStencil8, WGPUTextureFormat_Depth32FloatStencil8 },
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
#include "job.h"
|
||||
#include <stdatomic.h>
|
||||
#include <threads.h>
|
||||
#include <string.h>
|
||||
|
||||
#define MAX_WORKERS 64
|
||||
#define MAX_JOBS 1024
|
||||
|
||||
struct job {
|
||||
job* next;
|
||||
fn_job* fn;
|
||||
void* arg;
|
||||
atomic_uint done;
|
||||
};
|
||||
|
||||
static struct {
|
||||
job jobs[MAX_JOBS];
|
||||
thrd_t workers[MAX_WORKERS];
|
||||
uint32_t workerCount;
|
||||
job* head;
|
||||
job* tail;
|
||||
job* pool;
|
||||
cnd_t hasJob;
|
||||
mtx_t lock;
|
||||
bool quit;
|
||||
} state;
|
||||
|
||||
// Must hold lock, this will unlock it, state.head must exist
|
||||
static void runJob(void) {
|
||||
job* job = state.head;
|
||||
state.head = job->next;
|
||||
if (!job->next) state.tail = NULL;
|
||||
mtx_unlock(&state.lock);
|
||||
|
||||
job->fn(job->arg);
|
||||
job->done = true;
|
||||
}
|
||||
|
||||
static int workerLoop(void* arg) {
|
||||
for (;;) {
|
||||
mtx_lock(&state.lock);
|
||||
|
||||
while (!state.head && !state.quit) {
|
||||
cnd_wait(&state.hasJob, &state.lock);
|
||||
}
|
||||
|
||||
if (state.quit) {
|
||||
break;
|
||||
}
|
||||
|
||||
runJob();
|
||||
}
|
||||
|
||||
mtx_unlock(&state.lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool job_init(uint32_t count) {
|
||||
mtx_init(&state.lock, mtx_plain);
|
||||
cnd_init(&state.hasJob);
|
||||
|
||||
state.pool = state.jobs;
|
||||
for (uint32_t i = 0; i < MAX_JOBS - 1; i++) {
|
||||
state.jobs[i].next = &state.jobs[i + 1];
|
||||
}
|
||||
|
||||
if (count > MAX_WORKERS) count = MAX_WORKERS;
|
||||
for (uint32_t i = 0; i < count; i++, state.workerCount++) {
|
||||
if (thrd_create(&state.workers[i], workerLoop, (void*) (uintptr_t) i) != thrd_success) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void job_destroy(void) {
|
||||
state.quit = true;
|
||||
cnd_broadcast(&state.hasJob);
|
||||
for (uint32_t i = 0; i < state.workerCount; i++) {
|
||||
thrd_join(state.workers[i], NULL);
|
||||
}
|
||||
cnd_destroy(&state.hasJob);
|
||||
mtx_destroy(&state.lock);
|
||||
memset(&state, 0, sizeof(state));
|
||||
}
|
||||
|
||||
job* job_start(fn_job* fn, void* arg) {
|
||||
mtx_lock(&state.lock);
|
||||
|
||||
if (!state.pool) {
|
||||
mtx_unlock(&state.lock);
|
||||
fn(arg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
job* job = state.pool;
|
||||
state.pool = job->next;
|
||||
|
||||
if (state.tail) {
|
||||
state.tail->next = job;
|
||||
state.tail = job;
|
||||
} else {
|
||||
state.head = job;
|
||||
state.tail = job;
|
||||
cnd_signal(&state.hasJob);
|
||||
}
|
||||
|
||||
job->next = NULL;
|
||||
job->done = false;
|
||||
job->fn = fn;
|
||||
job->arg = arg;
|
||||
|
||||
mtx_unlock(&state.lock);
|
||||
return job;
|
||||
}
|
||||
|
||||
void job_wait(job* job) {
|
||||
if (!job) return;
|
||||
|
||||
while (!job->done) {
|
||||
mtx_lock(&state.lock);
|
||||
|
||||
if (state.head) {
|
||||
runJob();
|
||||
} else {
|
||||
mtx_unlock(&state.lock);
|
||||
thrd_yield();
|
||||
}
|
||||
}
|
||||
|
||||
mtx_lock(&state.lock);
|
||||
job->next = state.pool;
|
||||
state.pool = job;
|
||||
mtx_unlock(&state.lock);
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef struct job job;
|
||||
typedef void fn_job(void* arg);
|
||||
|
||||
bool job_init(uint32_t workerCount);
|
||||
void job_destroy(void);
|
||||
job* job_start(fn_job* fn, void* arg);
|
||||
void job_wait(job* job);
|
|
@ -160,6 +160,8 @@ void os_open_console(void);
|
|||
double os_get_time(void);
|
||||
void os_sleep(double seconds);
|
||||
void os_request_permission(os_permission permission);
|
||||
const char* os_get_clipboard_text(void);
|
||||
void os_set_clipboard_text(const char* text);
|
||||
|
||||
void* os_vm_init(size_t size);
|
||||
bool os_vm_free(void* p, size_t size);
|
||||
|
|
|
@ -269,6 +269,14 @@ void os_request_permission(os_permission permission) {
|
|||
}
|
||||
}
|
||||
|
||||
const char* os_get_clipboard_text(void) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void os_set_clipboard_text(const char* text) {
|
||||
//
|
||||
}
|
||||
|
||||
void* os_vm_init(size_t size) {
|
||||
return mmap(NULL, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
#ifndef LOVR_USE_GLFW
|
||||
|
||||
const char* os_get_clipboard_text(void) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void os_set_clipboard_text(const char* text) {
|
||||
//
|
||||
}
|
||||
|
||||
void os_poll_events(void) {
|
||||
//
|
||||
}
|
||||
|
@ -317,12 +325,22 @@ static int convertKey(os_key key) {
|
|||
case OS_KEY_RIGHT: return GLFW_KEY_RIGHT;
|
||||
case OS_KEY_LEFT_SHIFT: return GLFW_KEY_LEFT_SHIFT;
|
||||
case OS_KEY_RIGHT_SHIFT: return GLFW_KEY_RIGHT_SHIFT;
|
||||
case OS_KEY_LEFT_CONTROL: return GLFW_KEY_LEFT_CONTROL;
|
||||
case OS_KEY_RIGHT_CONTROL: return GLFW_KEY_RIGHT_CONTROL;
|
||||
case OS_KEY_ESCAPE: return GLFW_KEY_ESCAPE;
|
||||
case OS_KEY_F5: return GLFW_KEY_F5;
|
||||
default: return GLFW_KEY_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
const char* os_get_clipboard_text(void) {
|
||||
return glfwGetClipboardString(NULL);
|
||||
}
|
||||
|
||||
void os_set_clipboard_text(const char* text) {
|
||||
glfwSetClipboardString(NULL, text);
|
||||
}
|
||||
|
||||
void os_poll_events(void) {
|
||||
if (glfwState.window) {
|
||||
glfwPollEvents();
|
||||
|
|
|
@ -246,6 +246,14 @@ void os_request_permission(os_permission permission) {
|
|||
//
|
||||
}
|
||||
|
||||
const char* os_get_clipboard_text(void) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void os_set_clipboard_text(const char* text) {
|
||||
//
|
||||
}
|
||||
|
||||
void os_thread_attach(void) {
|
||||
//
|
||||
}
|
||||
|
|
141
src/core/spv.c
141
src/core/spv.c
|
@ -20,8 +20,7 @@ typedef union {
|
|||
uint16_t name;
|
||||
} attribute;
|
||||
struct {
|
||||
uint8_t set;
|
||||
uint8_t binding;
|
||||
uint16_t decoration;
|
||||
uint16_t name;
|
||||
} variable;
|
||||
struct {
|
||||
|
@ -220,8 +219,12 @@ static spv_result spv_parse_decoration(spv_context* spv, const uint32_t* op, spv
|
|||
case 1: spv->cache[id].flag.number = op[3]; break; // SpecID
|
||||
case 6: spv->cache[id].type.arrayStride = op[3]; break; // ArrayStride (overrides name)
|
||||
case 30: spv->cache[id].attribute.location = op[3]; break; // Location
|
||||
case 33: spv->cache[id].variable.binding = op[3]; break; // Binding
|
||||
case 34: spv->cache[id].variable.set = op[3]; break; // Set
|
||||
case 33:
|
||||
case 34:
|
||||
if (spv->cache[id].variable.decoration == 0xffff) {
|
||||
spv->cache[id].variable.decoration = op - spv->words;
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
|
@ -352,11 +355,8 @@ static spv_result spv_parse_variable(spv_context* spv, const uint32_t* op, spv_i
|
|||
return spv_parse_field(spv, type, info->pushConstants, info);
|
||||
}
|
||||
|
||||
uint32_t set = spv->cache[variableId].variable.set;
|
||||
uint32_t binding = spv->cache[variableId].variable.binding;
|
||||
|
||||
// Ignore output variables (storageClass 3) and anything without a set/binding decoration
|
||||
if (storageClass == 3 || set == 0xff || binding == 0xff) {
|
||||
if (storageClass == 3 || spv->cache[variableId].variable.decoration == 0xffff) {
|
||||
return SPV_OK;
|
||||
}
|
||||
|
||||
|
@ -374,8 +374,38 @@ static spv_result spv_parse_variable(spv_context* spv, const uint32_t* op, spv_i
|
|||
|
||||
spv_resource* resource = &info->resources[info->resourceCount++];
|
||||
|
||||
resource->set = set;
|
||||
resource->binding = binding;
|
||||
// Resolve the set/binding pointers. The cache stores the index of the first set/binding
|
||||
// decoration word, we need to search for the "other" one.
|
||||
const uint32_t* word = spv->words + spv->cache[variableId].variable.decoration;
|
||||
bool set = word[2] == 34;
|
||||
uint32_t other = set ? 33 : 34;
|
||||
|
||||
if (set) {
|
||||
resource->set = &word[3];
|
||||
resource->binding = NULL;
|
||||
} else {
|
||||
resource->set = NULL;
|
||||
resource->binding = &word[3];
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
const uint32_t* next = word + OP_LENGTH(word);
|
||||
|
||||
if (word == next || next > spv->edge || (OP_CODE(next) != 71 && OP_CODE(next) != 72)) {
|
||||
break;
|
||||
}
|
||||
|
||||
word = next;
|
||||
|
||||
if (OP_CODE(word) == 71 && word[1] == variableId && word[2] == other) {
|
||||
if (set) {
|
||||
resource->binding = &word[3];
|
||||
} else {
|
||||
resource->set = &word[3];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If it's an array, read the array size and unwrap the inner type
|
||||
if (OP_CODE(type) == 28) { // OpTypeArray
|
||||
|
@ -394,9 +424,9 @@ static spv_result spv_parse_variable(spv_context* spv, const uint32_t* op, spv_i
|
|||
return SPV_INVALID;
|
||||
}
|
||||
|
||||
resource->count = length[3];
|
||||
resource->arraySize = length[3];
|
||||
} else {
|
||||
resource->count = 0;
|
||||
resource->arraySize = 0;
|
||||
}
|
||||
|
||||
// Buffers
|
||||
|
@ -413,12 +443,12 @@ static spv_result spv_parse_variable(spv_context* spv, const uint32_t* op, spv_i
|
|||
}
|
||||
|
||||
info->fieldCount++;
|
||||
resource->fields = spv->fields++;
|
||||
resource->fields[0].offset = 0;
|
||||
resource->fields[0].name = resource->name;
|
||||
return spv_parse_field(spv, type, resource->fields, info);
|
||||
resource->bufferFields = spv->fields++;
|
||||
resource->bufferFields[0].offset = 0;
|
||||
resource->bufferFields[0].name = resource->name;
|
||||
return spv_parse_field(spv, type, resource->bufferFields, info);
|
||||
} else {
|
||||
resource->fields = NULL;
|
||||
resource->bufferFields = NULL;
|
||||
}
|
||||
|
||||
// Sampler and texture variables are named directly
|
||||
|
@ -431,39 +461,78 @@ static spv_result spv_parse_variable(spv_context* spv, const uint32_t* op, spv_i
|
|||
return SPV_OK;
|
||||
}
|
||||
|
||||
// Combined image samplers are currently not supported (ty webgpu)
|
||||
resource->textureFlags = 0;
|
||||
|
||||
// Unwrap combined image samplers
|
||||
if (OP_CODE(type) == 27) { // OpTypeSampledImage
|
||||
resource->type = SPV_COMBINED_TEXTURE_SAMPLER;
|
||||
return SPV_OK;
|
||||
if (!spv_load_type(spv, type[2], &type)) {
|
||||
return SPV_INVALID;
|
||||
}
|
||||
} else if (OP_CODE(type) != 25) { // OpTypeImage
|
||||
return SPV_INVALID;
|
||||
}
|
||||
} else {
|
||||
// Texel buffers use the DimBuffer dimensionality
|
||||
if (type[3] == 5) {
|
||||
resource->dimension = SPV_TEXTURE_1D;
|
||||
switch (type[7]) {
|
||||
case 1: resource->type = SPV_UNIFORM_TEXEL_BUFFER; return SPV_OK;
|
||||
case 2: resource->type = SPV_STORAGE_TEXEL_BUFFER; return SPV_OK;
|
||||
default: return SPV_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
// Texel buffers use the DimBuffer dimensionality
|
||||
if (type[3] == 5) {
|
||||
// Input attachments use the DimSubpassData dimensionality, and "Sampled" must be 2
|
||||
if (type[3] == 6) {
|
||||
if (type[7] == 2) {
|
||||
resource->type = SPV_INPUT_ATTACHMENT;
|
||||
return SPV_OK;
|
||||
} else {
|
||||
return SPV_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
// Read the Sampled key to determine if it's a sampled image (1) or a storage image (2)
|
||||
switch (type[7]) {
|
||||
case 1: resource->type = SPV_UNIFORM_TEXEL_BUFFER; return SPV_OK;
|
||||
case 2: resource->type = SPV_STORAGE_TEXEL_BUFFER; return SPV_OK;
|
||||
case 1: resource->type = SPV_SAMPLED_TEXTURE; break;
|
||||
case 2: resource->type = SPV_STORAGE_TEXTURE; break;
|
||||
default: return SPV_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
// Input attachments use the DimSubpassData dimensionality, and "Sampled" must be 2
|
||||
if (type[3] == 6) {
|
||||
if (type[7] == 2) {
|
||||
resource->type = SPV_INPUT_ATTACHMENT;
|
||||
return SPV_OK;
|
||||
} else {
|
||||
return SPV_INVALID;
|
||||
}
|
||||
const uint32_t* texelType = NULL;
|
||||
if (!spv_load_type(spv, type[2], &texelType)) {
|
||||
return SPV_INVALID;
|
||||
}
|
||||
|
||||
// Read the Sampled key to determine if it's a sampled image (1) or a storage image (2)
|
||||
switch (type[7]) {
|
||||
case 1: resource->type = SPV_SAMPLED_TEXTURE; return SPV_OK;
|
||||
case 2: resource->type = SPV_STORAGE_TEXTURE; return SPV_OK;
|
||||
if (OP_CODE(texelType) == 21) { // OpTypeInt
|
||||
resource->textureFlags |= SPV_TEXTURE_INTEGER;
|
||||
}
|
||||
|
||||
switch (type[3]) {
|
||||
case 0: resource->dimension = SPV_TEXTURE_1D; break;
|
||||
case 1: resource->dimension = SPV_TEXTURE_2D; break;
|
||||
case 2: resource->dimension = SPV_TEXTURE_3D; break;
|
||||
case 3: resource->dimension = SPV_TEXTURE_2D; resource->textureFlags |= SPV_TEXTURE_CUBE; break;
|
||||
case 4: resource->dimension = SPV_TEXTURE_2D; break;
|
||||
case 5: return SPV_INVALID; // Handled above
|
||||
case 6: return SPV_INVALID; // Handled above
|
||||
default: return SPV_INVALID;
|
||||
}
|
||||
|
||||
if (type[4] == 1) {
|
||||
resource->textureFlags |= SPV_TEXTURE_SHADOW;
|
||||
}
|
||||
|
||||
if (type[5] == 1) {
|
||||
resource->textureFlags |= SPV_TEXTURE_ARRAY;
|
||||
}
|
||||
|
||||
if (type[6] == 1) {
|
||||
resource->textureFlags |= SPV_TEXTURE_MULTISAMPLE;
|
||||
}
|
||||
|
||||
return SPV_OK;
|
||||
}
|
||||
|
||||
static spv_result spv_parse_field(spv_context* spv, const uint32_t* word, spv_field* field, spv_info* info) {
|
||||
|
|
|
@ -64,13 +64,29 @@ typedef enum {
|
|||
SPV_INPUT_ATTACHMENT
|
||||
} spv_resource_type;
|
||||
|
||||
typedef enum {
|
||||
SPV_TEXTURE_1D,
|
||||
SPV_TEXTURE_2D,
|
||||
SPV_TEXTURE_3D
|
||||
} spv_texture_dimension;
|
||||
|
||||
enum {
|
||||
SPV_TEXTURE_CUBE = (1 << 0),
|
||||
SPV_TEXTURE_ARRAY = (1 << 1),
|
||||
SPV_TEXTURE_SHADOW = (1 << 2),
|
||||
SPV_TEXTURE_MULTISAMPLE = (1 << 3),
|
||||
SPV_TEXTURE_INTEGER = (1 << 4)
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint32_t set;
|
||||
uint32_t binding;
|
||||
const uint32_t* set;
|
||||
const uint32_t* binding;
|
||||
const char* name;
|
||||
uint32_t arraySize;
|
||||
spv_resource_type type;
|
||||
uint32_t count;
|
||||
spv_field* fields;
|
||||
spv_texture_dimension dimension;
|
||||
uint32_t textureFlags;
|
||||
spv_field* bufferFields;
|
||||
} spv_resource;
|
||||
|
||||
typedef struct {
|
||||
|
|
|
@ -92,35 +92,35 @@ typedef uintmax_t atomic_uintmax_t;
|
|||
|
||||
// 7.17.7
|
||||
|
||||
#define atomic_store(p, x) __atomic_store(p, x, __ATOMIC_SEQ_CST)
|
||||
#define atomic_store_explicit __atomic_store
|
||||
#define atomic_store_explicit __atomic_store_n
|
||||
#define atomic_store(p, x) atomic_store_explicit(p, x, __ATOMIC_SEQ_CST)
|
||||
|
||||
#define atomic_load(p, x) __atomic_load(p, x, __ATOMIC_SEQ_CST)
|
||||
#define atomic_load_explicit __atomic_load
|
||||
#define atomic_load_explicit __atomic_load_n
|
||||
#define atomic_load(p) atomic_load_explicit(p, __ATOMIC_SEQ_CST)
|
||||
|
||||
#define atomic_exchange(p, x) __atomic_exchange(p, x, __ATOMIC_SEQ_CST)
|
||||
#define atomic_exchange_explicit __atomic_exchange
|
||||
#define atomic_exchange_explicit __atomic_exchange_n
|
||||
#define atomic_exchange(p, x) atomic_exchange_explicit(p, x, __ATOMIC_SEQ_CST)
|
||||
|
||||
#define atomic_compare_exchange_strong(p, x, y) __atomic_compare_exchange(p, x, y, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
|
||||
#define atomic_compare_exchange_strong_explicit(p, x, y, o1, o2) __atomic_compare_exchange(p, x, y, false, o1, o2)
|
||||
#define atomic_compare_exchange_strong_explicit(p, x, y, o1, o2) __atomic_compare_exchange_n(p, x, y, false, o1, o2)
|
||||
#define atomic_compare_exchange_strong(p, x, y) atomic_compare_exchange_strong_explicit(p, x, y, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
|
||||
|
||||
#define atomic_compare_exchange_weak(p, x, y) __atomic_compare_exchange(p, x, y, true, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
|
||||
#define atomic_compare_exchange_weak_explicit(p, x, y, o1, o2) __atomic_compare_exchange(p, x, y, true, o1, o2)
|
||||
#define atomic_compare_exchange_weak_explicit(p, x, y, o1, o2) __atomic_compare_exchange_n(p, x, y, true, o1, o2)
|
||||
#define atomic_compare_exchange_weak(p, x, y) atomic_compare_exchange_weak_explicit(p, x, y, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
|
||||
|
||||
#define atomic_fetch_add(p, x) __atomic_fetch_add(p, x, __ATOMIC_SEQ_CST)
|
||||
#define atomic_fetch_add_explicit __atomic_fetch_add
|
||||
#define atomic_fetch_add(p, x) atomic_fetch_add_explicit(p, x, __ATOMIC_SEQ_CST)
|
||||
|
||||
#define atomic_fetch_sub(p, x) __atomic_fetch_sub(p, x, __ATOMIC_SEQ_CST)
|
||||
#define atomic_fetch_sub_explicit __atomic_fetch_sub
|
||||
#define atomic_fetch_sub(p, x) atomic_fetch_sub_explicit(p, x, __ATOMIC_SEQ_CST)
|
||||
|
||||
#define atomic_fetch_or(p, x) __atomic_fetch_or(p, x, __ATOMIC_SEQ_CST)
|
||||
#define atomic_fetch_or_explicit __atomic_fetch_or
|
||||
#define atomic_fetch_or(p, x) atomic_fetch_or_explicit(p, x, __ATOMIC_SEQ_CST)
|
||||
|
||||
#define atomic_fetch_xor(p, x) __atomic_fetch_xor(p, x, __ATOMIC_SEQ_CST)
|
||||
#define atomic_fetch_xor_explicit __atomic_fetch_xor
|
||||
#define atomic_fetch_xor(p, x) atomic_fetch_xor_explicit(p, x, __ATOMIC_SEQ_CST)
|
||||
|
||||
#define atomic_fetch_and(p, x) __atomic_fetch_and(p, x, __ATOMIC_SEQ_CST)
|
||||
#define atomic_fetch_and_explicit __atomic_fetch_and
|
||||
#define atomic_fetch_and(p, x) atomic_fetch_and_explicit(p, x, __ATOMIC_SEQ_CST)
|
||||
|
||||
// 7.17.8
|
||||
|
||||
|
@ -145,8 +145,26 @@ _Bool atomic_flag_clear_explicit(volatile atomic_flag*, memory_order);
|
|||
|
||||
typedef volatile long atomic_uint;
|
||||
|
||||
#define atomic_store(p, x) *(p) = (x);
|
||||
#define atomic_store_explicit(p, x, o) atomic_store(p, x)
|
||||
|
||||
#define atomic_load(p) *(p)
|
||||
#define atomic_load_explicit(p, o) atomic_load(p)
|
||||
|
||||
#define atomic_fetch_add(p, x) _InterlockedExchangeAdd(p, x)
|
||||
#define atomic_fetch_add_explicit(p, x, o) atomic_fetch_add(p, x)
|
||||
|
||||
#define atomic_fetch_sub(p, x) _InterlockedExchangeAdd(p, -(x))
|
||||
#define atomic_fetch_sub_explicit(p, x, o) atomic_fetch_sub(p, x)
|
||||
|
||||
#define atomic_fetch_or(p, x) InterlockedOr(p, x)
|
||||
#define atomic_fetch_or_explicit(p, x, o) atomic_fetch_or(p, x)
|
||||
|
||||
#define atomic_fetch_xor(p, x) InterlockedXor(p, x)
|
||||
#define atomic_fetch_xor_explicit(p, x, o) atomic_fetch_xor(p, x)
|
||||
|
||||
#define atomic_fetch_and(p, x) InterlockedAnd(p, x)
|
||||
#define atomic_fetch_and_explicit(p, x, o) atomic_fetch_and(p, x)
|
||||
|
||||
#define ATOMIC_INT_LOCK_FREE 2
|
||||
|
||||
|
|
|
@ -13,11 +13,13 @@ enum { mtx_plain };
|
|||
typedef HANDLE thrd_t;
|
||||
typedef CRITICAL_SECTION mtx_t;
|
||||
typedef CONDITION_VARIABLE cnd_t;
|
||||
#define thread_local __declspec(thread)
|
||||
#else
|
||||
#include <pthread.h>
|
||||
typedef pthread_t thrd_t;
|
||||
typedef pthread_mutex_t mtx_t;
|
||||
typedef pthread_cond_t cnd_t;
|
||||
#define thread_local _Thread_local
|
||||
#endif
|
||||
|
||||
static inline int thrd_create(thrd_t* thread, thrd_start_t fn, void* arg);
|
||||
|
|
12
src/main.c
12
src/main.c
|
@ -10,6 +10,12 @@
|
|||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static void run(void* T) {
|
||||
while (luax_resume(T, 0) == LUA_YIELD) {
|
||||
os_sleep(0.);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
os_init();
|
||||
|
||||
|
@ -37,12 +43,8 @@ int main(int argc, char** argv) {
|
|||
}
|
||||
|
||||
lua_State* T = lua_tothread(L, -1);
|
||||
lovrSetErrorCallback(luax_vthrow, T);
|
||||
lovrSetLogCallback(luax_vlog, T);
|
||||
|
||||
while (luax_resume(T, 0) == LUA_YIELD) {
|
||||
os_sleep(0.);
|
||||
}
|
||||
lovrTry(run, T, luax_vthrow, T);
|
||||
|
||||
if (lua_type(T, 1) == LUA_TSTRING && !strcmp(lua_tostring(T, 1), "restart")) {
|
||||
luax_checkvariant(T, 2, &cookie);
|
||||
|
|
|
@ -229,7 +229,7 @@ void lovrAudioDestroy(void) {
|
|||
if (atomic_fetch_sub(&state.ref, 1) != 1) return;
|
||||
for (size_t i = 0; i < 2; i++) {
|
||||
ma_device_uninit(&state.devices[i]);
|
||||
free(state.deviceInfo[i]);
|
||||
lovrFree(state.deviceInfo[i]);
|
||||
}
|
||||
Source* source;
|
||||
FOREACH_SOURCE(source) lovrRelease(source, lovrSourceDestroy);
|
||||
|
@ -267,8 +267,7 @@ bool lovrAudioGetDevice(AudioType type, AudioDevice* device) {
|
|||
}
|
||||
|
||||
if (!state.deviceInfo[type]) {
|
||||
state.deviceInfo[type] = malloc(sizeof(ma_device_info));
|
||||
lovrAssert(state.deviceInfo[type], "Out of memory");
|
||||
state.deviceInfo[type] = lovrMalloc(sizeof(ma_device_info));
|
||||
}
|
||||
|
||||
ma_device_info* info = state.deviceInfo[type];
|
||||
|
@ -291,8 +290,8 @@ bool lovrAudioSetDevice(AudioType type, void* id, size_t size, Sound* sink, Audi
|
|||
lovrRetain(sink);
|
||||
}
|
||||
|
||||
lovrAssert(!sink || lovrSoundGetChannelLayout(sink) != CHANNEL_AMBISONIC, "Ambisonic Sounds cannot be used as sinks");
|
||||
lovrAssert(!sink || lovrSoundIsStream(sink), "Sinks must be streams");
|
||||
lovrCheck(!sink || lovrSoundGetChannelLayout(sink) != CHANNEL_AMBISONIC, "Ambisonic Sounds cannot be used as sinks");
|
||||
lovrCheck(!sink || lovrSoundIsStream(sink), "Sinks must be streams");
|
||||
|
||||
ma_device_uninit(&state.devices[type]);
|
||||
lovrRelease(state.sinks[type], lovrSoundDestroy);
|
||||
|
@ -407,9 +406,8 @@ void lovrAudioSetAbsorption(float absorption[3]) {
|
|||
// Source
|
||||
|
||||
Source* lovrSourceCreate(Sound* sound, bool pitchable, bool spatial, uint32_t effects) {
|
||||
lovrAssert(lovrSoundGetChannelLayout(sound) != CHANNEL_AMBISONIC, "Ambisonic Sources are not currently supported");
|
||||
Source* source = calloc(1, sizeof(Source));
|
||||
lovrAssert(source, "Out of memory");
|
||||
lovrCheck(lovrSoundGetChannelLayout(sound) != CHANNEL_AMBISONIC, "Ambisonic Sources are not currently supported");
|
||||
Source* source = lovrCalloc(sizeof(Source));
|
||||
source->ref = 1;
|
||||
source->index = ~0u;
|
||||
source->sound = sound;
|
||||
|
@ -432,8 +430,7 @@ Source* lovrSourceCreate(Sound* sound, bool pitchable, bool spatial, uint32_t ef
|
|||
config.allowDynamicSampleRate = pitchable;
|
||||
|
||||
if (pitchable || config.formatIn != config.formatOut || config.channelsIn != config.channelsOut || config.sampleRateIn != config.sampleRateOut) {
|
||||
source->converter = malloc(sizeof(ma_data_converter));
|
||||
lovrAssert(source->converter, "Out of memory");
|
||||
source->converter = lovrMalloc(sizeof(ma_data_converter));
|
||||
ma_result status = ma_data_converter_init(&config, NULL, source->converter);
|
||||
lovrAssert(status == MA_SUCCESS, "Problem creating Source data converter: %s (%d)", ma_result_description(status), status);
|
||||
}
|
||||
|
@ -442,8 +439,7 @@ Source* lovrSourceCreate(Sound* sound, bool pitchable, bool spatial, uint32_t ef
|
|||
}
|
||||
|
||||
Source* lovrSourceClone(Source* source) {
|
||||
Source* clone = calloc(1, sizeof(Source));
|
||||
lovrAssert(clone, "Out of memory");
|
||||
Source* clone = lovrCalloc(sizeof(Source));
|
||||
clone->ref = 1;
|
||||
clone->index = ~0u;
|
||||
clone->sound = source->sound;
|
||||
|
@ -460,8 +456,7 @@ Source* lovrSourceClone(Source* source) {
|
|||
clone->pitchable = source->pitchable;
|
||||
clone->spatial = source->spatial;
|
||||
if (source->converter) {
|
||||
clone->converter = malloc(sizeof(ma_data_converter));
|
||||
lovrAssert(clone->converter, "Out of memory");
|
||||
clone->converter = lovrMalloc(sizeof(ma_data_converter));
|
||||
ma_data_converter_config config = ma_data_converter_config_init_default();
|
||||
config.formatIn = source->converter->formatIn;
|
||||
config.formatOut = source->converter->formatOut;
|
||||
|
@ -480,8 +475,8 @@ void lovrSourceDestroy(void* ref) {
|
|||
Source* source = ref;
|
||||
lovrRelease(source->sound, lovrSoundDestroy);
|
||||
ma_data_converter_uninit(source->converter, NULL);
|
||||
free(source->converter);
|
||||
free(source);
|
||||
lovrFree(source->converter);
|
||||
lovrFree(source);
|
||||
}
|
||||
|
||||
Sound* lovrSourceGetSound(Source* source) {
|
||||
|
@ -530,7 +525,7 @@ bool lovrSourceIsLooping(Source* source) {
|
|||
}
|
||||
|
||||
void lovrSourceSetLooping(Source* source, bool loop) {
|
||||
lovrAssert(loop == false || lovrSoundIsStream(source->sound) == false, "Can't loop streams");
|
||||
lovrCheck(loop == false || lovrSoundIsStream(source->sound) == false, "Can't loop streams");
|
||||
source->looping = loop;
|
||||
}
|
||||
|
||||
|
|
|
@ -150,8 +150,7 @@ bool phonon_init(void) {
|
|||
state.renderingSettings.frameSize = BUFFER_SIZE;
|
||||
state.renderingSettings.convolutionType = IPL_CONVOLUTIONTYPE_PHONON;
|
||||
|
||||
state.scratchpad = malloc(BUFFER_SIZE * 4 * sizeof(float));
|
||||
if (!state.scratchpad) return phonon_destroy(), false;
|
||||
state.scratchpad = lovrMalloc(BUFFER_SIZE * 4 * sizeof(float));
|
||||
|
||||
IPLHrtfParams hrtfParams = {
|
||||
.type = IPL_HRTFDATABASETYPE_DEFAULT
|
||||
|
@ -167,7 +166,7 @@ bool phonon_init(void) {
|
|||
}
|
||||
|
||||
void phonon_destroy(void) {
|
||||
if (state.scratchpad) free(state.scratchpad);
|
||||
if (state.scratchpad) lovrFree(state.scratchpad);
|
||||
for (size_t i = 0; i < MAX_SOURCES; i++) {
|
||||
if (state.binauralEffect[i]) phonon_iplDestroyBinauralEffect(&state.binauralEffect[i]);
|
||||
if (state.directSoundEffect[i]) phonon_iplDestroyDirectSoundEffect(&state.directSoundEffect[i]);
|
||||
|
@ -334,8 +333,7 @@ bool phonon_setGeometry(float* vertices, uint32_t* indices, uint32_t vertexCount
|
|||
.irradianceMinDistance = .1f
|
||||
};
|
||||
|
||||
IPLint32* triangleMaterials = malloc(indexCount / 3 * sizeof(IPLint32));
|
||||
if (!triangleMaterials) goto fail;
|
||||
IPLint32* triangleMaterials = lovrMalloc(indexCount / 3 * sizeof(IPLint32));
|
||||
|
||||
for (uint32_t i = 0; i < indexCount / 3; i++) {
|
||||
triangleMaterials[i] = material;
|
||||
|
@ -356,11 +354,11 @@ bool phonon_setGeometry(float* vertices, uint32_t* indices, uint32_t vertexCount
|
|||
status = phonon_iplCreateEnvironmentalRenderer(state.context, state.environment, state.renderingSettings, AMBISONIC, NULL, NULL, &state.environmentalRenderer);
|
||||
if (status != IPL_STATUS_SUCCESS) goto fail;
|
||||
|
||||
free(triangleMaterials);
|
||||
lovrFree(triangleMaterials);
|
||||
return true;
|
||||
|
||||
fail:
|
||||
free(triangleMaterials);
|
||||
lovrFree(triangleMaterials);
|
||||
if (state.mesh) phonon_iplDestroyStaticMesh(&state.mesh);
|
||||
if (state.scene) phonon_iplDestroyScene(&state.scene);
|
||||
if (state.environment) phonon_iplDestroyEnvironment(&state.environment);
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
Blob* lovrBlobCreate(void* data, size_t size, const char* name) {
|
||||
Blob* blob = calloc(1, sizeof(Blob));
|
||||
lovrAssert(blob, "Out of memory");
|
||||
Blob* blob = lovrMalloc(sizeof(Blob));
|
||||
blob->ref = 1;
|
||||
blob->data = data;
|
||||
blob->size = size;
|
||||
|
@ -14,6 +13,6 @@ Blob* lovrBlobCreate(void* data, size_t size, const char* name) {
|
|||
|
||||
void lovrBlobDestroy(void* ref) {
|
||||
Blob* blob = ref;
|
||||
free(blob->data);
|
||||
free(blob);
|
||||
lovrFree(blob->data);
|
||||
lovrFree(blob);
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ static size_t measure(uint32_t w, uint32_t h, TextureFormat format) {
|
|||
case FORMAT_RGB10A2: return w * h * 4;
|
||||
case FORMAT_RG11B10F: return w * h * 4;
|
||||
case FORMAT_D16: return w * h * 2;
|
||||
case FORMAT_D24: return w * h * 4;
|
||||
case FORMAT_D32F: return w * h * 4;
|
||||
case FORMAT_D24S8: return w * h * 4;
|
||||
case FORMAT_D32FS8: return w * h * 5;
|
||||
|
@ -83,9 +84,8 @@ Image* lovrImageCreateRaw(uint32_t width, uint32_t height, TextureFormat format,
|
|||
lovrCheck(width > 0 && height > 0, "Image dimensions must be positive");
|
||||
lovrCheck(format < FORMAT_BC1, "Blank images cannot be compressed");
|
||||
size_t size = measure(width, height, format);
|
||||
void* data = malloc(size);
|
||||
Image* image = calloc(1, sizeof(Image));
|
||||
lovrAssert(image && data, "Out of memory");
|
||||
void* data = lovrMalloc(size);
|
||||
Image* image = lovrCalloc(sizeof(Image));
|
||||
image->ref = 1;
|
||||
image->flags = srgb ? IMAGE_SRGB : 0;
|
||||
image->width = width;
|
||||
|
@ -120,7 +120,7 @@ Image* lovrImageCreateFromFile(Blob* blob) {
|
|||
void lovrImageDestroy(void* ref) {
|
||||
Image* image = ref;
|
||||
lovrRelease(image->blob, lovrBlobDestroy);
|
||||
free(image);
|
||||
lovrFree(image);
|
||||
}
|
||||
|
||||
bool lovrImageIsSRGB(Image* image) {
|
||||
|
@ -138,6 +138,7 @@ bool lovrImageIsCube(Image* image) {
|
|||
bool lovrImageIsDepth(Image* image) {
|
||||
switch (image->format) {
|
||||
case FORMAT_D16:
|
||||
case FORMAT_D24:
|
||||
case FORMAT_D32F:
|
||||
case FORMAT_D24S8:
|
||||
case FORMAT_D32FS8:
|
||||
|
@ -209,7 +210,7 @@ static void setPixelRGBA32F(float* src, ImagePointer dst) { for (uint32_t i = 0;
|
|||
|
||||
void lovrImageGetPixel(Image* image, uint32_t x, uint32_t y, float pixel[4]) {
|
||||
lovrCheck(!lovrImageIsCompressed(image), "Unable to access individual pixels of a compressed image");
|
||||
lovrAssert(x < image->width && y < image->height, "Pixel coordinates must be within Image bounds");
|
||||
lovrCheck(x < image->width && y < image->height, "Pixel coordinates must be within Image bounds");
|
||||
size_t offset = measure(y * image->width + x, 1, image->format);
|
||||
ImagePointer p = { .u8 = (uint8_t*) image->mipmaps[0].data + offset };
|
||||
switch (image->format) {
|
||||
|
@ -228,7 +229,7 @@ void lovrImageGetPixel(Image* image, uint32_t x, uint32_t y, float pixel[4]) {
|
|||
|
||||
void lovrImageSetPixel(Image* image, uint32_t x, uint32_t y, float pixel[4]) {
|
||||
lovrCheck(!lovrImageIsCompressed(image), "Unable to access individual pixels of a compressed image");
|
||||
lovrAssert(x < image->width && y < image->height, "Pixel coordinates must be within Image bounds");
|
||||
lovrCheck(x < image->width && y < image->height, "Pixel coordinates must be within Image bounds");
|
||||
size_t offset = measure(y * image->width + x, 1, image->format);
|
||||
ImagePointer p = { .u8 = (uint8_t*) image->mipmaps[0].data + offset };
|
||||
switch (image->format) {
|
||||
|
@ -278,12 +279,12 @@ void lovrImageMapPixel(Image* image, uint32_t x0, uint32_t y0, uint32_t w, uint3
|
|||
}
|
||||
|
||||
void lovrImageCopy(Image* src, Image* dst, uint32_t srcOffset[2], uint32_t dstOffset[2], uint32_t extent[2]) {
|
||||
lovrAssert(src->format == dst->format, "To copy between Images, their formats must match");
|
||||
lovrAssert(!lovrImageIsCompressed(src), "Compressed Images cannot be copied");
|
||||
lovrAssert(dstOffset[0] + extent[0] <= dst->width, "Image copy region extends past the destination image width");
|
||||
lovrAssert(dstOffset[1] + extent[1] <= dst->height, "Image copy region extends past the destination image height");
|
||||
lovrAssert(srcOffset[0] + extent[0] <= src->width, "Image copy region extends past the source image width");
|
||||
lovrAssert(srcOffset[1] + extent[1] <= src->height, "Image copy region extends past the source image height");
|
||||
lovrCheck(src->format == dst->format, "To copy between Images, their formats must match");
|
||||
lovrCheck(!lovrImageIsCompressed(src), "Compressed Images cannot be copied");
|
||||
lovrCheck(dstOffset[0] + extent[0] <= dst->width, "Image copy region extends past the destination image width");
|
||||
lovrCheck(dstOffset[1] + extent[1] <= dst->height, "Image copy region extends past the destination image height");
|
||||
lovrCheck(srcOffset[0] + extent[0] <= src->width, "Image copy region extends past the source image width");
|
||||
lovrCheck(srcOffset[1] + extent[1] <= src->height, "Image copy region extends past the source image height");
|
||||
size_t pixelSize = measure(1, 1, src->format);
|
||||
uint8_t* p = (uint8_t*) lovrImageGetLayerData(src, 0, 0) + (srcOffset[1] * src->width + srcOffset[0]) * pixelSize;
|
||||
uint8_t* q = (uint8_t*) lovrImageGetLayerData(dst, 0, 0) + (dstOffset[1] * dst->width + dstOffset[0]) * pixelSize;
|
||||
|
@ -320,7 +321,7 @@ static uint32_t crc32(uint8_t* data, size_t length) {
|
|||
}
|
||||
|
||||
Blob* lovrImageEncode(Image* image) {
|
||||
lovrAssert(image->format == FORMAT_RGBA8, "Only images with the rgba8 format can be encoded");
|
||||
lovrCheck(image->format == FORMAT_RGBA8, "Currently, only images with the rgba8 format can be encoded");
|
||||
uint32_t w = image->width;
|
||||
uint32_t h = image->height;
|
||||
uint8_t* pixels = (uint8_t*) image->blob->data;
|
||||
|
@ -350,8 +351,7 @@ Blob* lovrImageEncode(Image* image) {
|
|||
size += 4 + strlen("IHDR") + sizeof(header) + 4;
|
||||
size += 4 + strlen("IDAT") + idatSize + 4;
|
||||
size += 4 + strlen("IEND") + 4;
|
||||
uint8_t* data = malloc(size);
|
||||
lovrAssert(data, "Out of memory");
|
||||
uint8_t* data = lovrMalloc(size);
|
||||
|
||||
crc_init();
|
||||
uint32_t crc;
|
||||
|
@ -755,7 +755,7 @@ static Image* loadDDS(Blob* blob) {
|
|||
default: lovrThrow("DDS file uses an unsupported DXGI format (%d)", header10->dxgiFormat);
|
||||
}
|
||||
|
||||
lovrAssert(header10->resourceDimension != D3D10_RESOURCE_DIMENSION_TEXTURE3D, "Loading 3D DDS images is not supported");
|
||||
lovrCheck(header10->resourceDimension != D3D10_RESOURCE_DIMENSION_TEXTURE3D, "Loading 3D DDS images is not supported");
|
||||
layers = header10->arraySize;
|
||||
|
||||
if (header10->miscFlag & DDS_RESOURCE_MISC_TEXTURECUBE) {
|
||||
|
@ -787,11 +787,10 @@ static Image* loadDDS(Blob* blob) {
|
|||
lovrThrow("DDS file uses an unsupported format"); // TODO could handle more uncompressed formats
|
||||
}
|
||||
|
||||
lovrAssert(~header->flags & DDSD_DEPTH, "Loading 3D DDS images is not supported");
|
||||
lovrCheck(~header->flags & DDSD_DEPTH, "Loading 3D DDS images is not supported");
|
||||
uint32_t levels = MAX(1, header->mipmapCount);
|
||||
|
||||
Image* image = calloc(1, offsetof(Image, mipmaps) + levels * sizeof(Mipmap));
|
||||
lovrAssert(image, "Out of memory");
|
||||
Image* image = lovrCalloc(offsetof(Image, mipmaps) + levels * sizeof(Mipmap));
|
||||
image->ref = 1;
|
||||
image->flags = flags;
|
||||
image->width = header->width;
|
||||
|
@ -870,8 +869,7 @@ static Image* loadASTC(Blob* blob) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
Image* image = calloc(1, sizeof(Image));
|
||||
lovrAssert(image, "Out of memory");
|
||||
Image* image = lovrCalloc(sizeof(Image));
|
||||
image->ref = 1;
|
||||
image->width = width;
|
||||
image->height = height;
|
||||
|
@ -927,15 +925,14 @@ static Image* loadKTX1(Blob* blob) {
|
|||
data += header.bytesOfKeyValueData;
|
||||
length -= header.bytesOfKeyValueData;
|
||||
|
||||
lovrAssert(header.pixelWidth > 0, "KTX image dimensions must be positive");
|
||||
lovrAssert(header.pixelHeight > 0, "Unable to load 1D KTX images");
|
||||
lovrAssert(header.pixelDepth == 0, "Unable to load 3D KTX images");
|
||||
lovrCheck(header.pixelWidth > 0, "KTX image dimensions must be positive");
|
||||
lovrCheck(header.pixelHeight > 0, "Unable to load 1D KTX images");
|
||||
lovrCheck(header.pixelDepth == 0, "Unable to load 3D KTX images");
|
||||
|
||||
uint32_t layers = MAX(header.numberOfArrayElements, 1);
|
||||
uint32_t levels = MAX(header.numberOfMipmapLevels, 1);
|
||||
|
||||
Image* image = calloc(1, offsetof(Image, mipmaps) + levels * sizeof(Mipmap));
|
||||
lovrAssert(image, "Out of memory");
|
||||
Image* image = lovrCalloc(offsetof(Image, mipmaps) + levels * sizeof(Mipmap));
|
||||
image->ref = 1;
|
||||
image->width = header.pixelWidth;
|
||||
image->height = header.pixelHeight;
|
||||
|
@ -945,8 +942,8 @@ static Image* loadKTX1(Blob* blob) {
|
|||
lovrRetain(blob);
|
||||
|
||||
if (header.numberOfFaces > 1) {
|
||||
lovrAssert(header.numberOfFaces == 6, "KTX files must have 1 or 6 faces");
|
||||
lovrAssert(header.numberOfArrayElements == 0, "KTX files with cubemap arrays are not supported");
|
||||
lovrCheck(header.numberOfFaces == 6, "KTX files must have 1 or 6 faces");
|
||||
lovrCheck(header.numberOfArrayElements == 0, "KTX files with cubemap arrays are not supported");
|
||||
image->flags |= IMAGE_CUBEMAP;
|
||||
image->layers = 6;
|
||||
}
|
||||
|
@ -971,6 +968,7 @@ static Image* loadKTX1(Blob* blob) {
|
|||
[FORMAT_RGB10A2] = { 0x8368, 0x1908, 0x8059, 0 },
|
||||
[FORMAT_RG11B10F] = { 0x8C3A, 0x1907, 0x8C3A, 0 },
|
||||
[FORMAT_D16] = { 0x1403, 0x1902, 0x81A5, 0 },
|
||||
[FORMAT_D24] = { 0x1405, 0x1902, 0x81A6, 0 },
|
||||
[FORMAT_D32F] = { 0x1406, 0x1902, 0x8CAC, 0 },
|
||||
[FORMAT_D24S8] = { 0x84FA, 0x84F9, 0x88F0, 0 },
|
||||
[FORMAT_D32FS8] = { 0x8DAD, 0x84F9, 0x8CAD, 0 },
|
||||
|
@ -1013,7 +1011,7 @@ static Image* loadKTX1(Blob* blob) {
|
|||
}
|
||||
}
|
||||
}
|
||||
lovrAssert(image->format != ~0u, "KTX1 file uses an unsupported image format (glType = %d, glFormat = %d, glInternalFormat = %d)", header.glType, header.glFormat, header.glInternalFormat);
|
||||
lovrCheck(image->format != ~0u, "KTX1 file uses an unsupported image format (glType = %d, glFormat = %d, glInternalFormat = %d)", header.glType, header.glFormat, header.glInternalFormat);
|
||||
|
||||
// Mipmaps
|
||||
uint32_t width = image->width;
|
||||
|
@ -1074,18 +1072,17 @@ static Image* loadKTX2(Blob* blob) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
lovrAssert(header->pixelWidth > 0, "KTX image dimensions must be positive");
|
||||
lovrAssert(header->pixelHeight > 0, "Unable to load 1D KTX images");
|
||||
lovrAssert(header->pixelDepth == 0, "Unable to load 3D KTX images");
|
||||
lovrAssert(header->faceCount == 1 || header->faceCount == 6, "Invalid KTX file (faceCount must be 1 or 6)");
|
||||
lovrAssert(header->layerCount == 0 || header->faceCount == 1, "Unable to load cubemap array KTX images");
|
||||
lovrAssert(!header->compression, "Supercompressed KTX files are not currently supported");
|
||||
lovrCheck(header->pixelWidth > 0, "KTX image dimensions must be positive");
|
||||
lovrCheck(header->pixelHeight > 0, "Unable to load 1D KTX images");
|
||||
lovrCheck(header->pixelDepth == 0, "Unable to load 3D KTX images");
|
||||
lovrCheck(header->faceCount == 1 || header->faceCount == 6, "Invalid KTX file (faceCount must be 1 or 6)");
|
||||
lovrCheck(header->layerCount == 0 || header->faceCount == 1, "Unable to load cubemap array KTX images");
|
||||
lovrCheck(!header->compression, "Supercompressed KTX files are not currently supported");
|
||||
|
||||
uint32_t layers = MAX(header->layerCount, 1);
|
||||
uint32_t levels = MAX(header->levelCount, 1);
|
||||
|
||||
Image* image = calloc(1, offsetof(Image, mipmaps) + levels * sizeof(Mipmap));
|
||||
lovrAssert(image, "Out of memory");
|
||||
Image* image = lovrCalloc(offsetof(Image, mipmaps) + levels * sizeof(Mipmap));
|
||||
image->ref = 1;
|
||||
image->width = header->pixelWidth;
|
||||
image->height = header->pixelHeight;
|
||||
|
@ -1118,6 +1115,7 @@ static Image* loadKTX2(Blob* blob) {
|
|||
case 64: image->format = FORMAT_RGB10A2; break;
|
||||
case 122: image->format = FORMAT_RG11B10F; break;
|
||||
case 124: image->format = FORMAT_D16; break;
|
||||
case 125: image->format = FORMAT_D24; break;
|
||||
case 126: image->format = FORMAT_D32F; break;
|
||||
case 129: image->format = FORMAT_D24S8; break;
|
||||
case 130: image->format = FORMAT_D32FS8; break;
|
||||
|
@ -1194,8 +1192,7 @@ static Image* loadSTB(Blob* blob) {
|
|||
|
||||
size_t size = measure(width, height, format);
|
||||
|
||||
Image* image = calloc(1, sizeof(Image));
|
||||
lovrAssert(image, "Out of memory");
|
||||
Image* image = lovrCalloc(sizeof(Image));
|
||||
image->ref = 1;
|
||||
image->flags = flags;
|
||||
image->width = width;
|
||||
|
|
|
@ -24,6 +24,7 @@ typedef enum {
|
|||
FORMAT_RGB10A2,
|
||||
FORMAT_RG11B10F,
|
||||
FORMAT_D16,
|
||||
FORMAT_D24,
|
||||
FORMAT_D32F,
|
||||
FORMAT_D24S8,
|
||||
FORMAT_D32FS8,
|
||||
|
@ -77,5 +78,4 @@ void lovrImageGetPixel(Image* image, uint32_t x, uint32_t y, float pixel[4]);
|
|||
void lovrImageSetPixel(Image* image, uint32_t x, uint32_t y, float pixel[4]);
|
||||
void lovrImageMapPixel(Image* image, uint32_t x, uint32_t y, uint32_t w, uint32_t h, MapPixelCallback* callback, void* userdata);
|
||||
void lovrImageCopy(Image* src, Image* dst, uint32_t srcOffset[2], uint32_t dstOffset[2], uint32_t extent[2]);
|
||||
void lovrImageClear(Image* image);
|
||||
struct Blob* lovrImageEncode(Image* image);
|
||||
|
|
|
@ -12,7 +12,8 @@ static size_t typeSizes[] = {
|
|||
[U16] = 2,
|
||||
[I32] = 4,
|
||||
[U32] = 4,
|
||||
[F32] = 4
|
||||
[F32] = 4,
|
||||
[SN10x3] = 4
|
||||
};
|
||||
|
||||
static void* nullIO(const char* path, size_t* count) {
|
||||
|
@ -20,8 +21,7 @@ static void* nullIO(const char* path, size_t* count) {
|
|||
}
|
||||
|
||||
ModelData* lovrModelDataCreate(Blob* source, ModelDataIO* io) {
|
||||
ModelData* model = calloc(1, sizeof(ModelData));
|
||||
lovrAssert(model, "Out of memory");
|
||||
ModelData* model = lovrCalloc(sizeof(ModelData));
|
||||
model->ref = 1;
|
||||
|
||||
if (!io) {
|
||||
|
@ -54,11 +54,11 @@ void lovrModelDataDestroy(void* ref) {
|
|||
map_free(&model->animationMap);
|
||||
map_free(&model->materialMap);
|
||||
map_free(&model->nodeMap);
|
||||
free(model->vertices);
|
||||
free(model->indices);
|
||||
free(model->metadata);
|
||||
free(model->data);
|
||||
free(model);
|
||||
lovrFree(model->vertices);
|
||||
lovrFree(model->indices);
|
||||
lovrFree(model->metadata);
|
||||
lovrFree(model->data);
|
||||
lovrFree(model);
|
||||
}
|
||||
|
||||
// Batches allocations for all the ModelData arrays
|
||||
|
@ -83,8 +83,7 @@ void lovrModelDataAllocate(ModelData* model) {
|
|||
totalSize += sizes[14] = model->charCount * sizeof(char);
|
||||
|
||||
size_t offset = 0;
|
||||
char* p = model->data = calloc(1, totalSize);
|
||||
lovrAssert(model->data, "Out of memory");
|
||||
char* p = model->data = lovrCalloc(totalSize);
|
||||
model->blobs = (Blob**) (p + offset), offset += sizes[0];
|
||||
model->buffers = (ModelBuffer*) (p + offset), offset += sizes[1];
|
||||
model->images = (Image**) (p + offset), offset += sizes[2];
|
||||
|
@ -243,6 +242,22 @@ void lovrModelDataCopyAttribute(ModelData* data, ModelAttribute* attribute, char
|
|||
} else {
|
||||
lovrUnreachable();
|
||||
}
|
||||
} else if (type == SN10x3) {
|
||||
if (attribute->type == F32) {
|
||||
for (uint32_t i = 0; i < count; i++, src += attribute->stride, dst += stride) {
|
||||
float x = ((float*) src)[0];
|
||||
float y = ((float*) src)[1];
|
||||
float z = ((float*) src)[2];
|
||||
float w = attribute->components == 4 ? ((float*) src)[3] : 0.f;
|
||||
*(uint32_t*) dst =
|
||||
((((uint32_t) (int32_t) (x * 511.f)) & 0x3ff) << 0) |
|
||||
((((uint32_t) (int32_t) (y * 511.f)) & 0x3ff) << 10) |
|
||||
((((uint32_t) (int32_t) (z * 511.f)) & 0x3ff) << 20) |
|
||||
((((uint32_t) (int32_t) (w * 2.f)) & 0x003) << 30);
|
||||
}
|
||||
} else {
|
||||
lovrUnreachable();
|
||||
}
|
||||
} else {
|
||||
lovrUnreachable();
|
||||
}
|
||||
|
@ -372,8 +387,7 @@ void lovrModelDataGetBoundingSphere(ModelData* model, float sphere[4]) {
|
|||
}
|
||||
|
||||
uint32_t pointCount = totalPrimitiveCount * 8;
|
||||
float* points = malloc(pointCount * 3 * sizeof(float));
|
||||
lovrAssert(points, "Out of memory");
|
||||
float* points = lovrMalloc(pointCount * 3 * sizeof(float));
|
||||
|
||||
uint32_t pointIndex = 0;
|
||||
boundingSphereHelper(model, model->rootNode, &pointIndex, points, (float[16]) MAT4_IDENTITY);
|
||||
|
@ -428,7 +442,7 @@ void lovrModelDataGetBoundingSphere(ModelData* model, float sphere[4]) {
|
|||
model->boundingSphere[1] = y;
|
||||
model->boundingSphere[2] = z;
|
||||
model->boundingSphere[3] = r;
|
||||
free(points);
|
||||
lovrFree(points);
|
||||
}
|
||||
|
||||
memcpy(sphere, model->boundingSphere, sizeof(model->boundingSphere));
|
||||
|
@ -513,7 +527,7 @@ static void collectVertices(ModelData* model, uint32_t nodeIndex, float** vertic
|
|||
*baseIndex += positions->count;
|
||||
}
|
||||
|
||||
if (index) {
|
||||
if (indices && index) {
|
||||
lovrAssert(index->type == U16 || index->type == U32, "Unreachable");
|
||||
|
||||
char* data = (char*) model->buffers[index->buffer].data + index->offset;
|
||||
|
@ -544,20 +558,18 @@ void lovrModelDataGetTriangles(ModelData* model, float** vertices, uint32_t** in
|
|||
}
|
||||
|
||||
if (vertices && !model->vertices) {
|
||||
uint32_t* tempIndices;
|
||||
uint32_t baseIndex = 0;
|
||||
model->vertices = malloc(model->totalVertexCount * 3 * sizeof(float));
|
||||
model->indices = malloc(model->totalIndexCount * sizeof(uint32_t));
|
||||
lovrAssert(model->vertices && model->indices, "Out of memory");
|
||||
model->vertices = lovrMalloc(model->totalVertexCount * 3 * sizeof(float));
|
||||
model->indices = lovrMalloc(model->totalIndexCount * sizeof(uint32_t));
|
||||
*vertices = model->vertices;
|
||||
*indices = model->indices;
|
||||
collectVertices(model, model->rootNode, vertices, indices, &baseIndex, (float[16]) MAT4_IDENTITY);
|
||||
tempIndices = model->indices;
|
||||
collectVertices(model, model->rootNode, vertices, &tempIndices, &baseIndex, (float[16]) MAT4_IDENTITY);
|
||||
}
|
||||
|
||||
*vertexCount = model->totalVertexCount;
|
||||
*indexCount = model->totalIndexCount;
|
||||
if (vertexCount) *vertexCount = model->totalVertexCount;
|
||||
if (indexCount) *indexCount = model->totalIndexCount;
|
||||
|
||||
if (vertices) {
|
||||
*vertices = model->vertices;
|
||||
*indices = model->indices;
|
||||
}
|
||||
if (vertices) *vertices = model->vertices;
|
||||
if (indices) *indices = model->indices;
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ typedef enum {
|
|||
MAX_DEFAULT_ATTRIBUTES
|
||||
} DefaultAttribute;
|
||||
|
||||
typedef enum { I8, U8, I16, U16, I32, U32, F32 } AttributeType;
|
||||
typedef enum { I8, U8, I16, U16, I32, U32, F32, SN10x3 } AttributeType;
|
||||
|
||||
typedef union {
|
||||
void* raw;
|
||||
|
|
|
@ -88,10 +88,7 @@ static void* decodeBase64(char* str, size_t length, size_t* decodedLength) {
|
|||
length -= s - str;
|
||||
int padding = (s[length - 1] == '=') + (s[length - 2] == '=');
|
||||
*decodedLength = length / 4 * 3 - padding;
|
||||
uint8_t* data = malloc(*decodedLength);
|
||||
if (!data) {
|
||||
return NULL;
|
||||
}
|
||||
uint8_t* data = lovrMalloc(*decodedLength);
|
||||
|
||||
uint32_t num = 0;
|
||||
uint32_t bits = 0;
|
||||
|
@ -113,7 +110,7 @@ static void* decodeBase64(char* str, size_t length, size_t* decodedLength) {
|
|||
} else if (c == '=') {
|
||||
break;
|
||||
} else {
|
||||
free(data);
|
||||
lovrFree(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -224,11 +221,16 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source, ModelDataIO* io
|
|||
json = (char*) &jsonHeader[1];
|
||||
jsonLength = jsonHeader->length;
|
||||
|
||||
gltfChunkHeader* binHeader = (gltfChunkHeader*) &json[jsonLength];
|
||||
lovrAssert(binHeader->type == MAGIC_BIN, "Invalid BIN header");
|
||||
if (source->size > sizeof(gltfHeader) + sizeof(gltfChunkHeader) + jsonLength + 4) {
|
||||
gltfChunkHeader* binHeader = (gltfChunkHeader*) &json[jsonLength];
|
||||
lovrAssert(binHeader->type == MAGIC_BIN, "Invalid BIN header");
|
||||
|
||||
binData = (char*) &binHeader[1];
|
||||
binOffset = (char*) binData - (char*) source->data;
|
||||
binData = (char*) &binHeader[1];
|
||||
binOffset = (char*) binData - (char*) source->data;
|
||||
} else {
|
||||
binData = NULL;
|
||||
binOffset = 0;
|
||||
}
|
||||
} else {
|
||||
json = (char*) data;
|
||||
jsonLength = source->size;
|
||||
|
@ -236,8 +238,7 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source, ModelDataIO* io
|
|||
binOffset = 0;
|
||||
}
|
||||
|
||||
model->metadata = malloc(jsonLength);
|
||||
lovrAssert(model->metadata, "Out of memory");
|
||||
model->metadata = lovrMalloc(jsonLength);
|
||||
memcpy(model->metadata, json, jsonLength);
|
||||
model->metadataSize = jsonLength;
|
||||
model->metadataType = META_GLTF_JSON;
|
||||
|
@ -266,7 +267,7 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source, ModelDataIO* io
|
|||
}
|
||||
|
||||
if (tokenCount <= 0 || tokens[0].type != JSMN_OBJECT) {
|
||||
free(heapTokens);
|
||||
lovrFree(heapTokens);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -320,8 +321,7 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source, ModelDataIO* io
|
|||
}
|
||||
}
|
||||
|
||||
animationSamplers = malloc(samplerCount * sizeof(gltfAnimationSampler));
|
||||
lovrAssert(animationSamplers, "Out of memory");
|
||||
animationSamplers = lovrMalloc(samplerCount * sizeof(gltfAnimationSampler));
|
||||
gltfAnimationSampler* sampler = animationSamplers;
|
||||
for (int i = (token++)->size; i > 0; i--) {
|
||||
for (int k = (token++)->size; k > 0; k--) {
|
||||
|
@ -364,8 +364,7 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source, ModelDataIO* io
|
|||
|
||||
} else if (STR_EQ(key, "images")) {
|
||||
model->imageCount = token->size;
|
||||
images = malloc(model->imageCount * sizeof(gltfImage));
|
||||
lovrAssert(images, "Out of memory");
|
||||
images = lovrMalloc(model->imageCount * sizeof(gltfImage));
|
||||
gltfImage* image = images;
|
||||
for (int i = (token++)->size; i > 0; i--, image++) {
|
||||
image->bufferView = ~0u;
|
||||
|
@ -383,8 +382,7 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source, ModelDataIO* io
|
|||
}
|
||||
|
||||
} else if (STR_EQ(key, "textures")) {
|
||||
textures = malloc(token->size * sizeof(gltfTexture));
|
||||
lovrAssert(textures, "Out of memory");
|
||||
textures = lovrMalloc(token->size * sizeof(gltfTexture));
|
||||
gltfTexture* texture = textures;
|
||||
for (int i = (token++)->size; i > 0; i--, texture++) {
|
||||
texture->image = ~0u;
|
||||
|
@ -428,8 +426,7 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source, ModelDataIO* io
|
|||
|
||||
} else if (STR_EQ(key, "meshes")) {
|
||||
info.meshes = token;
|
||||
meshes = malloc(token->size * sizeof(gltfMesh));
|
||||
lovrAssert(meshes, "Out of memory");
|
||||
meshes = lovrMalloc(token->size * sizeof(gltfMesh));
|
||||
gltfMesh* mesh = meshes;
|
||||
model->primitiveCount = 0;
|
||||
model->blendShapeCount = 0;
|
||||
|
@ -495,8 +492,7 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source, ModelDataIO* io
|
|||
} else if (STR_EQ(key, "scenes")) {
|
||||
info.scenes = token;
|
||||
info.sceneCount = token->size;
|
||||
scenes = malloc(info.sceneCount * sizeof(gltfScene));
|
||||
lovrAssert(scenes, "Out of memory");
|
||||
scenes = lovrMalloc(info.sceneCount * sizeof(gltfScene));
|
||||
gltfScene* scene = scenes;
|
||||
for (int i = (token++)->size; i > 0; i--, scene++) {
|
||||
for (int k = (token++)->size; k > 0; k--) {
|
||||
|
@ -1053,11 +1049,11 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source, ModelDataIO* io
|
|||
model->rootNode = scenes[rootScene].node;
|
||||
}
|
||||
|
||||
free(animationSamplers);
|
||||
free(meshes);
|
||||
free(images);
|
||||
free(textures);
|
||||
free(scenes);
|
||||
free(heapTokens);
|
||||
lovrFree(animationSamplers);
|
||||
lovrFree(meshes);
|
||||
lovrFree(images);
|
||||
lovrFree(textures);
|
||||
lovrFree(scenes);
|
||||
lovrFree(heapTokens);
|
||||
return model;
|
||||
}
|
||||
|
|
|
@ -101,7 +101,7 @@ static void parseMtl(char* path, char* base, ModelDataIO* io, arr_image_t* image
|
|||
data = newline + 1;
|
||||
}
|
||||
|
||||
free(p);
|
||||
lovrFree(p);
|
||||
}
|
||||
|
||||
ModelData* lovrModelDataInitObj(ModelData* model, Blob* source, ModelDataIO* io) {
|
||||
|
@ -123,16 +123,16 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source, ModelDataIO* io)
|
|||
arr_t(float) normals;
|
||||
arr_t(float) uvs;
|
||||
|
||||
arr_init(&groups, arr_alloc);
|
||||
arr_init(&images, arr_alloc);
|
||||
arr_init(&materials, arr_alloc);
|
||||
arr_init(&groups);
|
||||
arr_init(&images);
|
||||
arr_init(&materials);
|
||||
map_init(&materialMap, 0);
|
||||
arr_init(&vertexBlob, arr_alloc);
|
||||
arr_init(&indexBlob, arr_alloc);
|
||||
arr_init(&vertexBlob);
|
||||
arr_init(&indexBlob);
|
||||
map_init(&vertexMap, 0);
|
||||
arr_init(&positions, arr_alloc);
|
||||
arr_init(&normals, arr_alloc);
|
||||
arr_init(&uvs, arr_alloc);
|
||||
arr_init(&positions);
|
||||
arr_init(&normals);
|
||||
arr_init(&uvs);
|
||||
|
||||
arr_push(&groups, ((objGroup) { .material = -1 }));
|
||||
|
||||
|
@ -197,7 +197,7 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source, ModelDataIO* io)
|
|||
|
||||
// Triangulate faces (triangle fan)
|
||||
if (i >= 3) {
|
||||
arr_push(&indexBlob, indexBlob.data[indexBlob.length - i]);
|
||||
arr_push(&indexBlob, indexBlob.data[indexBlob.length - (3 * (i - 2))]);
|
||||
arr_push(&indexBlob, indexBlob.data[indexBlob.length - 2]);
|
||||
group->count += 2;
|
||||
}
|
||||
|
|
|
@ -17,8 +17,7 @@ static ModelData* lovrModelDataInitStlBinary(ModelData* model, Blob* source, Mod
|
|||
|
||||
uint32_t vertexCount = triangleCount * 3;
|
||||
size_t vertexBufferSize = vertexCount * 6 * sizeof(float);
|
||||
float* vertices = malloc(vertexBufferSize);
|
||||
lovrAssert(vertices, "Out of memory");
|
||||
float* vertices = lovrMalloc(vertexBufferSize);
|
||||
|
||||
model->blobCount = 1;
|
||||
model->bufferCount = 1;
|
||||
|
|
|
@ -19,8 +19,7 @@ struct Rasterizer {
|
|||
};
|
||||
|
||||
Rasterizer* lovrRasterizerCreate(Blob* blob, float size) {
|
||||
Rasterizer* rasterizer = calloc(1, sizeof(Rasterizer));
|
||||
lovrAssert(rasterizer, "Out of memory");
|
||||
Rasterizer* rasterizer = lovrCalloc(sizeof(Rasterizer));
|
||||
rasterizer->ref = 1;
|
||||
|
||||
stbtt_fontinfo* font = &rasterizer->font;
|
||||
|
@ -47,7 +46,7 @@ Rasterizer* lovrRasterizerCreate(Blob* blob, float size) {
|
|||
void lovrRasterizerDestroy(void* ref) {
|
||||
Rasterizer* rasterizer = ref;
|
||||
lovrRelease(rasterizer->blob, lovrBlobDestroy);
|
||||
free(rasterizer);
|
||||
lovrFree(rasterizer);
|
||||
}
|
||||
|
||||
float lovrRasterizerGetFontSize(Rasterizer* rasterizer) {
|
||||
|
|
|
@ -78,8 +78,7 @@ static uint32_t lovrSoundReadMp3(Sound* sound, uint32_t offset, uint32_t count,
|
|||
// Sound
|
||||
|
||||
Sound* lovrSoundCreateRaw(uint32_t frames, SampleFormat format, ChannelLayout layout, uint32_t sampleRate, Blob* blob) {
|
||||
Sound* sound = calloc(1, sizeof(Sound));
|
||||
lovrAssert(sound, "Out of memory");
|
||||
Sound* sound = lovrCalloc(sizeof(Sound));
|
||||
sound->ref = 1;
|
||||
sound->frames = frames;
|
||||
sound->format = format;
|
||||
|
@ -87,8 +86,7 @@ Sound* lovrSoundCreateRaw(uint32_t frames, SampleFormat format, ChannelLayout la
|
|||
sound->sampleRate = sampleRate;
|
||||
sound->read = lovrSoundReadRaw;
|
||||
size_t size = frames * lovrSoundGetStride(sound);
|
||||
void* data = calloc(1, size);
|
||||
lovrAssert(data, "Out of memory");
|
||||
void* data = lovrCalloc(size);
|
||||
sound->blob = lovrBlobCreate(data, size, "Sound");
|
||||
|
||||
if (blob) {
|
||||
|
@ -99,19 +97,16 @@ Sound* lovrSoundCreateRaw(uint32_t frames, SampleFormat format, ChannelLayout la
|
|||
}
|
||||
|
||||
Sound* lovrSoundCreateStream(uint32_t frames, SampleFormat format, ChannelLayout layout, uint32_t sampleRate) {
|
||||
Sound* sound = calloc(1, sizeof(Sound));
|
||||
lovrAssert(sound, "Out of memory");
|
||||
Sound* sound = lovrCalloc(sizeof(Sound));
|
||||
sound->ref = 1;
|
||||
sound->frames = frames;
|
||||
sound->format = format;
|
||||
sound->layout = layout;
|
||||
sound->sampleRate = sampleRate;
|
||||
sound->read = lovrSoundReadStream;
|
||||
sound->stream = malloc(sizeof(ma_pcm_rb));
|
||||
lovrAssert(sound->stream, "Out of memory");
|
||||
sound->stream = lovrMalloc(sizeof(ma_pcm_rb));
|
||||
size_t size = frames * lovrSoundGetStride(sound);
|
||||
void* data = malloc(size);
|
||||
lovrAssert(data, "Out of memory");
|
||||
void* data = lovrMalloc(size);
|
||||
sound->blob = lovrBlobCreate(data, size, NULL);
|
||||
ma_result status = ma_pcm_rb_init(miniaudioFormats[format], lovrSoundGetChannelCount(sound), frames, data, NULL, sound->stream);
|
||||
lovrAssert(status == MA_SUCCESS, "Failed to create ring buffer for streamed Sound: %s (%d)", ma_result_description(status), status);
|
||||
|
@ -135,8 +130,7 @@ static bool loadOgg(Sound* sound, Blob* blob, bool decode) {
|
|||
uint32_t channels = lovrSoundGetChannelCount(sound);
|
||||
lovrAssert(sound->frames * channels <= INT_MAX, "Decoded OGG file has too many samples");
|
||||
size_t size = sound->frames * lovrSoundGetStride(sound);
|
||||
void* data = calloc(1, size);
|
||||
lovrAssert(data, "Out of memory");
|
||||
void* data = lovrCalloc(size);
|
||||
sound->blob = lovrBlobCreate(data, size, "Sound");
|
||||
if (stb_vorbis_get_samples_float_interleaved(sound->decoder, channels, data, (int) size / sizeof(float)) < (int) sound->frames) {
|
||||
lovrThrow("Could not decode vorbis from '%s'", blob->name);
|
||||
|
@ -229,8 +223,7 @@ static bool loadWAV(Sound* sound, Blob* blob, bool decode) {
|
|||
// Conversion
|
||||
size_t samples = sound->frames * lovrSoundGetChannelCount(sound);
|
||||
size_t bytes = sound->frames * lovrSoundGetStride(sound);
|
||||
void* raw = malloc(bytes);
|
||||
lovrAssert(raw, "Out of memory");
|
||||
void* raw = lovrMalloc(bytes);
|
||||
if (pcm && wav->sampleSize == 24) {
|
||||
float* out = raw;
|
||||
const uint8_t* in = (const uint8_t*) data;
|
||||
|
@ -296,10 +289,9 @@ static bool loadMP3(Sound* sound, Blob* blob, bool decode) {
|
|||
sound->read = lovrSoundReadRaw;
|
||||
return true;
|
||||
} else {
|
||||
mp3dec_ex_t* decoder = sound->decoder = malloc(sizeof(mp3dec_ex_t));
|
||||
lovrAssert(decoder, "Out of memory");
|
||||
mp3dec_ex_t* decoder = sound->decoder = lovrMalloc(sizeof(mp3dec_ex_t));
|
||||
if (mp3dec_ex_open_buf(sound->decoder, blob->data, blob->size, MP3D_SEEK_TO_SAMPLE)) {
|
||||
free(sound->decoder);
|
||||
lovrFree(sound->decoder);
|
||||
lovrThrow("Could not load mp3 from '%s'", blob->name);
|
||||
}
|
||||
sound->format = SAMPLE_F32;
|
||||
|
@ -314,8 +306,7 @@ static bool loadMP3(Sound* sound, Blob* blob, bool decode) {
|
|||
}
|
||||
|
||||
Sound* lovrSoundCreateFromFile(Blob* blob, bool decode) {
|
||||
Sound* sound = calloc(1, sizeof(Sound));
|
||||
lovrAssert(sound, "Out of memory");
|
||||
Sound* sound = lovrCalloc(sizeof(Sound));
|
||||
sound->ref = 1;
|
||||
|
||||
if (loadOgg(sound, blob, decode)) return sound;
|
||||
|
@ -326,8 +317,7 @@ Sound* lovrSoundCreateFromFile(Blob* blob, bool decode) {
|
|||
}
|
||||
|
||||
Sound* lovrSoundCreateFromCallback(SoundCallback read, void *callbackMemo, SoundDestroyCallback callbackMemoDestroy, SampleFormat format, uint32_t sampleRate, ChannelLayout layout, uint32_t maxFrames) {
|
||||
Sound* sound = calloc(1, sizeof(Sound));
|
||||
lovrAssert(sound, "Out of memory");
|
||||
Sound* sound = lovrCalloc(sizeof(Sound));
|
||||
sound->ref = 1;
|
||||
sound->read = read;
|
||||
sound->format = format;
|
||||
|
@ -344,10 +334,10 @@ void lovrSoundDestroy(void* ref) {
|
|||
if (sound->callbackMemoDestroy) sound->callbackMemoDestroy(sound);
|
||||
lovrRelease(sound->blob, lovrBlobDestroy);
|
||||
if (sound->read == lovrSoundReadOgg) stb_vorbis_close(sound->decoder);
|
||||
if (sound->read == lovrSoundReadMp3) mp3dec_ex_close(sound->decoder), free(sound->decoder);
|
||||
if (sound->read == lovrSoundReadMp3) mp3dec_ex_close(sound->decoder), lovrFree(sound->decoder);
|
||||
ma_pcm_rb_uninit(sound->stream);
|
||||
free(sound->stream);
|
||||
free(sound);
|
||||
lovrFree(sound->stream);
|
||||
lovrFree(sound);
|
||||
}
|
||||
|
||||
Blob* lovrSoundGetBlob(Sound* sound) {
|
||||
|
@ -395,8 +385,8 @@ uint32_t lovrSoundRead(Sound* sound, uint32_t offset, uint32_t count, void* data
|
|||
}
|
||||
|
||||
uint32_t lovrSoundWrite(Sound* sound, uint32_t offset, uint32_t count, const void* data) {
|
||||
lovrAssert(!sound->decoder, "Compressed Sound can not be written to");
|
||||
lovrAssert(sound->stream || sound->blob, "Live-generated sound can not be written to");
|
||||
lovrCheck(!sound->decoder, "Compressed Sound can not be written to");
|
||||
lovrCheck(sound->stream || sound->blob, "Live-generated sound can not be written to");
|
||||
size_t stride = lovrSoundGetStride(sound);
|
||||
uint32_t frames = 0;
|
||||
|
||||
|
@ -422,11 +412,11 @@ uint32_t lovrSoundWrite(Sound* sound, uint32_t offset, uint32_t count, const voi
|
|||
}
|
||||
|
||||
uint32_t lovrSoundCopy(Sound* src, Sound* dst, uint32_t count, uint32_t srcOffset, uint32_t dstOffset) {
|
||||
lovrAssert(!dst->decoder, "Compressed Sound can not be written to");
|
||||
lovrAssert(dst->stream || dst->blob, "Live-generated sound can not be written to");
|
||||
lovrAssert(src != dst, "Can not copy a Sound to itself");
|
||||
lovrAssert(src->format == dst->format, "Sound formats need to match");
|
||||
lovrAssert(src->layout == dst->layout, "Sound channel layouts need to match");
|
||||
lovrCheck(!dst->decoder, "Compressed Sound can not be written to");
|
||||
lovrCheck(dst->stream || dst->blob, "Live-generated sound can not be written to");
|
||||
lovrCheck(src != dst, "Can not copy a Sound to itself");
|
||||
lovrCheck(src->format == dst->format, "Sound formats need to match");
|
||||
lovrCheck(src->layout == dst->layout, "Sound channel layouts need to match");
|
||||
uint32_t frames = 0;
|
||||
|
||||
if (dst->stream) {
|
||||
|
|
|
@ -13,16 +13,16 @@ static struct {
|
|||
|
||||
void lovrVariantDestroy(Variant* variant) {
|
||||
switch (variant->type) {
|
||||
case TYPE_STRING: free(variant->value.string.pointer); return;
|
||||
case TYPE_STRING: lovrFree(variant->value.string.pointer); return;
|
||||
case TYPE_OBJECT: lovrRelease(variant->value.object.pointer, variant->value.object.destructor); return;
|
||||
case TYPE_MATRIX: free(variant->value.matrix.data); return;
|
||||
case TYPE_MATRIX: lovrFree(variant->value.matrix.data); return;
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
bool lovrEventInit(void) {
|
||||
if (atomic_fetch_add(&state.ref, 1)) return false;
|
||||
arr_init(&state.events, arr_alloc);
|
||||
arr_init(&state.events);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -51,8 +51,7 @@ void lovrEventPush(Event event) {
|
|||
if (event.type == EVENT_THREAD_ERROR) {
|
||||
lovrRetain(event.data.thread.thread);
|
||||
size_t length = strlen(event.data.thread.error);
|
||||
char* copy = malloc(length + 1);
|
||||
lovrAssert(copy, "Out of memory");
|
||||
char* copy = lovrMalloc(length + 1);
|
||||
memcpy(copy, event.data.thread.error, length);
|
||||
copy[length] = '\0';
|
||||
event.data.thread.error = copy;
|
||||
|
|
|
@ -179,9 +179,9 @@ void lovrFilesystemDestroy(void) {
|
|||
}
|
||||
|
||||
void lovrFilesystemSetSource(const char* source) {
|
||||
lovrAssert(!state.source[0], "Source is already set!");
|
||||
lovrCheck(!state.source[0], "Source is already set!");
|
||||
size_t length = strlen(source);
|
||||
lovrAssert(sizeof(state.source) > length, "Source is too long!");
|
||||
lovrCheck(sizeof(state.source) > length, "Source is too long!");
|
||||
memcpy(state.source, source, length);
|
||||
state.source[length] = '\0';
|
||||
}
|
||||
|
@ -310,8 +310,7 @@ void* lovrFilesystemRead(const char* p, size_t* size) {
|
|||
}
|
||||
|
||||
*size = (size_t) bytes;
|
||||
void* data = malloc(*size);
|
||||
lovrAssert(data, "Out of memory");
|
||||
void* data = lovrMalloc(*size);
|
||||
|
||||
if (archive->read(archive, &handle, data, *size, size)) {
|
||||
archive->close(archive, &handle);
|
||||
|
@ -569,7 +568,7 @@ static bool zip_init(Archive* archive, const char* filename, const char* root) {
|
|||
|
||||
// Parse the number of file entries and reserve memory
|
||||
uint16_t nodeCount = readu16(p + 10);
|
||||
arr_init(&archive->nodes, realloc);
|
||||
arr_init(&archive->nodes);
|
||||
arr_reserve(&archive->nodes, nodeCount);
|
||||
map_init(&archive->lookup, nodeCount);
|
||||
|
||||
|
@ -737,8 +736,7 @@ static bool zip_open(Archive* archive, const char* path, Handle* handle) {
|
|||
}
|
||||
|
||||
if (handle->node->compressed) {
|
||||
zip_stream* stream = handle->stream = malloc(sizeof(zip_stream));
|
||||
lovrAssert(stream, "Out of memory");
|
||||
zip_stream* stream = handle->stream = lovrMalloc(sizeof(zip_stream));
|
||||
tinfl_init(&stream->decompressor);
|
||||
stream->inputCursor = 0;
|
||||
stream->outputCursor = 0;
|
||||
|
@ -752,7 +750,7 @@ static bool zip_open(Archive* archive, const char* path, Handle* handle) {
|
|||
}
|
||||
|
||||
static bool zip_close(Archive* archive, Handle* handle) {
|
||||
free(handle->stream);
|
||||
lovrFree(handle->stream);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -906,8 +904,7 @@ static void zip_list(Archive* archive, const char* path, fs_list_cb callback, vo
|
|||
// Archive
|
||||
|
||||
Archive* lovrArchiveCreate(const char* path, const char* mountpoint, const char* root) {
|
||||
Archive* archive = calloc(1, sizeof(Archive));
|
||||
lovrAssert(archive, "Out of memory");
|
||||
Archive* archive = lovrCalloc(sizeof(Archive));
|
||||
archive->ref = 1;
|
||||
|
||||
if (dir_init(archive, path, root)) {
|
||||
|
@ -927,20 +924,18 @@ Archive* lovrArchiveCreate(const char* path, const char* mountpoint, const char*
|
|||
archive->stat = zip_stat;
|
||||
archive->list = zip_list;
|
||||
} else {
|
||||
free(archive);
|
||||
lovrFree(archive);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mountpoint) {
|
||||
size_t length = strlen(mountpoint);
|
||||
archive->mountpoint = malloc(length + 1);
|
||||
lovrAssert(archive->mountpoint, "Out of memory");
|
||||
archive->mountpoint = lovrMalloc(length + 1);
|
||||
archive->mountLength = normalize(mountpoint, length, archive->mountpoint);
|
||||
}
|
||||
|
||||
archive->pathLength = strlen(path);
|
||||
archive->path = malloc(archive->pathLength + 1);
|
||||
lovrAssert(archive->path, "Out of memory");
|
||||
archive->path = lovrMalloc(archive->pathLength + 1);
|
||||
memcpy(archive->path, path, archive->pathLength + 1);
|
||||
|
||||
return archive;
|
||||
|
@ -949,9 +944,9 @@ Archive* lovrArchiveCreate(const char* path, const char* mountpoint, const char*
|
|||
void lovrArchiveDestroy(void* ref) {
|
||||
Archive* archive = ref;
|
||||
if (archive->data) zip_free(archive);
|
||||
free(archive->mountpoint);
|
||||
free(archive->path);
|
||||
free(archive);
|
||||
lovrFree(archive->mountpoint);
|
||||
lovrFree(archive->path);
|
||||
lovrFree(archive);
|
||||
}
|
||||
|
||||
// File
|
||||
|
@ -990,16 +985,14 @@ File* lovrFileCreate(const char* p, OpenMode mode, const char** error) {
|
|||
}
|
||||
}
|
||||
|
||||
File* file = calloc(1, sizeof(File));
|
||||
lovrAssert(file, "Out of memory");
|
||||
File* file = lovrCalloc(sizeof(File));
|
||||
file->ref = 1;
|
||||
file->mode = mode;
|
||||
file->handle = handle;
|
||||
file->archive = archive;
|
||||
lovrRetain(archive);
|
||||
|
||||
file->path = malloc(length + 1);
|
||||
lovrAssert(file->path, "Out of memory");
|
||||
file->path = lovrMalloc(length + 1);
|
||||
memcpy(file->path, path, length + 1);
|
||||
|
||||
return file;
|
||||
|
@ -1009,8 +1002,8 @@ void lovrFileDestroy(void* ref) {
|
|||
File* file = ref;
|
||||
if (file->archive) file->archive->close(file->archive, &file->handle);
|
||||
lovrRelease(file->archive, lovrArchiveDestroy);
|
||||
free(file->path);
|
||||
free(file);
|
||||
lovrFree(file->path);
|
||||
lovrFree(file);
|
||||
}
|
||||
|
||||
const char* lovrFileGetPath(File* file) {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -116,6 +116,7 @@ typedef enum {
|
|||
TYPE_U8x4,
|
||||
TYPE_SN8x4,
|
||||
TYPE_UN8x4,
|
||||
TYPE_SN10x3,
|
||||
TYPE_UN10x3,
|
||||
TYPE_I16,
|
||||
TYPE_I16x2,
|
||||
|
@ -201,32 +202,30 @@ enum {
|
|||
};
|
||||
|
||||
typedef struct {
|
||||
Texture* parent;
|
||||
TextureType type;
|
||||
uint32_t layerIndex;
|
||||
uint32_t layerCount;
|
||||
uint32_t levelIndex;
|
||||
uint32_t levelCount;
|
||||
} TextureViewInfo;
|
||||
|
||||
typedef struct {
|
||||
Texture* parent;
|
||||
TextureType type;
|
||||
uint32_t format;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint32_t layers;
|
||||
uint32_t mipmaps;
|
||||
uint32_t samples;
|
||||
uint32_t usage;
|
||||
bool srgb;
|
||||
bool xr;
|
||||
uintptr_t handle;
|
||||
uint32_t imageCount;
|
||||
struct Image** images;
|
||||
const char* label;
|
||||
uintptr_t handle;
|
||||
} TextureInfo;
|
||||
|
||||
typedef struct {
|
||||
TextureType type;
|
||||
uint32_t layerIndex;
|
||||
uint32_t layerCount;
|
||||
uint32_t levelIndex;
|
||||
uint32_t levelCount;
|
||||
const char* label;
|
||||
} TextureViewInfo;
|
||||
|
||||
typedef enum {
|
||||
FILTER_NEAREST,
|
||||
FILTER_LINEAR
|
||||
|
@ -234,7 +233,7 @@ typedef enum {
|
|||
|
||||
Texture* lovrGraphicsGetWindowTexture(void);
|
||||
Texture* lovrTextureCreate(const TextureInfo* info);
|
||||
Texture* lovrTextureCreateView(const TextureViewInfo* view);
|
||||
Texture* lovrTextureCreateView(Texture* parent, const TextureViewInfo* info);
|
||||
void lovrTextureDestroy(void* ref);
|
||||
const TextureInfo* lovrTextureGetInfo(Texture* texture);
|
||||
struct Image* lovrTextureGetPixels(Texture* texture, uint32_t offset[4], uint32_t extent[3]);
|
||||
|
@ -286,21 +285,25 @@ typedef enum {
|
|||
SHADER_EQUIRECT,
|
||||
SHADER_FILL_2D,
|
||||
SHADER_FILL_ARRAY,
|
||||
SHADER_LOGO,
|
||||
SHADER_ANIMATOR,
|
||||
SHADER_BLENDER,
|
||||
SHADER_TALLY_MERGE,
|
||||
DEFAULT_SHADER_COUNT
|
||||
} DefaultShader;
|
||||
|
||||
typedef enum {
|
||||
SHADER_GRAPHICS,
|
||||
SHADER_COMPUTE
|
||||
} ShaderType;
|
||||
|
||||
typedef enum {
|
||||
STAGE_VERTEX,
|
||||
STAGE_FRAGMENT,
|
||||
STAGE_COMPUTE,
|
||||
STAGE_COUNT
|
||||
STAGE_COMPUTE
|
||||
} ShaderStage;
|
||||
|
||||
typedef struct {
|
||||
ShaderStage stage;
|
||||
const void* code;
|
||||
size_t size;
|
||||
} ShaderSource;
|
||||
|
@ -312,15 +315,18 @@ typedef struct {
|
|||
} ShaderFlag;
|
||||
|
||||
typedef struct {
|
||||
ShaderSource source[STAGE_COUNT];
|
||||
uint32_t flagCount;
|
||||
ShaderType type;
|
||||
ShaderSource* stages;
|
||||
uint32_t stageCount;
|
||||
ShaderFlag* flags;
|
||||
uint32_t flagCount;
|
||||
const char* label;
|
||||
bool isDefault;
|
||||
} ShaderInfo;
|
||||
|
||||
typedef void* ShaderIncluder(const char* filename, size_t* bytesRead);
|
||||
|
||||
ShaderSource lovrGraphicsCompileShader(ShaderStage stage, ShaderSource* source, ShaderIncluder* includer);
|
||||
void lovrGraphicsCompileShader(ShaderSource* stages, ShaderSource* outputs, uint32_t count, ShaderIncluder* includer);
|
||||
ShaderSource lovrGraphicsGetDefaultShaderSource(DefaultShader type, ShaderStage stage);
|
||||
Shader* lovrGraphicsGetDefaultShader(DefaultShader type);
|
||||
Shader* lovrShaderCreate(const ShaderInfo* info);
|
||||
|
@ -607,10 +613,10 @@ void lovrPassSetViewCull(Pass* pass, bool enable);
|
|||
void lovrPassSetWinding(Pass* pass, Winding winding);
|
||||
void lovrPassSetWireframe(Pass* pass, bool wireframe);
|
||||
|
||||
void lovrPassSendBuffer(Pass* pass, const char* name, size_t length, uint32_t slot, Buffer* buffer, uint32_t offset, uint32_t extent);
|
||||
void lovrPassSendTexture(Pass* pass, const char* name, size_t length, uint32_t slot, Texture* texture);
|
||||
void lovrPassSendSampler(Pass* pass, const char* name, size_t length, uint32_t slot, Sampler* sampler);
|
||||
void lovrPassSendData(Pass* pass, const char* name, size_t length, uint32_t slot, void** data, DataField** format);
|
||||
void lovrPassSendBuffer(Pass* pass, const char* name, size_t length, Buffer* buffer, uint32_t offset, uint32_t extent);
|
||||
void lovrPassSendTexture(Pass* pass, const char* name, size_t length, Texture* texture);
|
||||
void lovrPassSendSampler(Pass* pass, const char* name, size_t length, Sampler* sampler);
|
||||
void lovrPassSendData(Pass* pass, const char* name, size_t length, void** data, DataField** format);
|
||||
|
||||
void lovrPassPoints(Pass* pass, uint32_t count, float** vertices);
|
||||
void lovrPassLine(Pass* pass, uint32_t count, float** vertices);
|
||||
|
|
|
@ -301,12 +301,6 @@ static void createReferenceSpace(XrTime time) {
|
|||
return;
|
||||
}
|
||||
|
||||
char name[256];
|
||||
if (openxr_getDriverName(name, sizeof(name)) && !memcmp(name, "SteamVR", strlen("SteamVR"))) {
|
||||
state.referenceSpace = state.spaces[DEVICE_FLOOR];
|
||||
return;
|
||||
}
|
||||
|
||||
if (state.features.localFloor) {
|
||||
info.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL_FLOOR_EXT;
|
||||
} else if (state.config.seated) {
|
||||
|
@ -439,6 +433,7 @@ static void swapchain_init(Swapchain* swapchain, uint32_t width, uint32_t height
|
|||
if (depth) {
|
||||
info.usageFlags = XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
switch (state.depthFormat) {
|
||||
case FORMAT_D24: info.format = VK_FORMAT_X8_D24_UNORM_PACK32; break;
|
||||
case FORMAT_D32F: info.format = VK_FORMAT_D32_SFLOAT; break;
|
||||
case FORMAT_D24S8: info.format = VK_FORMAT_D24_UNORM_S8_UINT; break;
|
||||
case FORMAT_D32FS8: info.format = VK_FORMAT_D32_SFLOAT_S8_UINT; break;
|
||||
|
@ -472,7 +467,6 @@ static void swapchain_init(Swapchain* swapchain, uint32_t width, uint32_t height
|
|||
.height = height,
|
||||
.layers = 1 << stereo,
|
||||
.mipmaps = 1,
|
||||
.samples = 1,
|
||||
.usage = TEXTURE_RENDER | (depth ? 0 : TEXTURE_SAMPLE),
|
||||
.handle = (uintptr_t) images[i].image,
|
||||
.label = "OpenXR Swapchain",
|
||||
|
@ -588,8 +582,7 @@ static bool openxr_init(HeadsetConfig* config) {
|
|||
XR_INIT(result, "Failed to query extensions");
|
||||
}
|
||||
|
||||
XrExtensionProperties* extensionProperties = calloc(extensionCount, sizeof(*extensionProperties));
|
||||
lovrAssert(extensionProperties, "Out of memory");
|
||||
XrExtensionProperties* extensionProperties = lovrCalloc(extensionCount * sizeof(*extensionProperties));
|
||||
for (uint32_t i = 0; i < extensionCount; i++) extensionProperties[i].type = XR_TYPE_EXTENSION_PROPERTIES;
|
||||
xrEnumerateInstanceExtensionProperties(NULL, extensionCount, &extensionCount, extensionProperties);
|
||||
|
||||
|
@ -638,7 +631,7 @@ static bool openxr_init(HeadsetConfig* config) {
|
|||
}
|
||||
}
|
||||
|
||||
free(extensionProperties);
|
||||
lovrFree(extensionProperties);
|
||||
|
||||
#ifdef __ANDROID__
|
||||
XrInstanceCreateInfoAndroidKHR androidInfo = {
|
||||
|
@ -732,8 +725,7 @@ static bool openxr_init(HeadsetConfig* config) {
|
|||
|
||||
// Blend modes
|
||||
XR_INIT(xrEnumerateEnvironmentBlendModes(state.instance, state.system, XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO, 0, &state.blendModeCount, NULL), "Failed to query blend modes");
|
||||
state.blendModes = malloc(state.blendModeCount * sizeof(XrEnvironmentBlendMode));
|
||||
lovrAssert(state.blendModes, "Out of memory");
|
||||
state.blendModes = lovrMalloc(state.blendModeCount * sizeof(XrEnvironmentBlendMode));
|
||||
XR_INIT(xrEnumerateEnvironmentBlendModes(state.instance, state.system, XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO, state.blendModeCount, &state.blendModeCount, state.blendModes), "Failed to query blend modes");
|
||||
state.blendMode = state.blendModes[0];
|
||||
}
|
||||
|
@ -1375,8 +1367,8 @@ static void openxr_start(void) {
|
|||
if (hasGraphics) {
|
||||
state.depthFormat = state.config.stencil ? FORMAT_D32FS8 : FORMAT_D32F;
|
||||
|
||||
if (state.config.stencil && !lovrGraphicsGetFormatSupport(state.depthFormat, TEXTURE_FEATURE_RENDER)) {
|
||||
state.depthFormat = FORMAT_D24S8; // Guaranteed to be supported if the other one isn't
|
||||
if (!lovrGraphicsGetFormatSupport(state.depthFormat, TEXTURE_FEATURE_RENDER)) {
|
||||
state.depthFormat = state.config.stencil ? FORMAT_D24S8 : FORMAT_D24;
|
||||
}
|
||||
|
||||
state.pass = lovrPassCreate();
|
||||
|
@ -1386,6 +1378,7 @@ static void openxr_start(void) {
|
|||
int64_t nativeDepthFormat;
|
||||
|
||||
switch (state.depthFormat) {
|
||||
case FORMAT_D24: nativeDepthFormat = VK_FORMAT_X8_D24_UNORM_PACK32; break;
|
||||
case FORMAT_D32F: nativeDepthFormat = VK_FORMAT_D32_SFLOAT; break;
|
||||
case FORMAT_D24S8: nativeDepthFormat = VK_FORMAT_D24_UNORM_S8_UINT; break;
|
||||
case FORMAT_D32FS8: nativeDepthFormat = VK_FORMAT_D32_SFLOAT_S8_UINT; break;
|
||||
|
@ -1475,8 +1468,7 @@ static void openxr_start(void) {
|
|||
|
||||
if (state.features.refreshRate) {
|
||||
XR(xrEnumerateDisplayRefreshRatesFB(state.session, 0, &state.refreshRateCount, NULL), "Failed to query refresh rates");
|
||||
state.refreshRates = malloc(state.refreshRateCount * sizeof(float));
|
||||
lovrAssert(state.refreshRates, "Out of memory");
|
||||
state.refreshRates = lovrMalloc(state.refreshRateCount * sizeof(float));
|
||||
XR(xrEnumerateDisplayRefreshRatesFB(state.session, state.refreshRateCount, &state.refreshRateCount, state.refreshRates), "Failed to query refresh rates");
|
||||
}
|
||||
}
|
||||
|
@ -2097,8 +2089,7 @@ static ModelData* openxr_newModelDataFB(XrHandTrackerEXT tracker, bool animated)
|
|||
totalSize += sizes[9] = ALIGN(jointCount * 16 * sizeof(float), alignment);
|
||||
|
||||
// Allocate
|
||||
char* meshData = malloc(totalSize);
|
||||
if (!meshData) return NULL;
|
||||
char* meshData = lovrMalloc(totalSize);
|
||||
|
||||
// Write offseted pointers to the mesh struct, to be filled in by the second call
|
||||
size_t offset = 0;
|
||||
|
@ -2117,12 +2108,11 @@ static ModelData* openxr_newModelDataFB(XrHandTrackerEXT tracker, bool animated)
|
|||
// Populate the data
|
||||
result = xrGetHandMeshFB(tracker, &mesh);
|
||||
if (XR_FAILED(result)) {
|
||||
free(meshData);
|
||||
lovrFree(meshData);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ModelData* model = calloc(1, sizeof(ModelData));
|
||||
lovrAssert(model, "Out of memory");
|
||||
ModelData* model = lovrCalloc(sizeof(ModelData));
|
||||
model->ref = 1;
|
||||
model->blobCount = 1;
|
||||
model->bufferCount = 6;
|
||||
|
@ -2134,8 +2124,7 @@ static ModelData* openxr_newModelDataFB(XrHandTrackerEXT tracker, bool animated)
|
|||
model->nodeCount = 2 + jointCount;
|
||||
lovrModelDataAllocate(model);
|
||||
|
||||
model->metadata = malloc(sizeof(XrHandTrackerEXT));
|
||||
lovrAssert(model->metadata, "Out of memory");
|
||||
model->metadata = lovrMalloc(sizeof(XrHandTrackerEXT));
|
||||
*((XrHandTrackerEXT*)model->metadata) = tracker;
|
||||
model->metadataSize = sizeof(XrHandTrackerEXT);
|
||||
model->metadataType = META_HANDTRACKING_FB;
|
||||
|
@ -2278,11 +2267,10 @@ static ModelData* openxr_newModelDataMSFT(XrControllerModelKeyMSFT modelKey, boo
|
|||
return NULL;
|
||||
}
|
||||
|
||||
unsigned char* modelData = malloc(size);
|
||||
if (!modelData) return NULL;
|
||||
unsigned char* modelData = lovrMalloc(size);
|
||||
|
||||
if (XR_FAILED(xrLoadControllerModelMSFT(state.session, modelKey, size, &size, modelData))) {
|
||||
free(modelData);
|
||||
lovrFree(modelData);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -2305,11 +2293,10 @@ static ModelData* openxr_newModelDataMSFT(XrControllerModelKeyMSFT modelKey, boo
|
|||
return false;
|
||||
}
|
||||
|
||||
free(model->metadata);
|
||||
lovrFree(model->metadata);
|
||||
model->metadataType = META_CONTROLLER_MSFT;
|
||||
model->metadataSize = sizeof(MetadataControllerMSFT) + sizeof(uint32_t) * properties.nodeCountOutput;
|
||||
model->metadata = malloc(model->metadataSize);
|
||||
lovrAssert(model->metadata, "Out of memory");
|
||||
model->metadata = lovrMalloc(model->metadataSize);
|
||||
|
||||
MetadataControllerMSFT* metadata = model->metadata;
|
||||
metadata->modelKey = modelKey;
|
||||
|
@ -2458,8 +2445,7 @@ static bool openxr_animate(Model* model) {
|
|||
}
|
||||
|
||||
static Layer* openxr_newLayer(uint32_t width, uint32_t height) {
|
||||
Layer* layer = calloc(1, sizeof(Layer));
|
||||
lovrAssert(layer, "Out of memory");
|
||||
Layer* layer = lovrCalloc(sizeof(Layer));
|
||||
layer->ref = 1;
|
||||
layer->width = width;
|
||||
layer->height = height;
|
||||
|
@ -2495,7 +2481,7 @@ static void openxr_destroyLayer(void* ref) {
|
|||
Layer* layer = ref;
|
||||
swapchain_destroy(&layer->swapchain);
|
||||
lovrRelease(layer->pass, lovrPassDestroy);
|
||||
free(layer);
|
||||
lovrFree(layer);
|
||||
}
|
||||
|
||||
static Layer** openxr_getLayers(uint32_t* count) {
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#define MOVESPEED 3.f
|
||||
#define SPRINTSPEED 15.f
|
||||
#define SLOWSPEED .5f
|
||||
#define MOVESMOOTH 30.f
|
||||
#define TURNSPEED .005f
|
||||
#define TURNSMOOTH 30.f
|
||||
|
@ -67,7 +68,6 @@ static void onFocus(bool focused) {
|
|||
|
||||
static bool simulator_init(HeadsetConfig* config) {
|
||||
state.config = *config;
|
||||
state.epoch = os_get_time();
|
||||
state.clipNear = .01f;
|
||||
state.clipFar = 0.f;
|
||||
state.distance = .5f;
|
||||
|
@ -96,10 +96,13 @@ static void simulator_start(void) {
|
|||
if (hasGraphics) {
|
||||
state.pass = lovrPassCreate();
|
||||
state.depthFormat = state.config.stencil ? FORMAT_D32FS8 : FORMAT_D32F;
|
||||
if (state.config.stencil && !lovrGraphicsGetFormatSupport(state.depthFormat, TEXTURE_FEATURE_RENDER)) {
|
||||
state.depthFormat = FORMAT_D24S8; // Guaranteed to be supported if the other one isn't
|
||||
if (!lovrGraphicsGetFormatSupport(state.depthFormat, TEXTURE_FEATURE_RENDER)) {
|
||||
state.depthFormat = state.config.stencil ? FORMAT_D24S8 : FORMAT_D24;
|
||||
}
|
||||
}
|
||||
|
||||
state.epoch = os_get_time();
|
||||
state.time = 0.;
|
||||
}
|
||||
|
||||
static void simulator_stop(void) {
|
||||
|
@ -135,6 +138,8 @@ static bool simulator_isSeated(void) {
|
|||
static void simulator_getDisplayDimensions(uint32_t* width, uint32_t* height) {
|
||||
float density = os_window_get_pixel_density();
|
||||
os_window_get_size(width, height);
|
||||
*width *= state.config.supersample;
|
||||
*height *= state.config.supersample;
|
||||
*width *= density;
|
||||
*height *= density;
|
||||
}
|
||||
|
@ -269,7 +274,7 @@ static bool simulator_animate(struct Model* model) {
|
|||
}
|
||||
|
||||
static Layer* simulator_newLayer(uint32_t width, uint32_t height) {
|
||||
Layer* layer = calloc(1, sizeof(Layer));
|
||||
Layer* layer = lovrCalloc(sizeof(Layer));
|
||||
layer->ref = 1;
|
||||
layer->textureWidth = width;
|
||||
layer->textureWeight = height;
|
||||
|
@ -278,7 +283,7 @@ static Layer* simulator_newLayer(uint32_t width, uint32_t height) {
|
|||
|
||||
static void simulator_destroyLayer(void* ref) {
|
||||
Layer* layer = ref;
|
||||
free(layer);
|
||||
lovrFree(layer);
|
||||
}
|
||||
|
||||
static Layer** simulator_getLayers(uint32_t* count) {
|
||||
|
@ -379,7 +384,6 @@ static Pass* simulator_getPass(void) {
|
|||
.height = height,
|
||||
.layers = 1,
|
||||
.mipmaps = 1,
|
||||
.samples = 1,
|
||||
.usage = TEXTURE_RENDER | TEXTURE_SAMPLE,
|
||||
});
|
||||
|
||||
|
@ -437,8 +441,8 @@ static double simulator_update(void) {
|
|||
state.pitch = CLAMP(state.pitch - (state.my - myprev) * TURNSPEED, -(float) M_PI / 2.f, (float) M_PI / 2.f);
|
||||
state.yaw -= (state.mx - mxprev) * TURNSPEED;
|
||||
} else {
|
||||
state.mxHand = state.mx;
|
||||
state.myHand = state.my;
|
||||
state.mxHand = state.mx * state.config.supersample;
|
||||
state.myHand = state.my * state.config.supersample;
|
||||
}
|
||||
|
||||
// Head
|
||||
|
@ -450,6 +454,7 @@ static double simulator_update(void) {
|
|||
quat_slerp(state.headOrientation, target, 1.f - expf(-TURNSMOOTH * state.dt));
|
||||
|
||||
bool sprint = os_is_key_down(OS_KEY_LEFT_SHIFT) || os_is_key_down(OS_KEY_RIGHT_SHIFT);
|
||||
bool slow = os_is_key_down(OS_KEY_LEFT_CONTROL) || os_is_key_down(OS_KEY_RIGHT_CONTROL);
|
||||
bool front = os_is_key_down(OS_KEY_W) || os_is_key_down(OS_KEY_UP);
|
||||
bool back = os_is_key_down(OS_KEY_S) || os_is_key_down(OS_KEY_DOWN);
|
||||
bool left = os_is_key_down(OS_KEY_A) || os_is_key_down(OS_KEY_LEFT);
|
||||
|
@ -461,7 +466,7 @@ static double simulator_update(void) {
|
|||
velocity[0] = (left ? -1.f : right ? 1.f : 0.f);
|
||||
velocity[1] = (down ? -1.f : up ? 1.f : 0.f);
|
||||
velocity[2] = (front ? -1.f : back ? 1.f : 0.f);
|
||||
vec3_scale(velocity, sprint ? SPRINTSPEED : MOVESPEED);
|
||||
vec3_scale(velocity, sprint ? SPRINTSPEED : (slow ? SLOWSPEED : MOVESPEED));
|
||||
vec3_lerp(state.velocity, velocity, 1.f - expf(-MOVESMOOTH * state.dt));
|
||||
|
||||
vec3_scale(vec3_init(velocity, state.velocity), state.dt);
|
||||
|
@ -478,6 +483,8 @@ static double simulator_update(void) {
|
|||
float ray[3];
|
||||
uint32_t width, height;
|
||||
os_window_get_size(&width, &height);
|
||||
width *= state.config.supersample;
|
||||
height *= state.config.supersample;
|
||||
vec3_set(ray, state.mxHand / width * 2.f - 1.f, state.myHand / height * 2.f - 1.f, 1.f);
|
||||
|
||||
mat4_mulPoint(inverseProjection, ray);
|
||||
|
|
|
@ -129,10 +129,9 @@ static void evaluate(float* restrict P, size_t n, float t, vec4 p) {
|
|||
}
|
||||
|
||||
Curve* lovrCurveCreate(void) {
|
||||
Curve* curve = calloc(1, sizeof(Curve));
|
||||
lovrAssert(curve, "Out of memory");
|
||||
Curve* curve = lovrCalloc(sizeof(Curve));
|
||||
curve->ref = 1;
|
||||
arr_init(&curve->points, arr_alloc);
|
||||
arr_init(&curve->points);
|
||||
arr_reserve(&curve->points, 16);
|
||||
return curve;
|
||||
}
|
||||
|
@ -140,12 +139,12 @@ Curve* lovrCurveCreate(void) {
|
|||
void lovrCurveDestroy(void* ref) {
|
||||
Curve* curve = ref;
|
||||
arr_free(&curve->points);
|
||||
free(curve);
|
||||
lovrFree(curve);
|
||||
}
|
||||
|
||||
void lovrCurveEvaluate(Curve* curve, float t, vec4 p) {
|
||||
lovrAssert(curve->points.length >= 8, "Need at least 2 points to evaluate a Curve");
|
||||
lovrAssert(t >= 0.f && t <= 1.f, "Curve evaluation interval must be within [0, 1]");
|
||||
lovrCheck(curve->points.length >= 8, "Need at least 2 points to evaluate a Curve");
|
||||
lovrCheck(t >= 0.f && t <= 1.f, "Curve evaluation interval must be within [0, 1]");
|
||||
evaluate(curve->points.data, curve->points.length / 4, t, p);
|
||||
}
|
||||
|
||||
|
@ -159,8 +158,8 @@ void lovrCurveGetTangent(Curve* curve, float t, vec4 p) {
|
|||
}
|
||||
|
||||
Curve* lovrCurveSlice(Curve* curve, float t1, float t2) {
|
||||
lovrAssert(curve->points.length >= 8, "Need at least 2 points to slice a Curve");
|
||||
lovrAssert(t1 >= 0.f && t2 <= 1.f, "Curve slice interval must be within [0, 1]");
|
||||
lovrCheck(curve->points.length >= 8, "Need at least 2 points to slice a Curve");
|
||||
lovrCheck(t1 >= 0.f && t2 <= 1.f, "Curve slice interval must be within [0, 1]");
|
||||
|
||||
Curve* new = lovrCurveCreate();
|
||||
arr_reserve(&new->points, curve->points.length);
|
||||
|
@ -227,8 +226,7 @@ static const size_t vectorComponents[] = {
|
|||
};
|
||||
|
||||
Pool* lovrPoolCreate(void) {
|
||||
Pool* pool = calloc(1, sizeof(Pool));
|
||||
lovrAssert(pool, "Out of memory");
|
||||
Pool* pool = lovrCalloc(sizeof(Pool));
|
||||
pool->ref = 1;
|
||||
pool->data = os_vm_init((1 << 24) * sizeof(float));
|
||||
lovrPoolGrow(pool, 1 << 12);
|
||||
|
@ -238,7 +236,7 @@ Pool* lovrPoolCreate(void) {
|
|||
void lovrPoolDestroy(void* ref) {
|
||||
Pool* pool = ref;
|
||||
os_vm_free(pool->data, (1 << 24) * sizeof(float));
|
||||
free(pool);
|
||||
lovrFree(pool);
|
||||
}
|
||||
|
||||
void lovrPoolGrow(Pool* pool, size_t count) {
|
||||
|
@ -271,7 +269,7 @@ Vector lovrPoolAllocate(Pool* pool, VectorType type, float** data) {
|
|||
}
|
||||
|
||||
float* lovrPoolResolve(Pool* pool, Vector vector) {
|
||||
lovrAssert(vector.handle.generation == pool->generation, "Attempt to use a temporary vector from a previous frame");
|
||||
lovrCheck(vector.handle.generation == pool->generation, "Attempt to use a temporary vector from a previous frame");
|
||||
return pool->data + vector.handle.index;
|
||||
}
|
||||
|
||||
|
@ -300,8 +298,7 @@ static uint64_t wangHash64(uint64_t key) {
|
|||
// Use an 'Xorshift*' variant, as shown here: http://xorshift.di.unimi.it
|
||||
|
||||
RandomGenerator* lovrRandomGeneratorCreate(void) {
|
||||
RandomGenerator* generator = calloc(1, sizeof(RandomGenerator));
|
||||
lovrAssert(generator, "Out of memory");
|
||||
RandomGenerator* generator = lovrCalloc(sizeof(RandomGenerator));
|
||||
generator->ref = 1;
|
||||
Seed seed = { .b32 = { .lo = 0xCBBF7A44, .hi = 0x0139408D } };
|
||||
lovrRandomGeneratorSetSeed(generator, seed);
|
||||
|
@ -310,7 +307,7 @@ RandomGenerator* lovrRandomGeneratorCreate(void) {
|
|||
}
|
||||
|
||||
void lovrRandomGeneratorDestroy(void* ref) {
|
||||
free(ref);
|
||||
lovrFree(ref);
|
||||
}
|
||||
|
||||
Seed lovrRandomGeneratorGetSeed(RandomGenerator* generator) {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#pragma once
|
||||
|
||||
#define MAX_CONTACTS 10
|
||||
#define MAX_TAGS 16
|
||||
#define MAX_TAGS 32
|
||||
#define NO_TAG ~0u
|
||||
|
||||
typedef struct World World;
|
||||
|
@ -17,8 +17,10 @@ typedef Shape SphereShape;
|
|||
typedef Shape BoxShape;
|
||||
typedef Shape CapsuleShape;
|
||||
typedef Shape CylinderShape;
|
||||
typedef Shape ConvexShape;
|
||||
typedef Shape MeshShape;
|
||||
typedef Shape TerrainShape;
|
||||
typedef Shape CompoundShape;
|
||||
|
||||
typedef Joint BallJoint;
|
||||
typedef Joint DistanceJoint;
|
||||
|
@ -26,8 +28,8 @@ typedef Joint HingeJoint;
|
|||
typedef Joint SliderJoint;
|
||||
|
||||
typedef void (*CollisionResolver)(World* world, void* userdata);
|
||||
typedef bool (*RaycastCallback)(Shape* shape, float x, float y, float z, float nx, float ny, float nz, void* userdata);
|
||||
typedef bool (*QueryCallback)(Shape* shape, void* userdata);
|
||||
typedef bool (*RaycastCallback)(Collider* collider, float position[3], float normal[3], uint32_t child, void* userdata);
|
||||
typedef bool (*QueryCallback)(Collider* collider, uint32_t child, void* userdata);
|
||||
|
||||
bool lovrPhysicsInit(void);
|
||||
void lovrPhysicsDestroy(void);
|
||||
|
@ -40,22 +42,40 @@ typedef struct {
|
|||
float depth;
|
||||
} Contact;
|
||||
|
||||
World* lovrWorldCreate(float xg, float yg, float zg, bool allowSleep, const char** tags, uint32_t tagCount);
|
||||
typedef struct {
|
||||
uint32_t maxColliders;
|
||||
uint32_t maxColliderPairs;
|
||||
uint32_t maxContacts;
|
||||
bool allowSleep;
|
||||
const char* tags[MAX_TAGS];
|
||||
uint32_t tagCount;
|
||||
} WorldInfo;
|
||||
|
||||
World* lovrWorldCreate(WorldInfo* info);
|
||||
void lovrWorldDestroy(void* ref);
|
||||
void lovrWorldDestroyData(World* world);
|
||||
uint32_t lovrWorldGetColliderCount(World* world);
|
||||
uint32_t lovrWorldGetJointCount(World* world);
|
||||
Collider* lovrWorldGetColliders(World* world, Collider* collider);
|
||||
Joint* lovrWorldGetJoints(World* world, Joint* joint);
|
||||
void lovrWorldUpdate(World* world, float dt, CollisionResolver resolver, void* userdata);
|
||||
int lovrWorldGetStepCount(World* world);
|
||||
void lovrWorldSetStepCount(World* world, int iterations);
|
||||
void lovrWorldComputeOverlaps(World* world);
|
||||
int lovrWorldGetNextOverlap(World* world, Shape** a, Shape** b);
|
||||
int lovrWorldCollide(World* world, Shape* a, Shape* b, float friction, float restitution);
|
||||
void lovrWorldGetContacts(World* world, Shape* a, Shape* b, Contact contacts[MAX_CONTACTS], uint32_t* count);
|
||||
void lovrWorldRaycast(World* world, float x1, float y1, float z1, float x2, float y2, float z2, RaycastCallback callback, void* userdata);
|
||||
void lovrWorldRaycast(World* world, float start[3], float end[3], RaycastCallback callback, void* userdata);
|
||||
bool lovrWorldQueryBox(World* world, float position[3], float size[3], QueryCallback callback, void* userdata);
|
||||
bool lovrWorldQuerySphere(World* world, float position[3], float radius, QueryCallback callback, void* userdata);
|
||||
Collider* lovrWorldGetFirstCollider(World* world);
|
||||
void lovrWorldGetGravity(World* world, float* x, float* y, float* z);
|
||||
void lovrWorldSetGravity(World* world, float x, float y, float z);
|
||||
void lovrWorldGetGravity(World* world, float gravity[3]);
|
||||
void lovrWorldSetGravity(World* world, float gravity[3]);
|
||||
const char* lovrWorldGetTagName(World* world, uint32_t tag);
|
||||
void lovrWorldDisableCollisionBetween(World* world, const char* tag1, const char* tag2);
|
||||
void lovrWorldEnableCollisionBetween(World* world, const char* tag1, const char* tag2);
|
||||
bool lovrWorldIsCollisionEnabledBetween(World* world, const char* tag1, const char* tag);
|
||||
|
||||
// Deprecated
|
||||
int lovrWorldGetStepCount(World* world);
|
||||
void lovrWorldSetStepCount(World* world, int iterations);
|
||||
float lovrWorldGetResponseTime(World* world);
|
||||
void lovrWorldSetResponseTime(World* world, float responseTime);
|
||||
float lovrWorldGetTightness(World* world);
|
||||
|
@ -66,26 +86,22 @@ void lovrWorldGetAngularDamping(World* world, float* damping, float* threshold);
|
|||
void lovrWorldSetAngularDamping(World* world, float damping, float threshold);
|
||||
bool lovrWorldIsSleepingAllowed(World* world);
|
||||
void lovrWorldSetSleepingAllowed(World* world, bool allowed);
|
||||
const char* lovrWorldGetTagName(World* world, uint32_t tag);
|
||||
void lovrWorldDisableCollisionBetween(World* world, const char* tag1, const char* tag2);
|
||||
void lovrWorldEnableCollisionBetween(World* world, const char* tag1, const char* tag2);
|
||||
bool lovrWorldIsCollisionEnabledBetween(World* world, const char* tag1, const char* tag);
|
||||
|
||||
// Collider
|
||||
|
||||
Collider* lovrColliderCreate(World* world, float x, float y, float z);
|
||||
Collider* lovrColliderCreate(World* world, Shape* shape, float position[3]);
|
||||
void lovrColliderDestroy(void* ref);
|
||||
void lovrColliderDestroyData(Collider* collider);
|
||||
bool lovrColliderIsDestroyed(Collider* collider);
|
||||
bool lovrColliderIsEnabled(Collider* collider);
|
||||
void lovrColliderSetEnabled(Collider* collider, bool enable);
|
||||
void lovrColliderInitInertia(Collider* collider, Shape* shape);
|
||||
World* lovrColliderGetWorld(Collider* collider);
|
||||
Collider* lovrColliderGetNext(Collider* collider);
|
||||
void lovrColliderAddShape(Collider* collider, Shape* shape);
|
||||
void lovrColliderRemoveShape(Collider* collider, Shape* shape);
|
||||
Shape** lovrColliderGetShapes(Collider* collider, size_t* count);
|
||||
Joint** lovrColliderGetJoints(Collider* collider, size_t* count);
|
||||
void* lovrColliderGetUserData(Collider* collider);
|
||||
void lovrColliderSetUserData(Collider* collider, void* data);
|
||||
Joint* lovrColliderGetJoints(Collider* collider, Joint* joint);
|
||||
Shape* lovrColliderGetShape(Collider* collider, uint32_t child);
|
||||
void lovrColliderSetShape(Collider* collider, Shape* shape);
|
||||
void lovrColliderGetShapeOffset(Collider* collider, float position[3], float orientation[4]);
|
||||
void lovrColliderSetShapeOffset(Collider* collider, float position[3], float orientation[4]);
|
||||
const char* lovrColliderGetTag(Collider* collider);
|
||||
bool lovrColliderSetTag(Collider* collider, const char* tag);
|
||||
float lovrColliderGetFriction(Collider* collider);
|
||||
|
@ -94,38 +110,45 @@ float lovrColliderGetRestitution(Collider* collider);
|
|||
void lovrColliderSetRestitution(Collider* collider, float restitution);
|
||||
bool lovrColliderIsKinematic(Collider* collider);
|
||||
void lovrColliderSetKinematic(Collider* collider, bool kinematic);
|
||||
bool lovrColliderIsGravityIgnored(Collider* collider);
|
||||
void lovrColliderSetGravityIgnored(Collider* collider, bool ignored);
|
||||
bool lovrColliderIsSensor(Collider* collider);
|
||||
void lovrColliderSetSensor(Collider* collider, bool sensor);
|
||||
bool lovrColliderIsContinuous(Collider* collider);
|
||||
void lovrColliderSetContinuous(Collider* collider, bool continuous);
|
||||
float lovrColliderGetGravityScale(Collider* collider);
|
||||
void lovrColliderSetGravityScale(Collider* collider, float scale);
|
||||
bool lovrColliderIsSleepingAllowed(Collider* collider);
|
||||
void lovrColliderSetSleepingAllowed(Collider* collider, bool allowed);
|
||||
bool lovrColliderIsAwake(Collider* collider);
|
||||
void lovrColliderSetAwake(Collider* collider, bool awake);
|
||||
float lovrColliderGetMass(Collider* collider);
|
||||
void lovrColliderSetMass(Collider* collider, float mass);
|
||||
void lovrColliderGetMassData(Collider* collider, float* cx, float* cy, float* cz, float* mass, float inertia[6]);
|
||||
void lovrColliderSetMassData(Collider* collider, float cx, float cy, float cz, float mass, float inertia[6]);
|
||||
void lovrColliderGetPosition(Collider* collider, float* x, float* y, float* z);
|
||||
void lovrColliderSetPosition(Collider* collider, float x, float y, float z);
|
||||
void lovrColliderGetOrientation(Collider* collider, float* orientation);
|
||||
void lovrColliderSetOrientation(Collider* collider, float* orientation);
|
||||
void lovrColliderGetLinearVelocity(Collider* collider, float* x, float* y, float* z);
|
||||
void lovrColliderSetLinearVelocity(Collider* collider, float x, float y, float z);
|
||||
void lovrColliderGetAngularVelocity(Collider* collider, float* x, float* y, float* z);
|
||||
void lovrColliderSetAngularVelocity(Collider* collider, float x, float y, float z);
|
||||
void lovrColliderGetMassData(Collider* collider, float centerOfMass[3], float* mass, float inertia[6]);
|
||||
void lovrColliderSetMassData(Collider* collider, float centerOfMass[3], float mass, float inertia[6]);
|
||||
void lovrColliderGetPosition(Collider* collider, float position[3]);
|
||||
void lovrColliderSetPosition(Collider* collider, float position[3]);
|
||||
void lovrColliderGetOrientation(Collider* collider, float orientation[4]);
|
||||
void lovrColliderSetOrientation(Collider* collider, float orientation[4]);
|
||||
void lovrColliderGetLinearVelocity(Collider* collider, float velocity[3]);
|
||||
void lovrColliderSetLinearVelocity(Collider* collider, float velocity[3]);
|
||||
void lovrColliderGetAngularVelocity(Collider* collider, float velocity[3]);
|
||||
void lovrColliderSetAngularVelocity(Collider* collider, float velocity[3]);
|
||||
void lovrColliderGetLinearDamping(Collider* collider, float* damping, float* threshold);
|
||||
void lovrColliderSetLinearDamping(Collider* collider, float damping, float threshold);
|
||||
void lovrColliderGetAngularDamping(Collider* collider, float* damping, float* threshold);
|
||||
void lovrColliderSetAngularDamping(Collider* collider, float damping, float threshold);
|
||||
void lovrColliderApplyForce(Collider* collider, float x, float y, float z);
|
||||
void lovrColliderApplyForceAtPosition(Collider* collider, float x, float y, float z, float cx, float cy, float cz);
|
||||
void lovrColliderApplyTorque(Collider* collider, float x, float y, float z);
|
||||
void lovrColliderGetLocalCenter(Collider* collider, float* x, float* y, float* z);
|
||||
void lovrColliderGetLocalPoint(Collider* collider, float wx, float wy, float wz, float* x, float* y, float* z);
|
||||
void lovrColliderGetWorldPoint(Collider* collider, float x, float y, float z, float* wx, float* wy, float* wz);
|
||||
void lovrColliderGetLocalVector(Collider* collider, float wx, float wy, float wz, float* x, float* y, float* z);
|
||||
void lovrColliderGetWorldVector(Collider* collider, float x, float y, float z, float* wx, float* wy, float* wz);
|
||||
void lovrColliderGetLinearVelocityFromLocalPoint(Collider* collider, float x, float y, float z, float* vx, float* vy, float* vz);
|
||||
void lovrColliderGetLinearVelocityFromWorldPoint(Collider* collider, float wx, float wy, float wz, float* vx, float* vy, float* vz);
|
||||
void lovrColliderApplyForce(Collider* collider, float force[3]);
|
||||
void lovrColliderApplyForceAtPosition(Collider* collider, float force[3], float position[3]);
|
||||
void lovrColliderApplyTorque(Collider* collider, float torque[3]);
|
||||
void lovrColliderApplyLinearImpulse(Collider* collider, float impulse[3]);
|
||||
void lovrColliderApplyLinearImpulseAtPosition(Collider* collider, float impulse[3], float position[3]);
|
||||
void lovrColliderApplyAngularImpulse(Collider* collider, float impulse[3]);
|
||||
void lovrColliderGetLocalCenter(Collider* collider, float center[3]);
|
||||
void lovrColliderGetLocalPoint(Collider* collider, float world[3], float local[3]);
|
||||
void lovrColliderGetWorldPoint(Collider* collider, float local[3], float world[3]);
|
||||
void lovrColliderGetLocalVector(Collider* collider, float world[3], float local[3]);
|
||||
void lovrColliderGetWorldVector(Collider* collider, float local[3], float world[3]);
|
||||
void lovrColliderGetLinearVelocityFromLocalPoint(Collider* collider, float point[3], float velocity[3]);
|
||||
void lovrColliderGetLinearVelocityFromWorldPoint(Collider* collider, float point[3], float velocity[3]);
|
||||
void lovrColliderGetAABB(Collider* collider, float aabb[6]);
|
||||
|
||||
// Shapes
|
||||
|
@ -135,58 +158,57 @@ typedef enum {
|
|||
SHAPE_BOX,
|
||||
SHAPE_CAPSULE,
|
||||
SHAPE_CYLINDER,
|
||||
SHAPE_CONVEX,
|
||||
SHAPE_MESH,
|
||||
SHAPE_TERRAIN
|
||||
SHAPE_TERRAIN,
|
||||
SHAPE_COMPOUND
|
||||
} ShapeType;
|
||||
|
||||
void lovrShapeDestroy(void* ref);
|
||||
void lovrShapeDestroyData(Shape* shape);
|
||||
ShapeType lovrShapeGetType(Shape* shape);
|
||||
Collider* lovrShapeGetCollider(Shape* shape);
|
||||
bool lovrShapeIsEnabled(Shape* shape);
|
||||
void lovrShapeSetEnabled(Shape* shape, bool enabled);
|
||||
bool lovrShapeIsSensor(Shape* shape);
|
||||
void lovrShapeSetSensor(Shape* shape, bool sensor);
|
||||
void* lovrShapeGetUserData(Shape* shape);
|
||||
void lovrShapeSetUserData(Shape* shape, void* data);
|
||||
void lovrShapeGetPosition(Shape* shape, float* x, float* y, float* z);
|
||||
void lovrShapeSetPosition(Shape* shape, float x, float y, float z);
|
||||
void lovrShapeGetOrientation(Shape* shape, float* orientation);
|
||||
void lovrShapeSetOrientation(Shape* shape, float* orientation);
|
||||
void lovrShapeGetMass(Shape* shape, float density, float* cx, float* cy, float* cz, float* mass, float inertia[6]);
|
||||
void lovrShapeGetAABB(Shape* shape, float aabb[6]);
|
||||
void lovrShapeGetMass(Shape* shape, float density, float centerOfMass[3], float* mass, float inertia[6]);
|
||||
void lovrShapeGetAABB(Shape* shape, float position[3], float orientation[4], float aabb[6]);
|
||||
|
||||
SphereShape* lovrSphereShapeCreate(float radius);
|
||||
float lovrSphereShapeGetRadius(SphereShape* sphere);
|
||||
void lovrSphereShapeSetRadius(SphereShape* sphere, float radius);
|
||||
|
||||
BoxShape* lovrBoxShapeCreate(float w, float h, float d);
|
||||
void lovrBoxShapeGetDimensions(BoxShape* box, float* w, float* h, float* d);
|
||||
void lovrBoxShapeSetDimensions(BoxShape* box, float w, float h, float d);
|
||||
BoxShape* lovrBoxShapeCreate(float dimensions[3]);
|
||||
void lovrBoxShapeGetDimensions(BoxShape* box, float dimensions[3]);
|
||||
|
||||
CapsuleShape* lovrCapsuleShapeCreate(float radius, float length);
|
||||
float lovrCapsuleShapeGetRadius(CapsuleShape* capsule);
|
||||
void lovrCapsuleShapeSetRadius(CapsuleShape* capsule, float radius);
|
||||
float lovrCapsuleShapeGetLength(CapsuleShape* capsule);
|
||||
void lovrCapsuleShapeSetLength(CapsuleShape* capsule, float length);
|
||||
|
||||
CylinderShape* lovrCylinderShapeCreate(float radius, float length);
|
||||
float lovrCylinderShapeGetRadius(CylinderShape* cylinder);
|
||||
void lovrCylinderShapeSetRadius(CylinderShape* cylinder, float radius);
|
||||
float lovrCylinderShapeGetLength(CylinderShape* cylinder);
|
||||
void lovrCylinderShapeSetLength(CylinderShape* cylinder, float length);
|
||||
|
||||
ConvexShape* lovrConvexShapeCreate(float points[], uint32_t count);
|
||||
|
||||
MeshShape* lovrMeshShapeCreate(int vertexCount, float vertices[], int indexCount, uint32_t indices[]);
|
||||
|
||||
TerrainShape* lovrTerrainShapeCreate(float* vertices, uint32_t widthSamples, uint32_t depthSamples, float horizontalScale, float verticalScale);
|
||||
TerrainShape* lovrTerrainShapeCreate(float* vertices, uint32_t n, float scaleXZ, float scaleY);
|
||||
|
||||
CompoundShape* lovrCompoundShapeCreate(Shape** shapes, float* positions, float* orientations, uint32_t count, bool freeze);
|
||||
bool lovrCompoundShapeIsFrozen(CompoundShape* shape);
|
||||
void lovrCompoundShapeAddChild(CompoundShape* shape, Shape* child, float position[3], float orientation[4]);
|
||||
void lovrCompoundShapeReplaceChild(CompoundShape* shape, uint32_t index, Shape* child, float position[3], float orientation[4]);
|
||||
void lovrCompoundShapeRemoveChild(CompoundShape* shape, uint32_t index);
|
||||
Shape* lovrCompoundShapeGetChild(CompoundShape* shape, uint32_t index);
|
||||
uint32_t lovrCompoundShapeGetChildCount(CompoundShape* shape);
|
||||
void lovrCompoundShapeGetChildOffset(CompoundShape* shape, uint32_t index, float position[3], float orientation[4]);
|
||||
void lovrCompoundShapeSetChildOffset(CompoundShape* shape, uint32_t index, float position[3], float orientation[4]);
|
||||
|
||||
// These tokens need to exist for Lua bindings
|
||||
#define lovrSphereShapeDestroy lovrShapeDestroy
|
||||
#define lovrBoxShapeDestroy lovrShapeDestroy
|
||||
#define lovrCapsuleShapeDestroy lovrShapeDestroy
|
||||
#define lovrCylinderShapeDestroy lovrShapeDestroy
|
||||
#define lovrConvexShapeDestroy lovrShapeDestroy
|
||||
#define lovrMeshShapeDestroy lovrShapeDestroy
|
||||
#define lovrTerrainShapeDestroy lovrShapeDestroy
|
||||
#define lovrCompoundShapeDestroy lovrShapeDestroy
|
||||
|
||||
// Joints
|
||||
|
||||
|
@ -199,14 +221,11 @@ typedef enum {
|
|||
|
||||
void lovrJointDestroy(void* ref);
|
||||
void lovrJointDestroyData(Joint* joint);
|
||||
bool lovrJointIsDestroyed(Joint* joint);
|
||||
JointType lovrJointGetType(Joint* joint);
|
||||
float lovrJointGetCFM(Joint* joint);
|
||||
void lovrJointSetCFM(Joint* joint, float cfm);
|
||||
float lovrJointGetERP(Joint* joint);
|
||||
void lovrJointSetERP(Joint* joint, float erp);
|
||||
void lovrJointGetColliders(Joint* joint, Collider** a, Collider** b);
|
||||
void* lovrJointGetUserData(Joint* joint);
|
||||
void lovrJointSetUserData(Joint* joint, void* data);
|
||||
Collider* lovrJointGetColliderA(Joint* joint);
|
||||
Collider* lovrJointGetColliderB(Joint* joint);
|
||||
Joint* lovrJointGetNext(Joint* joint, Collider* collider);
|
||||
bool lovrJointIsEnabled(Joint* joint);
|
||||
void lovrJointSetEnabled(Joint* joint, bool enable);
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -188,3 +188,11 @@ bool lovrSystemWasMouseReleased(int button) {
|
|||
float lovrSystemGetScrollDelta(void) {
|
||||
return state.scrollDelta;
|
||||
}
|
||||
|
||||
const char* lovrSystemGetClipboardText(void) {
|
||||
return os_get_clipboard_text();
|
||||
}
|
||||
|
||||
void lovrSystemSetClipboardText(const char* text) {
|
||||
os_set_clipboard_text(text);
|
||||
}
|
||||
|
|
|
@ -30,3 +30,5 @@ bool lovrSystemIsMouseDown(int button);
|
|||
bool lovrSystemWasMousePressed(int button);
|
||||
bool lovrSystemWasMouseReleased(int button);
|
||||
float lovrSystemGetScrollDelta(void);
|
||||
const char* lovrSystemGetClipboardText(void);
|
||||
void lovrSystemSetClipboardText(const char* text);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "thread/thread.h"
|
||||
#include "data/blob.h"
|
||||
#include "event/event.h"
|
||||
#include "core/job.h"
|
||||
#include "core/os.h"
|
||||
#include "util.h"
|
||||
#include <math.h>
|
||||
|
@ -38,10 +39,16 @@ static struct {
|
|||
map_t channels;
|
||||
} state;
|
||||
|
||||
bool lovrThreadModuleInit(void) {
|
||||
bool lovrThreadModuleInit(int32_t workers) {
|
||||
if (atomic_fetch_add(&state.ref, 1)) return false;
|
||||
mtx_init(&state.channelLock, mtx_plain);
|
||||
map_init(&state.channels, 0);
|
||||
|
||||
uint32_t cores = os_get_core_count();
|
||||
if (workers < 0) workers += cores;
|
||||
workers = MAX(workers, 0);
|
||||
job_init(workers);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -54,6 +61,7 @@ void lovrThreadModuleDestroy(void) {
|
|||
}
|
||||
mtx_destroy(&state.channelLock);
|
||||
map_free(&state.channels);
|
||||
job_destroy();
|
||||
memset(&state, 0, sizeof(state));
|
||||
}
|
||||
|
||||
|
@ -102,8 +110,7 @@ static int threadFunction(void* data) {
|
|||
}
|
||||
|
||||
Thread* lovrThreadCreate(ThreadFunction* function, Blob* body) {
|
||||
Thread* thread = calloc(1, sizeof(Thread));
|
||||
lovrAssert(thread, "Out of memory");
|
||||
Thread* thread = lovrCalloc(sizeof(Thread));
|
||||
thread->ref = 1;
|
||||
thread->body = body;
|
||||
thread->function = function;
|
||||
|
@ -117,8 +124,8 @@ void lovrThreadDestroy(void* ref) {
|
|||
mtx_destroy(&thread->lock);
|
||||
if (thread->handle) thrd_detach(thread->handle);
|
||||
lovrRelease(thread->body, lovrBlobDestroy);
|
||||
free(thread->error);
|
||||
free(thread);
|
||||
lovrFree(thread->error);
|
||||
lovrFree(thread);
|
||||
}
|
||||
|
||||
void lovrThreadStart(Thread* thread, Variant* arguments, uint32_t argumentCount) {
|
||||
|
@ -128,10 +135,10 @@ void lovrThreadStart(Thread* thread, Variant* arguments, uint32_t argumentCount)
|
|||
return;
|
||||
}
|
||||
|
||||
free(thread->error);
|
||||
lovrFree(thread->error);
|
||||
thread->error = NULL;
|
||||
|
||||
lovrAssert(argumentCount <= MAX_THREAD_ARGUMENTS, "Too many Thread arguments (max is %d)", MAX_THREAD_ARGUMENTS);
|
||||
lovrCheck(argumentCount <= MAX_THREAD_ARGUMENTS, "Too many Thread arguments (max is %d)", MAX_THREAD_ARGUMENTS);
|
||||
memcpy(thread->arguments, arguments, argumentCount * sizeof(Variant));
|
||||
thread->argumentCount = argumentCount;
|
||||
|
||||
|
@ -162,10 +169,9 @@ const char* lovrThreadGetError(Thread* thread) {
|
|||
// Channel
|
||||
|
||||
Channel* lovrChannelCreate(uint64_t hash) {
|
||||
Channel* channel = calloc(1, sizeof(Channel));
|
||||
lovrAssert(channel, "Out of memory");
|
||||
Channel* channel = lovrCalloc(sizeof(Channel));
|
||||
channel->ref = 1;
|
||||
arr_init(&channel->messages, arr_alloc);
|
||||
arr_init(&channel->messages);
|
||||
mtx_init(&channel->lock, mtx_plain);
|
||||
cnd_init(&channel->cond);
|
||||
channel->hash = hash;
|
||||
|
@ -178,7 +184,7 @@ void lovrChannelDestroy(void* ref) {
|
|||
arr_free(&channel->messages);
|
||||
mtx_destroy(&channel->lock);
|
||||
cnd_destroy(&channel->cond);
|
||||
free(channel);
|
||||
lovrFree(channel);
|
||||
}
|
||||
|
||||
bool lovrChannelPush(Channel* channel, Variant* variant, double timeout, uint64_t* id) {
|
||||
|
|
|
@ -14,7 +14,7 @@ struct Variant;
|
|||
typedef struct Thread Thread;
|
||||
typedef struct Channel Channel;
|
||||
|
||||
bool lovrThreadModuleInit(void);
|
||||
bool lovrThreadModuleInit(int32_t workers);
|
||||
void lovrThreadModuleDestroy(void);
|
||||
struct Channel* lovrThreadGetChannel(const char* name);
|
||||
|
||||
|
|
187
src/util.c
187
src/util.c
|
@ -1,42 +1,37 @@
|
|||
#include "util.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdatomic.h>
|
||||
#include <setjmp.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// Error handling
|
||||
static LOVR_THREAD_LOCAL errorFn* lovrErrorCallback;
|
||||
static LOVR_THREAD_LOCAL void* lovrErrorUserdata;
|
||||
// Allocation
|
||||
|
||||
void lovrSetErrorCallback(errorFn* callback, void* userdata) {
|
||||
lovrErrorCallback = callback;
|
||||
lovrErrorUserdata = userdata;
|
||||
void* lovrMalloc(size_t size) {
|
||||
void* data = malloc(size);
|
||||
lovrAssert(data, "Out of memory");
|
||||
return data;
|
||||
}
|
||||
|
||||
void lovrThrow(const char* format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
lovrErrorCallback(lovrErrorUserdata, format, args);
|
||||
va_end(args);
|
||||
exit(EXIT_FAILURE);
|
||||
void* lovrCalloc(size_t size) {
|
||||
void* data = calloc(1, size);
|
||||
lovrAssert(data, "Out of memory");
|
||||
return data;
|
||||
}
|
||||
|
||||
// Logging
|
||||
logFn* lovrLogCallback;
|
||||
void* lovrLogUserdata;
|
||||
|
||||
void lovrSetLogCallback(logFn* callback, void* userdata) {
|
||||
lovrLogCallback = callback;
|
||||
lovrLogUserdata = userdata;
|
||||
void* lovrRealloc(void* old, size_t size) {
|
||||
void* data = realloc(old, size);
|
||||
lovrAssert(data, "Out of memory");
|
||||
return data;
|
||||
}
|
||||
|
||||
void lovrLog(int level, const char* tag, const char* format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
lovrLogCallback(lovrLogUserdata, level, tag, format, args);
|
||||
va_end(args);
|
||||
void lovrFree(void* data) {
|
||||
free(data);
|
||||
}
|
||||
|
||||
// Refcounting
|
||||
|
||||
#if ATOMIC_INT_LOCK_FREE != 2
|
||||
#error "Lock-free integer atomics are not supported on this platform, but are required for refcounting"
|
||||
#endif
|
||||
|
@ -53,18 +48,119 @@ void lovrRelease(void* object, void (*destructor)(void*)) {
|
|||
}
|
||||
}
|
||||
|
||||
// Dynamic Array
|
||||
// Default malloc-based allocator for arr_t (like realloc except well-defined when size is 0)
|
||||
void* arr_alloc(void* data, size_t size) {
|
||||
if (size > 0) {
|
||||
return realloc(data, size);
|
||||
} else {
|
||||
free(data);
|
||||
return NULL;
|
||||
// Defer
|
||||
|
||||
typedef struct {
|
||||
void (*fn)(void*);
|
||||
void* arg;
|
||||
} Closure;
|
||||
|
||||
static LOVR_THREAD_LOCAL struct {
|
||||
Closure stack[16];
|
||||
uint16_t releaseMask;
|
||||
uint16_t errMask;
|
||||
uint32_t top;
|
||||
} defer;
|
||||
|
||||
uint32_t lovrDeferPush(void) {
|
||||
return defer.top;
|
||||
}
|
||||
|
||||
static void deferPop(uint32_t base, bool err) {
|
||||
while (defer.top > base) {
|
||||
uint32_t index = --defer.top;
|
||||
Closure c = defer.stack[index];
|
||||
if (err || (defer.errMask & (1u << index)) == 0) {
|
||||
if (defer.releaseMask & (1u << index)) {
|
||||
lovrRelease(c.arg, c.fn);
|
||||
} else {
|
||||
c.fn(c.arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void lovrDeferPop(uint32_t base) {
|
||||
deferPop(base, false);
|
||||
}
|
||||
|
||||
void lovrDefer(void (*fn)(void*), void* arg) {
|
||||
lovrAssert(defer.top < COUNTOF(defer.stack), "Defer stack overflow!");
|
||||
defer.releaseMask &= ~(1u << defer.top);
|
||||
defer.errMask &= ~(1u << defer.top);
|
||||
defer.stack[defer.top++] = (Closure) { fn, arg };
|
||||
}
|
||||
|
||||
void lovrErrDefer(void (*fn)(void*), void* arg) {
|
||||
lovrAssert(defer.top < COUNTOF(defer.stack), "Defer stack overflow!");
|
||||
defer.releaseMask &= ~(1u << defer.top);
|
||||
defer.errMask |= (1u << defer.top);
|
||||
defer.stack[defer.top++] = (Closure) { fn, arg };
|
||||
}
|
||||
|
||||
void lovrDeferRelease(void* object, void (*destructor)(void*)) {
|
||||
if (!object) return;
|
||||
lovrAssert(defer.top < COUNTOF(defer.stack), "Defer stack overflow!");
|
||||
defer.releaseMask |= (1u << defer.top);
|
||||
defer.errMask &= ~(1u << defer.top);
|
||||
defer.stack[defer.top++] = (Closure) { destructor, object };
|
||||
}
|
||||
|
||||
// Exceptions
|
||||
|
||||
typedef struct Handler {
|
||||
struct Handler* prev;
|
||||
uint32_t baseDefer;
|
||||
void (*catch)(void* arg, const char* format, va_list args);
|
||||
void* arg;
|
||||
jmp_buf env;
|
||||
} Handler;
|
||||
|
||||
static LOVR_THREAD_LOCAL Handler* lovrHandler;
|
||||
|
||||
void lovrTry(void (*fn)(void*), void* arg, void(*catch)(void*, const char*, va_list), void* catchArg) {
|
||||
lovrHandler = &(Handler) {
|
||||
.prev = lovrHandler,
|
||||
.baseDefer = defer.top,
|
||||
.catch = catch,
|
||||
.arg = arg
|
||||
};
|
||||
|
||||
if (setjmp(lovrHandler->env) == 0) {
|
||||
fn(arg);
|
||||
}
|
||||
|
||||
lovrHandler = lovrHandler->prev;
|
||||
}
|
||||
|
||||
void lovrThrow(const char* format, ...) {
|
||||
deferPop(lovrHandler->baseDefer, true);
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
lovrHandler->catch(lovrHandler->arg, format, args);
|
||||
va_end(args);
|
||||
longjmp(lovrHandler->env, 1);
|
||||
}
|
||||
|
||||
// Logging
|
||||
|
||||
static fn_log* lovrLogCallback;
|
||||
static void* lovrLogUserdata;
|
||||
|
||||
void lovrSetLogCallback(fn_log* callback, void* userdata) {
|
||||
lovrLogCallback = callback;
|
||||
lovrLogUserdata = userdata;
|
||||
}
|
||||
|
||||
void lovrLog(int level, const char* tag, const char* format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
lovrLogCallback(lovrLogUserdata, level, tag, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
// Hashmap
|
||||
|
||||
static void map_rehash(map_t* map) {
|
||||
map_t old = *map;
|
||||
map->size <<= 1;
|
||||
|
@ -129,34 +225,9 @@ void map_set(map_t* map, uint64_t hash, uint64_t value) {
|
|||
map->values[h] = value;
|
||||
}
|
||||
|
||||
void map_remove(map_t* map, uint64_t hash) {
|
||||
uint64_t h = map_find(map, hash);
|
||||
|
||||
if (map->hashes[h] == MAP_NIL) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t mask = map->size - 1;
|
||||
uint64_t i = h;
|
||||
|
||||
do {
|
||||
i = (i + 1) & mask;
|
||||
uint64_t x = map->hashes[i] & mask;
|
||||
// Removing a key from an open-addressed hash table is complicated
|
||||
if ((i > h && (x <= h || x > i)) || (i < h && (x <= h && x > i))) {
|
||||
map->hashes[h] = map->hashes[i];
|
||||
map->values[h] = map->values[i];
|
||||
h = i;
|
||||
}
|
||||
} while (map->hashes[i] != MAP_NIL);
|
||||
|
||||
map->hashes[i] = MAP_NIL;
|
||||
map->values[i] = MAP_NIL;
|
||||
map->used--;
|
||||
}
|
||||
|
||||
// UTF-8
|
||||
// https://github.com/starwing/luautf8
|
||||
|
||||
size_t utf8_decode(const char *s, const char *e, unsigned *pch) {
|
||||
unsigned ch;
|
||||
|
||||
|
|
94
src/util.h
94
src/util.h
|
@ -6,7 +6,7 @@
|
|||
|
||||
#define LOVR_VERSION_MAJOR 0
|
||||
#define LOVR_VERSION_MINOR 17
|
||||
#define LOVR_VERSION_PATCH 0
|
||||
#define LOVR_VERSION_PATCH 1
|
||||
#define LOVR_VERSION_ALIAS "Tritium Gourmet"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
@ -33,13 +33,28 @@
|
|||
#define CHECK_SIZEOF(T) int(*_o)[sizeof(T)]=1
|
||||
#define BREAK() __asm("int $3")
|
||||
|
||||
// Error handling
|
||||
typedef void errorFn(void*, const char*, va_list);
|
||||
void lovrSetErrorCallback(errorFn* callback, void* userdata);
|
||||
LOVR_NORETURN void lovrThrow(const char* format, ...);
|
||||
#define lovrAssert(c, ...) if (!(c)) { lovrThrow(__VA_ARGS__); }
|
||||
#define lovrUnreachable() lovrThrow("Unreachable")
|
||||
// Allocation
|
||||
void* lovrMalloc(size_t size);
|
||||
void* lovrCalloc(size_t size);
|
||||
void* lovrRealloc(void* data, size_t size);
|
||||
void lovrFree(void* data);
|
||||
|
||||
// Refcounting (to be refcounted, a struct must have a uint32_t refcount as its first field)
|
||||
void lovrRetain(void* ref);
|
||||
void lovrRelease(void* ref, void (*destructor)(void*));
|
||||
|
||||
// Defer
|
||||
uint32_t lovrDeferPush(void);
|
||||
void lovrDeferPop(uint32_t base);
|
||||
void lovrDefer(void (*fn)(void*), void* arg);
|
||||
void lovrErrDefer(void (*fn)(void*), void* arg);
|
||||
void lovrDeferRelease(void* ref, void (*destructor)(void*));
|
||||
|
||||
// Exceptions
|
||||
void lovrTry(void (*fn)(void*), void* arg, void (*catch)(void*, const char*, va_list), void* catchArg);
|
||||
LOVR_NORETURN void lovrThrow(const char* format, ...);
|
||||
#define lovrAssert(c, ...) do { if (!(c)) { lovrThrow(__VA_ARGS__); } } while(0)
|
||||
#define lovrUnreachable() lovrThrow("Unreachable")
|
||||
#ifdef LOVR_UNCHECKED
|
||||
#define lovrCheck(c, ...) ((void) 0)
|
||||
#else
|
||||
|
@ -47,11 +62,42 @@ LOVR_NORETURN void lovrThrow(const char* format, ...);
|
|||
#endif
|
||||
|
||||
// Logging
|
||||
typedef void logFn(void*, int, const char*, const char*, va_list);
|
||||
typedef void fn_log(void*, int, const char*, const char*, va_list);
|
||||
enum { LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR };
|
||||
void lovrSetLogCallback(logFn* callback, void* userdata);
|
||||
void lovrSetLogCallback(fn_log* callback, void* userdata);
|
||||
void lovrLog(int level, const char* tag, const char* format, ...);
|
||||
|
||||
// Profiling
|
||||
#ifdef LOVR_PROFILE
|
||||
#include <TracyC.h>
|
||||
#define lovrProfileMarkFrame() TracyCFrameMark
|
||||
#define lovrProfileStart(id, label) TracyCZoneN(id, label, true)
|
||||
#define lovrProfileEnd(id) TracyCZoneEnd(id)
|
||||
#else
|
||||
#define lovrProfileMarkFrame() ((void) 0)
|
||||
#define lovrProfileStart(id, label) ((void) 0)
|
||||
#define lovrProfileEnd(id) ((void) 0)
|
||||
#endif
|
||||
|
||||
// Dynamic Array
|
||||
#define arr_t(T) struct { T* data; size_t length, capacity; }
|
||||
#define arr_init(a) (a)->data = NULL, (a)->length = 0, (a)->capacity = 0
|
||||
#define arr_free(a) if ((a)->data) lovrFree((a)->data)
|
||||
#define arr_reserve(a, n) _arr_reserve((void**) &((a)->data), n, &(a)->capacity, sizeof(*(a)->data))
|
||||
#define arr_expand(a, n) arr_reserve(a, (a)->length + n)
|
||||
#define arr_push(a, x) arr_reserve(a, (a)->length + 1), (a)->data[(a)->length] = x, (a)->length++
|
||||
#define arr_pop(a) (a)->data[--(a)->length]
|
||||
#define arr_append(a, p, n) arr_reserve(a, (a)->length + n), memcpy((a)->data + (a)->length, p, n * sizeof(*(p))), (a)->length += n
|
||||
#define arr_splice(a, i, n) memmove((a)->data + (i), (a)->data + ((i) + n), ((a)->length - (i) - (n)) * sizeof(*(a)->data)), (a)->length -= n
|
||||
#define arr_clear(a) (a)->length = 0
|
||||
|
||||
static inline void _arr_reserve(void** data, size_t n, size_t* capacity, size_t stride) {
|
||||
if (*capacity >= n) return;
|
||||
if (*capacity == 0) *capacity = 1;
|
||||
while (*capacity < n) *capacity *= 2;
|
||||
*data = lovrRealloc(*data, *capacity * stride);
|
||||
}
|
||||
|
||||
// Hash function (FNV1a)
|
||||
static inline uint64_t hash64(const void* data, size_t length) {
|
||||
const uint8_t* bytes = (const uint8_t*) data;
|
||||
|
@ -62,34 +108,7 @@ static inline uint64_t hash64(const void* data, size_t length) {
|
|||
return hash;
|
||||
}
|
||||
|
||||
// Refcounting
|
||||
void lovrRetain(void* ref);
|
||||
void lovrRelease(void* ref, void (*destructor)(void*));
|
||||
|
||||
// Dynamic Array
|
||||
typedef void* arr_allocator(void* data, size_t size);
|
||||
#define arr_t(T) struct { T* data; arr_allocator* alloc; size_t length, capacity; }
|
||||
#define arr_init(a, allocator) (a)->data = NULL, (a)->length = 0, (a)->capacity = 0, (a)->alloc = allocator
|
||||
#define arr_free(a) if ((a)->data) (a)->alloc((a)->data, 0)
|
||||
#define arr_reserve(a, n) _arr_reserve((void**) &((a)->data), n, &(a)->capacity, sizeof(*(a)->data), (a)->alloc)
|
||||
#define arr_expand(a, n) arr_reserve(a, (a)->length + n)
|
||||
#define arr_push(a, x) arr_reserve(a, (a)->length + 1), (a)->data[(a)->length] = x, (a)->length++
|
||||
#define arr_pop(a) (a)->data[--(a)->length]
|
||||
#define arr_append(a, p, n) arr_reserve(a, (a)->length + n), memcpy((a)->data + (a)->length, p, n * sizeof(*(p))), (a)->length += n
|
||||
#define arr_splice(a, i, n) memmove((a)->data + (i), (a)->data + ((i) + n), ((a)->length - (i) - (n)) * sizeof(*(a)->data)), (a)->length -= n
|
||||
#define arr_clear(a) (a)->length = 0
|
||||
|
||||
void* arr_alloc(void* data, size_t size);
|
||||
|
||||
static inline void _arr_reserve(void** data, size_t n, size_t* capacity, size_t stride, arr_allocator* allocator) {
|
||||
if (*capacity >= n) return;
|
||||
if (*capacity == 0) *capacity = 1;
|
||||
while (*capacity < n) *capacity *= 2;
|
||||
*data = allocator(*data, *capacity * stride);
|
||||
lovrAssert(*data, "Out of memory");
|
||||
}
|
||||
|
||||
// Hashmap
|
||||
// Hashmap (does not support removal)
|
||||
typedef struct {
|
||||
uint64_t* hashes;
|
||||
uint64_t* values;
|
||||
|
@ -103,7 +122,6 @@ void map_init(map_t* map, uint32_t n);
|
|||
void map_free(map_t* map);
|
||||
uint64_t map_get(map_t* map, uint64_t hash);
|
||||
void map_set(map_t* map, uint64_t hash, uint64_t value);
|
||||
void map_remove(map_t* map, uint64_t hash);
|
||||
|
||||
// UTF-8
|
||||
size_t utf8_decode(const char *s, const char *e, unsigned *pch);
|
||||
|
|
Loading…
Reference in New Issue