diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2020-07-31 00:50:43 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2020-08-02 03:10:22 +0300 |
commit | 6a444830a389150662cdeeb04835a7c9108f2074 (patch) | |
tree | 463fb21c4b354495420209b4ded33cadb522a7ac /source/blender/gpu/intern/gpu_matrix.cc | |
parent | 6941e27f4a37ab6d91a18cda1bc99e8697f4f840 (diff) |
GPU: Convert gpu_matrix.c to C++
Diffstat (limited to 'source/blender/gpu/intern/gpu_matrix.cc')
-rw-r--r-- | source/blender/gpu/intern/gpu_matrix.cc | 785 |
1 files changed, 785 insertions, 0 deletions
diff --git a/source/blender/gpu/intern/gpu_matrix.cc b/source/blender/gpu/intern/gpu_matrix.cc new file mode 100644 index 00000000000..c15bb1fba19 --- /dev/null +++ b/source/blender/gpu/intern/gpu_matrix.cc @@ -0,0 +1,785 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * 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, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2012 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + */ + +#include "GPU_shader_interface.h" + +#include "gpu_context_private.h" +#include "gpu_matrix_private.h" + +#define SUPPRESS_GENERIC_MATRIX_API +#define USE_GPU_PY_MATRIX_API /* only so values are declared */ +#include "GPU_matrix.h" +#undef USE_GPU_PY_MATRIX_API + +#include "BLI_math_matrix.h" +#include "BLI_math_rotation.h" +#include "BLI_math_vector.h" + +#include "MEM_guardedalloc.h" + +#define MATRIX_STACK_DEPTH 32 + +typedef float Mat4[4][4]; +typedef float Mat3[3][3]; + +typedef struct MatrixStack { + Mat4 stack[MATRIX_STACK_DEPTH]; + uint top; +} MatrixStack; + +typedef struct GPUMatrixState { + MatrixStack model_view_stack; + MatrixStack projection_stack; + + bool dirty; + + /* TODO: cache of derived matrices (Normal, MVP, inverse MVP, etc) + * generate as needed for shaders, invalidate when original matrices change + * + * TODO: separate Model from View transform? Batches/objects have model, + * camera/eye has view & projection + */ +} GPUMatrixState; + +#define ModelViewStack gpu_context_active_matrix_state_get()->model_view_stack +#define ModelView ModelViewStack.stack[ModelViewStack.top] + +#define ProjectionStack gpu_context_active_matrix_state_get()->projection_stack +#define Projection ProjectionStack.stack[ProjectionStack.top] + +GPUMatrixState *GPU_matrix_state_create(void) +{ +#define MATRIX_4X4_IDENTITY \ + { \ + {1.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f, 0.0f}, \ + { \ + 0.0f, 0.0f, 0.0f, 1.0f \ + } \ + } + + GPUMatrixState *state = (GPUMatrixState *)MEM_mallocN(sizeof(*state), __func__); + const MatrixStack identity_stack = {{MATRIX_4X4_IDENTITY}, 0}; + + state->model_view_stack = state->projection_stack = identity_stack; + state->dirty = true; + +#undef MATRIX_4X4_IDENTITY + + return state; +} + +void GPU_matrix_state_discard(GPUMatrixState *state) +{ + MEM_freeN(state); +} + +static void gpu_matrix_state_active_set_dirty(bool value) +{ + GPUMatrixState *state = gpu_context_active_matrix_state_get(); + state->dirty = value; +} + +void GPU_matrix_reset(void) +{ + GPUMatrixState *state = gpu_context_active_matrix_state_get(); + state->model_view_stack.top = 0; + state->projection_stack.top = 0; + unit_m4(ModelView); + unit_m4(Projection); + gpu_matrix_state_active_set_dirty(true); +} + +#ifdef WITH_GPU_SAFETY + +/* Check if matrix is numerically good */ +static void checkmat(cosnt float *m) +{ + const int n = 16; + for (int i = 0; i < n; i++) { +# if _MSC_VER + BLI_assert(_finite(m[i])); +# else + BLI_assert(!isinf(m[i])); +# endif + } +} + +# define CHECKMAT(m) checkmat((const float *)m) + +#else + +# define CHECKMAT(m) + +#endif + +void GPU_matrix_push(void) +{ + BLI_assert(ModelViewStack.top + 1 < MATRIX_STACK_DEPTH); + ModelViewStack.top++; + copy_m4_m4(ModelView, ModelViewStack.stack[ModelViewStack.top - 1]); +} + +void GPU_matrix_pop(void) +{ + BLI_assert(ModelViewStack.top > 0); + ModelViewStack.top--; + gpu_matrix_state_active_set_dirty(true); +} + +void GPU_matrix_push_projection(void) +{ + BLI_assert(ProjectionStack.top + 1 < MATRIX_STACK_DEPTH); + ProjectionStack.top++; + copy_m4_m4(Projection, ProjectionStack.stack[ProjectionStack.top - 1]); +} + +void GPU_matrix_pop_projection(void) +{ + BLI_assert(ProjectionStack.top > 0); + ProjectionStack.top--; + gpu_matrix_state_active_set_dirty(true); +} + +void GPU_matrix_set(const float m[4][4]) +{ + copy_m4_m4(ModelView, m); + CHECKMAT(ModelView3D); + gpu_matrix_state_active_set_dirty(true); +} + +void GPU_matrix_identity_projection_set(void) +{ + unit_m4(Projection); + CHECKMAT(Projection3D); + gpu_matrix_state_active_set_dirty(true); +} + +void GPU_matrix_projection_set(const float m[4][4]) +{ + copy_m4_m4(Projection, m); + CHECKMAT(Projection3D); + gpu_matrix_state_active_set_dirty(true); +} + +void GPU_matrix_identity_set(void) +{ + unit_m4(ModelView); + gpu_matrix_state_active_set_dirty(true); +} + +void GPU_matrix_translate_2f(float x, float y) +{ + Mat4 m; + unit_m4(m); + m[3][0] = x; + m[3][1] = y; + GPU_matrix_mul(m); +} + +void GPU_matrix_translate_2fv(const float vec[2]) +{ + GPU_matrix_translate_2f(vec[0], vec[1]); +} + +void GPU_matrix_translate_3f(float x, float y, float z) +{ +#if 1 + translate_m4(ModelView, x, y, z); + CHECKMAT(ModelView); +#else /* above works well in early testing, below is generic version */ + Mat4 m; + unit_m4(m); + m[3][0] = x; + m[3][1] = y; + m[3][2] = z; + GPU_matrix_mul(m); +#endif + gpu_matrix_state_active_set_dirty(true); +} + +void GPU_matrix_translate_3fv(const float vec[3]) +{ + GPU_matrix_translate_3f(vec[0], vec[1], vec[2]); +} + +void GPU_matrix_scale_1f(float factor) +{ + Mat4 m; + scale_m4_fl(m, factor); + GPU_matrix_mul(m); +} + +void GPU_matrix_scale_2f(float x, float y) +{ + Mat4 m = {{0.0f}}; + m[0][0] = x; + m[1][1] = y; + m[2][2] = 1.0f; + m[3][3] = 1.0f; + GPU_matrix_mul(m); +} + +void GPU_matrix_scale_2fv(const float vec[2]) +{ + GPU_matrix_scale_2f(vec[0], vec[1]); +} + +void GPU_matrix_scale_3f(float x, float y, float z) +{ + Mat4 m = {{0.0f}}; + m[0][0] = x; + m[1][1] = y; + m[2][2] = z; + m[3][3] = 1.0f; + GPU_matrix_mul(m); +} + +void GPU_matrix_scale_3fv(const float vec[3]) +{ + GPU_matrix_scale_3f(vec[0], vec[1], vec[2]); +} + +void GPU_matrix_mul(const float m[4][4]) +{ + mul_m4_m4_post(ModelView, m); + CHECKMAT(ModelView); + gpu_matrix_state_active_set_dirty(true); +} + +void GPU_matrix_rotate_2d(float deg) +{ + /* essentially RotateAxis('Z') + * TODO: simpler math for 2D case + */ + rotate_m4(ModelView, 'Z', DEG2RADF(deg)); +} + +void GPU_matrix_rotate_3f(float deg, float x, float y, float z) +{ + const float axis[3] = {x, y, z}; + GPU_matrix_rotate_3fv(deg, axis); +} + +void GPU_matrix_rotate_3fv(float deg, const float axis[3]) +{ + Mat4 m; + axis_angle_to_mat4(m, axis, DEG2RADF(deg)); + GPU_matrix_mul(m); +} + +void GPU_matrix_rotate_axis(float deg, char axis) +{ + /* rotate_m4 works in place */ + rotate_m4(ModelView, axis, DEG2RADF(deg)); + CHECKMAT(ModelView); + gpu_matrix_state_active_set_dirty(true); +} + +static void mat4_ortho_set( + float m[4][4], float left, float right, float bottom, float top, float near, float far) +{ + m[0][0] = 2.0f / (right - left); + m[1][0] = 0.0f; + m[2][0] = 0.0f; + m[3][0] = -(right + left) / (right - left); + + m[0][1] = 0.0f; + m[1][1] = 2.0f / (top - bottom); + m[2][1] = 0.0f; + m[3][1] = -(top + bottom) / (top - bottom); + + m[0][2] = 0.0f; + m[1][2] = 0.0f; + m[2][2] = -2.0f / (far - near); + m[3][2] = -(far + near) / (far - near); + + m[0][3] = 0.0f; + m[1][3] = 0.0f; + m[2][3] = 0.0f; + m[3][3] = 1.0f; + + gpu_matrix_state_active_set_dirty(true); +} + +static void mat4_frustum_set( + float m[4][4], float left, float right, float bottom, float top, float near, float far) +{ + m[0][0] = 2.0f * near / (right - left); + m[1][0] = 0.0f; + m[2][0] = (right + left) / (right - left); + m[3][0] = 0.0f; + + m[0][1] = 0.0f; + m[1][1] = 2.0f * near / (top - bottom); + m[2][1] = (top + bottom) / (top - bottom); + m[3][1] = 0.0f; + + m[0][2] = 0.0f; + m[1][2] = 0.0f; + m[2][2] = -(far + near) / (far - near); + m[3][2] = -2.0f * far * near / (far - near); + + m[0][3] = 0.0f; + m[1][3] = 0.0f; + m[2][3] = -1.0f; + m[3][3] = 0.0f; + + gpu_matrix_state_active_set_dirty(true); +} + +static void mat4_look_from_origin(float m[4][4], float lookdir[3], float camup[3]) +{ + /* This function is loosely based on Mesa implementation. + * + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ + float side[3]; + + normalize_v3(lookdir); + + cross_v3_v3v3(side, lookdir, camup); + + normalize_v3(side); + + cross_v3_v3v3(camup, side, lookdir); + + m[0][0] = side[0]; + m[1][0] = side[1]; + m[2][0] = side[2]; + m[3][0] = 0.0f; + + m[0][1] = camup[0]; + m[1][1] = camup[1]; + m[2][1] = camup[2]; + m[3][1] = 0.0f; + + m[0][2] = -lookdir[0]; + m[1][2] = -lookdir[1]; + m[2][2] = -lookdir[2]; + m[3][2] = 0.0f; + + m[0][3] = 0.0f; + m[1][3] = 0.0f; + m[2][3] = 0.0f; + m[3][3] = 1.0f; + + gpu_matrix_state_active_set_dirty(true); +} + +void GPU_matrix_ortho_set(float left, float right, float bottom, float top, float near, float far) +{ + mat4_ortho_set(Projection, left, right, bottom, top, near, far); + CHECKMAT(Projection); + gpu_matrix_state_active_set_dirty(true); +} + +void GPU_matrix_ortho_set_z(float near, float far) +{ + CHECKMAT(Projection); + Projection[2][2] = -2.0f / (far - near); + Projection[3][2] = -(far + near) / (far - near); + gpu_matrix_state_active_set_dirty(true); +} + +void GPU_matrix_ortho_2d_set(float left, float right, float bottom, float top) +{ + Mat4 m; + mat4_ortho_set(m, left, right, bottom, top, -1.0f, 1.0f); + CHECKMAT(Projection2D); + gpu_matrix_state_active_set_dirty(true); +} + +void GPU_matrix_frustum_set( + float left, float right, float bottom, float top, float near, float far) +{ + mat4_frustum_set(Projection, left, right, bottom, top, near, far); + CHECKMAT(Projection); + gpu_matrix_state_active_set_dirty(true); +} + +void GPU_matrix_perspective_set(float fovy, float aspect, float near, float far) +{ + float half_height = tanf(fovy * (float)(M_PI / 360.0)) * near; + float half_width = half_height * aspect; + GPU_matrix_frustum_set(-half_width, +half_width, -half_height, +half_height, near, far); +} + +void GPU_matrix_look_at(float eyeX, + float eyeY, + float eyeZ, + float centerX, + float centerY, + float centerZ, + float upX, + float upY, + float upZ) +{ + Mat4 cm; + float lookdir[3]; + float camup[3] = {upX, upY, upZ}; + + lookdir[0] = centerX - eyeX; + lookdir[1] = centerY - eyeY; + lookdir[2] = centerZ - eyeZ; + + mat4_look_from_origin(cm, lookdir, camup); + + GPU_matrix_mul(cm); + GPU_matrix_translate_3f(-eyeX, -eyeY, -eyeZ); +} + +void GPU_matrix_project(const float world[3], + const float model[4][4], + const float proj[4][4], + const int view[4], + float win[3]) +{ + float v[4]; + + mul_v4_m4v3(v, model, world); + mul_m4_v4(proj, v); + + if (v[3] != 0.0f) { + mul_v3_fl(v, 1.0f / v[3]); + } + + win[0] = view[0] + (view[2] * (v[0] + 1)) * 0.5f; + win[1] = view[1] + (view[3] * (v[1] + 1)) * 0.5f; + win[2] = (v[2] + 1) * 0.5f; +} + +/** + * The same result could be obtained as follows: + * + * \code{.c} + * float projinv[4][4]; + * invert_m4_m4(projinv, projmat); + * co[0] = 2 * co[0] - 1; + * co[1] = 2 * co[1] - 1; + * co[2] = 2 * co[2] - 1; + * mul_project_m4_v3(projinv, co); + * \endcode + * + * But that solution loses much precision. + * Therefore, get the same result without inverting the matrix. + */ +static void gpu_mul_invert_projmat_m4_unmapped_v3_with_precalc( + const struct GPUMatrixUnproject_Precalc *precalc, float co[3]) +{ + /* 'precalc->dims' is the result of 'projmat_dimensions(proj, ...)'. */ + co[0] = precalc->dims.xmin + co[0] * (precalc->dims.xmax - precalc->dims.xmin); + co[1] = precalc->dims.ymin + co[1] * (precalc->dims.ymax - precalc->dims.ymin); + + if (precalc->is_persp) { + co[2] = precalc->dims.zmax * precalc->dims.zmin / + (precalc->dims.zmax + co[2] * (precalc->dims.zmin - precalc->dims.zmax)); + co[0] *= co[2]; + co[1] *= co[2]; + } + else { + co[2] = precalc->dims.zmin + co[2] * (precalc->dims.zmax - precalc->dims.zmin); + } + co[2] *= -1; +} + +bool GPU_matrix_unproject_precalc(struct GPUMatrixUnproject_Precalc *precalc, + const float model[4][4], + const float proj[4][4], + const int view[4]) +{ + precalc->is_persp = proj[3][3] == 0.0f; + projmat_dimensions_db(proj, + &precalc->dims.xmin, + &precalc->dims.xmax, + &precalc->dims.ymin, + &precalc->dims.ymax, + &precalc->dims.zmin, + &precalc->dims.zmax); + if (isinf(precalc->dims.zmax)) { + /* We cannot retrieve the actual value of the clip_end. + * Use `FLT_MAX` to avoid nans. */ + precalc->dims.zmax = FLT_MAX; + } + for (int i = 0; i < 4; i++) { + precalc->view[i] = (float)view[i]; + } + if (!invert_m4_m4(precalc->model_inverted, model)) { + unit_m4(precalc->model_inverted); + return false; + } + return true; +} + +void GPU_matrix_unproject_with_precalc(const struct GPUMatrixUnproject_Precalc *precalc, + const float win[3], + float r_world[3]) +{ + float in[3] = { + (win[0] - precalc->view[0]) / precalc->view[2], + (win[1] - precalc->view[1]) / precalc->view[3], + win[2], + }; + gpu_mul_invert_projmat_m4_unmapped_v3_with_precalc(precalc, in); + mul_v3_m4v3(r_world, precalc->model_inverted, in); +} + +bool GPU_matrix_unproject(const float win[3], + const float model[4][4], + const float proj[4][4], + const int view[4], + float r_world[3]) +{ + struct GPUMatrixUnproject_Precalc precalc; + if (!GPU_matrix_unproject_precalc(&precalc, model, proj, view)) { + zero_v3(r_world); + return false; + } + GPU_matrix_unproject_with_precalc(&precalc, win, r_world); + return true; +} + +const float (*GPU_matrix_model_view_get(float m[4][4]))[4] +{ + if (m) { + copy_m4_m4(m, ModelView); + return m; + } + else { + return ModelView; + } +} + +const float (*GPU_matrix_projection_get(float m[4][4]))[4] +{ + if (m) { + copy_m4_m4(m, Projection); + return m; + } + else { + return Projection; + } +} + +const float (*GPU_matrix_model_view_projection_get(float m[4][4]))[4] +{ + if (m == NULL) { + static Mat4 temp; + m = temp; + } + + mul_m4_m4m4(m, Projection, ModelView); + return m; +} + +const float (*GPU_matrix_normal_get(float m[3][3]))[3] +{ + if (m == NULL) { + static Mat3 temp3; + m = temp3; + } + + copy_m3_m4(m, (const float(*)[4])GPU_matrix_model_view_get(NULL)); + + invert_m3(m); + transpose_m3(m); + + return m; +} + +const float (*GPU_matrix_normal_inverse_get(float m[3][3]))[3] +{ + if (m == NULL) { + static Mat3 temp3; + m = temp3; + } + + GPU_matrix_normal_get(m); + invert_m3(m); + + return m; +} + +void GPU_matrix_bind(const GPUShaderInterface *shaderface) +{ + /* set uniform values to matrix stack values + * call this before a draw call if desired matrices are dirty + * call glUseProgram before this, as glUniform expects program to be bound + */ + + int32_t MV = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_MODELVIEW); + int32_t P = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_PROJECTION); + int32_t MVP = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_MVP); + + int32_t N = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_NORMAL); + int32_t MV_inv = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_MODELVIEW_INV); + int32_t P_inv = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_PROJECTION_INV); + + /* XXX(fclem) this works but this assumes shader is unused inside GPU_shader_uniform_vector. */ + GPUShader *sh = NULL; + if (MV != -1) { + GPU_shader_uniform_vector(sh, MV, 16, 1, (const float *)GPU_matrix_model_view_get(NULL)); + } + if (P != -1) { + GPU_shader_uniform_vector(sh, P, 16, 1, (const float *)GPU_matrix_projection_get(NULL)); + } + if (MVP != -1) { + GPU_shader_uniform_vector( + sh, MVP, 16, 1, (const float *)GPU_matrix_model_view_projection_get(NULL)); + } + if (N != -1) { + GPU_shader_uniform_vector(sh, N, 9, 1, (const float *)GPU_matrix_normal_get(NULL)); + } + if (MV_inv != -1) { + Mat4 m; + GPU_matrix_model_view_get(m); + invert_m4(m); + GPU_shader_uniform_vector(sh, MV_inv, 16, 1, (const float *)m); + } + if (P_inv != -1) { + Mat4 m; + GPU_matrix_projection_get(m); + invert_m4(m); + GPU_shader_uniform_vector(sh, P_inv, 16, 1, (const float *)m); + } + + gpu_matrix_state_active_set_dirty(false); +} + +bool GPU_matrix_dirty_get(void) +{ + GPUMatrixState *state = gpu_context_active_matrix_state_get(); + return state->dirty; +} + +/* -------------------------------------------------------------------- */ +/** \name Python API Helpers + * \{ */ +BLI_STATIC_ASSERT(GPU_PY_MATRIX_STACK_LEN + 1 == MATRIX_STACK_DEPTH, "define mismatch"); + +/* Return int since caller is may subtract. */ + +int GPU_matrix_stack_level_get_model_view(void) +{ + GPUMatrixState *state = gpu_context_active_matrix_state_get(); + return (int)state->model_view_stack.top; +} + +int GPU_matrix_stack_level_get_projection(void) +{ + GPUMatrixState *state = gpu_context_active_matrix_state_get(); + return (int)state->projection_stack.top; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Polygon Offset Hack + * + * Workaround the fact that polygon-offset is implementation dependent. + * We modify the projection matrix \a winmat in order to change the final depth a tiny amount. + * \{ */ + +float GPU_polygon_offset_calc(const float (*winmat)[4], float viewdist, float dist) +{ + /* Seems like we have a factor of 2 more offset than 2.79 for some reason. Correct for this. */ + dist *= 0.5f; + + if (winmat[3][3] > 0.5f) { +#if 1 + return 0.00001f * dist * viewdist; // ortho tweaking +#else + static float depth_fac = 0.0f; + if (depth_fac == 0.0f) { + int depthbits; + glGetIntegerv(GL_DEPTH_BITS, &depthbits); + depth_fac = 1.0f / (float)((1 << depthbits) - 1); + } + offs = (-1.0 / winmat[2][2]) * dist * depth_fac; + + UNUSED_VARS(viewdist); +#endif + } + + /* This adjustment effectively results in reducing the Z value by 0.25%. + * + * winmat[4][3] actually evaluates to `-2 * far * near / (far - near)`, + * is very close to -0.2 with default clip range, + * and is used as the coefficient multiplied by `w / z`, + * thus controlling the z dependent part of the depth value. + */ + return winmat[3][2] * -0.0025f * dist; +} + +/** + * \note \a viewdist is only for ortho at the moment. + */ +void GPU_polygon_offset(float viewdist, float dist) +{ + static float winmat[4][4], offset = 0.0f; + + if (dist != 0.0f) { + /* hack below is to mimic polygon offset */ + GPU_matrix_projection_get(winmat); + + /* dist is from camera to center point */ + + float offs = GPU_polygon_offset_calc(winmat, viewdist, dist); + + winmat[3][2] -= offs; + offset += offs; + } + else { + winmat[3][2] += offset; + offset = 0.0; + } + + GPU_matrix_projection_set(winmat); +} + +/** \} */ |