/*****************************************************************************
* Global options configuration from config file and command line arguments.  *
* (config file name is irender.cfg, and it contains program options)         *
******************************************************************************
* (C) Gershon Elber, Technion, Israel Institute of Technology                *
******************************************************************************
* Written by:  Bassarab Dmitri & Plavnik Michael       Ver 0.2, Apr. 1995    *
*****************************************************************************/

#include "program.h"
#include "getarg.h"

static char TheHelp[] =
{
    " -z\t\t\tthis message\n"
    " -v\t\t\tverbose mode\n"  
    " -s xSize ySize\t\tgeometry of resulting image\n"
    " -a Ambient\t\t(% of ambient component) in (0, 1)\n"
    " -b R G B\t\tcolor of background\n"
    " -B\t\t\tapply backface culling\n"
    " -F n m\t\t\tsurface to polygons aproximation optimal and fineness\n"
    " -f n m\t\t\tcurve to polylines aproximation optimal and samples\n"
    " -M Flat/Gouraud/Phong\tshade model\n"
    " -P Wmin [Wmax]\t\thandle polylines\n"
    " -S\t\t\thandle shadows\n"
    " -T\t\t\thandle transparency\n"
    " -t\t\t\tanimation time\n"
    " -A FilterName\t\tapply filter (sinc, box, triangle etc.)\n"
    " -Z\t\t\twrite Z depth instead of color\n"
    " -n\t\t\treverse vertex and plane normals direction\n"
    " -i\t\t\tsets image type to handle (rle/ppm)\n"
    " file...\t\tfiles to proceed { *.(dat|mat)[.Z] }\n"
};

static char
    *Size = "512 512",
    *BgRGB = "0 0 0",
    *Srf2Plg = "0 20",
    *Crv2Pll = "0 64",
    *Model = "Phong",
    *PllWidth = "0.001 0.01",
    *ImageTypeStr = "rle";

