mirror of https://github.com/bjornbytes/lovr.git
Pass camera functions;
This commit is contained in:
parent
205767bc81
commit
e59a75fce8
|
@ -2,6 +2,7 @@
|
|||
#include "graphics/graphics.h"
|
||||
#include "data/blob.h"
|
||||
#include "data/image.h"
|
||||
#include "core/maf.h"
|
||||
#include "util.h"
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
|
@ -21,6 +22,104 @@ static int l_lovrPassPush(lua_State* L) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrPassGetViewPose(lua_State* L) {
|
||||
Pass* pass = luax_checktype(L, 1, Pass);
|
||||
uint32_t view = luaL_checkinteger(L, 2) - 1;
|
||||
if (lua_gettop(L) > 2) {
|
||||
float* matrix = luax_checkvector(L, 3, V_MAT4, NULL);
|
||||
bool invert = lua_toboolean(L, 4);
|
||||
lovrPassGetViewMatrix(pass, view, matrix);
|
||||
if (!invert) mat4_invert(matrix);
|
||||
lua_settop(L, 3);
|
||||
return 1;
|
||||
} else {
|
||||
float matrix[16], angle, ax, ay, az;
|
||||
lovrPassGetViewMatrix(pass, view, matrix);
|
||||
mat4_invert(matrix);
|
||||
mat4_getAngleAxis(matrix, &angle, &ax, &ay, &az);
|
||||
lua_pushnumber(L, matrix[12]);
|
||||
lua_pushnumber(L, matrix[13]);
|
||||
lua_pushnumber(L, matrix[14]);
|
||||
lua_pushnumber(L, angle);
|
||||
lua_pushnumber(L, ax);
|
||||
lua_pushnumber(L, ay);
|
||||
lua_pushnumber(L, az);
|
||||
return 7;
|
||||
}
|
||||
}
|
||||
|
||||
static int l_lovrPassSetViewPose(lua_State* L) {
|
||||
Pass* pass = luax_checktype(L, 1, Pass);
|
||||
uint32_t view = luaL_checkinteger(L, 2) - 1;
|
||||
VectorType type;
|
||||
float* p = luax_tovector(L, 3, &type);
|
||||
if (p && type == V_MAT4) {
|
||||
float matrix[16];
|
||||
mat4_init(matrix, p);
|
||||
bool inverted = lua_toboolean(L, 4);
|
||||
if (!inverted) mat4_invert(matrix);
|
||||
lovrPassSetViewMatrix(pass, view, matrix);
|
||||
} else {
|
||||
int index = 3;
|
||||
float position[4], orientation[4], matrix[16];
|
||||
index = luax_readvec3(L, index, position, "vec3, number, or mat4");
|
||||
index = luax_readquat(L, index, orientation, NULL);
|
||||
mat4_fromQuat(matrix, orientation);
|
||||
memcpy(matrix + 12, position, 3 * sizeof(float));
|
||||
mat4_invert(matrix);
|
||||
lovrPassSetViewMatrix(pass, view, matrix);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrPassGetProjection(lua_State* L) {
|
||||
Pass* pass = luax_checktype(L, 1, Pass);
|
||||
uint32_t view = luaL_checkinteger(L, 2) - 1;
|
||||
if (lua_gettop(L) > 2) {
|
||||
float* matrix = luax_checkvector(L, 3, V_MAT4, NULL);
|
||||
lovrPassGetProjection(pass, view, matrix);
|
||||
lua_settop(L, 3);
|
||||
return 1;
|
||||
} else {
|
||||
float matrix[16], left, right, up, down;
|
||||
lovrPassGetProjection(pass, view, matrix);
|
||||
mat4_getFov(matrix, &left, &right, &up, &down);
|
||||
lua_pushnumber(L, left);
|
||||
lua_pushnumber(L, right);
|
||||
lua_pushnumber(L, up);
|
||||
lua_pushnumber(L, down);
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
static int l_lovrPassSetProjection(lua_State* L) {
|
||||
Pass* pass = luax_checktype(L, 1, Pass);
|
||||
uint32_t view = luaL_checkinteger(L, 2) - 1;
|
||||
if (lua_type(L, 3) == LUA_TSTRING && !strcmp(lua_tostring(L, 3), "orthographic")) {
|
||||
float ortho[16];
|
||||
float width = luax_checkfloat(L, 4);
|
||||
float height = luax_checkfloat(L, 5);
|
||||
float near = luax_optfloat(L, 6, -1.f);
|
||||
float far = luax_optfloat(L, 7, 1.f);
|
||||
mat4_orthographic(ortho, 0.f, width, 0.f, height, near, far);
|
||||
lovrPassSetProjection(pass, view, ortho);
|
||||
} else if (lua_type(L, 3) == LUA_TNUMBER) {
|
||||
float left = luax_checkfloat(L, 3);
|
||||
float right = luax_checkfloat(L, 4);
|
||||
float up = luax_checkfloat(L, 5);
|
||||
float down = luax_checkfloat(L, 6);
|
||||
float clipNear = luax_optfloat(L, 7, .01f);
|
||||
float clipFar = luax_optfloat(L, 8, 100.f);
|
||||
float matrix[16];
|
||||
mat4_fov(matrix, left, right, up, down, clipNear, clipFar);
|
||||
lovrPassSetProjection(pass, view, matrix);
|
||||
} else {
|
||||
float* matrix = luax_checkvector(L, 3, V_MAT4, "mat4 or number");
|
||||
lovrPassSetProjection(pass, view, matrix);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrPassPop(lua_State* L) {
|
||||
Pass* pass = luax_checktype(L, 1, Pass);
|
||||
StackType stack = luax_checkenum(L, 2, StackType, "transform");
|
||||
|
@ -388,13 +487,21 @@ static int l_lovrPassMipmap(lua_State* L) {
|
|||
|
||||
const luaL_Reg lovrPass[] = {
|
||||
{ "getType", l_lovrPassGetType },
|
||||
|
||||
{ "getViewPose", l_lovrPassGetViewPose },
|
||||
{ "setViewPose", l_lovrPassSetViewPose },
|
||||
{ "getProjection", l_lovrPassGetProjection },
|
||||
{ "setProjection", l_lovrPassSetProjection },
|
||||
|
||||
{ "push", l_lovrPassPush },
|
||||
{ "pop", l_lovrPassPop },
|
||||
|
||||
{ "origin", l_lovrPassOrigin },
|
||||
{ "translate", l_lovrPassTranslate },
|
||||
{ "rotate", l_lovrPassRotate },
|
||||
{ "scale", l_lovrPassScale },
|
||||
{ "transform", l_lovrPassTransform },
|
||||
|
||||
{ "setAlphaToCoverage", l_lovrPassSetAlphaToCoverage },
|
||||
{ "setBlendMode", l_lovrPassSetBlendMode },
|
||||
{ "setColor", l_lovrPassSetColor },
|
||||
|
@ -409,10 +516,13 @@ const luaL_Reg lovrPass[] = {
|
|||
{ "setStencilWrite", l_lovrPassSetStencilWrite },
|
||||
{ "setWinding", l_lovrPassSetWinding },
|
||||
{ "setWireframe", l_lovrPassSetWireframe },
|
||||
|
||||
{ "send", l_lovrPassSend },
|
||||
|
||||
{ "clear", l_lovrPassClear },
|
||||
{ "copy", l_lovrPassCopy },
|
||||
{ "blit", l_lovrPassBlit },
|
||||
{ "mipmap", l_lovrPassMipmap },
|
||||
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
|
|
@ -85,6 +85,13 @@ struct Shader {
|
|||
uint32_t* flagLookup;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
float view[16];
|
||||
float projection[16];
|
||||
float viewProjection[16];
|
||||
float inverseProjection[16];
|
||||
} Camera;
|
||||
|
||||
typedef struct {
|
||||
float color[4];
|
||||
Shader* shader;
|
||||
|
@ -105,6 +112,9 @@ struct Pass {
|
|||
gpu_binding bindings[32];
|
||||
uint32_t bindingMask;
|
||||
bool bindingsDirty;
|
||||
Camera* cameras;
|
||||
uint32_t cameraCount;
|
||||
bool cameraDirty;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
|
@ -216,9 +226,9 @@ bool lovrGraphicsInit(bool debug, bool vsync) {
|
|||
arr_init(&state.layouts, realloc);
|
||||
|
||||
gpu_slot builtins[] = {
|
||||
{ 0, GPU_SLOT_UNIFORM_BUFFER_DYNAMIC, GPU_STAGE_ALL },
|
||||
{ 1, GPU_SLOT_UNIFORM_BUFFER_DYNAMIC, GPU_STAGE_ALL },
|
||||
{ 2, GPU_SLOT_SAMPLER, GPU_STAGE_ALL }
|
||||
{ 0, GPU_SLOT_UNIFORM_BUFFER, GPU_STAGE_ALL }, // Cameras
|
||||
{ 1, GPU_SLOT_UNIFORM_BUFFER, GPU_STAGE_ALL }, // Draw data
|
||||
{ 2, GPU_SLOT_SAMPLER, GPU_STAGE_ALL } // Default sampler
|
||||
};
|
||||
|
||||
state.builtinLayout = getLayout(builtins, COUNTOF(builtins));
|
||||
|
@ -1170,79 +1180,110 @@ Pass* lovrGraphicsGetPass(PassInfo* info) {
|
|||
pass->info = *info;
|
||||
pass->stream = gpu_stream_begin(info->label);
|
||||
|
||||
if (info->type == PASS_RENDER) {
|
||||
Canvas* canvas = &info->canvas;
|
||||
const TextureInfo* main = canvas->textures[0] ? &canvas->textures[0]->info : &canvas->depth.texture->info;
|
||||
lovrCheck(canvas->textures[0] || canvas->depth.texture, "Render pass must have at least one color or depth texture");
|
||||
lovrCheck(main->width <= state.limits.renderSize[0], "Render pass width (%d) exceeds the renderSize limit of this GPU (%d)", main->width, state.limits.renderSize[0]);
|
||||
lovrCheck(main->height <= state.limits.renderSize[1], "Render pass height (%d) exceeds the renderSize limit of this GPU (%d)", main->height, state.limits.renderSize[1]);
|
||||
lovrCheck(main->depth <= state.limits.renderSize[2], "Render pass view count (%d) exceeds the renderSize limit of this GPU (%d)", main->depth, state.limits.renderSize[2]);
|
||||
lovrCheck(canvas->samples == 1 || canvas->samples == 4, "Render pass sample count must be 1 or 4...for now");
|
||||
if (info->type != PASS_RENDER) {
|
||||
return pass;
|
||||
}
|
||||
|
||||
uint32_t colorTextureCount = 0;
|
||||
for (uint32_t i = 0; i < COUNTOF(canvas->textures) && canvas->textures[i]; i++, colorTextureCount++) {
|
||||
const TextureInfo* texture = &canvas->textures[i]->info;
|
||||
bool renderable = texture->format == GPU_FORMAT_SURFACE || (state.features.formats[texture->format] & GPU_FEATURE_RENDER);
|
||||
lovrCheck(renderable, "This GPU does not support rendering to the texture format used by Canvas texture #%d", i + 1);
|
||||
Canvas* canvas = &info->canvas;
|
||||
const TextureInfo* main = canvas->textures[0] ? &canvas->textures[0]->info : &canvas->depth.texture->info;
|
||||
lovrCheck(canvas->textures[0] || canvas->depth.texture, "Render pass must have at least one color or depth texture");
|
||||
lovrCheck(main->width <= state.limits.renderSize[0], "Render pass width (%d) exceeds the renderSize limit of this GPU (%d)", main->width, state.limits.renderSize[0]);
|
||||
lovrCheck(main->height <= state.limits.renderSize[1], "Render pass height (%d) exceeds the renderSize limit of this GPU (%d)", main->height, state.limits.renderSize[1]);
|
||||
lovrCheck(main->depth <= state.limits.renderSize[2], "Render pass view count (%d) exceeds the renderSize limit of this GPU (%d)", main->depth, state.limits.renderSize[2]);
|
||||
lovrCheck(canvas->samples == 1 || canvas->samples == 4, "Render pass sample count must be 1 or 4...for now");
|
||||
|
||||
uint32_t colorTextureCount = 0;
|
||||
for (uint32_t i = 0; i < COUNTOF(canvas->textures) && canvas->textures[i]; i++, colorTextureCount++) {
|
||||
const TextureInfo* texture = &canvas->textures[i]->info;
|
||||
bool renderable = texture->format == GPU_FORMAT_SURFACE || (state.features.formats[texture->format] & GPU_FEATURE_RENDER);
|
||||
lovrCheck(renderable, "This GPU does not support rendering to the texture format used by Canvas texture #%d", i + 1);
|
||||
lovrCheck(texture->usage & TEXTURE_RENDER, "Texture must be created with the 'render' flag to render to it");
|
||||
lovrCheck(texture->width == main->width, "Render pass texture sizes must match");
|
||||
lovrCheck(texture->height == main->height, "Render pass texture sizes must match");
|
||||
lovrCheck(texture->depth == main->depth, "Render pass texture sizes must match");
|
||||
lovrCheck(texture->samples == main->samples, "Render pass texture sample counts must match");
|
||||
}
|
||||
|
||||
if (canvas->depth.texture || canvas->depth.format) {
|
||||
TextureFormat format = canvas->depth.texture ? canvas->depth.texture->info.format : canvas->depth.format;
|
||||
bool renderable = state.features.formats[format] & GPU_FEATURE_RENDER;
|
||||
lovrCheck(format == FORMAT_D16 || format == FORMAT_D24S8 || format == FORMAT_D32F, "Depth buffer must use a depth format");
|
||||
lovrCheck(renderable, "This GPU does not support depth buffers with this texture format");
|
||||
if (canvas->depth.texture) {
|
||||
const TextureInfo* texture = &canvas->depth.texture->info;
|
||||
lovrCheck(texture->usage & TEXTURE_RENDER, "Texture must be created with the 'render' flag to render to it");
|
||||
lovrCheck(texture->width == main->width, "Render pass texture sizes must match");
|
||||
lovrCheck(texture->height == main->height, "Render pass texture sizes must match");
|
||||
lovrCheck(texture->depth == main->depth, "Render pass texture sizes must match");
|
||||
lovrCheck(texture->samples == main->samples, "Render pass texture sample counts must match");
|
||||
lovrCheck(texture->samples == main->samples, "Depth buffer sample count must match the main render pass sample count...for now");
|
||||
}
|
||||
|
||||
if (canvas->depth.texture || canvas->depth.format) {
|
||||
TextureFormat format = canvas->depth.texture ? canvas->depth.texture->info.format : canvas->depth.format;
|
||||
bool renderable = state.features.formats[format] & GPU_FEATURE_RENDER;
|
||||
lovrCheck(format == FORMAT_D16 || format == FORMAT_D24S8 || format == FORMAT_D32F, "Depth buffer must use a depth format");
|
||||
lovrCheck(renderable, "This GPU does not support depth buffers with this texture format");
|
||||
if (canvas->depth.texture) {
|
||||
const TextureInfo* texture = &canvas->depth.texture->info;
|
||||
lovrCheck(texture->usage & TEXTURE_RENDER, "Texture must be created with the 'render' flag to render to it");
|
||||
lovrCheck(texture->width == main->width, "Render pass texture sizes must match");
|
||||
lovrCheck(texture->height == main->height, "Render pass texture sizes must match");
|
||||
lovrCheck(texture->depth == main->depth, "Render pass texture sizes must match");
|
||||
lovrCheck(texture->samples == main->samples, "Depth buffer sample count must match the main render pass sample count...for now");
|
||||
}
|
||||
}
|
||||
|
||||
gpu_canvas target = {
|
||||
.size = { main->width, main->height }
|
||||
};
|
||||
|
||||
for (uint32_t i = 0; i < colorTextureCount; i++) {
|
||||
if (main->samples == 1 && canvas->samples > 1) {
|
||||
TextureFormat format = canvas->textures[i]->info.format;
|
||||
bool srgb = canvas->textures[i]->info.srgb;
|
||||
target.color[i].texture = getAttachment(target.size, main->depth, format, srgb, canvas->samples);
|
||||
target.color[i].resolve = canvas->textures[i]->renderView;
|
||||
} else {
|
||||
target.color[i].texture = canvas->textures[i]->renderView;
|
||||
}
|
||||
|
||||
target.color[i].load = (gpu_load_op) canvas->loads[i];
|
||||
target.color[i].save = GPU_SAVE_OP_SAVE;
|
||||
target.color[i].clear[0] = lovrMathGammaToLinear(canvas->clears[i][0]);
|
||||
target.color[i].clear[1] = lovrMathGammaToLinear(canvas->clears[i][1]);
|
||||
target.color[i].clear[2] = lovrMathGammaToLinear(canvas->clears[i][2]);
|
||||
target.color[i].clear[3] = canvas->clears[i][2];
|
||||
}
|
||||
|
||||
if (canvas->depth.texture) {
|
||||
target.depth.texture = canvas->depth.texture->renderView;
|
||||
} else {
|
||||
target.depth.texture = getAttachment(target.size, main->depth, canvas->depth.format, false, canvas->samples);
|
||||
}
|
||||
|
||||
target.depth.load = target.depth.stencilLoad = (gpu_load_op) canvas->depth.load;
|
||||
target.depth.save = canvas->depth.texture ? GPU_SAVE_OP_SAVE : GPU_SAVE_OP_DISCARD;
|
||||
target.depth.clear.depth = canvas->depth.clear;
|
||||
|
||||
gpu_render_begin(pass->stream, &target);
|
||||
}
|
||||
|
||||
gpu_canvas target = {
|
||||
.size = { main->width, main->height }
|
||||
};
|
||||
|
||||
for (uint32_t i = 0; i < colorTextureCount; i++) {
|
||||
if (main->samples == 1 && canvas->samples > 1) {
|
||||
TextureFormat format = canvas->textures[i]->info.format;
|
||||
bool srgb = canvas->textures[i]->info.srgb;
|
||||
target.color[i].texture = getAttachment(target.size, main->depth, format, srgb, canvas->samples);
|
||||
target.color[i].resolve = canvas->textures[i]->renderView;
|
||||
} else {
|
||||
target.color[i].texture = canvas->textures[i]->renderView;
|
||||
}
|
||||
|
||||
target.color[i].load = (gpu_load_op) canvas->loads[i];
|
||||
target.color[i].save = GPU_SAVE_OP_SAVE;
|
||||
target.color[i].clear[0] = lovrMathGammaToLinear(canvas->clears[i][0]);
|
||||
target.color[i].clear[1] = lovrMathGammaToLinear(canvas->clears[i][1]);
|
||||
target.color[i].clear[2] = lovrMathGammaToLinear(canvas->clears[i][2]);
|
||||
target.color[i].clear[3] = canvas->clears[i][2];
|
||||
}
|
||||
|
||||
if (canvas->depth.texture) {
|
||||
target.depth.texture = canvas->depth.texture->renderView;
|
||||
} else {
|
||||
target.depth.texture = getAttachment(target.size, main->depth, canvas->depth.format, false, canvas->samples);
|
||||
}
|
||||
|
||||
target.depth.load = target.depth.stencilLoad = (gpu_load_op) canvas->depth.load;
|
||||
target.depth.save = canvas->depth.texture ? GPU_SAVE_OP_SAVE : GPU_SAVE_OP_DISCARD;
|
||||
target.depth.clear.depth = canvas->depth.clear;
|
||||
|
||||
gpu_render_begin(pass->stream, &target);
|
||||
|
||||
float viewport[4] = { 0.f, 0.f, (float) main->width, (float) main->height };
|
||||
float depthRange[2] = { 0.f, 1.f };
|
||||
gpu_set_viewport(pass->stream, viewport, depthRange);
|
||||
|
||||
uint32_t scissor[4] = { 0, 0, main->width, main->height };
|
||||
gpu_set_scissor(pass->stream, scissor);
|
||||
|
||||
pass->transform = pass->transforms[0];
|
||||
mat4_identity(pass->transform);
|
||||
|
||||
pass->pipeline = &pass->pipelines[0];
|
||||
memset(&pass->pipeline->info, 0, sizeof(pass->pipeline->info));
|
||||
pass->pipeline->info.depth.test = GPU_COMPARE_LEQUAL;
|
||||
pass->pipeline->info.depth.write = true;
|
||||
pass->pipeline->info.color[0].mask = 0xf;
|
||||
pass->pipeline->info.color[1].mask = 0xf;
|
||||
pass->pipeline->info.color[2].mask = 0xf;
|
||||
pass->pipeline->info.color[3].mask = 0xf;
|
||||
pass->pipeline->color[0] = 1.f;
|
||||
pass->pipeline->color[1] = 1.f;
|
||||
pass->pipeline->color[2] = 1.f;
|
||||
pass->pipeline->color[3] = 1.f;
|
||||
pass->pipeline->shader = NULL;
|
||||
pass->pipeline->dirty = true;
|
||||
|
||||
pass->bindingMask = 0;
|
||||
pass->bindingsDirty = true;
|
||||
|
||||
pass->cameraCount = main->depth;
|
||||
pass->cameras = tempAlloc(pass->cameraCount * sizeof(Camera));
|
||||
pass->cameraDirty = true;
|
||||
|
||||
return pass;
|
||||
}
|
||||
|
@ -1259,6 +1300,28 @@ const PassInfo* lovrPassGetInfo(Pass* pass) {
|
|||
return &pass->info;
|
||||
}
|
||||
|
||||
void lovrPassGetViewMatrix(Pass* pass, uint32_t index, float* viewMatrix) {
|
||||
lovrCheck(index < pass->cameraCount, "Invalid camera index '%d'", index);
|
||||
mat4_init(viewMatrix, pass->cameras[index].view);
|
||||
}
|
||||
|
||||
void lovrPassSetViewMatrix(Pass* pass, uint32_t index, float* viewMatrix) {
|
||||
lovrCheck(index < pass->cameraCount, "Invalid camera index '%d'", index);
|
||||
mat4_init(pass->cameras[index].view, viewMatrix);
|
||||
pass->cameraDirty = true;
|
||||
}
|
||||
|
||||
void lovrPassGetProjection(Pass* pass, uint32_t index, float* projection) {
|
||||
lovrCheck(index < pass->cameraCount, "Invalid camera index '%d'", index);
|
||||
mat4_init(projection, pass->cameras[index].projection);
|
||||
}
|
||||
|
||||
void lovrPassSetProjection(Pass* pass, uint32_t index, float* projection) {
|
||||
lovrCheck(index < pass->cameraCount, "Invalid camera index '%d'", index);
|
||||
mat4_init(pass->cameras[index].projection, projection);
|
||||
pass->cameraDirty = true;
|
||||
}
|
||||
|
||||
void lovrPassPush(Pass* pass, StackType stack) {
|
||||
if (stack == STACK_TRANSFORM) {
|
||||
pass->transform = pass->transforms[++pass->transformIndex];
|
||||
|
|
|
@ -354,6 +354,10 @@ typedef struct {
|
|||
Pass* lovrGraphicsGetPass(PassInfo* info);
|
||||
void lovrPassDestroy(void* ref);
|
||||
const PassInfo* lovrPassGetInfo(Pass* pass);
|
||||
void lovrPassGetViewMatrix(Pass* pass, uint32_t index, float viewMatrix[16]);
|
||||
void lovrPassSetViewMatrix(Pass* pass, uint32_t index, float viewMatrix[16]);
|
||||
void lovrPassGetProjection(Pass* pass, uint32_t index, float projection[16]);
|
||||
void lovrPassSetProjection(Pass* pass, uint32_t index, float projection[16]);
|
||||
void lovrPassPush(Pass* pass, StackType stack);
|
||||
void lovrPassPop(Pass* pass, StackType stack);
|
||||
void lovrPassOrigin(Pass* pass);
|
||||
|
|
Loading…
Reference in New Issue