Blob Blame Raw

#include "private.h"
#include "drawing.h"


HeliGLBlendFuncSeparatePtr       heliGLBlendFuncSeparatePtr;
HeliGLStencilOpSeparatePtr       heliGLStencilOpSeparatePtr;
HeliGLTexImage2DMultisamplePtr   heliGLTexImage2DMultisamplePtr;
HeliGLGenFramebuffersPtr         heliGLGenFramebuffersPtr;
HeliGLDeleteFramebuffersPtr      heliGLDeleteFramebuffersPtr;
HeliGLBindFramebufferPtr         heliGLBindFramebufferPtr;
HeliGLBlitFramebufferPtr         heliGLBlitFramebufferPtr;
HeliGLFramebufferRenderbufferPtr heliGLFramebufferRenderbufferPtr;
HeliGLFramebufferTexture2DPtr    heliGLFramebufferTexture2DPtr;
HeliGLCheckFramebufferStatusPtr  heliGLCheckFramebufferStatusPtr;
HeliGLGenRenderbuffersPtr        heliGLGenRenderbuffersPtr;
HeliGLDeleteRenderbuffersPtr     heliGLDeleteRenderbuffersPtr;
HeliGLBindRenderbufferPtr        heliGLBindRenderbufferPtr;
HeliGLRenderbufferStoragePtr     heliGLRenderbufferStoragePtr;
HeliGLRenderbufferStorageMultisamplePtr heliGLRenderbufferStorageMultisamplePtr;

unsigned int heliGLWindowFramebufferReadId = 0;
unsigned int heliGLWindowFramebufferDrawId = 0;


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);
}


double heliGLGetPixelSize() {
	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;
  
	double l = sqrt(l0*l1);
	return l <= HELI_PRECISION ? 0 : l;
}


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);
		}
	}
	
	if (state->flags & STATE_TARGET_FRAMEBUFFER) {
		glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, (int*)&state->framebuffer_read_id);
		glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, (int*)&state->framebuffer_draw_id);
	}
	if (state->flags & STATE_TARGET_VIEWPORT)
		glGetIntegerv(GL_VIEWPORT, state->viewport);
	if (state->flags & STATE_TARGET_PROJECTION)
		glGetDoublev(GL_PROJECTION_MATRIX, state->projectionMatrix);
	if (state->flags & STATE_BACKGROUND)
		glGetDoublev(GL_COLOR_CLEAR_VALUE, state->clearColor);
}


void heliGLSetCommonState(const HeliGLCommonState *state) {
	int loadClip = state->flags & STATE_CLIP;
	int loadTransform = state->flags & STATE_TRANSFORM;
	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);
	}
	
	if (state->flags & STATE_TARGET_FRAMEBUFFER) {
		if (heliGLBindFramebufferPtr) {
			heliGLBindFramebufferPtr(GL_DRAW_FRAMEBUFFER, state->framebuffer_draw_id);
			heliGLBindFramebufferPtr(GL_READ_FRAMEBUFFER, state->framebuffer_read_id);
		}
	}
	if (state->flags & STATE_TARGET_VIEWPORT)
		glViewport(state->viewport[0], state->viewport[1], state->viewport[2], state->viewport[3]);
	if (state->flags & STATE_TARGET_PROJECTION) {
		unsigned int mode;
		glGetIntegerv(GL_MATRIX_MODE, (int*)&mode);
		glMatrixMode(GL_PROJECTION);
		glLoadMatrixd(state->projectionMatrix);
		glMatrixMode(mode);
	}
	if (state->flags & STATE_BACKGROUND)
		glClearColor(state->clearColor[0], state->clearColor[1], state->clearColor[2], state->clearColor[3]);
}