/*******************************************************************************
This program generates a gridded quadrilateral of given dimensions, and writes
the result as a VRML 1.0 or X-file formatted output stream.  The resultant
quadrilateral is in the XY plane, going from [-1,-1] to [+1,+1].
*******************************************************************************/

#include <stdio.h>
#include <stdlib.h>


void WriteVRML1 (int nrows, int ncols);
void WriteXFILE (int nrows, int ncols);

inline void print (char *string) { fputs (string, stdout); }



/*****************************************************************************
*****************************************************************************/

int main (int argc, char *argv[])
{
    enum { VRML, XFILE } filetype = VRML;

    int nrows = 0,
        ncols = 0;

    int argi;
    for (argi=1;  argi < argc;  ++argi)
    {
        if ((argv[argi][0] == '-') && (tolower(argv[argi][1]) == 'x'))
        {   filetype = XFILE;
            continue;
        }

        if (nrows == 0)
            nrows = atoi (argv[argi]);
        else
            ncols = atoi (argv[argi]);
    }

    if (nrows <= 0)
    {   fputs
        (   "quadgrid:  Generates VRML1 or X-file gridded quadrilateral\n"
            "Usage:     quadgrid [-x] <rows> [columns]\n"
            "\n"
            "If [columns] is omitted, quadgrid uses the number of rows.\n"
            "Use the -x option to generate X files.\n\n",
            stderr
        );
        exit (-1);
    }

    if (ncols == 0)
        ncols = nrows;

    if (filetype == VRML)
        WriteVRML1 (nrows, ncols);
    else
        WriteXFILE (nrows, ncols);

    return 0;
}



/*****************************************************************************
This procedure writes out a grid in VRML 1.0 format.
*****************************************************************************/

void WriteVRML1 (int nrows, int ncols)
{
    // VRML 1.0 Header

    printf (
        "#VRML V1.0 ascii\n\n"
        "Separator {\n"
        "Info { string "
            "\"%d x %d gridded quadrilateral generated by quadgrid.\""
        " }\n",
        nrows, ncols
    );

    // Write out the vertex coordinates.

    print ("\nCoordinate3 { point [\n");

    //   N   2N        3N     ... (N+1)(M+1)-1  This is the vertex indexing
    //   :    :         :              :        for the generated grid layout.
    //   3  (N+1)+3  2(N+1)+3 ...   M(N+1)+3    This contains (N+1)(M+1)
    //   2  (N+1)+2  2(N+1)+2 ...   M(N+1)+2    vertices, NM quadrilaterals,
    //   1  (N+1)+1  2(N+1)+1       M(N+1)+1    and 2NM triangles.
    //   0  (N+1)    2(N+1)   ...   M(N+1)

    int row, col;

    for (col=0;  col <= ncols;  ++col)
    {   for (row=0;  row <= nrows;  ++row)
        {   printf ("\t% g\t% g\t0,\n",
                (((col / double(ncols)) * 2) - 1),
                (((row / double(nrows)) * 2) - 1));
        }
    }

    print ("] } # Coordinate3\n");

    // Write out the texture coordinates.

    print ("\nTextureCoordinate2 { point [\n");

    for (col=0;  col <= ncols;  ++col)
    {   for (row=0;  row <= nrows;  ++row)
        {   printf ("\t%g\t%g,\n",
                (col / double (ncols)),
                (row / double (nrows)));
        }
    }

    print ("] } # TextureCoordinate2\n");

    // Write out the normal vectors.

    print
    (   "\nNormal { vector [0 0 1] }\n"
        "NormalBinding { value OVERALL }\n"
    );

    // Lay out triangles column by column.

    print ("\nIndexedFaceSet { coordIndex [\n");

    int left  = 0;         // Lower Left  Vertex Index
    int right = 1+nrows;   // Lower Right Vertex Index

    for (col=0;  col < ncols;  ++col, ++left, ++right)
    {   for (row=0;  row < nrows;  ++row, ++left, ++right)
        {   printf ("\t%d,\t%d,\t%d,\t-1,\n", left, right, right+1);
            printf ("\t%d,\t%d,\t%d,\t-1,\n", left, right+1, left+1);
        }
    }

    // Epilogue

    print
    (   "] } # IndexedFaceSet\n"
        "\n} # Separator\n"
    );
}



