Blob Blame Raw

#include "private.h"


// matrix

void heliMatrix4Identity(double *r) {
	r[ 0] = 1; r[ 1] = 0; r[ 2] = 0; r[ 3] = 0;
	r[ 4] = 0; r[ 5] = 1; r[ 6] = 0; r[ 7] = 0;
	r[ 8] = 0; r[ 9] = 0; r[10] = 1; r[11] = 0;
	r[12] = 0; r[13] = 0; r[14] = 0; r[15] = 1;
}

void heliMatrix4Translation(double *r, double x, double y, double z) {
	r[ 0] = 1; r[ 1] = 0; r[ 2] = 0; r[ 3] = 0;
	r[ 4] = 0; r[ 5] = 1; r[ 6] = 0; r[ 7] = 0;
	r[ 8] = 0; r[ 9] = 0; r[10] = 1; r[11] = 0;
	r[12] = x; r[13] = y; r[14] = z; r[15] = 1;
}

void heliMatrix4Scale(double *r, double x, double y, double z) {
	r[ 0] = x; r[ 1] = 0; r[ 2] = 0; r[ 3] = 0;
	r[ 4] = 0; r[ 5] = y; r[ 6] = 0; r[ 7] = 0;
	r[ 8] = 0; r[ 9] = 0; r[10] = z; r[11] = 0;
	r[12] = 0; r[13] = 0; r[14] = 0; r[15] = 1;
}

void heliMatrix4RotationZ(double *r, double a) {
	double s = sin(a);
	double c = cos(a);
	r[ 0] = c; r[ 1] = s; r[ 2] = 0; r[ 3] = 0;
	r[ 4] =-s; r[ 5] = c; r[ 6] = 0; r[ 7] = 0;
	r[ 8] = 0; r[ 9] = 0; r[10] = 1; r[11] = 0;
	r[12] = 0; r[13] = 0; r[14] = 0; r[15] = 1;
}

void heliMatrix4MultVec(double *r, const double *m, const double *v) {
	r[0] = v[0]*m[0] + v[1]*m[4] + v[2]*m[ 8] + v[3]*m[12];
	r[1] = v[0]*m[1] + v[1]*m[5] + v[2]*m[ 9] + v[3]*m[13];
	r[2] = v[0]*m[2] + v[1]*m[6] + v[2]*m[10] + v[3]*m[14];
	r[3] = v[0]*m[3] + v[1]*m[7] + v[2]*m[11] + v[3]*m[15];
}

void heliMatrix4Mult(double *r, const double *a, const double *b) {
	heliMatrix4MultVec(r +  0, a, b +  0);
	heliMatrix4MultVec(r +  4, a, b +  4);
	heliMatrix4MultVec(r +  8, a, b +  8);
	heliMatrix4MultVec(r + 12, a, b + 12);
}