static ConfigStruct SetUp[] =
{
    { "Size",        "-s", (VoidPtr) &Size,                  SU_STRING_TYPE },
    { "Ambient",     "-a", (VoidPtr) &Options.Ambient,       SU_REAL_TYPE },
    { "Background",  "-b", (VoidPtr) &BgRGB,                 SU_STRING_TYPE },
    { "BackfaceCull","-B", (VoidPtr) &Options.BackFace,      SU_BOOLEAN_TYPE },
    { "Srf2poly",    "-F", (VoidPtr) &Srf2Plg,               SU_STRING_TYPE },
    { "Crv2Poly",    "-f", (VoidPtr) &Crv2Pll,               SU_STRING_TYPE },
    { "ShadeModel",  "-M", (VoidPtr) &Model,                 SU_STRING_TYPE },
    { "PolylnWidth", "-P", (VoidPtr) &PllWidth,              SU_STRING_TYPE },
    { "ShadowCast",  "-S", (VoidPtr) &Options.Shadows,       SU_BOOLEAN_TYPE },
    { "Transparency","-T", (VoidPtr) &Options.Transp,        SU_BOOLEAN_TYPE },
    { "FilterName",  "-A", (VoidPtr) &Options.FilterName,    SU_STRING_TYPE },
    { "ZDepth",      "-Z", (VoidPtr) &Options.ZDepth,        SU_BOOLEAN_TYPE },
    { "Normals",     "-n", (VoidPtr) &Options.NormalReverse, SU_BOOLEAN_TYPE },
    { "ImageType",   "-i", (VoidPtr) &ImageTypeStr,	     SU_STRING_TYPE }
};
#define NUM_SET_UP	(sizeof(SetUp) / sizeof(ConfigStruct))

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Prints global state of the program before processing.                    M
*   It is active only in DEBUG compilation mode.                             M
*                                                                            *
* PARAMETERS:                                                                M
*   None                                                                     M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   PrintOptions                                                             M
*****************************************************************************/
void PrintOptions(void)
{
    int f;

    fprintf(stderr,
	    "\nAmbient................. %g\n",
	    Options.Ambient);
    fprintf(stderr,
	    "Background.............. %g, %g, %g\n",
	    Options.BackGround[R],
	    Options.BackGround[G],
	    Options.BackGround[B]);
    fprintf(stderr,
	    "Backface culling........ %s\n",
	    (Options.BackFace) ? "TRUE" : "FALSE");
    fprintf(stderr,
	    "Geometry................ %d x %d\n",
	    Options.XSize, Options.YSize);
    fprintf(stderr,
            "Curve to polylines...... optimal: %d, samples: %d\n",
            (int) Options.Crv2PllMethod,
            Options.Crv2PllSamples);
    fprintf(stderr,
            "Surface to polygons..... optimal: %d, fineness: %g\n",
            Options.Srf2PlgOptimal,
            Options.Srf2PlgFineness);
    fprintf(stderr, "Shade model............. ");
    switch (Options.ShadeModel) {
        case FLAT:
            fprintf(stderr, "Flat\n");
            break;
        case GOURAUD:
            fprintf(stderr, "Gouraud\n");
            break;
        case PHONG:
            fprintf(stderr, "Phong\n");
	    break;
    }
    fprintf(stderr,
	    "Antialias filter........ %s\n",
	    Options.FilterName ? Options.FilterName : "None");
    fprintf(stderr,
	    "Normal reverse.......... %s\n",
	    Options.NormalReverse ? "TRUE" : "FALSE");
    fprintf(stderr,
	    "Polylines............... %s",
	    (Options.Polylines) ? "TRUE" : "FALSE");
    if (Options.Polylines)
        fprintf(stderr,
		", min width: %g, max width: %g\n",
		Options.PllMinW, Options.PllMaxW);
    else
        fprintf(stderr, "\n");
    fprintf(stderr,
	    "Shadows casting......... %s\n",
	    (Options.Shadows) ? "TRUE" : "FALSE");
    fprintf(stderr,
	    "Transparency............ %s\n",
	    (Options.Transp) ? "TRUE" : "FALSE");
    if (Options.HasTime)
        fprintf(stderr, "Animation Time.......... %f\n", Options.Time);
    else
	fprintf(stderr, "Animation Time.......... None\n");
    fprintf(stderr,
	    "Z depth................. %s\n",
	    (Options.ZDepth) ? "TRUE" : "FALSE");
    fprintf(stderr,
	    "Image Type.............. %s\n",
	    ImageTypeStr);
    fprintf(stderr, "Files................... ");
    for (f = 0; f < Options.NFiles; f++)
        fprintf(stderr, "%s ", Options.Files[f]);
    fprintf(stderr, "\n");
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Reads configuration file and initialize global state of the program.     M
*   It has lowest priorety in the configuration management initializations.  M
*   Checks validity of the options and prints error messages to stderr.      M
*                                                                            *
* PARAMETERS:                                                                M
*   argv:     IN, pointer to the command line parameters of the program.     M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   GetConfig, configuration, global state                                   M
*****************************************************************************/
void GetConfig(char *argv[])
{
    Config("irender", SetUp, NUM_SET_UP);

    if (Size) {
        int x, y;

        if (sscanf(Size, "%d %d", &x, &y) == 2) {
            Options.XSize = x;
            Options.YSize = y;
        }
    }
    if (BgRGB) {
        int r, g, b;

        if (sscanf(BgRGB, "%d, %d, %d", &r, &g, &b) == 3) {
            Options.BackGround[R] = r;
            Options.BackGround[G] = g;
	    Options.BackGround[B] = b;
            PT_SCALE(Options.BackGround, 1. / 0xff);
        }
    }
    if (Srf2Plg) {
        int o;
        RealType f;

#ifdef IRIT_DOUBLE
        if (sscanf(Srf2Plg, "%d, %lf", &o, &f) == 2) {
#else
        if (sscanf(Srf2Plg, "%d, %f", &o, &f) == 2) {
#endif /* IRIT_DOUBLE */
            Options.Srf2PlgOptimal = o;
            Options.Srf2PlgFineness = f;
        }
    }
    if (Crv2Pll) {
        int o, s;

        if (sscanf(Crv2Pll, "%d, %d", &o, &s) == 2) {
            Options.Crv2PllMethod = (SymbCrvApproxMethodType) o;
            Options.Crv2PllSamples = s;
        }
    }
    if (PllWidth) {
        RealType Min, Max;

#ifdef IRIT_DOUBLE
        if ((Options.Polylines = sscanf(PllWidth, "%lf %lf", &Min, &Max))
#else
        if ((Options.Polylines = sscanf(PllWidth, "%f %f", &Min, &Max))
#endif /* IRIT_DOUBLE */
								!= FALSE) {
            Options.PllMinW = Min;
            Options.PllMaxW = Options.Polylines == 2 ? Max : Options.PllMinW;
        }
    }
    if (Options.ZDepth) {
        Options.ShadeModel = FLAT;
        Options.Shadows = FALSE;
        Options.Transp = FALSE;
        Options.FilterName = NULL;
    }
    else if (Model)
        if (!stricmp(Model, "Flat"))
            Options.ShadeModel = FLAT;
        else if (!stricmp(Model, "Gouraud"))
            Options.ShadeModel = GOURAUD;
        else if (!stricmp(Model, "Phong"))
            Options.ShadeModel = PHONG;
        else
            fprintf(stderr, "Warning: unknown shading model, Phong used\n");
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Reads command line options, checks validity, and initialize global state M
*   of the program. It has the greatest priorety in configuration management M
*   Error messages are printed to stderr stream.                             M
*                                                                            *
* PARAMETERS:                                                                M
*   argc:    IN, number of command line parameters.                          M
*   argv:    IN, command line parameters.                                    M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   GetOptions, configuration, global state                                  M
*****************************************************************************/
void GetOptions(int argc, char *argv[])
{
    int Error, Dummy;
    RealType Min,
	Max = -IRIT_INFNTY;
    int  BgRed, BgGreen, BgBlue,
	Help = FALSE,
	Plls = FALSE,
	ImTp = FALSE;
    char
#ifdef IRIT_DOUBLE
        *Format = "z%- v%- s%-XSize|YSize!d!d a%-Ambient!F b%-R|G|B!d!d!d B%- F%-PolyOpti|FineNess!d!F f%-PolyOpti|SampPerCrv!d!d M%-Flat/Gouraud/Phong!s P%-WMin|[WMax]!F%F S%- T%- t%-AnimTime!F A%-FilterName!s Z%- n%- i%-rle/ppm!s files!*s",
#else
        *Format = "z%- v%- s%-XSize|YSize!d!d a%-Ambient!f b%-R|G|B!d!d!d B%- F%-PolyOpti|FineNess!d!f f%-PolyOpti|SampPerCrv!d!d M%-Flat/Gouraud/Phong!s P%-WMin|[WMax]!f%f S%- T%- t%-AnimTime!f A%-FilterName!s Z%- n%- i%-rle/ppm!s files!*s",
#endif /* IRIT_DOUBLE */
	*Model = NULL,
        *Control = MALLOC(char, strlen(argv[0]) + strlen(Format) + 2);

    PT_SCALE(Options.BackGround, 0xff);
    BgRed = (int) Options.BackGround[R];
    BgGreen = (int) Options.BackGround[G];
    BgBlue = (int) Options.BackGround[B];
    sprintf(Control, "%s %s", argv[0], Format);
    Error = GAGetArgs(argc, argv, Control,
                      &Help,
		      &Options.Verbose,
                      &Dummy, &Options.XSize, &Options.YSize,
                      &Dummy, &Options.Ambient,
                      &Dummy, &BgRed, &BgGreen, &BgBlue,
                      &Options.BackFace,
                      &Dummy, &Options.Srf2PlgOptimal, &Options.Srf2PlgFineness,
                      &Dummy, &Options.Crv2PllMethod, &Options.Crv2PllSamples,
                      &Dummy, &Model,
                      &Plls, &Min, &Max,
                      &Options.Shadows,
                      &Options.Transp,
                      &Options.HasTime, &Options.Time,
                      &Dummy, &Options.FilterName,
                      &Options.ZDepth,
                      &Options.NormalReverse,
		      &ImTp, &ImageTypeStr,
                      &Options.NFiles, &Options.Files);

    if (Plls) {
        Options.Polylines = Plls;
        Options.PllMinW = Min;
        Options.PllMaxW = Max > 0 ? Max : Options.PllMinW;
    }

    if (Options.ZDepth) {
        Options.ShadeModel = FLAT;
        Options.Shadows = FALSE;
        Options.Transp = FALSE;
        Options.FilterName = NULL;
    }
    else if (Model) {
        if (!stricmp(Model, "Flat"))
            Options.ShadeModel = FLAT;
        else if (!stricmp(Model, "Gouraud"))
            Options.ShadeModel = GOURAUD;
        else if (!stricmp(Model, "Phong"))
            Options.ShadeModel = PHONG;
        else
            fprintf(stderr, "Warning: unknown shading model, Phong used\n");
    }

    Options.BackGround[R] = BgRed;
    Options.BackGround[G] = BgGreen;
    Options.BackGround[B] = BgBlue;
    PT_SCALE(Options.BackGround, 1. / 0xff);

    if (stricmp(Options.FilterName, "None") == 0)
        Options.FilterName = NULL;

    if (Help) {
        GAPrintHowTo(Control);
        fprintf(stderr, "%s\n", TheHelp);
	PrintOptions();
        exit(0);
    }
    if (Error) {
        GAPrintErrMsg(Error);
        GAPrintHowTo(Control);
	PrintOptions();
        exit(Error);
    }
    if (!Options.NFiles) {
        fprintf(stderr, "Error in command line parsing - No files found.\n");
        GAPrintHowTo(Control);
        exit(1);
    }

    ImageSetImageType(ImageTypeStr);
}
