diff --git a/src/graphics/graphics.c b/src/graphics/graphics.c index e3c54036..b437ecef 100644 --- a/src/graphics/graphics.c +++ b/src/graphics/graphics.c @@ -17,7 +17,9 @@ void lovrGraphicsInit() { for (int i = 0; i < MAX_TRANSFORMS; i++) { state.transforms[i] = mat4_init(); } - state.projection = mat4_init(); + state.canvases[0].framebuffer = 0; + glGetIntegerv(GL_VIEWPORT, state.canvases[0].viewport); + state.canvases[0].isSystem = 1; state.defaultShader = lovrShaderCreate(lovrDefaultVertexShader, lovrDefaultFragmentShader); state.skyboxShader = lovrShaderCreate(lovrSkyboxVertexShader, lovrSkyboxFragmentShader); int uniformId = lovrShaderGetUniformId(state.skyboxShader, "cube"); @@ -38,7 +40,6 @@ void lovrGraphicsDestroy() { for (int i = 0; i < MAX_TRANSFORMS; i++) { mat4_deinit(state.transforms[i]); } - mat4_deinit(state.projection); lovrRelease(&state.defaultShader->ref); lovrRelease(&state.skyboxShader->ref); lovrRelease(&state.defaultTexture->ref); @@ -51,6 +52,7 @@ void lovrGraphicsDestroy() { void lovrGraphicsReset() { state.transform = 0; + state.canvas = 0; lovrGraphicsSetProjection(.1f, 100.f, 67 * M_PI / 180); // TODO customize via lovr.conf lovrGraphicsSetShader(NULL); lovrGraphicsBindTexture(NULL); @@ -86,7 +88,9 @@ void lovrGraphicsPresent() { void lovrGraphicsPrepare() { Shader* shader = lovrGraphicsGetShader(); - lovrShaderBind(shader, state.transforms[state.transform], state.projection, state.color, 0); + mat4 transform = state.transforms[state.transform]; + mat4 projection = state.canvases[state.canvas].projection; + lovrShaderBind(shader, transform, projection, state.color, 0); } // State @@ -188,11 +192,7 @@ void lovrGraphicsBindTexture(Texture* texture) { void lovrGraphicsSetProjection(float near, float far, float fov) { int width, height; glfwGetWindowSize(window, &width, &height); - mat4_setProjection(state.projection, near, far, fov, (float) width / height); -} - -void lovrGraphicsSetProjectionRaw(mat4 projection) { - memcpy(state.projection, projection, 16 * sizeof(float)); + mat4_setProjection(state.canvases[state.canvas].projection, near, far, fov, (float) width / height); } float lovrGraphicsGetLineWidth() { @@ -274,6 +274,30 @@ int lovrGraphicsGetHeight() { return height; } +void lovrGraphicsPushCanvas(CanvasState canvasState) { + if (!canvasState.isSystem && !state.canvases[state.canvas].isSystem) { + lovrGraphicsPopCanvas(); + } else if (++state.canvas >= MAX_CANVASES) { + error("Canvas overflow"); + } + + int* viewport = canvasState.viewport; + glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); + glBindFramebuffer(GL_FRAMEBUFFER, canvasState.framebuffer); + state.canvases[state.canvas] = canvasState; +} + +void lovrGraphicsPopCanvas() { + if (--state.canvas < 0) { + error("Canvas underflow"); + } + + CanvasState* canvasState = &state.canvases[state.canvas]; + int* viewport = canvasState->viewport; + glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); + glBindFramebuffer(GL_FRAMEBUFFER, canvasState->framebuffer); +} + // Transforms int lovrGraphicsPush() { diff --git a/src/graphics/graphics.h b/src/graphics/graphics.h index 2a992499..6cf25833 100644 --- a/src/graphics/graphics.h +++ b/src/graphics/graphics.h @@ -9,13 +9,7 @@ #define LOVR_GRAPHICS_TYPES #define MAX_TRANSFORMS 64 - -typedef struct { - int x; - int y; - int width; - int height; -} ScissorRectangle; +#define MAX_CANVASES 4 typedef enum { DRAW_MODE_FILL, @@ -37,6 +31,20 @@ typedef enum { COMPARE_GREATER = GL_GREATER } CompareMode; +typedef struct { + int x; + int y; + int width; + int height; +} ScissorRectangle; + +typedef struct CanvasState { + int framebuffer; + float projection[16]; + int viewport[4]; + int isSystem; +} CanvasState; + typedef struct { Shader* activeShader; Shader* defaultShader; @@ -44,7 +52,8 @@ typedef struct { Texture* defaultTexture; int transform; mat4 transforms[MAX_TRANSFORMS]; - mat4 projection; + int canvas; + CanvasState canvases[MAX_CANVASES]; unsigned int color; char colorMask; int isScissorEnabled; @@ -87,7 +96,6 @@ Shader* lovrGraphicsGetShader(); void lovrGraphicsSetShader(Shader* shader); void lovrGraphicsBindTexture(Texture* texture); void lovrGraphicsSetProjection(float near, float far, float fov); -void lovrGraphicsSetProjectionRaw(mat4 projection); float lovrGraphicsGetLineWidth(); void lovrGraphicsSetLineWidth(float width); float lovrGraphicsGetPointSize(); @@ -102,6 +110,8 @@ int lovrGraphicsIsWireframe(); void lovrGraphicsSetWireframe(int wireframe); int lovrGraphicsGetWidth(); int lovrGraphicsGetHeight(); +void lovrGraphicsPushCanvas(CanvasState canvasState); +void lovrGraphicsPopCanvas(); // Transforms int lovrGraphicsPush(); diff --git a/src/graphics/texture.c b/src/graphics/texture.c index 47f3c8b9..9e226fc6 100644 --- a/src/graphics/texture.c +++ b/src/graphics/texture.c @@ -1,4 +1,5 @@ #include "graphics/texture.h" +#include "graphics/graphics.h" #include "util.h" #include @@ -47,6 +48,22 @@ void lovrTextureBind(Texture* texture) { glBindTexture(GL_TEXTURE_2D, texture->id); } +CanvasState lovrTextureGetCanvasState(Texture* texture) { + if (!texture->fbo) { + error("Texture cannot be used as a canvas"); + } + + CanvasState canvasState = { + .framebuffer = texture->fbo, + .viewport = { 0, 0, texture->width, texture->height }, + .isSystem = 0 + }; + + mat4_setIdentity(canvasState.projection); // TODO + + return canvasState; +} + int lovrTextureGetHeight(Texture* texture) { return texture->height; } @@ -60,20 +77,6 @@ void lovrTextureGetFilter(Texture* texture, FilterMode* min, FilterMode* mag) { *mag = texture->filterMag; } -void lovrTextureRenderTo(Texture* texture, textureRenderCallback callback, void* userdata) { - if (!texture->fbo) { - error("Texture does not have a framebuffer"); - } - - int oldViewport[4]; - glGetIntegerv(GL_VIEWPORT, oldViewport); - glViewport(0, 0, texture->textureData->width, texture->textureData->height); - glBindFramebuffer(GL_FRAMEBUFFER, texture->fbo); - callback(userdata); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glViewport(oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]); -} - void lovrTextureSetFilter(Texture* texture, FilterMode min, FilterMode mag) { texture->filterMin = min; texture->filterMag = mag; diff --git a/src/graphics/texture.h b/src/graphics/texture.h index f5f3f374..187cc452 100644 --- a/src/graphics/texture.h +++ b/src/graphics/texture.h @@ -1,13 +1,11 @@ #include "glfw.h" #include "util.h" -struct Buffer; +struct CanvasState; #ifndef LOVR_TEXTURE_TYPES #define LOVR_TEXTURE_TYPES -typedef void (*textureRenderCallback)(void*); - typedef struct { void* data; int width; @@ -27,11 +25,17 @@ typedef enum { WRAP_CLAMP_ZERO = GL_CLAMP_TO_BORDER } WrapMode; +typedef enum { + PROJECTION_ORTHOGRAPHIC, + PROJECTION_PERSPECTIVE +} ProjectionType; + typedef struct { Ref ref; TextureData* textureData; GLuint id; GLuint fbo; + ProjectionType projectionType; int width; int height; FilterMode filterMin; @@ -46,10 +50,10 @@ Texture* lovrTextureCreate(TextureData* textureData, int hasFramebuffer); void lovrTextureDestroy(const Ref* ref); void lovrTextureDataDestroy(TextureData* textureData); void lovrTextureBind(Texture* texture); +struct CanvasState lovrTextureGetCanvasState(Texture* texture); void lovrTextureRefresh(Texture* texture); int lovrTextureGetHeight(Texture* texture); int lovrTextureGetWidth(Texture* texture); -void lovrTextureRenderTo(Texture* texture, textureRenderCallback callback, void* userdata); void lovrTextureGetFilter(Texture* texture, FilterMode* min, FilterMode* mag); void lovrTextureSetFilter(Texture* texture, FilterMode min, FilterMode mag); void lovrTextureGetWrap(Texture* texture, WrapMode* horizontal, WrapMode* vertical); diff --git a/src/headset/vive.c b/src/headset/vive.c index f0be75a7..a72de634 100644 --- a/src/headset/vive.c +++ b/src/headset/vive.c @@ -484,7 +484,12 @@ void* viveControllerGetModel(void* headset, Controller* controller, ControllerMo void viveRenderTo(void* headset, headsetRenderCallback callback, void* userdata) { Vive* vive = (Vive*) headset; - float headMatrix[16], eyeMatrix[16], projectionMatrix[16]; + CanvasState canvasState = { + .framebuffer = vive->framebuffer, + .viewport = { 0, 0, vive->renderWidth, vive->renderHeight }, + .isSystem = 1 + }; + float headMatrix[16], eyeMatrix[16]; float (*matrix)[4]; vive->isRendering = 1; @@ -502,21 +507,19 @@ void viveRenderTo(void* headset, headsetRenderCallback callback, void* userdata) float near = vive->clipNear; float far = vive->clipFar; matrix = vive->system->GetProjectionMatrix(eye, near, far).m; - mat4_fromMat44(projectionMatrix, matrix); + mat4_fromMat44(canvasState.projection, matrix); glEnable(GL_MULTISAMPLE); - glBindFramebuffer(GL_FRAMEBUFFER, vive->framebuffer); - glViewport(0, 0, vive->renderWidth, vive->renderHeight); + lovrGraphicsPushCanvas(canvasState); lovrGraphicsClear(1, 1); lovrGraphicsPush(); lovrGraphicsOrigin(); lovrGraphicsMatrixTransform(transformMatrix); - lovrGraphicsSetProjectionRaw(projectionMatrix); callback(i, userdata); lovrGraphicsPop(); + lovrGraphicsPopCanvas(); - glBindFramebuffer(GL_FRAMEBUFFER, 0); glDisable(GL_MULTISAMPLE); glBindFramebuffer(GL_READ_FRAMEBUFFER, vive->framebuffer); diff --git a/src/lovr/types/texture.c b/src/lovr/types/texture.c index 9921611c..525e9989 100644 --- a/src/lovr/types/texture.c +++ b/src/lovr/types/texture.c @@ -1,5 +1,6 @@ #include "lovr/types/texture.h" #include "lovr/graphics.h" +#include "graphics/graphics.h" #include "util.h" const luaL_Reg lovrTexture[] = { @@ -15,12 +16,6 @@ const luaL_Reg lovrTexture[] = { { NULL, NULL } }; -static void renderHelper(void* userdata) { - lua_State* L = (lua_State*) userdata; - luaL_checktype(L, -1, LUA_TFUNCTION); - lua_call(L, 0, 0); -} - int l_lovrTextureBind(lua_State* L) { Texture* texture = luax_checktype(L, 1, Texture); lovrTextureBind(texture); @@ -66,8 +61,10 @@ int l_lovrTextureGetWrap(lua_State* L) { int l_lovrTextureRenderTo(lua_State* L) { Texture* texture = luax_checktype(L, 1, Texture); + lovrGraphicsPushCanvas(lovrTextureGetCanvasState(texture)); lua_settop(L, 2); - lovrTextureRenderTo(texture, renderHelper, L); + lua_call(L, 0, 0); + lovrGraphicsPopCanvas(); return 0; }