Blob Blame Raw


#include "pins.h"
#include "tfxparam.h"
#include "trop.h"
#include "tmathutil.h"
#include "tofflinegl.h"

//------------------------------------------------------------------------------
#ifdef _WIN32
#define ISNAN _isnan
#else
extern "C" int isnan(double);
#define ISNAN isnan
#endif

namespace
{

//----------------------------------------------------------------------------

bool lineIntersection(const TPointD &P, const TPointD &R,
					  const TPointD &Q, const TPointD &S, TPointD &ret);

//----------------------------------------------------------------------------

bool lineIntersection(const TPointD &P, const TPointD &R,
					  const TPointD &Q, const TPointD &S, TPointD &ret)
{
	TPointD u = R - P;
	TPointD v = S - Q;
	double r;
	if (u.y * v.x - u.x * v.y != 0) {
		r = (P.x * u.y - Q.x * u.y + u.x * (Q.y - P.y)) / (u.y * v.x - u.x * v.y);
		assert(!ISNAN(r));
		ret = Q + v * r;
		assert(!ISNAN(ret.x) && !ISNAN(ret.y));
		return true;
	} else {
		ret = P;
		assert(!ISNAN(ret.x) && !ISNAN(ret.y));
		return false;
	}
}

//----------------------------------------------------------------------------
};

#ifndef checkErrorsByGL
#define checkErrorsByGL                      \
	{                                        \
		GLenum err = glGetError();           \
		assert(err != GL_INVALID_ENUM);      \
		assert(err != GL_INVALID_VALUE);     \
		assert(err != GL_INVALID_OPERATION); \
		assert(err != GL_STACK_OVERFLOW);    \
		assert(err != GL_STACK_UNDERFLOW);   \
		assert(err != GL_OUT_OF_MEMORY);     \
		assert(err == GL_NO_ERROR);          \
	}
#endif

// ---------------------------------------- --------------------------------

