#include "private.h"
#include "drawing.h"
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
HeliGLCommonState s;
const int clipCount = (int)(sizeof(s.clipPlanes)/sizeof(*s.clipPlanes));
//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 heliGLGetCommonState(HeliGLCommonState *state, unsigned int flags) {
memset(state, 0, sizeof(*state));
state->flags = flags;
if (state->flags & STATE_TRANSFORM)
glGetDoublev(GL_MODELVIEW_MATRIX, state->modelviewMatrix);
if (state->flags & STATE_CLIP) {
const int clipCount = (int)(sizeof(state->clipPlanes)/sizeof(*state->clipPlanes));
for(int i = 0; i < clipCount; ++i) {
state->clipPlanes[i].enabled = glIsEnabled(GL_CLIP_PLANE0 + i) != 0;
glGetClipPlane(GL_CLIP_PLANE0 + i, state->clipPlanes[i].equation);
}
}
}
void heliGLSetCommonState(const HeliGLCommonState *state) {
int loadClip = state->flags & STATE_CLIP;
int loadTransform = state->flags & STATE_CLIP;
if (loadClip) {
unsigned int mode;
glGetIntegerv(GL_MATRIX_MODE, (int*)&mode);
glMatrixMode(GL_MODELVIEW);
if (!loadTransform) glPushMatrix();
const int clipCount = (int)(sizeof(state->clipPlanes)/sizeof(*state->clipPlanes));
for(int i = 0; i < clipCount; ++i) {
if (state->clipPlanes[i].enabled) glEnable(GL_CLIP_PLANE0+i);
else glDisable(GL_CLIP_PLANE0+i);
glClipPlane(GL_CLIP_PLANE0+i, state->clipPlanes[i].equation);
}
if (!loadTransform) glPopMatrix(); else glLoadMatrixd(state->modelviewMatrix);
glMatrixMode(mode);
} else
if (loadTransform) {
unsigned int mode;
glGetIntegerv(GL_MATRIX_MODE, (int*)&mode);
glMatrixMode(GL_MODELVIEW);
glLoadMatrixd(state->modelviewMatrix);
glMatrixMode(mode);
}
}