Pipeline stack for graphics state; Simplify clearing;

This commit is contained in:
bjorn 2018-07-14 18:26:02 -07:00
parent 6933914650
commit b64489b020
8 changed files with 355 additions and 281 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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++) {