void subCompute(TRasterFxPort &m_input, TTile &tile, double frame, const TRenderSettings &ri,
				TPointD p00, TPointD p01, TPointD p11, TPointD p10, int details, bool wireframe,
				TDimension m_offScreenSize, bool isCast)
{

	TPixel32 bgColor;
	TRectD outBBox, inBBox;
	outBBox = inBBox = TRectD(tile.m_pos, TDimensionD(tile.getRaster()->getLx(), tile.getRaster()->getLy()));
	m_input->getBBox(frame, inBBox, ri);
	if (inBBox == TConsts::infiniteRectD) // e' uno zerario
		inBBox = outBBox;

	int inBBoxLx = (int)inBBox.getLx() / ri.m_shrinkX;
	int inBBoxLy = (int)inBBox.getLy() / ri.m_shrinkY;

	if (inBBox.isEmpty())
		return;

	if (p00 == p01 && p00 == p10 && p00 == p11 && !isCast) // significa che non c'e' deformazione
	{
		m_input->compute(tile, frame, ri);
		return;
	}

	TRaster32P rasIn;
	TPointD rasInPos;

	if (!wireframe) {
		if (ri.m_bpp == 64 || ri.m_bpp == 48) {
			TRaster64P aux = TRaster64P(inBBoxLx, inBBoxLy);
			rasInPos = TPointD(inBBox.x0 / ri.m_shrinkX, inBBox.y0 / ri.m_shrinkY);
			TTile tmp(aux, rasInPos);
			m_input->compute(tmp, frame, ri);
			rasIn = TRaster32P(inBBoxLx, inBBoxLy);
			TRop::convert(rasIn, aux);
		} else {
			rasInPos = TPointD(inBBox.x0 / ri.m_shrinkX, inBBox.y0 / ri.m_shrinkY);
			TTile tmp(TRaster32P(inBBoxLx, inBBoxLy), rasInPos);
			m_input->allocateAndCompute(tmp, rasInPos, TDimension(inBBoxLx, inBBoxLy), TRaster32P(), frame, ri);
			rasIn = tmp.getRaster();
		}
	}

	unsigned int texWidth = 2;
	unsigned int texHeight = 2;

	while (texWidth < (unsigned int)inBBoxLx)
		texWidth = texWidth << 1;

	while (texHeight < (unsigned int)inBBoxLy)
		texHeight = texHeight << 1;

	while (texWidth > 1024 || texHeight > 1024) //avevo usato la costante GL_MAX_TEXTURE_SIZE invece di 1024, ma non funzionava!
	{
		inBBoxLx = inBBoxLx >> 1;
		inBBoxLy = inBBoxLy >> 1;
		texWidth = texWidth >> 1;
		texHeight = texHeight >> 1;
	}

	if (rasIn->getLx() != inBBoxLx || rasIn->getLy() != inBBoxLy) {
		TRaster32P rasOut = TRaster32P(inBBoxLx, inBBoxLy);
		TRop::resample(rasOut, rasIn, TScale((double)rasOut->getLx() / rasIn->getLx(), (double)rasOut->getLy() / rasIn->getLy()));
		rasIn = rasOut;
	}

	int rasterWidth = tile.getRaster()->getLx() + 2;
	int rasterHeight = tile.getRaster()->getLy() + 2;
	assert(rasterWidth > 0);
	assert(rasterHeight > 0);

	TRectD clippingRect = TRectD(tile.m_pos,
								 TDimensionD(tile.getRaster()->getLx(),
											 tile.getRaster()->getLy()));
#if CREATE_GL_CONTEXT_ONE_TIME
	int ret = wglMakeCurrent(m_offScreenGL.m_offDC, m_offScreenGL.m_hglRC);
	assert(ret == TRUE);
#else
	TOfflineGL offScreenRendering(TDimension(rasterWidth, rasterHeight));
	//#ifdef _WIN32
	offScreenRendering.makeCurrent();
//#else
//#if defined(LINUX) || defined(MACOSX)
// offScreenRendering.m_offlineGL->makeCurrent();
//#endif
#endif

	checkErrorsByGL
		// disabilito quello che non mi serve per le texture
		glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
	glDisable(GL_DITHER);
	glDisable(GL_DEPTH_TEST);
	glCullFace(GL_FRONT);
	glDisable(GL_STENCIL_TEST);
	glDisable(GL_LOGIC_OP);

	// creo la texture in base all'immagine originale
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

	checkErrorsByGL
#if !CREATE_GL_CONTEXT_ONE_TIME
		TRaster32P rasaux;
	if (!wireframe) {
		TRaster32P texture(texWidth, texHeight);
		texture->clear();
		rasaux = texture;
		rasaux->lock();
		texture->copy(rasIn);

		glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
		glTexImage2D(GL_TEXTURE_2D,
					 0,
					 4,
					 texWidth,
					 texHeight,
					 0,
					 GL_RGBA,
					 GL_UNSIGNED_BYTE,
					 texture->getRawData());
	}
#else

		unsigned int texWidth = 1024;
	unsigned int texHeight = 1024;
	rasaux = rasIn;
	rasaux->lock();

	glTexSubImage2D(GL_TEXTURE_2D, 0,
					0, 0,
					rasIn->getLx(), rasIn->getLy(),
					GL_RGBA,
					GL_UNSIGNED_BYTE,
					rasIn->getRawData());

#endif
	checkErrorsByGL

		glEnable(GL_TEXTURE_2D);

	// cfr. help: OpenGL/Programming tip/OpenGL Correctness Tips
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(-rasterWidth * 0.5, rasterWidth * 0.5, -rasterHeight * 0.5, rasterHeight * 0.5, -1, 1);
	glViewport(0, 0, rasterWidth, rasterHeight);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	glClear(GL_COLOR_BUFFER_BIT);

	// do OpenGL draw

	double lwTex = (double)(inBBoxLx - 1) / (double)(texWidth - 1);
	double lhTex = (double)(inBBoxLy - 1) / (double)(texHeight - 1);

	TPointD tex00 = TPointD(0.0, 0.0);
	TPointD tex10 = TPointD(lwTex, 0.0);
	TPointD tex11 = TPointD(lwTex, lhTex);
	TPointD tex01 = TPointD(0.0, lhTex);

	GLenum polygonStyle;
	if (wireframe) {
		polygonStyle = GL_LINE;
		glDisable(GL_TEXTURE_2D);
	} else
		polygonStyle = GL_FILL;
	checkErrorsByGL
		p00.x /= ri.m_shrinkX;
	p00.y /= ri.m_shrinkY;

	p10.x /= ri.m_shrinkX;
	p10.y /= ri.m_shrinkY;

	p11.x /= ri.m_shrinkX;
	p11.y /= ri.m_shrinkY;

	p01.x /= ri.m_shrinkX;
	p01.y /= ri.m_shrinkY;

	TPointD translate = TPointD(tile.m_pos.x + tile.getRaster()->getLx() * 0.5,
								tile.m_pos.y + tile.getRaster()->getLy() * 0.5);
	glTranslated(-translate.x, -translate.y, 0.0);

	// disegno il poligono
	double dist_p00_p01 = tdistance2(p00, p01);
	double dist_p10_p11 = tdistance2(p10, p11);
	double dist_p01_p11 = tdistance2(p01, p11);
	double dist_p00_p10 = tdistance2(p00, p10);
	bool vertical = (dist_p00_p01 == dist_p10_p11);
	bool horizontal = (dist_p00_p10 == dist_p01_p11);
	if (vertical && horizontal)
		details = 1;
	glPolygonMode(GL_FRONT_AND_BACK, polygonStyle);
	subdivision(p00, p10, p11, p01,
				tex00, tex10, tex11, tex01,
				clippingRect,
				details);

	if (!wireframe) {
		// abilito l'antialiasing delle linee
		glEnable(GL_LINE_SMOOTH);
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);

		// disegno il bordo del poligono
		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
		glBegin(GL_QUADS);
		glTexCoord2d(tex00.x, tex00.y);
		tglVertex(p00);
		glTexCoord2d(tex10.x, tex10.y);
		tglVertex(p10);
		glTexCoord2d(tex11.x, tex11.y);
		tglVertex(p11);
		glTexCoord2d(tex01.x, tex01.y);
		tglVertex(p01);
		glEnd();

		// disabilito l'antialiasing per le linee
		glDisable(GL_LINE_SMOOTH);
		glDisable(GL_BLEND);
		glDisableClientState(GL_VERTEX_ARRAY);
		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
		glDisable(GL_TEXTURE_2D);
	}

	// force to finish
	glFlush();

	// rimetto il disegno dei poligoni a GL_FILL
	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

	// metto il frame buffer nel raster del tile
	glPixelStorei(GL_UNPACK_ROW_LENGTH, rasterWidth);
	glPixelStorei(GL_UNPACK_ALIGNMENT, 4);

	TRaster32P newRas(tile.getRaster()->getLx(), tile.getRaster()->getLy());
	newRas->lock();
	glReadPixels(1, 1,
				 newRas->getLx(), newRas->getLy(),
				 GL_RGBA, GL_UNSIGNED_BYTE, (void *)newRas->getRawData());
	newRas->unlock();
	checkErrorsByGL

		rasaux->unlock();

	tile.getRaster()->copy(newRas);
}

