mirror of https://github.com/bjornbytes/lovr.git
rm graphics module;
This commit is contained in:
parent
218134d79c
commit
37221afbc6
|
@ -39,7 +39,6 @@ set(LOVR_SYMBOL_VISIBILITY "hidden" CACHE STRING "What should the C symbol visib
|
|||
if(EMSCRIPTEN)
|
||||
string(CONCAT LOVR_EMSCRIPTEN_FLAGS
|
||||
"-Os "
|
||||
"-s USE_WEBGL2=1 "
|
||||
"-s FORCE_FILESYSTEM=1 "
|
||||
"-s \"EXPORTED_FUNCTIONS=['_main','_lovrDestroy','_webxr_attach','_webxr_detach','_lovrCanvasCreateFromHandle','_lovrCanvasDestroy','_lovrGraphicsSetBackbuffer','_lovrGraphicsSetViewMatrix','_lovrGraphicsSetProjection']\" "
|
||||
"-s \"EXTRA_EXPORTED_RUNTIME_METHODS=['getValue','setValue']\" "
|
||||
|
@ -164,16 +163,6 @@ if(LOVR_ENABLE_PHYSICS)
|
|||
endif()
|
||||
endif()
|
||||
|
||||
# OpenGL
|
||||
if(NOT (WIN32 OR EMSCRIPTEN OR ANDROID))
|
||||
if(UNIX AND NOT APPLE)
|
||||
set(OpenGL_GL_PREFERENCE "GLVND")
|
||||
endif()
|
||||
find_package(OpenGL REQUIRED)
|
||||
include_directories(${OPENGL_INCLUDE_DIRS})
|
||||
set(LOVR_OPENGL ${OPENGL_LIBRARIES})
|
||||
endif()
|
||||
|
||||
# OpenXR
|
||||
if(LOVR_ENABLE_HEADSET AND LOVR_USE_OPENXR)
|
||||
include_directories(deps/openxr/include)
|
||||
|
@ -329,7 +318,6 @@ target_link_libraries(lovr
|
|||
${LOVR_LUA}
|
||||
${LOVR_MSDF}
|
||||
${LOVR_ODE}
|
||||
${LOVR_OPENGL}
|
||||
${LOVR_OPENXR}
|
||||
${LOVR_OCULUS_AUDIO}
|
||||
${LOVR_PTHREADS}
|
||||
|
@ -418,22 +406,8 @@ endif()
|
|||
|
||||
if(LOVR_ENABLE_GRAPHICS)
|
||||
target_sources(lovr PRIVATE
|
||||
src/modules/graphics/font.c
|
||||
src/modules/graphics/graphics.c
|
||||
src/modules/graphics/material.c
|
||||
src/modules/graphics/model.c
|
||||
src/modules/graphics/opengl.c
|
||||
src/api/l_graphics.c
|
||||
src/api/l_graphics_canvas.c
|
||||
src/api/l_graphics_font.c
|
||||
src/api/l_graphics_material.c
|
||||
src/api/l_graphics_mesh.c
|
||||
src/api/l_graphics_model.c
|
||||
src/api/l_graphics_shader.c
|
||||
src/api/l_graphics_shaderBlock.c
|
||||
src/api/l_graphics_texture.c
|
||||
src/lib/glad/glad.c
|
||||
etc/shaders.c
|
||||
)
|
||||
else()
|
||||
target_compile_definitions(lovr PRIVATE LOVR_DISABLE_GRAPHICS)
|
||||
|
@ -576,13 +550,11 @@ if(WIN32)
|
|||
foreach(target ${ALL_PLUGIN_TARGETS})
|
||||
move_dll(${target})
|
||||
endforeach()
|
||||
target_compile_definitions(lovr PRIVATE LOVR_GL)
|
||||
elseif(APPLE)
|
||||
find_library(AVFOUNDATION AVFoundation)
|
||||
target_link_libraries(lovr objc ${AVFOUNDATION})
|
||||
target_sources(lovr PRIVATE src/core/os_macos.c)
|
||||
set_source_files_properties(src/core/os_macos.c PROPERTIES COMPILE_FLAGS -xobjective-c)
|
||||
target_compile_definitions(lovr PRIVATE LOVR_GL)
|
||||
set_target_properties(lovr PROPERTIES
|
||||
MACOSX_RPATH TRUE
|
||||
BUILD_WITH_INSTALL_RPATH TRUE
|
||||
|
@ -629,12 +601,10 @@ elseif(APPLE)
|
|||
endforeach()
|
||||
elseif(EMSCRIPTEN)
|
||||
target_sources(lovr PRIVATE src/core/os_wasm.c)
|
||||
target_compile_definitions(lovr PRIVATE LOVR_WEBGL)
|
||||
configure_file(etc/lovr.ico favicon.ico COPYONLY)
|
||||
elseif(ANDROID)
|
||||
target_sources(lovr PRIVATE src/core/os_android.c)
|
||||
target_link_libraries(lovr log EGL GLESv3 android dl)
|
||||
target_compile_definitions(lovr PRIVATE LOVR_GLES)
|
||||
target_link_libraries(lovr log EGL android dl)
|
||||
target_include_directories(lovr PRIVATE "${ANDROID_NDK}/sources/android/native_app_glue")
|
||||
|
||||
# Dynamically linked targets output libraries in raw/lib/<ABI> for easy including in apk with aapt
|
||||
|
@ -732,7 +702,6 @@ elseif(UNIX)
|
|||
target_compile_definitions(lovr PRIVATE LOVR_LINUX_X11)
|
||||
endif()
|
||||
target_sources(lovr PRIVATE src/core/os_linux.c)
|
||||
target_compile_definitions(lovr PRIVATE LOVR_GL)
|
||||
set_target_properties(lovr PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
|
||||
BUILD_WITH_INSTALL_RPATH TRUE
|
||||
|
|
17
Tupfile.lua
17
Tupfile.lua
|
@ -109,7 +109,6 @@ lflags += not config.debug and '-Wl,-s' or ''
|
|||
lflags += config.optimize and (target == 'macos' and '-Wl,-dead_strip' or '-Wl,--gc-sections') or ''
|
||||
|
||||
if target == 'win32' then
|
||||
cflags += '-DLOVR_GL'
|
||||
cflags += '-D_CRT_SECURE_NO_WARNINGS'
|
||||
cflags += '-DWINVER=0x0600' -- Vista
|
||||
cflags += '-D_WIN32_WINNT=0x0600'
|
||||
|
@ -124,7 +123,6 @@ if target == 'win32' then
|
|||
end
|
||||
|
||||
if target == 'macos' then
|
||||
cflags += '-DLOVR_GL'
|
||||
cflags_os_macos += '-xobjective-c'
|
||||
lflags += '-Wl,-rpath,@executable_path'
|
||||
lflags += '-lobjc'
|
||||
|
@ -132,7 +130,6 @@ if target == 'macos' then
|
|||
end
|
||||
|
||||
if target == 'linux' then
|
||||
cflags += '-DLOVR_GL'
|
||||
cflags += '-D_POSIX_C_SOURCE=200809L'
|
||||
cflags += '-D_DEFAULT_SOURCE'
|
||||
lflags += '-lm -lpthread -ldl'
|
||||
|
@ -143,15 +140,9 @@ if target == 'wasm' then
|
|||
cc = 'emcc'
|
||||
cxx = 'em++'
|
||||
cflags += '-std=gnu11'
|
||||
cflags += '-DLOVR_WEBGL'
|
||||
cflags += '-D_POSIX_C_SOURCE=200809L'
|
||||
lflags += '-s USE_WEBGL2'
|
||||
lflags += '-s FORCE_FILESYSTEM'
|
||||
lflags += ([[-s EXPORTED_FUNCTIONS="[
|
||||
'_main','_lovrDestroy','_webxr_attach','_webxr_detach',
|
||||
'_lovrCanvasCreateFromHandle','_lovrCanvasDestroy',
|
||||
'_lovrGraphicsSetBackbuffer','_lovrGraphicsSetViewMatrix','_lovrGraphicsSetProjection'
|
||||
]"]]):gsub('%s', '')
|
||||
lflags += ([[-s EXPORTED_FUNCTIONS="['_main','_lovrDestroy','_webxr_attach','_webxr_detach']"]])
|
||||
if config.headsets.webxr then
|
||||
lflags += '--js-library etc/webxr.js'
|
||||
end
|
||||
|
@ -171,14 +162,12 @@ if target == 'android' then
|
|||
cxx = cc .. '++'
|
||||
flags += '--target=aarch64-linux-android' .. config.android.version
|
||||
flags += config.debug and '-funwind-tables' or ''
|
||||
cflags += '-DLOVR_GLES'
|
||||
cflags += '-D_POSIX_C_SOURCE=200809L'
|
||||
cflags += ('-I%s/sources/android/native_app_glue'):format(config.android.ndk)
|
||||
lflags += '-shared -landroid -lEGL -lGLESv3'
|
||||
lflags += '-shared -landroid'
|
||||
end
|
||||
|
||||
troublemakers = {
|
||||
glad = '-Wno-pedantic',
|
||||
os_android = '-Wno-format-pedantic',
|
||||
miniaudio = '-Wno-unused-function -Wno-pedantic',
|
||||
}
|
||||
|
@ -392,8 +381,6 @@ src += 'src/lib/stb/*.c'
|
|||
src += (config.modules.audio or config.modules.data) and 'src/lib/miniaudio/*.c' or nil
|
||||
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.graphics and 'src/lib/glad/*.c' or nil
|
||||
src += config.modules.graphics and 'etc/shaders.c' or nil
|
||||
src += config.modules.math and 'src/lib/noise/*.c' or nil
|
||||
src += config.modules.thread and 'src/lib/tinycthread/*.c' or nil
|
||||
|
||||
|
|
151
etc/boot.lua
151
etc/boot.lua
|
@ -11,87 +11,12 @@ local function nogame()
|
|||
local models = {}
|
||||
|
||||
function lovr.load()
|
||||
if not lovr.graphics then
|
||||
print(string.format('LÖVR %d.%d.%d\nNo game', lovr.getVersion()))
|
||||
lovr.event.quit()
|
||||
return
|
||||
end
|
||||
|
||||
lovr.graphics.setBackgroundColor(0x20232c)
|
||||
lovr.graphics.setCullingEnabled(true)
|
||||
|
||||
logo = lovr.graphics.newShader([[
|
||||
vec4 position(mat4 projection, mat4 transform, vec4 vertex) {
|
||||
return projection * transform * vertex;
|
||||
}
|
||||
]], [[
|
||||
vec4 color(vec4 graphicsColor, sampler2D image, vec2 uv) {
|
||||
float y = (1. - uv.y);
|
||||
uv = uv * 4. - 2.;
|
||||
const float k = sqrt(3.);
|
||||
uv.x = abs(uv.x) - 1.;
|
||||
uv.y = uv.y + 1. / k + .25;
|
||||
if (uv.x + k * uv.y > 0.) {
|
||||
uv = vec2(uv.x - k * uv.y, -k * uv.x - uv.y) / 2.;
|
||||
}
|
||||
uv.x -= clamp(uv.x, -2., 0.);
|
||||
float sdf = -length(uv) * sign(uv.y) - .5;
|
||||
float w = fwidth(sdf) * .5;
|
||||
float alpha = smoothstep(.22 + w, .22 - w, sdf);
|
||||
vec3 color = mix(vec3(.094, .662, .890), vec3(.913, .275, .6), clamp(y * 1.5 - .25, 0., 1.));
|
||||
color = mix(color, vec3(.2, .2, .24), smoothstep(-.12 + w, -.12 - w, sdf));
|
||||
return vec4(pow(color, vec3(2.2)), alpha);
|
||||
}
|
||||
]], { flags = { highp = true } })
|
||||
|
||||
text = lovr.graphics.newShader('font', { flags = { highp = true } })
|
||||
print(string.format('LÖVR %d.%d.%d\nNo game', lovr.getVersion()))
|
||||
lovr.event.quit()
|
||||
end
|
||||
|
||||
function lovr.draw()
|
||||
lovr.graphics.setColor(0xffffff)
|
||||
|
||||
local padding = .1
|
||||
local font = lovr.graphics.getFont()
|
||||
local fade = .315 + .685 * math.abs(math.sin(lovr.timer.getTime() * 2))
|
||||
local titlePosition = 1.4 - padding
|
||||
local subtitlePosition = titlePosition - font:getHeight() * .25 - padding
|
||||
|
||||
lovr.graphics.setShader(logo)
|
||||
lovr.graphics.plane('fill', 0, 1.9, -3, 1, 1, 0, 0, 1)
|
||||
|
||||
lovr.graphics.setShader(text)
|
||||
lovr.graphics.setColor(0xffffff)
|
||||
lovr.graphics.print('LÖVR', -.012, titlePosition, -3, .25, 0, 0, 1, 0, nil, 'center', 'top')
|
||||
|
||||
lovr.graphics.setColor(.9, .9, .9, fade)
|
||||
lovr.graphics.print('No game :(', -.005, subtitlePosition, -3, .15, 0, 0, 1, 0, nil, 'center', 'top')
|
||||
lovr.graphics.setColor(0xffffff)
|
||||
lovr.graphics.setShader()
|
||||
|
||||
if lovr.headset then
|
||||
for i, hand in ipairs(lovr.headset.getHands()) do
|
||||
models[hand] = models[hand] or lovr.headset.newModel(hand, { animated = true })
|
||||
if models[hand] then
|
||||
lovr.headset.animate(hand, models[hand])
|
||||
|
||||
local pose = mat4(lovr.headset.getPose(hand))
|
||||
if models[hand]:hasJoints() then
|
||||
animated = animated or lovr.graphics.newShader('unlit', { flags = { animated = true } })
|
||||
lovr.graphics.setShader(animated)
|
||||
lovr.graphics.setColorMask()
|
||||
models[hand]:draw(pose)
|
||||
lovr.graphics.setColorMask(true, true, true, true)
|
||||
lovr.graphics.setColor(0, 0, 0, .5)
|
||||
models[hand]:draw(pose)
|
||||
lovr.graphics.setShader()
|
||||
else
|
||||
models[hand]:draw(pose)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
lovr.graphics.setColor(0xffffff)
|
||||
--
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -117,9 +42,6 @@ function lovr.boot()
|
|||
start = true,
|
||||
spatializer = nil
|
||||
},
|
||||
graphics = {
|
||||
debug = false
|
||||
},
|
||||
headset = {
|
||||
drivers = { 'openxr', 'webxr', 'desktop' },
|
||||
supersample = false,
|
||||
|
@ -202,35 +124,12 @@ function lovr.run()
|
|||
if lovr.timer then dt = lovr.timer.step() end
|
||||
if lovr.headset then dt = lovr.headset.update() end
|
||||
if lovr.update then lovr.update(dt) end
|
||||
if lovr.graphics then
|
||||
lovr.graphics.origin()
|
||||
if lovr.headset then
|
||||
lovr.headset.renderTo(lovr.draw)
|
||||
end
|
||||
if lovr.graphics.hasWindow() then
|
||||
lovr.mirror()
|
||||
end
|
||||
lovr.graphics.present()
|
||||
end
|
||||
if lovr.math then lovr.math.drain() end
|
||||
end
|
||||
end
|
||||
|
||||
function lovr.mirror()
|
||||
if lovr.headset then -- On some systems, headset module will be disabled
|
||||
local blend, alpha = lovr.graphics.getBlendMode()
|
||||
lovr.graphics.setBlendMode()
|
||||
local texture = lovr.headset.getMirrorTexture()
|
||||
if texture then -- On some drivers, texture is printed directly to the window
|
||||
lovr.graphics.fill(texture)
|
||||
end
|
||||
lovr.graphics.setBlendMode(blend, alpha)
|
||||
else
|
||||
lovr.graphics.clear()
|
||||
if lovr.draw then
|
||||
lovr.draw()
|
||||
end
|
||||
end
|
||||
--
|
||||
end
|
||||
|
||||
local function formatTraceback(s)
|
||||
|
@ -241,47 +140,7 @@ function lovr.errhand(message, traceback)
|
|||
message = tostring(message)
|
||||
message = message .. formatTraceback(traceback or debug.traceback('', 4))
|
||||
print('Error:\n' .. message)
|
||||
if not lovr.graphics then return function() return 1 end end
|
||||
|
||||
lovr.graphics.reset()
|
||||
lovr.graphics.setBackgroundColor(.11, .10, .14)
|
||||
lovr.graphics.setColor(.85, .85, .85)
|
||||
local font = lovr.graphics.getFont()
|
||||
font:setPixelDensity()
|
||||
font:setFlipEnabled(false)
|
||||
local wrap = .7 * font:getPixelDensity()
|
||||
local width, lines = font:getWidth(message, wrap)
|
||||
local height = 2.6 + lines
|
||||
local y = math.min(height / 2, 10)
|
||||
local function render()
|
||||
lovr.graphics.print('Error', -width / 2, y, -20, 1.6, 0, 0, 0, 0, nil, 'left', 'top')
|
||||
lovr.graphics.print(message, -width / 2, y - 2.6, -20, 1.0, 0, 0, 0, 0, wrap, 'left', 'top')
|
||||
end
|
||||
|
||||
return function()
|
||||
lovr.event.pump()
|
||||
for name, a in lovr.event.poll() do
|
||||
if name == 'quit' then return a or 1
|
||||
elseif name == 'restart' then return 'restart', lovr.restart and lovr.restart() end
|
||||
end
|
||||
lovr.graphics.origin()
|
||||
if lovr.headset then
|
||||
lovr.headset.update()
|
||||
lovr.headset.renderTo(render)
|
||||
end
|
||||
if lovr.graphics.hasWindow() then
|
||||
lovr.graphics.setViewPose(1)
|
||||
local width, height = lovr.graphics.getDimensions()
|
||||
local projection = lovr.math.mat4():perspective(.1, 100, math.rad(67), width / height)
|
||||
lovr.graphics.setProjection(1, projection)
|
||||
lovr.graphics.clear()
|
||||
render()
|
||||
end
|
||||
lovr.graphics.present()
|
||||
if lovr.math then
|
||||
lovr.math.drain()
|
||||
end
|
||||
end
|
||||
return function() return 1 end
|
||||
end
|
||||
|
||||
function lovr.threaderror(thread, err)
|
||||
|
|
402
etc/shaders.c
402
etc/shaders.c
|
@ -1,402 +0,0 @@
|
|||
#include "shaders.h"
|
||||
|
||||
const char* lovrShaderVertexPrefix = ""
|
||||
"#define VERTEX VERTEX \n"
|
||||
"#define MAX_BONES 48 \n"
|
||||
"#define MAX_DRAWS 256 \n"
|
||||
"#define lovrView lovrViews[lovrViewID] \n"
|
||||
"#define lovrProjection lovrProjections[lovrViewID] \n"
|
||||
"#define lovrModel lovrModels[lovrDrawID] \n"
|
||||
"#define lovrTransform (lovrView * lovrModel) \n"
|
||||
"#ifdef FLAG_uniformScale \n"
|
||||
"#define lovrNormalMatrix mat3(lovrModel) \n"
|
||||
"#else \n"
|
||||
"#define lovrNormalMatrix mat3(transpose(inverse(lovrModel))) \n"
|
||||
"#endif \n"
|
||||
"#define lovrPoseMatrix ("
|
||||
"lovrPose[lovrBones[0]] * lovrBoneWeights[0] +"
|
||||
"lovrPose[lovrBones[1]] * lovrBoneWeights[1] +"
|
||||
"lovrPose[lovrBones[2]] * lovrBoneWeights[2] +"
|
||||
"lovrPose[lovrBones[3]] * lovrBoneWeights[3]"
|
||||
") \n"
|
||||
"#ifdef FLAG_animated \n"
|
||||
"#define lovrVertex (lovrPoseMatrix * vec4(lovrPosition, 1.)) \n"
|
||||
"#else \n"
|
||||
"#define lovrVertex vec4(lovrPosition, 1.) \n"
|
||||
"#endif \n"
|
||||
"precision highp float; \n"
|
||||
"precision highp int; \n"
|
||||
"in vec3 lovrPosition; \n"
|
||||
"in vec3 lovrNormal; \n"
|
||||
"in vec2 lovrTexCoord; \n"
|
||||
"in vec4 lovrVertexColor; \n"
|
||||
"in vec4 lovrTangent; \n"
|
||||
"in uvec4 lovrBones; \n"
|
||||
"in vec4 lovrBoneWeights; \n"
|
||||
"in uint lovrDrawID; \n"
|
||||
"out vec2 texCoord; \n"
|
||||
"out vec4 vertexColor; \n"
|
||||
"out vec4 lovrGraphicsColor; \n"
|
||||
"layout(std140) uniform lovrModelBlock { mat4 lovrModels[MAX_DRAWS]; }; \n"
|
||||
"layout(std140) uniform lovrColorBlock { vec4 lovrColors[MAX_DRAWS]; }; \n"
|
||||
"layout(std140) uniform lovrFrameBlock { mat4 lovrViews[2]; mat4 lovrProjections[2]; }; \n"
|
||||
"uniform mat3 lovrMaterialTransform; \n"
|
||||
"uniform float lovrPointSize; \n"
|
||||
"uniform mat4 lovrPose[MAX_BONES]; \n"
|
||||
"uniform lowp int lovrViewportCount; \n"
|
||||
"#if defined MULTIVIEW \n"
|
||||
"layout(num_views = 2) in; \n"
|
||||
"#define lovrViewID (int(gl_ViewID_OVR)) \n"
|
||||
"#define lovrInstanceID gl_InstanceID \n"
|
||||
"#elif defined INSTANCED_STEREO \n"
|
||||
"#define lovrViewID gl_ViewportIndex \n"
|
||||
"#define lovrInstanceID (gl_InstanceID / lovrViewportCount) \n"
|
||||
"#else \n"
|
||||
"uniform lowp int lovrViewID; \n"
|
||||
"#define lovrInstanceID gl_InstanceID \n"
|
||||
"#endif \n"
|
||||
"#line 0 \n";
|
||||
|
||||
const char* lovrShaderVertexSuffix = ""
|
||||
"void main() { \n"
|
||||
" texCoord = (lovrMaterialTransform * vec3(lovrTexCoord, 1.)).xy; \n"
|
||||
" vertexColor = lovrVertexColor; \n"
|
||||
" lovrGraphicsColor = lovrColors[lovrDrawID]; \n"
|
||||
"#if defined INSTANCED_STEREO \n"
|
||||
" gl_ViewportIndex = gl_InstanceID % lovrViewportCount; \n"
|
||||
"#endif \n"
|
||||
" gl_PointSize = lovrPointSize; \n"
|
||||
" gl_Position = position(lovrProjection, lovrTransform, lovrVertex); \n"
|
||||
"}";
|
||||
|
||||
const char* lovrShaderFragmentPrefix = ""
|
||||
"#define PIXEL PIXEL \n"
|
||||
"#define FRAGMENT FRAGMENT \n"
|
||||
"#define lovrTexCoord texCoord \n"
|
||||
"#define lovrVertexColor vertexColor \n"
|
||||
"#ifdef FLAG_highp \n"
|
||||
"precision highp float; \n"
|
||||
"precision highp int; \n"
|
||||
"#else \n"
|
||||
"precision mediump float; \n"
|
||||
"precision mediump int; \n"
|
||||
"#endif \n"
|
||||
"in vec2 texCoord; \n"
|
||||
"in vec4 vertexColor; \n"
|
||||
"in vec4 lovrGraphicsColor; \n"
|
||||
"out vec4 lovrCanvas[gl_MaxDrawBuffers]; \n"
|
||||
"uniform float lovrMetalness; \n"
|
||||
"uniform float lovrRoughness; \n"
|
||||
"uniform float lovrAlphaCutoff; \n"
|
||||
"uniform vec4 lovrDiffuseColor; \n"
|
||||
"uniform vec4 lovrEmissiveColor; \n"
|
||||
"uniform sampler2D lovrDiffuseTexture; \n"
|
||||
"uniform sampler2D lovrEmissiveTexture; \n"
|
||||
"uniform sampler2D lovrMetalnessTexture; \n"
|
||||
"uniform sampler2D lovrRoughnessTexture; \n"
|
||||
"uniform sampler2D lovrOcclusionTexture; \n"
|
||||
"uniform sampler2D lovrNormalTexture; \n"
|
||||
"uniform lowp int lovrViewportCount; \n"
|
||||
"#if defined MULTIVIEW \n"
|
||||
"#define lovrViewID gl_ViewID_OVR \n"
|
||||
"#elif defined INSTANCED_STEREO \n"
|
||||
"#define lovrViewID gl_ViewportIndex \n"
|
||||
"#else \n"
|
||||
"uniform lowp int lovrViewID; \n"
|
||||
"#endif \n"
|
||||
"#ifdef MULTIVIEW \n"
|
||||
"#define sampler2DMultiview sampler2DArray \n"
|
||||
"vec4 textureMultiview(sampler2DMultiview t, vec2 uv) { \n"
|
||||
" return texture(t, vec3(uv, lovrViewID)); \n"
|
||||
"} \n"
|
||||
"#else \n"
|
||||
"#define sampler2DMultiview sampler2D \n"
|
||||
"vec4 textureMultiview(sampler2DMultiview t, vec2 uv) { \n"
|
||||
" uv = clamp(uv, 0., 1.) * vec2(.5, 1.) + vec2(lovrViewID) * vec2(.5, 0.); \n"
|
||||
" return texture(t, uv); \n"
|
||||
"} \n"
|
||||
"#endif \n"
|
||||
"#line 0 \n";
|
||||
|
||||
const char* lovrShaderFragmentSuffix = ""
|
||||
"void main() { \n"
|
||||
"#if defined(MULTICANVAS) || defined(FLAG_multicanvas) \n"
|
||||
" colors(lovrGraphicsColor, lovrDiffuseTexture, texCoord); \n"
|
||||
"#else \n"
|
||||
" lovrCanvas[0] = color(lovrGraphicsColor, lovrDiffuseTexture, lovrTexCoord); \n"
|
||||
"#ifdef FLAG_alphaCutoff \n"
|
||||
" if (lovrCanvas[0].a < lovrAlphaCutoff) { \n"
|
||||
" discard; \n"
|
||||
" } \n"
|
||||
"#endif \n"
|
||||
#if defined(LOVR_WEBGL)
|
||||
" lovrCanvas[0].rgb = pow(lovrCanvas[0].rgb, vec3(.4545)); \n"
|
||||
#endif
|
||||
"#endif \n"
|
||||
"}";
|
||||
|
||||
#ifdef LOVR_GLES
|
||||
const char* lovrShaderComputePrefix = ""
|
||||
"#version 310 es \n"
|
||||
"#line 0 \n";
|
||||
#else
|
||||
const char* lovrShaderComputePrefix = ""
|
||||
"#version 330 \n"
|
||||
"#extension GL_ARB_compute_shader : enable \n"
|
||||
"#extension GL_ARB_shader_storage_buffer_object : enable \n"
|
||||
"#extension GL_ARB_shader_image_load_store : enable \n"
|
||||
"#line 0 \n";
|
||||
#endif
|
||||
|
||||
const char* lovrShaderComputeSuffix = ""
|
||||
"void main() { \n"
|
||||
" compute(); \n"
|
||||
"}";
|
||||
|
||||
const char* lovrUnlitVertexShader = ""
|
||||
"vec4 position(mat4 projection, mat4 transform, vec4 vertex) { \n"
|
||||
" return lovrProjection * lovrTransform * lovrVertex; \n"
|
||||
"}";
|
||||
|
||||
const char* lovrUnlitFragmentShader = ""
|
||||
"vec4 color(vec4 graphicsColor, sampler2D image, vec2 uv) { \n"
|
||||
" return lovrGraphicsColor * lovrVertexColor * lovrDiffuseColor * texture(lovrDiffuseTexture, lovrTexCoord); \n"
|
||||
"}";
|
||||
|
||||
const char* lovrStandardVertexShader = ""
|
||||
"out vec3 vVertexPositionWorld; \n"
|
||||
"out vec3 vCameraPositionWorld; \n"
|
||||
"#ifdef FLAG_normalMap \n"
|
||||
"out mat3 vTangentMatrix; \n"
|
||||
"#else \n"
|
||||
"out vec3 vNormal; \n"
|
||||
"#endif \n"
|
||||
|
||||
"vec4 position(mat4 projection, mat4 transform, vec4 vertex) { \n"
|
||||
" vVertexPositionWorld = vec3(lovrModel * lovrVertex); \n"
|
||||
" vCameraPositionWorld = -lovrView[3].xyz * mat3(lovrView); \n"
|
||||
"#ifdef FLAG_normalMap \n"
|
||||
" vec3 normal = normalize(lovrNormalMatrix * lovrNormal); \n"
|
||||
" vec3 tangent = normalize(lovrNormalMatrix * lovrTangent.xyz); \n"
|
||||
" vec3 bitangent = cross(normal, tangent) * lovrTangent.w; \n"
|
||||
" vTangentMatrix = mat3(tangent, bitangent, normal); \n"
|
||||
"#else \n"
|
||||
" vNormal = normalize(lovrNormalMatrix * lovrNormal); \n"
|
||||
"#endif \n"
|
||||
" return lovrProjection * lovrTransform * lovrVertex; \n"
|
||||
"}";
|
||||
|
||||
const char* lovrStandardFragmentShader = ""
|
||||
"#define PI 3.14159265358979 \n"
|
||||
"#if defined(GL_ES) && !defined(FLAG_highp) \n"
|
||||
"#define EPS 1e-4 \n"
|
||||
"#else \n"
|
||||
"#define EPS 1e-8 \n"
|
||||
"#endif \n"
|
||||
|
||||
"in vec3 vVertexPositionWorld; \n"
|
||||
"in vec3 vCameraPositionWorld; \n"
|
||||
"#ifdef FLAG_normalMap \n"
|
||||
"in mat3 vTangentMatrix; \n"
|
||||
"#else \n"
|
||||
"in vec3 vNormal; \n"
|
||||
"#endif \n"
|
||||
|
||||
"uniform vec3 lovrLightDirection; \n"
|
||||
"uniform vec4 lovrLightColor; \n"
|
||||
"uniform samplerCube lovrEnvironmentMap; \n"
|
||||
"uniform vec3 lovrSphericalHarmonics[9]; \n"
|
||||
"uniform float lovrExposure; \n"
|
||||
|
||||
"float D_GGX(float NoH, float roughness); \n"
|
||||
"float G_SmithGGXCorrelated(float NoV, float NoL, float roughness); \n"
|
||||
"vec3 F_Schlick(vec3 F0, float VoH); \n"
|
||||
"vec3 E_SphericalHarmonics(vec3 sh[9], vec3 n); \n"
|
||||
"vec2 prefilteredBRDF(float NoV, float roughness); \n"
|
||||
"vec3 tonemap_ACES(vec3 color); \n"
|
||||
|
||||
"vec4 color(vec4 graphicsColor, sampler2D image, vec2 uv) { \n"
|
||||
" vec3 result = vec3(0.); \n"
|
||||
|
||||
// Parameters
|
||||
" vec4 baseColor = texture(lovrDiffuseTexture, lovrTexCoord) * lovrDiffuseColor; \n"
|
||||
" float metalness = texture(lovrMetalnessTexture, lovrTexCoord).b * lovrMetalness; \n"
|
||||
" float roughness = max(texture(lovrRoughnessTexture, lovrTexCoord).g * lovrRoughness, .05); \n"
|
||||
"#ifdef FLAG_normalMap \n"
|
||||
" vec3 N = normalize(vTangentMatrix * (texture(lovrNormalTexture, lovrTexCoord).rgb * 2. - 1.)); \n"
|
||||
"#else \n"
|
||||
" vec3 N = normalize(vNormal); \n"
|
||||
"#endif \n"
|
||||
" vec3 V = normalize(vCameraPositionWorld - vVertexPositionWorld); \n"
|
||||
" vec3 L = normalize(-lovrLightDirection); \n"
|
||||
" vec3 H = normalize(V + L); \n"
|
||||
" vec3 R = normalize(reflect(-V, N)); \n"
|
||||
" float NoV = abs(dot(N, V)) + EPS; \n"
|
||||
" float NoL = clamp(dot(N, L), 0., 1.); \n"
|
||||
" float NoH = clamp(dot(N, H), 0., 1.); \n"
|
||||
" float VoH = clamp(dot(V, H), 0., 1.); \n"
|
||||
|
||||
// Direct lighting
|
||||
" vec3 F0 = mix(vec3(.04), baseColor.rgb, metalness); \n"
|
||||
" float D = D_GGX(NoH, roughness); \n"
|
||||
" float G = G_SmithGGXCorrelated(NoV, NoL, roughness); \n"
|
||||
" vec3 F = F_Schlick(F0, VoH); \n"
|
||||
" vec3 specularDirect = vec3(D * G * F); \n"
|
||||
" vec3 diffuseDirect = (vec3(1.) - F) * (1. - metalness) * baseColor.rgb; \n"
|
||||
" result += (diffuseDirect / PI + specularDirect) * NoL * lovrLightColor.rgb * lovrLightColor.a; \n"
|
||||
|
||||
// Indirect lighting
|
||||
"#ifdef FLAG_indirectLighting \n"
|
||||
" vec2 lookup = prefilteredBRDF(NoV, roughness); \n"
|
||||
" float mipmapCount = log2(float(textureSize(lovrEnvironmentMap, 0).x)); \n"
|
||||
" vec3 specularIndirect = (F0 * lookup.r + lookup.g) * textureLod(lovrEnvironmentMap, R, roughness * mipmapCount).rgb; \n"
|
||||
" vec3 diffuseIndirect = diffuseDirect * E_SphericalHarmonics(lovrSphericalHarmonics, N); \n"
|
||||
"#ifdef FLAG_occlusion \n" // Occlusion only affects indirect diffuse light
|
||||
" diffuseIndirect *= texture(lovrOcclusionTexture, lovrTexCoord).r; \n"
|
||||
"#endif \n"
|
||||
" result += diffuseIndirect + specularIndirect; \n"
|
||||
"#endif \n"
|
||||
|
||||
// Emissive
|
||||
"#ifdef FLAG_emissive \n" // Currently emissive texture and color have to be used together
|
||||
" result += texture(lovrEmissiveTexture, lovrTexCoord).rgb * lovrEmissiveColor.rgb; \n"
|
||||
"#endif \n"
|
||||
|
||||
// Tonemap
|
||||
"#ifndef FLAG_skipTonemap \n"
|
||||
" result = tonemap_ACES(result * lovrExposure); \n"
|
||||
"#endif \n"
|
||||
|
||||
" return lovrGraphicsColor * vec4(result, baseColor.a); \n"
|
||||
"}"
|
||||
|
||||
// Helpers
|
||||
"float D_GGX(float NoH, float roughness) { \n"
|
||||
" float alpha = roughness * roughness; \n"
|
||||
" float alpha2 = alpha * alpha; \n"
|
||||
" float denom = (NoH * NoH) * (alpha2 - 1.) + 1.; \n"
|
||||
" return alpha2 / max(PI * denom * denom, EPS); \n"
|
||||
"} \n"
|
||||
|
||||
"float G_SmithGGXCorrelated(float NoV, float NoL, float roughness) { \n"
|
||||
" float alpha = roughness * roughness; \n"
|
||||
" float alpha2 = alpha * alpha; \n"
|
||||
" float GGXV = NoL * sqrt(alpha2 + (1. - alpha2) * (NoV * NoV)); \n"
|
||||
" float GGXL = NoV * sqrt(alpha2 + (1. - alpha2) * (NoL * NoL)); \n"
|
||||
" return .5 / max(GGXV + GGXL, EPS); \n"
|
||||
"} \n"
|
||||
|
||||
"vec3 F_Schlick(vec3 F0, float VoH) { \n"
|
||||
" return F0 + (vec3(1.) - F0) * pow(1. - VoH, 5.); \n"
|
||||
"} \n"
|
||||
|
||||
"vec3 E_SphericalHarmonics(vec3 sh[9], vec3 n) { \n"
|
||||
" n = -n; \n"
|
||||
" return max("
|
||||
"sh[0] + "
|
||||
"sh[1] * n.y + "
|
||||
"sh[2] * n.z + "
|
||||
"sh[3] * n.x + "
|
||||
"sh[4] * n.y * n.x + "
|
||||
"sh[5] * n.y * n.z + "
|
||||
"sh[6] * (3. * n.z * n.z - 1.) + "
|
||||
"sh[7] * n.z * n.x + "
|
||||
"sh[8] * (n.x * n.x - n.y * n.y)"
|
||||
", 0.); \n"
|
||||
"} \n"
|
||||
|
||||
// https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile
|
||||
"vec2 prefilteredBRDF(float NoV, float roughness) { \n"
|
||||
" vec4 c0 = vec4(-1., -.0275, -.572, .022); \n"
|
||||
" vec4 c1 = vec4(1., .0425, 1.04, -.04); \n"
|
||||
" vec4 r = roughness * c0 + c1; \n"
|
||||
" float a004 = min(r.x * r.x, exp2(-9.28 * NoV)) * r.x + r.y; \n"
|
||||
" return vec2(-1.04, 1.04) * a004 + r.zw; \n"
|
||||
"} \n"
|
||||
|
||||
"vec3 tonemap_ACES(vec3 x) { \n"
|
||||
" float a = 2.51; \n"
|
||||
" float b = 0.03; \n"
|
||||
" float c = 2.43; \n"
|
||||
" float d = 0.59; \n"
|
||||
" float e = 0.14; \n"
|
||||
" return (x * (a * x + b)) / (x * (c * x + d) + e); \n"
|
||||
"}";
|
||||
|
||||
const char* lovrCubeVertexShader = ""
|
||||
"out vec3 texturePosition[2]; \n"
|
||||
"vec4 position(mat4 projection, mat4 transform, vec4 vertex) { \n"
|
||||
" texturePosition[lovrViewID] = inverse(mat3(lovrTransform)) * (inverse(lovrProjection) * lovrVertex).xyz; \n"
|
||||
" return lovrVertex; \n"
|
||||
"}";
|
||||
|
||||
const char* lovrCubeFragmentShader = ""
|
||||
"in vec3 texturePosition[2]; \n"
|
||||
"uniform samplerCube lovrSkyboxTexture; \n"
|
||||
"vec4 color(vec4 graphicsColor, sampler2D image, vec2 uv) { \n"
|
||||
" return lovrGraphicsColor * texture(lovrSkyboxTexture, texturePosition[lovrViewID] * vec3(-1, 1, 1)); \n"
|
||||
"}";
|
||||
|
||||
const char* lovrPanoFragmentShader = ""
|
||||
"in vec3 texturePosition[2]; \n"
|
||||
"#define PI 3.141592653589 \n"
|
||||
"vec4 color(vec4 graphicsColor, sampler2D image, vec2 uv) { \n"
|
||||
" vec3 direction = texturePosition[lovrViewID]; \n"
|
||||
" float theta = acos(-direction.y / length(direction)); \n"
|
||||
" float phi = atan(direction.x, -direction.z); \n"
|
||||
" vec2 cubeUv = vec2(.5 + phi / (2. * PI), theta / PI); \n"
|
||||
" return lovrGraphicsColor * texture(lovrDiffuseTexture, cubeUv); \n"
|
||||
"}";
|
||||
|
||||
const char* lovrFontFragmentShader = ""
|
||||
"uniform vec2 lovrSdfRange; \n"
|
||||
"float screenPxRange() { \n"
|
||||
" vec2 screenTexSize = vec2(1.) / fwidth(lovrTexCoord); \n"
|
||||
" return max(.5 * dot(lovrSdfRange, screenTexSize), 1.); \n"
|
||||
"} \n"
|
||||
"float median(float r, float g, float b) { \n"
|
||||
" return max(min(r, g), min(max(r, g), b)); \n"
|
||||
"} \n"
|
||||
"vec4 color(vec4 graphicsColor, sampler2D image, vec2 uv) { \n"
|
||||
" vec3 msd = texture(lovrDiffuseTexture, lovrTexCoord).rgb; \n"
|
||||
" float sd = median(msd.r, msd.g, msd.b); \n"
|
||||
" float screenPxDistance = screenPxRange() * (sd - .5); \n"
|
||||
" float alpha = clamp(screenPxDistance + .5, 0., 1.); \n"
|
||||
" if (alpha <= 0.0) discard; \n"
|
||||
" return vec4(lovrGraphicsColor.rgb, lovrGraphicsColor.a * alpha); \n"
|
||||
"}";
|
||||
|
||||
const char* lovrFillVertexShader = ""
|
||||
"vec4 position(mat4 projection, mat4 transform, vec4 vertex) { \n"
|
||||
" return lovrVertex; \n"
|
||||
"}";
|
||||
|
||||
const char* lovrShaderScalarUniforms[] = {
|
||||
"lovrMetalness",
|
||||
"lovrRoughness",
|
||||
"lovrAlphaCutoff"
|
||||
};
|
||||
|
||||
const char* lovrShaderColorUniforms[] = {
|
||||
"lovrDiffuseColor",
|
||||
"lovrEmissiveColor"
|
||||
};
|
||||
|
||||
const char* lovrShaderTextureUniforms[] = {
|
||||
"lovrDiffuseTexture",
|
||||
"lovrEmissiveTexture",
|
||||
"lovrMetalnessTexture",
|
||||
"lovrRoughnessTexture",
|
||||
"lovrOcclusionTexture",
|
||||
"lovrNormalTexture"
|
||||
};
|
||||
|
||||
const char* lovrShaderAttributeNames[] = {
|
||||
"lovrPosition",
|
||||
"lovrNormal",
|
||||
"lovrTexCoord",
|
||||
"lovrVertexColor",
|
||||
"lovrTangent",
|
||||
"lovrBones",
|
||||
"lovrBoneWeights"
|
||||
};
|
|
@ -1,22 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
extern const char* lovrShaderVertexPrefix;
|
||||
extern const char* lovrShaderVertexSuffix;
|
||||
extern const char* lovrShaderFragmentPrefix;
|
||||
extern const char* lovrShaderFragmentSuffix;
|
||||
extern const char* lovrShaderComputePrefix;
|
||||
extern const char* lovrShaderComputeSuffix;
|
||||
extern const char* lovrUnlitVertexShader;
|
||||
extern const char* lovrUnlitFragmentShader;
|
||||
extern const char* lovrStandardVertexShader;
|
||||
extern const char* lovrStandardFragmentShader;
|
||||
extern const char* lovrCubeVertexShader;
|
||||
extern const char* lovrCubeFragmentShader;
|
||||
extern const char* lovrPanoFragmentShader;
|
||||
extern const char* lovrFontFragmentShader;
|
||||
extern const char* lovrFillVertexShader;
|
||||
|
||||
extern const char* lovrShaderScalarUniforms[];
|
||||
extern const char* lovrShaderColorUniforms[];
|
||||
extern const char* lovrShaderTextureUniforms[];
|
||||
extern const char* lovrShaderAttributeNames[];
|
|
@ -5,9 +5,6 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#ifndef LOVR_DISABLE_GRAPHICS
|
||||
#include "graphics/model.h"
|
||||
#endif
|
||||
|
||||
typedef void voidFn(void);
|
||||
typedef void destructorFn(void*);
|
||||
|
@ -479,14 +476,5 @@ int luax_readmesh(lua_State* L, int index, float** vertices, uint32_t* vertexCou
|
|||
return index + 2;
|
||||
}
|
||||
|
||||
#ifndef LOVR_DISABLE_GRAPHICS
|
||||
Model* model = luax_totype(L, index, Model);
|
||||
if (model) {
|
||||
lovrModelGetTriangles(model, vertices, vertexCount, indices, indexCount);
|
||||
*shouldFree = false;
|
||||
return index + 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return luaL_argerror(L, index, "table or Model");
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ extern StringEntry lovrBufferUsage[];
|
|||
extern StringEntry lovrChannelLayout[];
|
||||
extern StringEntry lovrCompareMode[];
|
||||
extern StringEntry lovrCoordinateSpace[];
|
||||
extern StringEntry lovrDefaultAttribute[];
|
||||
extern StringEntry lovrDevice[];
|
||||
extern StringEntry lovrDeviceAxis[];
|
||||
extern StringEntry lovrDeviceButton[];
|
||||
|
|
|
@ -16,6 +16,62 @@ StringEntry lovrAnimationProperty[] = {
|
|||
{ 0 }
|
||||
};
|
||||
|
||||
StringEntry lovrAttributeType[] = {
|
||||
[I8] = ENTRY("byte"),
|
||||
[U8] = ENTRY("ubyte"),
|
||||
[I16] = ENTRY("short"),
|
||||
[U16] = ENTRY("ushort"),
|
||||
[I32] = ENTRY("int"),
|
||||
[U32] = ENTRY("uint"),
|
||||
[F32] = ENTRY("float"),
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
StringEntry lovrDefaultAttribute[] = {
|
||||
[ATTR_POSITION] = ENTRY("position"),
|
||||
[ATTR_NORMAL] = ENTRY("normal"),
|
||||
[ATTR_TEXCOORD] = ENTRY("texcoord"),
|
||||
[ATTR_COLOR] = ENTRY("color"),
|
||||
[ATTR_TANGENT] = ENTRY("tangent"),
|
||||
[ATTR_BONES] = ENTRY("bones"),
|
||||
[ATTR_WEIGHTS] = ENTRY("weights"),
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
StringEntry lovrDrawMode[] = {
|
||||
[DRAW_POINTS] = ENTRY("points"),
|
||||
[DRAW_LINES] = ENTRY("lines"),
|
||||
[DRAW_LINE_STRIP] = ENTRY("linestrip"),
|
||||
[DRAW_LINE_LOOP] = ENTRY("lineloop"),
|
||||
[DRAW_TRIANGLE_STRIP] = ENTRY("strip"),
|
||||
[DRAW_TRIANGLES] = ENTRY("triangles"),
|
||||
[DRAW_TRIANGLE_FAN] = ENTRY("fan"),
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
StringEntry lovrMaterialColor[] = {
|
||||
[COLOR_DIFFUSE] = ENTRY("diffuse"),
|
||||
[COLOR_EMISSIVE] = ENTRY("emissive"),
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
StringEntry lovrMaterialScalar[] = {
|
||||
[SCALAR_METALNESS] = ENTRY("metalness"),
|
||||
[SCALAR_ROUGHNESS] = ENTRY("roughness"),
|
||||
[SCALAR_ALPHA_CUTOFF] = ENTRY("alphacutoff"),
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
StringEntry lovrMaterialTexture[] = {
|
||||
[TEXTURE_DIFFUSE] = ENTRY("diffuse"),
|
||||
[TEXTURE_EMISSIVE] = ENTRY("emissive"),
|
||||
[TEXTURE_METALNESS] = ENTRY("metalness"),
|
||||
[TEXTURE_ROUGHNESS] = ENTRY("roughness"),
|
||||
[TEXTURE_OCCLUSION] = ENTRY("occlusion"),
|
||||
[TEXTURE_NORMAL] = ENTRY("normal"),
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
StringEntry lovrSmoothMode[] = {
|
||||
[SMOOTH_STEP] = ENTRY("step"),
|
||||
[SMOOTH_LINEAR] = ENTRY("linear"),
|
||||
|
|
|
@ -4,6 +4,45 @@
|
|||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
|
||||
StringEntry lovrTextureFormat[] = {
|
||||
[FORMAT_RGB] = ENTRY("rgb"),
|
||||
[FORMAT_RGBA] = ENTRY("rgba"),
|
||||
[FORMAT_RGBA4] = ENTRY("rgba4"),
|
||||
[FORMAT_R16] = ENTRY("r16"),
|
||||
[FORMAT_RG16] = ENTRY("rg16"),
|
||||
[FORMAT_RGBA16] = ENTRY("rgba16"),
|
||||
[FORMAT_RGBA16F] = ENTRY("rgba16f"),
|
||||
[FORMAT_RGBA32F] = ENTRY("rgba32f"),
|
||||
[FORMAT_R16F] = ENTRY("r16f"),
|
||||
[FORMAT_R32F] = ENTRY("r32f"),
|
||||
[FORMAT_RG16F] = ENTRY("rg16f"),
|
||||
[FORMAT_RG32F] = ENTRY("rg32f"),
|
||||
[FORMAT_RGB5A1] = ENTRY("rgb5a1"),
|
||||
[FORMAT_RGB10A2] = ENTRY("rgb10a2"),
|
||||
[FORMAT_RG11B10F] = ENTRY("rg11b10f"),
|
||||
[FORMAT_D16] = ENTRY("d16"),
|
||||
[FORMAT_D32F] = ENTRY("d32f"),
|
||||
[FORMAT_D24S8] = ENTRY("d24s8"),
|
||||
[FORMAT_DXT1] = ENTRY("dxt1"),
|
||||
[FORMAT_DXT3] = ENTRY("dxt3"),
|
||||
[FORMAT_DXT5] = ENTRY("dxt5"),
|
||||
[FORMAT_ASTC_4x4] = ENTRY("astc4x4"),
|
||||
[FORMAT_ASTC_5x4] = ENTRY("astc5x4"),
|
||||
[FORMAT_ASTC_5x5] = ENTRY("astc5x5"),
|
||||
[FORMAT_ASTC_6x5] = ENTRY("astc6x5"),
|
||||
[FORMAT_ASTC_6x6] = ENTRY("astc6x6"),
|
||||
[FORMAT_ASTC_8x5] = ENTRY("astc8x5"),
|
||||
[FORMAT_ASTC_8x6] = ENTRY("astc8x6"),
|
||||
[FORMAT_ASTC_8x8] = ENTRY("astc8x8"),
|
||||
[FORMAT_ASTC_10x5] = ENTRY("astc10x5"),
|
||||
[FORMAT_ASTC_10x6] = ENTRY("astc10x6"),
|
||||
[FORMAT_ASTC_10x8] = ENTRY("astc10x8"),
|
||||
[FORMAT_ASTC_10x10] = ENTRY("astc10x10"),
|
||||
[FORMAT_ASTC_12x10] = ENTRY("astc12x10"),
|
||||
[FORMAT_ASTC_12x12] = ENTRY("astc12x12"),
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static int l_lovrImageEncode(lua_State* L) {
|
||||
Image* image = luax_checktype(L, 1, Image);
|
||||
Blob* blob = lovrImageEncode(image);
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#include "api.h"
|
||||
#include "data/modelData.h"
|
||||
#include "core/maf.h"
|
||||
#include "shaders.h"
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
|
||||
|
@ -288,7 +287,7 @@ static int l_lovrModelDataGetMeshVertexFormat(lua_State* L) {
|
|||
|
||||
lua_createtable(L, 6, 0);
|
||||
|
||||
lua_pushstring(L, lovrShaderAttributeNames[i]);
|
||||
luax_pushenum(L, DefaultAttribute, i);
|
||||
lua_rawseti(L, -2, 1);
|
||||
|
||||
luax_pushenum(L, AttributeType, attribute->type);
|
||||
|
|
1854
src/api/l_graphics.c
1854
src/api/l_graphics.c
File diff suppressed because it is too large
Load Diff
|
@ -1,149 +0,0 @@
|
|||
#include "api.h"
|
||||
#include "graphics/canvas.h"
|
||||
#include "graphics/graphics.h"
|
||||
#include "graphics/texture.h"
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static int luax_checkattachment(lua_State* L, int index, Attachment* attachment) {
|
||||
if (lua_istable(L, index)) {
|
||||
lua_rawgeti(L, index, 1);
|
||||
attachment->texture = luax_checktype(L, -1, Texture);
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_rawgeti(L, index, 2);
|
||||
attachment->slice = luax_optu32(L, -1, 1) - 1;
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_rawgeti(L, index, 3);
|
||||
attachment->level = luax_optmipmap(L, -1, attachment->texture);
|
||||
lua_pop(L, 1);
|
||||
|
||||
index++;
|
||||
} else {
|
||||
attachment->texture = luax_checktype(L, index++, Texture);
|
||||
attachment->slice = lua_type(L, index) == LUA_TNUMBER ? lua_tointeger(L, index++) - 1 : 0;
|
||||
attachment->level = lua_type(L, index) == LUA_TNUMBER ? luax_optmipmap(L, index++, attachment->texture) : 0;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
void luax_readattachments(lua_State* L, int index, Attachment* attachments, int* count) {
|
||||
bool table = lua_istable(L, index);
|
||||
int top = table ? -1 : lua_gettop(L);
|
||||
int n;
|
||||
|
||||
if (table) {
|
||||
n = luax_len(L, index);
|
||||
n = MIN(n, 3 * MAX_CANVAS_ATTACHMENTS);
|
||||
for (int i = 0; i < n; i++) {
|
||||
lua_rawgeti(L, index, i + 1);
|
||||
}
|
||||
index = -n;
|
||||
}
|
||||
|
||||
for (*count = 0; *count < MAX_CANVAS_ATTACHMENTS && index <= top; (*count)++) {
|
||||
index = luax_checkattachment(L, index, attachments + *count);
|
||||
}
|
||||
|
||||
if (table) {
|
||||
lua_pop(L, n);
|
||||
}
|
||||
}
|
||||
|
||||
static int l_lovrCanvasNewImage(lua_State* L) {
|
||||
Canvas* canvas = luax_checktype(L, 1, Canvas);
|
||||
uint32_t index = luaL_optinteger(L, 2, 1) - 1;
|
||||
uint32_t count;
|
||||
lovrCanvasGetAttachments(canvas, &count);
|
||||
lovrAssert(index < count, "Can not create an Image from Texture #%d of Canvas (it only has %d textures)", index, count);
|
||||
Image* image = lovrCanvasNewImage(canvas, index);
|
||||
luax_pushtype(L, Image, image);
|
||||
lovrRelease(image, lovrImageDestroy);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrCanvasRenderTo(lua_State* L) {
|
||||
Canvas* canvas = luax_checktype(L, 1, Canvas);
|
||||
luaL_checktype(L, 2, LUA_TFUNCTION);
|
||||
int argumentCount = lua_gettop(L) - 2;
|
||||
Canvas* old = lovrGraphicsGetCanvas();
|
||||
lovrGraphicsSetCanvas(canvas);
|
||||
lua_call(L, argumentCount, 0);
|
||||
lovrGraphicsSetCanvas(old);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrCanvasGetTexture(lua_State* L) {
|
||||
Canvas* canvas = luax_checktype(L, 1, Canvas);
|
||||
uint32_t count;
|
||||
const Attachment* attachments = lovrCanvasGetAttachments(canvas, &count);
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
luax_pushtype(L, Texture, attachments[i].texture);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static int l_lovrCanvasSetTexture(lua_State* L) {
|
||||
Canvas* canvas = luax_checktype(L, 1, Canvas);
|
||||
Attachment attachments[MAX_CANVAS_ATTACHMENTS];
|
||||
int count;
|
||||
luax_readattachments(L, 2, attachments, &count);
|
||||
lovrCanvasSetAttachments(canvas, attachments, count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrCanvasGetWidth(lua_State* L) {
|
||||
Canvas* canvas = luax_checktype(L, 1, Canvas);
|
||||
lua_pushinteger(L, lovrCanvasGetWidth(canvas));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrCanvasGetHeight(lua_State* L) {
|
||||
Canvas* canvas = luax_checktype(L, 1, Canvas);
|
||||
lua_pushinteger(L, lovrCanvasGetHeight(canvas));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrCanvasGetDimensions(lua_State* L) {
|
||||
Canvas* canvas = luax_checktype(L, 1, Canvas);
|
||||
lua_pushinteger(L, lovrCanvasGetWidth(canvas));
|
||||
lua_pushinteger(L, lovrCanvasGetHeight(canvas));
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int l_lovrCanvasGetDepthTexture(lua_State* L) {
|
||||
Canvas* canvas = luax_checktype(L, 1, Canvas);
|
||||
Texture* texture = lovrCanvasGetDepthTexture(canvas);
|
||||
luax_pushtype(L, Texture, texture);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrCanvasGetMSAA(lua_State* L) {
|
||||
Canvas* canvas = luax_checktype(L, 1, Canvas);
|
||||
int msaa = lovrCanvasGetMSAA(canvas);
|
||||
lua_pushinteger(L, msaa);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrCanvasIsStereo(lua_State* L) {
|
||||
Canvas* canvas = luax_checktype(L, 1, Canvas);
|
||||
bool stereo = lovrCanvasIsStereo(canvas);
|
||||
lua_pushboolean(L, stereo);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const luaL_Reg lovrCanvas[] = {
|
||||
{ "newImage", l_lovrCanvasNewImage },
|
||||
{ "renderTo", l_lovrCanvasRenderTo },
|
||||
{ "getTexture", l_lovrCanvasGetTexture },
|
||||
{ "setTexture", l_lovrCanvasSetTexture },
|
||||
{ "getWidth", l_lovrCanvasGetWidth },
|
||||
{ "getHeight", l_lovrCanvasGetHeight },
|
||||
{ "getDimensions", l_lovrCanvasGetDimensions },
|
||||
{ "getDepthTexture", l_lovrCanvasGetDepthTexture },
|
||||
{ "getMSAA", l_lovrCanvasGetMSAA },
|
||||
{ "isStereo", l_lovrCanvasIsStereo },
|
||||
{ NULL, NULL }
|
||||
};
|
|
@ -1,146 +0,0 @@
|
|||
#include "api.h"
|
||||
#include "graphics/font.h"
|
||||
#include "data/rasterizer.h"
|
||||
#include "util.h"
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
|
||||
static int l_lovrFontGetWidth(lua_State* L) {
|
||||
Font* font = luax_checktype(L, 1, Font);
|
||||
size_t length;
|
||||
const char* string = luaL_checklstring(L, 2, &length);
|
||||
float wrap = luax_optfloat(L, 3, 0.f);
|
||||
float width;
|
||||
float lastLineWidth;
|
||||
float height;
|
||||
uint32_t lineCount;
|
||||
uint32_t glyphCount;
|
||||
lovrFontMeasure(font, string, length, wrap, &width, &lastLineWidth, &height, &lineCount, &glyphCount);
|
||||
lua_pushnumber(L, width);
|
||||
lua_pushnumber(L, lineCount + 1);
|
||||
lua_pushnumber(L, lastLineWidth);
|
||||
return 3;
|
||||
}
|
||||
|
||||
static int l_lovrFontGetHeight(lua_State* L) {
|
||||
Font* font = luax_checktype(L, 1, Font);
|
||||
lua_pushnumber(L, lovrFontGetHeight(font));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrFontGetAscent(lua_State* L) {
|
||||
Font* font = luax_checktype(L, 1, Font);
|
||||
lua_pushnumber(L, lovrFontGetAscent(font));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrFontGetDescent(lua_State* L) {
|
||||
Font* font = luax_checktype(L, 1, Font);
|
||||
lua_pushnumber(L, lovrFontGetDescent(font));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrFontGetBaseline(lua_State* L) {
|
||||
Font* font = luax_checktype(L, 1, Font);
|
||||
lua_pushnumber(L, lovrFontGetBaseline(font));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrFontGetLineHeight(lua_State* L) {
|
||||
Font* font = luax_checktype(L, 1, Font);
|
||||
lua_pushnumber(L, lovrFontGetLineHeight(font));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrFontSetLineHeight(lua_State* L) {
|
||||
Font* font = luax_checktype(L, 1, Font);
|
||||
float lineHeight = luax_checkfloat(L, 2);
|
||||
lovrFontSetLineHeight(font, lineHeight);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrFontIsFlipEnabled(lua_State* L) {
|
||||
Font* font = luax_checktype(L, 1, Font);
|
||||
lua_pushboolean(L, lovrFontIsFlipEnabled(font));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrFontSetFlipEnabled(lua_State* L) {
|
||||
Font* font = luax_checktype(L, 1, Font);
|
||||
lovrFontSetFlipEnabled(font, lua_toboolean(L, 2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrFontGetPixelDensity(lua_State* L) {
|
||||
Font* font = luax_checktype(L, 1, Font);
|
||||
lua_pushnumber(L, lovrFontGetPixelDensity(font));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrFontSetPixelDensity(lua_State* L) {
|
||||
Font* font = luax_checktype(L, 1, Font);
|
||||
if (lua_isnoneornil(L, 2)) {
|
||||
lovrFontSetPixelDensity(font, lovrRasterizerGetHeight(lovrFontGetRasterizer(font)));
|
||||
} else {
|
||||
float pixelDensity = luax_optfloat(L, 2, -1.f);
|
||||
lovrFontSetPixelDensity(font, pixelDensity);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrFontGetRasterizer(lua_State* L) {
|
||||
Font* font = luax_checktype(L, 1, Font);
|
||||
luax_pushtype(L, Rasterizer, lovrFontGetRasterizer(font));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrFontHasGlyphs(lua_State* L) {
|
||||
Font* font = luax_checktype(L, 1, Font);
|
||||
Rasterizer* rasterizer = lovrFontGetRasterizer(font);
|
||||
bool hasGlyphs = true;
|
||||
for (int i = 2; i <= lua_gettop(L); i++) {
|
||||
if (lua_type(L, i) == LUA_TSTRING) {
|
||||
hasGlyphs &= lovrRasterizerHasGlyphs(rasterizer, lua_tostring(L, i));
|
||||
} else {
|
||||
hasGlyphs &= lovrRasterizerHasGlyph(rasterizer, luaL_checkinteger(L, i));
|
||||
}
|
||||
}
|
||||
lua_pushboolean(L, hasGlyphs);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrFontGetFilter(lua_State* L) {
|
||||
Font* font = luax_checktype(L, 1, Font);
|
||||
TextureFilter filter = lovrFontGetFilter(font);
|
||||
luax_pushenum(L, FilterMode, filter.mode);
|
||||
lua_pushnumber(L, filter.anisotropy);
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int l_lovrFontSetFilter(lua_State* L) {
|
||||
Font* font = luax_checktype(L, 1, Font);
|
||||
FilterMode mode = luax_checkenum(L, 2, FilterMode, NULL);
|
||||
float anisotropy = luax_optfloat(L, 3, 1.f);
|
||||
TextureFilter filter = { .mode = mode, .anisotropy = anisotropy };
|
||||
lovrFontSetFilter(font, filter);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const luaL_Reg lovrFont[] = {
|
||||
{ "getWidth", l_lovrFontGetWidth },
|
||||
{ "getHeight", l_lovrFontGetHeight },
|
||||
{ "getAscent", l_lovrFontGetAscent },
|
||||
{ "getDescent", l_lovrFontGetDescent },
|
||||
{ "getBaseline", l_lovrFontGetBaseline },
|
||||
{ "getLineHeight", l_lovrFontGetLineHeight },
|
||||
{ "setLineHeight", l_lovrFontSetLineHeight },
|
||||
{ "isFlipEnabled", l_lovrFontIsFlipEnabled },
|
||||
{ "setFlipEnabled", l_lovrFontSetFlipEnabled },
|
||||
{ "getPixelDensity", l_lovrFontGetPixelDensity },
|
||||
{ "setPixelDensity", l_lovrFontSetPixelDensity },
|
||||
{ "getRasterizer", l_lovrFontGetRasterizer},
|
||||
{ "hasGlyphs", l_lovrFontHasGlyphs },
|
||||
{ "getFilter", l_lovrFontGetFilter },
|
||||
{ "setFilter", l_lovrFontSetFilter },
|
||||
{ NULL, NULL }
|
||||
};
|
|
@ -1,102 +0,0 @@
|
|||
#include "api.h"
|
||||
#include "graphics/material.h"
|
||||
#include "graphics/texture.h"
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
|
||||
static int l_lovrMaterialGetColor(lua_State* L) {
|
||||
Material* material = luax_checktype(L, 1, Material);
|
||||
MaterialColor colorType = luax_checkenum(L, 2, MaterialColor, "diffuse");
|
||||
Color color = lovrMaterialGetColor(material, colorType);
|
||||
lua_pushnumber(L, color.r);
|
||||
lua_pushnumber(L, color.g);
|
||||
lua_pushnumber(L, color.b);
|
||||
lua_pushnumber(L, color.a);
|
||||
return 4;
|
||||
}
|
||||
|
||||
static int l_lovrMaterialSetColor(lua_State* L) {
|
||||
Material* material = luax_checktype(L, 1, Material);
|
||||
MaterialColor colorType = COLOR_DIFFUSE;
|
||||
int index = 2;
|
||||
if (lua_type(L, index) == LUA_TSTRING) {
|
||||
colorType = luax_checkenum(L, index, MaterialColor, NULL);
|
||||
index++;
|
||||
}
|
||||
Color color;
|
||||
luax_readcolor(L, index, &color);
|
||||
lovrMaterialSetColor(material, colorType, color);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrMaterialGetScalar(lua_State* L) {
|
||||
Material* material = luax_checktype(L, 1, Material);
|
||||
MaterialScalar scalarType = luax_checkenum(L, 2, MaterialScalar, NULL);
|
||||
float value = lovrMaterialGetScalar(material, scalarType);
|
||||
lua_pushnumber(L, value);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrMaterialSetScalar(lua_State* L) {
|
||||
Material* material = luax_checktype(L, 1, Material);
|
||||
MaterialScalar scalarType = luax_checkenum(L, 2, MaterialScalar, NULL);
|
||||
float value = luax_checkfloat(L, 3);
|
||||
lovrMaterialSetScalar(material, scalarType, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrMaterialGetTexture(lua_State* L) {
|
||||
Material* material = luax_checktype(L, 1, Material);
|
||||
MaterialTexture textureType = luax_checkenum(L, 2, MaterialTexture, "diffuse");
|
||||
Texture* texture = lovrMaterialGetTexture(material, textureType);
|
||||
luax_pushtype(L, Texture, texture);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrMaterialSetTexture(lua_State* L) {
|
||||
Material* material = luax_checktype(L, 1, Material);
|
||||
MaterialTexture textureType = TEXTURE_DIFFUSE;
|
||||
int index = 2;
|
||||
if (lua_type(L, index) == LUA_TSTRING) {
|
||||
textureType = luax_checkenum(L, index, MaterialTexture, NULL);
|
||||
index++;
|
||||
}
|
||||
Texture* texture = lua_isnoneornil(L, index) ? NULL : luax_checktype(L, index, Texture);
|
||||
lovrMaterialSetTexture(material, textureType, texture);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrMaterialGetTransform(lua_State* L) {
|
||||
Material* material = luax_checktype(L, 1, Material);
|
||||
float ox, oy, sx, sy, angle;
|
||||
lovrMaterialGetTransform(material, &ox, &oy, &sx, &sy, &angle);
|
||||
lua_pushnumber(L, ox);
|
||||
lua_pushnumber(L, oy);
|
||||
lua_pushnumber(L, sx);
|
||||
lua_pushnumber(L, sy);
|
||||
lua_pushnumber(L, angle);
|
||||
return 5;
|
||||
}
|
||||
|
||||
static int l_lovrMaterialSetTransform(lua_State* L) {
|
||||
Material* material = luax_checktype(L, 1, Material);
|
||||
float ox = luax_optfloat(L, 2, 0.f);
|
||||
float oy = luax_optfloat(L, 3, 0.f);
|
||||
float sx = luax_optfloat(L, 4, 1.f);
|
||||
float sy = luax_optfloat(L, 5, sx);
|
||||
float angle = luax_optfloat(L, 6, 0.f);
|
||||
lovrMaterialSetTransform(material, ox, oy, sx, sy, angle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const luaL_Reg lovrMaterial[] = {
|
||||
{ "getColor", l_lovrMaterialGetColor },
|
||||
{ "setColor", l_lovrMaterialSetColor },
|
||||
{ "getScalar", l_lovrMaterialGetScalar },
|
||||
{ "setScalar", l_lovrMaterialSetScalar },
|
||||
{ "getTexture", l_lovrMaterialGetTexture },
|
||||
{ "setTexture", l_lovrMaterialSetTexture },
|
||||
{ "getTransform", l_lovrMaterialGetTransform },
|
||||
{ "setTransform", l_lovrMaterialSetTransform },
|
||||
{ NULL, NULL }
|
||||
};
|
|
@ -1,537 +0,0 @@
|
|||
#include "api.h"
|
||||
#include "graphics/buffer.h"
|
||||
#include "graphics/graphics.h"
|
||||
#include "graphics/material.h"
|
||||
#include "graphics/mesh.h"
|
||||
#include "data/blob.h"
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
#include <limits.h>
|
||||
|
||||
static int l_lovrMeshAttachAttributes(lua_State* L) {
|
||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||
Mesh* other = luax_checktype(L, 2, Mesh);
|
||||
int instanceDivisor = luaL_optinteger(L, 3, 0);
|
||||
if (lua_isnoneornil(L, 4)) {
|
||||
uint32_t count = lovrMeshGetAttributeCount(other);
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
MeshAttribute attachment = *lovrMeshGetAttribute(other, i);
|
||||
if (attachment.buffer != lovrMeshGetVertexBuffer(other)) {
|
||||
break;
|
||||
}
|
||||
attachment.divisor = instanceDivisor;
|
||||
lovrMeshAttachAttribute(mesh, lovrMeshGetAttributeName(other, i), &attachment);
|
||||
}
|
||||
} else if (lua_istable(L, 4)) {
|
||||
int length = luax_len(L, 4);
|
||||
for (int i = 0; i < length; i++) {
|
||||
lua_rawgeti(L, 4, i + 1);
|
||||
const char* name = lua_tostring(L, -1);
|
||||
uint32_t index = lovrMeshGetAttributeIndex(other, name);
|
||||
const MeshAttribute* attribute = lovrMeshGetAttribute(other, index);
|
||||
lovrAssert(attribute, "Tried to attach non-existent attribute %s", name);
|
||||
MeshAttribute attachment = *attribute;
|
||||
attachment.divisor = instanceDivisor;
|
||||
lovrMeshAttachAttribute(mesh, name, &attachment);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
} else {
|
||||
int top = lua_gettop(L);
|
||||
for (int i = 4; i <= top; i++) {
|
||||
const char* name = lua_tostring(L, i);
|
||||
uint32_t index = lovrMeshGetAttributeIndex(other, name);
|
||||
const MeshAttribute* attribute = lovrMeshGetAttribute(other, index);
|
||||
lovrAssert(attribute, "Tried to attach non-existent attribute %s", name);
|
||||
MeshAttribute attachment = *attribute;
|
||||
attachment.divisor = instanceDivisor;
|
||||
lovrMeshAttachAttribute(mesh, name, &attachment);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrMeshDetachAttributes(lua_State* L) {
|
||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||
if (lua_isuserdata(L, 2)) {
|
||||
Mesh* other = luax_checktype(L, 2, Mesh);
|
||||
uint32_t count = lovrMeshGetAttributeCount(other);
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
const MeshAttribute* attachment = lovrMeshGetAttribute(other, i);
|
||||
if (attachment->buffer != lovrMeshGetVertexBuffer(other)) {
|
||||
break;
|
||||
}
|
||||
lovrMeshDetachAttribute(mesh, lovrMeshGetAttributeName(other, i));
|
||||
}
|
||||
} else if (lua_istable(L, 2)) {
|
||||
int length = luax_len(L, 2);
|
||||
for (int i = 0; i < length; i++) {
|
||||
lua_rawgeti(L, 2, i + 1);
|
||||
lovrMeshDetachAttribute(mesh, lua_tostring(L, -1));
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
} else {
|
||||
int top = lua_gettop(L);
|
||||
for (int i = 2; i <= top; i++) {
|
||||
lovrMeshDetachAttribute(mesh, lua_tostring(L, i));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrMeshDraw(lua_State* L) {
|
||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||
float transform[16];
|
||||
int index = luax_readmat4(L, 2, transform, 1);
|
||||
int instances = luaL_optinteger(L, index, 1);
|
||||
lovrGraphicsDrawMesh(mesh, transform, instances, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrMeshGetDrawMode(lua_State* L) {
|
||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||
luax_pushenum(L, DrawMode, lovrMeshGetDrawMode(mesh));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrMeshSetDrawMode(lua_State* L) {
|
||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||
DrawMode mode = luax_checkenum(L, 2, DrawMode, NULL);
|
||||
lovrMeshSetDrawMode(mesh, mode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrMeshGetVertexFormat(lua_State* L) {
|
||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||
uint32_t attributeCount = lovrMeshGetAttributeCount(mesh);
|
||||
lua_createtable(L, attributeCount, 0);
|
||||
for (uint32_t i = 0; i < attributeCount; i++) {
|
||||
const MeshAttribute* attribute = lovrMeshGetAttribute(mesh, i);
|
||||
if (attribute->buffer != lovrMeshGetVertexBuffer(mesh)) {
|
||||
break;
|
||||
}
|
||||
lua_createtable(L, 3, 0);
|
||||
lua_pushstring(L, lovrMeshGetAttributeName(mesh, i));
|
||||
lua_rawseti(L, -2, 1);
|
||||
luax_pushenum(L, AttributeType, attribute->type);
|
||||
lua_rawseti(L, -2, 2);
|
||||
lua_pushinteger(L, attribute->components);
|
||||
lua_rawseti(L, -2, 3);
|
||||
lua_rawseti(L, -2, i + 1);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrMeshGetVertexCount(lua_State* L) {
|
||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||
lua_pushinteger(L, lovrMeshGetVertexCount(mesh));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrMeshGetVertex(lua_State* L) {
|
||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||
int index = luaL_checkinteger(L, 2) - 1;
|
||||
Buffer* buffer = lovrMeshGetVertexBuffer(mesh);
|
||||
uint32_t attributeCount = lovrMeshGetAttributeCount(mesh);
|
||||
const MeshAttribute* firstAttribute = lovrMeshGetAttribute(mesh, 0);
|
||||
|
||||
if (!buffer || attributeCount == 0 || firstAttribute->buffer != buffer) {
|
||||
lovrThrow("Mesh does not have a vertex buffer");
|
||||
}
|
||||
|
||||
lovrAssert(lovrBufferIsReadable(buffer), "Mesh:getVertex can only be used if the Mesh was created with the readable flag");
|
||||
AttributeData data = { .raw = lovrBufferMap(buffer, index * firstAttribute->stride, false) };
|
||||
|
||||
int components = 0;
|
||||
for (uint32_t i = 0; i < attributeCount; i++) {
|
||||
const MeshAttribute* attribute = lovrMeshGetAttribute(mesh, i);
|
||||
if (attribute->buffer != buffer) {
|
||||
break;
|
||||
}
|
||||
for (unsigned j = 0; j < attribute->components; j++, components++) {
|
||||
switch (attribute->type) {
|
||||
case I8: lua_pushinteger(L, *data.i8++); break;
|
||||
case U8: lua_pushinteger(L, *data.u8++); break;
|
||||
case I16: lua_pushinteger(L, *data.i16++); break;
|
||||
case U16: lua_pushinteger(L, *data.u16++); break;
|
||||
case I32: lua_pushinteger(L, *data.i32++); break;
|
||||
case U32: lua_pushinteger(L, *data.u32++); break;
|
||||
case F32: lua_pushnumber(L, *data.f32++); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return components;
|
||||
}
|
||||
|
||||
static int l_lovrMeshSetVertex(lua_State* L) {
|
||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||
Buffer* buffer = lovrMeshGetVertexBuffer(mesh);
|
||||
uint32_t index = luaL_checkinteger(L, 2) - 1;
|
||||
lovrAssert(index < lovrMeshGetVertexCount(mesh), "Invalid mesh vertex index: %d", index + 1);
|
||||
bool table = lua_istable(L, 3);
|
||||
uint32_t attributeCount = lovrMeshGetAttributeCount(mesh);
|
||||
const MeshAttribute* firstAttribute = lovrMeshGetAttribute(mesh, 0);
|
||||
|
||||
if (!buffer || attributeCount == 0 || firstAttribute->buffer != buffer) {
|
||||
lovrThrow("Mesh does not have a vertex buffer");
|
||||
}
|
||||
|
||||
size_t stride = firstAttribute->stride;
|
||||
AttributeData data = { .raw = lovrBufferMap(buffer, index * stride, false) };
|
||||
int component = 0;
|
||||
for (uint32_t i = 0; i < attributeCount; i++) {
|
||||
const MeshAttribute* attribute = lovrMeshGetAttribute(mesh, i);
|
||||
if (attribute->buffer != buffer) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (unsigned j = 0; j < attribute->components; j++) {
|
||||
int k = 3 + j;
|
||||
if (table) {
|
||||
lua_rawgeti(L, 3, ++component);
|
||||
k = -1;
|
||||
}
|
||||
|
||||
switch (attribute->type) {
|
||||
case I8: *data.i8++ = luaL_optinteger(L, k, 0); break;
|
||||
case U8: *data.u8++ = luaL_optinteger(L, k, 0); break;
|
||||
case I16: *data.i16++ = luaL_optinteger(L, k, 0); break;
|
||||
case U16: *data.u16++ = luaL_optinteger(L, k, 0); break;
|
||||
case I32: *data.i32++ = luaL_optinteger(L, k, 0); break;
|
||||
case U32: *data.u32++ = luaL_optinteger(L, k, 0); break;
|
||||
case F32: *data.f32++ = luaL_optnumber(L, k, 0.); break;
|
||||
}
|
||||
|
||||
if (table) {
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
lovrBufferFlush(buffer, index * stride, stride);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrMeshGetVertexAttribute(lua_State* L) {
|
||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||
uint32_t vertexIndex = luaL_checkinteger(L, 2) - 1;
|
||||
uint32_t attributeIndex = luaL_checkinteger(L, 3) - 1;
|
||||
Buffer* buffer = lovrMeshGetVertexBuffer(mesh);
|
||||
lovrAssert(lovrBufferIsReadable(buffer), "Mesh:getVertex can only be used if the Mesh was created with the readable flag");
|
||||
lovrAssert(vertexIndex < lovrMeshGetVertexCount(mesh), "Invalid mesh vertex: %d", vertexIndex + 1);
|
||||
const MeshAttribute* attribute = lovrMeshGetAttribute(mesh, attributeIndex);
|
||||
lovrAssert(attribute && attribute->buffer == buffer, "Invalid mesh attribute: %d", attributeIndex + 1);
|
||||
AttributeData data = { .raw = lovrBufferMap(buffer, vertexIndex * attribute->stride + attribute->offset, false) };
|
||||
for (unsigned i = 0; i < attribute->components; i++) {
|
||||
switch (attribute->type) {
|
||||
case I8: lua_pushinteger(L, *data.i8++); break;
|
||||
case U8: lua_pushinteger(L, *data.u8++); break;
|
||||
case I16: lua_pushinteger(L, *data.i16++); break;
|
||||
case U16: lua_pushinteger(L, *data.u16++); break;
|
||||
case I32: lua_pushinteger(L, *data.i32++); break;
|
||||
case U32: lua_pushinteger(L, *data.u32++); break;
|
||||
case F32: lua_pushnumber(L, *data.f32++); break;
|
||||
}
|
||||
}
|
||||
return attribute->components;
|
||||
}
|
||||
|
||||
static int l_lovrMeshSetVertexAttribute(lua_State* L) {
|
||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||
Buffer* buffer = lovrMeshGetVertexBuffer(mesh);
|
||||
uint32_t vertexIndex = luaL_checkinteger(L, 2) - 1;
|
||||
uint32_t attributeIndex = luaL_checkinteger(L, 3) - 1;
|
||||
bool table = lua_istable(L, 4);
|
||||
lovrAssert(vertexIndex < lovrMeshGetVertexCount(mesh), "Invalid mesh vertex: %d", vertexIndex + 1);
|
||||
const MeshAttribute* attribute = lovrMeshGetAttribute(mesh, attributeIndex);
|
||||
lovrAssert(attribute && attribute->buffer == buffer, "Invalid mesh attribute: %d", attributeIndex + 1);
|
||||
AttributeData data = { .raw = lovrBufferMap(buffer, vertexIndex * attribute->stride + attribute->offset, false) };
|
||||
for (unsigned i = 0; i < attribute->components; i++) {
|
||||
int index = 4 + i;
|
||||
if (table) {
|
||||
lua_rawgeti(L, 4, i + 1);
|
||||
index = -1;
|
||||
}
|
||||
|
||||
switch (attribute->type) {
|
||||
case I8: *data.i8++ = luaL_optinteger(L, index, 0); break;
|
||||
case U8: *data.u8++ = luaL_optinteger(L, index, 0); break;
|
||||
case I16: *data.i16++ = luaL_optinteger(L, index, 0); break;
|
||||
case U16: *data.u16++ = luaL_optinteger(L, index, 0); break;
|
||||
case I32: *data.i32++ = luaL_optinteger(L, index, 0); break;
|
||||
case U32: *data.u32++ = luaL_optinteger(L, index, 0); break;
|
||||
case F32: *data.f32++ = luaL_optnumber(L, index, 0.); break;
|
||||
}
|
||||
|
||||
if (table) {
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
size_t attributeSize = 0;
|
||||
switch (attribute->type) {
|
||||
case I8: attributeSize = attribute->components * sizeof(int8_t); break;
|
||||
case U8: attributeSize = attribute->components * sizeof(uint8_t); break;
|
||||
case I16: attributeSize = attribute->components * sizeof(int16_t); break;
|
||||
case U16: attributeSize = attribute->components * sizeof(uint16_t); break;
|
||||
case I32: attributeSize = attribute->components * sizeof(int32_t); break;
|
||||
case U32: attributeSize = attribute->components * sizeof(uint32_t); break;
|
||||
case F32: attributeSize = attribute->components * sizeof(float); break;
|
||||
}
|
||||
lovrBufferFlush(buffer, vertexIndex * attribute->stride + attribute->offset, attributeSize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrMeshSetVertices(lua_State* L) {
|
||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||
Buffer* buffer = lovrMeshGetVertexBuffer(mesh);
|
||||
uint32_t attributeCount = lovrMeshGetAttributeCount(mesh);
|
||||
const MeshAttribute* firstAttribute = lovrMeshGetAttribute(mesh, 0);
|
||||
|
||||
if (!buffer || attributeCount == 0 || firstAttribute->buffer != buffer) {
|
||||
lovrThrow("Mesh:setVertices does not work when the Mesh does not have a vertex buffer");
|
||||
}
|
||||
|
||||
uint32_t capacity = lovrMeshGetVertexCount(mesh);
|
||||
uint32_t start = luaL_optinteger(L, 3, 1) - 1;
|
||||
lovrAssert(start < capacity, "Starting vertex index must be in range [1, %d]", capacity);
|
||||
uint32_t count = luaL_optinteger(L, 4, capacity - start);
|
||||
size_t stride = firstAttribute->stride;
|
||||
|
||||
Blob* blob = luax_totype(L, 2, Blob);
|
||||
if (blob) {
|
||||
count = MIN(count, (uint32_t) (blob->size / stride));
|
||||
lovrAssert(start + count <= capacity, "Overflow in Mesh:setVertices: Mesh can only hold %d vertices", capacity);
|
||||
void* data = lovrBufferMap(buffer, start * stride, false);
|
||||
memcpy(data, blob->data, count * stride);
|
||||
lovrBufferFlush(buffer, start * stride, count * stride);
|
||||
return 0;
|
||||
}
|
||||
|
||||
luaL_checktype(L, 2, LUA_TTABLE);
|
||||
count = MIN(count, (uint32_t) luax_len(L, 2));
|
||||
lovrAssert(start + count <= capacity, "Overflow in Mesh:setVertices: Mesh can only hold %d vertices", capacity);
|
||||
|
||||
AttributeData data = { .raw = lovrBufferMap(buffer, start * stride, false) };
|
||||
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
lua_rawgeti(L, 2, i + 1);
|
||||
luaL_checktype(L, -1, LUA_TTABLE);
|
||||
int component = 0;
|
||||
for (uint32_t j = 0; j < attributeCount; j++) {
|
||||
const MeshAttribute* attribute = lovrMeshGetAttribute(mesh, j);
|
||||
if (attribute->buffer != buffer) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (unsigned k = 0; k < attribute->components; k++) {
|
||||
lua_rawgeti(L, -1, ++component);
|
||||
|
||||
switch (attribute->type) {
|
||||
case I8: *data.i8++ = luaL_optinteger(L, -1, 0); break;
|
||||
case U8: *data.u8++ = luaL_optinteger(L, -1, 0); break;
|
||||
case I16: *data.i16++ = luaL_optinteger(L, -1, 0); break;
|
||||
case U16: *data.u16++ = luaL_optinteger(L, -1, 0); break;
|
||||
case I32: *data.i32++ = luaL_optinteger(L, -1, 0); break;
|
||||
case U32: *data.u32++ = luaL_optinteger(L, -1, 0); break;
|
||||
case F32: *data.f32++ = luaL_optnumber(L, -1, 0.); break;
|
||||
}
|
||||
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
lovrBufferFlush(buffer, start * stride, count * stride);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrMeshGetVertexMap(lua_State* L) {
|
||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||
Buffer* buffer = lovrMeshGetIndexBuffer(mesh);
|
||||
uint32_t count = lovrMeshGetIndexCount(mesh);
|
||||
size_t size = lovrMeshGetIndexSize(mesh);
|
||||
|
||||
if (!buffer || count == 0 || size == 0) {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
lovrAssert(lovrBufferIsReadable(buffer), "Mesh:getVertexMap can only be used if the Mesh was created with the readable flag");
|
||||
union { void* raw; uint16_t* shorts; uint32_t* ints; } indices = { .raw = lovrBufferMap(buffer, 0, false) };
|
||||
|
||||
if (lua_istable(L, 2)) {
|
||||
lua_settop(L, 2);
|
||||
} else if (lua_isuserdata(L, 2)) {
|
||||
Blob* blob = luax_checktype(L, 2, Blob);
|
||||
lovrAssert(size * count <= blob->size, "Mesh vertex map is %zu bytes, but Blob can only hold %zu", size * count, blob->size);
|
||||
memcpy(blob->data, indices.raw, size * count);
|
||||
return 0;
|
||||
} else {
|
||||
lua_settop(L, 1);
|
||||
lua_createtable(L, count, 0);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
uint32_t index = size == sizeof(uint32_t) ? indices.ints[i] : indices.shorts[i];
|
||||
lua_pushinteger(L, index + 1);
|
||||
lua_rawseti(L, 2, i + 1);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrMeshSetVertexMap(lua_State* L) {
|
||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||
Buffer* release = NULL;
|
||||
|
||||
if (lua_isnoneornil(L, 2)) {
|
||||
lovrMeshSetIndexBuffer(mesh, NULL, 0, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lua_type(L, 2) == LUA_TUSERDATA) {
|
||||
Blob* blob = luax_checktype(L, 2, Blob);
|
||||
size_t size = luaL_optinteger(L, 3, 4);
|
||||
lovrAssert(size == 2 || size == 4, "Size of Mesh indices should be 2 bytes or 4 bytes");
|
||||
lovrAssert(blob->size / size < UINT32_MAX, "Too many Mesh indices");
|
||||
uint32_t count = (uint32_t) (blob->size / size);
|
||||
Buffer* indexBuffer = lovrMeshGetIndexBuffer(mesh);
|
||||
if (!indexBuffer || count * size > lovrBufferGetSize(indexBuffer)) {
|
||||
Buffer* vertexBuffer = lovrMeshGetVertexBuffer(mesh);
|
||||
BufferUsage usage = vertexBuffer ? lovrBufferGetUsage(vertexBuffer) : USAGE_DYNAMIC;
|
||||
bool readable = vertexBuffer ? lovrBufferIsReadable(vertexBuffer) : false;
|
||||
indexBuffer = release = lovrBufferCreate(blob->size, blob->data, BUFFER_INDEX, usage, readable);
|
||||
lovrMeshSetIndexBuffer(mesh, indexBuffer, count, size, 0);
|
||||
} else {
|
||||
void* indices = lovrBufferMap(indexBuffer, 0, false);
|
||||
memcpy(indices, blob->data, blob->size);
|
||||
lovrBufferFlush(indexBuffer, 0, blob->size);
|
||||
}
|
||||
} else {
|
||||
luaL_checktype(L, 2, LUA_TTABLE);
|
||||
uint32_t count = luax_len(L, 2);
|
||||
uint32_t vertexCount = lovrMeshGetVertexCount(mesh);
|
||||
size_t size = vertexCount > USHRT_MAX ? sizeof(uint32_t) : sizeof(uint16_t);
|
||||
|
||||
Buffer* indexBuffer = lovrMeshGetIndexBuffer(mesh);
|
||||
if (!indexBuffer || count * size > lovrBufferGetSize(indexBuffer)) {
|
||||
Buffer* vertexBuffer = lovrMeshGetVertexBuffer(mesh);
|
||||
BufferUsage usage = vertexBuffer ? lovrBufferGetUsage(vertexBuffer) : USAGE_DYNAMIC;
|
||||
bool readable = vertexBuffer ? lovrBufferIsReadable(vertexBuffer) : false;
|
||||
indexBuffer = release = lovrBufferCreate(count * size, NULL, BUFFER_INDEX, usage, readable);
|
||||
}
|
||||
|
||||
union { void* raw; uint16_t* shorts; uint32_t* ints; } indices = { .raw = lovrBufferMap(indexBuffer, 0, false) };
|
||||
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
lua_rawgeti(L, 2, i + 1);
|
||||
if (!lua_isnumber(L, -1)) {
|
||||
return luaL_error(L, "Mesh vertex map index #%d must be numeric", i);
|
||||
}
|
||||
|
||||
uint32_t index = lua_tointeger(L, -1);
|
||||
if (index > vertexCount || index < 1) {
|
||||
return luaL_error(L, "Invalid vertex map value: %d", index);
|
||||
}
|
||||
|
||||
if (size == sizeof(uint16_t)) {
|
||||
indices.shorts[i] = index - 1;
|
||||
} else {
|
||||
indices.ints[i] = index - 1;
|
||||
}
|
||||
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
lovrMeshSetIndexBuffer(mesh, indexBuffer, count, size, 0);
|
||||
lovrBufferFlush(indexBuffer, 0, count * size);
|
||||
}
|
||||
|
||||
lovrRelease(release, lovrBufferDestroy);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrMeshIsAttributeEnabled(lua_State* L) {
|
||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||
const char* attribute = luaL_checkstring(L, 2);
|
||||
lua_pushboolean(L, lovrMeshIsAttributeEnabled(mesh, attribute));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrMeshSetAttributeEnabled(lua_State* L) {
|
||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||
const char* attribute = luaL_checkstring(L, 2);
|
||||
bool enabled = lua_toboolean(L, 3);
|
||||
lovrMeshSetAttributeEnabled(mesh, attribute, enabled);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrMeshGetDrawRange(lua_State* L) {
|
||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||
uint32_t start, count;
|
||||
lovrMeshGetDrawRange(mesh, &start, &count);
|
||||
|
||||
if (count == 0) {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
lua_pushinteger(L, start + 1);
|
||||
lua_pushinteger(L, count);
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int l_lovrMeshSetDrawRange(lua_State* L) {
|
||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||
if (lua_isnoneornil(L, 2)) {
|
||||
lovrMeshSetDrawRange(mesh, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rangeStart = luaL_checkinteger(L, 2) - 1;
|
||||
int rangeCount = luaL_checkinteger(L, 3);
|
||||
lovrMeshSetDrawRange(mesh, rangeStart, rangeCount);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrMeshGetMaterial(lua_State* L) {
|
||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||
Material* material = lovrMeshGetMaterial(mesh);
|
||||
luax_pushtype(L, Material, material);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrMeshSetMaterial(lua_State* L) {
|
||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||
if (lua_isnoneornil(L, 2)) {
|
||||
lovrMeshSetMaterial(mesh, NULL);
|
||||
} else {
|
||||
Material* material = luax_checktype(L, 2, Material);
|
||||
lovrMeshSetMaterial(mesh, material);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const luaL_Reg lovrMesh[] = {
|
||||
{ "attachAttributes", l_lovrMeshAttachAttributes },
|
||||
{ "detachAttributes", l_lovrMeshDetachAttributes },
|
||||
{ "draw", l_lovrMeshDraw },
|
||||
{ "getVertexFormat", l_lovrMeshGetVertexFormat },
|
||||
{ "getVertexCount", l_lovrMeshGetVertexCount },
|
||||
{ "getVertex", l_lovrMeshGetVertex },
|
||||
{ "setVertex", l_lovrMeshSetVertex },
|
||||
{ "getVertexAttribute", l_lovrMeshGetVertexAttribute },
|
||||
{ "setVertexAttribute", l_lovrMeshSetVertexAttribute },
|
||||
{ "setVertices", l_lovrMeshSetVertices },
|
||||
{ "getVertexMap", l_lovrMeshGetVertexMap },
|
||||
{ "setVertexMap", l_lovrMeshSetVertexMap },
|
||||
{ "isAttributeEnabled", l_lovrMeshIsAttributeEnabled },
|
||||
{ "setAttributeEnabled", l_lovrMeshSetAttributeEnabled },
|
||||
{ "getDrawMode", l_lovrMeshGetDrawMode },
|
||||
{ "setDrawMode", l_lovrMeshSetDrawMode },
|
||||
{ "getDrawRange", l_lovrMeshGetDrawRange },
|
||||
{ "setDrawRange", l_lovrMeshSetDrawRange },
|
||||
{ "getMaterial", l_lovrMeshGetMaterial },
|
||||
{ "setMaterial", l_lovrMeshSetMaterial },
|
||||
{ NULL, NULL }
|
||||
};
|
|
@ -1,243 +0,0 @@
|
|||
#include "api.h"
|
||||
#include "graphics/material.h"
|
||||
#include "graphics/model.h"
|
||||
#include "data/modelData.h"
|
||||
#include "core/maf.h"
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
|
||||
static uint32_t luax_checkanimation(lua_State* L, int index, Model* model) {
|
||||
switch (lua_type(L, index)) {
|
||||
case LUA_TSTRING: {
|
||||
size_t length;
|
||||
const char* name = lua_tolstring(L, index, &length);
|
||||
ModelData* modelData = lovrModelGetModelData(model);
|
||||
uint64_t animationIndex = map_get(&modelData->animationMap, hash64(name, length));
|
||||
lovrAssert(animationIndex != MAP_NIL, "Model has no animation named '%s'", name);
|
||||
return (uint32_t) animationIndex;
|
||||
}
|
||||
case LUA_TNUMBER: return lua_tointeger(L, index) - 1;
|
||||
default: return luax_typeerror(L, index, "number or string");
|
||||
}
|
||||
}
|
||||
|
||||
static int l_lovrModelDraw(lua_State* L) {
|
||||
Model* model = luax_checktype(L, 1, Model);
|
||||
float transform[16];
|
||||
int index = luax_readmat4(L, 2, transform, 1);
|
||||
int instances = luaL_optinteger(L, index, 1);
|
||||
lovrModelDraw(model, transform, instances);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrModelAnimate(lua_State* L) {
|
||||
Model* model = luax_checktype(L, 1, Model);
|
||||
uint32_t animation = luax_checkanimation(L, 2, model);
|
||||
float time = luaL_checknumber(L, 3);
|
||||
float alpha = luax_optfloat(L, 4, 1.f);
|
||||
lovrModelAnimate(model, animation, time, alpha);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrModelPose(lua_State* L) {
|
||||
Model* model = luax_checktype(L, 1, Model);
|
||||
|
||||
uint32_t node;
|
||||
switch (lua_type(L, 2)) {
|
||||
case LUA_TNONE:
|
||||
case LUA_TNIL:
|
||||
lovrModelResetPose(model);
|
||||
return 0;
|
||||
case LUA_TNUMBER:
|
||||
node = lua_tointeger(L, 2) - 1;
|
||||
break;
|
||||
case LUA_TSTRING: {
|
||||
size_t length;
|
||||
const char* name = lua_tolstring(L, 2, &length);
|
||||
ModelData* modelData = lovrModelGetModelData(model);
|
||||
uint64_t index = map_get(&modelData->nodeMap, hash64(name, length));
|
||||
lovrAssert(index != MAP_NIL, "Model has no node named '%s'", name);
|
||||
node = (uint32_t) index;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return luax_typeerror(L, 2, "nil, number, or string");
|
||||
}
|
||||
|
||||
int index = 3;
|
||||
float position[4], rotation[4];
|
||||
index = luax_readvec3(L, index, position, NULL);
|
||||
index = luax_readquat(L, index, rotation, NULL);
|
||||
float alpha = luax_optfloat(L, index, 1.f);
|
||||
lovrModelPose(model, node, position, rotation, alpha);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrModelGetMaterial(lua_State* L) {
|
||||
Model* model = luax_checktype(L, 1, Model);
|
||||
|
||||
uint32_t material;
|
||||
switch (lua_type(L, 2)) {
|
||||
case LUA_TNUMBER:
|
||||
material = lua_tointeger(L, 2) - 1;
|
||||
break;
|
||||
case LUA_TSTRING: {
|
||||
size_t length;
|
||||
const char* name = lua_tolstring(L, 2, &length);
|
||||
ModelData* modelData = lovrModelGetModelData(model);
|
||||
uint64_t index = map_get(&modelData->materialMap, hash64(name, length));
|
||||
lovrAssert(index != MAP_NIL, "Model has no material named '%s'", name);
|
||||
material = (uint32_t) index;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return luax_typeerror(L, 2, "nil, number, or string");
|
||||
}
|
||||
|
||||
luax_pushtype(L, Material, lovrModelGetMaterial(model, material));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrModelGetAABB(lua_State* L) {
|
||||
Model* model = luax_checktype(L, 1, Model);
|
||||
float aabb[6];
|
||||
lovrModelGetAABB(model, aabb);
|
||||
for (int i = 0; i < 6; i++) {
|
||||
lua_pushnumber(L, aabb[i]);
|
||||
}
|
||||
return 6;
|
||||
}
|
||||
|
||||
static int l_lovrModelGetTriangles(lua_State* L) {
|
||||
Model* model = luax_checktype(L, 1, Model);
|
||||
float* vertices = NULL;
|
||||
uint32_t* indices = NULL;
|
||||
uint32_t vertexCount;
|
||||
uint32_t indexCount;
|
||||
lovrModelGetTriangles(model, &vertices, &vertexCount, &indices, &indexCount);
|
||||
|
||||
lua_createtable(L, vertexCount * 3, 0);
|
||||
for (uint32_t i = 0; i < vertexCount * 3; i++) {
|
||||
lua_pushnumber(L, vertices[i]);
|
||||
lua_rawseti(L, -2, i + 1);
|
||||
}
|
||||
|
||||
lua_createtable(L, indexCount, 0);
|
||||
for (uint32_t i = 0; i < indexCount; i++) {
|
||||
lua_pushinteger(L, indices[i] + 1);
|
||||
lua_rawseti(L, -2, i + 1);
|
||||
}
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int l_lovrModelGetNodePose(lua_State* L) {
|
||||
Model* model = luax_checktype(L, 1, Model);
|
||||
uint32_t node;
|
||||
switch (lua_type(L, 2)) {
|
||||
case LUA_TNUMBER:
|
||||
node = lua_tointeger(L, 2) - 1;
|
||||
break;
|
||||
case LUA_TSTRING: {
|
||||
size_t length;
|
||||
const char* name = lua_tolstring(L, 2, &length);
|
||||
ModelData* modelData = lovrModelGetModelData(model);
|
||||
uint64_t index = map_get(&modelData->nodeMap, hash64(name, length));
|
||||
lovrAssert(index != MAP_NIL, "Model has no node named '%s'", name);
|
||||
node = (uint32_t) index;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return luax_typeerror(L, 2, "number or string");
|
||||
}
|
||||
|
||||
float position[4], rotation[4], angle, ax, ay, az;
|
||||
CoordinateSpace space = luax_checkenum(L, 3, CoordinateSpace, "global");
|
||||
lovrModelGetNodePose(model, node, position, rotation, space);
|
||||
lua_pushnumber(L, position[0]);
|
||||
lua_pushnumber(L, position[1]);
|
||||
lua_pushnumber(L, position[2]);
|
||||
quat_getAngleAxis(rotation, &angle, &ax, &ay, &az);
|
||||
lua_pushnumber(L, angle);
|
||||
lua_pushnumber(L, ax);
|
||||
lua_pushnumber(L, ay);
|
||||
lua_pushnumber(L, az);
|
||||
return 7;
|
||||
}
|
||||
|
||||
static int l_lovrModelGetAnimationName(lua_State* L) {
|
||||
Model* model = luax_checktype(L, 1, Model);
|
||||
uint32_t index = luaL_checkinteger(L, 2);
|
||||
ModelData* modelData = lovrModelGetModelData(model);
|
||||
lovrAssert(index > 0 && index <= modelData->animationCount, "Model has no animation at index %d", index);
|
||||
lua_pushstring(L, modelData->animations[index - 1].name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrModelGetMaterialName(lua_State* L) {
|
||||
Model* model = luax_checktype(L, 1, Model);
|
||||
uint32_t index = luaL_checkinteger(L, 2);
|
||||
ModelData* modelData = lovrModelGetModelData(model);
|
||||
lovrAssert(index > 0 && index <= modelData->materialCount, "Model has no material at index %d", index);
|
||||
lua_pushstring(L, modelData->materials[index - 1].name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrModelGetNodeName(lua_State* L) {
|
||||
Model* model = luax_checktype(L, 1, Model);
|
||||
uint32_t index = luaL_checkinteger(L, 2);
|
||||
ModelData* modelData = lovrModelGetModelData(model);
|
||||
lovrAssert(index > 0 && index <= modelData->nodeCount, "Model has no node at index %d", index);
|
||||
lua_pushstring(L, modelData->nodes[index - 1].name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrModelGetAnimationCount(lua_State* L) {
|
||||
Model* model = luax_checktype(L, 1, Model);
|
||||
lua_pushinteger(L, lovrModelGetModelData(model)->animationCount);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrModelGetMaterialCount(lua_State* L) {
|
||||
Model* model = luax_checktype(L, 1, Model);
|
||||
lua_pushinteger(L, lovrModelGetModelData(model)->materialCount);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrModelGetNodeCount(lua_State* L) {
|
||||
Model* model = luax_checktype(L, 1, Model);
|
||||
lua_pushinteger(L, lovrModelGetModelData(model)->nodeCount);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrModelGetAnimationDuration(lua_State* L) {
|
||||
Model* model = luax_checktype(L, 1, Model);
|
||||
uint32_t animation = luax_checkanimation(L, 2, model);
|
||||
lua_pushnumber(L, lovrModelGetModelData(model)->animations[animation].duration);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrModelHasJoints(lua_State* L) {
|
||||
Model* model = luax_checktype(L, 1, Model);
|
||||
lua_pushboolean(L, lovrModelGetModelData(model)->skinCount > 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const luaL_Reg lovrModel[] = {
|
||||
{ "draw", l_lovrModelDraw },
|
||||
{ "animate", l_lovrModelAnimate },
|
||||
{ "pose", l_lovrModelPose },
|
||||
{ "getMaterial", l_lovrModelGetMaterial },
|
||||
{ "getAABB", l_lovrModelGetAABB },
|
||||
{ "getTriangles", l_lovrModelGetTriangles },
|
||||
{ "getNodePose", l_lovrModelGetNodePose },
|
||||
{ "getAnimationName", l_lovrModelGetAnimationName },
|
||||
{ "getMaterialName", l_lovrModelGetMaterialName },
|
||||
{ "getNodeName", l_lovrModelGetNodeName },
|
||||
{ "getAnimationCount", l_lovrModelGetAnimationCount },
|
||||
{ "getMaterialCount", l_lovrModelGetMaterialCount },
|
||||
{ "getNodeCount", l_lovrModelGetNodeCount },
|
||||
{ "getAnimationDuration", l_lovrModelGetAnimationDuration },
|
||||
{ "hasJoints", l_lovrModelHasJoints },
|
||||
{ NULL, NULL }
|
||||
};
|
|
@ -1,274 +0,0 @@
|
|||
#include "api.h"
|
||||
#include "graphics/buffer.h"
|
||||
#include "graphics/shader.h"
|
||||
#include "data/blob.h"
|
||||
#include "core/maf.h"
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct TempData {
|
||||
void* data;
|
||||
int size;
|
||||
};
|
||||
|
||||
// Not thread safe
|
||||
static struct TempData tempData;
|
||||
|
||||
int luax_checkuniform(lua_State* L, int index, const Uniform* uniform, void* dest, const char* debug) {
|
||||
Blob* blob = luax_totype(L, index, Blob);
|
||||
UniformType uniformType = uniform->type;
|
||||
int components = uniform->components;
|
||||
int count = uniform->count;
|
||||
|
||||
if (uniformType == UNIFORM_MATRIX) {
|
||||
components *= components;
|
||||
}
|
||||
|
||||
if (blob) {
|
||||
size_t elements = count * components;
|
||||
const char* s = elements == 1 ? "" : "s";
|
||||
size_t capacity;
|
||||
|
||||
switch (uniformType) {
|
||||
case UNIFORM_FLOAT:
|
||||
case UNIFORM_MATRIX:
|
||||
capacity = blob->size / sizeof(float);
|
||||
lovrAssert(capacity >= elements, "Blob can only hold %d float%s, at least %d needed for uniform '%s'", capacity, s, elements, debug);
|
||||
memcpy(dest, blob->data, elements * sizeof(float));
|
||||
break;
|
||||
|
||||
case UNIFORM_INT:
|
||||
capacity = blob->size / sizeof(int);
|
||||
lovrAssert(capacity >= elements, "Blob can only hold %d int%s, at least %d needed for uniform '%s'", capacity, s, elements, debug);
|
||||
memcpy(dest, blob->data, elements * sizeof(int));
|
||||
break;
|
||||
|
||||
case UNIFORM_SAMPLER: lovrThrow("Sampler uniform '%s' can not be updated with a Blob", debug);
|
||||
case UNIFORM_IMAGE: lovrThrow("Image uniform '%s' can not be updated with a Blob", debug);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (components == 1) {
|
||||
bool isTable = lua_istable(L, index);
|
||||
int length = isTable ? luax_len(L, index) : count;
|
||||
length = MIN(length, count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
int j = index + i;
|
||||
if (isTable) {
|
||||
lua_rawgeti(L, index, i + 1);
|
||||
j = -1;
|
||||
}
|
||||
|
||||
switch (uniformType) {
|
||||
case UNIFORM_FLOAT: *((float*) dest + i) = luax_optfloat(L, j, 0.f); break;
|
||||
case UNIFORM_INT: *((int*) dest + i) = luaL_optinteger(L, j, 0); break;
|
||||
case UNIFORM_SAMPLER: {
|
||||
*((Texture**) dest + i) = luax_checktype(L, j, Texture);
|
||||
TextureType type = lovrTextureGetType(*((Texture**) dest + i));
|
||||
lovrAssert(type == uniform->textureType, "Attempt to send %s texture to %s sampler uniform", lovrTextureType[type].string, lovrTextureType[uniform->textureType].string);
|
||||
break;
|
||||
}
|
||||
|
||||
case UNIFORM_IMAGE: {
|
||||
StorageImage* image = (StorageImage*) dest + i;
|
||||
image->texture = luax_checktype(L, j, Texture);
|
||||
image->slice = -1;
|
||||
image->mipmap = 0;
|
||||
image->access = ACCESS_READ_WRITE;
|
||||
TextureType type = lovrTextureGetType(image->texture);
|
||||
lovrAssert(type == uniform->textureType, "Attempt to send %s texture to %s storage image uniform", lovrTextureType[type], lovrTextureType[uniform->textureType]);
|
||||
break;
|
||||
}
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (isTable) {
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bool wrappedTable = false;
|
||||
|
||||
if (lua_istable(L, index)) {
|
||||
lua_rawgeti(L, index, 1);
|
||||
wrappedTable = !lua_isnumber(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
if (wrappedTable) {
|
||||
int length = luax_len(L, index);
|
||||
length = MIN(length, count);
|
||||
for (int i = 0; i < length; i++) {
|
||||
lua_rawgeti(L, index, i + 1);
|
||||
|
||||
if (uniformType == UNIFORM_MATRIX && components == 16) {
|
||||
VectorType type;
|
||||
mat4 m = luax_tovector(L, -1, &type);
|
||||
if (m && type == V_MAT4) {
|
||||
mat4_init((float*) dest + i * components, m);
|
||||
lua_pop(L, 1);
|
||||
continue;
|
||||
}
|
||||
} else if (uniformType == UNIFORM_FLOAT && components == 3) {
|
||||
VectorType type;
|
||||
vec3 v = luax_tovector(L, -1, &type);
|
||||
if (v && type == V_VEC3) {
|
||||
vec3_init((float*) dest + i * components, v);
|
||||
lua_pop(L, 1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
luaL_checktype(L, -1, LUA_TTABLE);
|
||||
for (int j = 0; j < components; j++) {
|
||||
lua_rawgeti(L, -1, j + 1);
|
||||
switch (uniformType) {
|
||||
case UNIFORM_FLOAT:
|
||||
case UNIFORM_MATRIX:
|
||||
*((float*) dest + i * components + j) = luax_optfloat(L, -1, 0.f);
|
||||
break;
|
||||
|
||||
case UNIFORM_INT:
|
||||
*((int*) dest + i * components + j) = luaL_optinteger(L, -1, 0);
|
||||
break;
|
||||
|
||||
case UNIFORM_SAMPLER:
|
||||
case UNIFORM_IMAGE:
|
||||
lovrThrow("Unreachable");
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (uniformType == UNIFORM_MATRIX && components == 16) {
|
||||
VectorType type;
|
||||
mat4 m = luax_tovector(L, index + i, &type);
|
||||
if (m && type == V_MAT4) {
|
||||
mat4_init((float*) dest + i * components, m);
|
||||
continue;
|
||||
}
|
||||
} else if (uniformType == UNIFORM_FLOAT && components == 3) {
|
||||
VectorType type;
|
||||
vec3 v = luax_tovector(L, index + i, &type);
|
||||
if (v && type == V_VEC3) {
|
||||
vec3_init((float*) dest + i * components, v);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
luaL_checktype(L, index + i, LUA_TTABLE);
|
||||
for (int j = 0; j < components; j++) {
|
||||
lua_rawgeti(L, index + i, j + 1);
|
||||
switch (uniformType) {
|
||||
case UNIFORM_FLOAT:
|
||||
case UNIFORM_MATRIX:
|
||||
*((float*) dest + i * components + j) = luax_optfloat(L, -1, 0.f);
|
||||
break;
|
||||
|
||||
case UNIFORM_INT:
|
||||
*((int*) dest + i * components + j) = luaL_optinteger(L, -1, 0);
|
||||
break;
|
||||
|
||||
case UNIFORM_SAMPLER:
|
||||
case UNIFORM_IMAGE:
|
||||
lovrThrow("Unreachable");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrShaderGetType(lua_State* L) {
|
||||
Shader* shader = luax_checktype(L, 1, Shader);
|
||||
luax_pushenum(L, ShaderType, lovrShaderGetType(shader));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrShaderHasUniform(lua_State* L) {
|
||||
Shader* shader = luax_checktype(L, 1, Shader);
|
||||
const char* name = luaL_checkstring(L, 2);
|
||||
lua_pushboolean(L, lovrShaderHasUniform(shader, name));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrShaderHasBlock(lua_State* L) {
|
||||
Shader* shader = luax_checktype(L, 1, Shader);
|
||||
const char* name = luaL_checkstring(L, 2);
|
||||
lua_pushboolean(L, lovrShaderHasBlock(shader, name));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrShaderSend(lua_State* L) {
|
||||
Shader* shader = luax_checktype(L, 1, Shader);
|
||||
const char* name = luaL_checkstring(L, 2);
|
||||
const Uniform* uniform = lovrShaderGetUniform(shader, name);
|
||||
if (!uniform) {
|
||||
lua_pushboolean(L, false);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (tempData.size < uniform->size) {
|
||||
tempData.size = uniform->size;
|
||||
tempData.data = realloc(tempData.data, tempData.size);
|
||||
}
|
||||
|
||||
luax_checkuniform(L, 3, uniform, tempData.data, name);
|
||||
switch (uniform->type) {
|
||||
case UNIFORM_FLOAT: lovrShaderSetFloats(shader, uniform->name, tempData.data, 0, uniform->count * uniform->components); break;
|
||||
case UNIFORM_INT: lovrShaderSetInts(shader, uniform->name, tempData.data, 0, uniform->count * uniform->components); break;
|
||||
case UNIFORM_MATRIX: lovrShaderSetMatrices(shader, uniform->name, tempData.data, 0, uniform->count * uniform->components * uniform->components); break;
|
||||
case UNIFORM_SAMPLER: lovrShaderSetTextures(shader, uniform->name, tempData.data, 0, uniform->count); break;
|
||||
case UNIFORM_IMAGE: lovrShaderSetImages(shader, uniform->name, tempData.data, 0, uniform->count); break;
|
||||
}
|
||||
lua_pushboolean(L, true);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrShaderSendBlock(lua_State* L) {
|
||||
Shader* shader = luax_checktype(L, 1, Shader);
|
||||
const char* name = luaL_checkstring(L, 2);
|
||||
lovrAssert(lovrShaderHasBlock(shader, name), "Unknown shader block '%s'", name);
|
||||
ShaderBlock* block = luax_checktype(L, 3, ShaderBlock);
|
||||
UniformAccess access = luax_checkenum(L, 4, UniformAccess, "readwrite");
|
||||
Buffer* buffer = lovrShaderBlockGetBuffer(block);
|
||||
lovrShaderSetBlock(shader, name, buffer, 0, lovrBufferGetSize(buffer), access);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrShaderSendImage(lua_State* L) {
|
||||
int index = 1;
|
||||
Shader* shader = luax_checktype(L, index++, Shader);
|
||||
const char* name = luaL_checkstring(L, index++);
|
||||
|
||||
int start = 0;
|
||||
if (lua_type(L, index) == LUA_TNUMBER) {
|
||||
start = lua_tointeger(L, index++);
|
||||
}
|
||||
|
||||
Texture* texture = luax_checktype(L, index++, Texture);
|
||||
int slice = luaL_optinteger(L, index++, 0) - 1; // Default is -1
|
||||
int mipmap = luax_optmipmap(L, index++, texture);
|
||||
UniformAccess access = luax_checkenum(L, index++, UniformAccess, "readwrite");
|
||||
StorageImage image = { .texture = texture, .slice = slice, .mipmap = mipmap, .access = access };
|
||||
lovrShaderSetImages(shader, name, &image, start, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const luaL_Reg lovrShader[] = {
|
||||
{ "getType", l_lovrShaderGetType },
|
||||
{ "hasUniform", l_lovrShaderHasUniform },
|
||||
{ "hasBlock", l_lovrShaderHasBlock },
|
||||
{ "send", l_lovrShaderSend },
|
||||
{ "sendBlock", l_lovrShaderSendBlock },
|
||||
{ "sendImage", l_lovrShaderSendImage },
|
||||
{ NULL, NULL }
|
||||
};
|
|
@ -1,134 +0,0 @@
|
|||
#include "api.h"
|
||||
#include "graphics/buffer.h"
|
||||
#include "graphics/shader.h"
|
||||
#include "data/blob.h"
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static int l_lovrShaderBlockGetType(lua_State* L) {
|
||||
ShaderBlock* block = luax_checktype(L, 1, ShaderBlock);
|
||||
luax_pushenum(L, BlockType, lovrShaderBlockGetType(block));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrShaderBlockGetSize(lua_State* L) {
|
||||
ShaderBlock* block = luax_checktype(L, 1, ShaderBlock);
|
||||
Buffer* buffer = lovrShaderBlockGetBuffer(block);
|
||||
lua_pushinteger(L, lovrBufferGetSize(buffer));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrShaderBlockGetOffset(lua_State* L) {
|
||||
ShaderBlock* block = luax_checktype(L, 1, ShaderBlock);
|
||||
const char* name = luaL_checkstring(L, 2);
|
||||
const Uniform* uniform = lovrShaderBlockGetUniform(block, name);
|
||||
lovrAssert(uniform, "Unknown uniform for ShaderBlock '%s'", name);
|
||||
lua_pushinteger(L, uniform->offset);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrShaderBlockSend(lua_State* L) {
|
||||
ShaderBlock* block = luax_checktype(L, 1, ShaderBlock);
|
||||
Buffer* buffer = lovrShaderBlockGetBuffer(block);
|
||||
if (lua_type(L, 2) == LUA_TSTRING) {
|
||||
const char* name = luaL_checkstring(L, 2);
|
||||
const Uniform* uniform = lovrShaderBlockGetUniform(block, name);
|
||||
lovrAssert(uniform, "Unknown uniform for ShaderBlock '%s'", name);
|
||||
uint8_t* data = lovrBufferMap(buffer, uniform->offset, false);
|
||||
luax_checkuniform(L, 3, uniform, data, name);
|
||||
lovrBufferFlush(buffer, uniform->offset, uniform->size);
|
||||
return 0;
|
||||
} else {
|
||||
Blob* blob = luax_checktype(L, 2, Blob);
|
||||
size_t srcOffset = luaL_optinteger(L, 3, 0);
|
||||
size_t dstOffset = luaL_optinteger(L, 4, 0);
|
||||
size_t bufferSize = lovrBufferGetSize(buffer);
|
||||
// TODO make/use shared helper to check srcOffset/dstOffset/size are non-negative to make these errors better
|
||||
lovrAssert(srcOffset <= blob->size, "Source offset is bigger than the Blob size (%d > %d)", srcOffset, blob->size);
|
||||
lovrAssert(dstOffset <= bufferSize, "Destination offset is bigger than the ShaderBlock size (%d > %d)", dstOffset, bufferSize);
|
||||
size_t maxSize = MIN(blob->size - srcOffset, bufferSize - dstOffset);
|
||||
size_t size = luaL_optinteger(L, 5, maxSize);
|
||||
lovrAssert(size <= blob->size - srcOffset, "Source offset plus copy size exceeds Blob size (%d > %d)", srcOffset + size, blob->size);
|
||||
lovrAssert(size <= bufferSize - dstOffset, "Destination offset plus copy size exceeds ShaderBlock size (%d > %d)", dstOffset + size, bufferSize);
|
||||
|
||||
char* dst = lovrBufferMap(buffer, dstOffset, false);
|
||||
char* src = (char*) blob->data + srcOffset;
|
||||
memcpy(dst, src, size);
|
||||
lovrBufferFlush(buffer, dstOffset, size);
|
||||
lua_pushinteger(L, size);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int l_lovrShaderBlockRead(lua_State* L) {
|
||||
ShaderBlock* block = luax_checktype(L, 1, ShaderBlock);
|
||||
const char* name = luaL_checkstring(L, 2);
|
||||
const Uniform* uniform = lovrShaderBlockGetUniform(block, name);
|
||||
lovrAssert(uniform, "Unknown uniform for ShaderBlock '%s'", name);
|
||||
Buffer* buffer = lovrShaderBlockGetBuffer(block);
|
||||
lovrAssert(lovrBufferIsReadable(buffer), "ShaderBlock:read requires the ShaderBlock to be created with the readable flag");
|
||||
union { float* floats; int* ints; } data = { .floats = lovrBufferMap(buffer, uniform->offset, false) };
|
||||
int components = uniform->components;
|
||||
|
||||
if (uniform->type == UNIFORM_MATRIX) {
|
||||
components *= components;
|
||||
}
|
||||
|
||||
lua_createtable(L, uniform->count, 0);
|
||||
for (int i = 0; i < uniform->count; i++) {
|
||||
if (components == 1) {
|
||||
switch (uniform->type) {
|
||||
case UNIFORM_FLOAT:
|
||||
lua_pushnumber(L, data.floats[i]);
|
||||
lua_rawseti(L, -2, i + 1);
|
||||
break;
|
||||
case UNIFORM_INT:
|
||||
lua_pushinteger(L, data.ints[i]);
|
||||
lua_rawseti(L, -2, i + 1);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
} else {
|
||||
lua_createtable(L, components, 0);
|
||||
for (int j = 0; j < components; j++) {
|
||||
switch (uniform->type) {
|
||||
case UNIFORM_FLOAT:
|
||||
case UNIFORM_MATRIX:
|
||||
lua_pushnumber(L, data.floats[i * components + j]);
|
||||
lua_rawseti(L, -2, j + 1);
|
||||
break;
|
||||
case UNIFORM_INT:
|
||||
lua_pushinteger(L, data.ints[i * components + j]);
|
||||
lua_rawseti(L, -2, j + 1);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
lua_rawseti(L, -2, i + 1);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrShaderBlockGetShaderCode(lua_State* L) {
|
||||
ShaderBlock* block = luax_checktype(L, 1, ShaderBlock);
|
||||
const char* blockName = luaL_checkstring(L, 2);
|
||||
const char* namespace = luaL_optstring(L, 3, NULL);
|
||||
size_t length;
|
||||
char* code = lovrShaderBlockGetShaderCode(block, blockName, namespace, &length);
|
||||
lua_pushlstring(L, code, length);
|
||||
free(code);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const luaL_Reg lovrShaderBlock[] = {
|
||||
{ "getType", l_lovrShaderBlockGetType },
|
||||
{ "getSize", l_lovrShaderBlockGetSize },
|
||||
{ "getOffset", l_lovrShaderBlockGetOffset },
|
||||
{ "read", l_lovrShaderBlockRead },
|
||||
{ "send", l_lovrShaderBlockSend },
|
||||
{ "getShaderCode", l_lovrShaderBlockGetShaderCode },
|
||||
{ NULL, NULL }
|
||||
};
|
|
@ -1,139 +0,0 @@
|
|||
#include "api.h"
|
||||
#include "graphics/texture.h"
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
|
||||
int luax_optmipmap(lua_State* L, int index, Texture* texture) {
|
||||
uint32_t mipmap = luaL_optinteger(L, index, 1);
|
||||
lovrAssert(mipmap <= lovrTextureGetMipmapCount(texture), "Invalid mipmap %d", mipmap);
|
||||
return mipmap - 1;
|
||||
}
|
||||
|
||||
static int l_lovrTextureGetCompareMode(lua_State* L) {
|
||||
Texture* texture = luax_checktype(L, 1, Texture);
|
||||
luax_pushenum(L, CompareMode, lovrTextureGetCompareMode(texture));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrTextureGetDepth(lua_State* L) {
|
||||
Texture* texture = luax_checktype(L, 1, Texture);
|
||||
lua_pushnumber(L, lovrTextureGetDepth(texture, luax_optmipmap(L, 2, texture)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrTextureGetDimensions(lua_State* L) {
|
||||
Texture* texture = luax_checktype(L, 1, Texture);
|
||||
int mipmap = luax_optmipmap(L, 2, texture);
|
||||
lua_pushinteger(L, lovrTextureGetWidth(texture, mipmap));
|
||||
lua_pushinteger(L, lovrTextureGetHeight(texture, mipmap));
|
||||
if (lovrTextureGetType(texture) != TEXTURE_2D) {
|
||||
lua_pushinteger(L, lovrTextureGetDepth(texture, mipmap));
|
||||
return 3;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int l_lovrTextureGetFilter(lua_State* L) {
|
||||
Texture* texture = luax_checktype(L, 1, Texture);
|
||||
TextureFilter filter = lovrTextureGetFilter(texture);
|
||||
luax_pushenum(L, FilterMode, filter.mode);
|
||||
lua_pushnumber(L, filter.anisotropy);
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int l_lovrTextureGetFormat(lua_State* L) {
|
||||
Texture* texture = luax_checktype(L, 1, Texture);
|
||||
luax_pushenum(L, TextureFormat, lovrTextureGetFormat(texture));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrTextureGetHeight(lua_State* L) {
|
||||
Texture* texture = luax_checktype(L, 1, Texture);
|
||||
lua_pushnumber(L, lovrTextureGetHeight(texture, luax_optmipmap(L, 2, texture)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrTextureGetMipmapCount(lua_State* L) {
|
||||
Texture* texture = luax_checktype(L, 1, Texture);
|
||||
lua_pushinteger(L, lovrTextureGetMipmapCount(texture));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrTextureGetType(lua_State* L) {
|
||||
Texture* texture = luax_checktype(L, 1, Texture);
|
||||
luax_pushenum(L, TextureType, lovrTextureGetType(texture));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrTextureGetWidth(lua_State* L) {
|
||||
Texture* texture = luax_checktype(L, 1, Texture);
|
||||
lua_pushnumber(L, lovrTextureGetWidth(texture, luax_optmipmap(L, 2, texture)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrTextureGetWrap(lua_State* L) {
|
||||
Texture* texture = luax_checktype(L, 1, Texture);
|
||||
TextureWrap wrap = lovrTextureGetWrap(texture);
|
||||
luax_pushenum(L, WrapMode, wrap.s);
|
||||
luax_pushenum(L, WrapMode, wrap.t);
|
||||
if (lovrTextureGetType(texture) == TEXTURE_CUBE) {
|
||||
luax_pushenum(L, WrapMode, wrap.r);
|
||||
return 3;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int l_lovrTextureReplacePixels(lua_State* L) {
|
||||
Texture* texture = luax_checktype(L, 1, Texture);
|
||||
Image* image = luax_checktype(L, 2, Image);
|
||||
int x = luaL_optinteger(L, 3, 0);
|
||||
int y = luaL_optinteger(L, 4, 0);
|
||||
int slice = luaL_optinteger(L, 5, 1) - 1;
|
||||
int mipmap = luaL_optinteger(L, 6, 1) - 1;
|
||||
lovrTextureReplacePixels(texture, image, x, y, slice, mipmap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrTextureSetCompareMode(lua_State* L) {
|
||||
Texture* texture = luax_checktype(L, 1, Texture);
|
||||
CompareMode mode = lua_isnoneornil(L, 2) ? COMPARE_NONE : luax_checkenum(L, 2, CompareMode, NULL);
|
||||
lovrTextureSetCompareMode(texture, mode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrTextureSetFilter(lua_State* L) {
|
||||
Texture* texture = luax_checktype(L, 1, Texture);
|
||||
FilterMode mode = luax_checkenum(L, 2, FilterMode, NULL);
|
||||
float anisotropy = luax_optfloat(L, 3, 1.f);
|
||||
TextureFilter filter = { .mode = mode, .anisotropy = anisotropy };
|
||||
lovrTextureSetFilter(texture, filter);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrTextureSetWrap(lua_State* L) {
|
||||
Texture* texture = luax_checktype(L, 1, Texture);
|
||||
TextureWrap wrap;
|
||||
wrap.s = luax_checkenum(L, 2, WrapMode, NULL);
|
||||
wrap.t = luax_checkenum(L, 3, WrapMode, lua_tostring(L, 2));
|
||||
wrap.r = luax_checkenum(L, 4, WrapMode, lua_tostring(L, 2));
|
||||
lovrTextureSetWrap(texture, wrap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const luaL_Reg lovrTexture[] = {
|
||||
{ "getCompareMode", l_lovrTextureGetCompareMode },
|
||||
{ "getDepth", l_lovrTextureGetDepth },
|
||||
{ "getDimensions", l_lovrTextureGetDimensions },
|
||||
{ "getFilter", l_lovrTextureGetFilter },
|
||||
{ "getFormat", l_lovrTextureGetFormat },
|
||||
{ "getHeight", l_lovrTextureGetHeight },
|
||||
{ "getMipmapCount", l_lovrTextureGetMipmapCount },
|
||||
{ "getType", l_lovrTextureGetType },
|
||||
{ "getWidth", l_lovrTextureGetWidth },
|
||||
{ "getWrap", l_lovrTextureGetWrap },
|
||||
{ "replacePixels", l_lovrTextureReplacePixels },
|
||||
{ "setCompareMode", l_lovrTextureSetCompareMode },
|
||||
{ "setFilter", l_lovrTextureSetFilter },
|
||||
{ "setWrap", l_lovrTextureSetWrap },
|
||||
{ NULL, NULL }
|
||||
};
|
|
@ -1,9 +1,6 @@
|
|||
#include "api.h"
|
||||
#include "headset/headset.h"
|
||||
#include "data/modelData.h"
|
||||
#include "graphics/graphics.h"
|
||||
#include "graphics/model.h"
|
||||
#include "graphics/texture.h"
|
||||
#include "core/maf.h"
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
|
@ -472,26 +469,13 @@ static int l_lovrHeadsetNewModel(lua_State* L) {
|
|||
}
|
||||
|
||||
ModelData* modelData = lovrHeadsetInterface->newModelData(device, animated);
|
||||
|
||||
if (modelData) {
|
||||
Model* model = lovrModelCreate(modelData);
|
||||
luax_pushtype(L, Model, model);
|
||||
lovrRelease(modelData, lovrModelDataDestroy);
|
||||
lovrRelease(model, lovrModelDestroy);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
lua_pushnil(L); // TODO
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrHeadsetAnimate(lua_State* L) {
|
||||
Device device = luax_optdevice(L, 1);
|
||||
Model* model = luax_checktype(L, 2, Model);
|
||||
if (lovrHeadsetInterface->animate(device, model)) {
|
||||
lua_pushboolean(L, true);
|
||||
return 1;
|
||||
}
|
||||
lua_pushboolean(L, false);
|
||||
lua_pushboolean(L, false); // TODO
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -532,12 +516,7 @@ static int l_lovrHeadsetGetDeltaTime(lua_State* L) {
|
|||
}
|
||||
|
||||
static int l_lovrHeadsetGetMirrorTexture(lua_State* L) {
|
||||
if (lovrHeadsetInterface->getMirrorTexture) {
|
||||
Texture* texture = lovrHeadsetInterface->getMirrorTexture();
|
||||
luax_pushtype(L, Texture, texture);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
return 0; // TODO
|
||||
}
|
||||
|
||||
static int l_lovrHeadsetGetHands(lua_State* L) {
|
||||
|
|
1762
src/lib/glad/glad.c
1762
src/lib/glad/glad.c
File diff suppressed because it is too large
Load Diff
3189
src/lib/glad/glad.h
3189
src/lib/glad/glad.h
File diff suppressed because it is too large
Load Diff
|
@ -1,290 +0,0 @@
|
|||
#ifndef __khrplatform_h_
|
||||
#define __khrplatform_h_
|
||||
|
||||
/*
|
||||
** Copyright (c) 2008-2018 The Khronos Group Inc.
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a
|
||||
** copy of this software and/or associated documentation files (the
|
||||
** "Materials"), to deal in the Materials without restriction, including
|
||||
** without limitation the rights to use, copy, modify, merge, publish,
|
||||
** distribute, sublicense, and/or sell copies of the Materials, and to
|
||||
** permit persons to whom the Materials are furnished to do so, subject to
|
||||
** the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included
|
||||
** in all copies or substantial portions of the Materials.
|
||||
**
|
||||
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
*/
|
||||
|
||||
/* Khronos platform-specific types and definitions.
|
||||
*
|
||||
* The master copy of khrplatform.h is maintained in the Khronos EGL
|
||||
* Registry repository at https://github.com/KhronosGroup/EGL-Registry
|
||||
* The last semantic modification to khrplatform.h was at commit ID:
|
||||
* 67a3e0864c2d75ea5287b9f3d2eb74a745936692
|
||||
*
|
||||
* Adopters may modify this file to suit their platform. Adopters are
|
||||
* encouraged to submit platform specific modifications to the Khronos
|
||||
* group so that they can be included in future versions of this file.
|
||||
* Please submit changes by filing pull requests or issues on
|
||||
* the EGL Registry repository linked above.
|
||||
*
|
||||
*
|
||||
* See the Implementer's Guidelines for information about where this file
|
||||
* should be located on your system and for more details of its use:
|
||||
* http://www.khronos.org/registry/implementers_guide.pdf
|
||||
*
|
||||
* This file should be included as
|
||||
* #include <KHR/khrplatform.h>
|
||||
* by Khronos client API header files that use its types and defines.
|
||||
*
|
||||
* The types in khrplatform.h should only be used to define API-specific types.
|
||||
*
|
||||
* Types defined in khrplatform.h:
|
||||
* khronos_int8_t signed 8 bit
|
||||
* khronos_uint8_t unsigned 8 bit
|
||||
* khronos_int16_t signed 16 bit
|
||||
* khronos_uint16_t unsigned 16 bit
|
||||
* khronos_int32_t signed 32 bit
|
||||
* khronos_uint32_t unsigned 32 bit
|
||||
* khronos_int64_t signed 64 bit
|
||||
* khronos_uint64_t unsigned 64 bit
|
||||
* khronos_intptr_t signed same number of bits as a pointer
|
||||
* khronos_uintptr_t unsigned same number of bits as a pointer
|
||||
* khronos_ssize_t signed size
|
||||
* khronos_usize_t unsigned size
|
||||
* khronos_float_t signed 32 bit floating point
|
||||
* khronos_time_ns_t unsigned 64 bit time in nanoseconds
|
||||
* khronos_utime_nanoseconds_t unsigned time interval or absolute time in
|
||||
* nanoseconds
|
||||
* khronos_stime_nanoseconds_t signed time interval in nanoseconds
|
||||
* khronos_boolean_enum_t enumerated boolean type. This should
|
||||
* only be used as a base type when a client API's boolean type is
|
||||
* an enum. Client APIs which use an integer or other type for
|
||||
* booleans cannot use this as the base type for their boolean.
|
||||
*
|
||||
* Tokens defined in khrplatform.h:
|
||||
*
|
||||
* KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
|
||||
*
|
||||
* KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
|
||||
* KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
|
||||
*
|
||||
* Calling convention macros defined in this file:
|
||||
* KHRONOS_APICALL
|
||||
* KHRONOS_APIENTRY
|
||||
* KHRONOS_APIATTRIBUTES
|
||||
*
|
||||
* These may be used in function prototypes as:
|
||||
*
|
||||
* KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
|
||||
* int arg1,
|
||||
* int arg2) KHRONOS_APIATTRIBUTES;
|
||||
*/
|
||||
|
||||
#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC)
|
||||
# define KHRONOS_STATIC 1
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Definition of KHRONOS_APICALL
|
||||
*-------------------------------------------------------------------------
|
||||
* This precedes the return type of the function in the function prototype.
|
||||
*/
|
||||
#if defined(KHRONOS_STATIC)
|
||||
/* If the preprocessor constant KHRONOS_STATIC is defined, make the
|
||||
* header compatible with static linking. */
|
||||
# define KHRONOS_APICALL
|
||||
#elif defined(_WIN32)
|
||||
# define KHRONOS_APICALL __declspec(dllimport)
|
||||
#elif defined (__SYMBIAN32__)
|
||||
# define KHRONOS_APICALL IMPORT_C
|
||||
#elif defined(__ANDROID__)
|
||||
# define KHRONOS_APICALL __attribute__((visibility("default")))
|
||||
#else
|
||||
# define KHRONOS_APICALL
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Definition of KHRONOS_APIENTRY
|
||||
*-------------------------------------------------------------------------
|
||||
* This follows the return type of the function and precedes the function
|
||||
* name in the function prototype.
|
||||
*/
|
||||
#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
|
||||
/* Win32 but not WinCE */
|
||||
# define KHRONOS_APIENTRY __stdcall
|
||||
#else
|
||||
# define KHRONOS_APIENTRY
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Definition of KHRONOS_APIATTRIBUTES
|
||||
*-------------------------------------------------------------------------
|
||||
* This follows the closing parenthesis of the function prototype arguments.
|
||||
*/
|
||||
#if defined (__ARMCC_2__)
|
||||
#define KHRONOS_APIATTRIBUTES __softfp
|
||||
#else
|
||||
#define KHRONOS_APIATTRIBUTES
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* basic type definitions
|
||||
*-----------------------------------------------------------------------*/
|
||||
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
|
||||
|
||||
|
||||
/*
|
||||
* Using <stdint.h>
|
||||
*/
|
||||
#include <stdint.h>
|
||||
typedef int32_t khronos_int32_t;
|
||||
typedef uint32_t khronos_uint32_t;
|
||||
typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif defined(__VMS ) || defined(__sgi)
|
||||
|
||||
/*
|
||||
* Using <inttypes.h>
|
||||
*/
|
||||
#include <inttypes.h>
|
||||
typedef int32_t khronos_int32_t;
|
||||
typedef uint32_t khronos_uint32_t;
|
||||
typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
|
||||
|
||||
/*
|
||||
* Win32
|
||||
*/
|
||||
typedef __int32 khronos_int32_t;
|
||||
typedef unsigned __int32 khronos_uint32_t;
|
||||
typedef __int64 khronos_int64_t;
|
||||
typedef unsigned __int64 khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif defined(__sun__) || defined(__digital__)
|
||||
|
||||
/*
|
||||
* Sun or Digital
|
||||
*/
|
||||
typedef int khronos_int32_t;
|
||||
typedef unsigned int khronos_uint32_t;
|
||||
#if defined(__arch64__) || defined(_LP64)
|
||||
typedef long int khronos_int64_t;
|
||||
typedef unsigned long int khronos_uint64_t;
|
||||
#else
|
||||
typedef long long int khronos_int64_t;
|
||||
typedef unsigned long long int khronos_uint64_t;
|
||||
#endif /* __arch64__ */
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif 0
|
||||
|
||||
/*
|
||||
* Hypothetical platform with no float or int64 support
|
||||
*/
|
||||
typedef int khronos_int32_t;
|
||||
typedef unsigned int khronos_uint32_t;
|
||||
#define KHRONOS_SUPPORT_INT64 0
|
||||
#define KHRONOS_SUPPORT_FLOAT 0
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* Generic fallback
|
||||
*/
|
||||
#include <stdint.h>
|
||||
typedef int32_t khronos_int32_t;
|
||||
typedef uint32_t khronos_uint32_t;
|
||||
typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Types that are (so far) the same on all platforms
|
||||
*/
|
||||
typedef signed char khronos_int8_t;
|
||||
typedef unsigned char khronos_uint8_t;
|
||||
typedef signed short int khronos_int16_t;
|
||||
typedef unsigned short int khronos_uint16_t;
|
||||
|
||||
/*
|
||||
* Types that differ between LLP64 and LP64 architectures - in LLP64,
|
||||
* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
|
||||
* to be the only LLP64 architecture in current use.
|
||||
*/
|
||||
#ifdef _WIN64
|
||||
typedef signed long long int khronos_intptr_t;
|
||||
typedef unsigned long long int khronos_uintptr_t;
|
||||
typedef signed long long int khronos_ssize_t;
|
||||
typedef unsigned long long int khronos_usize_t;
|
||||
#else
|
||||
typedef signed long int khronos_intptr_t;
|
||||
typedef unsigned long int khronos_uintptr_t;
|
||||
typedef signed long int khronos_ssize_t;
|
||||
typedef unsigned long int khronos_usize_t;
|
||||
#endif
|
||||
|
||||
#if KHRONOS_SUPPORT_FLOAT
|
||||
/*
|
||||
* Float type
|
||||
*/
|
||||
typedef float khronos_float_t;
|
||||
#endif
|
||||
|
||||
#if KHRONOS_SUPPORT_INT64
|
||||
/* Time types
|
||||
*
|
||||
* These types can be used to represent a time interval in nanoseconds or
|
||||
* an absolute Unadjusted System Time. Unadjusted System Time is the number
|
||||
* of nanoseconds since some arbitrary system event (e.g. since the last
|
||||
* time the system booted). The Unadjusted System Time is an unsigned
|
||||
* 64 bit value that wraps back to 0 every 584 years. Time intervals
|
||||
* may be either signed or unsigned.
|
||||
*/
|
||||
typedef khronos_uint64_t khronos_utime_nanoseconds_t;
|
||||
typedef khronos_int64_t khronos_stime_nanoseconds_t;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Dummy value used to pad enum types to 32 bits.
|
||||
*/
|
||||
#ifndef KHRONOS_MAX_ENUM
|
||||
#define KHRONOS_MAX_ENUM 0x7FFFFFFF
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Enumerated boolean type
|
||||
*
|
||||
* Values other than zero should be considered to be true. Therefore
|
||||
* comparisons should not be made against KHRONOS_TRUE.
|
||||
*/
|
||||
typedef enum {
|
||||
KHRONOS_FALSE = 0,
|
||||
KHRONOS_TRUE = 1,
|
||||
KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
|
||||
} khronos_boolean_enum_t;
|
||||
|
||||
#endif /* __khrplatform_h_ */
|
|
@ -1,30 +0,0 @@
|
|||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef enum {
|
||||
BUFFER_VERTEX,
|
||||
BUFFER_INDEX,
|
||||
BUFFER_UNIFORM,
|
||||
BUFFER_SHADER_STORAGE,
|
||||
BUFFER_GENERIC,
|
||||
MAX_BUFFER_TYPES
|
||||
} BufferType;
|
||||
|
||||
typedef enum {
|
||||
USAGE_STATIC,
|
||||
USAGE_DYNAMIC,
|
||||
USAGE_STREAM
|
||||
} BufferUsage;
|
||||
|
||||
typedef struct Buffer Buffer;
|
||||
Buffer* lovrBufferCreate(size_t size, void* data, BufferType type, BufferUsage usage, bool readable);
|
||||
void lovrBufferDestroy(void* ref);
|
||||
size_t lovrBufferGetSize(Buffer* buffer);
|
||||
bool lovrBufferIsReadable(Buffer* buffer);
|
||||
BufferUsage lovrBufferGetUsage(Buffer* buffer);
|
||||
void* lovrBufferMap(Buffer* buffer, size_t offset, bool unsynchronized);
|
||||
void lovrBufferFlush(Buffer* buffer, size_t offset, size_t size);
|
||||
void lovrBufferUnmap(Buffer* buffer);
|
||||
void lovrBufferDiscard(Buffer* buffer);
|
|
@ -1,42 +0,0 @@
|
|||
#include "data/image.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
#define MAX_CANVAS_ATTACHMENTS 4
|
||||
|
||||
struct Image;
|
||||
struct Texture;
|
||||
|
||||
typedef struct Attachment {
|
||||
struct Texture* texture;
|
||||
uint32_t slice;
|
||||
uint32_t level;
|
||||
} Attachment;
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
bool enabled;
|
||||
bool readable;
|
||||
TextureFormat format;
|
||||
} depth;
|
||||
uint32_t msaa;
|
||||
bool stereo;
|
||||
bool mipmaps;
|
||||
} CanvasFlags;
|
||||
|
||||
typedef struct Canvas Canvas;
|
||||
Canvas* lovrCanvasCreate(uint32_t width, uint32_t height, CanvasFlags flags);
|
||||
Canvas* lovrCanvasCreateFromHandle(uint32_t width, uint32_t height, CanvasFlags flags, uint32_t framebuffer, uint32_t depthBuffer, uint32_t resolveBuffer, uint32_t attachmentCount, bool immortal);
|
||||
void lovrCanvasDestroy(void* ref);
|
||||
const Attachment* lovrCanvasGetAttachments(Canvas* canvas, uint32_t* count);
|
||||
void lovrCanvasSetAttachments(Canvas* canvas, Attachment* attachments, uint32_t count);
|
||||
void lovrCanvasResolve(Canvas* canvas);
|
||||
bool lovrCanvasIsStereo(Canvas* canvas);
|
||||
void lovrCanvasSetStereo(Canvas* canvas, bool stereo);
|
||||
uint32_t lovrCanvasGetWidth(Canvas* canvas);
|
||||
uint32_t lovrCanvasGetHeight(Canvas* canvas);
|
||||
void lovrCanvasSetWidth(Canvas* canvas, uint32_t width);
|
||||
void lovrCanvasSetHeight(Canvas* canvas, uint32_t height);
|
||||
uint32_t lovrCanvasGetMSAA(Canvas* canvas);
|
||||
struct Texture* lovrCanvasGetDepthTexture(Canvas* canvas);
|
||||
struct Image* lovrCanvasNewImage(Canvas* canvas, uint32_t index);
|
|
@ -1,380 +0,0 @@
|
|||
#include "graphics/font.h"
|
||||
#include "graphics/graphics.h"
|
||||
#include "graphics/texture.h"
|
||||
#include "data/rasterizer.h"
|
||||
#include "data/image.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct {
|
||||
uint32_t x;
|
||||
uint32_t y;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint32_t rowHeight;
|
||||
uint32_t padding;
|
||||
arr_t(Glyph) glyphs;
|
||||
map_t glyphMap;
|
||||
} FontAtlas;
|
||||
|
||||
struct Font {
|
||||
uint32_t ref;
|
||||
Rasterizer* rasterizer;
|
||||
Texture* texture;
|
||||
FontAtlas atlas;
|
||||
map_t kerning;
|
||||
double spread;
|
||||
uint32_t padding;
|
||||
float lineHeight;
|
||||
float pixelDensity;
|
||||
TextureFilter filter;
|
||||
bool flip;
|
||||
};
|
||||
|
||||
static float* lovrFontAlignLine(float* x, float* lineEnd, float width, HorizontalAlign halign) {
|
||||
while (x < lineEnd) {
|
||||
if (halign == ALIGN_CENTER) {
|
||||
*x -= width / 2.f;
|
||||
} else if (halign == ALIGN_RIGHT) {
|
||||
*x -= width;
|
||||
}
|
||||
|
||||
x += 8;
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static Glyph* lovrFontGetGlyph(Font* font, uint32_t codepoint);
|
||||
static void lovrFontAddGlyph(Font* font, Glyph* glyph);
|
||||
static void lovrFontExpandTexture(Font* font);
|
||||
static void lovrFontCreateTexture(Font* font);
|
||||
|
||||
Font* lovrFontCreate(Rasterizer* rasterizer, uint32_t padding, double spread) {
|
||||
Font* font = calloc(1, sizeof(Font));
|
||||
lovrAssert(font, "Out of memory");
|
||||
font->ref = 1;
|
||||
|
||||
lovrRetain(rasterizer);
|
||||
font->rasterizer = rasterizer;
|
||||
font->padding = padding;
|
||||
font->spread = spread;
|
||||
font->lineHeight = 1.f;
|
||||
font->pixelDensity = (float) lovrRasterizerGetHeight(rasterizer);
|
||||
font->filter = lovrGraphicsGetDefaultFilter();
|
||||
map_init(&font->kerning, 0);
|
||||
|
||||
// Atlas
|
||||
// The atlas padding affects the padding of the edges of the atlas and the space between rows.
|
||||
// It is different from the main font->padding, which is the padding on each individual glyph.
|
||||
uint32_t atlasPadding = 1;
|
||||
font->atlas.x = atlasPadding;
|
||||
font->atlas.y = atlasPadding;
|
||||
font->atlas.width = 256;
|
||||
font->atlas.height = 256;
|
||||
font->atlas.padding = atlasPadding;
|
||||
arr_init(&font->atlas.glyphs, arr_alloc);
|
||||
map_init(&font->atlas.glyphMap, 0);
|
||||
|
||||
// Set initial atlas size
|
||||
while (font->atlas.height < 4 * lovrRasterizerGetSize(rasterizer)) {
|
||||
lovrFontExpandTexture(font);
|
||||
}
|
||||
|
||||
// Create the texture
|
||||
lovrFontCreateTexture(font);
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
void lovrFontDestroy(void* ref) {
|
||||
Font* font = ref;
|
||||
lovrRelease(font->rasterizer, lovrRasterizerDestroy);
|
||||
lovrRelease(font->texture, lovrTextureDestroy);
|
||||
for (size_t i = 0; i < font->atlas.glyphs.length; i++) {
|
||||
lovrRelease(font->atlas.glyphs.data[i].data, lovrImageDestroy);
|
||||
}
|
||||
arr_free(&font->atlas.glyphs);
|
||||
map_free(&font->atlas.glyphMap);
|
||||
map_free(&font->kerning);
|
||||
free(font);
|
||||
}
|
||||
|
||||
Rasterizer* lovrFontGetRasterizer(Font* font) {
|
||||
return font->rasterizer;
|
||||
}
|
||||
|
||||
Texture* lovrFontGetTexture(Font* font) {
|
||||
return font->texture;
|
||||
}
|
||||
|
||||
TextureFilter lovrFontGetFilter(Font* font) {
|
||||
return font->filter;
|
||||
}
|
||||
|
||||
void lovrFontSetFilter(Font* font, TextureFilter filter) {
|
||||
if (font->filter.mode != filter.mode || font->filter.anisotropy != filter.anisotropy) {
|
||||
font->filter = filter;
|
||||
lovrTextureSetFilter(font->texture, filter);
|
||||
}
|
||||
}
|
||||
|
||||
void lovrFontRender(Font* font, const char* str, size_t length, float wrap, HorizontalAlign halign, float* vertices, uint16_t* indices, uint16_t baseVertex) {
|
||||
FontAtlas* atlas = &font->atlas;
|
||||
|
||||
int height = lovrRasterizerGetHeight(font->rasterizer);
|
||||
|
||||
float cx = 0.f;
|
||||
float cy = -height * .8f;
|
||||
float u = atlas->width;
|
||||
float v = atlas->height;
|
||||
float scale = 1.f / font->pixelDensity;
|
||||
|
||||
const char* start = str;
|
||||
const char* end = str + length;
|
||||
unsigned int previous = '\0';
|
||||
unsigned int codepoint;
|
||||
size_t bytes;
|
||||
|
||||
float* vertexCursor = vertices;
|
||||
uint16_t* indexCursor = indices;
|
||||
float* lineStart = vertices;
|
||||
uint16_t I = baseVertex;
|
||||
|
||||
while ((bytes = utf8_decode(str, end, &codepoint)) > 0) {
|
||||
|
||||
// Newlines
|
||||
if (codepoint == '\n' || (wrap && cx * scale > wrap && (codepoint == ' ' || previous == ' '))) {
|
||||
lineStart = lovrFontAlignLine(lineStart, vertexCursor, cx, halign);
|
||||
cx = 0.f;
|
||||
cy -= height * font->lineHeight;
|
||||
previous = '\0';
|
||||
if (codepoint == ' ' || codepoint == '\n') {
|
||||
str += bytes;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Tabs
|
||||
if (codepoint == '\t') {
|
||||
Glyph* space = lovrFontGetGlyph(font, ' ');
|
||||
cx += space->advance * 4.f;
|
||||
str += bytes;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Kerning
|
||||
cx += lovrFontGetKerning(font, previous, codepoint);
|
||||
previous = codepoint;
|
||||
|
||||
// Get glyph
|
||||
Glyph* glyph = lovrFontGetGlyph(font, codepoint);
|
||||
|
||||
// Start over if texture was repacked
|
||||
if (u != atlas->width || v != atlas->height) {
|
||||
lovrFontRender(font, start, length, wrap, halign, vertices, indices, baseVertex);
|
||||
return;
|
||||
}
|
||||
|
||||
// Triangles
|
||||
if (glyph->w > 0 && glyph->h > 0) {
|
||||
int32_t padding = font->padding;
|
||||
float x1 = cx + glyph->dx - padding;
|
||||
float y1 = cy + (glyph->dy + padding);
|
||||
float x2 = x1 + glyph->tw;
|
||||
float y2 = y1 - glyph->th;
|
||||
float s1 = glyph->x / u;
|
||||
float t1 = (glyph->y + glyph->th) / v;
|
||||
float s2 = (glyph->x + glyph->tw) / u;
|
||||
float t2 = glyph->y / v;
|
||||
|
||||
if (font->flip) {
|
||||
float tmp = y1;
|
||||
y1 = -y2; y2 = -tmp;
|
||||
tmp = t1;
|
||||
t1 = t2; t2 = tmp;
|
||||
}
|
||||
|
||||
memcpy(vertexCursor, (float[32]) {
|
||||
x1, y1, 0.f, 0.f, 0.f, 0.f, s1, t1,
|
||||
x1, y2, 0.f, 0.f, 0.f, 0.f, s1, t2,
|
||||
x2, y1, 0.f, 0.f, 0.f, 0.f, s2, t1,
|
||||
x2, y2, 0.f, 0.f, 0.f, 0.f, s2, t2
|
||||
}, 32 * sizeof(float));
|
||||
|
||||
memcpy(indexCursor, (uint16_t[6]) { I + 0, I + 1, I + 2, I + 2, I + 1, I + 3 }, 6 * sizeof(uint16_t));
|
||||
|
||||
vertexCursor += 32;
|
||||
indexCursor += 6;
|
||||
I += 4;
|
||||
}
|
||||
|
||||
// Advance cursor
|
||||
cx += glyph->advance;
|
||||
str += bytes;
|
||||
}
|
||||
|
||||
// Align the last line
|
||||
lovrFontAlignLine(lineStart, vertexCursor, cx, halign);
|
||||
}
|
||||
|
||||
void lovrFontMeasure(Font* font, const char* str, size_t length, float wrap, float* width, float* lastLineWidth, float* height, uint32_t* lineCount, uint32_t* glyphCount) {
|
||||
wrap *= font->pixelDensity;
|
||||
lovrRasterizerMeasure(font->rasterizer, str, length, wrap, width, lastLineWidth, height, lineCount, glyphCount);
|
||||
*width /= font->pixelDensity;
|
||||
*lastLineWidth /= font->pixelDensity;
|
||||
*height *= font->lineHeight * (font->flip ? -1 : 1);
|
||||
}
|
||||
|
||||
uint32_t lovrFontGetPadding(Font* font) {
|
||||
return font->padding;
|
||||
}
|
||||
|
||||
double lovrFontGetSpread(Font* font) {
|
||||
return font->spread;
|
||||
}
|
||||
|
||||
float lovrFontGetHeight(Font* font) {
|
||||
return lovrRasterizerGetHeight(font->rasterizer) / font->pixelDensity;
|
||||
}
|
||||
|
||||
float lovrFontGetAscent(Font* font) {
|
||||
return lovrRasterizerGetAscent(font->rasterizer) / font->pixelDensity;
|
||||
}
|
||||
|
||||
float lovrFontGetDescent(Font* font) {
|
||||
return lovrRasterizerGetDescent(font->rasterizer) / font->pixelDensity;
|
||||
}
|
||||
|
||||
float lovrFontGetBaseline(Font* font) {
|
||||
return lovrRasterizerGetHeight(font->rasterizer) * .8f / font->pixelDensity;
|
||||
}
|
||||
|
||||
float lovrFontGetLineHeight(Font* font) {
|
||||
return font->lineHeight;
|
||||
}
|
||||
|
||||
void lovrFontSetLineHeight(Font* font, float lineHeight) {
|
||||
font->lineHeight = lineHeight;
|
||||
}
|
||||
|
||||
bool lovrFontIsFlipEnabled(Font* font) {
|
||||
return font->flip;
|
||||
}
|
||||
|
||||
void lovrFontSetFlipEnabled(Font* font, bool flip) {
|
||||
font->flip = flip;
|
||||
}
|
||||
|
||||
int32_t lovrFontGetKerning(Font* font, uint32_t left, uint32_t right) {
|
||||
uint64_t key = ((uint64_t) left << 32) + right;
|
||||
uint64_t hash = hash64(&key, sizeof(key)); // TODO improve number hashing
|
||||
uint64_t kerning = map_get(&font->kerning, hash);
|
||||
|
||||
if (kerning == MAP_NIL) {
|
||||
kerning = lovrRasterizerGetKerning(font->rasterizer, left, right);
|
||||
map_set(&font->kerning, hash, kerning);
|
||||
}
|
||||
|
||||
return kerning;
|
||||
}
|
||||
|
||||
float lovrFontGetPixelDensity(Font* font) {
|
||||
return font->pixelDensity;
|
||||
}
|
||||
|
||||
void lovrFontSetPixelDensity(Font* font, float pixelDensity) {
|
||||
if (pixelDensity <= 0) {
|
||||
pixelDensity = lovrRasterizerGetHeight(font->rasterizer);
|
||||
}
|
||||
|
||||
font->pixelDensity = pixelDensity;
|
||||
}
|
||||
|
||||
static Glyph* lovrFontGetGlyph(Font* font, uint32_t codepoint) {
|
||||
FontAtlas* atlas = &font->atlas;
|
||||
uint64_t hash = hash64(&codepoint, sizeof(codepoint));
|
||||
uint64_t index = map_get(&atlas->glyphMap, hash);
|
||||
|
||||
// Add the glyph to the atlas if it isn't there
|
||||
if (index == MAP_NIL) {
|
||||
index = atlas->glyphs.length;
|
||||
arr_reserve(&atlas->glyphs, atlas->glyphs.length + 1);
|
||||
lovrRasterizerLoadGlyph(font->rasterizer, codepoint, font->padding, font->spread, &atlas->glyphs.data[atlas->glyphs.length++]);
|
||||
map_set(&atlas->glyphMap, hash, index);
|
||||
lovrFontAddGlyph(font, &atlas->glyphs.data[index]);
|
||||
}
|
||||
|
||||
return &atlas->glyphs.data[index];
|
||||
}
|
||||
|
||||
static void lovrFontAddGlyph(Font* font, Glyph* glyph) {
|
||||
FontAtlas* atlas = &font->atlas;
|
||||
|
||||
// Don't waste space on empty glyphs
|
||||
if (glyph->w == 0 && glyph->h == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the glyph does not fit, you must acquit (new row)
|
||||
if (atlas->x + glyph->tw > atlas->width - 2 * atlas->padding) {
|
||||
atlas->x = atlas->padding;
|
||||
atlas->y += atlas->rowHeight + atlas->padding;
|
||||
atlas->rowHeight = 0;
|
||||
}
|
||||
|
||||
// Expand the texture if needed. Expanding the texture re-adds all the glyphs, so we can return.
|
||||
if (atlas->y + glyph->th > atlas->height - 2 * atlas->padding) {
|
||||
lovrFontExpandTexture(font);
|
||||
return;
|
||||
}
|
||||
|
||||
// Keep track of glyph's position in the atlas
|
||||
glyph->x = atlas->x;
|
||||
glyph->y = atlas->y;
|
||||
|
||||
// Paste glyph into texture
|
||||
lovrTextureReplacePixels(font->texture, glyph->data, atlas->x, atlas->y, 0, 0);
|
||||
|
||||
// Advance atlas cursor
|
||||
atlas->x += glyph->tw + atlas->padding;
|
||||
atlas->rowHeight = MAX(atlas->rowHeight, glyph->th);
|
||||
}
|
||||
|
||||
static void lovrFontExpandTexture(Font* font) {
|
||||
FontAtlas* atlas = &font->atlas;
|
||||
|
||||
if (atlas->width == atlas->height) {
|
||||
atlas->width *= 2;
|
||||
} else {
|
||||
atlas->height *= 2;
|
||||
}
|
||||
|
||||
if (!font->texture) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Recreate the texture
|
||||
lovrFontCreateTexture(font);
|
||||
|
||||
// Reset the cursor
|
||||
atlas->x = atlas->padding;
|
||||
atlas->y = atlas->padding;
|
||||
atlas->rowHeight = 0;
|
||||
|
||||
// Re-pack all the glyphs
|
||||
for (size_t i = 0; i < atlas->glyphs.length; i++) {
|
||||
lovrFontAddGlyph(font, &atlas->glyphs.data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO we only need the Image here to clear the texture, but it's a big waste of memory.
|
||||
// Could look into using glClearTexImage when supported to make this more efficient.
|
||||
static void lovrFontCreateTexture(Font* font) {
|
||||
lovrRelease(font->texture, lovrTextureDestroy);
|
||||
Image* image = lovrImageCreate(font->atlas.width, font->atlas.height, NULL, 0x0, FORMAT_RGBA16F);
|
||||
font->texture = lovrTextureCreate(TEXTURE_2D, &image, 1, false, false, 0);
|
||||
lovrTextureSetFilter(font->texture, font->filter);
|
||||
lovrTextureSetWrap(font->texture, (TextureWrap) { .s = WRAP_CLAMP, .t = WRAP_CLAMP });
|
||||
lovrRelease(image, lovrImageDestroy);
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "data/modelData.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
struct Rasterizer;
|
||||
struct Texture;
|
||||
|
||||
typedef enum {
|
||||
ALIGN_LEFT,
|
||||
ALIGN_CENTER,
|
||||
ALIGN_RIGHT
|
||||
} HorizontalAlign;
|
||||
|
||||
typedef enum {
|
||||
ALIGN_TOP,
|
||||
ALIGN_MIDDLE,
|
||||
ALIGN_BOTTOM
|
||||
} VerticalAlign;
|
||||
|
||||
typedef struct Font Font;
|
||||
Font* lovrFontCreate(struct Rasterizer* rasterizer, uint32_t padding, double spread);
|
||||
void lovrFontDestroy(void* ref);
|
||||
struct Rasterizer* lovrFontGetRasterizer(Font* font);
|
||||
struct Texture* lovrFontGetTexture(Font* font);
|
||||
TextureFilter lovrFontGetFilter(Font* font);
|
||||
void lovrFontSetFilter(Font* font, TextureFilter filter);
|
||||
void lovrFontRender(Font* font, const char* str, size_t length, float wrap, HorizontalAlign halign, float* vertices, uint16_t* indices, uint16_t baseVertex);
|
||||
void lovrFontMeasure(Font* font, const char* string, size_t length, float wrap, float* width, float* lastLineWidth, float* height, uint32_t* lineCount, uint32_t* glyphCount);
|
||||
uint32_t lovrFontGetPadding(Font* font);
|
||||
double lovrFontGetSpread(Font* font);
|
||||
float lovrFontGetHeight(Font* font);
|
||||
float lovrFontGetAscent(Font* font);
|
||||
float lovrFontGetDescent(Font* font);
|
||||
float lovrFontGetBaseline(Font* font);
|
||||
float lovrFontGetLineHeight(Font* font);
|
||||
void lovrFontSetLineHeight(Font* font, float lineHeight);
|
||||
bool lovrFontIsFlipEnabled(Font* font);
|
||||
void lovrFontSetFlipEnabled(Font* font, bool flip);
|
||||
int32_t lovrFontGetKerning(Font* font, unsigned int a, unsigned int b);
|
||||
float lovrFontGetPixelDensity(Font* font);
|
||||
void lovrFontSetPixelDensity(Font* font, float pixelDensity);
|
File diff suppressed because it is too large
Load Diff
|
@ -1,243 +1,6 @@
|
|||
#include "graphics/font.h"
|
||||
#include "data/modelData.h"
|
||||
#include "core/maf.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#pragma once
|
||||
|
||||
struct Buffer;
|
||||
struct Canvas;
|
||||
struct Font;
|
||||
struct Material;
|
||||
struct Mesh;
|
||||
struct Shader;
|
||||
struct Texture;
|
||||
|
||||
typedef void (*StencilCallback)(void* userdata);
|
||||
|
||||
typedef enum {
|
||||
ARC_MODE_PIE,
|
||||
ARC_MODE_OPEN,
|
||||
ARC_MODE_CLOSED
|
||||
} ArcMode;
|
||||
|
||||
typedef enum {
|
||||
BLEND_ALPHA,
|
||||
BLEND_ADD,
|
||||
BLEND_SUBTRACT,
|
||||
BLEND_MULTIPLY,
|
||||
BLEND_LIGHTEN,
|
||||
BLEND_DARKEN,
|
||||
BLEND_SCREEN,
|
||||
BLEND_NONE
|
||||
} BlendMode;
|
||||
|
||||
typedef enum {
|
||||
BLEND_ALPHA_MULTIPLY,
|
||||
BLEND_PREMULTIPLIED
|
||||
} BlendAlphaMode;
|
||||
|
||||
typedef enum {
|
||||
COMPARE_EQUAL,
|
||||
COMPARE_NEQUAL,
|
||||
COMPARE_LESS,
|
||||
COMPARE_LEQUAL,
|
||||
COMPARE_GREATER,
|
||||
COMPARE_GEQUAL,
|
||||
COMPARE_NONE
|
||||
} CompareMode;
|
||||
|
||||
typedef enum {
|
||||
STYLE_FILL,
|
||||
STYLE_LINE
|
||||
} DrawStyle;
|
||||
|
||||
typedef enum {
|
||||
STENCIL_REPLACE,
|
||||
STENCIL_INCREMENT,
|
||||
STENCIL_DECREMENT,
|
||||
STENCIL_INCREMENT_WRAP,
|
||||
STENCIL_DECREMENT_WRAP,
|
||||
STENCIL_INVERT
|
||||
} StencilAction;
|
||||
|
||||
typedef enum {
|
||||
WINDING_CLOCKWISE,
|
||||
WINDING_COUNTERCLOCKWISE
|
||||
} Winding;
|
||||
|
||||
typedef struct {
|
||||
float lineWidth;
|
||||
unsigned alphaSampling : 1;
|
||||
unsigned blendMode : 3; // BlendMode
|
||||
unsigned blendAlphaMode : 1; // BlendAlphaMode
|
||||
unsigned colorMask : 4;
|
||||
unsigned culling : 1;
|
||||
unsigned depthTest : 3; // CompareMode
|
||||
unsigned depthWrite : 1;
|
||||
unsigned stencilValue: 8;
|
||||
unsigned stencilMode : 3; // CompareMode
|
||||
unsigned winding : 1; // Winding
|
||||
unsigned wireframe : 1;
|
||||
} Pipeline;
|
||||
|
||||
typedef struct {
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
bool fullscreen;
|
||||
bool resizable;
|
||||
bool debug;
|
||||
int vsync;
|
||||
int msaa;
|
||||
const char* title;
|
||||
struct {
|
||||
void* data;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
} icon;
|
||||
} WindowFlags;
|
||||
|
||||
// Base
|
||||
bool lovrGraphicsInit(bool debug);
|
||||
bool lovrGraphicsInit(void);
|
||||
void lovrGraphicsDestroy(void);
|
||||
void lovrGraphicsPresent(void);
|
||||
void lovrGraphicsCreateWindow(WindowFlags* flags);
|
||||
int lovrGraphicsGetWidth(void);
|
||||
int lovrGraphicsGetHeight(void);
|
||||
float lovrGraphicsGetPixelDensity(void);
|
||||
void lovrGraphicsSetBackbuffer(struct Canvas* canvas, bool stereo, bool clear);
|
||||
void lovrGraphicsGetViewMatrix(uint32_t index, float* viewMatrix);
|
||||
void lovrGraphicsSetViewMatrix(uint32_t index, float* viewMatrix);
|
||||
void lovrGraphicsGetProjection(uint32_t index, float* projection);
|
||||
void lovrGraphicsSetProjection(uint32_t index, float* projection);
|
||||
struct Buffer* lovrGraphicsGetIdentityBuffer(void);
|
||||
#define lovrGraphicsTick lovrGpuTick
|
||||
#define lovrGraphicsTock lovrGpuTock
|
||||
#define lovrGraphicsGetFeatures lovrGpuGetFeatures
|
||||
#define lovrGraphicsGetLimits lovrGpuGetLimits
|
||||
#define lovrGraphicsGetStats lovrGpuGetStats
|
||||
|
||||
// State
|
||||
void lovrGraphicsReset(void);
|
||||
bool lovrGraphicsGetAlphaSampling(void);
|
||||
void lovrGraphicsSetAlphaSampling(bool sample);
|
||||
Color lovrGraphicsGetBackgroundColor(void);
|
||||
void lovrGraphicsSetBackgroundColor(Color color);
|
||||
void lovrGraphicsGetBlendMode(BlendMode* mode, BlendAlphaMode* alphaMode);
|
||||
void lovrGraphicsSetBlendMode(BlendMode mode, BlendAlphaMode alphaMode);
|
||||
struct Canvas* lovrGraphicsGetCanvas(void);
|
||||
void lovrGraphicsSetCanvas(struct Canvas* canvas);
|
||||
Color lovrGraphicsGetColor(void);
|
||||
void lovrGraphicsSetColor(Color color);
|
||||
void lovrGraphicsGetColorMask(bool* r, bool* g, bool* b, bool* a);
|
||||
void lovrGraphicsSetColorMask(bool r, bool g, bool b, bool a);
|
||||
bool lovrGraphicsIsCullingEnabled(void);
|
||||
void lovrGraphicsSetCullingEnabled(bool culling);
|
||||
TextureFilter lovrGraphicsGetDefaultFilter(void);
|
||||
void lovrGraphicsSetDefaultFilter(TextureFilter filter);
|
||||
void lovrGraphicsGetDepthTest(CompareMode* mode, bool* write);
|
||||
void lovrGraphicsSetDepthTest(CompareMode depthTest, bool write);
|
||||
struct Font* lovrGraphicsGetFont(void);
|
||||
void lovrGraphicsSetFont(struct Font* font);
|
||||
float lovrGraphicsGetLineWidth(void);
|
||||
void lovrGraphicsSetLineWidth(float width);
|
||||
float lovrGraphicsGetPointSize(void);
|
||||
void lovrGraphicsSetPointSize(float size);
|
||||
struct Shader* lovrGraphicsGetShader(void);
|
||||
void lovrGraphicsSetShader(struct Shader* shader);
|
||||
void lovrGraphicsGetStencilTest(CompareMode* mode, int* value);
|
||||
void lovrGraphicsSetStencilTest(CompareMode mode, int value);
|
||||
Winding lovrGraphicsGetWinding(void);
|
||||
void lovrGraphicsSetWinding(Winding winding);
|
||||
bool lovrGraphicsIsWireframe(void);
|
||||
void lovrGraphicsSetWireframe(bool wireframe);
|
||||
|
||||
// Transforms
|
||||
void lovrGraphicsPush(void);
|
||||
void lovrGraphicsPop(void);
|
||||
void lovrGraphicsOrigin(void);
|
||||
void lovrGraphicsTranslate(vec3 translation);
|
||||
void lovrGraphicsRotate(quat rotation);
|
||||
void lovrGraphicsScale(vec3 scale);
|
||||
void lovrGraphicsMatrixTransform(mat4 transform);
|
||||
|
||||
// Rendering
|
||||
void lovrGraphicsFlush(void);
|
||||
void lovrGraphicsFlushCanvas(struct Canvas* canvas);
|
||||
void lovrGraphicsFlushShader(struct Shader* shader);
|
||||
void lovrGraphicsFlushMaterial(struct Material* material);
|
||||
void lovrGraphicsFlushMesh(struct Mesh* mesh);
|
||||
void lovrGraphicsClear(Color* color, float* depth, int* stencil);
|
||||
void lovrGraphicsDiscard(bool color, bool depth, bool stencil);
|
||||
void lovrGraphicsPoints(uint32_t count, float** vertices);
|
||||
void lovrGraphicsLine(uint32_t count, float** vertices);
|
||||
void lovrGraphicsPlane(DrawStyle style, struct Material* material, mat4 transform, float u, float v, float w, float h);
|
||||
void lovrGraphicsBox(DrawStyle style, struct Material* material, mat4 transform);
|
||||
void lovrGraphicsArc(DrawStyle style, ArcMode mode, struct Material* material, mat4 transform, float r1, float r2, int segments);
|
||||
void lovrGraphicsCircle(DrawStyle style, struct Material* material, mat4 transform, int segments);
|
||||
void lovrGraphicsCylinder(struct Material* material, mat4 transform, float r1, float r2, bool capped, int segments);
|
||||
void lovrGraphicsSphere(struct Material* material, mat4 transform, int segments);
|
||||
void lovrGraphicsSkybox(struct Texture* texture);
|
||||
void lovrGraphicsPrint(const char* str, size_t length, mat4 transform, float wrap, HorizontalAlign halign, VerticalAlign valign);
|
||||
void lovrGraphicsFill(struct Texture* texture, float u, float v, float w, float h);
|
||||
void lovrGraphicsDrawMesh(struct Mesh* mesh, mat4 transform, uint32_t instances, float* pose);
|
||||
#define lovrGraphicsStencil lovrGpuStencil
|
||||
#define lovrGraphicsCompute lovrGpuCompute
|
||||
|
||||
// GPU
|
||||
|
||||
typedef struct {
|
||||
bool astc;
|
||||
bool compute;
|
||||
bool dxt;
|
||||
bool instancedStereo;
|
||||
bool multiview;
|
||||
bool timers;
|
||||
} GpuFeatures;
|
||||
|
||||
typedef struct {
|
||||
float pointSizes[2];
|
||||
int textureSize;
|
||||
int textureMSAA;
|
||||
float textureAnisotropy;
|
||||
int blockSize;
|
||||
int blockAlign;
|
||||
int compute[3];
|
||||
} GpuLimits;
|
||||
|
||||
typedef struct {
|
||||
uint32_t shaderSwitches;
|
||||
uint32_t renderPasses;
|
||||
uint32_t drawCalls;
|
||||
uint32_t bufferCount;
|
||||
uint32_t textureCount;
|
||||
uint64_t bufferMemory;
|
||||
uint64_t textureMemory;
|
||||
} GpuStats;
|
||||
|
||||
typedef struct {
|
||||
struct Mesh* mesh;
|
||||
struct Canvas* canvas;
|
||||
struct Shader* shader;
|
||||
Pipeline pipeline;
|
||||
DrawMode topology;
|
||||
uint32_t rangeStart;
|
||||
uint32_t rangeCount;
|
||||
uint32_t instances;
|
||||
} DrawCommand;
|
||||
|
||||
void lovrGpuInit(void (*getProcAddress(const char*))(void), bool debug);
|
||||
void lovrGpuDestroy(void);
|
||||
void lovrGpuClear(struct Canvas* canvas, Color* color, float* depth, int* stencil);
|
||||
void lovrGpuCompute(struct Shader* shader, int x, int y, int z);
|
||||
void lovrGpuDiscard(struct Canvas* canvas, bool color, bool depth, bool stencil);
|
||||
void lovrGpuDraw(DrawCommand* draw);
|
||||
void lovrGpuStencil(StencilAction action, int replaceValue, StencilCallback callback, void* userdata);
|
||||
void lovrGpuPresent(void);
|
||||
void lovrGpuDirtyTexture(void);
|
||||
void lovrGpuTick(const char* label);
|
||||
double lovrGpuTock(const char* label);
|
||||
const GpuFeatures* lovrGpuGetFeatures(void);
|
||||
const GpuLimits* lovrGpuGetLimits(void);
|
||||
const GpuStats* lovrGpuGetStats(void);
|
||||
|
|
|
@ -1,121 +0,0 @@
|
|||
#include "graphics/material.h"
|
||||
#include "graphics/graphics.h"
|
||||
#include "graphics/shader.h"
|
||||
#include "graphics/texture.h"
|
||||
#include "shaders.h"
|
||||
#include "util.h"
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
struct Material {
|
||||
uint32_t ref;
|
||||
float scalars[MAX_MATERIAL_SCALARS];
|
||||
Color colors[MAX_MATERIAL_COLORS];
|
||||
struct Texture* textures[MAX_MATERIAL_TEXTURES];
|
||||
float transform[9];
|
||||
};
|
||||
|
||||
Material* lovrMaterialCreate() {
|
||||
Material* material = calloc(1, sizeof(Material));
|
||||
lovrAssert(material, "Out of memory");
|
||||
material->ref = 1;
|
||||
|
||||
for (int i = 0; i < MAX_MATERIAL_SCALARS; i++) {
|
||||
material->scalars[i] = i == SCALAR_ALPHA_CUTOFF ? 0.f : 1.f;
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_MATERIAL_COLORS; i++) {
|
||||
if (i == COLOR_EMISSIVE) {
|
||||
material->colors[i] = (Color) { 0.f, 0.f, 0.f, 0.f };
|
||||
} else {
|
||||
material->colors[i] = (Color) { 1.f, 1.f, 1.f, 1.f };
|
||||
}
|
||||
}
|
||||
|
||||
lovrMaterialSetTransform(material, 0.f, 0.f, 1.f, 1.f, 0.f);
|
||||
return material;
|
||||
}
|
||||
|
||||
void lovrMaterialDestroy(void* ref) {
|
||||
Material* material = ref;
|
||||
lovrGraphicsFlushMaterial(material);
|
||||
for (int i = 0; i < MAX_MATERIAL_TEXTURES; i++) {
|
||||
lovrRelease(material->textures[i], lovrTextureDestroy);
|
||||
}
|
||||
free(material);
|
||||
}
|
||||
|
||||
void lovrMaterialBind(Material* material, Shader* shader) {
|
||||
for (int i = 0; i < MAX_MATERIAL_SCALARS; i++) {
|
||||
lovrShaderSetFloats(shader, lovrShaderScalarUniforms[i], &material->scalars[i], 0, 1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_MATERIAL_COLORS; i++) {
|
||||
lovrShaderSetColor(shader, lovrShaderColorUniforms[i], material->colors[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_MATERIAL_TEXTURES; i++) {
|
||||
lovrShaderSetTextures(shader, lovrShaderTextureUniforms[i], &material->textures[i], 0, 1);
|
||||
}
|
||||
|
||||
lovrShaderSetMatrices(shader, "lovrMaterialTransform", material->transform, 0, 9);
|
||||
}
|
||||
|
||||
float lovrMaterialGetScalar(Material* material, MaterialScalar scalarType) {
|
||||
return material->scalars[scalarType];
|
||||
}
|
||||
|
||||
void lovrMaterialSetScalar(Material* material, MaterialScalar scalarType, float value) {
|
||||
if (material->scalars[scalarType] != value) {
|
||||
lovrGraphicsFlushMaterial(material);
|
||||
material->scalars[scalarType] = value;
|
||||
}
|
||||
}
|
||||
|
||||
Color lovrMaterialGetColor(Material* material, MaterialColor colorType) {
|
||||
return material->colors[colorType];
|
||||
}
|
||||
|
||||
void lovrMaterialSetColor(Material* material, MaterialColor colorType, Color color) {
|
||||
if (memcmp(&material->colors[colorType], &color, 4 * sizeof(float))) {
|
||||
lovrGraphicsFlushMaterial(material);
|
||||
material->colors[colorType] = color;
|
||||
}
|
||||
}
|
||||
|
||||
Texture* lovrMaterialGetTexture(Material* material, MaterialTexture textureType) {
|
||||
return material->textures[textureType];
|
||||
}
|
||||
|
||||
void lovrMaterialSetTexture(Material* material, MaterialTexture textureType, Texture* texture) {
|
||||
if (material->textures[textureType] != texture) {
|
||||
lovrAssert(!texture || lovrTextureGetType(texture) == TEXTURE_2D, "Material textures must be 2D");
|
||||
lovrGraphicsFlushMaterial(material);
|
||||
lovrRetain(texture);
|
||||
lovrRelease(material->textures[textureType], lovrTextureDestroy);
|
||||
material->textures[textureType] = texture;
|
||||
}
|
||||
}
|
||||
|
||||
void lovrMaterialGetTransform(Material* material, float* ox, float* oy, float* sx, float* sy, float* angle) {
|
||||
*ox = material->transform[6];
|
||||
*oy = material->transform[7];
|
||||
*sx = sqrtf(material->transform[0] * material->transform[0] + material->transform[1] * material->transform[1]);
|
||||
*sy = sqrtf(material->transform[3] * material->transform[3] + material->transform[4] * material->transform[4]);
|
||||
*angle = atan2f(-material->transform[3], material->transform[0]);
|
||||
}
|
||||
|
||||
void lovrMaterialSetTransform(Material* material, float ox, float oy, float sx, float sy, float angle) {
|
||||
lovrGraphicsFlushMaterial(material);
|
||||
float c = cosf(angle);
|
||||
float s = sinf(angle);
|
||||
material->transform[0] = c * sx;
|
||||
material->transform[1] = s * sx;
|
||||
material->transform[2] = 0.f;
|
||||
material->transform[3] = -s * sy;
|
||||
material->transform[4] = c * sy;
|
||||
material->transform[5] = 0.f;
|
||||
material->transform[6] = ox;
|
||||
material->transform[7] = oy;
|
||||
material->transform[8] = 1.f;
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
#include "data/modelData.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
struct Texture;
|
||||
struct Shader;
|
||||
|
||||
typedef struct Material Material;
|
||||
Material* lovrMaterialCreate(void);
|
||||
void lovrMaterialDestroy(void* ref);
|
||||
void lovrMaterialBind(Material* material, struct Shader* shader);
|
||||
float lovrMaterialGetScalar(Material* material, MaterialScalar scalarType);
|
||||
void lovrMaterialSetScalar(Material* material, MaterialScalar scalarType, float value);
|
||||
Color lovrMaterialGetColor(Material* material, MaterialColor colorType);
|
||||
void lovrMaterialSetColor(Material* material, MaterialColor colorType, Color color);
|
||||
struct Texture* lovrMaterialGetTexture(Material* material, MaterialTexture textureType);
|
||||
void lovrMaterialSetTexture(Material* material, MaterialTexture textureType, struct Texture* texture);
|
||||
void lovrMaterialGetTransform(Material* material, float* ox, float* oy, float* sx, float* sy, float* angle);
|
||||
void lovrMaterialSetTransform(Material* material, float ox, float oy, float sx, float sy, float angle);
|
|
@ -1,45 +0,0 @@
|
|||
#include "data/modelData.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#pragma once
|
||||
|
||||
#define MAX_ATTRIBUTES 16
|
||||
#define MAX_ATTRIBUTE_NAME_LENGTH 32
|
||||
|
||||
struct Buffer;
|
||||
struct Material;
|
||||
|
||||
typedef struct {
|
||||
struct Buffer* buffer;
|
||||
uint32_t offset;
|
||||
unsigned stride : 8;
|
||||
unsigned divisor : 8;
|
||||
unsigned type : 3; // AttributeType
|
||||
unsigned components : 3;
|
||||
unsigned normalized : 1;
|
||||
unsigned disabled : 1;
|
||||
} MeshAttribute;
|
||||
|
||||
typedef struct Mesh Mesh;
|
||||
Mesh* lovrMeshCreate(DrawMode mode, struct Buffer* vertexBuffer, uint32_t vertexCount);
|
||||
void lovrMeshDestroy(void* ref);
|
||||
struct Buffer* lovrMeshGetVertexBuffer(Mesh* mesh);
|
||||
struct Buffer* lovrMeshGetIndexBuffer(Mesh* mesh);
|
||||
void lovrMeshSetIndexBuffer(Mesh* mesh, struct Buffer* buffer, uint32_t indexCount, size_t indexSize, size_t offset);
|
||||
uint32_t lovrMeshGetVertexCount(Mesh* mesh);
|
||||
uint32_t lovrMeshGetIndexCount(Mesh* mesh);
|
||||
size_t lovrMeshGetIndexSize(Mesh* mesh);
|
||||
uint32_t lovrMeshGetAttributeCount(Mesh* mesh);
|
||||
void lovrMeshAttachAttribute(Mesh* mesh, const char* name, MeshAttribute* attribute);
|
||||
void lovrMeshDetachAttribute(Mesh* mesh, const char* name);
|
||||
const MeshAttribute* lovrMeshGetAttribute(Mesh* mesh, uint32_t index);
|
||||
uint32_t lovrMeshGetAttributeIndex(Mesh* mesh, const char* name);
|
||||
const char* lovrMeshGetAttributeName(Mesh* mesh, uint32_t index);
|
||||
bool lovrMeshIsAttributeEnabled(Mesh* mesh, const char* name);
|
||||
void lovrMeshSetAttributeEnabled(Mesh* mesh, const char* name, bool enabled);
|
||||
DrawMode lovrMeshGetDrawMode(Mesh* mesh);
|
||||
void lovrMeshSetDrawMode(Mesh* mesh, DrawMode mode);
|
||||
void lovrMeshGetDrawRange(Mesh* mesh, uint32_t* start, uint32_t* count);
|
||||
void lovrMeshSetDrawRange(Mesh* mesh, uint32_t start, uint32_t count);
|
||||
struct Material* lovrMeshGetMaterial(Mesh* mesh);
|
||||
void lovrMeshSetMaterial(Mesh* mesh, struct Material* material);
|
|
@ -1,534 +0,0 @@
|
|||
#include "graphics/model.h"
|
||||
#include "graphics/buffer.h"
|
||||
#include "graphics/graphics.h"
|
||||
#include "graphics/material.h"
|
||||
#include "graphics/mesh.h"
|
||||
#include "graphics/texture.h"
|
||||
#include "core/maf.h"
|
||||
#include "shaders.h"
|
||||
#include <stdlib.h>
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
|
||||
typedef struct {
|
||||
float properties[3][4];
|
||||
} NodeTransform;
|
||||
|
||||
struct Model {
|
||||
uint32_t ref;
|
||||
struct ModelData* data;
|
||||
struct Buffer** buffers;
|
||||
struct Mesh** meshes;
|
||||
struct Texture** textures;
|
||||
struct Material** materials;
|
||||
float* vertices;
|
||||
uint32_t* indices;
|
||||
uint32_t vertexCount;
|
||||
uint32_t indexCount;
|
||||
NodeTransform* localTransforms;
|
||||
float* globalTransforms;
|
||||
bool transformsDirty;
|
||||
};
|
||||
|
||||
static void updateGlobalTransform(Model* model, uint32_t nodeIndex, mat4 parent) {
|
||||
mat4 global = model->globalTransforms + 16 * nodeIndex;
|
||||
NodeTransform* local = &model->localTransforms[nodeIndex];
|
||||
vec3 T = local->properties[PROP_TRANSLATION];
|
||||
quat R = local->properties[PROP_ROTATION];
|
||||
vec3 S = local->properties[PROP_SCALE];
|
||||
|
||||
mat4_init(global, parent);
|
||||
mat4_translate(global, T[0], T[1], T[2]);
|
||||
mat4_rotateQuat(global, R);
|
||||
mat4_scale(global, S[0], S[1], S[2]);
|
||||
|
||||
ModelNode* node = &model->data->nodes[nodeIndex];
|
||||
for (uint32_t i = 0; i < node->childCount; i++) {
|
||||
updateGlobalTransform(model, node->children[i], global);
|
||||
}
|
||||
}
|
||||
|
||||
static void renderNode(Model* model, uint32_t nodeIndex, uint32_t instances) {
|
||||
ModelNode* node = &model->data->nodes[nodeIndex];
|
||||
mat4 globalTransform = model->globalTransforms + 16 * nodeIndex;
|
||||
float poseMatrix[16 * MAX_BONES];
|
||||
float* pose = NULL;
|
||||
|
||||
if (node->skin != ~0u) {
|
||||
ModelSkin* skin = &model->data->skins[node->skin];
|
||||
pose = poseMatrix;
|
||||
|
||||
for (uint32_t j = 0; j < skin->jointCount; j++) {
|
||||
mat4 globalJointTransform = model->globalTransforms + 16 * skin->joints[j];
|
||||
mat4 inverseBindMatrix = skin->inverseBindMatrices + 16 * j;
|
||||
mat4 jointPose = pose + 16 * j;
|
||||
|
||||
mat4_set(jointPose, globalTransform);
|
||||
mat4_invert(jointPose);
|
||||
mat4_mul(jointPose, globalJointTransform);
|
||||
mat4_mul(jointPose, inverseBindMatrix);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < node->primitiveCount; i++) {
|
||||
lovrGraphicsDrawMesh(model->meshes[node->primitiveIndex + i], globalTransform, instances, pose);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < node->childCount; i++) {
|
||||
renderNode(model, node->children[i], instances);
|
||||
}
|
||||
}
|
||||
|
||||
Model* lovrModelCreate(ModelData* data) {
|
||||
Model* model = calloc(1, sizeof(Model));
|
||||
lovrAssert(model, "Out of memory");
|
||||
model->ref = 1;
|
||||
model->data = data;
|
||||
lovrRetain(data);
|
||||
|
||||
// Materials
|
||||
if (data->materialCount > 0) {
|
||||
model->materials = malloc(data->materialCount * sizeof(Material*));
|
||||
|
||||
if (data->imageCount > 0) {
|
||||
model->textures = calloc(data->imageCount, sizeof(Texture*));
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < data->materialCount; i++) {
|
||||
Material* material = lovrMaterialCreate();
|
||||
|
||||
for (uint32_t j = 0; j < MAX_MATERIAL_SCALARS; j++) {
|
||||
lovrMaterialSetScalar(material, j, data->materials[i].scalars[j]);
|
||||
}
|
||||
|
||||
for (uint32_t j = 0; j < MAX_MATERIAL_COLORS; j++) {
|
||||
lovrMaterialSetColor(material, j, data->materials[i].colors[j]);
|
||||
}
|
||||
|
||||
for (uint32_t j = 0; j < MAX_MATERIAL_TEXTURES; j++) {
|
||||
uint32_t index = data->materials[i].images[j];
|
||||
|
||||
if (index != ~0u) {
|
||||
if (!model->textures[index]) {
|
||||
Image* image = data->images[index];
|
||||
bool srgb = j == TEXTURE_DIFFUSE || j == TEXTURE_EMISSIVE;
|
||||
model->textures[index] = lovrTextureCreate(TEXTURE_2D, &image, 1, srgb, true, 0);
|
||||
lovrTextureSetFilter(model->textures[index], data->materials[i].filters[j]);
|
||||
lovrTextureSetWrap(model->textures[index], data->materials[i].wraps[j]);
|
||||
}
|
||||
|
||||
lovrMaterialSetTexture(material, j, model->textures[index]);
|
||||
}
|
||||
}
|
||||
|
||||
model->materials[i] = material;
|
||||
}
|
||||
}
|
||||
|
||||
// Geometry
|
||||
if (data->primitiveCount > 0) {
|
||||
if (data->bufferCount > 0) {
|
||||
model->buffers = calloc(data->bufferCount, sizeof(Buffer*));
|
||||
}
|
||||
|
||||
model->meshes = calloc(data->primitiveCount, sizeof(Mesh*));
|
||||
for (uint32_t i = 0; i < data->primitiveCount; i++) {
|
||||
ModelPrimitive* primitive = &data->primitives[i];
|
||||
uint32_t vertexCount = primitive->attributes[ATTR_POSITION] ? primitive->attributes[ATTR_POSITION]->count : 0;
|
||||
model->meshes[i] = lovrMeshCreate(primitive->mode, NULL, vertexCount);
|
||||
|
||||
if (primitive->material != ~0u) {
|
||||
lovrMeshSetMaterial(model->meshes[i], model->materials[primitive->material]);
|
||||
}
|
||||
|
||||
bool setDrawRange = false;
|
||||
for (uint32_t j = 0; j < MAX_DEFAULT_ATTRIBUTES; j++) {
|
||||
if (primitive->attributes[j]) {
|
||||
ModelAttribute* attribute = primitive->attributes[j];
|
||||
|
||||
if (!model->buffers[attribute->buffer]) {
|
||||
ModelBuffer* buffer = &data->buffers[attribute->buffer];
|
||||
model->buffers[attribute->buffer] = lovrBufferCreate(buffer->size, buffer->data, BUFFER_VERTEX, USAGE_STATIC, false);
|
||||
}
|
||||
|
||||
lovrMeshAttachAttribute(model->meshes[i], lovrShaderAttributeNames[j], &(MeshAttribute) {
|
||||
.buffer = model->buffers[attribute->buffer],
|
||||
.offset = attribute->offset,
|
||||
.stride = data->buffers[attribute->buffer].stride,
|
||||
.type = attribute->type,
|
||||
.components = attribute->components,
|
||||
.normalized = attribute->normalized
|
||||
});
|
||||
|
||||
if (!setDrawRange && !primitive->indices) {
|
||||
lovrMeshSetDrawRange(model->meshes[i], 0, attribute->count);
|
||||
setDrawRange = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lovrMeshAttachAttribute(model->meshes[i], "lovrDrawID", &(MeshAttribute) {
|
||||
.buffer = lovrGraphicsGetIdentityBuffer(),
|
||||
.type = U8,
|
||||
.components = 1,
|
||||
.divisor = 1
|
||||
});
|
||||
|
||||
if (primitive->indices) {
|
||||
ModelAttribute* attribute = primitive->indices;
|
||||
|
||||
if (!model->buffers[attribute->buffer]) {
|
||||
ModelBuffer* buffer = &data->buffers[attribute->buffer];
|
||||
model->buffers[attribute->buffer] = lovrBufferCreate(buffer->size, buffer->data, BUFFER_INDEX, USAGE_STATIC, false);
|
||||
}
|
||||
|
||||
size_t indexSize = attribute->type == U16 ? 2 : 4;
|
||||
lovrMeshSetIndexBuffer(model->meshes[i], model->buffers[attribute->buffer], attribute->count, indexSize, attribute->offset);
|
||||
lovrMeshSetDrawRange(model->meshes[i], 0, attribute->count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure skin bone count doesn't exceed the maximum supported limit
|
||||
for (uint32_t i = 0; i < data->skinCount; i++) {
|
||||
uint32_t jointCount = data->skins[i].jointCount;
|
||||
lovrAssert(jointCount < MAX_BONES, "ModelData skin '%d' has too many joints (%d, max is %d)", i, jointCount, MAX_BONES);
|
||||
}
|
||||
|
||||
model->localTransforms = malloc(sizeof(NodeTransform) * data->nodeCount);
|
||||
model->globalTransforms = malloc(16 * sizeof(float) * data->nodeCount);
|
||||
lovrModelResetPose(model);
|
||||
return model;
|
||||
}
|
||||
|
||||
void lovrModelDestroy(void* ref) {
|
||||
Model* model = ref;
|
||||
|
||||
if (model->buffers) {
|
||||
for (uint32_t i = 0; i < model->data->bufferCount; i++) {
|
||||
lovrRelease(model->buffers[i], lovrBufferDestroy);
|
||||
}
|
||||
free(model->buffers);
|
||||
}
|
||||
|
||||
if (model->meshes) {
|
||||
for (uint32_t i = 0; i < model->data->primitiveCount; i++) {
|
||||
lovrRelease(model->meshes[i], lovrMeshDestroy);
|
||||
}
|
||||
free(model->meshes);
|
||||
}
|
||||
|
||||
if (model->textures) {
|
||||
for (uint32_t i = 0; i < model->data->imageCount; i++) {
|
||||
lovrRelease(model->textures[i], lovrTextureDestroy);
|
||||
}
|
||||
free(model->textures);
|
||||
}
|
||||
|
||||
if (model->materials) {
|
||||
for (uint32_t i = 0; i < model->data->materialCount; i++) {
|
||||
lovrRelease(model->materials[i], lovrMaterialDestroy);
|
||||
}
|
||||
free(model->materials);
|
||||
}
|
||||
|
||||
lovrRelease(model->data, lovrModelDataDestroy);
|
||||
free(model->globalTransforms);
|
||||
free(model->localTransforms);
|
||||
free(model);
|
||||
}
|
||||
|
||||
ModelData* lovrModelGetModelData(Model* model) {
|
||||
return model->data;
|
||||
}
|
||||
|
||||
void lovrModelDraw(Model* model, mat4 transform, uint32_t instances) {
|
||||
if (model->transformsDirty) {
|
||||
updateGlobalTransform(model, model->data->rootNode, (float[]) MAT4_IDENTITY);
|
||||
model->transformsDirty = false;
|
||||
}
|
||||
|
||||
lovrGraphicsPush();
|
||||
lovrGraphicsMatrixTransform(transform);
|
||||
renderNode(model, model->data->rootNode, instances);
|
||||
lovrGraphicsPop();
|
||||
}
|
||||
|
||||
void lovrModelAnimate(Model* model, uint32_t animationIndex, float time, float alpha) {
|
||||
if (alpha <= 0.f) {
|
||||
return;
|
||||
}
|
||||
|
||||
lovrAssert(animationIndex < model->data->animationCount, "Invalid animation index '%d' (Model only has %d animations)", animationIndex, model->data->animationCount);
|
||||
ModelAnimation* animation = &model->data->animations[animationIndex];
|
||||
time = fmodf(time, animation->duration);
|
||||
|
||||
for (uint32_t i = 0; i < animation->channelCount; i++) {
|
||||
ModelAnimationChannel* channel = &animation->channels[i];
|
||||
uint32_t nodeIndex = channel->nodeIndex;
|
||||
NodeTransform* transform = &model->localTransforms[nodeIndex];
|
||||
|
||||
uint32_t keyframe = 0;
|
||||
while (keyframe < channel->keyframeCount && channel->times[keyframe] < time) {
|
||||
keyframe++;
|
||||
}
|
||||
|
||||
float property[4];
|
||||
bool rotate = channel->property == PROP_ROTATION;
|
||||
size_t n = 3 + rotate;
|
||||
float* (*lerp)(float* a, float* b, float t) = rotate ? quat_slerp : vec3_lerp;
|
||||
|
||||
if (keyframe == 0 || keyframe >= channel->keyframeCount) {
|
||||
size_t index = MIN(keyframe, channel->keyframeCount - 1);
|
||||
|
||||
// For cubic interpolation, each keyframe has 3 parts, and the actual data is in the middle (*3, +1)
|
||||
if (channel->smoothing == SMOOTH_CUBIC) {
|
||||
index = 3 * index + 1;
|
||||
}
|
||||
|
||||
memcpy(property, channel->data + index * n, n * sizeof(float));
|
||||
} else {
|
||||
float t1 = channel->times[keyframe - 1];
|
||||
float t2 = channel->times[keyframe];
|
||||
float z = (time - t1) / (t2 - t1);
|
||||
|
||||
switch (channel->smoothing) {
|
||||
case SMOOTH_STEP:
|
||||
memcpy(property, channel->data + (z >= .5f ? keyframe : keyframe - 1) * n, n * sizeof(float));
|
||||
break;
|
||||
case SMOOTH_LINEAR:
|
||||
memcpy(property, channel->data + (keyframe - 1) * n, n * sizeof(float));
|
||||
lerp(property, channel->data + keyframe * n, z);
|
||||
break;
|
||||
case SMOOTH_CUBIC: {
|
||||
size_t stride = 3 * n;
|
||||
float* p0 = channel->data + (keyframe - 1) * stride + 1 * n;
|
||||
float* m0 = channel->data + (keyframe - 1) * stride + 2 * n;
|
||||
float* p1 = channel->data + (keyframe - 0) * stride + 1 * n;
|
||||
float* m1 = channel->data + (keyframe - 0) * stride + 0 * n;
|
||||
float dt = t2 - t1;
|
||||
float z2 = z * z;
|
||||
float z3 = z2 * z;
|
||||
float a = 2.f * z3 - 3.f * z2 + 1.f;
|
||||
float b = 2.f * z3 - 3.f * z2 + 1.f;
|
||||
float c = (-2.f * z3 + 3.f * z2);
|
||||
float d = (z3 * -z2) * dt;
|
||||
for (size_t j = 0; j < n; j++) {
|
||||
property[j] = a * p0[j] + b * m0[j] + c * p1[j] + d * m1[j];
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (alpha >= 1.f) {
|
||||
memcpy(transform->properties[channel->property], property, n * sizeof(float));
|
||||
} else {
|
||||
lerp(transform->properties[channel->property], property, alpha);
|
||||
}
|
||||
}
|
||||
|
||||
model->transformsDirty = true;
|
||||
}
|
||||
|
||||
void lovrModelGetNodePose(Model* model, uint32_t nodeIndex, float position[4], float rotation[4], CoordinateSpace space) {
|
||||
lovrAssert(nodeIndex < model->data->nodeCount, "Invalid node index '%d' (Model only has %d nodes)", nodeIndex, model->data->nodeCount);
|
||||
if (space == SPACE_LOCAL) {
|
||||
vec3_init(position, model->localTransforms[nodeIndex].properties[PROP_TRANSLATION]);
|
||||
quat_init(rotation, model->localTransforms[nodeIndex].properties[PROP_ROTATION]);
|
||||
} else {
|
||||
if (model->transformsDirty) {
|
||||
updateGlobalTransform(model, model->data->rootNode, (float[]) MAT4_IDENTITY);
|
||||
model->transformsDirty = false;
|
||||
}
|
||||
|
||||
mat4_getPosition(model->globalTransforms + 16 * nodeIndex, position);
|
||||
mat4_getOrientation(model->globalTransforms + 16 * nodeIndex, rotation);
|
||||
}
|
||||
}
|
||||
|
||||
void lovrModelPose(Model* model, uint32_t nodeIndex, float position[4], float rotation[4], float alpha) {
|
||||
if (alpha <= 0.f) {
|
||||
return;
|
||||
}
|
||||
|
||||
lovrAssert(nodeIndex < model->data->nodeCount, "Invalid node index '%d' (Model only has %d node)", nodeIndex + 1, model->data->nodeCount, model->data->nodeCount == 1 ? "" : "s");
|
||||
NodeTransform* transform = &model->localTransforms[nodeIndex];
|
||||
if (alpha >= 1.f) {
|
||||
vec3_init(transform->properties[PROP_TRANSLATION], position);
|
||||
quat_init(transform->properties[PROP_ROTATION], rotation);
|
||||
} else {
|
||||
vec3_lerp(transform->properties[PROP_TRANSLATION], position, alpha);
|
||||
quat_slerp(transform->properties[PROP_ROTATION], rotation, alpha);
|
||||
}
|
||||
model->transformsDirty = true;
|
||||
}
|
||||
|
||||
void lovrModelResetPose(Model* model) {
|
||||
for (uint32_t i = 0; i < model->data->nodeCount; i++) {
|
||||
if (model->data->nodes[i].matrix) {
|
||||
mat4_getPosition(model->data->nodes[i].transform.matrix, model->localTransforms[i].properties[PROP_TRANSLATION]);
|
||||
mat4_getOrientation(model->data->nodes[i].transform.matrix, model->localTransforms[i].properties[PROP_ROTATION]);
|
||||
mat4_getScale(model->data->nodes[i].transform.matrix, model->localTransforms[i].properties[PROP_SCALE]);
|
||||
} else {
|
||||
vec3_init(model->localTransforms[i].properties[PROP_TRANSLATION], model->data->nodes[i].transform.properties.translation);
|
||||
quat_init(model->localTransforms[i].properties[PROP_ROTATION], model->data->nodes[i].transform.properties.rotation);
|
||||
vec3_init(model->localTransforms[i].properties[PROP_SCALE], model->data->nodes[i].transform.properties.scale);
|
||||
}
|
||||
}
|
||||
|
||||
model->transformsDirty = true;
|
||||
}
|
||||
|
||||
Material* lovrModelGetMaterial(Model* model, uint32_t material) {
|
||||
lovrAssert(material < model->data->materialCount, "Invalid material index '%d' (Model only has %d material%s)", material + 1, model->data->materialCount, model->data->materialCount == 1 ? "" : "s");
|
||||
return model->materials[material];
|
||||
}
|
||||
|
||||
static void applyAABB(Model* model, uint32_t nodeIndex, float aabb[6]) {
|
||||
ModelNode* node = &model->data->nodes[nodeIndex];
|
||||
|
||||
for (uint32_t i = 0; i < node->primitiveCount; i++) {
|
||||
ModelAttribute* position = model->data->primitives[node->primitiveIndex + i].attributes[ATTR_POSITION];
|
||||
if (position && position->hasMin && position->hasMax) {
|
||||
mat4 m = model->globalTransforms + 16 * nodeIndex;
|
||||
|
||||
float xa[3] = { position->min[0] * m[0], position->min[0] * m[1], position->min[0] * m[2] };
|
||||
float xb[3] = { position->max[0] * m[0], position->max[0] * m[1], position->max[0] * m[2] };
|
||||
|
||||
float ya[3] = { position->min[1] * m[4], position->min[1] * m[5], position->min[1] * m[6] };
|
||||
float yb[3] = { position->max[1] * m[4], position->max[1] * m[5], position->max[1] * m[6] };
|
||||
|
||||
float za[3] = { position->min[2] * m[8], position->min[2] * m[9], position->min[2] * m[10] };
|
||||
float zb[3] = { position->max[2] * m[8], position->max[2] * m[9], position->max[2] * m[10] };
|
||||
|
||||
float min[3] = {
|
||||
MIN(xa[0], xb[0]) + MIN(ya[0], yb[0]) + MIN(za[0], zb[0]) + m[12],
|
||||
MIN(xa[1], xb[1]) + MIN(ya[1], yb[1]) + MIN(za[1], zb[1]) + m[13],
|
||||
MIN(xa[2], xb[2]) + MIN(ya[2], yb[2]) + MIN(za[2], zb[2]) + m[14]
|
||||
};
|
||||
|
||||
float max[3] = {
|
||||
MAX(xa[0], xb[0]) + MAX(ya[0], yb[0]) + MAX(za[0], zb[0]) + m[12],
|
||||
MAX(xa[1], xb[1]) + MAX(ya[1], yb[1]) + MAX(za[1], zb[1]) + m[13],
|
||||
MAX(xa[2], xb[2]) + MAX(ya[2], yb[2]) + MAX(za[2], zb[2]) + m[14]
|
||||
};
|
||||
|
||||
aabb[0] = MIN(aabb[0], min[0]);
|
||||
aabb[1] = MAX(aabb[1], max[0]);
|
||||
aabb[2] = MIN(aabb[2], min[1]);
|
||||
aabb[3] = MAX(aabb[3], max[1]);
|
||||
aabb[4] = MIN(aabb[4], min[2]);
|
||||
aabb[5] = MAX(aabb[5], max[2]);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < node->childCount; i++) {
|
||||
applyAABB(model, node->children[i], aabb);
|
||||
}
|
||||
}
|
||||
|
||||
void lovrModelGetAABB(Model* model, float aabb[6]) {
|
||||
if (model->transformsDirty) {
|
||||
updateGlobalTransform(model, model->data->rootNode, (float[]) MAT4_IDENTITY);
|
||||
model->transformsDirty = false;
|
||||
}
|
||||
|
||||
aabb[0] = aabb[2] = aabb[4] = FLT_MAX;
|
||||
aabb[1] = aabb[3] = aabb[5] = -FLT_MAX;
|
||||
applyAABB(model, model->data->rootNode, aabb);
|
||||
}
|
||||
|
||||
static void countVertices(Model* model, uint32_t nodeIndex, uint32_t* vertexCount, uint32_t* indexCount) {
|
||||
ModelNode* node = &model->data->nodes[nodeIndex];
|
||||
|
||||
for (uint32_t i = 0; i < node->primitiveCount; i++) {
|
||||
ModelPrimitive* primitive = &model->data->primitives[node->primitiveIndex + i];
|
||||
ModelAttribute* positions = primitive->attributes[ATTR_POSITION];
|
||||
ModelAttribute* indices = primitive->indices;
|
||||
uint32_t count = positions ? positions->count : 0;
|
||||
*vertexCount += count;
|
||||
*indexCount += indices ? indices->count : count;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < node->childCount; i++) {
|
||||
countVertices(model, node->children[i], vertexCount, indexCount);
|
||||
}
|
||||
}
|
||||
|
||||
static void collectVertices(Model* model, uint32_t nodeIndex, float** vertices, uint32_t** indices, uint32_t* baseIndex) {
|
||||
ModelNode* node = &model->data->nodes[nodeIndex];
|
||||
mat4 transform = model->globalTransforms + 16 * nodeIndex;
|
||||
|
||||
for (uint32_t i = 0; i < node->primitiveCount; i++) {
|
||||
ModelPrimitive* primitive = &model->data->primitives[node->primitiveIndex + i];
|
||||
|
||||
ModelAttribute* positions = primitive->attributes[ATTR_POSITION];
|
||||
if (!positions) continue;
|
||||
|
||||
ModelBuffer* buffer = &model->data->buffers[positions->buffer];
|
||||
char* data = (char*) buffer->data + positions->offset;
|
||||
size_t stride = buffer->stride == 0 ? 3 * sizeof(float) : buffer->stride;
|
||||
|
||||
for (uint32_t j = 0; j < positions->count; j++) {
|
||||
float v[4];
|
||||
memcpy(v, data, 3 * sizeof(float));
|
||||
mat4_transform(transform, v);
|
||||
memcpy(*vertices, v, 3 * sizeof(float));
|
||||
*vertices += 3;
|
||||
data += stride;
|
||||
}
|
||||
|
||||
ModelAttribute* index = primitive->indices;
|
||||
if (index) {
|
||||
AttributeType type = index->type;
|
||||
lovrAssert(type == U16 || type == U32, "Unreachable");
|
||||
|
||||
buffer = &model->data->buffers[index->buffer];
|
||||
data = (char*) buffer->data + index->offset;
|
||||
size_t stride = buffer->stride == 0 ? (type == U16 ? 2 : 4) : buffer->stride;
|
||||
|
||||
for (uint32_t j = 0; j < index->count; j++) {
|
||||
**indices = (type == U16 ? ((uint32_t) *(uint16_t*) data) : *(uint32_t*) data) + *baseIndex;
|
||||
*indices += 1;
|
||||
data += stride;
|
||||
}
|
||||
} else {
|
||||
for (uint32_t j = 0; j < positions->count; j++) {
|
||||
**indices = j + *baseIndex;
|
||||
*indices += 1;
|
||||
}
|
||||
}
|
||||
|
||||
*baseIndex += positions->count;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < node->childCount; i++) {
|
||||
collectVertices(model, node->children[i], vertices, indices, baseIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void lovrModelGetTriangles(Model* model, float** vertices, uint32_t* vertexCount, uint32_t** indices, uint32_t* indexCount) {
|
||||
if (model->transformsDirty) {
|
||||
updateGlobalTransform(model, model->data->rootNode, (float[]) MAT4_IDENTITY);
|
||||
model->transformsDirty = false;
|
||||
}
|
||||
|
||||
if (!model->vertices) {
|
||||
countVertices(model, model->data->rootNode, &model->vertexCount, &model->indexCount);
|
||||
model->vertices = malloc(model->vertexCount * 3 * sizeof(float));
|
||||
model->indices = malloc(model->indexCount * sizeof(uint32_t));
|
||||
lovrAssert(model->vertices && model->indices, "Out of memory");
|
||||
}
|
||||
|
||||
*vertices = model->vertices;
|
||||
*indices = model->indices;
|
||||
uint32_t baseIndex = 0;
|
||||
collectVertices(model, model->data->rootNode, vertices, indices, &baseIndex);
|
||||
*vertexCount = model->vertexCount;
|
||||
*indexCount = model->indexCount;
|
||||
*vertices = model->vertices;
|
||||
*indices = model->indices;
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#pragma once
|
||||
|
||||
struct Material;
|
||||
struct ModelData;
|
||||
|
||||
typedef enum {
|
||||
SPACE_LOCAL,
|
||||
SPACE_GLOBAL
|
||||
} CoordinateSpace;
|
||||
|
||||
typedef struct Model Model;
|
||||
Model* lovrModelCreate(struct ModelData* data);
|
||||
void lovrModelDestroy(void* ref);
|
||||
struct ModelData* lovrModelGetModelData(Model* model);
|
||||
void lovrModelDraw(Model* model, float* transform, uint32_t instances);
|
||||
void lovrModelAnimate(Model* model, uint32_t animationIndex, float time, float alpha);
|
||||
void lovrModelGetNodePose(Model* model, uint32_t nodeIndex, float position[4], float rotation[4], CoordinateSpace space);
|
||||
void lovrModelPose(Model* model, uint32_t nodeIndex, float position[4], float rotation[4], float alpha);
|
||||
void lovrModelResetPose(Model* model);
|
||||
struct Material* lovrModelGetMaterial(Model* model, uint32_t material);
|
||||
void lovrModelGetAABB(Model* model, float aabb[6]);
|
||||
void lovrModelGetTriangles(Model* model, float** vertices, uint32_t* vertexCount, uint32_t** indices, uint32_t* indexCount);
|
File diff suppressed because it is too large
Load Diff
|
@ -1,135 +0,0 @@
|
|||
#include "graphics/texture.h"
|
||||
#include "util.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#pragma once
|
||||
|
||||
#define LOVR_MAX_UNIFORM_LENGTH 64
|
||||
#define LOVR_MAX_ATTRIBUTE_LENGTH 64
|
||||
|
||||
struct Buffer;
|
||||
struct Texture;
|
||||
|
||||
typedef enum {
|
||||
ACCESS_READ,
|
||||
ACCESS_WRITE,
|
||||
ACCESS_READ_WRITE
|
||||
} UniformAccess;
|
||||
|
||||
typedef enum {
|
||||
BLOCK_UNIFORM,
|
||||
BLOCK_COMPUTE
|
||||
} BlockType;
|
||||
|
||||
typedef enum {
|
||||
UNIFORM_FLOAT,
|
||||
UNIFORM_MATRIX,
|
||||
UNIFORM_INT,
|
||||
UNIFORM_SAMPLER,
|
||||
UNIFORM_IMAGE
|
||||
} UniformType;
|
||||
|
||||
typedef enum {
|
||||
SHADER_GRAPHICS,
|
||||
SHADER_COMPUTE
|
||||
} ShaderType;
|
||||
|
||||
typedef enum {
|
||||
FLAG_BOOL,
|
||||
FLAG_INT
|
||||
} ShaderFlagType;
|
||||
|
||||
typedef struct {
|
||||
uint32_t index;
|
||||
const char* name;
|
||||
ShaderFlagType type;
|
||||
union {
|
||||
bool b32;
|
||||
int32_t i32;
|
||||
} value;
|
||||
} ShaderFlag;
|
||||
|
||||
typedef enum {
|
||||
SHADER_UNLIT,
|
||||
SHADER_STANDARD,
|
||||
SHADER_CUBE,
|
||||
SHADER_PANO,
|
||||
SHADER_FONT,
|
||||
SHADER_FILL,
|
||||
MAX_DEFAULT_SHADERS
|
||||
} DefaultShader;
|
||||
|
||||
typedef struct {
|
||||
struct Texture* texture;
|
||||
int slice;
|
||||
int mipmap;
|
||||
UniformAccess access;
|
||||
} StorageImage;
|
||||
|
||||
typedef struct Uniform {
|
||||
char name[LOVR_MAX_UNIFORM_LENGTH];
|
||||
UniformType type;
|
||||
int components;
|
||||
int count;
|
||||
int location;
|
||||
int offset;
|
||||
int size;
|
||||
union {
|
||||
void* data;
|
||||
char* bytes;
|
||||
int* ints;
|
||||
float* floats;
|
||||
struct Texture** textures;
|
||||
StorageImage* images;
|
||||
} value;
|
||||
TextureType textureType;
|
||||
int baseSlot;
|
||||
bool shadow;
|
||||
bool image;
|
||||
bool dirty;
|
||||
} Uniform;
|
||||
|
||||
typedef arr_t(Uniform) arr_uniform_t;
|
||||
|
||||
typedef struct {
|
||||
arr_uniform_t uniforms;
|
||||
UniformAccess access;
|
||||
struct Buffer* source;
|
||||
size_t offset;
|
||||
size_t size;
|
||||
int slot;
|
||||
} UniformBlock;
|
||||
|
||||
typedef arr_t(UniformBlock) arr_block_t;
|
||||
|
||||
// Shader
|
||||
|
||||
typedef struct Shader Shader;
|
||||
Shader* lovrShaderCreateGraphics(const char* vertexSource, int vertexSourceLength, const char* fragmentSource, int fragmentSourceLength, ShaderFlag* flags, uint32_t flagCount, bool multiview);
|
||||
Shader* lovrShaderCreateCompute(const char* source, int length, ShaderFlag* flags, uint32_t flagCount);
|
||||
Shader* lovrShaderCreateDefault(DefaultShader type, ShaderFlag* flags, uint32_t flagCount, bool multiview);
|
||||
void lovrShaderDestroy(void* ref);
|
||||
ShaderType lovrShaderGetType(Shader* shader);
|
||||
int lovrShaderGetAttributeLocation(Shader* shader, const char* name, bool* integer);
|
||||
bool lovrShaderHasUniform(Shader* shader, const char* name);
|
||||
bool lovrShaderHasBlock(Shader* shader, const char* name);
|
||||
const Uniform* lovrShaderGetUniform(Shader* shader, const char* name);
|
||||
void lovrShaderSetFloats(Shader* shader, const char* name, float* data, int start, int count);
|
||||
void lovrShaderSetInts(Shader* shader, const char* name, int* data, int start, int count);
|
||||
void lovrShaderSetMatrices(Shader* shader, const char* name, float* data, int start, int count);
|
||||
void lovrShaderSetTextures(Shader* shader, const char* name, struct Texture** data, int start, int count);
|
||||
void lovrShaderSetImages(Shader* shader, const char* name, StorageImage* data, int start, int count);
|
||||
void lovrShaderSetColor(Shader* shader, const char* name, Color color);
|
||||
void lovrShaderSetBlock(Shader* shader, const char* name, struct Buffer* buffer, size_t offset, size_t size, UniformAccess access);
|
||||
|
||||
// ShaderBlock
|
||||
|
||||
size_t lovrShaderComputeUniformLayout(arr_uniform_t* uniforms);
|
||||
|
||||
typedef struct ShaderBlock ShaderBlock;
|
||||
ShaderBlock* lovrShaderBlockCreate(BlockType type, struct Buffer* buffer, arr_uniform_t* uniforms);
|
||||
void lovrShaderBlockDestroy(void* ref);
|
||||
BlockType lovrShaderBlockGetType(ShaderBlock* block);
|
||||
char* lovrShaderBlockGetShaderCode(ShaderBlock* block, const char* blockName, const char* namespace, size_t* length);
|
||||
const Uniform* lovrShaderBlockGetUniform(ShaderBlock* block, const char* name);
|
||||
struct Buffer* lovrShaderBlockGetBuffer(ShaderBlock* block);
|
|
@ -1,36 +0,0 @@
|
|||
#include "data/image.h"
|
||||
#include "graphics/graphics.h"
|
||||
#include "data/modelData.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#pragma once
|
||||
|
||||
struct Image;
|
||||
|
||||
typedef enum {
|
||||
TEXTURE_2D,
|
||||
TEXTURE_CUBE,
|
||||
TEXTURE_ARRAY,
|
||||
TEXTURE_VOLUME
|
||||
} TextureType;
|
||||
|
||||
typedef struct Texture Texture;
|
||||
Texture* lovrTextureCreate(TextureType type, struct Image** slices, uint32_t sliceCount, bool srgb, bool mipmaps, uint32_t msaa);
|
||||
Texture* lovrTextureCreateFromHandle(uint32_t handle, TextureType type, uint32_t depth, uint32_t msaa);
|
||||
void lovrTextureDestroy(void* ref);
|
||||
void lovrTextureAllocate(Texture* texture, uint32_t width, uint32_t height, uint32_t depth, TextureFormat format);
|
||||
void lovrTextureReplacePixels(Texture* texture, struct Image* data, uint32_t x, uint32_t y, uint32_t slice, uint32_t mipmap);
|
||||
uint64_t lovrTextureGetId(Texture* texture);
|
||||
uint32_t lovrTextureGetWidth(Texture* texture, uint32_t mipmap);
|
||||
uint32_t lovrTextureGetHeight(Texture* texture, uint32_t mipmap);
|
||||
uint32_t lovrTextureGetDepth(Texture* texture, uint32_t mipmap);
|
||||
uint32_t lovrTextureGetMipmapCount(Texture* texture);
|
||||
uint32_t lovrTextureGetMSAA(Texture* texture);
|
||||
TextureType lovrTextureGetType(Texture* texture);
|
||||
TextureFormat lovrTextureGetFormat(Texture* texture);
|
||||
CompareMode lovrTextureGetCompareMode(Texture* texture);
|
||||
void lovrTextureSetCompareMode(Texture* texture, CompareMode compareMode);
|
||||
TextureFilter lovrTextureGetFilter(Texture* texture);
|
||||
void lovrTextureSetFilter(Texture* texture, TextureFilter filter);
|
||||
TextureWrap lovrTextureGetWrap(Texture* texture);
|
||||
void lovrTextureSetWrap(Texture* texture, TextureWrap wrap);
|
|
@ -1,4 +1,5 @@
|
|||
#include "headset/headset.h"
|
||||
#include "data/modelData.h"
|
||||
#include "event/event.h"
|
||||
#include "graphics/graphics.h"
|
||||
#include "core/maf.h"
|
||||
|
@ -188,20 +189,7 @@ static bool desktop_animate(Device device, struct Model* model) {
|
|||
}
|
||||
|
||||
static void desktop_renderTo(void (*callback)(void*), void* userdata) {
|
||||
float projection[16], left, right, up, down;
|
||||
desktop_getViewAngles(0, &left, &right, &up, &down);
|
||||
mat4_fov(projection, left, right, up, down, state.clipNear, state.clipFar);
|
||||
|
||||
float viewMatrix[16];
|
||||
mat4_invert(mat4_init(viewMatrix, state.headTransform));
|
||||
|
||||
lovrGraphicsSetProjection(0, projection);
|
||||
lovrGraphicsSetProjection(1, projection);
|
||||
lovrGraphicsSetViewMatrix(0, viewMatrix);
|
||||
lovrGraphicsSetViewMatrix(1, viewMatrix);
|
||||
lovrGraphicsSetBackbuffer(NULL, true, true);
|
||||
callback(userdata);
|
||||
lovrGraphicsSetBackbuffer(NULL, false, false);
|
||||
//
|
||||
}
|
||||
|
||||
static bool desktop_isFocused(void) {
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
#include "headset/headset.h"
|
||||
#include "data/blob.h"
|
||||
#include "event/event.h"
|
||||
#include "graphics/graphics.h"
|
||||
#include "graphics/canvas.h"
|
||||
#include "graphics/model.h"
|
||||
#include "graphics/texture.h"
|
||||
#include "core/os.h"
|
||||
#include "util.h"
|
||||
#include <stdlib.h>
|
||||
|
@ -39,6 +35,8 @@ typedef XID GLXContext;
|
|||
#elif defined(LOVR_GLES)
|
||||
#define XR_USE_GRAPHICS_API_OPENGL_ES
|
||||
#define GRAPHICS_EXTENSION "XR_KHR_opengl_es_enable"
|
||||
#else
|
||||
#error "Unsupported renderer"
|
||||
#endif
|
||||
|
||||
#define XR_NO_PROTOTYPES
|
||||
|
@ -782,6 +780,8 @@ static void openxr_start(void) {
|
|||
XR_LOAD(xrGetOpenGLESGraphicsRequirementsKHR);
|
||||
xrGetOpenGLESGraphicsRequirementsKHR(state.instance, state.system, &requirements);
|
||||
// TODO validate OpenGLES versions, potentially in init
|
||||
#else
|
||||
#error "Unsupported renderer"
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && defined(LOVR_GL)
|
||||
|
@ -1681,46 +1681,16 @@ static void openxr_renderTo(void (*callback)(void*), void* userdata) {
|
|||
XR(xrWaitSwapchainImage(state.swapchain, &waitInfo));
|
||||
state.hasImage = true;
|
||||
|
||||
uint32_t count;
|
||||
XrView views[2];
|
||||
getViews(views, &count);
|
||||
|
||||
for (int eye = 0; eye < 2; eye++) {
|
||||
float viewMatrix[16];
|
||||
XrView* view = &views[eye];
|
||||
mat4_fromQuat(viewMatrix, &view->pose.orientation.x);
|
||||
memcpy(viewMatrix + 12, &view->pose.position.x, 3 * sizeof(float));
|
||||
mat4_invert(viewMatrix);
|
||||
lovrGraphicsSetViewMatrix(eye, viewMatrix);
|
||||
|
||||
float projection[16];
|
||||
XrFovf* fov = &view->fov;
|
||||
mat4_fov(projection, -fov->angleLeft, fov->angleRight, fov->angleUp, -fov->angleDown, state.clipNear, state.clipFar);
|
||||
lovrGraphicsSetProjection(eye, projection);
|
||||
}
|
||||
|
||||
lovrGraphicsSetBackbuffer(state.canvases[state.imageIndex], true, true);
|
||||
callback(userdata);
|
||||
lovrGraphicsSetBackbuffer(NULL, false, false);
|
||||
|
||||
endInfo.layerCount = 1;
|
||||
state.layerViews[0].pose = views[0].pose;
|
||||
state.layerViews[0].fov = views[0].fov;
|
||||
state.layerViews[1].pose = views[1].pose;
|
||||
state.layerViews[1].fov = views[1].fov;
|
||||
|
||||
XR(xrReleaseSwapchainImage(state.swapchain, NULL));
|
||||
state.hasImage = false;
|
||||
}
|
||||
|
||||
XR(xrEndFrame(state.session, &endInfo));
|
||||
lovrGpuDirtyTexture();
|
||||
state.waited = false;
|
||||
}
|
||||
|
||||
static Texture* openxr_getMirrorTexture(void) {
|
||||
Canvas* canvas = state.canvases[state.imageIndex];
|
||||
return canvas ? lovrCanvasGetAttachments(canvas, NULL)[0].texture : NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool openxr_isFocused(void) {
|
||||
|
|
Loading…
Reference in New Issue