mirror of https://github.com/bjornbytes/lovr.git
Pipeline stack for graphics state; Simplify clearing;
This commit is contained in:
parent
6933914650
commit
b64489b020
|
@ -294,7 +294,7 @@ int l_lovrGraphicsClear(lua_State* L) {
|
|||
bool clearDepth = true;
|
||||
bool clearStencil = true;
|
||||
Color color = lovrGraphicsGetBackgroundColor();
|
||||
float depth = 1.0;
|
||||
float depth = 1.f;
|
||||
int stencil = 0;
|
||||
|
||||
if (top >= index) {
|
||||
|
@ -324,7 +324,7 @@ int l_lovrGraphicsClear(lua_State* L) {
|
|||
}
|
||||
}
|
||||
|
||||
lovrGraphicsClear(clearColor, clearDepth, clearStencil, color, depth, stencil);
|
||||
lovrGraphicsClear(clearColor ? &color : NULL, clearDepth ? &depth : NULL, clearStencil ? &stencil : NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -816,7 +816,7 @@ int l_lovrGraphicsStencil(lua_State* L) {
|
|||
bool keepValues = lua_toboolean(L, 4);
|
||||
if (!keepValues) {
|
||||
int clearTo = lua_isnumber(L, 4) ? lua_tonumber(L, 4) : 0;
|
||||
lovrGraphicsClear(false, false, true, (Color) { 0, 0, 0, 0 }, 0, clearTo);
|
||||
lovrGraphicsClear(NULL, NULL, &clearTo);
|
||||
}
|
||||
lua_settop(L, 1);
|
||||
lovrGraphicsStencil(action, replaceValue, stencilCallback, L);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "graphics/canvas.h"
|
||||
#include "graphics/font.h"
|
||||
#include "graphics/material.h"
|
||||
#include "graphics/mesh.h"
|
||||
#include "graphics/shader.h"
|
||||
|
@ -16,6 +17,83 @@ typedef struct {
|
|||
int drawCalls;
|
||||
} GpuStats;
|
||||
|
||||
typedef enum {
|
||||
BLEND_ALPHA,
|
||||
BLEND_ADD,
|
||||
BLEND_SUBTRACT,
|
||||
BLEND_MULTIPLY,
|
||||
BLEND_LIGHTEN,
|
||||
BLEND_DARKEN,
|
||||
BLEND_SCREEN,
|
||||
BLEND_REPLACE
|
||||
} BlendMode;
|
||||
|
||||
typedef enum {
|
||||
BLEND_ALPHA_MULTIPLY,
|
||||
BLEND_PREMULTIPLIED
|
||||
} BlendAlphaMode;
|
||||
|
||||
typedef enum {
|
||||
DRAW_MODE_FILL,
|
||||
DRAW_MODE_LINE
|
||||
} DrawMode;
|
||||
|
||||
typedef enum {
|
||||
ARC_MODE_PIE,
|
||||
ARC_MODE_OPEN,
|
||||
ARC_MODE_CLOSED
|
||||
} ArcMode;
|
||||
|
||||
typedef enum {
|
||||
WINDING_CLOCKWISE,
|
||||
WINDING_COUNTERCLOCKWISE
|
||||
} Winding;
|
||||
|
||||
typedef enum {
|
||||
COMPARE_NONE,
|
||||
COMPARE_EQUAL,
|
||||
COMPARE_NEQUAL,
|
||||
COMPARE_LESS,
|
||||
COMPARE_LEQUAL,
|
||||
COMPARE_GREATER,
|
||||
COMPARE_GEQUAL
|
||||
} CompareMode;
|
||||
|
||||
typedef enum {
|
||||
STENCIL_REPLACE,
|
||||
STENCIL_INCREMENT,
|
||||
STENCIL_DECREMENT,
|
||||
STENCIL_INCREMENT_WRAP,
|
||||
STENCIL_DECREMENT_WRAP,
|
||||
STENCIL_INVERT
|
||||
} StencilAction;
|
||||
|
||||
typedef struct {
|
||||
bool initialized;
|
||||
float pointSizes[2];
|
||||
int textureSize;
|
||||
int textureMSAA;
|
||||
float textureAnisotropy;
|
||||
} GraphicsLimits;
|
||||
|
||||
typedef struct {
|
||||
Color backgroundColor;
|
||||
BlendMode blendMode;
|
||||
BlendAlphaMode blendAlphaMode;
|
||||
Color color;
|
||||
bool culling;
|
||||
CompareMode depthTest;
|
||||
bool depthWrite;
|
||||
Font* font;
|
||||
float lineWidth;
|
||||
float pointSize;
|
||||
Shader* shader;
|
||||
CompareMode stencilMode;
|
||||
int stencilValue;
|
||||
Winding winding;
|
||||
bool wireframe;
|
||||
} Pipeline;
|
||||
|
||||
typedef struct {
|
||||
float projection[16];
|
||||
float view[16];
|
||||
|
@ -31,8 +109,7 @@ typedef struct {
|
|||
Shader* shader;
|
||||
Material* material;
|
||||
Mesh* mesh;
|
||||
Color color;
|
||||
float pointSize;
|
||||
Pipeline pipeline;
|
||||
int instances;
|
||||
} GpuDrawCommand;
|
||||
|
||||
|
@ -40,6 +117,7 @@ typedef void (*gpuProc)(void);
|
|||
|
||||
void gpuInit(bool srgb, gpuProc (*getProcAddress)(const char*));
|
||||
void gpuDestroy();
|
||||
void gpuClear(Canvas** canvas, int canvasCount, Color* color, float* depth, int* stencil);
|
||||
void gpuDraw(GpuDrawCommand* command);
|
||||
void gpuPresent();
|
||||
GpuStats gpuGetStats();
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
#include "graphics/graphics.h"
|
||||
#include "data/textureData.h"
|
||||
#include "data/rasterizer.h"
|
||||
#include "resources/shaders.h"
|
||||
#include "event/event.h"
|
||||
#include "math/math.h"
|
||||
#include "math/mat4.h"
|
||||
#include "math/vec3.h"
|
||||
#include "util.h"
|
||||
|
@ -26,26 +24,6 @@ static void onCloseWindow(GLFWwindow* window) {
|
|||
}
|
||||
}
|
||||
|
||||
static void gammaCorrectColor(Color* color) {
|
||||
if (state.gammaCorrect) {
|
||||
color->r = lovrMathGammaToLinear(color->r);
|
||||
color->g = lovrMathGammaToLinear(color->g);
|
||||
color->b = lovrMathGammaToLinear(color->b);
|
||||
}
|
||||
}
|
||||
|
||||
static GLenum convertCompareMode(CompareMode mode) {
|
||||
switch (mode) {
|
||||
case COMPARE_NONE: return GL_ALWAYS;
|
||||
case COMPARE_EQUAL: return GL_EQUAL;
|
||||
case COMPARE_NEQUAL: return GL_NOTEQUAL;
|
||||
case COMPARE_LESS: return GL_LESS;
|
||||
case COMPARE_LEQUAL: return GL_LEQUAL;
|
||||
case COMPARE_GREATER: return GL_GREATER;
|
||||
case COMPARE_GEQUAL: return GL_GEQUAL;
|
||||
}
|
||||
}
|
||||
|
||||
// Base
|
||||
|
||||
void lovrGraphicsInit() {
|
||||
|
@ -92,26 +70,9 @@ void lovrGraphicsReset() {
|
|||
lovrGraphicsOrigin();
|
||||
}
|
||||
|
||||
void lovrGraphicsClear(bool clearColor, bool clearDepth, bool clearStencil, Color color, float depth, int stencil) {
|
||||
void lovrGraphicsClear(Color* color, float* depth, int* stencil) {
|
||||
Layer layer = state.layers[state.layer];
|
||||
gpuBindFramebuffer(layer.canvasCount > 0 ? lovrCanvasGetId(layer.canvas[0]) : 0);
|
||||
|
||||
if (clearColor) {
|
||||
gammaCorrectColor(&color);
|
||||
float c[4] = { color.r, color.g, color.b, color.a };
|
||||
glClearBufferfv(GL_COLOR, 0, c);
|
||||
for (int i = 1; i < layer.canvasCount; i++) {
|
||||
glClearBufferfv(GL_COLOR, i, c);
|
||||
}
|
||||
}
|
||||
|
||||
if (clearDepth) {
|
||||
glClearBufferfv(GL_DEPTH, 0, &depth);
|
||||
}
|
||||
|
||||
if (clearStencil) {
|
||||
glClearBufferiv(GL_STENCIL, 0, &stencil);
|
||||
}
|
||||
gpuClear(layer.canvas, layer.canvasCount, color, depth, stencil);
|
||||
}
|
||||
|
||||
void lovrGraphicsPresent() {
|
||||
|
@ -198,68 +159,21 @@ GpuStats lovrGraphicsGetStats() {
|
|||
// State
|
||||
|
||||
Color lovrGraphicsGetBackgroundColor() {
|
||||
return state.backgroundColor;
|
||||
return state.pipelines[state.pipeline].backgroundColor;
|
||||
}
|
||||
|
||||
void lovrGraphicsSetBackgroundColor(Color color) {
|
||||
state.backgroundColor = color;
|
||||
gammaCorrectColor(&color);
|
||||
glClearColor(color.r, color.g, color.b, color.a);
|
||||
state.pipelines[state.pipeline].backgroundColor = color;
|
||||
}
|
||||
|
||||
void lovrGraphicsGetBlendMode(BlendMode* mode, BlendAlphaMode* alphaMode) {
|
||||
*mode = state.blendMode;
|
||||
*alphaMode = state.blendAlphaMode;
|
||||
*mode = state.pipelines[state.pipeline].blendMode;
|
||||
*alphaMode = state.pipelines[state.pipeline].blendAlphaMode;
|
||||
}
|
||||
|
||||
void lovrGraphicsSetBlendMode(BlendMode mode, BlendAlphaMode alphaMode) {
|
||||
GLenum srcRGB = mode == BLEND_MULTIPLY ? GL_DST_COLOR : GL_ONE;
|
||||
|
||||
if (srcRGB == GL_ONE && alphaMode == BLEND_ALPHA_MULTIPLY) {
|
||||
srcRGB = GL_SRC_ALPHA;
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case BLEND_ALPHA:
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFuncSeparate(srcRGB, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
break;
|
||||
|
||||
case BLEND_ADD:
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFuncSeparate(srcRGB, GL_ONE, GL_ZERO, GL_ONE);
|
||||
break;
|
||||
|
||||
case BLEND_SUBTRACT:
|
||||
glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
|
||||
glBlendFuncSeparate(srcRGB, GL_ONE, GL_ZERO, GL_ONE);
|
||||
break;
|
||||
|
||||
case BLEND_MULTIPLY:
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFuncSeparate(srcRGB, GL_ZERO, GL_DST_COLOR, GL_ZERO);
|
||||
break;
|
||||
|
||||
case BLEND_LIGHTEN:
|
||||
glBlendEquation(GL_MAX);
|
||||
glBlendFuncSeparate(srcRGB, GL_ZERO, GL_ONE, GL_ZERO);
|
||||
break;
|
||||
|
||||
case BLEND_DARKEN:
|
||||
glBlendEquation(GL_MIN);
|
||||
glBlendFuncSeparate(srcRGB, GL_ZERO, GL_ONE, GL_ZERO);
|
||||
break;
|
||||
|
||||
case BLEND_SCREEN:
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFuncSeparate(srcRGB, GL_ONE_MINUS_SRC_COLOR, GL_ONE, GL_ONE_MINUS_SRC_COLOR);
|
||||
break;
|
||||
|
||||
case BLEND_REPLACE:
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFuncSeparate(srcRGB, GL_ZERO, GL_ONE, GL_ZERO);
|
||||
break;
|
||||
}
|
||||
state.pipelines[state.pipeline].blendMode = mode;
|
||||
state.pipelines[state.pipeline].blendAlphaMode = alphaMode;
|
||||
}
|
||||
|
||||
void lovrGraphicsGetCanvas(Canvas** canvas, int* count) {
|
||||
|
@ -281,26 +195,19 @@ void lovrGraphicsSetCanvas(Canvas** canvas, int count) {
|
|||
}
|
||||
|
||||
Color lovrGraphicsGetColor() {
|
||||
return state.color;
|
||||
return state.pipelines[state.pipeline].color;
|
||||
}
|
||||
|
||||
void lovrGraphicsSetColor(Color color) {
|
||||
state.color = color;
|
||||
state.pipelines[state.pipeline].color = color;
|
||||
}
|
||||
|
||||
bool lovrGraphicsIsCullingEnabled() {
|
||||
return state.culling;
|
||||
return state.pipelines[state.pipeline].culling;
|
||||
}
|
||||
|
||||
void lovrGraphicsSetCullingEnabled(bool culling) {
|
||||
if (culling != state.culling) {
|
||||
state.culling = culling;
|
||||
if (culling) {
|
||||
glEnable(GL_CULL_FACE);
|
||||
} else {
|
||||
glDisable(GL_CULL_FACE);
|
||||
}
|
||||
}
|
||||
state.pipelines[state.pipeline].culling = culling;
|
||||
}
|
||||
|
||||
TextureFilter lovrGraphicsGetDefaultFilter() {
|
||||
|
@ -312,29 +219,17 @@ void lovrGraphicsSetDefaultFilter(TextureFilter filter) {
|
|||
}
|
||||
|
||||
void lovrGraphicsGetDepthTest(CompareMode* mode, bool* write) {
|
||||
*mode = state.depthTest;
|
||||
*write = state.depthWrite;
|
||||
*mode = state.pipelines[state.pipeline].depthTest;
|
||||
*write = state.pipelines[state.pipeline].depthWrite;
|
||||
}
|
||||
|
||||
void lovrGraphicsSetDepthTest(CompareMode mode, bool write) {
|
||||
if (state.depthTest != mode) {
|
||||
state.depthTest = mode;
|
||||
if (mode != COMPARE_NONE) {
|
||||
glDepthFunc(convertCompareMode(mode));
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
} else {
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
}
|
||||
}
|
||||
|
||||
if (state.depthWrite != write) {
|
||||
state.depthWrite = write;
|
||||
glDepthMask(write);
|
||||
}
|
||||
state.pipelines[state.pipeline].depthTest = mode;
|
||||
state.pipelines[state.pipeline].depthWrite = write;
|
||||
}
|
||||
|
||||
Font* lovrGraphicsGetFont() {
|
||||
if (!state.font) {
|
||||
if (!state.pipelines[state.pipeline].font) {
|
||||
if (!state.defaultFont) {
|
||||
Rasterizer* rasterizer = lovrRasterizerCreate(NULL, 32);
|
||||
state.defaultFont = lovrFontCreate(rasterizer);
|
||||
|
@ -344,13 +239,13 @@ Font* lovrGraphicsGetFont() {
|
|||
lovrGraphicsSetFont(state.defaultFont);
|
||||
}
|
||||
|
||||
return state.font;
|
||||
return state.pipelines[state.pipeline].font;
|
||||
}
|
||||
|
||||
void lovrGraphicsSetFont(Font* font) {
|
||||
lovrRetain(font);
|
||||
lovrRelease(state.font);
|
||||
state.font = font;
|
||||
lovrRelease(state.pipelines[state.pipeline].font);
|
||||
state.pipelines[state.pipeline].font = font;
|
||||
}
|
||||
|
||||
bool lovrGraphicsIsGammaCorrect() {
|
||||
|
@ -378,94 +273,62 @@ GraphicsLimits lovrGraphicsGetLimits() {
|
|||
}
|
||||
|
||||
float lovrGraphicsGetLineWidth() {
|
||||
return state.lineWidth;
|
||||
return state.pipelines[state.pipeline].lineWidth;
|
||||
}
|
||||
|
||||
void lovrGraphicsSetLineWidth(float width) {
|
||||
state.lineWidth = width;
|
||||
glLineWidth(width);
|
||||
state.pipelines[state.pipeline].lineWidth = width;
|
||||
}
|
||||
|
||||
float lovrGraphicsGetPointSize() {
|
||||
return state.pointSize;
|
||||
return state.pipelines[state.pipeline].pointSize;
|
||||
}
|
||||
|
||||
void lovrGraphicsSetPointSize(float size) {
|
||||
state.pointSize = size;
|
||||
state.pipelines[state.pipeline].pointSize = size;
|
||||
}
|
||||
|
||||
Shader* lovrGraphicsGetShader() {
|
||||
return state.shader;
|
||||
return state.pipelines[state.pipeline].shader;
|
||||
}
|
||||
|
||||
void lovrGraphicsSetShader(Shader* shader) {
|
||||
if (shader != state.shader) {
|
||||
if (shader != state.pipelines[state.pipeline].shader) {
|
||||
lovrRetain(shader);
|
||||
lovrRelease(state.shader);
|
||||
state.shader = shader;
|
||||
lovrRelease(state.pipelines[state.pipeline].shader);
|
||||
state.pipelines[state.pipeline].shader = shader;
|
||||
}
|
||||
}
|
||||
|
||||
void lovrGraphicsGetStencilTest(CompareMode* mode, int* value) {
|
||||
*mode = state.stencilMode;
|
||||
*value = state.stencilValue;
|
||||
*mode = state.pipelines[state.pipeline].stencilMode;
|
||||
*value = state.pipelines[state.pipeline].stencilValue;
|
||||
}
|
||||
|
||||
void lovrGraphicsSetStencilTest(CompareMode mode, int value) {
|
||||
state.stencilMode = mode;
|
||||
state.stencilValue = value;
|
||||
|
||||
if (state.stencilWriting) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode != COMPARE_NONE) {
|
||||
if (!state.stencilEnabled) {
|
||||
glEnable(GL_STENCIL_TEST);
|
||||
state.stencilEnabled = true;
|
||||
}
|
||||
|
||||
GLenum glMode = GL_ALWAYS;
|
||||
switch (mode) {
|
||||
case COMPARE_EQUAL: glMode = GL_EQUAL; break;
|
||||
case COMPARE_NEQUAL: glMode = GL_NOTEQUAL; break;
|
||||
case COMPARE_LESS: glMode = GL_GREATER; break;
|
||||
case COMPARE_LEQUAL: glMode = GL_GEQUAL; break;
|
||||
case COMPARE_GREATER: glMode = GL_LESS; break;
|
||||
case COMPARE_GEQUAL: glMode = GL_LEQUAL; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
glStencilFunc(glMode, value, 0xff);
|
||||
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
||||
} else if (state.stencilEnabled) {
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
state.stencilEnabled = false;
|
||||
}
|
||||
state.pipelines[state.pipeline].stencilMode = mode;
|
||||
state.pipelines[state.pipeline].stencilValue = value;
|
||||
}
|
||||
|
||||
Winding lovrGraphicsGetWinding() {
|
||||
return state.winding;
|
||||
return state.pipelines[state.pipeline].winding;
|
||||
}
|
||||
|
||||
void lovrGraphicsSetWinding(Winding winding) {
|
||||
if (winding != state.winding) {
|
||||
state.winding = winding;
|
||||
GLenum glWinding = winding == WINDING_CLOCKWISE ? GL_CW : GL_CCW;
|
||||
glFrontFace(glWinding);
|
||||
}
|
||||
state.pipelines[state.pipeline].winding = winding;
|
||||
}
|
||||
|
||||
bool lovrGraphicsIsWireframe() {
|
||||
return state.wireframe;
|
||||
return state.pipelines[state.pipeline].wireframe;
|
||||
}
|
||||
|
||||
void lovrGraphicsSetWireframe(bool wireframe) {
|
||||
#ifndef EMSCRIPTEN
|
||||
if (state.wireframe != wireframe) {
|
||||
state.wireframe = wireframe;
|
||||
glPolygonMode(GL_FRONT_AND_BACK, wireframe ? GL_LINE : GL_FILL);
|
||||
}
|
||||
state.pipelines[state.pipeline].wireframe = wireframe;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -836,7 +699,7 @@ void lovrGraphicsSkybox(Texture* texture, float angle, float ax, float ay, float
|
|||
TextureType type = lovrTextureGetType(texture);
|
||||
lovrAssert(type == TEXTURE_CUBE || type == TEXTURE_2D, "Only 2D and cube textures can be used as skyboxes");
|
||||
MaterialTexture materialTexture = type == TEXTURE_CUBE ? TEXTURE_ENVIRONMENT_MAP : TEXTURE_DIFFUSE;
|
||||
Winding winding = state.winding;
|
||||
lovrGraphicsPushPipeline();
|
||||
lovrGraphicsSetWinding(WINDING_COUNTERCLOCKWISE);
|
||||
Material* material = lovrGraphicsGetDefaultMaterial();
|
||||
lovrMaterialSetTexture(material, materialTexture, texture);
|
||||
|
@ -852,7 +715,7 @@ void lovrGraphicsSkybox(Texture* texture, float angle, float ax, float ay, float
|
|||
}
|
||||
});
|
||||
lovrMaterialSetTexture(material, materialTexture, NULL);
|
||||
lovrGraphicsSetWinding(winding);
|
||||
lovrGraphicsPopPipeline();
|
||||
}
|
||||
|
||||
void lovrGraphicsPrint(const char* str, mat4 transform, float wrap, HorizontalAlign halign, VerticalAlign valign) {
|
||||
|
@ -871,17 +734,15 @@ void lovrGraphicsPrint(const char* str, mat4 transform, float wrap, HorizontalAl
|
|||
lovrGraphicsTranslate(0, offsety, 0);
|
||||
Material* material = lovrGraphicsGetDefaultMaterial();
|
||||
lovrMaterialSetTexture(material, TEXTURE_DIFFUSE, font->texture);
|
||||
CompareMode mode;
|
||||
bool write;
|
||||
lovrGraphicsGetDepthTest(&mode, &write);
|
||||
lovrGraphicsSetDepthTest(mode, false);
|
||||
lovrGraphicsPushPipeline();
|
||||
state.pipelines[state.pipeline].depthWrite = false;
|
||||
lovrGraphicsDraw(&(GraphicsDraw) {
|
||||
.shader = SHADER_FONT,
|
||||
.material = material,
|
||||
.mode = MESH_TRIANGLES,
|
||||
.range = { 0, vertexCount }
|
||||
});
|
||||
lovrGraphicsSetDepthTest(mode, write);
|
||||
lovrGraphicsPopPipeline();
|
||||
lovrMaterialSetTexture(material, TEXTURE_DIFFUSE, NULL);
|
||||
lovrGraphicsPop();
|
||||
}
|
||||
|
@ -917,13 +778,11 @@ void lovrGraphicsStencil(StencilAction action, int replaceValue, StencilCallback
|
|||
|
||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
lovrGraphicsSetDepthTest(mode, write);
|
||||
lovrGraphicsSetStencilTest(state.stencilMode, state.stencilValue);
|
||||
lovrGraphicsSetStencilTest(state.pipelines[state.pipeline].stencilMode, state.pipelines[state.pipeline].stencilValue);
|
||||
}
|
||||
|
||||
void lovrGraphicsFill(Texture* texture) {
|
||||
CompareMode mode;
|
||||
bool write;
|
||||
lovrGraphicsGetDepthTest(&mode, &write);
|
||||
lovrGraphicsPushPipeline();
|
||||
lovrGraphicsSetDepthTest(COMPARE_NONE, false);
|
||||
Material* material = lovrGraphicsGetDefaultMaterial();
|
||||
lovrMaterialSetTexture(material, TEXTURE_DIFFUSE, texture);
|
||||
|
@ -940,7 +799,7 @@ void lovrGraphicsFill(Texture* texture) {
|
|||
}
|
||||
});
|
||||
lovrMaterialSetTexture(material, TEXTURE_DIFFUSE, NULL);
|
||||
lovrGraphicsSetDepthTest(mode, write);
|
||||
lovrGraphicsPopPipeline();
|
||||
}
|
||||
|
||||
// Internal
|
||||
|
@ -950,7 +809,7 @@ void lovrGraphicsDraw(GraphicsDraw* draw) {
|
|||
lovrGraphicsMatrixTransform(draw->transform);
|
||||
}
|
||||
|
||||
Shader* shader = state.shader ? state.shader : state.defaultShaders[draw->shader];
|
||||
Shader* shader = state.pipelines[state.pipeline].shader ? state.pipelines[state.pipeline].shader : state.defaultShaders[draw->shader];
|
||||
if (!shader) shader = state.defaultShaders[draw->shader] = lovrShaderCreateDefault(draw->shader);
|
||||
|
||||
Mesh* mesh = draw->mesh;
|
||||
|
@ -980,8 +839,7 @@ void lovrGraphicsDraw(GraphicsDraw* draw) {
|
|||
.material = material,
|
||||
.transform = state.transforms[state.transform],
|
||||
.mesh = mesh,
|
||||
.color = state.color,
|
||||
.pointSize = state.pointSize,
|
||||
.pipeline = state.pipelines[state.pipeline],
|
||||
.instances = draw->instances
|
||||
});
|
||||
|
||||
|
@ -1034,6 +892,20 @@ void lovrGraphicsPopLayer() {
|
|||
lovrAssert(--state.layer >= 0, "Layer underflow");
|
||||
}
|
||||
|
||||
void lovrGraphicsPushPipeline() {
|
||||
if (++state.pipeline >= MAX_PIPELINES) {
|
||||
lovrThrow("Unbalanced pipeline stack (more pushes than pops?)");
|
||||
}
|
||||
|
||||
memcpy(&state.pipelines[state.pipeline], &state.pipelines[state.pipeline - 1], sizeof(Pipeline));
|
||||
}
|
||||
|
||||
void lovrGraphicsPopPipeline() {
|
||||
if (--state.pipeline < 0) {
|
||||
lovrThrow("Unbalanced pipeline stack (more pops than pushes?)");
|
||||
}
|
||||
}
|
||||
|
||||
void lovrGraphicsSetCamera(mat4 projection, mat4 view) {
|
||||
mat4_set(state.layers[state.layer].projection, projection);
|
||||
mat4_set(state.layers[state.layer].view, view);
|
||||
|
|
|
@ -12,73 +12,16 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#define MAX_LAYERS 4
|
||||
#define MAX_TRANSFORMS 60
|
||||
#define INTERNAL_TRANSFORMS 4
|
||||
#define MAX_LAYERS 4
|
||||
#define MAX_PIPELINES 14
|
||||
#define INTERNAL_PIPELINES 2
|
||||
#define DEFAULT_SHADER_COUNT 5
|
||||
#define MAX_TEXTURES 16
|
||||
|
||||
typedef void (*StencilCallback)(void* userdata);
|
||||
|
||||
typedef enum {
|
||||
BLEND_ALPHA,
|
||||
BLEND_ADD,
|
||||
BLEND_SUBTRACT,
|
||||
BLEND_MULTIPLY,
|
||||
BLEND_LIGHTEN,
|
||||
BLEND_DARKEN,
|
||||
BLEND_SCREEN,
|
||||
BLEND_REPLACE
|
||||
} BlendMode;
|
||||
|
||||
typedef enum {
|
||||
BLEND_ALPHA_MULTIPLY,
|
||||
BLEND_PREMULTIPLIED
|
||||
} BlendAlphaMode;
|
||||
|
||||
typedef enum {
|
||||
DRAW_MODE_FILL,
|
||||
DRAW_MODE_LINE
|
||||
} DrawMode;
|
||||
|
||||
typedef enum {
|
||||
ARC_MODE_PIE,
|
||||
ARC_MODE_OPEN,
|
||||
ARC_MODE_CLOSED
|
||||
} ArcMode;
|
||||
|
||||
typedef enum {
|
||||
WINDING_CLOCKWISE,
|
||||
WINDING_COUNTERCLOCKWISE
|
||||
} Winding;
|
||||
|
||||
typedef enum {
|
||||
COMPARE_NONE,
|
||||
COMPARE_EQUAL,
|
||||
COMPARE_NEQUAL,
|
||||
COMPARE_LESS,
|
||||
COMPARE_LEQUAL,
|
||||
COMPARE_GREATER,
|
||||
COMPARE_GEQUAL
|
||||
} CompareMode;
|
||||
|
||||
typedef enum {
|
||||
STENCIL_REPLACE,
|
||||
STENCIL_INCREMENT,
|
||||
STENCIL_DECREMENT,
|
||||
STENCIL_INCREMENT_WRAP,
|
||||
STENCIL_DECREMENT_WRAP,
|
||||
STENCIL_INVERT
|
||||
} StencilAction;
|
||||
|
||||
typedef struct {
|
||||
bool initialized;
|
||||
float pointSizes[2];
|
||||
int textureSize;
|
||||
int textureMSAA;
|
||||
float textureAnisotropy;
|
||||
} GraphicsLimits;
|
||||
|
||||
typedef struct {
|
||||
mat4 transform;
|
||||
DefaultShader shader;
|
||||
|
@ -106,38 +49,25 @@ typedef struct {
|
|||
Shader* defaultShaders[DEFAULT_SHADER_COUNT];
|
||||
Material* defaultMaterial;
|
||||
Font* defaultFont;
|
||||
TextureFilter defaultFilter;
|
||||
bool gammaCorrect;
|
||||
GraphicsLimits limits;
|
||||
Mesh* mesh;
|
||||
float transforms[MAX_TRANSFORMS + INTERNAL_TRANSFORMS][16];
|
||||
int transform;
|
||||
Layer layers[MAX_LAYERS];
|
||||
int layer;
|
||||
Color backgroundColor;
|
||||
BlendMode blendMode;
|
||||
BlendAlphaMode blendAlphaMode;
|
||||
Color color;
|
||||
bool culling;
|
||||
TextureFilter defaultFilter;
|
||||
CompareMode depthTest;
|
||||
bool depthWrite;
|
||||
Font* font;
|
||||
bool gammaCorrect;
|
||||
GraphicsLimits limits;
|
||||
float lineWidth;
|
||||
float pointSize;
|
||||
Shader* shader;
|
||||
CompareMode stencilMode;
|
||||
int stencilValue;
|
||||
Winding winding;
|
||||
bool wireframe;
|
||||
Mesh* mesh;
|
||||
bool stencilEnabled;
|
||||
Pipeline pipelines[MAX_PIPELINES + INTERNAL_PIPELINES];
|
||||
int pipeline;
|
||||
bool stencilWriting;
|
||||
bool stencilEnabled;
|
||||
} GraphicsState;
|
||||
|
||||
// Base
|
||||
void lovrGraphicsInit();
|
||||
void lovrGraphicsDestroy();
|
||||
void lovrGraphicsReset();
|
||||
void lovrGraphicsClear(bool clearColor, bool clearDepth, bool clearStencil, Color color, float depth, int stencil);
|
||||
void lovrGraphicsClear(Color* color, float* depth, int* stencil);
|
||||
void lovrGraphicsPresent();
|
||||
void lovrGraphicsCreateWindow(int w, int h, bool fullscreen, int msaa, const char* title, const char* icon);
|
||||
int lovrGraphicsGetWidth();
|
||||
|
@ -202,10 +132,12 @@ void lovrGraphicsStencil(StencilAction action, int replaceValue, StencilCallback
|
|||
void lovrGraphicsFill(Texture* texture);
|
||||
|
||||
// Internal
|
||||
void lovrGraphicsDraw(GraphicsDraw* draw);
|
||||
VertexPointer lovrGraphicsGetVertexPointer(uint32_t capacity);
|
||||
void lovrGraphicsDraw(GraphicsDraw* draw);
|
||||
void lovrGraphicsPushLayer(Canvas** canvas, int count, bool user);
|
||||
void lovrGraphicsPopLayer();
|
||||
void lovrGraphicsPushPipeline();
|
||||
void lovrGraphicsPopPipeline();
|
||||
void lovrGraphicsSetCamera(mat4 projection, mat4 view);
|
||||
void lovrGraphicsSetViewport(uint32_t x, uint32_t y, uint32_t width, uint32_t height);
|
||||
Material* lovrGraphicsGetDefaultMaterial();
|
||||
|
|
|
@ -71,7 +71,7 @@ Canvas* lovrCanvasCreate(int width, int height, TextureFormat format, CanvasFlag
|
|||
}
|
||||
|
||||
lovrAssert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE, "Error creating Canvas");
|
||||
lovrGraphicsClear(true, true, true, (Color) { 0, 0, 0, 0 }, 1., 0);
|
||||
lovrGraphicsClear(&(Color) { 0, 0, 0, 0 }, &(float) { 1. }, &(int) { 0 });
|
||||
gpuBindFramebuffer(0);
|
||||
|
||||
return canvas;
|
||||
|
|
|
@ -9,6 +9,18 @@
|
|||
|
||||
static struct {
|
||||
Texture* defaultTexture;
|
||||
BlendMode blendMode;
|
||||
BlendAlphaMode blendAlphaMode;
|
||||
bool culling;
|
||||
bool depthEnabled;
|
||||
CompareMode depthTest;
|
||||
bool depthWrite;
|
||||
float lineWidth;
|
||||
bool stencilEnabled;
|
||||
CompareMode stencilMode;
|
||||
int stencilValue;
|
||||
Winding winding;
|
||||
bool wireframe;
|
||||
uint32_t framebuffer;
|
||||
uint32_t indexBuffer;
|
||||
uint32_t program;
|
||||
|
@ -28,6 +40,18 @@ static void gammaCorrectColor(Color* color) {
|
|||
}
|
||||
}
|
||||
|
||||
static GLenum convertCompareMode(CompareMode mode) {
|
||||
switch (mode) {
|
||||
case COMPARE_NONE: return GL_ALWAYS;
|
||||
case COMPARE_EQUAL: return GL_EQUAL;
|
||||
case COMPARE_NEQUAL: return GL_NOTEQUAL;
|
||||
case COMPARE_LESS: return GL_LESS;
|
||||
case COMPARE_LEQUAL: return GL_LEQUAL;
|
||||
case COMPARE_GREATER: return GL_GREATER;
|
||||
case COMPARE_GEQUAL: return GL_GEQUAL;
|
||||
}
|
||||
}
|
||||
|
||||
void gpuInit(bool srgb, gpuProc (*getProcAddress)(const char*)) {
|
||||
#ifndef EMSCRIPTEN
|
||||
gladLoadGLLoader((GLADloadproc) getProcAddress);
|
||||
|
@ -40,9 +64,20 @@ void gpuInit(bool srgb, gpuProc (*getProcAddress)(const char*)) {
|
|||
}
|
||||
#endif
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
state.srgb = srgb;
|
||||
state.blendMode = -1;
|
||||
state.blendAlphaMode = -1;
|
||||
state.culling = -1;
|
||||
state.depthEnabled = -1;
|
||||
state.depthTest = -1;
|
||||
state.depthWrite = -1;
|
||||
state.lineWidth = -1;
|
||||
state.stencilEnabled = -1;
|
||||
state.stencilMode = -1;
|
||||
state.stencilValue = -1;
|
||||
state.winding = -1;
|
||||
state.wireframe = -1;
|
||||
}
|
||||
|
||||
void gpuDestroy() {
|
||||
|
@ -52,12 +87,167 @@ void gpuDestroy() {
|
|||
}
|
||||
}
|
||||
|
||||
void gpuClear(Canvas** canvas, int canvasCount, Color* color, float* depth, int* stencil) {
|
||||
gpuBindFramebuffer(canvasCount > 0 ? lovrCanvasGetId(canvas[0]) : 0);
|
||||
|
||||
if (color) {
|
||||
gammaCorrectColor(color);
|
||||
float c[4] = { color->r, color->g, color->b, color->a };
|
||||
glClearBufferfv(GL_COLOR, 0, c);
|
||||
for (int i = 1; i < canvasCount; i++) {
|
||||
glClearBufferfv(GL_COLOR, i, c);
|
||||
}
|
||||
}
|
||||
|
||||
if (depth) {
|
||||
glClearBufferfv(GL_DEPTH, 0, depth);
|
||||
}
|
||||
|
||||
if (stencil) {
|
||||
glClearBufferiv(GL_STENCIL, 0, stencil);
|
||||
}
|
||||
}
|
||||
|
||||
void gpuDraw(GpuDrawCommand* command) {
|
||||
Mesh* mesh = command->mesh;
|
||||
Material* material = command->material;
|
||||
Shader* shader = command->shader;
|
||||
Pipeline* pipeline = &command->pipeline;
|
||||
int instances = command->instances;
|
||||
|
||||
// Blend mode
|
||||
if (state.blendMode != pipeline->blendMode || state.blendAlphaMode != pipeline->blendAlphaMode) {
|
||||
state.blendMode = pipeline->blendMode;
|
||||
state.blendAlphaMode = pipeline->blendAlphaMode;
|
||||
|
||||
GLenum srcRGB = state.blendMode == BLEND_MULTIPLY ? GL_DST_COLOR : GL_ONE;
|
||||
if (srcRGB == GL_ONE && state.blendAlphaMode == BLEND_ALPHA_MULTIPLY) {
|
||||
srcRGB = GL_SRC_ALPHA;
|
||||
}
|
||||
|
||||
switch (state.blendMode) {
|
||||
case BLEND_ALPHA:
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFuncSeparate(srcRGB, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
break;
|
||||
|
||||
case BLEND_ADD:
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFuncSeparate(srcRGB, GL_ONE, GL_ZERO, GL_ONE);
|
||||
break;
|
||||
|
||||
case BLEND_SUBTRACT:
|
||||
glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
|
||||
glBlendFuncSeparate(srcRGB, GL_ONE, GL_ZERO, GL_ONE);
|
||||
break;
|
||||
|
||||
case BLEND_MULTIPLY:
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFuncSeparate(srcRGB, GL_ZERO, GL_DST_COLOR, GL_ZERO);
|
||||
break;
|
||||
|
||||
case BLEND_LIGHTEN:
|
||||
glBlendEquation(GL_MAX);
|
||||
glBlendFuncSeparate(srcRGB, GL_ZERO, GL_ONE, GL_ZERO);
|
||||
break;
|
||||
|
||||
case BLEND_DARKEN:
|
||||
glBlendEquation(GL_MIN);
|
||||
glBlendFuncSeparate(srcRGB, GL_ZERO, GL_ONE, GL_ZERO);
|
||||
break;
|
||||
|
||||
case BLEND_SCREEN:
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFuncSeparate(srcRGB, GL_ONE_MINUS_SRC_COLOR, GL_ONE, GL_ONE_MINUS_SRC_COLOR);
|
||||
break;
|
||||
|
||||
case BLEND_REPLACE:
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFuncSeparate(srcRGB, GL_ZERO, GL_ONE, GL_ZERO);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Culling
|
||||
if (state.culling != pipeline->culling) {
|
||||
state.culling = pipeline->culling;
|
||||
if (state.culling) {
|
||||
glEnable(GL_CULL_FACE);
|
||||
} else {
|
||||
glDisable(GL_CULL_FACE);
|
||||
}
|
||||
}
|
||||
|
||||
// Depth test
|
||||
if (state.depthTest != pipeline->depthTest) {
|
||||
state.depthTest = pipeline->depthTest;
|
||||
if (state.depthTest != COMPARE_NONE) {
|
||||
if (!state.depthEnabled) {
|
||||
state.depthEnabled = true;
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
}
|
||||
glDepthFunc(convertCompareMode(state.depthTest));
|
||||
} else if (state.depthEnabled) {
|
||||
state.depthEnabled = false;
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
}
|
||||
}
|
||||
|
||||
// Depth write
|
||||
if (state.depthWrite != pipeline->depthWrite) {
|
||||
state.depthWrite = pipeline->depthWrite;
|
||||
glDepthMask(state.depthWrite);
|
||||
}
|
||||
|
||||
// Line width
|
||||
if (state.lineWidth != pipeline->lineWidth) {
|
||||
state.lineWidth = state.lineWidth;
|
||||
glLineWidth(state.lineWidth);
|
||||
}
|
||||
|
||||
// Stencil mode
|
||||
if (state.stencilMode != pipeline->stencilMode || state.stencilValue != pipeline->stencilValue) {
|
||||
state.stencilMode = pipeline->stencilMode;
|
||||
state.stencilValue = pipeline->stencilValue;
|
||||
if (state.stencilMode != COMPARE_NONE) {
|
||||
if (!state.stencilEnabled) {
|
||||
state.stencilEnabled = true;
|
||||
glEnable(GL_STENCIL_TEST);
|
||||
}
|
||||
|
||||
GLenum glMode = GL_ALWAYS;
|
||||
switch (state.stencilMode) {
|
||||
case COMPARE_EQUAL: glMode = GL_EQUAL; break;
|
||||
case COMPARE_NEQUAL: glMode = GL_NOTEQUAL; break;
|
||||
case COMPARE_LESS: glMode = GL_GREATER; break;
|
||||
case COMPARE_LEQUAL: glMode = GL_GEQUAL; break;
|
||||
case COMPARE_GREATER: glMode = GL_LESS; break;
|
||||
case COMPARE_GEQUAL: glMode = GL_LEQUAL; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
glStencilFunc(glMode, state.stencilValue, 0xff);
|
||||
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
||||
} else if (state.stencilEnabled) {
|
||||
state.stencilEnabled = false;
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
}
|
||||
}
|
||||
|
||||
// Winding
|
||||
if (state.winding != pipeline->winding) {
|
||||
state.winding = pipeline->winding;
|
||||
glFrontFace(state.winding == WINDING_CLOCKWISE ? GL_CW : GL_CCW);
|
||||
}
|
||||
|
||||
// Wireframe
|
||||
if (state.wireframe != pipeline->wireframe) {
|
||||
state.wireframe = pipeline->wireframe;
|
||||
#ifndef EMSCRIPTEN
|
||||
glPolygonMode(GL_FRONT_AND_BACK, state.wireframe ? GL_LINE : GL_FILL);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Transform
|
||||
lovrShaderSetMatrix(shader, "lovrProjection", command->layer.projection, 16);
|
||||
lovrShaderSetMatrix(shader, "lovrView", command->layer.view, 16);
|
||||
|
@ -94,10 +284,10 @@ void gpuDraw(GpuDrawCommand* command) {
|
|||
}
|
||||
|
||||
// Point size
|
||||
lovrShaderSetFloat(shader, "lovrPointSize", &command->pointSize, 1);
|
||||
lovrShaderSetFloat(shader, "lovrPointSize", &pipeline->pointSize, 1);
|
||||
|
||||
// Color
|
||||
Color color = command->color;
|
||||
Color color = pipeline->color;
|
||||
gammaCorrectColor(&color);
|
||||
float data[4] = { color.r, color.g, color.b, color.a };
|
||||
lovrShaderSetFloat(shader, "lovrColor", data, 4);
|
||||
|
|
|
@ -292,8 +292,9 @@ static void fakeRenderTo(void (*callback)(void*), void* userdata) {
|
|||
mat4_multiply(view, state.transform);
|
||||
mat4_invert(view);
|
||||
|
||||
Color backgroundColor = lovrGraphicsGetBackgroundColor();
|
||||
lovrGraphicsPushLayer(NULL, 0, false);
|
||||
lovrGraphicsClear(true, true, true, lovrGraphicsGetBackgroundColor(), 1., 0);
|
||||
lovrGraphicsClear(&backgroundColor, &(float) { 1. }, &(int) { 0 });
|
||||
lovrGraphicsSetCamera(projection, view);
|
||||
lovrGraphicsSetViewport(0, 0, width, height);
|
||||
callback(userdata);
|
||||
|
|
|
@ -673,8 +673,9 @@ static void openvrRenderTo(void (*callback)(void*), void* userdata) {
|
|||
state.compositor->WaitGetPoses(state.renderPoses, 16, NULL, 0);
|
||||
mat4_fromMat34(head, state.renderPoses[state.headsetIndex].mDeviceToAbsoluteTracking.m);
|
||||
|
||||
Color backgroundColor = lovrGraphicsGetBackgroundColor();
|
||||
lovrGraphicsPushLayer(&state.canvas, 1, false);
|
||||
lovrGraphicsClear(true, true, false, lovrGraphicsGetBackgroundColor(), 1., 0);
|
||||
lovrGraphicsClear(&backgroundColor, &(float) { 1. }, NULL);
|
||||
|
||||
for (HeadsetEye i = EYE_LEFT; i <= EYE_RIGHT; i++) {
|
||||
|
||||
|
|
Loading…
Reference in New Issue