warzone2100/lib/ivis_opengl/piematrix.cpp

421 lines
10 KiB
C++

/*
This file is part of Warzone 2100.
Copyright (C) 1999-2004 Eidos Interactive
Copyright (C) 2005-2011 Warzone 2100 Project
Warzone 2100 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.
Warzone 2100 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 Warzone 2100; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/** \file
* Matrix manipulation functions.
*/
#include "lib/framework/frame.h"
#include "lib/framework/opengl.h"
#include "lib/framework/fixedpoint.h"
#include "lib/ivis_opengl/pieclip.h"
#include "piematrix.h"
#include "lib/ivis_opengl/piemode.h"
/***************************************************************************/
/*
* Local Definitions
*/
/***************************************************************************/
#define MATRIX_MAX 8
/*
* Matrices are of this form:
* [ a d g j ]
* [ b e h k ]
* [ c f i l ]
* [ 0 0 0 1 ]
*/
struct SDMATRIX
{
SDWORD a, b, c,
d, e, f,
g, h, i,
j, k, l;
};
static SDMATRIX aMatrixStack[MATRIX_MAX];
static SDMATRIX *psMatrix = &aMatrixStack[0];
bool drawing_interface = true;
//*************************************************************************
static const SDMATRIX Identitymatrix = {
FP12_MULTIPLIER, 0, 0,
0, FP12_MULTIPLIER, 0,
0, 0, FP12_MULTIPLIER,
0, 0, 0,
};
static SDWORD _MATRIX_INDEX;
//*************************************************************************
//*** reset transformation matrix stack and make current identity
//*
//******
static void pie_MatReset(void)
{
psMatrix = &aMatrixStack[0];
// make 1st matrix identity
*psMatrix = Identitymatrix;
glLoadIdentity();
}
//*************************************************************************
//*** create new matrix from current transformation matrix and make current
//*
//******
void pie_MatBegin(void)
{
_MATRIX_INDEX++;
ASSERT( _MATRIX_INDEX < MATRIX_MAX, "pie_MatBegin past top of the stack" );
psMatrix++;
aMatrixStack[_MATRIX_INDEX] = aMatrixStack[_MATRIX_INDEX-1];
glPushMatrix();
}
//*************************************************************************
//*** make current transformation matrix previous one on stack
//*
//******
void pie_MatEnd(void)
{
_MATRIX_INDEX--;
ASSERT( _MATRIX_INDEX >= 0, "pie_MatEnd of the bottom of the stack" );
psMatrix--;
glPopMatrix();
}
void pie_MATTRANS(float x, float y, float z)
{
GLfloat matrix[16];
psMatrix->j = x * FP12_MULTIPLIER;
psMatrix->k = y * FP12_MULTIPLIER;
psMatrix->l = z * FP12_MULTIPLIER;
glGetFloatv(GL_MODELVIEW_MATRIX, matrix);
matrix[12] = x;
matrix[13] = y;
matrix[14] = z;
glLoadMatrixf(matrix);
}
void pie_TRANSLATE(int32_t x, int32_t y, int32_t z)
{
/*
* curMatrix = curMatrix . translationMatrix(x, y, z)
*
* [ 1 0 0 x ]
* [ 0 1 0 y ]
* curMatrix = curMatrix . [ 0 0 1 z ]
* [ 0 0 0 1 ]
*/
psMatrix->j += x * psMatrix->a + y * psMatrix->d + z * psMatrix->g;
psMatrix->k += x * psMatrix->b + y * psMatrix->e + z * psMatrix->h;
psMatrix->l += x * psMatrix->c + y * psMatrix->f + z * psMatrix->i;
glTranslatef(x, y, z);
}
//*************************************************************************
//*** matrix scale current transformation matrix
//*
//******
void pie_MatScale(float scale)
{
/*
* s := scale
* curMatrix = curMatrix . scaleMatrix(s, s, s)
*
* [ s 0 0 0 ]
* [ 0 s 0 0 ]
* curMatrix = curMatrix . [ 0 0 s 0 ]
* [ 0 0 0 1 ]
*
* curMatrix = scale * curMatrix
*/
psMatrix->a = psMatrix->a * scale;
psMatrix->b = psMatrix->b * scale;
psMatrix->c = psMatrix->c * scale;
psMatrix->d = psMatrix->d * scale;
psMatrix->e = psMatrix->e * scale;
psMatrix->f = psMatrix->f * scale;
psMatrix->g = psMatrix->g * scale;
psMatrix->h = psMatrix->h * scale;
psMatrix->i = psMatrix->i * scale;
glScalef(scale, scale, scale);
}
//*************************************************************************
//*** matrix rotate y (yaw) current transformation matrix
//*
//******
void pie_MatRotY(uint16_t y)
{
/*
* a := angle
* c := cos(a)
* s := sin(a)
*
* curMatrix = curMatrix . rotationMatrix(a, 0, 1, 0)
*
* [ c 0 s 0 ]
* [ 0 1 0 0 ]
* curMatrix = curMatrix . [ -s 0 c 0 ]
* [ 0 0 0 1 ]
*/
if (y != 0)
{
int t;
int64_t cra = iCos(y), sra = iSin(y);
t = (cra*psMatrix->a - sra*psMatrix->g)>>16;
psMatrix->g = (sra*psMatrix->a + cra*psMatrix->g)>>16;
psMatrix->a = t;
t = (cra*psMatrix->b - sra*psMatrix->h)>>16;
psMatrix->h = (sra*psMatrix->b + cra*psMatrix->h)>>16;
psMatrix->b = t;
t = (cra*psMatrix->c - sra*psMatrix->i)>>16;
psMatrix->i = (sra*psMatrix->c + cra*psMatrix->i)>>16;
psMatrix->c = t;
glRotatef(UNDEG(y), 0.0f, 1.0f, 0.0f);
}
}
//*************************************************************************
//*** matrix rotate z (roll) current transformation matrix
//*
//******
void pie_MatRotZ(uint16_t z)
{
/*
* a := angle
* c := cos(a)
* s := sin(a)
*
* curMatrix = curMatrix . rotationMatrix(a, 0, 0, 1)
*
* [ c -s 0 0 ]
* [ s c 0 0 ]
* curMatrix = curMatrix . [ 0 0 1 0 ]
* [ 0 0 0 1 ]
*/
if (z != 0)
{
int t;
int64_t cra = iCos(z), sra = iSin(z);
t = (cra*psMatrix->a + sra*psMatrix->d)>>16;
psMatrix->d = (cra*psMatrix->d - sra*psMatrix->a)>>16;
psMatrix->a = t;
t = (cra*psMatrix->b + sra*psMatrix->e)>>16;
psMatrix->e = (cra*psMatrix->e - sra*psMatrix->b)>>16;
psMatrix->b = t;
t = (cra*psMatrix->c + sra*psMatrix->f)>>16;
psMatrix->f = (cra*psMatrix->f - sra*psMatrix->c)>>16;
psMatrix->c = t;
glRotatef(UNDEG(z), 0.0f, 0.0f, 1.0f);
}
}
//*************************************************************************
//*** matrix rotate x (pitch) current transformation matrix
//*
//******
void pie_MatRotX(uint16_t x)
{
/*
* a := angle
* c := cos(a)
* s := sin(a)
*
* curMatrix = curMatrix . rotationMatrix(a, 0, 0, 1)
*
* [ 1 0 0 0 ]
* [ 0 c -s 0 ]
* curMatrix = curMatrix . [ 0 s c 0 ]
* [ 0 0 0 1 ]
*/
if (x != 0.f)
{
int t;
int64_t cra = iCos(x), sra = iSin(x);
t = (cra*psMatrix->d + sra*psMatrix->g)>>16;
psMatrix->g = (cra*psMatrix->g - sra*psMatrix->d)>>16;
psMatrix->d = t;
t = (cra*psMatrix->e + sra*psMatrix->h)>>16;
psMatrix->h = (cra*psMatrix->h - sra*psMatrix->e)>>16;
psMatrix->e = t;
t = (cra*psMatrix->f + sra*psMatrix->i)>>16;
psMatrix->i = (cra*psMatrix->i - sra*psMatrix->f)>>16;
psMatrix->f = t;
glRotatef(UNDEG(x), 1.0f, 0.0f, 0.0f);
}
}
/*!
* 3D vector perspective projection
* Projects 3D vector into 2D screen space
* \param v3d 3D vector to project
* \param[out] v2d resulting 2D vector
* \return projected z component of v2d
*/
int32_t pie_RotateProject(const Vector3i *v3d, Vector2i *v2d)
{
/*
* v = curMatrix . v3d
*/
Vector3i v(
v3d->x * psMatrix->a + v3d->y * psMatrix->d + v3d->z * psMatrix->g + psMatrix->j,
v3d->x * psMatrix->b + v3d->y * psMatrix->e + v3d->z * psMatrix->h + psMatrix->k,
v3d->x * psMatrix->c + v3d->y * psMatrix->f + v3d->z * psMatrix->i + psMatrix->l
);
const int zz = v.z >> STRETCHED_Z_SHIFT;
if (zz < MIN_STRETCHED_Z)
{
v2d->x = LONG_WAY; //just along way off screen
v2d->y = LONG_WAY;
}
else
{
v2d->x = rendSurface.xcentre + (v.x / zz);
v2d->y = rendSurface.ycentre - (v.y / zz);
}
return zz;
}
void pie_PerspectiveBegin(void)
{
const float width = pie_GetVideoBufferWidth();
const float height = pie_GetVideoBufferHeight();
const float xangle = width/6.0f;
const float yangle = height/6.0f;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glTranslatef(
(2 * rendSurface.xcentre-width) / width,
(height - 2 * rendSurface.ycentre) / height,
0);
glFrustum(-xangle, xangle, -yangle, yangle, 330, 100000);
glScalef(1, 1, -1);
glMatrixMode(GL_MODELVIEW);
}
void pie_PerspectiveEnd(void)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0f, (double) pie_GetVideoBufferWidth(), (double) pie_GetVideoBufferHeight(), 0.0f, 1.0f, -1.0f);
glMatrixMode(GL_MODELVIEW);
}
void pie_Begin3DScene(void)
{
glDepthRange(0.1, 1);
drawing_interface = false;
}
void pie_BeginInterface(void)
{
glDepthRange(0, 0.1);
drawing_interface = true;
}
void pie_SetGeometricOffset(int x, int y)
{
rendSurface.xcentre = x;
rendSurface.ycentre = y;
}
/** Inverse rotate 3D vector with current rotation matrix.
* @param v1 3D vector to rotate
* @param[out] v2 inverse rotated 3D vector
*/
void pie_VectorInverseRotate0(const Vector3i *v1, Vector3i *v2)
{
/*
* invMatrix = transpose(sub3x3Matrix(curMatrix))
* v2 = invMatrix . v1
*/
v2->x = (v1->x * psMatrix->a + v1->y * psMatrix->b + v1->z * psMatrix->c) / FP12_MULTIPLIER;
v2->y = (v1->x * psMatrix->d + v1->y * psMatrix->e + v1->z * psMatrix->f) / FP12_MULTIPLIER;
v2->z = (v1->x * psMatrix->g + v1->y * psMatrix->h + v1->z * psMatrix->i) / FP12_MULTIPLIER;
}
/** Sets up transformation matrices/quaternions and trig tables
*/
void pie_MatInit(void)
{
// init matrix/quat stack
pie_MatReset();
}
void pie_RotateTranslate3i(const Vector3i *v, Vector3i *s)
{
/*
* [ 1 0 0 0 ] [ 1 0 0 0 ]
* [ 0 0 1 0 ] [ 0 0 1 0 ]
* s = [ 0 1 0 0 ] . curMatrix . [ 0 1 0 0 ] . v
* [ 0 0 0 1 ] [ 0 0 0 1 ]
*/
s->x = ((int64_t)v->x * psMatrix->a + (int64_t)v->y * psMatrix->g + (int64_t)v->z * psMatrix->d + psMatrix->j) / FP12_MULTIPLIER;
s->y = ((int64_t)v->x * psMatrix->c + (int64_t)v->y * psMatrix->i + (int64_t)v->z * psMatrix->f + psMatrix->l) / FP12_MULTIPLIER;
s->z = ((int64_t)v->x * psMatrix->b + (int64_t)v->y * psMatrix->h + (int64_t)v->z * psMatrix->e + psMatrix->k) / FP12_MULTIPLIER;
}