diff options
Diffstat (limited to 'source/blender/gpu/intern/gpu_matrix.c')
-rw-r--r-- | source/blender/gpu/intern/gpu_matrix.c | 550 |
1 files changed, 550 insertions, 0 deletions
diff --git a/source/blender/gpu/intern/gpu_matrix.c b/source/blender/gpu/intern/gpu_matrix.c new file mode 100644 index 00000000000..dab468e6733 --- /dev/null +++ b/source/blender/gpu/intern/gpu_matrix.c @@ -0,0 +1,550 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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 ipmlied 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. + * + * The Original Code is: all of this file. + * + * Contributor(s): Alexandr Kuznetsov, Jason Wilkins + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file source/blender/gpu/intern/gpu_matrix.c + * \ingroup gpu + */ + +#if WITH_GL_PROFILE_COMPAT +#define GPU_MANGLE_DEPRECATED 0 /* Allow use of deprecated OpenGL functions in this file */ +#endif + +/* my interface */ +#include "intern/gpu_matrix_intern.h" + +/* my library */ +#include "GPU_common.h" +#include "GPU_extensions.h" +#include "GPU_safety.h" + +/* internal */ +#include "intern/gpu_common_intern.h" + +/* external */ + +#include "BLI_math_matrix.h" +#include "BLI_math_rotation.h" +#include "BLI_math_vector.h" + +#include "MEM_guardedalloc.h" + + + +typedef GLfloat GPU_matrix[4][4]; + +typedef struct GPU_matrix_stack +{ + GLsizei size; + GLsizei pos; + GPU_matrix* dynstack; +} GPU_matrix_stack; + + + +static GPU_matrix_stack ms_modelview; +static GPU_matrix_stack ms_projection; +static GPU_matrix_stack ms_texture; + +static GPU_matrix_stack* ms_current; +static GLenum ms_current_mode; + + + +#define current_matrix() (ms_current->dynstack[ms_current->pos]) + + + +/* Check if we have a good matrix */ +#ifdef WITH_GPU_SAFETY + +static void checkmat(GLfloat *m) +{ + GLint i; + + for(i = 0; i < 16; i++) { +#if _MSC_VER + GPU_ASSERT(_finite(m[i])); +#else + GPU_ASSERT(!isinf(m[i])); +#endif + } +} + +#define CHECKMAT(m) checkmat((GLfloat*)m) + +#else + +#define CHECKMAT(m) + +#endif + + + +static void ms_init(GPU_matrix_stack* ms, GLint initsize) +{ + BLI_assert(initsize > 0); + + ms->size = initsize; + ms->pos = 0; + ms->dynstack = (GPU_matrix*)MEM_mallocN(ms->size*sizeof(*(ms->dynstack)), "MatrixStack"); +} + + + +static void ms_free(GPU_matrix_stack * ms) +{ + ms->size = 0; + ms->pos = 0; + MEM_freeN(ms->dynstack); + ms->dynstack = NULL; +} + + + +void gpu_matrix_init(void) +{ + ms_init(&ms_texture, 16); + ms_init(&ms_projection, 16); + ms_init(&ms_modelview, 32); + + gpuMatrixMode(GL_TEXTURE); + gpuLoadIdentity(); + + gpuMatrixMode(GL_PROJECTION); + gpuLoadIdentity(); + + gpuMatrixMode(GL_MODELVIEW); + gpuLoadIdentity(); +} + +void gpu_matrix_exit(void) +{ + ms_free(&ms_modelview); + ms_free(&ms_projection); + ms_free(&ms_texture); + + ms_current_mode = 0; + ms_current = NULL; +} + + + +void gpu_commit_matrix(void) +{ + const struct GPUcommon* common = gpu_get_common(); + + GPU_CHECK_NO_ERROR(); + + if (common) { + int i; + + GLfloat (*m)[4] = (GLfloat (*)[4])gpuGetMatrix(GL_MODELVIEW_MATRIX, NULL); + GLfloat (*p)[4] = (GLfloat (*)[4])gpuGetMatrix(GL_PROJECTION_MATRIX, NULL); + + if (common->modelview_matrix != -1) + glUniformMatrix4fv(common->modelview_matrix, 1, GL_FALSE, m[0]); + + if (common->normal_matrix != -1) { + GLfloat n[3][3]; + copy_m3_m4(n, m); + invert_m3(n); + transpose_m3(n); + glUniformMatrix3fv(common->normal_matrix, 1, GL_FALSE, n[0]); + } + + if (common->modelview_matrix_inverse != -1) { + GLfloat i[4][4]; + invert_m4_m4(i, m); + glUniformMatrix4fv(common->modelview_matrix_inverse, 1, GL_FALSE, i[0]); + } + + if (common->modelview_projection_matrix != -1) { + GLfloat pm[4][4]; + mul_m4_m4m4(pm, p, m); + glUniformMatrix4fv(common->modelview_projection_matrix, 1, GL_FALSE, pm[0]); + } + + if (common->projection_matrix != -1) + glUniformMatrix4fv(common->projection_matrix, 1, GL_FALSE, p[0]); + + for (i = 0; i < GPU_MAX_COMMON_TEXCOORDS; i++) { + if (common->texture_matrix[i] != -1) { + GPU_set_common_active_texture(i); + glUniformMatrix4fv(common->texture_matrix[i], 1, GL_FALSE, gpuGetMatrix(GL_TEXTURE_MATRIX, NULL)); + } + } + + GPU_set_common_active_texture(0); + + GPU_CHECK_NO_ERROR(); + + return; + } + +#if defined(WITH_GL_PROFILE_COMPAT) + glMatrixMode(GL_TEXTURE); + glLoadMatrixf(gpuGetMatrix(GL_TEXTURE_MATRIX, NULL)); + + glMatrixMode(GL_PROJECTION); + glLoadMatrixf(gpuGetMatrix(GL_PROJECTION_MATRIX, NULL)); + + glMatrixMode(GL_MODELVIEW); + glLoadMatrixf(gpuGetMatrix(GL_MODELVIEW_MATRIX, NULL)); +#endif + + GPU_CHECK_NO_ERROR(); +} + + + +void gpuPushMatrix(void) +{ + GLsizei new_pos = ms_current->pos + 1; + + GPU_ASSERT(new_pos < ms_current->size); + + if (new_pos < ms_current->size) { + ms_current->pos++; + + gpuLoadMatrix((GLfloat*)ms_current->dynstack[ms_current->pos-1]); + } +} + + + +void gpuPopMatrix(void) +{ + GPU_ASSERT(ms_current->pos != 0); + + if (ms_current->pos != 0) { + ms_current->pos--; + + CHECKMAT(ms_current); + } +} + + + +void gpuMatrixMode(GLenum mode) +{ + GPU_ASSERT(ELEM3(mode, GL_MODELVIEW, GL_PROJECTION, GL_TEXTURE)); + + ms_current_mode = mode; + + switch(mode) { + case GL_MODELVIEW: + ms_current = &ms_modelview; + break; + case GL_PROJECTION: + ms_current = &ms_projection; + break; + case GL_TEXTURE: + ms_current = &ms_texture; + break; + default: + /* ignore */ + break; + } +} + + + +GLenum gpuGetMatrixMode(void) +{ + return ms_current_mode; +} + + + +void gpuLoadMatrix(const GLfloat* m) +{ + copy_m4_m4(current_matrix(), (GLfloat (*)[4])m); + + CHECKMAT(ms_current); +} + + + +const GLfloat* gpuGetMatrix(GLenum type, GLfloat *m) +{ + GPU_matrix_stack* ms_select; + + GPU_ASSERT(ELEM3(type, GL_MODELVIEW_MATRIX, GL_PROJECTION_MATRIX, GL_TEXTURE_MATRIX)); + + switch(type) { + case GL_MODELVIEW_MATRIX: + ms_select = &ms_modelview; + break; + case GL_PROJECTION_MATRIX: + ms_select = &ms_projection; + break; + case GL_TEXTURE_MATRIX: + ms_select = &ms_texture; + break; + default: + return NULL; + } + + if (m) { + copy_m4_m4((GLfloat (*)[4])m, ms_select->dynstack[ms_select->pos]); + return m; + } + else { + return (GLfloat*)(ms_select->dynstack[ms_select->pos]); + } +} + + + +void gpuLoadIdentity(void) +{ + unit_m4(current_matrix()); + + CHECKMAT(ms_current); +} + + + +void gpuTranslate(GLfloat x, GLfloat y, GLfloat z) +{ + translate_m4(current_matrix(), x, y, z); + + CHECKMAT(ms_current); +} + + + +void gpuScale(GLfloat x, GLfloat y, GLfloat z) +{ + scale_m4(current_matrix(), x, y, z); + + CHECKMAT(ms_current); +} + + + +void gpuMultMatrix(const GLfloat *m) +{ + GPU_matrix cm; + + copy_m4_m4(cm, current_matrix()); + mul_m4_m4m4_q(current_matrix(), cm, (GLfloat (*)[4])m); + + CHECKMAT(ms_current); +} + + + +void gpuMultMatrixd(const double *m) +{ + GLfloat mf[16]; + GLint i; + + for(i = 0; i < 16; i++) { + mf[i] = m[i]; + } + + gpuMultMatrix(mf); +} + + + +void gpuRotateVector(GLfloat deg, GLfloat vector[3]) +{ + float rm[3][3]; + GPU_matrix cm; + + axis_angle_to_mat3(rm, vector, DEG2RADF(deg)); + + copy_m4_m4(cm, current_matrix()); + mul_m4_m3m4_q(current_matrix(), cm, rm); + + CHECKMAT(ms_current); +} + + + +void gpuRotateAxis(GLfloat deg, char axis) +{ + rotate_m4(current_matrix(), axis, DEG2RADF(deg)); + + CHECKMAT(ms_current); +} + + + +void gpuRotateRight(char type) +{ + rotate_m4_right(current_matrix(), type); + + CHECKMAT(ms_current); +} + + + +void gpuLoadOrtho(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat nearVal, GLfloat farVal) +{ + mat4_ortho_set(current_matrix(), left, right, bottom, top, nearVal, farVal); + + CHECKMAT(ms_current); +} + + + +void gpuOrtho(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat nearVal, GLfloat farVal) +{ + GPU_matrix om; + + mat4_ortho_set(om, left, right, bottom, top, nearVal, farVal); + + gpuMultMatrix((GLfloat*)om); +} + + + +void gpuFrustum(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat nearVal, GLfloat farVal) +{ + GPU_matrix fm; + + mat4_frustum_set(fm, left, right, bottom, top, nearVal, farVal); + + gpuMultMatrix((GLfloat*) fm); +} + + + +void gpuLoadFrustum(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat nearVal, GLfloat farVal) +{ + mat4_frustum_set(current_matrix(), left, right, bottom, top, nearVal, farVal); + + CHECKMAT(ms_current); +} + + + +void gpuLookAt(GLfloat eyeX, GLfloat eyeY, GLfloat eyeZ, GLfloat centerX, GLfloat centerY, GLfloat centerZ, GLfloat upX, GLfloat upY, GLfloat upZ) +{ + GPU_matrix cm; + GLfloat lookdir[3]; + GLfloat camup[3] = {upX, upY, upZ}; + + lookdir[0] = centerX - eyeX; + lookdir[1] = centerY - eyeY; + lookdir[2] = centerZ - eyeZ; + + mat4_look_from_origin(cm, lookdir, camup); + + gpuMultMatrix((GLfloat*) cm); + gpuTranslate(-eyeX, -eyeY, -eyeZ); +} + + + +void gpuProject(const GLfloat obj[3], const GLfloat model[16], const GLfloat proj[16], const GLint view[4], GLfloat win[3]) +{ + float v[4]; + + mul_v4_m4v3(v, (float(*)[4])model, obj); + mul_m4_v4((float(*)[4])proj, v); + + 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; +} + + + +GLboolean gpuUnProject(const GLfloat win[3], const GLfloat model[16], const GLfloat proj[16], const GLint view[4], GLfloat obj[3]) +{ + GLfloat pm[4][4]; + GLfloat in[4]; + GLfloat out[4]; + + mul_m4_m4m4(pm, (float(*)[4])proj, (float(*)[4])model); + + if (!invert_m4(pm)) { + return GL_FALSE; + } + + in[0]=win[0]; + in[1]=win[1]; + in[2]=win[2]; + in[3]=1; + + /* Map x and y from window coordinates */ + in[0] = (in[0] - view[0]) / view[2]; + in[1] = (in[1] - view[1]) / view[3]; + + /* Map to range -1 to 1 */ + in[0] = 2 * in[0] - 1; + in[1] = 2 * in[1] - 1; + in[2] = 2 * in[2] - 1; + + mul_v4_m4v3(out, pm, in); + + if (out[3] == 0.0) { + return GL_FALSE; + } + else { + out[0] /= out[3]; + out[1] /= out[3]; + out[2] /= out[3]; + + obj[0] = out[0]; + obj[1] = out[1]; + obj[2] = out[2]; + + return GL_TRUE; + } +} + + + +void GPU_feedback_vertex_3fv(GLenum type, GLfloat x, GLfloat y, GLfloat z, GLfloat out[3]) +{ + GPU_matrix* m = (GPU_matrix*)gpuGetMatrix(type, NULL); + float in[3] = {x, y, z}; + mul_v3_m4v3(out, m[0], in); +} + + + +void GPU_feedback_vertex_4fv(GLenum type, GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat out[3]) +{ + GPU_matrix* m = (GPU_matrix*)gpuGetMatrix(type, NULL); + float in[4] = {x, y, z, w}; + mul_v4_m4v4(out, m[0], in); +} + + + +void GPU_feedback_vertex_4dv(GLenum type, GLdouble x, GLdouble y, GLdouble z, GLdouble w, GLdouble out[3]) +{ + GPU_matrix* m = (GPU_matrix*)gpuGetMatrix(type, NULL); + double in[4] = {x, y, z, w}; + mul_v4d_m4v4d(out, m[0], in); +} |