Pass camera functions;

This commit is contained in:
bjorn 2022-05-30 12:29:00 -07:00
parent 205767bc81
commit e59a75fce8
3 changed files with 243 additions and 66 deletions

View File

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

View File

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

View File

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