#include "poly.h"
#include "pmap.h"
#include "mx3.h"

#define X(i) p->vert[i].sx      /* screen coordinates */
#define Y(i) p->vert[i].sy

#define U(i) p->vert[i].u       /* texture coordinates */
#define V(i) p->vert[i].v

/*
 * pmap_poly: find the projective mapping ST from screen to texture space
 * given the screen and texture coordinates at the vertices of a polygon,
 * which are passed in the fields (sx,sy) and (u,v) of p->vert[i], respectively.
 */
int pmap_quad_quad(poly *p,
                   double ST[3][3]);

int pmap_poly(poly *p,
              double ST[3][3])
{
    double scr[4][2];                   /* vertices of screen quadrilateral */

    if (p->n!=4)
        ERROR("only do quadrilaterals at the moment\n");

    /* if edges 0-1 and 2-3 are horz, 1-2 and 3-0 are vert */
    if (V(0)==V(1) && V(2)==V(3) && U(1)==U(2) && U(3)==U(0)) {
        scr[0][0] = X(0); scr[0][1] = Y(0);
        scr[1][0] = X(1); scr[1][1] = Y(1);
        scr[2][0] = X(2); scr[2][1] = Y(2);
        scr[3][0] = X(3); scr[3][1] = Y(3);
        return pmap_quad_rect(U(0), V(0), U(2), V(2), scr, ST);
    }

    /* if edges 0-1 and 2-3 are vert, 1-2 and 3-0 are horz */
    else if (U(0)==U(1) && U(2)==U(3) && V(1)==V(2) && V(3)==V(0)) {
        scr[0][0] = X(1); scr[0][1] = Y(1);
        scr[1][0] = X(2); scr[1][1] = Y(2);
        scr[2][0] = X(3); scr[2][1] = Y(3);
        scr[3][0] = X(0); scr[3][1] = Y(0);
        return pmap_quad_rect(U(1), V(1), U(3), V(3), scr, ST);
    }

    /* if texture is not an orthogonally-oriented rectangle */
    else return pmap_quad_quad(p, ST);
}

/*
 * pmap_quad_quad: find the projective mapping ST from screen to texture space
 * given the screen and texture coordinates at the vertices of a quadrilateral.
 *
 * Method: concatenate screen_quad->mid_square and
 * mid_square->texture_quad transform matrices.
 * The alternate method, solving an 8x8 system of equations, takes longer.
 */

int pmap_quad_quad(poly *p,
                   double ST[3][3])
{
    int type1, type2;
    double quad[4][2], MS[3][3];
    double SM[3][3], MT[3][3];          /* screen->mid and mid->texture */

    quad[0][0] = X(0); quad[0][1] = Y(0);
    quad[1][0] = X(1); quad[1][1] = Y(1);
    quad[2][0] = X(2); quad[2][1] = Y(2);
    quad[3][0] = X(3); quad[3][1] = Y(3);
    type1 = pmap_square_quad(quad, MS);
    if (mx3d_adjoint(MS, SM) == 0.)
        ERROR("pmap_quad_quad: warning: determinant=0\n");

    quad[0][0] = U(0); quad[0][1] = V(0);
    quad[1][0] = U(1); quad[1][1] = V(1);
    quad[2][0] = U(2); quad[2][1] = V(2);
    quad[3][0] = U(3); quad[3][1] = V(3);
    type2 = pmap_square_quad(quad, MT);

    if (type1==PMAP_BAD || type2==PMAP_BAD) return PMAP_BAD;

    mx3d_mul(SM, MT, ST);
    
    return type1|type2;                 /* PMAP_PROJECTIVE prevails */
}
