rm graphics module;

This commit is contained in:
bjorn 2022-04-18 19:30:58 -07:00
parent 218134d79c
commit 37221afbc6
39 changed files with 123 additions and 15647 deletions

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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"
};

View File

@ -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[];

View File

@ -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");
}

View File

@ -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[];

View File

@ -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"),

View File

@ -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);

View File

@ -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);

File diff suppressed because it is too large Load Diff

View File

@ -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 }
};

View File

@ -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 }
};

View File

@ -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 }
};

View File

@ -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 }
};

View File

@ -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 }
};

View File

@ -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 }
};

View File

@ -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 }
};

View File

@ -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 }
};

View File

@ -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) {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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_ */

View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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) {

View File

@ -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) {