diff options
author | chai <chaifix@163.com> | 2019-12-21 22:24:15 +0800 |
---|---|---|
committer | chai <chaifix@163.com> | 2019-12-21 22:24:15 +0800 |
commit | ec111247c614663d8231245a17c314b9b8b4a28c (patch) | |
tree | a66058508161da488371c90316865ae850b8be15 /src/core/device.c | |
parent | c3f45735ecfab6e567be371758f21395e92dfef6 (diff) |
*misc
Diffstat (limited to 'src/core/device.c')
-rw-r--r-- | src/core/device.c | 396 |
1 files changed, 289 insertions, 107 deletions
diff --git a/src/core/device.c b/src/core/device.c index b5468cd..dc4d80e 100644 --- a/src/core/device.c +++ b/src/core/device.c @@ -3,93 +3,111 @@ #include "clip.h" #include "shader.h" #include "../util/assert.h" +#include "framebuffer.h" +#include "depth.h" +#include "stencil.h" ssr_Config config; -typedef enum ssr_VertexAttrMask { +typedef enum { VERTEXATTR_POS = 1, VERTEXATTR_COLOR = 1 << 1, VERTEXATTR_UV = 1 << 2, VERTEXATTR_NORMAL = 1 << 3, } ssr_VertexAttrMask; -typedef struct VertexAttr { +typedef struct { int start; int offset; } VertexAttr; -/* -** 状态结构 -*/ static struct { - /* MVP矩阵栈 */ Mat4 matrices[3][MATRIXDEPTH]; - uint matrixtop[3]; - ssr_MatrixMode matrixmode; + uint matrix_top[3]; + ssr_MatrixMode matrix_mode; + + Vec4 viewport; - /* 屏幕缓冲区 */ Color* target; - Color* framebuffer; - uint buffersize; /*framebuffer size in bytess*/ + Color* color_buffer; /*screen color buffer*/ + uint buffer_size; + + float* depth_buffer; + float* depth_screen_buffer; + DepthFunc depth_func; - /* zbuffer 深度会被映射到0~1的非线性区间*/ - float* zbuffer; + byte* stencil_buffer; + byte* stencil_screen_buffer; + byte stencil_read_mask; + uint stencil_ref; + byte stencil_write_mask; + StencilFunc stencil_func; + StencilOp stencil_failop, stencil_dpfailop, stencil_passop; - /* 顶点数据 */ - Vert* verts; uint nverts; - uint* indices; uint nprims; + Vert* verts; uint vert_count; + uint* indices; uint prim_count; - /* shader program */ Program* program; UniformCollection uniforms; - /* texture relavent */ - FilterMode filtermode; - WrapMode wrapmode; - - //FrameBuffer* framebuffer; + FrameBuffer* frame_buffer; uint enable; struct { ssr_BlendFactor src; ssr_BlendFactor dst; - } blendfactor; + } blend_factor; } state; -/* -** MVP矩阵栈 -*/ -#define MATRIXTOP state.matrixtop[state.matrixmode] -#define MATRIX state.matrices[state.matrixmode][MATRIXTOP] -#define MATRIXSTACK state.matrices[state.matrixmode] +#define MATRIXTOP state.matrix_top[state.matrix_mode] +#define MATRIX state.matrices[state.matrix_mode][MATRIXTOP] +#define MATRIXSTACK state.matrices[state.matrix_mode] -#define GETMATRIX(MODE) state.matrices[MODE][state.matrixtop[MODE]] +#define GETMATRIX(MODE) state.matrices[MODE][state.matrix_top[MODE]] -#define BUFFER (state.framebuffer) +#define BUFFER (state.color_buffer) +/*topleft*/ #define contains(x, y, l, r, t, b) (x >= l && x <= r && y <= b && y >= t) void ssr_init(ssr_Config* conf) { config = *conf; - ssrM_zero(state.matrixtop, sizeof(state.matrixtop)); + ssrM_zero(state.matrix_top, sizeof(state.matrix_top)); + state.target = conf->target; + + int size = config.width * config.height; + if (config.dbuffer) { - state.framebuffer = ssrM_newvector(Color, config.width * config.height); + state.color_buffer = ssrM_newvector(Color, size); } else { - state.framebuffer = conf->target; + state.color_buffer = conf->target; } - state.buffersize = sizeof(Color) * config.width * config.height; - state.zbuffer = ssrM_newvector(float, config.width * config.height); - //memset(state.zbuffer, 0xff, sizeof(uint)*config.width*config.height); + state.buffer_size = sizeof(Color) * size; + + state.depth_screen_buffer = ssrM_newvector(float, size); + state.depth_buffer = state.depth_screen_buffer; + state.depth_func = depth_leuqal; + + state.blend_factor.src = BLEND_SRC_ALPHA; + state.blend_factor.dst = BLEND_ONE_MINUS_SRC_ALPHA; + + state.stencil_screen_buffer = ssrM_newvector(byte, size); + state.stencil_buffer = state.stencil_screen_buffer; + state.stencil_ref = 1; + state.stencil_read_mask = 1; + state.stencil_write_mask = 0; + state.stencil_func = stencil_equal; + state.stencil_failop = stencilop_keep; + state.stencil_dpfailop = stencilop_keep; + state.stencil_passop = stencilop_replace; - state.filtermode = FILTERMODE_POINT; - state.wrapmode = WRAPMODE_CLAMP; + state.frame_buffer = NULL; - state.blendfactor.src = BLEND_SRC_ALPHA; - state.blendfactor.dst = BLEND_ONE_MINUS_SRC_ALPHA; + ssr_viewport(0, config.width, config.height, 0); } float ssr_getaspect() { @@ -104,44 +122,38 @@ int ssr_getframebufferh() { return config.height; } -void ssr_setfiltermode(FilterMode filter_mode) { - state.filtermode = filter_mode; -} - -void ssr_setwrapmode(WrapMode wrap_mode) { - state.wrapmode = wrap_mode; -} - -FilterMode ssr_getfiltermode() { - return state.filtermode; -} - -WrapMode ssr_getwrapmode() { - return state.wrapmode; -} - void ssr_bindframebuffer(FrameBuffer* fbo) { - + ssr_assert(fbo); + state.frame_buffer = fbo; + state.depth_buffer = fbo->depth_buffer; + state.stencil_buffer = fbo->stencil_buffer; } void ssr_unbindframebuffer() { - + state.frame_buffer = NULL; + state.depth_buffer = state.depth_screen_buffer; + state.stencil_buffer = state.stencil_screen_buffer; } void ssr_setblendfunc(ssr_BlendFactor sfactor, ssr_BlendFactor dfactor) { - state.blendfactor.src = sfactor; - state.blendfactor.dst = dfactor; + state.blend_factor.src = sfactor; + state.blend_factor.dst = dfactor; +} + +void ssrU_blendscreencolor(uint x, uint y, Color32* src) { + Color c = state.color_buffer[x + y * config.width]; + Color32 dst; color_tocolor32(c, &dst); + ssr_blend(src, &dst, src); } void ssr_matrixmode(ssr_MatrixMode mode) { - state.matrixmode = mode; + state.matrix_mode = mode; } void ssr_loadidentity() { mat4_setidentity(&MATRIX); } -/* push进去之后会将最新的拷贝一份放在栈顶 */ void ssr_pushmatrix() { ssr_assert(MATRIXTOP < MATRIXDEPTH - 1); ++MATRIXTOP; @@ -152,7 +164,6 @@ void ssr_popmatrix() { MATRIXTOP = clamp(--MATRIXTOP, 0, MATRIXDEPTH - 1); } -/*用来做world->view的变换矩阵*/ /*http://warmcat.org/chai/blog/?p=559*/ void ssr_lookat(Vec3* pos, Vec3* target, Vec3* up) { ssr_assert(pos && target && up); @@ -171,7 +182,6 @@ void ssr_lookat(Vec3* pos, Vec3* target, Vec3* up) { mat4_multiply(&MATRIX, &m, &MATRIX); } -/* scalematrix * matrix */ void ssr_scale(float sx, float sy, float sz) { Vec3 scale = { sx, sy, sz }; mat4_scale(&MATRIX, &scale, &MATRIX); @@ -227,6 +237,10 @@ bool ssr_isenable(uint mask) { } void ssr_viewport(float l, float r, float b, float t) { + state.viewport.x = l; + state.viewport.y = r; + state.viewport.z = b; + state.viewport.w = t; } void ssr_ortho(float l, float r, float b, float t, float n, float f) { @@ -236,13 +250,14 @@ void ssr_ortho(float l, float r, float b, float t, float n, float f) { } void ssr_frustum(float l, float r, float b, float t, float n, float f) { + ssr_assert(n > 0 && f > 0 && f > n); Mat4 m; mat4_setfrustum(l, r, b, t, n, f, &m); mat4_multiply(&MATRIX, &m, &MATRIX); } -/*注意这里nf都要是正数,代表距离*/ void ssr_perspective(float fov, float aspect, float n, float f) { + ssr_assert(n > 0 && f > 0 && f > n); Mat4 m; mat4_setperspective(fov, aspect, n, f, &m); mat4_multiply(&MATRIX, &m, &MATRIX); @@ -250,30 +265,60 @@ void ssr_perspective(float fov, float aspect, float n, float f) { void ssr_present() { if (config.dbuffer) { - memcpy(state.target, state.framebuffer, state.buffersize); + memcpy(state.target, state.color_buffer, state.buffer_size); } } -void ssr_clearcolor(Color color) { +static void _clearscreen(Color color) { if (color == 0x00) { - memset(state.framebuffer, 0, state.buffersize); + memset(state.color_buffer, 0, state.buffer_size); } else { uint size = config.width * sizeof(Color); - for(int x = 0; x < config.width; ++x) - state.framebuffer[x] = color; + for (int x = 0; x < config.width; ++x) + state.color_buffer[x] = color; for (int y = 1; y < config.height; ++y) - ssrM_copy(&state.framebuffer[config.width * y], state.framebuffer, size); + ssrM_copy(&state.color_buffer[config.width * y], state.color_buffer, size); + } +} + +static void _clearcolorbuffer(Color32 color) { + Texture* rt; + Color32* pixels; + for (int i = 0; i < RENDER_TARGET_COUNT; ++i) { + rt = state.frame_buffer->render_textures[i]; + if (rt == NULL) continue; + pixels = rt->pixels; + uint size = rt->width * sizeof(Color32); + for (int x = 0; x < rt->width; ++x) + pixels[x] = color; + for (int y = 1; y < rt->height; ++y) + ssrM_copy(&pixels[rt->width * y], pixels, size); + } +} + +void ssr_clearcolor(Color color) { + if (state.frame_buffer == NULL) { + _clearscreen(color); + } + else { + Color32 c; color_tocolor32(color, &c); + _clearcolorbuffer(c); } } void ssr_cleardepth() { - //memset(state.zbuffer, 0xff, sizeof(uint)*config.width*config.height); + ssr_assert(state.depth_buffer); for (int i = 0; i < config.width * config.height; ++i) { - state.zbuffer[i] = 1; + state.depth_buffer[i] = 1; } } +void ssr_clearstencil(byte val) { + ssr_assert(state.stencil_buffer); + memset(state.stencil_buffer, val, config.width * config.height); +} + void ssr_putpoint(uint screenx, uint screeny, Color color) { if (!contains(screenx, screeny, 0, config.width - 1, 0, config.height - 1)) return; @@ -291,26 +336,46 @@ Color ssr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char } bool ssr_testdepth(uint x, uint y, float depth){ + ssr_assert(state.depth_buffer); uint off = x + y * config.width; - return state.zbuffer[off] >= depth; + return state.depth_func(depth, state.depth_buffer[off]); } void ssr_writedepth(uint x, uint y, float depth) { + ssr_assert(state.depth_buffer); uint off = x + y * config.width; - state.zbuffer[off] = depth; + state.depth_buffer[off] = depth; +} + +void ssr_setdepthfunc(ssr_DepthFunc func) { + switch (func) + { + case DEPTHFUNC_ALWAYS: state.depth_func = depth_always; break; + case DEPTHFUNC_NEVER: state.depth_func = depth_never; break; + case DEPTHFUNC_LESS: state.depth_func = depth_less; break; + case DEPTHFUNC_EQUAL: state.depth_func = depth_equal; break; + case DEPTHFUNC_LEQUAL: state.depth_func = depth_leuqal; break; + case DEPTHFUNC_GREATER: state.depth_func = depth_greater; break; + case DEPTHFUNC_NOTEQUAL: state.depth_func = depth_notequal; break; + case DEPTHFUNC_GEQUAL: state.depth_func = depth_gequer; break; + default: ssr_assert(FALSE); + } } void ssrU_viewport(Vec2* p, Vec2* out) { ssr_assert(p && out); - float halfw = config.width / 2.f, halfh = config.height / 2.f; - //out->x = (int)round(p->x * halfw + halfw); - //out->y = (int)round(halfh - p->y * halfh); - out->x = (int)round((p->x + 1) * (halfw - 0.5f)); - out->y = (int)round((1 - p->y) * (halfh - 0.5f)); + float l = state.viewport.x, + r = state.viewport.y, + b = state.viewport.z, + t = state.viewport.w, + w2 = (r - l) * 0.5f, + h2 = (b - t) * 0.5f; + out->x = (int)round((p->x + 1) * (w2 - 0.5f) + l); + out->y = (int)round((1 - p->y) * (h2 - 0.5f) + t); } void ssr_blend(Color32* src, Color32* dst, Color32* out) { - ssrU_blend(state.blendfactor.src, state.blendfactor.dst, src, dst, out); + ssrU_blend(state.blend_factor.src, state.blend_factor.dst, src, dst, out); } static _blend(ssr_BlendFactor factor, Color32* src, Color32* dst, Color32* out) { @@ -391,18 +456,12 @@ void ssrU_blend( out->a = src->a + dst->a; } -Color32 ssr_getfbocolor(uint x, uint y) { - Color c = state.framebuffer[x + y * config.width]; - Color32 c32; color_tocolor32(c, &c32); - return c32; -} - -void ssr_bindvertices(Vert* verts, int nverts, uint* indices, int nprims) { +void ssr_bindvertices(Vert* verts, int vert_count, uint* indices, int prim_count) { ssr_assert(verts && indices); state.verts = verts; - state.nverts = nverts; + state.vert_count = vert_count; state.indices = indices; - state.nprims = nprims; + state.prim_count = prim_count; } void ssr_useprogram(Program* program) { @@ -444,30 +503,31 @@ void ssr_draw(ssr_PrimitiveType primitive) { /*prepare registers if necessary*/ if (use_extra_varyings) { ssrS_openregs(varying_flag); - ssrS_setregisters(state.nverts); + ssrS_setregisters(state.vert_count); ssrS_setactiveregr(); } /*resize clipping coords buffer*/ - if (clip_coords.length < state.nverts) { + if (clip_coords.length < state.vert_count) { ssrM_resizevector( Vec4, clip_coords.coords, clip_coords.length, - state.nverts, + state.vert_count, FALSE ); } /*vertex operation*/ - for (int i = 0; i < state.nverts; ++i) { + VertexShader vert_shader = state.program->vertexshader; + for (int i = 0; i < state.vert_count; ++i) { Vert* vert = &state.verts[i]; ssr_vert_in.vertex = vert; /*set register pointers*/ if (use_extra_varyings) { ssrS_setupregisterpointers(vert->index); } - state.program->vertexshader(&state.uniforms, &ssr_vert_in, &clip_coords.coords[i]); + vert_shader(&state.uniforms, &ssr_vert_in, &clip_coords.coords[i]); } /*set register pointer to frag-in*/ @@ -479,9 +539,8 @@ void ssr_draw(ssr_PrimitiveType primitive) { if (primitive == PRIMITIVE_TRIANGLE) { uint i0, i1, i2; Vec4 *h0, *h1, *h2; - Vert *v0, *v1, *v2; bool reset_active_reg = FALSE; - for (int i = 0; i < state.nprims; ++i) { + for (int i = 0; i < state.prim_count; ++i) { i0 = state.indices[i * 3]; i1 = state.indices[i * 3 + 1]; i2 = state.indices[i * 3 + 2]; @@ -490,10 +549,6 @@ void ssr_draw(ssr_PrimitiveType primitive) { h1 = &clip_coords.coords[i1], h2 = &clip_coords.coords[i2]; - v0 = &state.verts[i0]; - v1 = &state.verts[i1]; - v2 = &state.verts[i2]; - /*back face culling*/ if (ssr_isenable(ENABLE_BACKFACECULL)) { float w0 = 1 / h0->w, w1 = 1 / h1->w, w2 = 1 / h2->w; @@ -508,7 +563,7 @@ void ssr_draw(ssr_PrimitiveType primitive) { } /*clipping*/ - bool clipped = clip_triangle(h0, h1, h2, v0, v1, v2, varying_flag, &clip_buffer); + bool clipped = clip_triangle(h0, h1, h2, i0, i1, i2, varying_flag, &clip_buffer); /*rasterization*/ if (!clipped) { @@ -516,7 +571,7 @@ void ssr_draw(ssr_PrimitiveType primitive) { reset_active_reg = FALSE; ssrS_setactiveregr(); } - ssrR_triangle(h0, h1, h2, v0, v1, v2, state.program, &state.uniforms); + ssrR_triangle(h0, h1, h2, i0, i1, i2, state.program, &state.uniforms); } else { if (!reset_active_reg) { reset_active_reg = TRUE; @@ -528,14 +583,14 @@ void ssr_draw(ssr_PrimitiveType primitive) { vt1 = &clip_buffer.vertices[i]; vt2 = &clip_buffer.vertices[i + 1]; h0 = &vt0->clip_coord; h1 = &vt1->clip_coord; h2 = &vt2->clip_coord; - v0 = &vt0->vertex; v1 = &vt1->vertex; v2 = &vt2->vertex; - ssrR_triangle(h0, h1, h2, v0, v1, v2, state.program, &state.uniforms); + i0 = vt0->index; i1 = vt1->index; i2 = vt2->index; + ssrR_triangle(h0, h1, h2, i0, i1, i2, state.program, &state.uniforms); } } } } } else if (primitive == PRIMITIVE_POINT) { - + } else if (primitive == PRIMITIVE_LINE) { } @@ -574,3 +629,130 @@ void ssr_setuniformtex(uint idx, Texture* tex) { void ssr_setuniformu(void* userdata) { state.uniforms.userdata = userdata; } + +bool ssr_teststencil(uint x, uint y, bool pass_depth_test) { + int index = x + config.width * y; + byte mask = state.stencil_read_mask; + byte val = state.stencil_buffer[index]; + return state.stencil_func(val, state.stencil_ref); +} + +void ssr_writestencil(uint x, uint y, bool pass_depth_test, bool pass_stencil_test) { + byte write_mask = state.stencil_write_mask; + if (write_mask == 0) return;/*dont write*/ + int index = x + config.width * y; + byte read_mask = state.stencil_read_mask; + byte val = state.stencil_buffer[index]; + if (pass_stencil_test && pass_depth_test) { + val = state.stencil_passop(val & read_mask, state.stencil_ref & read_mask); + } + else if (pass_stencil_test && !pass_depth_test) { + val = state.stencil_dpfailop(val & read_mask, state.stencil_ref & read_mask); + } + else if (!pass_stencil_test) { + val = state.stencil_failop(val & read_mask, state.stencil_ref & read_mask); + } + /*https://stackoverflow.com/questions/31660747/what-exactly-does-glstencilmask-do*/ + state.stencil_buffer[index] &= ~write_mask; + state.stencil_buffer[index] |= (val & write_mask); +} + +void ssr_setstencilfunc(ssr_StencilFunc func, byte ref, uint mask) { + switch (func) + { + case STENCILFUNC_ALWAYS: state.stencil_func = stencil_always; break; + case STENCILFUNC_NEVER: state.stencil_func = stencil_never; break; + case STENCILFUNC_LESS: state.stencil_func = stencil_less; break; + case STENCILFUNC_EQUAL: state.stencil_func = stencil_equal; break; + case STENCILFUNC_LEQUAL: state.stencil_func = stencil_leuqal; break; + case STENCILFUNC_GREATER: state.stencil_func = stencil_greater; break; + case STENCILFUNC_NOTEQUAL: state.stencil_func = stencil_notequal; break; + case STENCILFUNC_GEQUAL: state.stencil_func = stencil_gequer; break; + default: ssr_assert(FALSE); + } + state.stencil_ref = ref; + state.stencil_read_mask = mask; +} + +static void setstencilop(ssr_StencilOp v, StencilOp* op) { + switch (v) { + case STENCILOP_KEEP: *op = stencilop_keep; break; + case STENCILOP_ZERO: *op = stencilop_zero; break; + case STENCILOP_REPLACE: *op = stencilop_replace; break; + case STENCILOP_INCR: *op = stencilop_incr; break; + case STENCILOP_INCR_WRAP: *op = stencilop_incrwrap; break; + case STENCILOP_DECR: *op = stencilop_decr; break; + case STENCILOP_DECR_WRAP: *op = stencilop_decrwrap; break; + case STENCILOP_INVERT: *op = stencilop_invert; break; + default: + ssr_assert(FALSE); + } +} + +void ssr_setstencilop(ssr_StencilOp fail, ssr_StencilOp dpfail, ssr_StencilOp pass) { + setstencilop(fail, &state.stencil_failop); + setstencilop(dpfail, &state.stencil_dpfailop); + setstencilop(pass, &state.stencil_passop); +} + +void ssr_setstencilmask(byte mask) { + state.stencil_write_mask = mask; +} + +bool ssr_iswritesencil() { + return state.stencil_write_mask != 0x00; +} + +void ssr_blendandputpoint(int x, int y, bool blend) { + if (!state.frame_buffer) { /*directly onto screen*/ + if (blend) { + ssrU_blendscreencolor(x, y, out_color[0]); + } + color32_saturate(out_color[0]); + ssr_putpoint32(x, y, out_color[0]); + } + else { /*onto framebuffer color buffer*/ + Color32 *src, *dst; + Texture* rt; + for (int i = 0; i < RENDER_TARGET_COUNT; ++i) { + rt = state.frame_buffer->render_textures[i]; + if (rt == NULL || !contains(x, y, 0, rt->width, 0, rt->height)) + continue; + dst = &rt->pixels[x + y * rt->width]; + src = out_color[i]; + if (blend) + ssr_blend(src, dst, src); + *dst = *src; + } + } +} + +FrameBuffer* fbo_create() { + FrameBuffer* fb = ssrM_new(FrameBuffer); + fbo_attachdepthbuffer(fb, 0); + fbo_attachstencilbuffer(fb, 0); + ssrM_zero(fb->render_textures, sizeof(Texture*) * RENDER_TARGET_COUNT); + return fb; +} + +void fbo_attachrendertexture(FrameBuffer* fb, uint attachment, Texture* rt) { + fb->render_textures[attachment] = rt; +} + +void fbo_attachdepthbuffer(FrameBuffer* fb, float* depthbuffer) { + if (depthbuffer == NULL) + fb->depth_buffer = state.depth_screen_buffer; + else + fb->depth_buffer = depthbuffer; +} + +void fbo_attachstencilbuffer(FrameBuffer* fb, byte* stencilbuffer) { + if (stencilbuffer == NULL) + fb->stencil_buffer = state.stencil_screen_buffer; + else + fb->stencil_buffer = stencilbuffer; +} + +void fbo_free(FrameBuffer* fb) { + ssrM_free(fb); +} |