int heliMatrix4Invert(double *r, const double *m) {
	r[ 0] = m[ 5]*(m[10]*m[15] - m[11]*m[14]) + m[ 6]*(m[11]*m[13] - m[ 9]*m[15]) + m[ 7]*(m[ 9]*m[14] - m[10]*m[13]);
	r[ 4] = m[ 4]*(m[11]*m[14] - m[10]*m[15]) + m[ 6]*(m[ 8]*m[15] - m[11]*m[12]) + m[ 7]*(m[10]*m[12] - m[ 8]*m[14]);
	r[ 8] = m[ 4]*(m[ 9]*m[15] - m[11]*m[13]) + m[ 5]*(m[11]*m[12] - m[ 8]*m[15]) + m[ 7]*(m[ 8]*m[13] - m[ 9]*m[12]);
	r[12] = m[ 4]*(m[10]*m[13] - m[ 9]*m[14]) + m[ 5]*(m[ 8]*m[14] - m[10]*m[12]) + m[ 6]*(m[ 9]*m[12] - m[ 8]*m[13]);
	
	double det = m[ 0]*r[0] + m[ 1]*r[4] + m[ 2]*r[8] + m[ 3]*r[12];
	if (fabs(det) <= HELI_PRECISION) {
		memset(r, 0, sizeof(*r)*16);
		return FALSE;
	}
	det = 1/det;
	r[ 0] *= det;
	r[ 4] *= det;
	r[ 8] *= det;
	r[12] *= det;
	
	r[ 1] = det*(m[ 1]*(m[11]*m[14] - m[10]*m[15]) + m[ 2]*(m[ 9]*m[15] - m[11]*m[13]) + m[ 3]*(m[10]*m[13] - m[ 9]*m[14]));
	r[ 5] = det*(m[ 0]*(m[10]*m[15] - m[11]*m[14]) + m[ 2]*(m[11]*m[12] - m[ 8]*m[15]) + m[ 3]*(m[ 8]*m[14] - m[10]*m[12]));
	r[ 9] = det*(m[ 0]*(m[11]*m[13] - m[ 9]*m[15]) + m[ 1]*(m[ 8]*m[15] - m[11]*m[12]) + m[ 3]*(m[ 9]*m[12] - m[ 8]*m[13]));
	r[13] = det*(m[ 0]*(m[ 9]*m[14] - m[10]*m[13]) + m[ 1]*(m[10]*m[12] - m[ 8]*m[14]) + m[ 2]*(m[ 8]*m[13] - m[ 9]*m[12]));
	r[ 2] = det*(m[ 1]*(m[ 6]*m[15] - m[ 7]*m[14]) + m[ 2]*(m[ 7]*m[13] - m[ 5]*m[15]) + m[ 3]*(m[ 5]*m[14] - m[ 6]*m[13]));
	r[ 6] = det*(m[ 0]*(m[ 7]*m[14] - m[ 6]*m[15]) + m[ 2]*(m[ 4]*m[15] - m[ 7]*m[12]) + m[ 3]*(m[ 6]*m[12] - m[ 4]*m[14]));
	r[10] = det*(m[ 0]*(m[ 5]*m[15] - m[ 7]*m[13]) + m[ 1]*(m[ 7]*m[12] - m[ 4]*m[15]) + m[ 3]*(m[ 4]*m[13] - m[ 5]*m[12]));
	r[14] = det*(m[ 0]*(m[ 6]*m[13] - m[ 5]*m[14]) + m[ 1]*(m[ 4]*m[14] - m[ 6]*m[12]) + m[ 2]*(m[ 5]*m[12] - m[ 4]*m[13]));
	r[ 3] = det*(m[ 1]*(m[ 7]*m[10] - m[ 6]*m[11]) + m[ 2]*(m[ 5]*m[11] - m[ 7]*m[ 9]) + m[ 3]*(m[ 6]*m[ 9] - m[ 5]*m[10]));
	r[ 7] = det*(m[ 0]*(m[ 6]*m[11] - m[ 7]*m[10]) + m[ 2]*(m[ 7]*m[ 8] - m[ 4]*m[11]) + m[ 3]*(m[ 4]*m[10] - m[ 6]*m[ 8]));
	r[11] = det*(m[ 0]*(m[ 7]*m[ 9] - m[ 5]*m[11]) + m[ 1]*(m[ 4]*m[11] - m[ 7]*m[ 8]) + m[ 3]*(m[ 5]*m[ 8] - m[ 4]*m[ 9]));
	r[15] = det*(m[ 0]*(m[ 5]*m[10] - m[ 6]*m[ 9]) + m[ 1]*(m[ 6]*m[ 8] - m[ 4]*m[10]) + m[ 2]*(m[ 4]*m[ 9] - m[ 5]*m[ 8]));
	
	return TRUE;
}


// opengl

double heliGLGetAAResolution() {
	if (!heliGLIsIntegerClipping()) return 0;
	
	double proj[16] = {};
	double model[16] = {};
	glGetDoublev(GL_PROJECTION_MATRIX, proj);
	glGetDoublev(GL_MODELVIEW_MATRIX, model);
	
	double full[16] = {};
	double fullinv[16] = {};
	heliMatrix4Mult(full, proj, model);

	full[8] = 0, full[9] = 0, full[10] = 1, full[11] = 0; // assume z is zero
	if (!heliMatrix4Invert(fullinv, full)) return 0;
	
	if (fabs(fullinv[15]) < HELI_PRECISION_SQR) return 0; // bad perspective
	double k = 1/fullinv[15];
	
	if ( fabs(fullinv[3]*k) > 1e-5
	  || fabs(fullinv[7]*k) > 1e-5 ) return 0; // perspective distortion
	
	int rect[4] = {}; // x, y, w, h
	glGetIntegerv(GL_VIEWPORT, rect);
	double w = rect[2], h = rect[3];
	
	double m00 = fullinv[0]*k*2/w, m01 = fullinv[1]*k*2/w,
	       m10 = fullinv[4]*k*2/h, m11 = fullinv[5]*k*2/h;
	double l0 = sqrt(m00*m00 + m01*m01);
	double l1 = sqrt(m10*m10 + m11*m11);
	if (l0 > l1) { double l = l0; l0 = l1; l1 = l; }
	if (l0 < HELI_PRECISION || l1 < HELI_PRECISION) return 0;
	if (l0/l1 < 0.75) return 0; // to big aspect ratio
	
	return sqrt(l0*l1);
}


static int isInteger(double x)
	{ return fabs(floor(x + 0.5) - x) > 0.01; }

