mirror of
https://github.com/libretro/RetroArch
synced 2025-03-29 13:20:30 +00:00
2934af8af0 Added Patreon sponsor link. c8f18b6f0f Getting current program only when required for vglDrawObjects. 4c5d136b0d Added directive to enable vitaShaRK usage from cmd. 4a10df3be5 Minor adjustments and bugfixes. 14a0124acf Added GL_TEXTURE_LOD_BIAS support. 40c8c6205e Added GL_NONE def and fixed glUniform4f impl. 868079c51e Added glUniform4f implementation. 0a682cbad2 Typo fix. be3ce61ae7 Added GL_DEPTH_BITS and GL_STENCIL_BITS support. 21e6d1d330 Added runtime shader compiler support. 696e40bc62 Beautify error handler code. 537b37b110 Added glUniform3fv implementation. 7dd1403015 Fixed GLenum size and added missing types defines. 0c75f27ff1 Moved to NEON optimized memcpy usage. 98951895de Added gluPerspective implementation. 23e0b0b309 Fix for vglInitExtended not working on sys app mode. 4989c33ef5 Run clang-format. 429f1c1d8a Added system mode support. 9231680d02 Initializing sceGxm before free mem checking on vglInitExtended. 091e5e7882 Added vglInitWithCustomSizes. f4c646ea78 Added vglSetParamBufferSize. 1b9a063c41 Beautify some code. 089e81efc5 Fix for duplicated symbols 789dcbf812 Typo fix in readRGBA4444. 1514a4b2cb Disabling lto due to it being broken on vitasdk with gcc 9.1. fca18d9ab7 Added support for RGBA4444 texture format. d449f12808 Added support for RGB565 texture format. git-subtree-dir: deps/vitaGL git-subtree-split: 2934af8af083a9acf598ab75233c518a251c6f0d
511 lines
15 KiB
C
511 lines
15 KiB
C
/*
|
|
* This file is part of vitaGL
|
|
* Copyright 2017, 2018, 2019, 2020 Rinnegatamante
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as published
|
|
* by the Free Software Foundation, version 3 of the License, or (at your
|
|
* option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/*
|
|
* tests.c:
|
|
* Implementation for all drawing tests functions
|
|
*/
|
|
|
|
#include "shared.h"
|
|
|
|
// Depth Test
|
|
GLboolean depth_test_state = GL_FALSE; // Current state for GL_DEPTH_TEST
|
|
SceGxmDepthFunc gxm_depth = SCE_GXM_DEPTH_FUNC_LESS; // Current in-use depth test func
|
|
GLenum orig_depth_test; // Original depth test state (used for depth test invalidation)
|
|
GLdouble depth_value = 1.0f; // Current depth test clear value
|
|
GLboolean depth_mask_state = GL_TRUE; // Current state for glDepthMask
|
|
|
|
// Scissor Test
|
|
scissor_region region; // Current scissor test region setup
|
|
GLboolean scissor_test_state = GL_FALSE; // Current state for GL_SCISSOR_TEST
|
|
SceGxmFragmentProgram *scissor_test_fragment_program; // Scissor test fragment program
|
|
vector4f *scissor_test_vertices = NULL; // Scissor test region vertices
|
|
SceUID scissor_test_vertices_uid; // Scissor test vertices memblock id
|
|
|
|
// Stencil Test
|
|
uint8_t stencil_mask_front = 0xFF; // Current in use mask for stencil test on front
|
|
uint8_t stencil_mask_back = 0xFF; // Current in use mask for stencil test on back
|
|
uint8_t stencil_mask_front_write = 0xFF; // Current in use mask for write stencil test on front
|
|
uint8_t stencil_mask_back_write = 0xFF; // Current in use mask for write stencil test on back
|
|
uint8_t stencil_ref_front = 0; // Current in use reference for stencil test on front
|
|
uint8_t stencil_ref_back = 0; // Current in use reference for stencil test on back
|
|
SceGxmStencilOp stencil_fail_front = SCE_GXM_STENCIL_OP_KEEP; // Current in use stencil operation when stencil test fails for front
|
|
SceGxmStencilOp depth_fail_front = SCE_GXM_STENCIL_OP_KEEP; // Current in use stencil operation when depth test fails for front
|
|
SceGxmStencilOp depth_pass_front = SCE_GXM_STENCIL_OP_KEEP; // Current in use stencil operation when depth test passes for front
|
|
SceGxmStencilOp stencil_fail_back = SCE_GXM_STENCIL_OP_KEEP; // Current in use stencil operation when stencil test fails for back
|
|
SceGxmStencilOp depth_fail_back = SCE_GXM_STENCIL_OP_KEEP; // Current in use stencil operation when depth test fails for back
|
|
SceGxmStencilOp depth_pass_back = SCE_GXM_STENCIL_OP_KEEP; // Current in use stencil operation when depth test passes for back
|
|
SceGxmStencilFunc stencil_func_front = SCE_GXM_STENCIL_FUNC_ALWAYS; // Current in use stencil function on front
|
|
SceGxmStencilFunc stencil_func_back = SCE_GXM_STENCIL_FUNC_ALWAYS; // Current in use stencil function on back
|
|
GLboolean stencil_test_state = GL_FALSE; // Current state for GL_STENCIL_TEST
|
|
GLint stencil_value = 0; // Current stencil test clear value
|
|
|
|
// Alpha Test
|
|
GLenum alpha_func = GL_ALWAYS; // Current in-use alpha test mode
|
|
GLfloat alpha_ref = 0.0f; // Current in use alpha test reference value
|
|
int alpha_op = ALWAYS; // Current in use alpha test operation
|
|
GLboolean alpha_test_state = GL_FALSE; // Current state for GL_ALPHA_TEST
|
|
|
|
void change_depth_write(SceGxmDepthWriteMode mode) {
|
|
// Change depth write mode for both front and back primitives
|
|
sceGxmSetFrontDepthWriteEnable(gxm_context, mode);
|
|
sceGxmSetBackDepthWriteEnable(gxm_context, mode);
|
|
}
|
|
|
|
void change_depth_func() {
|
|
// Setting depth function for both front and back primitives
|
|
sceGxmSetFrontDepthFunc(gxm_context, depth_test_state ? gxm_depth : SCE_GXM_DEPTH_FUNC_ALWAYS);
|
|
sceGxmSetBackDepthFunc(gxm_context, depth_test_state ? gxm_depth : SCE_GXM_DEPTH_FUNC_ALWAYS);
|
|
|
|
// Calling an update for the depth write mode
|
|
change_depth_write(depth_mask_state ? SCE_GXM_DEPTH_WRITE_ENABLED : SCE_GXM_DEPTH_WRITE_DISABLED);
|
|
}
|
|
|
|
void invalidate_depth_test() {
|
|
// Invalidating current depth test state
|
|
orig_depth_test = depth_test_state;
|
|
depth_test_state = GL_FALSE;
|
|
|
|
// Invoking a depth function update
|
|
change_depth_func();
|
|
}
|
|
|
|
void validate_depth_test() {
|
|
// Restoring original depth test state
|
|
depth_test_state = orig_depth_test;
|
|
|
|
// Invoking a depth function update
|
|
change_depth_func();
|
|
}
|
|
|
|
void invalidate_viewport() {
|
|
// Invalidating current viewport
|
|
sceGxmSetViewport(gxm_context, fullscreen_x_port, fullscreen_x_scale, fullscreen_y_port, fullscreen_y_scale, fullscreen_z_port, fullscreen_z_scale);
|
|
}
|
|
|
|
void validate_viewport() {
|
|
// Restoring original viewport
|
|
sceGxmSetViewport(gxm_context, x_port, x_scale, y_port, y_scale, z_port, z_scale);
|
|
}
|
|
|
|
void change_stencil_settings() {
|
|
if (stencil_test_state) {
|
|
// Setting stencil function for both front and back primitives
|
|
sceGxmSetFrontStencilFunc(gxm_context,
|
|
stencil_func_front,
|
|
stencil_fail_front,
|
|
depth_fail_front,
|
|
depth_pass_front,
|
|
stencil_mask_front, stencil_mask_front_write);
|
|
sceGxmSetBackStencilFunc(gxm_context,
|
|
stencil_func_back,
|
|
stencil_fail_back,
|
|
depth_fail_back,
|
|
depth_pass_back,
|
|
stencil_mask_back, stencil_mask_back_write);
|
|
|
|
// Setting stencil ref for both front and back primitives
|
|
sceGxmSetFrontStencilRef(gxm_context, stencil_ref_front);
|
|
sceGxmSetBackStencilRef(gxm_context, stencil_ref_back);
|
|
|
|
} else {
|
|
sceGxmSetFrontStencilFunc(gxm_context,
|
|
SCE_GXM_STENCIL_FUNC_ALWAYS,
|
|
SCE_GXM_STENCIL_OP_KEEP,
|
|
SCE_GXM_STENCIL_OP_KEEP,
|
|
SCE_GXM_STENCIL_OP_KEEP,
|
|
0, 0);
|
|
sceGxmSetBackStencilFunc(gxm_context,
|
|
SCE_GXM_STENCIL_FUNC_ALWAYS,
|
|
SCE_GXM_STENCIL_OP_KEEP,
|
|
SCE_GXM_STENCIL_OP_KEEP,
|
|
SCE_GXM_STENCIL_OP_KEEP,
|
|
0, 0);
|
|
}
|
|
}
|
|
|
|
GLboolean change_stencil_config(SceGxmStencilOp *cfg, GLenum new) {
|
|
// Translating openGL stencil operation value to sceGxm one
|
|
GLboolean ret = GL_TRUE;
|
|
switch (new) {
|
|
case GL_KEEP:
|
|
*cfg = SCE_GXM_STENCIL_OP_KEEP;
|
|
break;
|
|
case GL_ZERO:
|
|
*cfg = SCE_GXM_STENCIL_OP_ZERO;
|
|
break;
|
|
case GL_REPLACE:
|
|
*cfg = SCE_GXM_STENCIL_OP_REPLACE;
|
|
break;
|
|
case GL_INCR:
|
|
*cfg = SCE_GXM_STENCIL_OP_INCR;
|
|
break;
|
|
case GL_INCR_WRAP:
|
|
*cfg = SCE_GXM_STENCIL_OP_INCR_WRAP;
|
|
break;
|
|
case GL_DECR:
|
|
*cfg = SCE_GXM_STENCIL_OP_DECR;
|
|
break;
|
|
case GL_DECR_WRAP:
|
|
*cfg = SCE_GXM_STENCIL_OP_DECR_WRAP;
|
|
break;
|
|
case GL_INVERT:
|
|
*cfg = SCE_GXM_STENCIL_OP_INVERT;
|
|
break;
|
|
default:
|
|
ret = GL_FALSE;
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
GLboolean change_stencil_func_config(SceGxmStencilFunc *cfg, GLenum new) {
|
|
// Translating openGL stencil function to sceGxm one
|
|
GLboolean ret = GL_TRUE;
|
|
switch (new) {
|
|
case GL_NEVER:
|
|
*cfg = SCE_GXM_STENCIL_FUNC_NEVER;
|
|
break;
|
|
case GL_LESS:
|
|
*cfg = SCE_GXM_STENCIL_FUNC_LESS;
|
|
break;
|
|
case GL_LEQUAL:
|
|
*cfg = SCE_GXM_STENCIL_FUNC_LESS_EQUAL;
|
|
break;
|
|
case GL_GREATER:
|
|
*cfg = SCE_GXM_STENCIL_FUNC_GREATER;
|
|
break;
|
|
case GL_GEQUAL:
|
|
*cfg = SCE_GXM_STENCIL_FUNC_GREATER_EQUAL;
|
|
break;
|
|
case GL_EQUAL:
|
|
*cfg = SCE_GXM_STENCIL_FUNC_EQUAL;
|
|
break;
|
|
case GL_NOTEQUAL:
|
|
*cfg = SCE_GXM_STENCIL_FUNC_NOT_EQUAL;
|
|
break;
|
|
case GL_ALWAYS:
|
|
*cfg = SCE_GXM_STENCIL_FUNC_ALWAYS;
|
|
break;
|
|
default:
|
|
ret = GL_FALSE;
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void update_alpha_test_settings() {
|
|
// Translating openGL alpha test operation to internal one
|
|
if (alpha_test_state) {
|
|
switch (alpha_func) {
|
|
case GL_EQUAL:
|
|
alpha_op = EQUAL;
|
|
break;
|
|
case GL_LEQUAL:
|
|
alpha_op = LESS_EQUAL;
|
|
break;
|
|
case GL_GEQUAL:
|
|
alpha_op = GREATER_EQUAL;
|
|
break;
|
|
case GL_LESS:
|
|
alpha_op = LESS;
|
|
break;
|
|
case GL_GREATER:
|
|
alpha_op = GREATER;
|
|
break;
|
|
case GL_NOTEQUAL:
|
|
alpha_op = NOT_EQUAL;
|
|
break;
|
|
case GL_NEVER:
|
|
alpha_op = NEVER;
|
|
break;
|
|
default:
|
|
alpha_op = ALWAYS;
|
|
break;
|
|
}
|
|
} else
|
|
alpha_op = ALWAYS;
|
|
}
|
|
|
|
void update_scissor_test() {
|
|
// Setting current vertex program to clear screen one and fragment program to scissor test one
|
|
sceGxmSetVertexProgram(gxm_context, clear_vertex_program_patched);
|
|
sceGxmSetFragmentProgram(gxm_context, scissor_test_fragment_program);
|
|
|
|
// Invalidating viewport
|
|
invalidate_viewport();
|
|
|
|
// Invalidating internal tile based region clip
|
|
sceGxmSetRegionClip(gxm_context, SCE_GXM_REGION_CLIP_OUTSIDE, 0, 0, DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1);
|
|
|
|
if (scissor_test_state) {
|
|
// Calculating scissor test region vertices
|
|
vector4f_convert_to_local_space(scissor_test_vertices, region.x, region.y, region.w, region.h);
|
|
|
|
void *vertex_buffer;
|
|
sceGxmReserveVertexDefaultUniformBuffer(gxm_context, &vertex_buffer);
|
|
sceGxmSetUniformDataF(vertex_buffer, clear_position, 0, 4, &clear_vertices->x);
|
|
|
|
// Cleaning stencil surface mask update bit on the whole screen
|
|
sceGxmSetFrontStencilFunc(gxm_context,
|
|
SCE_GXM_STENCIL_FUNC_NEVER,
|
|
SCE_GXM_STENCIL_OP_KEEP,
|
|
SCE_GXM_STENCIL_OP_KEEP,
|
|
SCE_GXM_STENCIL_OP_KEEP,
|
|
0, 0);
|
|
sceGxmSetBackStencilFunc(gxm_context,
|
|
SCE_GXM_STENCIL_FUNC_NEVER,
|
|
SCE_GXM_STENCIL_OP_KEEP,
|
|
SCE_GXM_STENCIL_OP_KEEP,
|
|
SCE_GXM_STENCIL_OP_KEEP,
|
|
0, 0);
|
|
sceGxmDraw(gxm_context, SCE_GXM_PRIMITIVE_TRIANGLE_FAN, SCE_GXM_INDEX_FORMAT_U16, depth_clear_indices, 4);
|
|
}
|
|
|
|
// Setting stencil surface mask update bit on the scissor test region
|
|
sceGxmSetFrontStencilFunc(gxm_context,
|
|
SCE_GXM_STENCIL_FUNC_ALWAYS,
|
|
SCE_GXM_STENCIL_OP_KEEP,
|
|
SCE_GXM_STENCIL_OP_KEEP,
|
|
SCE_GXM_STENCIL_OP_KEEP,
|
|
0, 0);
|
|
sceGxmSetBackStencilFunc(gxm_context,
|
|
SCE_GXM_STENCIL_FUNC_ALWAYS,
|
|
SCE_GXM_STENCIL_OP_KEEP,
|
|
SCE_GXM_STENCIL_OP_KEEP,
|
|
SCE_GXM_STENCIL_OP_KEEP,
|
|
0, 0);
|
|
|
|
void *vertex_buffer;
|
|
sceGxmReserveVertexDefaultUniformBuffer(gxm_context, &vertex_buffer);
|
|
if (scissor_test_state)
|
|
sceGxmSetUniformDataF(vertex_buffer, clear_position, 0, 4, &scissor_test_vertices->x);
|
|
else
|
|
sceGxmSetUniformDataF(vertex_buffer, clear_position, 0, 4, &clear_vertices->x);
|
|
sceGxmDraw(gxm_context, SCE_GXM_PRIMITIVE_TRIANGLE_FAN, SCE_GXM_INDEX_FORMAT_U16, depth_clear_indices, 4);
|
|
|
|
// Restoring viewport
|
|
validate_viewport();
|
|
|
|
// Reducing GPU workload by performing tile granularity clipping
|
|
if (scissor_test_state)
|
|
sceGxmSetRegionClip(gxm_context, SCE_GXM_REGION_CLIP_OUTSIDE, region.x, region.y, region.x + region.w - 1, region.y + region.h - 1);
|
|
|
|
// Restoring original stencil test settings
|
|
change_stencil_settings();
|
|
}
|
|
|
|
void resetScissorTestRegion(void) {
|
|
// Setting scissor test region to default values
|
|
region.x = region.y = 0;
|
|
region.w = DISPLAY_WIDTH;
|
|
region.h = DISPLAY_HEIGHT;
|
|
}
|
|
|
|
/*
|
|
* ------------------------------
|
|
* - IMPLEMENTATION STARTS HERE -
|
|
* ------------------------------
|
|
*/
|
|
|
|
void glScissor(GLint x, GLint y, GLsizei width, GLsizei height) {
|
|
#ifndef SKIP_ERROR_HANDLING
|
|
// Error handling
|
|
if ((width < 0) || (height < 0)) {
|
|
SET_GL_ERROR(GL_INVALID_VALUE)
|
|
}
|
|
#endif
|
|
|
|
// Converting openGL scissor test region to sceGxm one
|
|
region.x = x;
|
|
region.y = DISPLAY_HEIGHT - y - height;
|
|
region.w = width;
|
|
region.h = height;
|
|
|
|
// Updating in use scissor test parameters if GL_SCISSOR_TEST is enabled
|
|
if (scissor_test_state)
|
|
update_scissor_test();
|
|
}
|
|
|
|
void glDepthFunc(GLenum func) {
|
|
// Properly translating openGL function to sceGxm one
|
|
switch (func) {
|
|
case GL_NEVER:
|
|
gxm_depth = SCE_GXM_DEPTH_FUNC_NEVER;
|
|
break;
|
|
case GL_LESS:
|
|
gxm_depth = SCE_GXM_DEPTH_FUNC_LESS;
|
|
break;
|
|
case GL_EQUAL:
|
|
gxm_depth = SCE_GXM_DEPTH_FUNC_EQUAL;
|
|
break;
|
|
case GL_LEQUAL:
|
|
gxm_depth = SCE_GXM_DEPTH_FUNC_LESS_EQUAL;
|
|
break;
|
|
case GL_GREATER:
|
|
gxm_depth = SCE_GXM_DEPTH_FUNC_GREATER;
|
|
break;
|
|
case GL_NOTEQUAL:
|
|
gxm_depth = SCE_GXM_DEPTH_FUNC_NOT_EQUAL;
|
|
break;
|
|
case GL_GEQUAL:
|
|
gxm_depth = SCE_GXM_DEPTH_FUNC_GREATER_EQUAL;
|
|
break;
|
|
case GL_ALWAYS:
|
|
gxm_depth = SCE_GXM_DEPTH_FUNC_ALWAYS;
|
|
break;
|
|
}
|
|
|
|
// Updating in use depth function
|
|
change_depth_func();
|
|
}
|
|
|
|
void glClearDepth(GLdouble depth) {
|
|
// Set current in use depth test depth value
|
|
depth_value = depth;
|
|
}
|
|
|
|
void glDepthMask(GLboolean flag) {
|
|
#ifndef SKIP_ERROR_HANDLING
|
|
// Error handling
|
|
if (phase == MODEL_CREATION) {
|
|
SET_GL_ERROR(GL_INVALID_OPERATION)
|
|
}
|
|
#endif
|
|
|
|
// Set current in use depth mask and invoking a depth write mode update
|
|
depth_mask_state = flag;
|
|
change_depth_write(depth_mask_state ? SCE_GXM_DEPTH_WRITE_ENABLED : SCE_GXM_DEPTH_WRITE_DISABLED);
|
|
}
|
|
|
|
void glAlphaFunc(GLenum func, GLfloat ref) {
|
|
// Updating in use alpha test parameters
|
|
alpha_func = func;
|
|
alpha_ref = ref;
|
|
update_alpha_test_settings();
|
|
}
|
|
|
|
void glStencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) {
|
|
// Properly updating stencil operation settings
|
|
switch (face) {
|
|
case GL_FRONT:
|
|
if (!change_stencil_config(&stencil_fail_front, sfail))
|
|
SET_GL_ERROR(GL_INVALID_ENUM)
|
|
if (!change_stencil_config(&depth_fail_front, dpfail))
|
|
SET_GL_ERROR(GL_INVALID_ENUM)
|
|
if (!change_stencil_config(&depth_pass_front, dppass))
|
|
SET_GL_ERROR(GL_INVALID_ENUM)
|
|
break;
|
|
case GL_BACK:
|
|
if (!change_stencil_config(&stencil_fail_back, sfail))
|
|
SET_GL_ERROR(GL_INVALID_ENUM)
|
|
if (!change_stencil_config(&depth_fail_back, dpfail))
|
|
SET_GL_ERROR(GL_INVALID_ENUM)
|
|
if (!change_stencil_config(&depth_pass_front, dppass))
|
|
SET_GL_ERROR(GL_INVALID_ENUM)
|
|
break;
|
|
case GL_FRONT_AND_BACK:
|
|
if (!change_stencil_config(&stencil_fail_front, sfail))
|
|
SET_GL_ERROR(GL_INVALID_ENUM)
|
|
if (!change_stencil_config(&stencil_fail_back, sfail))
|
|
SET_GL_ERROR(GL_INVALID_ENUM)
|
|
if (!change_stencil_config(&depth_fail_front, dpfail))
|
|
SET_GL_ERROR(GL_INVALID_ENUM)
|
|
if (!change_stencil_config(&depth_fail_back, dpfail))
|
|
SET_GL_ERROR(GL_INVALID_ENUM)
|
|
if (!change_stencil_config(&depth_pass_front, dppass))
|
|
SET_GL_ERROR(GL_INVALID_ENUM)
|
|
if (!change_stencil_config(&depth_pass_back, dppass))
|
|
SET_GL_ERROR(GL_INVALID_ENUM)
|
|
break;
|
|
default:
|
|
SET_GL_ERROR(GL_INVALID_ENUM)
|
|
break;
|
|
}
|
|
change_stencil_settings();
|
|
}
|
|
|
|
void glStencilOp(GLenum sfail, GLenum dpfail, GLenum dppass) {
|
|
glStencilOpSeparate(GL_FRONT_AND_BACK, sfail, dpfail, dppass);
|
|
}
|
|
|
|
void glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) {
|
|
// Properly updating stencil test function settings
|
|
switch (face) {
|
|
case GL_FRONT:
|
|
if (!change_stencil_func_config(&stencil_func_front, func)) {
|
|
SET_GL_ERROR(GL_INVALID_ENUM)
|
|
}
|
|
stencil_mask_front = mask;
|
|
stencil_ref_front = ref;
|
|
break;
|
|
case GL_BACK:
|
|
if (!change_stencil_func_config(&stencil_func_back, func)) {
|
|
SET_GL_ERROR(GL_INVALID_ENUM)
|
|
}
|
|
stencil_mask_back = mask;
|
|
stencil_ref_back = ref;
|
|
break;
|
|
case GL_FRONT_AND_BACK:
|
|
if (!change_stencil_func_config(&stencil_func_front, func)) {
|
|
SET_GL_ERROR(GL_INVALID_ENUM)
|
|
}
|
|
if (!change_stencil_func_config(&stencil_func_back, func)) {
|
|
SET_GL_ERROR(GL_INVALID_ENUM)
|
|
}
|
|
stencil_mask_front = stencil_mask_back = mask;
|
|
stencil_ref_front = stencil_ref_back = ref;
|
|
break;
|
|
default:
|
|
SET_GL_ERROR(GL_INVALID_ENUM)
|
|
break;
|
|
}
|
|
change_stencil_settings();
|
|
}
|
|
|
|
void glStencilFunc(GLenum func, GLint ref, GLuint mask) {
|
|
glStencilFuncSeparate(GL_FRONT_AND_BACK, func, ref, mask);
|
|
}
|
|
|
|
void glStencilMaskSeparate(GLenum face, GLuint mask) {
|
|
// Properly updating stencil test mask settings
|
|
switch (face) {
|
|
case GL_FRONT:
|
|
stencil_mask_front_write = mask;
|
|
break;
|
|
case GL_BACK:
|
|
stencil_mask_back_write = mask;
|
|
break;
|
|
case GL_FRONT_AND_BACK:
|
|
stencil_mask_front_write = stencil_mask_back_write = mask;
|
|
break;
|
|
default:
|
|
SET_GL_ERROR(GL_INVALID_ENUM)
|
|
return;
|
|
}
|
|
change_stencil_settings();
|
|
}
|
|
|
|
void glStencilMask(GLuint mask) {
|
|
glStencilMaskSeparate(GL_FRONT_AND_BACK, mask);
|
|
}
|
|
|
|
void glClearStencil(GLint s) {
|
|
stencil_value = s;
|
|
}
|