mirror of https://github.com/bjornbytes/lovr.git
Pass pipeline API;
This commit is contained in:
parent
bd970a5ec8
commit
bfa0d94f2d
|
@ -29,6 +29,7 @@ extern StringEntry lovrBufferLayout[];
|
|||
extern StringEntry lovrChannelLayout[];
|
||||
extern StringEntry lovrCompareMode[];
|
||||
extern StringEntry lovrCoordinateSpace[];
|
||||
extern StringEntry lovrCullMode[];
|
||||
extern StringEntry lovrDefaultAttribute[];
|
||||
extern StringEntry lovrDevice[];
|
||||
extern StringEntry lovrDeviceAxis[];
|
||||
|
|
|
@ -8,6 +8,23 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
StringEntry lovrBlendAlphaMode[] = {
|
||||
[BLEND_ALPHA_MULTIPLY] = ENTRY("alphamultiply"),
|
||||
[BLEND_PREMULTIPLIED] = ENTRY("premultiplied"),
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
StringEntry lovrBlendMode[] = {
|
||||
[BLEND_ALPHA] = ENTRY("alpha"),
|
||||
[BLEND_ADD] = ENTRY("add"),
|
||||
[BLEND_SUBTRACT] = ENTRY("subtract"),
|
||||
[BLEND_MULTIPLY] = ENTRY("multiply"),
|
||||
[BLEND_LIGHTEN] = ENTRY("lighten"),
|
||||
[BLEND_DARKEN] = ENTRY("darken"),
|
||||
[BLEND_SCREEN] = ENTRY("screen"),
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
StringEntry lovrBufferLayout[] = {
|
||||
[LAYOUT_PACKED] = ENTRY("packed"),
|
||||
[LAYOUT_STD140] = ENTRY("std140"),
|
||||
|
@ -26,6 +43,13 @@ StringEntry lovrCompareMode[] = {
|
|||
{ 0 }
|
||||
};
|
||||
|
||||
StringEntry lovrCullMode[] = {
|
||||
[CULL_NONE] = ENTRY("none"),
|
||||
[CULL_FRONT] = ENTRY("front"),
|
||||
[CULL_BACK] = ENTRY("back"),
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
StringEntry lovrFieldType[] = {
|
||||
[FIELD_I8x4] = ENTRY("i8x4"),
|
||||
[FIELD_U8x4] = ENTRY("u8x4"),
|
||||
|
@ -94,6 +118,17 @@ StringEntry lovrStackType[] = {
|
|||
{ 0 }
|
||||
};
|
||||
|
||||
StringEntry lovrStencilAction[] = {
|
||||
[STENCIL_KEEP] = ENTRY("keep"),
|
||||
[STENCIL_REPLACE] = ENTRY("replace"),
|
||||
[STENCIL_INCREMENT] = ENTRY("increment"),
|
||||
[STENCIL_DECREMENT] = ENTRY("decrement"),
|
||||
[STENCIL_INCREMENT_WRAP] = ENTRY("incrementwrap"),
|
||||
[STENCIL_DECREMENT_WRAP] = ENTRY("decrementwrap"),
|
||||
[STENCIL_INVERT] = ENTRY("invert"),
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
StringEntry lovrTextureFeature[] = {
|
||||
[0] = ENTRY("sample"),
|
||||
[1] = ENTRY("filter"),
|
||||
|
@ -122,6 +157,12 @@ StringEntry lovrTextureUsage[] = {
|
|||
{ 0 }
|
||||
};
|
||||
|
||||
StringEntry lovrWinding[] = {
|
||||
[WINDING_COUNTERCLOCKWISE] = ENTRY("counterclockwise"),
|
||||
[WINDING_CLOCKWISE] = ENTRY("clockwise"),
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
StringEntry lovrWrapMode[] = {
|
||||
[WRAP_CLAMP] = ENTRY("clamp"),
|
||||
[WRAP_REPEAT] = ENTRY("repeat"),
|
||||
|
|
|
@ -63,6 +63,126 @@ static int l_lovrPassTransform(lua_State* L) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrPassSetAlphaToCoverage(lua_State* L) {
|
||||
Pass* pass = luax_checktype(L, 1, Pass);
|
||||
lovrPassSetAlphaToCoverage(pass, lua_toboolean(L, 2));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrPassSetBlendMode(lua_State* L) {
|
||||
Pass* pass = luax_checktype(L, 1, Pass);
|
||||
BlendMode mode = lua_isnoneornil(L, 2) ? BLEND_NONE : luax_checkenum(L, 1, BlendMode, NULL);
|
||||
BlendAlphaMode alphaMode = luax_checkenum(L, 3, BlendAlphaMode, "alphamultiply");
|
||||
lovrPassSetBlendMode(pass, mode, alphaMode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrPassSetColorMask(lua_State* L) {
|
||||
Pass* pass = luax_checktype(L, 1, Pass);
|
||||
bool r = lua_toboolean(L, 2);
|
||||
bool g = lua_toboolean(L, 3);
|
||||
bool b = lua_toboolean(L, 4);
|
||||
bool a = lua_toboolean(L, 5);
|
||||
lovrPassSetColorMask(pass, r, g, b, a);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrPassSetCullMode(lua_State* L) {
|
||||
Pass* pass = luax_checktype(L, 1, Pass);
|
||||
CullMode mode = luax_checkenum(L, 2, CullMode, "none");
|
||||
lovrPassSetCullMode(pass, mode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrPassSetDepthTest(lua_State* L) {
|
||||
Pass* pass = luax_checktype(L, 1, Pass);
|
||||
CompareMode test = lua_isnoneornil(L, 2) ? COMPARE_NONE : luax_checkenum(L, 2, CompareMode, NULL);
|
||||
lovrPassSetDepthTest(pass, test);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrPassSetDepthWrite(lua_State* L) {
|
||||
Pass* pass = luax_checktype(L, 1, Pass);
|
||||
bool write = lua_toboolean(L, 2);
|
||||
lovrPassSetDepthWrite(pass, write);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrPassSetDepthOffset(lua_State* L) {
|
||||
Pass* pass = luax_checktype(L, 1, Pass);
|
||||
float offset = luax_optfloat(L, 2, 0.f);
|
||||
float sloped = luax_optfloat(L, 3, 0.f);
|
||||
lovrPassSetDepthOffset(pass, offset, sloped);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrPassSetDepthClamp(lua_State* L) {
|
||||
Pass* pass = luax_checktype(L, 1, Pass);
|
||||
bool clamp = lua_toboolean(L, 2);
|
||||
lovrPassSetDepthClamp(pass, clamp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrPassSetShader(lua_State* L) {
|
||||
Pass* pass = luax_checktype(L, 1, Pass);
|
||||
switch (lua_type(L, 2)) {
|
||||
case LUA_TNONE: case LUA_TNIL: lovrPassSetShader(pass, NULL); return 0;
|
||||
default: lovrPassSetShader(pass, luax_checktype(L, 2, Shader)); return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int l_lovrPassSetStencilTest(lua_State* L) {
|
||||
Pass* pass = luax_checktype(L, 1, Pass);
|
||||
if (lua_isnoneornil(L, 2)) {
|
||||
lovrPassSetStencilTest(pass, COMPARE_NONE, 0, 0xff);
|
||||
} else {
|
||||
CompareMode test = luax_checkenum(L, 2, CompareMode, NULL);
|
||||
uint8_t value = luaL_checkinteger(L, 3);
|
||||
uint8_t mask = luaL_optinteger(L, 4, 0xff);
|
||||
lovrPassSetStencilTest(pass, test, value, mask);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrPassSetStencilWrite(lua_State* L) {
|
||||
Pass* pass = luax_checktype(L, 1, Pass);
|
||||
StencilAction actions[3];
|
||||
if (lua_isnoneornil(L, 2)) {
|
||||
actions[0] = actions[1] = actions[2] = STENCIL_KEEP;
|
||||
lovrPassSetStencilWrite(pass, actions, 0, 0xff);
|
||||
} else {
|
||||
if (lua_istable(L, 2)) {
|
||||
lua_rawgeti(L, 2, 1);
|
||||
lua_rawgeti(L, 2, 2);
|
||||
lua_rawgeti(L, 2, 3);
|
||||
actions[0] = luax_checkenum(L, -3, StencilAction, NULL);
|
||||
actions[1] = luax_checkenum(L, -2, StencilAction, NULL);
|
||||
actions[2] = luax_checkenum(L, -1, StencilAction, NULL);
|
||||
lua_pop(L, 3);
|
||||
} else {
|
||||
actions[0] = actions[1] = actions[2] = luax_checkenum(L, 2, StencilAction, NULL);
|
||||
}
|
||||
uint8_t value = luaL_optinteger(L, 3, 1);
|
||||
uint8_t mask = luaL_optinteger(L, 4, 0xff);
|
||||
lovrPassSetStencilWrite(pass, actions, value, mask);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrPassSetWinding(lua_State* L) {
|
||||
Pass* pass = luax_checktype(L, 1, Pass);
|
||||
Winding winding = luax_checkenum(L, 2, Winding, NULL);
|
||||
lovrPassSetWinding(pass, winding);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrPassSetWireframe(lua_State* L) {
|
||||
Pass* pass = luax_checktype(L, 1, Pass);
|
||||
bool wireframe = lua_toboolean(L, 2);
|
||||
lovrPassSetWireframe(pass, wireframe);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const luaL_Reg lovrPass[] = {
|
||||
{ "getType", l_lovrPassGetType },
|
||||
{ "push", l_lovrPassPush },
|
||||
|
@ -72,5 +192,18 @@ const luaL_Reg lovrPass[] = {
|
|||
{ "rotate", l_lovrPassRotate },
|
||||
{ "scale", l_lovrPassScale },
|
||||
{ "transform", l_lovrPassTransform },
|
||||
{ "setAlphaToCoverage", l_lovrPassSetAlphaToCoverage },
|
||||
{ "setBlendMode", l_lovrPassSetBlendMode },
|
||||
{ "setColorMask", l_lovrPassSetColorMask },
|
||||
{ "setCullMode", l_lovrPassSetCullMode },
|
||||
{ "setDepthTest", l_lovrPassSetDepthTest },
|
||||
{ "setDepthWrite", l_lovrPassSetDepthWrite },
|
||||
{ "setDepthOffset", l_lovrPassSetDepthOffset },
|
||||
{ "setDepthClamp", l_lovrPassSetDepthClamp },
|
||||
{ "setShader", l_lovrPassSetShader },
|
||||
{ "setStencilTest", l_lovrPassSetStencilTest },
|
||||
{ "setStencilWrite", l_lovrPassSetStencilWrite },
|
||||
{ "setWinding", l_lovrPassSetWinding },
|
||||
{ "setWireframe", l_lovrPassSetWireframe },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
|
|
@ -42,13 +42,23 @@ struct Shader {
|
|||
ShaderInfo info;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
float color[4];
|
||||
Shader* shader;
|
||||
gpu_pipeline_info info;
|
||||
bool dirty;
|
||||
} Pipeline;
|
||||
|
||||
struct Pass {
|
||||
uint32_t ref;
|
||||
PassInfo info;
|
||||
gpu_stream* stream;
|
||||
float* transform;
|
||||
uint32_t transformIndex;
|
||||
float transforms[16][16];
|
||||
uint32_t transformIndex;
|
||||
Pipeline* pipeline;
|
||||
Pipeline pipelines[4];
|
||||
uint32_t pipelineIndex;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
|
@ -631,7 +641,6 @@ const PassInfo* lovrPassGetInfo(Pass* pass) {
|
|||
}
|
||||
|
||||
void lovrPassPush(Pass* pass, StackType stack) {
|
||||
lovrCheck(pass->info.type == PASS_RENDER, "This function can only be called on a render pass");
|
||||
if (stack == STACK_TRANSFORM) {
|
||||
pass->transform = pass->transforms[++pass->transformIndex];
|
||||
lovrCheck(pass->transformIndex < COUNTOF(pass->transforms), "Transform stack overflow (more pushes than pops?)");
|
||||
|
@ -640,7 +649,6 @@ void lovrPassPush(Pass* pass, StackType stack) {
|
|||
}
|
||||
|
||||
void lovrPassPop(Pass* pass, StackType stack) {
|
||||
lovrCheck(pass->info.type == PASS_RENDER, "This function can only be called on a render pass");
|
||||
if (stack == STACK_TRANSFORM) {
|
||||
pass->transform = pass->transforms[--pass->transformIndex];
|
||||
lovrCheck(pass->transformIndex < COUNTOF(pass->transforms), "Transform stack underflow (more pops than pushes?)");
|
||||
|
@ -667,6 +675,178 @@ void lovrPassTransform(Pass* pass, mat4 transform) {
|
|||
mat4_mul(pass->transform, transform);
|
||||
}
|
||||
|
||||
void lovrPassSetAlphaToCoverage(Pass* pass, bool enabled) {
|
||||
pass->pipeline->dirty |= enabled != pass->pipeline->info.multisample.alphaToCoverage;
|
||||
pass->pipeline->info.multisample.alphaToCoverage = enabled;
|
||||
}
|
||||
|
||||
void lovrPassSetBlendMode(Pass* pass, BlendMode mode, BlendAlphaMode alphaMode) {
|
||||
if (mode == BLEND_NONE) {
|
||||
pass->pipeline->dirty |= pass->pipeline->info.color[0].blend.enabled;
|
||||
memset(&pass->pipeline->info.color[0].blend, 0, sizeof(gpu_blend_state));
|
||||
return;
|
||||
}
|
||||
|
||||
gpu_blend_state* blend = &pass->pipeline->info.color[0].blend;
|
||||
|
||||
switch (mode) {
|
||||
case BLEND_ALPHA:
|
||||
blend->color.src = GPU_BLEND_SRC_ALPHA;
|
||||
blend->color.dst = GPU_BLEND_ONE_MINUS_SRC_ALPHA;
|
||||
blend->color.op = GPU_BLEND_ADD;
|
||||
blend->alpha.src = GPU_BLEND_ONE;
|
||||
blend->alpha.dst = GPU_BLEND_ONE_MINUS_SRC_ALPHA;
|
||||
blend->alpha.op = GPU_BLEND_ADD;
|
||||
break;
|
||||
case BLEND_ADD:
|
||||
blend->color.src = GPU_BLEND_SRC_ALPHA;
|
||||
blend->color.dst = GPU_BLEND_ONE;
|
||||
blend->color.op = GPU_BLEND_ADD;
|
||||
blend->alpha.src = GPU_BLEND_ZERO;
|
||||
blend->alpha.dst = GPU_BLEND_ONE;
|
||||
blend->alpha.op = GPU_BLEND_ADD;
|
||||
break;
|
||||
case BLEND_SUBTRACT:
|
||||
blend->color.src = GPU_BLEND_SRC_ALPHA;
|
||||
blend->color.dst = GPU_BLEND_ONE;
|
||||
blend->color.op = GPU_BLEND_RSUB;
|
||||
blend->alpha.src = GPU_BLEND_ZERO;
|
||||
blend->alpha.dst = GPU_BLEND_ONE;
|
||||
blend->alpha.op = GPU_BLEND_RSUB;
|
||||
break;
|
||||
case BLEND_MULTIPLY:
|
||||
blend->color.src = GPU_BLEND_DST_COLOR;
|
||||
blend->color.dst = GPU_BLEND_ZERO;
|
||||
blend->color.op = GPU_BLEND_ADD;
|
||||
blend->alpha.src = GPU_BLEND_DST_COLOR;
|
||||
blend->alpha.dst = GPU_BLEND_ZERO;
|
||||
blend->alpha.op = GPU_BLEND_ADD;
|
||||
break;
|
||||
case BLEND_LIGHTEN:
|
||||
blend->color.src = GPU_BLEND_SRC_ALPHA;
|
||||
blend->color.dst = GPU_BLEND_ZERO;
|
||||
blend->color.op = GPU_BLEND_MAX;
|
||||
blend->alpha.src = GPU_BLEND_ONE;
|
||||
blend->alpha.dst = GPU_BLEND_ZERO;
|
||||
blend->alpha.op = GPU_BLEND_MAX;
|
||||
break;
|
||||
case BLEND_DARKEN:
|
||||
blend->color.src = GPU_BLEND_SRC_ALPHA;
|
||||
blend->color.dst = GPU_BLEND_ZERO;
|
||||
blend->color.op = GPU_BLEND_MIN;
|
||||
blend->alpha.src = GPU_BLEND_ONE;
|
||||
blend->alpha.dst = GPU_BLEND_ZERO;
|
||||
blend->alpha.op = GPU_BLEND_MIN;
|
||||
break;
|
||||
case BLEND_SCREEN:
|
||||
blend->color.src = GPU_BLEND_SRC_ALPHA;
|
||||
blend->color.dst = GPU_BLEND_ONE_MINUS_SRC_COLOR;
|
||||
blend->color.op = GPU_BLEND_ADD;
|
||||
blend->alpha.src = GPU_BLEND_ONE;
|
||||
blend->alpha.dst = GPU_BLEND_ONE_MINUS_SRC_COLOR;
|
||||
blend->alpha.op = GPU_BLEND_ADD;
|
||||
break;
|
||||
default: lovrUnreachable();
|
||||
};
|
||||
|
||||
if (alphaMode == BLEND_PREMULTIPLIED && mode != BLEND_MULTIPLY) {
|
||||
blend->color.src = GPU_BLEND_ONE;
|
||||
}
|
||||
|
||||
blend->enabled = true;
|
||||
pass->pipeline->dirty = true;
|
||||
}
|
||||
|
||||
void lovrPassSetColorMask(Pass* pass, bool r, bool g, bool b, bool a) {
|
||||
uint8_t mask = (r << 0) | (g << 1) | (b << 2) | (a << 3);
|
||||
pass->pipeline->dirty |= pass->pipeline->info.color[0].mask != mask;
|
||||
pass->pipeline->info.color[0].mask = mask;
|
||||
}
|
||||
|
||||
void lovrPassSetCullMode(Pass* pass, CullMode mode) {
|
||||
pass->pipeline->dirty |= pass->pipeline->info.rasterizer.cullMode != (gpu_cull_mode) mode;
|
||||
pass->pipeline->info.rasterizer.cullMode = (gpu_cull_mode) mode;
|
||||
}
|
||||
|
||||
void lovrPassSetDepthTest(Pass* pass, CompareMode test) {
|
||||
pass->pipeline->dirty |= pass->pipeline->info.depth.test != (gpu_compare_mode) test;
|
||||
pass->pipeline->info.depth.test = (gpu_compare_mode) test;
|
||||
}
|
||||
|
||||
void lovrPassSetDepthWrite(Pass* pass, bool write) {
|
||||
pass->pipeline->dirty |= pass->pipeline->info.depth.write != write;
|
||||
pass->pipeline->info.depth.write = write;
|
||||
}
|
||||
|
||||
void lovrPassSetDepthOffset(Pass* pass, float offset, float sloped) {
|
||||
pass->pipeline->info.rasterizer.depthOffset = offset;
|
||||
pass->pipeline->info.rasterizer.depthOffsetSloped = sloped;
|
||||
pass->pipeline->dirty = true;
|
||||
}
|
||||
|
||||
void lovrPassSetDepthClamp(Pass* pass, bool clamp) {
|
||||
if (state.features.depthClamp) {
|
||||
pass->pipeline->dirty |= pass->pipeline->info.rasterizer.depthClamp != clamp;
|
||||
pass->pipeline->info.rasterizer.depthClamp = clamp;
|
||||
}
|
||||
}
|
||||
|
||||
void lovrPassSetShader(Pass* pass, Shader* shader) {
|
||||
lovrRetain(shader);
|
||||
lovrRelease(pass->pipeline->shader, lovrShaderDestroy);
|
||||
|
||||
pass->pipeline->shader = shader;
|
||||
pass->pipeline->info.shader = shader ? shader->gpu : NULL;
|
||||
pass->pipeline->dirty = true;
|
||||
}
|
||||
|
||||
void lovrPassSetStencilTest(Pass* pass, CompareMode test, uint8_t value, uint8_t mask) {
|
||||
bool hasReplace = false;
|
||||
hasReplace |= pass->pipeline->info.stencil.failOp == GPU_STENCIL_REPLACE;
|
||||
hasReplace |= pass->pipeline->info.stencil.depthFailOp == GPU_STENCIL_REPLACE;
|
||||
hasReplace |= pass->pipeline->info.stencil.passOp == GPU_STENCIL_REPLACE;
|
||||
if (hasReplace && test != COMPARE_NONE) {
|
||||
lovrCheck(value == pass->pipeline->info.stencil.value, "When stencil write is 'replace' and stencil test is active, their values must match");
|
||||
}
|
||||
switch (test) { // (Reversed compare mode)
|
||||
case COMPARE_NONE: default: pass->pipeline->info.stencil.test = GPU_COMPARE_NONE; break;
|
||||
case COMPARE_EQUAL: pass->pipeline->info.stencil.test = GPU_COMPARE_EQUAL; break;
|
||||
case COMPARE_NEQUAL: pass->pipeline->info.stencil.test = GPU_COMPARE_NEQUAL; break;
|
||||
case COMPARE_LESS: pass->pipeline->info.stencil.test = GPU_COMPARE_GREATER; break;
|
||||
case COMPARE_LEQUAL: pass->pipeline->info.stencil.test = GPU_COMPARE_GEQUAL; break;
|
||||
case COMPARE_GREATER: pass->pipeline->info.stencil.test = GPU_COMPARE_LESS; break;
|
||||
case COMPARE_GEQUAL: pass->pipeline->info.stencil.test = GPU_COMPARE_LEQUAL; break;
|
||||
}
|
||||
pass->pipeline->info.stencil.testMask = mask;
|
||||
if (test != COMPARE_NONE) pass->pipeline->info.stencil.value = value;
|
||||
pass->pipeline->dirty = true;
|
||||
}
|
||||
|
||||
void lovrPassSetStencilWrite(Pass* pass, StencilAction actions[3], uint8_t value, uint8_t mask) {
|
||||
bool hasReplace = actions[0] == STENCIL_REPLACE || actions[1] == STENCIL_REPLACE || actions[2] == STENCIL_REPLACE;
|
||||
if (hasReplace && pass->pipeline->info.stencil.test != GPU_COMPARE_NONE) {
|
||||
lovrCheck(value == pass->pipeline->info.stencil.value, "When stencil write is 'replace' and stencil test is active, their values must match");
|
||||
}
|
||||
pass->pipeline->info.stencil.failOp = (gpu_stencil_op) actions[0];
|
||||
pass->pipeline->info.stencil.depthFailOp = (gpu_stencil_op) actions[1];
|
||||
pass->pipeline->info.stencil.passOp = (gpu_stencil_op) actions[2];
|
||||
pass->pipeline->info.stencil.writeMask = mask;
|
||||
if (hasReplace) pass->pipeline->info.stencil.value = value;
|
||||
pass->pipeline->dirty = true;
|
||||
}
|
||||
|
||||
void lovrPassSetWinding(Pass* pass, Winding winding) {
|
||||
pass->pipeline->dirty |= pass->pipeline->info.rasterizer.winding != (gpu_winding) winding;
|
||||
pass->pipeline->info.rasterizer.winding = (gpu_winding) winding;
|
||||
}
|
||||
|
||||
void lovrPassSetWireframe(Pass* pass, bool wireframe) {
|
||||
if (state.features.wireframe) {
|
||||
pass->pipeline->dirty |= pass->pipeline->info.rasterizer.wireframe != (gpu_winding) wireframe;
|
||||
pass->pipeline->info.rasterizer.wireframe = wireframe;
|
||||
}
|
||||
}
|
||||
|
||||
// Helpers
|
||||
|
||||
static void* tempAlloc(size_t size) {
|
||||
|
|
|
@ -275,6 +275,44 @@ typedef enum {
|
|||
STACK_PIPELINE
|
||||
} StackType;
|
||||
|
||||
typedef enum {
|
||||
BLEND_ALPHA_MULTIPLY,
|
||||
BLEND_PREMULTIPLIED
|
||||
} BlendAlphaMode;
|
||||
|
||||
typedef enum {
|
||||
BLEND_ALPHA,
|
||||
BLEND_ADD,
|
||||
BLEND_SUBTRACT,
|
||||
BLEND_MULTIPLY,
|
||||
BLEND_LIGHTEN,
|
||||
BLEND_DARKEN,
|
||||
BLEND_SCREEN,
|
||||
BLEND_NONE
|
||||
} BlendMode;
|
||||
|
||||
typedef enum {
|
||||
CULL_NONE,
|
||||
CULL_FRONT,
|
||||
CULL_BACK
|
||||
} CullMode;
|
||||
|
||||
typedef enum {
|
||||
STENCIL_KEEP,
|
||||
STENCIL_ZERO,
|
||||
STENCIL_REPLACE,
|
||||
STENCIL_INCREMENT,
|
||||
STENCIL_DECREMENT,
|
||||
STENCIL_INCREMENT_WRAP,
|
||||
STENCIL_DECREMENT_WRAP,
|
||||
STENCIL_INVERT
|
||||
} StencilAction;
|
||||
|
||||
typedef enum {
|
||||
WINDING_COUNTERCLOCKWISE,
|
||||
WINDING_CLOCKWISE
|
||||
} Winding;
|
||||
|
||||
typedef enum {
|
||||
LOAD_KEEP,
|
||||
LOAD_CLEAR,
|
||||
|
@ -314,3 +352,16 @@ void lovrPassTranslate(Pass* pass, float* translation);
|
|||
void lovrPassRotate(Pass* pass, float* rotation);
|
||||
void lovrPassScale(Pass* pass, float* scale);
|
||||
void lovrPassTransform(Pass* pass, float* transform);
|
||||
void lovrPassSetAlphaToCoverage(Pass* pass, bool enabled);
|
||||
void lovrPassSetBlendMode(Pass* pass, BlendMode mode, BlendAlphaMode alphaMode);
|
||||
void lovrPassSetColorMask(Pass* pass, bool r, bool g, bool b, bool a);
|
||||
void lovrPassSetCullMode(Pass* pass, CullMode mode);
|
||||
void lovrPassSetDepthTest(Pass* pass, CompareMode test);
|
||||
void lovrPassSetDepthWrite(Pass* pass, bool write);
|
||||
void lovrPassSetDepthOffset(Pass* pass, float offset, float sloped);
|
||||
void lovrPassSetDepthClamp(Pass* pass, bool clamp);
|
||||
void lovrPassSetShader(Pass* pass, Shader* shader);
|
||||
void lovrPassSetStencilTest(Pass* pass, CompareMode test, uint8_t value, uint8_t mask);
|
||||
void lovrPassSetStencilWrite(Pass* pass, StencilAction actions[3], uint8_t value, uint8_t mask);
|
||||
void lovrPassSetWinding(Pass* pass, Winding winding);
|
||||
void lovrPassSetWireframe(Pass* pass, bool wireframe);
|
||||
|
|
Loading…
Reference in New Issue