int heliGLIsIntegerClipping() {
	double proj[16] = {};
	double model[16] = {};
	double viewproj[16] = {};
	double viewmodel[16] = {};
	
	int rect[4] = {}; // x, y, w, h
	glGetIntegerv(GL_VIEWPORT, rect);
	double hw = 0.5*rect[2], hh = 0.5*rect[3];
	double view[16] = {
		hw,  0, 0, 0,
		 0,-hh, 0, 0,
		 0,  0, 1, 0,
		hw, hh, 0, 1 };
	
	glGetDoublev(GL_PROJECTION_MATRIX, proj);
	glGetDoublev(GL_MODELVIEW_MATRIX, model);
	heliMatrix4Mult(viewproj, view, proj);
	heliMatrix4Mult(viewmodel, viewproj, model);
	
	int badMatrix = FALSE;
	if (fabs(viewmodel[15]) < HELI_PRECISION_SQR) badMatrix = TRUE; // bad perspective
	double k = badMatrix ? 0 : 1/viewmodel[15];
	if ( fabs(viewmodel[3]*k) > 1e-5
	  || fabs(viewmodel[7]*k) > 1e-5 ) badMatrix = TRUE; // perspective distortion
	
	HeliGLState s;
	const int clipCount = (int)(sizeof(s.clipEnabled)/sizeof(*s.clipEnabled));
	//glGetIntegerv(GL_MAX_CLIP_PLANES, &clipCount);
	double eq[4] = {}, eqv[4] = {};
	for(int i = 0; i < clipCount; ++i) {
		if (!glIsEnabled(GL_CLIP_PLANE0 + i)) continue;
		if (badMatrix) return FALSE;
		
		glGetClipPlane(GL_CLIP_PLANE0 + i, eq);
		heliMatrix4MultVec(eqv, viewproj, eq);
		double a = (eqv[0] + eqv[2]*viewmodel[2])*k;
		double b = (eqv[1] + eqv[2]*viewmodel[6])*k;
		double c = eqv[2]*viewmodel[14]*k + 1;
		
		if (fabs(a) > 1e-5 && fabs(b) > 1e-5) return FALSE;
		if (fabs(a) > 1e-5 && !isInteger(c/a)) return FALSE;
		if (fabs(b) > 1e-5 && !isInteger(b/a)) return FALSE;
	}
	
	return TRUE;
}

int heliGLBackTransform(double *x, double *y) {
	double proj[16] = {};
	double model[16] = {};
	double viewproj[16] = {};
	double viewmodel[16] = {};
	double inv[16] = {};
	
	double v[2][4] = {
		{ *x, *y, 0, 1 },
		{ *x, *y, 1, 1 } };
	double vv[2][4] = {};
	*x = 0; *y = 0;

	int rect[4] = {}; // x, y, w, h
	glGetIntegerv(GL_VIEWPORT, rect);
	double hw = 0.5*rect[2], hh = 0.5*rect[3];
	double view[16] = {
		hw,  0, 0, 0,
		 0,-hh, 0, 0,
		 0,  0, 1, 0,
		hw, hh, 0, 1 };
	
	glGetDoublev(GL_PROJECTION_MATRIX, proj);
	glGetDoublev(GL_MODELVIEW_MATRIX, model);
	heliMatrix4Mult(viewproj, view, proj);
	heliMatrix4Mult(viewmodel, viewproj, model);
	
	if (!heliMatrix4Invert(inv, viewmodel)) return FALSE;
	heliMatrix4MultVec(vv[0], inv, v[0]);
	heliMatrix4MultVec(vv[1], inv, v[1]);
	
	double l = vv[0][2] - vv[1][2];
	if (fabs(l) <= HELI_PRECISION) return FALSE;
	l = vv[0][2]/l;
	
	double kw = vv[0][3] + (vv[1][3] - vv[0][3])*l;
	if (fabs(kw) <= HELI_PRECISION) return FALSE;
	kw = 1/kw;
	
	*x = (vv[0][0] + (vv[1][0] - vv[0][0])*l)*kw;
	*y = (vv[0][1] + (vv[1][1] - vv[0][1])*l)*kw;
	return TRUE;
}


void heliGLGetState(HeliGLState *state) {
	const int clipCount = (int)(sizeof(state->clipEnabled)/sizeof(*state->clipEnabled));
	glGetDoublev(GL_MODELVIEW_MATRIX, state->modelviewMatrix);
	for(int i = 0; i < clipCount; ++i) {
		state->clipEnabled[i] = glIsEnabled(GL_CLIP_PLANE0 + i) != 0;
		glGetClipPlane(GL_CLIP_PLANE0 + i, state->clipEquations[i]);
	}
}

void heliGLSetState(const HeliGLState *state) {
	const int clipCount = (int)(sizeof(state->clipEnabled)/sizeof(*state->clipEnabled));
	unsigned int mode;
	glGetIntegerv(GL_MATRIX_MODE, (int*)&mode);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	for(int i = 0; i < clipCount; ++i) {
		if (state->clipEnabled[i]) glEnable(GL_CLIP_PLANE0+i); else glDisable(GL_CLIP_PLANE0+i);
		glClipPlane(GL_CLIP_PLANE0+i, state->clipEquations[i]);
	}
	glLoadMatrixd(state->modelviewMatrix);
	glMatrixMode(mode);
}