// ------------------------------------------------------------------------

void subdivision(const TPointD &p00,
				 const TPointD &p10,
				 const TPointD &p11,
				 const TPointD &p01,
				 const TPointD &tex00,
				 const TPointD &tex10,
				 const TPointD &tex11,
				 const TPointD &tex01,
				 const TRectD &clippingRect,
				 int details)
{
	if (details == 1) {
		glBegin(GL_QUADS);

		glTexCoord2d(tex00.x, tex00.y);
		tglVertex(p00);

		glTexCoord2d(tex10.x, tex10.y);
		tglVertex(p10);

		glTexCoord2d(tex11.x, tex11.y);
		tglVertex(p11);

		glTexCoord2d(tex01.x, tex01.y);
		tglVertex(p01);

		glEnd();
	} else {
		TPointD A = p00;
		TPointD B = p10;
		TPointD C = p11;
		TPointD D = p01;

		/*
     *     D                L2               C
     *     +----------------+----------------+
     *     |                |                |
     *     |                |                |
     *     |                |                |
     *     |                |                |
     *     |                |                |
     *  H1 +----------------+----------------+ H2
     *     |                | M              |
     *     |                |                |
     *     |                |                |
     *     |                |                |
     *     |                |                |
     *     +----------------+----------------+
     *     A                L1               B
     *
     */

		TPointD M, L1, L2, H1, H2, P1, P2;
		bool intersection;

		// M
		intersection = lineIntersection(A, C, B, D, M);
		assert(intersection);

		// P1 (punto di fuga)
		intersection = lineIntersection(D, C, A, B, P1);
		if (!intersection) {
			P1.x = 0.5 * (A.x + D.x);
			P1.y = 0.5 * (A.y + D.y);
		}
		// H1
		intersection = lineIntersection(A, D, P1, M, H1);
		assert(intersection);

		// H2
		intersection = lineIntersection(B, C, P1, M, H2);
		assert(intersection);

		// P2 (punto di fuga)
		intersection = lineIntersection(A, D, B, C, P2);
		if (!intersection) {
			P2.x = 0.5 * (A.x + B.x);
			P2.y = 0.5 * (A.y + B.y);
		}
		// L1
		intersection = lineIntersection(A, B, P2, M, L1);
		assert(intersection);

		// L2
		intersection = lineIntersection(D, C, P2, M, L2);
		assert(intersection);

		TPointD texA = (tex00 + tex10) * 0.5;
		TPointD texB = (tex10 + tex11) * 0.5;
		TPointD texC = (tex11 + tex01) * 0.5;
		TPointD texD = (tex01 + tex00) * 0.5;
		TPointD texM = (texA + texC) * 0.5;

		details--;

		TRectD r1 = TRectD(tmin(A.x, L1.x, M.x, H1.x), tmin(A.y, L1.y, M.y, H1.y),
						   tmax(A.x, L1.x, M.x, H1.x), tmax(A.y, L1.y, M.y, H1.y));

		TRectD r2 = TRectD(tmin(L1.x, B.x, H2.x, M.x), tmin(L1.y, B.y, H2.y, M.y),
						   tmax(L1.x, B.x, H2.x, M.x), tmax(L1.y, B.y, H2.y, M.y));

		TRectD r3 = TRectD(tmin(M.x, H2.x, C.x, L2.x), tmin(M.y, H2.y, C.y, L2.y),
						   tmax(M.x, H2.x, C.x, L2.x), tmax(M.y, H2.y, C.y, L2.y));

		TRectD r4 = TRectD(tmin(H1.x, M.x, L2.x, D.x), tmin(H1.y, M.y, L2.y, D.y),
						   tmax(H1.x, M.x, L2.x, D.x), tmax(H1.y, M.y, L2.y, D.y));

		if (r1.overlaps(clippingRect))
			subdivision(A, L1, M, H1, tex00, texA, texM, texD, clippingRect, details);

		if (r2.overlaps(clippingRect))
			subdivision(L1, B, H2, M, texA, tex10, texB, texM, clippingRect, details);

		if (r3.overlaps(clippingRect))
			subdivision(M, H2, C, L2, texM, texB, tex11, texC, clippingRect, details);

		if (r4.overlaps(clippingRect))
			subdivision(H1, M, L2, D, texD, texM, texC, tex01, clippingRect, details);
	}
}

