/* KallistiGL for KallistiOS ##version## libgl/gl-matrix.c Copyright (C) 2013-2014 Josh Pearson Copyright (C) 2014 Lawrence Sebald Some functionality adapted from the original KOS libgl: Copyright (C) 2001 Dan Potter The GL matrix operations use the KOS SH4 matrix operations. Basically, we keep two seperate matrix stacks: 1.) Internal GL API Matrix Stack ( screenview, modelview, etc. ) ( fixed stack size ) 2.) External Matrix Stack for client to push / pop ( size of each stack is determined by MAX_MATRICES ) */ #include #include "gl.h" #include "glu.h" #include "gl-api.h" #include "gl-sh4.h" /* This Matrix contains the GL Base Stack */ static matrix4f Matrix[GL_MATRIX_COUNT] __attribute__((aligned(32))); static GLsizei MatrixMode = 0; /* This Matrix contains the GL Push/Pop Stack ( fixed size per mode, 32 matrices )*/ static const GLsizei MAX_MATRICES = 32; static matrix4f MatrixStack[GL_MATRIX_COUNT][32] __attribute__((aligned(32))); static GLsizei MatrixStackPos[GL_MATRIX_COUNT]; /* Viewport mapping */ static GLfloat gl_viewport_scale[3], gl_viewport_offset[3]; /* Depth range */ static GLclampf gl_depthrange_near, gl_depthrange_far; /* Viewport size */ static GLint gl_viewport_x1, gl_viewport_y1, gl_viewport_width, gl_viewport_height; /* Frustum attributes */ typedef struct { float left, right, bottom, top, znear, zfar; } gl_frustum_t; static gl_frustum_t gl_frustum; /* Frustum Matrix */ static matrix4f FrustumMatrix __attribute__((aligned(32))) = { { 0.0f, 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f, -1.0f }, { 0.0f, 0.0f, 0.0f, 0.0f } }; /* Ortho Matrix */ static matrix4f OrthoMatrix __attribute__((aligned(32))) = { { 0.0f, 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f, 1.0f } }; /* Matrix for user to submit externally, ensure 32byte allignment */ static matrix4f ml __attribute__((aligned(32))); /* Look-At Matrix */ static matrix4f MatrixLookAt __attribute__((aligned(32))) = { { 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 } }; /* Modelview Rotation Matrix - Applied to Vertex Normal when Lighting is Enabled */ static matrix4f MatrixMdlRot __attribute__((aligned(32))) = { { 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 } }; void glMatrixMode(GLenum mode) { if(mode >= GL_SCREENVIEW && mode <= GL_IDENTITY) MatrixMode = mode; } void glPushMatrix() { if(MatrixStackPos[MatrixMode] < MAX_MATRICES - 1) { mat_load(Matrix + MatrixMode); mat_store(&MatrixStack[MatrixMode][MatrixStackPos[MatrixMode]]); ++MatrixStackPos[MatrixMode]; } } void glPopMatrix() { if(MatrixStackPos[MatrixMode]) { --MatrixStackPos[MatrixMode]; mat_load(&MatrixStack[MatrixMode][MatrixStackPos[MatrixMode]]); mat_store(Matrix + MatrixMode); } } void glLoadIdentity() { mat_load(Matrix + GL_IDENTITY); mat_store(Matrix + MatrixMode); if(MatrixMode == GL_MODELVIEW) { mat_store(&MatrixMdlRot); mat_store(&MatrixLookAt); } } void glTranslatef(GLfloat x, GLfloat y, GLfloat z) { mat_load(Matrix + MatrixMode); mat_translate(x, y, z); mat_store(Matrix + MatrixMode); } void glScalef(GLfloat x, GLfloat y, GLfloat z) { mat_load(Matrix + MatrixMode); mat_scale(x, y, z); mat_store(Matrix + MatrixMode); } void glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) { float r = DEG2RAD * -angle; vec3f_normalize(x, y, z); mat_load(Matrix + MatrixMode); mat_rotate(r * x, r * y, r * z); mat_store(Matrix + MatrixMode); if(MatrixMode == GL_MODELVIEW) { mat_load(&MatrixMdlRot); mat_rotate(r * x, r * y, r * z); mat_store(&MatrixMdlRot); } } /* Load an arbitrary matrix */ void glLoadMatrixf(const GLfloat *m) { memcpy(ml, m, sizeof(matrix4f)); mat_load(&ml); mat_store(Matrix + MatrixMode); } /* Load an arbitrary transposed matrix */ void glLoadTransposeMatrixf(const GLfloat *m) { ml[0][0] = m[0]; ml[0][1] = m[4]; ml[0][2] = m[8]; ml[0][3] = m[12]; ml[1][0] = m[1]; ml[1][1] = m[5]; ml[1][2] = m[9]; ml[1][3] = m[13]; ml[2][0] = m[2]; ml[2][1] = m[6]; ml[2][2] = m[10]; ml[2][3] = m[14]; ml[3][0] = m[3]; ml[3][1] = m[7]; ml[3][2] = m[11]; ml[3][3] = m[15]; mat_load(&ml); mat_store(Matrix + MatrixMode); } /* Multiply the current matrix by an arbitrary matrix */ void glMultMatrixf(const GLfloat *m) { memcpy(ml, m, sizeof(matrix4f)); mat_load(Matrix + MatrixMode); mat_apply(&ml); mat_store(Matrix + MatrixMode); } /* Multiply the current matrix by an arbitrary transposed matrix */ void glMultTransposeMatrixf(const GLfloat *m) { ml[0][0] = m[0]; ml[0][1] = m[4]; ml[0][2] = m[8]; ml[0][3] = m[12]; ml[1][0] = m[1]; ml[1][1] = m[5]; ml[1][2] = m[9]; ml[1][3] = m[13]; ml[2][0] = m[2]; ml[2][1] = m[6]; ml[2][2] = m[10]; ml[2][3] = m[14]; ml[3][0] = m[3]; ml[3][1] = m[7]; ml[3][2] = m[11]; ml[3][3] = m[15]; mat_load(Matrix + MatrixMode); mat_apply(&ml); mat_store(Matrix + MatrixMode); } /* Set the depth range */ void glDepthRange(GLclampf n, GLclampf f) { /* clamp the values... */ if(n < 0.0f) n = 0.0f; else if(n > 1.0f) n = 1.0f; if(f < 0.0f) f = 0.0f; else if(f > 1.0f) f = 1.0f; gl_depthrange_near = n; gl_depthrange_far = f; /* Adjust the viewport scale and offset for Z */ gl_viewport_scale[2] = ((f - n) / 2.0f); gl_viewport_offset[2] = (n + f) / 2.0f; } /* Set the GL viewport */ void glViewport(GLint x, GLint y, GLsizei width, GLsizei height) { gl_viewport_x1 = x; gl_viewport_y1 = y; gl_viewport_width = width; gl_viewport_height = height; /* Calculate the viewport scale and offset */ gl_viewport_scale[0] = (GLfloat)width / 2.0f; gl_viewport_offset[0] = gl_viewport_scale[0] + (GLfloat)x; gl_viewport_scale[1] = (GLfloat)height / 2.0f; gl_viewport_offset[1] = gl_viewport_scale[1] + (GLfloat)y; gl_viewport_scale[2] = (gl_depthrange_far - gl_depthrange_near) / 2.0f; gl_viewport_offset[2] = (gl_depthrange_near + gl_depthrange_far) / 2.0f; gl_viewport_offset[2] += 0.0001f; /* Set the Screenview Matrix based on the viewport */ Matrix[GL_SCREENVIEW][0][0] = gl_viewport_scale[0]; Matrix[GL_SCREENVIEW][1][1] = -gl_viewport_scale[1]; Matrix[GL_SCREENVIEW][2][2] = 1; Matrix[GL_SCREENVIEW][3][0] = gl_viewport_offset[0]; Matrix[GL_SCREENVIEW][3][1] = vid_mode->height - gl_viewport_offset[1]; } /* Set the GL frustum */ void glFrustum(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat znear, GLfloat zfar) { gl_frustum.left = left; gl_frustum.right = right; gl_frustum.bottom = bottom; gl_frustum.top = top; gl_frustum.znear = znear; gl_frustum.zfar = zfar; FrustumMatrix[0][0] = (2.0f * znear) / (right - left); FrustumMatrix[2][0] = (right + left) / (right - left); FrustumMatrix[1][1] = (2.0f * znear) / (top - bottom); FrustumMatrix[2][1] = (top + bottom) / (top - bottom); FrustumMatrix[2][2] = zfar / (zfar - znear); FrustumMatrix[3][2] = -(zfar * znear) / (zfar - znear); mat_load(Matrix + MatrixMode); mat_apply(&FrustumMatrix); mat_store(Matrix + MatrixMode); } /* Ortho */ void glOrtho(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat znear, GLfloat zfar) { OrthoMatrix[0][0] = 2.0f / (right - left); OrthoMatrix[1][1] = 2.0f / (top - bottom); OrthoMatrix[2][2] = -2.0f / (zfar - znear); OrthoMatrix[3][0] = -(right + left) / (right - left);; OrthoMatrix[3][1] = -(top + bottom) / (top - bottom); OrthoMatrix[3][2] = -(zfar + znear) / (zfar - znear); mat_load(Matrix + MatrixMode); mat_apply(&OrthoMatrix); mat_store(Matrix + MatrixMode); } /* Set the Perspective */ void gluPerspective(GLfloat angle, GLfloat aspect, GLfloat znear, GLfloat zfar) { GLfloat xmin, xmax, ymin, ymax; ymax = znear * ftan(angle * F_PI / 360.0f); ymin = -ymax; xmin = ymin * aspect; xmax = ymax * aspect; glFrustum(xmin, xmax, ymin, ymax, znear, zfar); } /* Vector Cross Product - Used by glhLookAtf2 */ void vec3f_cross(vector3f v1, vector3f v2, vector3f result) { result[0] = v1[1] * v2[2] - v1[2] * v2[1]; result[1] = v1[2] * v2[0] - v1[0] * v2[2]; result[2] = v1[0] * v2[1] - v1[1] * v2[0]; } /* glhLookAtf2 adapted from http://www.opengl.org/wiki/GluLookAt_code */ void glhLookAtf2(vector3f eyePosition3D, vector3f center3D, vector3f upVector3D) { vector3f forward, side, up; _glKosSetEyePosition(eyePosition3D); vec3f_sub_normalize(center3D[0], center3D[1], center3D[2], eyePosition3D[0], eyePosition3D[1], eyePosition3D[2], forward[0], forward[1], forward[2]); //Side = forward x up vec3f_cross(forward, upVector3D, side); vec3f_normalize(side[0], side[1], side[2]); //Recompute up as: up = side x forward vec3f_cross(side, forward, up); MatrixLookAt[0][0] = side[0]; MatrixLookAt[1][0] = side[1]; MatrixLookAt[2][0] = side[2]; MatrixLookAt[3][0] = 0; MatrixLookAt[0][1] = up[0]; MatrixLookAt[1][1] = up[1]; MatrixLookAt[2][1] = up[2]; MatrixLookAt[3][1] = 0; MatrixLookAt[0][2] = -forward[0]; MatrixLookAt[1][2] = -forward[1]; MatrixLookAt[2][2] = -forward[2]; MatrixLookAt[3][2] = 0; MatrixLookAt[0][3] = MatrixLookAt[1][3] = MatrixLookAt[2][3] = 0; MatrixLookAt[3][3] = 1; // Does not modify internal Modelview matrix mat_load(&MatrixLookAt); mat_translate(-eyePosition3D[0], -eyePosition3D[1], -eyePosition3D[2]); mat_apply(Matrix + GL_MODELVIEW); mat_store(Matrix + GL_MODELVIEW); } void gluLookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez, GLfloat centerx, GLfloat centery, GLfloat centerz, GLfloat upx, GLfloat upy, GLfloat upz) { vector3f eye = { eyex, eyey, eyez }; vector3f point = { centerx, centery, centerz }; vector3f up = { upx, upy, upz }; glhLookAtf2(eye, point, up); } void _glKosMatrixApplyRender() { mat_load(Matrix + GL_SCREENVIEW); mat_apply(Matrix + GL_PROJECTION); mat_apply(Matrix + GL_MODELVIEW); mat_store(Matrix + GL_RENDER); } void _glKosMatrixLoadRender() { mat_load(Matrix + GL_RENDER); } void _glKosMatrixLoadTexture() { mat_load(Matrix + GL_TEXTURE); } void _glKosMatrixLoadModelView() { mat_load(Matrix + GL_MODELVIEW); } void _glKosMatrixLoadModelRot() { mat_load(&MatrixMdlRot); } void _glKosMatrixApplyScreenSpace() { mat_load(Matrix + GL_SCREENVIEW); mat_apply(Matrix + GL_PROJECTION); mat_apply(&MatrixLookAt); } void _glKosInitMatrix() { mat_identity(); mat_store(Matrix + GL_SCREENVIEW); mat_store(Matrix + GL_PROJECTION); mat_store(Matrix + GL_MODELVIEW); mat_store(Matrix + GL_TEXTURE); mat_store(Matrix + GL_IDENTITY); mat_store(Matrix + GL_RENDER); int i; for(i = 0; i < GL_MATRIX_COUNT; i++) MatrixStackPos[i] = 0; glDepthRange(0.0f, 1.0f); glViewport(0, 0, vid_mode->width, vid_mode->height); } void glKosGetMatrix(GLenum mode, GLfloat *params) { if(mode < GL_SCREENVIEW || mode > GL_RENDER) *params = (GLfloat)GL_INVALID_ENUM; memcpy(params, Matrix + mode, sizeof(GLfloat) * 16); }