mirror of https://github.com/bjornbytes/lovr.git
Multiview;
This commit is contained in:
parent
a691192af9
commit
928ccee5f1
|
@ -409,8 +409,10 @@ static int l_lovrGraphicsGetFeatures(lua_State* L) {
|
|||
lua_setfield(L, -2, "compute");
|
||||
lua_pushboolean(L, features->dxt);
|
||||
lua_setfield(L, -2, "dxt");
|
||||
lua_pushboolean(L, features->singlepass);
|
||||
lua_setfield(L, -2, "singlepass");
|
||||
lua_pushboolean(L, features->instancedStereo);
|
||||
lua_setfield(L, -2, "instancedstereo");
|
||||
lua_pushboolean(L, features->multiview);
|
||||
lua_setfield(L, -2, "multiview");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -1093,16 +1095,16 @@ static int l_lovrGraphicsNewCanvas(lua_State* L) {
|
|||
index = 3;
|
||||
}
|
||||
|
||||
TextureFormat format = FORMAT_RGBA;
|
||||
bool anonymous = attachmentCount == 0;
|
||||
|
||||
CanvasFlags flags = {
|
||||
.depth = { .enabled = true, .readable = false, .format = FORMAT_D16 },
|
||||
.stereo = true,
|
||||
.stereo = anonymous,
|
||||
.msaa = 0,
|
||||
.mipmaps = true
|
||||
};
|
||||
|
||||
TextureFormat format = FORMAT_RGBA;
|
||||
bool anonymous = attachmentCount == 0;
|
||||
|
||||
if (lua_istable(L, index)) {
|
||||
lua_getfield(L, index, "depth");
|
||||
switch (lua_type(L, -1)) {
|
||||
|
@ -1142,14 +1144,6 @@ static int l_lovrGraphicsNewCanvas(lua_State* L) {
|
|||
}
|
||||
}
|
||||
|
||||
if (anonymous) {
|
||||
Texture* texture = lovrTextureCreate(TEXTURE_2D, NULL, 0, true, flags.mipmaps, flags.msaa);
|
||||
lovrTextureAllocate(texture, width, height, 1, format);
|
||||
lovrTextureSetWrap(texture, (TextureWrap) { .s = WRAP_CLAMP, .t = WRAP_CLAMP, .r = WRAP_CLAMP });
|
||||
attachments[0] = (Attachment) { texture, 0, 0 };
|
||||
attachmentCount++;
|
||||
}
|
||||
|
||||
if (width == 0 && height == 0 && attachmentCount > 0) {
|
||||
width = lovrTextureGetWidth(attachments[0].texture, attachments[0].level);
|
||||
height = lovrTextureGetHeight(attachments[0].texture, attachments[0].level);
|
||||
|
@ -1157,6 +1151,14 @@ static int l_lovrGraphicsNewCanvas(lua_State* L) {
|
|||
|
||||
Canvas* canvas = lovrCanvasCreate(width, height, flags);
|
||||
|
||||
if (anonymous) {
|
||||
Texture* texture = lovrTextureCreate(TEXTURE_2D, NULL, 0, true, flags.mipmaps, flags.msaa);
|
||||
lovrTextureAllocate(texture, lovrCanvasGetWidth(canvas), lovrCanvasGetHeight(canvas), 1, format);
|
||||
lovrTextureSetWrap(texture, (TextureWrap) { .s = WRAP_CLAMP, .t = WRAP_CLAMP, .r = WRAP_CLAMP });
|
||||
attachments[0] = (Attachment) { texture, 0, 0 };
|
||||
attachmentCount++;
|
||||
}
|
||||
|
||||
if (attachmentCount > 0) {
|
||||
lovrCanvasSetAttachments(canvas, attachments, attachmentCount);
|
||||
if (anonymous) {
|
||||
|
@ -1450,6 +1452,7 @@ static void luax_parseshaderflags(lua_State* L, int index, ShaderFlag flags[MAX_
|
|||
static int l_lovrGraphicsNewShader(lua_State* L) {
|
||||
ShaderFlag flags[MAX_SHADER_FLAGS];
|
||||
uint32_t flagCount = 0;
|
||||
bool multiview = true;
|
||||
Shader* shader;
|
||||
|
||||
if (lua_isstring(L, 1) && (lua_istable(L, 2) || lua_gettop(L) == 1)) {
|
||||
|
@ -1459,6 +1462,10 @@ static int l_lovrGraphicsNewShader(lua_State* L) {
|
|||
lua_getfield(L, 2, "flags");
|
||||
luax_parseshaderflags(L, -1, flags, &flagCount);
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_getfield(L, 2, "stereo");
|
||||
multiview = lua_isnil(L, -1) ? multiview : lua_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
shader = lovrShaderCreateDefault(shaderType, flags, flagCount);
|
||||
|
@ -1472,9 +1479,13 @@ static int l_lovrGraphicsNewShader(lua_State* L) {
|
|||
lua_getfield(L, 3, "flags");
|
||||
luax_parseshaderflags(L, -1, flags, &flagCount);
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_getfield(L, 2, "stereo");
|
||||
multiview = lua_isnil(L, -1) ? multiview : lua_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
shader = lovrShaderCreateGraphics(vertexSource, fragmentSource, flags, flagCount);
|
||||
shader = lovrShaderCreateGraphics(vertexSource, fragmentSource, flags, flagCount, multiview);
|
||||
}
|
||||
|
||||
luax_pushtype(L, Shader, shader);
|
||||
|
|
|
@ -55,7 +55,7 @@ static const size_t BUFFER_STRIDES[] = {
|
|||
static const BufferType BUFFER_TYPES[] = {
|
||||
[STREAM_VERTEX] = BUFFER_VERTEX,
|
||||
[STREAM_INDEX] = BUFFER_INDEX,
|
||||
[STREAM_DRAW_ID] = BUFFER_GENERIC,
|
||||
[STREAM_DRAW_ID] = BUFFER_GENERIC, // So it doesn't thrash vertex buffer binding as much
|
||||
[STREAM_TRANSFORM] = BUFFER_UNIFORM,
|
||||
[STREAM_COLOR] = BUFFER_UNIFORM
|
||||
};
|
||||
|
@ -641,7 +641,7 @@ void lovrGraphicsFlush() {
|
|||
.rangeCount = rangeCount,
|
||||
.width = batch->canvas ? lovrCanvasGetWidth(batch->canvas) : state.width,
|
||||
.height = batch->canvas ? lovrCanvasGetHeight(batch->canvas) : state.height,
|
||||
.stereo = batch->type != BATCH_FILL && (batch->canvas ? lovrCanvasIsStereo(batch->canvas) : state.camera.stereo)
|
||||
.stereo = batch->canvas ? lovrCanvasIsStereo(batch->canvas) : state.camera.stereo
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1147,18 +1147,18 @@ void lovrGraphicsFill(Texture* texture, float u, float v, float w, float h) {
|
|||
.params.fill = { .u = u, .v = v, .w = w, .h = h },
|
||||
.drawMode = DRAW_TRIANGLE_STRIP,
|
||||
.shader = SHADER_FILL,
|
||||
.pipeline = &pipeline,
|
||||
.diffuseTexture = texture,
|
||||
.pipeline = &pipeline,
|
||||
.vertexCount = 4,
|
||||
.vertices = &vertices
|
||||
});
|
||||
|
||||
if (vertices) {
|
||||
memcpy(vertices, (float[32]) {
|
||||
-1, 1, 0, 0, 0, 0, u, v + h,
|
||||
-1, -1, 0, 0, 0, 0, u, v,
|
||||
1, 1, 0, 0, 0, 0, u + w, v + h,
|
||||
1, -1, 0, 0, 0, 0, u + w, v
|
||||
-1.f, 1.f, 0.f, 0.f, 0.f, 0.f, u, v + h,
|
||||
-1.f, -1.f, 0.f, 0.f, 0.f, 0.f, u, v,
|
||||
1.f, 1.f, 0.f, 0.f, 0.f, 0.f, u + w, v + h,
|
||||
1.f, -1.f, 0.f, 0.f, 0.f, 0.f, u + w, v
|
||||
}, 32 * sizeof(float));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -284,7 +284,8 @@ typedef struct {
|
|||
bool astc;
|
||||
bool compute;
|
||||
bool dxt;
|
||||
bool singlepass;
|
||||
bool instancedStereo;
|
||||
bool multiview;
|
||||
bool timers;
|
||||
} GpuFeatures;
|
||||
|
||||
|
|
|
@ -55,6 +55,7 @@ typedef struct {
|
|||
|
||||
static struct {
|
||||
Texture* defaultTexture;
|
||||
enum { NONE, INSTANCED_STEREO, MULTIVIEW } singlepass;
|
||||
bool alphaToCoverage;
|
||||
bool blendEnabled;
|
||||
BlendMode blendMode;
|
||||
|
@ -502,6 +503,10 @@ static void lovrGpuBindBlockBuffer(BlockType type, uint32_t buffer, int slot, si
|
|||
block->offset = offset;
|
||||
block->size = size;
|
||||
glBindBufferRange(target, slot, buffer, offset, size);
|
||||
|
||||
// Binding to an indexed target also binds to the generic target
|
||||
BufferType bufferType = type == BLOCK_UNIFORM ? BUFFER_UNIFORM : BUFFER_SHADER_STORAGE;
|
||||
state.buffers[bufferType] = buffer;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -639,21 +644,25 @@ static void lovrGpuBindCanvas(Canvas* canvas, bool willDraw) {
|
|||
|
||||
GLenum buffers[MAX_CANVAS_ATTACHMENTS] = { GL_NONE };
|
||||
for (uint32_t i = 0; i < canvas->attachmentCount; i++) {
|
||||
GLenum buffer = buffers[i] = GL_COLOR_ATTACHMENT0 + i;
|
||||
GLenum drawBuffer = buffers[i] = GL_COLOR_ATTACHMENT0 + i;
|
||||
Attachment* attachment = &canvas->attachments[i];
|
||||
Texture* texture = attachment->texture;
|
||||
uint32_t slice = attachment->slice;
|
||||
uint32_t level = attachment->level;
|
||||
|
||||
if (canvas->flags.msaa) {
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, buffer, GL_RENDERBUFFER, texture->msaaId);
|
||||
}
|
||||
if (canvas->flags.stereo && state.singlepass == MULTIVIEW) {
|
||||
glFramebufferTextureMultisampleMultiviewOVR(GL_READ_FRAMEBUFFER, drawBuffer, texture->id, level, canvas->flags.msaa, slice, 2);
|
||||
} else {
|
||||
if (canvas->flags.msaa) {
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, drawBuffer, GL_RENDERBUFFER, texture->msaaId);
|
||||
}
|
||||
|
||||
switch (texture->type) {
|
||||
case TEXTURE_2D: glFramebufferTexture2D(GL_READ_FRAMEBUFFER, buffer, GL_TEXTURE_2D, texture->id, level); break;
|
||||
case TEXTURE_CUBE: glFramebufferTexture2D(GL_READ_FRAMEBUFFER, buffer, GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice, texture->id, level); break;
|
||||
case TEXTURE_ARRAY: glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, buffer, texture->id, level, slice); break;
|
||||
case TEXTURE_VOLUME: glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, buffer, texture->id, level, slice); break;
|
||||
switch (texture->type) {
|
||||
case TEXTURE_2D: glFramebufferTexture2D(GL_READ_FRAMEBUFFER, drawBuffer, GL_TEXTURE_2D, texture->id, level); break;
|
||||
case TEXTURE_CUBE: glFramebufferTexture2D(GL_READ_FRAMEBUFFER, drawBuffer, GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice, texture->id, level); break;
|
||||
case TEXTURE_ARRAY: glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, drawBuffer, texture->id, level, slice); break;
|
||||
case TEXTURE_VOLUME: glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, drawBuffer, texture->id, level, slice); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
glDrawBuffers(canvas->attachmentCount, buffers);
|
||||
|
@ -983,12 +992,14 @@ void lovrGpuInit(getProcAddressProc getProcAddress) {
|
|||
state.features.astc = GLAD_GL_ES_VERSION_3_2;
|
||||
state.features.compute = GLAD_GL_ARB_compute_shader;
|
||||
state.features.dxt = GLAD_GL_EXT_texture_compression_s3tc;
|
||||
state.features.singlepass = GLAD_GL_ARB_viewport_array && GLAD_GL_AMD_vertex_shader_viewport_index && GLAD_GL_ARB_fragment_layer_viewport;
|
||||
state.features.instancedStereo = GLAD_GL_ARB_viewport_array && GLAD_GL_AMD_vertex_shader_viewport_index && GLAD_GL_ARB_fragment_layer_viewport;
|
||||
state.features.multiview = GLAD_GL_OVR_multiview2 && GLAD_GL_OVR_multiview_multisampled_render_to_texture;
|
||||
state.features.timers = GLAD_GL_VERSION_3_3 || GLAD_GL_EXT_disjoint_timer_query;
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
glEnable(GL_PROGRAM_POINT_SIZE);
|
||||
glEnable(GL_FRAMEBUFFER_SRGB);
|
||||
glGetFloatv(GL_POINT_SIZE_RANGE, state.limits.pointSizes);
|
||||
state.singlepass = (state.features.multiview && GLAD_GL_ES_VERSION_3_0) ? MULTIVIEW : (state.features.instancedStereo ? INSTANCED_STEREO : NONE);
|
||||
#else
|
||||
glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, state.limits.pointSizes);
|
||||
#endif
|
||||
|
@ -1136,23 +1147,25 @@ void lovrGpuDiscard(Canvas* canvas, bool color, bool depth, bool stencil) {
|
|||
}
|
||||
|
||||
void lovrGpuDraw(DrawCommand* draw) {
|
||||
uint32_t viewCount = 1 + draw->stereo;
|
||||
uint32_t drawCount = state.features.singlepass ? 1 : viewCount;
|
||||
uint32_t viewsPerDraw = state.features.singlepass ? viewCount : 1;
|
||||
uint32_t instances = MAX(draw->instances, 1) * viewsPerDraw;
|
||||
lovrAssert(state.singlepass != MULTIVIEW || draw->shader->multiview == draw->canvas->flags.stereo, "Shader and Canvas multiview settings must match!");
|
||||
uint32_t viewportCount = (draw->stereo && state.singlepass != MULTIVIEW) ? 2 : 1;
|
||||
uint32_t drawCount = state.singlepass == NONE ? viewportCount : 1;
|
||||
uint32_t instanceMultiplier = state.singlepass == INSTANCED_STEREO ? viewportCount : 1;
|
||||
uint32_t viewportsPerDraw = instanceMultiplier;
|
||||
uint32_t instances = MAX(draw->instances, 1) * instanceMultiplier;
|
||||
|
||||
float w = draw->width / (float) viewCount;
|
||||
float w = state.singlepass == MULTIVIEW ? draw->width : draw->width / (float) viewportCount;
|
||||
float h = draw->height;
|
||||
float viewports[2][4] = { { 0, 0, w, h }, { w, 0, w, h } };
|
||||
lovrShaderSetInts(draw->shader, "lovrViewportCount", &(int) { viewCount }, 0, 1);
|
||||
float viewports[2][4] = { { 0.f, 0.f, w, h }, { w, 0.f, w, h } };
|
||||
lovrShaderSetInts(draw->shader, "lovrViewportCount", &(int) { viewportCount }, 0, 1);
|
||||
|
||||
lovrGpuBindCanvas(draw->canvas, true);
|
||||
lovrGpuBindPipeline(&draw->pipeline);
|
||||
lovrGpuBindMesh(draw->mesh, draw->shader, viewsPerDraw);
|
||||
lovrGpuBindMesh(draw->mesh, draw->shader, instanceMultiplier);
|
||||
|
||||
for (uint32_t i = 0; i < drawCount; i++) {
|
||||
lovrGpuSetViewports(&viewports[i][0], viewsPerDraw);
|
||||
lovrShaderSetInts(draw->shader, "lovrViewportIndex", &(int) { i }, 0, 1);
|
||||
lovrGpuSetViewports(&viewports[i][0], viewportsPerDraw);
|
||||
lovrShaderSetInts(draw->shader, "lovrViewID", &(int) { i }, 0, 1);
|
||||
lovrGpuBindShader(draw->shader);
|
||||
|
||||
Mesh* mesh = draw->mesh;
|
||||
|
@ -1508,6 +1521,10 @@ void lovrTextureSetWrap(Texture* texture, TextureWrap wrap) {
|
|||
// Canvas
|
||||
|
||||
Canvas* lovrCanvasInit(Canvas* canvas, uint32_t width, uint32_t height, CanvasFlags flags) {
|
||||
if (flags.stereo && state.singlepass != MULTIVIEW) {
|
||||
width *= 2;
|
||||
}
|
||||
|
||||
canvas->width = width;
|
||||
canvas->height = height;
|
||||
canvas->flags = flags;
|
||||
|
@ -1518,7 +1535,11 @@ Canvas* lovrCanvasInit(Canvas* canvas, uint32_t width, uint32_t height, CanvasFl
|
|||
if (flags.depth.enabled) {
|
||||
lovrAssert(isTextureFormatDepth(flags.depth.format), "Canvas depth buffer can't use a color TextureFormat");
|
||||
GLenum attachment = flags.depth.format == FORMAT_D24S8 ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT;
|
||||
if (flags.depth.readable) {
|
||||
if (flags.stereo && state.singlepass == MULTIVIEW) {
|
||||
canvas->depth.texture = lovrTextureCreate(TEXTURE_ARRAY, NULL, 0, false, flags.mipmaps, flags.msaa);
|
||||
lovrTextureAllocate(canvas->depth.texture, width, height, 2, flags.depth.format);
|
||||
glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, attachment, canvas->depth.texture->id, 0, flags.msaa, 0, 2);
|
||||
} else if (flags.depth.readable) {
|
||||
canvas->depth.texture = lovrTextureCreate(TEXTURE_2D, NULL, 0, false, flags.mipmaps, flags.msaa);
|
||||
lovrTextureAllocate(canvas->depth.texture, width, height, 1, flags.depth.format);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, canvas->depth.texture->id, 0);
|
||||
|
@ -2005,33 +2026,33 @@ static char* lovrShaderGetFlagCode(ShaderFlag* flags, uint32_t flagCount) {
|
|||
return code;
|
||||
}
|
||||
|
||||
Shader* lovrShaderInitGraphics(Shader* shader, const char* vertexSource, const char* fragmentSource, ShaderFlag* flags, uint32_t flagCount) {
|
||||
Shader* lovrShaderInitGraphics(Shader* shader, const char* vertexSource, const char* fragmentSource, ShaderFlag* flags, uint32_t flagCount, bool multiview) {
|
||||
#if defined(LOVR_WEBGL) || defined(LOVR_GLES)
|
||||
const char* vertexHeader = "#version 300 es\nprecision highp float;\nprecision highp int;\n";
|
||||
const char* fragmentHeader = "#version 300 es\nprecision mediump float;\nprecision mediump int;\n";
|
||||
const char* version = "#version 300 es\n";
|
||||
const char* precision[2] = { "precision highp float;\nprecision highp int;\n", "precision mediump float;\nprecision mediump int;\n" };
|
||||
#else
|
||||
const char* vertexHeader = state.features.compute ? "#version 430\n" : "#version 150\n";
|
||||
const char* fragmentHeader = "#version 150\n";
|
||||
const char* version = state.features.compute ? "#version 430\n" : "#version 150\n";
|
||||
const char* precision[2] = { "", "" };
|
||||
#endif
|
||||
|
||||
const char* vertexSinglepass = state.features.singlepass ?
|
||||
"#extension GL_AMD_vertex_shader_viewport_index : require\n" "#define SINGLEPASS 1\n" :
|
||||
"#define SINGLEPASS 0\n";
|
||||
|
||||
const char* fragmentSinglepass = state.features.singlepass ?
|
||||
"#extension GL_ARB_fragment_layer_viewport : require\n" "#define SINGLEPASS 1\n" :
|
||||
"#define SINGLEPASS 0\n";
|
||||
const char* singlepass[2] = { "", "" };
|
||||
if (multiview && state.singlepass == MULTIVIEW) {
|
||||
singlepass[0] = singlepass[1] = "#extension GL_OVR_multiview2 : require\n#define MULTIVIEW\n";
|
||||
} else if (state.singlepass == INSTANCED_STEREO) {
|
||||
singlepass[0] = "#extension GL_AMD_vertex_shader_viewport_index : require\n""#define INSTANCED_STEREO\n";
|
||||
singlepass[1] = "#extension GL_AMD_fragment_layer_viewport : require\n""#define INSTANCED_STEREO\n";
|
||||
}
|
||||
|
||||
char* flagSource = lovrShaderGetFlagCode(flags, flagCount);
|
||||
|
||||
// Vertex
|
||||
vertexSource = vertexSource == NULL ? lovrUnlitVertexShader : vertexSource;
|
||||
const char* vertexSources[] = { vertexHeader, vertexSinglepass, flagSource ? flagSource : "", lovrShaderVertexPrefix, vertexSource, lovrShaderVertexSuffix };
|
||||
const char* vertexSources[] = { version, singlepass[0], precision[0], flagSource ? flagSource : "", lovrShaderVertexPrefix, vertexSource, lovrShaderVertexSuffix };
|
||||
GLuint vertexShader = compileShader(GL_VERTEX_SHADER, vertexSources, sizeof(vertexSources) / sizeof(vertexSources[0]));
|
||||
|
||||
// Fragment
|
||||
fragmentSource = fragmentSource == NULL ? lovrUnlitFragmentShader : fragmentSource;
|
||||
const char* fragmentSources[] = { fragmentHeader, fragmentSinglepass, flagSource ? flagSource : "", lovrShaderFragmentPrefix, fragmentSource, lovrShaderFragmentSuffix };
|
||||
const char* fragmentSources[] = { version, singlepass[1], precision[1], flagSource ? flagSource : "", lovrShaderFragmentPrefix, fragmentSource, lovrShaderFragmentSuffix };
|
||||
GLuint fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragmentSources, sizeof(fragmentSources) / sizeof(fragmentSources[0]));
|
||||
|
||||
free(flagSource);
|
||||
|
@ -2077,6 +2098,8 @@ Shader* lovrShaderInitGraphics(Shader* shader, const char* vertexSource, const c
|
|||
map_set(&shader->attributes, name, glGetAttribLocation(program, name));
|
||||
}
|
||||
|
||||
shader->multiview = multiview;
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
|
|
|
@ -61,12 +61,12 @@ static const char* getUniformTypeName(const Uniform* uniform) {
|
|||
|
||||
Shader* lovrShaderInitDefault(Shader* shader, DefaultShader type, ShaderFlag* flags, uint32_t flagCount) {
|
||||
switch (type) {
|
||||
case SHADER_UNLIT: return lovrShaderInitGraphics(shader, NULL, NULL, flags, flagCount);
|
||||
case SHADER_STANDARD: return lovrShaderInitGraphics(shader, lovrStandardVertexShader, lovrStandardFragmentShader, flags, flagCount);
|
||||
case SHADER_CUBE: return lovrShaderInitGraphics(shader, lovrCubeVertexShader, lovrCubeFragmentShader, flags, flagCount);
|
||||
case SHADER_PANO: return lovrShaderInitGraphics(shader, lovrCubeVertexShader, lovrPanoFragmentShader, flags, flagCount);
|
||||
case SHADER_FONT: return lovrShaderInitGraphics(shader, NULL, lovrFontFragmentShader, flags, flagCount);
|
||||
case SHADER_FILL: return lovrShaderInitGraphics(shader, lovrFillVertexShader, NULL, flags, flagCount);
|
||||
case SHADER_UNLIT: return lovrShaderInitGraphics(shader, NULL, NULL, flags, flagCount, true);
|
||||
case SHADER_STANDARD: return lovrShaderInitGraphics(shader, lovrStandardVertexShader, lovrStandardFragmentShader, flags, flagCount, true);
|
||||
case SHADER_CUBE: return lovrShaderInitGraphics(shader, lovrCubeVertexShader, lovrCubeFragmentShader, flags, flagCount, true);
|
||||
case SHADER_PANO: return lovrShaderInitGraphics(shader, lovrCubeVertexShader, lovrPanoFragmentShader, flags, flagCount, true);
|
||||
case SHADER_FONT: return lovrShaderInitGraphics(shader, NULL, lovrFontFragmentShader, flags, flagCount, true);
|
||||
case SHADER_FILL: return lovrShaderInitGraphics(shader, lovrFillVertexShader, NULL, flags, flagCount, true);
|
||||
default: lovrThrow("Unknown default shader type"); return NULL;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -117,12 +117,13 @@ typedef struct Shader {
|
|||
map_int_t attributes;
|
||||
map_int_t uniformMap;
|
||||
map_int_t blockMap;
|
||||
bool multiview;
|
||||
GPU_SHADER_FIELDS
|
||||
} Shader;
|
||||
|
||||
// Shader
|
||||
|
||||
Shader* lovrShaderInitGraphics(Shader* shader, const char* vertexSource, const char* fragmentSource, ShaderFlag* flags, uint32_t flagCount);
|
||||
Shader* lovrShaderInitGraphics(Shader* shader, const char* vertexSource, const char* fragmentSource, ShaderFlag* flags, uint32_t flagCount, bool multiview);
|
||||
Shader* lovrShaderInitCompute(Shader* shader, const char* source, ShaderFlag* flags, uint32_t flagCount);
|
||||
Shader* lovrShaderInitDefault(Shader* shader, DefaultShader type, ShaderFlag* flags, uint32_t flagCount);
|
||||
#define lovrShaderCreateGraphics(...) lovrShaderInitGraphics(lovrAlloc(Shader), __VA_ARGS__)
|
||||
|
|
|
@ -477,17 +477,24 @@ void bridgeLovrUpdate(BridgeLovrUpdateData *updateData) {
|
|||
}
|
||||
}
|
||||
|
||||
static void lovrOculusMobileDraw(int framebuffer, int width, int height, float *eyeViewMatrix, float *projectionMatrix) {
|
||||
lovrGpuDirtyTexture();
|
||||
void bridgeLovrDraw(BridgeLovrDrawData *drawData) {
|
||||
lovrGpuDirtyTexture(); // Clear texture state since LÖVR doesn't completely own the GL context
|
||||
|
||||
// Initialize a temporary Canvas from the framebuffer handle created by lovr-oculus-mobile
|
||||
Canvas canvas = { 0 };
|
||||
lovrCanvasInitFromHandle(&canvas, width, height, (CanvasFlags) { 0 }, framebuffer, 0, 0, 1, true);
|
||||
CanvasFlags flags = { .stereo = true };
|
||||
uint32_t width = bridgeLovrMobileData.displayDimensions.width;
|
||||
uint32_t height = bridgeLovrMobileData.displayDimensions.height;
|
||||
lovrCanvasInitFromHandle(&canvas, width, height, flags, drawData->framebuffer, 0, 0, 1, true);
|
||||
|
||||
Camera camera = { .canvas = &canvas, .stereo = false };
|
||||
memcpy(camera.viewMatrix[0], eyeViewMatrix, sizeof(camera.viewMatrix[0]));
|
||||
mat4_translate(camera.viewMatrix[0], 0, -state.offset, 0);
|
||||
|
||||
memcpy(camera.projection[0], projectionMatrix, sizeof(camera.projection[0]));
|
||||
// Set up a camera using the view and projection matrices from lovr-oculus-mobile
|
||||
Camera camera = { .canvas = &canvas };
|
||||
mat4_init(camera.viewMatrix[0], bridgeLovrMobileData.updateData.eyeViewMatrix[0]);
|
||||
mat4_init(camera.viewMatrix[1], bridgeLovrMobileData.updateData.eyeViewMatrix[1]);
|
||||
mat4_init(camera.projection[0], bridgeLovrMobileData.updateData.projectionMatrix[0]);
|
||||
mat4_init(camera.projection[1], bridgeLovrMobileData.updateData.projectionMatrix[1]);
|
||||
mat4_translate(camera.viewMatrix[0], 0.f, -state.offset, 0.f);
|
||||
mat4_translate(camera.viewMatrix[1], 0.f, -state.offset, 0.f);
|
||||
|
||||
lovrGraphicsSetCamera(&camera, true);
|
||||
|
||||
|
@ -499,12 +506,6 @@ static void lovrOculusMobileDraw(int framebuffer, int width, int height, float *
|
|||
lovrCanvasDestroy(&canvas);
|
||||
}
|
||||
|
||||
void bridgeLovrDraw(BridgeLovrDrawData *drawData) {
|
||||
int eye = drawData->eye;
|
||||
lovrOculusMobileDraw(drawData->framebuffer, bridgeLovrMobileData.displayDimensions.width, bridgeLovrMobileData.displayDimensions.height,
|
||||
bridgeLovrMobileData.updateData.eyeViewMatrix[eye], bridgeLovrMobileData.updateData.projectionMatrix[eye]); // Is this indexing safe?
|
||||
}
|
||||
|
||||
// Android activity has been stopped or resumed
|
||||
// In order to prevent weird dt jumps, we need to freeze and reset the clock
|
||||
static bool armedUnpause;
|
||||
|
|
|
@ -4,8 +4,11 @@ const char* lovrShaderVertexPrefix = ""
|
|||
"#define VERTEX VERTEX \n"
|
||||
"#define MAX_BONES 48 \n"
|
||||
"#define MAX_DRAWS 256 \n"
|
||||
"#define lovrView lovrViews[lovrViewportIndex] \n"
|
||||
"#define lovrProjection lovrProjections[lovrViewportIndex] \n"
|
||||
"#ifndef FLAG_skinned \n"
|
||||
"#define FLAG_skinned 0 \n"
|
||||
"#endif \n"
|
||||
"#define lovrView lovrViews[lovrViewID] \n"
|
||||
"#define lovrProjection lovrProjections[lovrViewID] \n"
|
||||
"#define lovrModel lovrModels[lovrDrawID] \n"
|
||||
"#define lovrTransform (lovrView * lovrModel) \n"
|
||||
"#define lovrNormalMatrix mat3(transpose(inverse(lovrTransform))) \n"
|
||||
|
@ -35,13 +38,13 @@ const char* lovrShaderVertexPrefix = ""
|
|||
"uniform float lovrPointSize; \n"
|
||||
"uniform mat4 lovrPose[MAX_BONES]; \n"
|
||||
"uniform int lovrViewportCount; \n"
|
||||
"#if SINGLEPASS \n"
|
||||
"#define lovrViewportIndex gl_ViewportIndex \n"
|
||||
"#if defined MULTIVIEW \n"
|
||||
"layout(num_views = 2) in; \n"
|
||||
"#define lovrViewID gl_ViewID_OVR \n"
|
||||
"#elif defined INSTANCED_STEREO \n"
|
||||
"#define lovrViewID gl_ViewportIndex \n"
|
||||
"#else \n"
|
||||
"uniform int lovrViewportIndex; \n"
|
||||
"#endif \n"
|
||||
"#ifndef FLAG_skinned \n"
|
||||
"#define FLAG_skinned false \n"
|
||||
"uniform int lovrViewID; \n"
|
||||
"#endif \n"
|
||||
"#line 0 \n";
|
||||
|
||||
|
@ -50,14 +53,14 @@ const char* lovrShaderVertexSuffix = ""
|
|||
" texCoord = (lovrMaterialTransform * vec3(lovrTexCoord, 1.)).xy; \n"
|
||||
" vertexColor = lovrVertexColor; \n"
|
||||
" lovrColor = lovrColors[lovrDrawID]; \n"
|
||||
"#if SINGLEPASS \n"
|
||||
"#if defined INSTANCED_STEREO \n"
|
||||
" gl_ViewportIndex = gl_InstanceID % lovrViewportCount; \n"
|
||||
"#endif \n"
|
||||
" gl_PointSize = lovrPointSize; \n"
|
||||
" vec4 vertexPosition = vec4(lovrPosition, 1.); \n"
|
||||
" if (FLAG_skinned) { \n"
|
||||
" vertexPosition = lovrPoseMatrix * vertexPosition; \n"
|
||||
" } \n"
|
||||
"#if FLAG_skinned \n"
|
||||
" vertexPosition = lovrPoseMatrix * vertexPosition; \n"
|
||||
"#endif \n"
|
||||
" gl_Position = position(lovrProjection, lovrTransform, vertexPosition); \n"
|
||||
"}";
|
||||
|
||||
|
@ -80,10 +83,12 @@ const char* lovrShaderFragmentPrefix = ""
|
|||
"uniform sampler2D lovrNormalTexture; \n"
|
||||
"uniform samplerCube lovrEnvironmentTexture; \n"
|
||||
"uniform int lovrViewportCount; \n"
|
||||
"#if SINGLEPASS \n"
|
||||
"#define lovrViewportIndex gl_ViewportIndex \n"
|
||||
"#if defined MULTIVIEW \n"
|
||||
"#define lovrViewID gl_ViewID_OVR \n"
|
||||
"#elif defined INSTANCED_STEREO \n"
|
||||
"#define lovrViewID gl_ViewportIndex \n"
|
||||
"#else \n"
|
||||
"uniform int lovrViewportIndex; \n"
|
||||
"uniform int lovrViewID; \n"
|
||||
"#endif \n"
|
||||
"#line 0 \n";
|
||||
|
||||
|
@ -207,21 +212,21 @@ const char* lovrStandardFragmentShader = ""
|
|||
const char* lovrCubeVertexShader = ""
|
||||
"out vec3 texturePosition[2]; \n"
|
||||
"vec4 position(mat4 projection, mat4 transform, vec4 vertex) { \n"
|
||||
" texturePosition[lovrViewportIndex] = inverse(mat3(transform)) * (inverse(projection) * vertex).xyz; \n"
|
||||
" texturePosition[lovrViewID] = inverse(mat3(transform)) * (inverse(projection) * vertex).xyz; \n"
|
||||
" return vertex; \n"
|
||||
"}";
|
||||
|
||||
const char* lovrCubeFragmentShader = ""
|
||||
"in vec3 texturePosition[2]; \n"
|
||||
"vec4 color(vec4 graphicsColor, sampler2D image, vec2 uv) { \n"
|
||||
" return graphicsColor * texture(lovrEnvironmentTexture, texturePosition[lovrViewportIndex] * vec3(-1, 1, 1)); \n"
|
||||
" return graphicsColor * texture(lovrEnvironmentTexture, 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[lovrViewportIndex]; \n"
|
||||
" vec3 direction = texturePosition[lovrViewID]; \n"
|
||||
" float theta = acos(-direction.y / length(direction)); \n"
|
||||
" float phi = atan(direction.x, -direction.z); \n"
|
||||
" uv = vec2(.5 + phi / (2. * PI), theta / PI); \n"
|
||||
|
|
Loading…
Reference in New Issue