// ------------------------------------------------------------------------
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------
#define TINY 1.0e-20

int splitMatrix(double **a, int n, int *index)
{
	int i, imax = 0, j, k;
	double big, dum, sum, temp;
	double *vv, d;

	vv = new double[n];

	d = 1.00;
	for (i = 0; i < n; i++) {
		big = 0.0;
		for (j = 0; j < n; j++)
			if ((temp = fabs(a[i][j])) > big)
				big = temp;
		if (big == 0.0) {
			/*printf("aho, sta matrice e 'vota!!\n");*/
			return 0;
			//exit(0);
		}
		vv[i] = 1.0 / big;
	}
	for (j = 0; j < n; j++) {
		for (i = 0; i < j; i++) {
			sum = a[i][j];
			for (k = 0; k < i; k++)
				sum -= a[i][k] * a[k][j];
			a[i][j] = sum;
		}
		big = 0.0;
		for (i = j; i < n; i++) {
			sum = a[i][j];
			for (k = 0; k < j; k++)
				sum -= a[i][k] * a[k][j];
			a[i][j] = sum;
			if ((dum = vv[i] * fabs(sum)) >= big) {
				big = dum;
				imax = i;
			}
		}
		if (j != imax) {
			for (k = 0; k < n; k++) {
				dum = a[imax][k];
				a[imax][k] = a[j][k];
				a[j][k] = dum;
			}
			d = -d;
			vv[imax] = vv[j];
		}
		index[j] = imax;
		if (fabsf(a[j][j]) <= TINY && (j != n - 1)) {
			/*printf("Cazzo, E' singolare %f!\n", a[j][j] );*/
			return imax + 1;
		}
		if (j != n - 1) {
			dum = 1.0 / a[j][j];
			for (i = j + 1; i < n; i++)
				a[i][j] *= dum;
		}
	}
	delete vv;
	return 0;
}

/*-----------------------------------------------------------------*/