/*****************************************************************************
This procedure writes out a grid in X-file format.
*****************************************************************************/

void WriteXFILE (int nrows, int ncols)
{
    int nverts = (nrows+1) * (ncols+1);

    // Header

    printf
    (   "xof 0302txt 0032\n\n"
        "# %d x %d gridded quadrilateral generated by 'quadgrid'\n\n"
        "Header { 1;0;1; }\n\n"
        "Mesh {\n\n",
        nrows, ncols
    );

    // Write out the vertex coordinates.

    print ("# Vertex Coordinates\n\n");

    //   N   2N        3N     ... (N+1)(M+1)-1  This is the vertex indexing
    //   :    :         :              :        for the generated grid layout.
    //   3  (N+1)+3  2(N+1)+3 ...   M(N+1)+3    This contains (N+1)(M+1)
    //   2  (N+1)+2  2(N+1)+2 ...   M(N+1)+2    vertices, NM quadrilaterals,
    //   1  (N+1)+1  2(N+1)+1       M(N+1)+1    and 2NM triangles.
    //   0  (N+1)    2(N+1)   ...   M(N+1)

    printf ("%d;\n", nverts);

    int row, col;

    for (col=0;  col <= ncols;  ++col)
    {
        for (row=0;  row <= nrows;  ++row)
        {
            if (col || row) print (",\n");

            printf ("% f; % f; 0.0;",
                (((col / double(ncols)) * 2) - 1),
                (((row / double(nrows)) * 2) - 1));
        }
    }

    print (";\n\n");

    // Face Coordinate Indices

    printf ("# Faces\n\n%d;\n", 2 * nrows * ncols);

    int left  = 0;         // Lower Left  Vertex Index
    int right = 1+nrows;   // Lower Right Vertex Index

    for (col=0;  col < ncols;  ++col, ++left, ++right)
    {   for (row=0;  row < nrows;  ++row, ++left, ++right)
        {   if (row || col) print (",\n");
            printf ("3;%4d,%4d,%4d;,\n", left, right+1, right);
            printf ("3;%4d,%4d,%4d;",    left, left+1,  right+1);
        }
    }

    print (";\n\n");

    // Write out the texture coordinates.

    printf ("MeshTextureCoords { \n\t%d;\n", nverts);

    for (col=0;  col <= ncols;  ++col)
    {   for (row=0;  row <= nrows;  ++row)
        {   printf ("%s\t%.4f; %.4f;",
                ((row || col) ? ",\n" : ""),
                (col / double (ncols)),
                (row / double (nrows)));
        }
    }

    print (";\n}\n\n");

    // Write out default material

    print
    (   "MeshMaterialList {\n"
        "	# Diffuse White\n"
        "	1;1;0;;\n"
        "	Material {\n"
        "		1.0; 1.0; 1.0; 1.0;;\n"
        "		1.0;\n"
        "		0.0; 0.0; 0.0;\n"
        "		0.0; 0.0; 0.0;\n"
        "	}\n"
        "}\n\n"
    );

    // Write out the normal vectors.

    print ("MeshNormals {\n\t1;\n\t0.0; 0.0; -1.0;;\n\n");

    // Face Normal Indices

    printf ("\t%d;\n", 2 * nrows * ncols);

    int i;
    for (i=0;  i < (2*nrows*ncols);  ++i)
        printf ("%s\t3;0,0,0;", (i ? ",\n" : ""));

    print (";\n}\n");

    // Epilogue

    print ("\n}\n");
}