417 lines
12 KiB
C
417 lines
12 KiB
C
#include <dc/matrix.h>
|
|
|
|
#include "../include/gl.h"
|
|
#include "../containers/stack.h"
|
|
|
|
#define DEG2RAD (0.01745329251994329576923690768489)
|
|
|
|
/* 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;
|
|
|
|
static Stack MATRIX_STACKS[3]; // modelview, projection, texture
|
|
static matrix_t NORMAL_MATRIX __attribute__((aligned(32)));
|
|
static matrix_t SCREENVIEW_MATRIX __attribute__((aligned(32)));
|
|
static matrix_t RENDER_MATRIX __attribute__((aligned(32)));
|
|
|
|
static GLenum MATRIX_MODE = GL_MODELVIEW;
|
|
static GLubyte MATRIX_IDX = 0;
|
|
|
|
static const matrix_t 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}
|
|
};
|
|
|
|
void APIENTRY glDepthRange(GLclampf n, GLclampf f);
|
|
|
|
void initMatrices() {
|
|
init_stack(&MATRIX_STACKS[0], sizeof(matrix_t), 32);
|
|
init_stack(&MATRIX_STACKS[1], sizeof(matrix_t), 32);
|
|
init_stack(&MATRIX_STACKS[2], sizeof(matrix_t), 32);
|
|
|
|
stack_push(&MATRIX_STACKS[0], IDENTITY);
|
|
stack_push(&MATRIX_STACKS[1], IDENTITY);
|
|
stack_push(&MATRIX_STACKS[2], IDENTITY);
|
|
|
|
memcpy(NORMAL_MATRIX, IDENTITY, sizeof(matrix_t));
|
|
memcpy(SCREENVIEW_MATRIX, IDENTITY, sizeof(matrix_t));
|
|
|
|
glDepthRange(0.0f, 1.0f);
|
|
glViewport(0, 0, vid_mode->width, vid_mode->height);
|
|
}
|
|
|
|
#define swap(a, b) { \
|
|
GLfloat x = (a); \
|
|
a = b; \
|
|
b = x; \
|
|
}
|
|
|
|
static void inverse(GLfloat* m) {
|
|
GLfloat f4 = m[4];
|
|
GLfloat f8 = m[8];
|
|
GLfloat f1 = m[1];
|
|
GLfloat f9 = m[9];
|
|
GLfloat f2 = m[2];
|
|
GLfloat f6 = m[6];
|
|
GLfloat f12 = m[12];
|
|
GLfloat f13 = m[13];
|
|
GLfloat f14 = m[14];
|
|
|
|
m[1] = f4;
|
|
m[2] = f8;
|
|
m[4] = f1;
|
|
m[6] = f9;
|
|
m[8] = f2;
|
|
m[9] = f6;
|
|
m[12] = -(f12 * m[0] + f13 * m[4] + f14 * m[8]);
|
|
m[13] = -(f12 * m[1] + f13 * m[5] + f14 * m[9]);
|
|
m[14] = -(f12 * m[2] + f13 * m[6] + f14 * m[10]);
|
|
}
|
|
|
|
static void transpose(GLfloat* m) {
|
|
swap(m[1], m[4]);
|
|
swap(m[2], m[8]);
|
|
swap(m[3], m[12]);
|
|
swap(m[6], m[9]);
|
|
swap(m[7], m[3]);
|
|
swap(m[11], m[14]);
|
|
}
|
|
|
|
static void recalculateNormalMatrix() {
|
|
memcpy(NORMAL_MATRIX, stack_top(MATRIX_STACKS + (GL_MODELVIEW & 0xF)), sizeof(matrix_t));
|
|
inverse((GLfloat*) NORMAL_MATRIX);
|
|
transpose((GLfloat*) NORMAL_MATRIX);
|
|
}
|
|
|
|
void APIENTRY glMatrixMode(GLenum mode) {
|
|
MATRIX_MODE = mode;
|
|
MATRIX_IDX = mode & 0xF;
|
|
}
|
|
|
|
void APIENTRY glPushMatrix() {
|
|
stack_push(MATRIX_STACKS + MATRIX_IDX, stack_top(MATRIX_STACKS + MATRIX_IDX));
|
|
}
|
|
|
|
void APIENTRY glPopMatrix() {
|
|
stack_pop(MATRIX_STACKS + MATRIX_IDX);
|
|
if(MATRIX_MODE == GL_MODELVIEW) {
|
|
recalculateNormalMatrix();
|
|
}
|
|
}
|
|
|
|
void APIENTRY glLoadIdentity() {
|
|
stack_replace(MATRIX_STACKS + MATRIX_IDX, IDENTITY);
|
|
}
|
|
|
|
void APIENTRY glTranslatef(GLfloat x, GLfloat y, GLfloat z) {
|
|
mat_load(stack_top(MATRIX_STACKS + MATRIX_IDX));
|
|
mat_translate(x, y, z);
|
|
mat_store(stack_top(MATRIX_STACKS + MATRIX_IDX));
|
|
|
|
if(MATRIX_MODE == GL_MODELVIEW) {
|
|
recalculateNormalMatrix();
|
|
}
|
|
}
|
|
|
|
|
|
void APIENTRY glScalef(GLfloat x, GLfloat y, GLfloat z) {
|
|
mat_load(stack_top(MATRIX_STACKS + MATRIX_IDX));
|
|
mat_scale(x, y, z);
|
|
mat_store(stack_top(MATRIX_STACKS + MATRIX_IDX));
|
|
|
|
if(MATRIX_MODE == GL_MODELVIEW) {
|
|
recalculateNormalMatrix();
|
|
}
|
|
}
|
|
|
|
void APIENTRY glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) {
|
|
float r = DEG2RAD * -angle;
|
|
|
|
vec3f_normalize(x, y, z);
|
|
|
|
mat_load(stack_top(MATRIX_STACKS + MATRIX_IDX));
|
|
mat_rotate(r * x, r * y, r * z);
|
|
mat_store(stack_top(MATRIX_STACKS + MATRIX_IDX));
|
|
|
|
if(MATRIX_MODE == GL_MODELVIEW) {
|
|
recalculateNormalMatrix();
|
|
}
|
|
}
|
|
|
|
/* Load an arbitrary matrix */
|
|
void APIENTRY glLoadMatrixf(const GLfloat *m) {
|
|
stack_replace(MATRIX_STACKS + MATRIX_IDX, m);
|
|
|
|
if(MATRIX_MODE == GL_MODELVIEW) {
|
|
recalculateNormalMatrix();
|
|
}
|
|
}
|
|
|
|
/* Ortho */
|
|
void APIENTRY glOrtho(GLfloat left, GLfloat right,
|
|
GLfloat bottom, GLfloat top,
|
|
GLfloat znear, GLfloat zfar) {
|
|
|
|
/* Ortho Matrix */
|
|
static matrix_t 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 }
|
|
};
|
|
|
|
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(stack_top(MATRIX_STACKS + MATRIX_MODE));
|
|
mat_apply(&OrthoMatrix);
|
|
mat_store(stack_top(MATRIX_STACKS + MATRIX_MODE));
|
|
}
|
|
|
|
|
|
/* Set the GL frustum */
|
|
void APIENTRY glFrustum(GLfloat left, GLfloat right,
|
|
GLfloat bottom, GLfloat top,
|
|
GLfloat znear, GLfloat zfar) {
|
|
|
|
/* Frustum Matrix */
|
|
static matrix_t 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 }
|
|
};
|
|
|
|
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(stack_top(MATRIX_STACKS + MATRIX_IDX));
|
|
mat_apply(&FrustumMatrix);
|
|
mat_store(stack_top(MATRIX_STACKS + MATRIX_IDX));
|
|
}
|
|
|
|
/* 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);
|
|
}
|
|
|
|
/* Multiply the current matrix by an arbitrary matrix */
|
|
void glMultMatrixf(const GLfloat *m) {
|
|
static matrix_t TEMP __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 }
|
|
};
|
|
|
|
memcpy(TEMP, m, sizeof(matrix_t));
|
|
|
|
mat_load(stack_top(MATRIX_STACKS + MATRIX_IDX));
|
|
mat_apply(&TEMP);
|
|
mat_store(stack_top(MATRIX_STACKS + MATRIX_IDX));
|
|
|
|
if(MATRIX_MODE == GL_MODELVIEW) {
|
|
recalculateNormalMatrix();
|
|
}
|
|
}
|
|
|
|
/* Load an arbitrary transposed matrix */
|
|
void glLoadTransposeMatrixf(const GLfloat *m) {
|
|
stack_replace(MATRIX_STACKS + MATRIX_IDX, m);
|
|
transpose(stack_top(MATRIX_STACKS + MATRIX_IDX));
|
|
|
|
if(MATRIX_MODE == GL_MODELVIEW) {
|
|
recalculateNormalMatrix();
|
|
}
|
|
}
|
|
|
|
/* Multiply the current matrix by an arbitrary transposed matrix */
|
|
void glMultTransposeMatrixf(const GLfloat *m) {
|
|
static matrix_t ml;
|
|
|
|
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(stack_top(MATRIX_STACKS + MATRIX_IDX));
|
|
mat_apply(&ml);
|
|
mat_store(stack_top(MATRIX_STACKS + MATRIX_IDX));
|
|
|
|
if(MATRIX_MODE == GL_MODELVIEW) {
|
|
recalculateNormalMatrix();
|
|
}
|
|
}
|
|
|
|
/* Set the GL viewport */
|
|
void APIENTRY 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 */
|
|
SCREENVIEW_MATRIX[0][0] = gl_viewport_scale[0];
|
|
SCREENVIEW_MATRIX[1][1] = -gl_viewport_scale[1];
|
|
SCREENVIEW_MATRIX[2][2] = 1;
|
|
SCREENVIEW_MATRIX[3][0] = gl_viewport_offset[0];
|
|
SCREENVIEW_MATRIX[3][1] = vid_mode->height - gl_viewport_offset[1];
|
|
}
|
|
|
|
/* Set the depth range */
|
|
void APIENTRY 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;
|
|
}
|
|
|
|
/* Vector Cross Product - Used by glhLookAtf2 */
|
|
static inline void vec3f_cross(const GLfloat* v1, const GLfloat* v2, GLfloat* 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(const GLfloat* eyePosition3D,
|
|
const GLfloat* center3D,
|
|
const GLfloat* upVector3D) {
|
|
|
|
/* Look-At Matrix */
|
|
static matrix_t 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 }
|
|
};
|
|
|
|
GLfloat forward[3];
|
|
GLfloat side[3];
|
|
GLfloat up[3];
|
|
|
|
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(stack_top(MATRIX_STACKS + (GL_MODELVIEW & 0xF)));
|
|
mat_store(stack_top(MATRIX_STACKS + (GL_MODELVIEW & 0xF)));
|
|
}
|
|
|
|
void gluLookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez, GLfloat centerx,
|
|
GLfloat centery, GLfloat centerz, GLfloat upx, GLfloat upy,
|
|
GLfloat upz) {
|
|
GLfloat eye [] = { eyex, eyey, eyez };
|
|
GLfloat point [] = { centerx, centery, centerz };
|
|
GLfloat up [] = { upx, upy, upz };
|
|
glhLookAtf2(eye, point, up);
|
|
}
|
|
|
|
void _applyRenderMatrix() {
|
|
mat_load(&SCREENVIEW_MATRIX);
|
|
mat_apply(stack_top(MATRIX_STACKS + (GL_PROJECTION & 0xF)));
|
|
mat_apply(stack_top(MATRIX_STACKS + (GL_MODELVIEW & 0xF)));
|
|
mat_store(&RENDER_MATRIX);
|
|
}
|
|
|
|
void _matrixLoadRender() {
|
|
mat_load(&RENDER_MATRIX);
|
|
}
|
|
|
|
void _matrixLoadTexture() {
|
|
mat_load(stack_top(MATRIX_STACKS + (GL_TEXTURE & 0xF)));
|
|
}
|
|
|
|
void _matrixLoadModelView() {
|
|
mat_load(stack_top(MATRIX_STACKS + (GL_MODELVIEW & 0xF)));
|
|
}
|
|
|
|
void _matrixLoadNormal() {
|
|
mat_load(&NORMAL_MATRIX);
|
|
}
|