void buildMatrixes(const FourPoints &ss, const FourPoints &dd,
				   double **a, double *b)
{
	int i;
	TPointD s[4], d[4];

	s[0] = ss.m_p00, s[1] = ss.m_p01, s[2] = ss.m_p10, s[3] = ss.m_p11;
	d[0] = dd.m_p00, d[1] = dd.m_p01, d[2] = dd.m_p10, d[3] = dd.m_p11;

	for (i = 0; i < 4; i++) {
		a[i][0] = a[i + 4][3] = s[i].x;
		a[i][1] = a[i + 4][4] = s[i].y;
		a[i][2] = a[i + 4][5] = 1;
		a[i][3] = a[i + 4][0] = 0;
		a[i][4] = a[i + 4][1] = 0;
		a[i][5] = a[i + 4][2] = 0;
		a[i][6] = -s[i].x * d[i].x;
		a[i + 4][6] = -s[i].x * d[i].y;
		a[i][7] = -s[i].y * d[i].x;
		a[i + 4][7] = -s[i].y * d[i].y;

		b[i] = d[i].x;
		b[i + 4] = d[i].y;
	}
}

/*-----------------------------------------------------------------*/

void computeSolutions(double **a, int *index, double *b)
{
	int i, ii = 0, ip, j;
	double sum;

	for (i = 0; i < 8; i++) {
		ip = index[i];
		sum = b[ip];
		b[ip] = b[i];
		if (ii)
			for (j = ii - 1; j <= i - 1; j++)
				sum -= a[i][j] * b[j];
		else if (sum)
			ii = i + 1;
		b[i] = sum;
	}
	for (i = 7; i >= 0; i--) {
		sum = b[i];
		for (j = i + 1; j < 8; j++)
			sum -= a[i][j] * b[j];
		b[i] = sum / a[i][i];
	}
}

/*-----------------------------------------------------------------*/

void solveSystems(double **a, double *bx)
{
	int index[255], i, count = 0, bad_line;
	double **atmp;
	int n = 8;

	atmp = new double *[n];

	for (i = 0; i < n; i++) {
		atmp[i] = new double[n];
		memcpy(atmp[i], a[i], n * sizeof(double));
	}

	while ((bad_line = splitMatrix(atmp, n, index)) != 0 && n > 0) {
		/*printf("la riga %d fa schifo!\n", bad_line);*/
		/*bad_lines[count] = bad_line;*/
		for (i = bad_line - 1; i < n - 1; i++)
			memcpy(atmp[i], a[i + 1], n * sizeof(a[i + 1]));
		n--;
		count++;
	}

	if (count == 0)
		computeSolutions(atmp, index, bx);

	for (i = 0; i < n; i++)
		delete atmp[i];

	delete atmp;
}

/*-----------------------------------------------------------------*/

void computeTransformation(const FourPoints &s, const FourPoints &d,
						   TAffine &aff, TPointD &perspectDen)
{
	double **a, *b;

	int i;
	a = new double *[8];
	for (i = 0; i < 8; i++)
		a[i] = new double[8];
	b = new double[8];

	buildMatrixes(s, d, a, b);

	solveSystems(a, b);

	aff.a11 = b[0];
	aff.a12 = b[1];
	aff.a13 = b[2];
	aff.a21 = b[3];
	aff.a22 = b[4];
	aff.a23 = b[5];
	perspectDen.x = b[6];
	perspectDen.y = b[7];

	for (i = 0; i < 8; i++)
		delete a[i];
	delete b;
	delete a;
}

/*-----------------------------------------------------------------*/

FourPoints computeTransformed(const FourPoints &pointsFrom, const FourPoints &pointsTo, const FourPoints &from)
{
	TAffine aff;
	TPointD perspectiveDen;

	computeTransformation(pointsFrom, pointsTo, aff, perspectiveDen);

	double den;
	FourPoints fp;

	den = perspectiveDen.x * from.m_p00.x + perspectiveDen.y * from.m_p00.y + 1;
	assert(den != 0);
	fp.m_p00 = (1.0 / den) * (aff * from.m_p00);
	den = perspectiveDen.x * from.m_p01.x + perspectiveDen.y * from.m_p01.y + 1;
	assert(den != 0);
	fp.m_p01 = (1.0 / den) * (aff * from.m_p01);
	den = perspectiveDen.x * from.m_p10.x + perspectiveDen.y * from.m_p10.y + 1;
	assert(den != 0);
	fp.m_p10 = (1.0 / den) * (aff * from.m_p10);
	den = perspectiveDen.x * from.m_p11.x + perspectiveDen.y * from.m_p11.y + 1;
	assert(den != 0);
	fp.m_p11 = (1.0 / den) * (aff * from.m_p11);

	return fp;
}