/*
 * Converting no hs worlds to real binary worlds (with bsps).
 * No HS worlds are used in the generation process of worlds
 *
 * Copyright (c) 1998 Criterion Software Ltd.
 */

/****************************************************************************
 Includes
 */

#include <stdlib.h>
#include <math.h>
#include <string.h>

#include "rwcore.h"
#include "rpworld.h"

#include "rpdbgerr.h"

#include "nhsworld.h"
#include "nhsstats.h"
#include "nhsutil.h"

static const char   rcsid[] __RWUNUSED__ =
    "@@(#)$Id: nhsstats.c,v 1.21 2001/07/09 09:00:44 johns Exp $";

#define MAXMATERIALS    2048

typedef struct RtBoundaryState RtBoundaryState;
struct RtBoundaryState
{
    RtWorldImportBuildVertex *boundaries;

    /* count usage of each material */
    RwUInt32           *matl, *matr;
    /* vertex stats for current polygon */
    RwInt32             clip;
    RwReal              dist, distLeft, distRight;

    /* running polygon total */
    RwInt32             nLeft;
    RwInt32             nRight;
    RwInt32             nSplit;
    RwReal              overLeft;
    RwReal              overRight;
    RwBool              alphaInOverlap;
};

#define InitBuildSectorGetClipStatistics(_state)                            \
MACRO_START                                                                 \
{                                                                           \
    (_state)->clip =  rwCLIPVERTEXLEFT | rwCLIPVERTEXRIGHT;                 \
    (_state)->distLeft = (_state)->distRight = 0.0f;                        \
}                                                                           \
MACRO_STOP

#define VertexBuildSectorGetClipStatistics(_state, _vpVert, _plane, _value) \
MACRO_START                                                                 \
{                                                                           \
    (_state)->dist =  GETCOORD((_vpVert)->OC,  (_plane)) - (_value);        \
    (_state)->clip &= (_vpVert)->state.clipFlags;                           \
                                                                            \
    if ((_state)->dist < 0.0f)                                              \
    {                                                                       \
        if (-(_state)->dist > (_state)->distLeft)                           \
        {                                                                   \
            (_state)->distLeft = -(_state)->dist;                           \
        }                                                                   \
    }                                                                       \
    else                                                                    \
    {                                                                       \
        if ((_state)->dist > (_state)->distRight)                           \
        {                                                                   \
            (_state)->distRight = (_state)->dist;                           \
        }                                                                   \
    }                                                                       \
}                                                                           \
MACRO_STOP

#define TerminatorBuildSectorGetClipStatistics(_state)                      \
MACRO_START                                                                 \
{                                                                           \
    /* figure stats for this boundary */                                    \
    switch ((_state)->clip & (rwCLIPVERTEXLEFT | rwCLIPVERTEXRIGHT))        \
    {                                                                       \
        case rwCLIPVERTEXLEFT:                                              \
            {                                                               \
                (_state)->nLeft++;                                          \
                (_state)->matl[(_state)->boundaries->pinfo.matIndex]++;     \
                break;                                                      \
            }                                                               \
        case rwCLIPVERTEXLEFT | rwCLIPVERTEXRIGHT:                          \
        case rwCLIPVERTEXRIGHT:                                             \
            {                                                               \
                (_state)->nRight++;                                         \
                (_state)->matr[(_state)->boundaries->pinfo.matIndex]++;     \
                break;                                                      \
            }                                                               \
        case 0:                                                             \
            {                                                               \
                (_state)->nSplit++;                                         \
                                                                            \
                if ((_state)->distRight > (_state)->distLeft)               \
                {                                                           \
                    (_state)->nRight++;                                     \
                    (_state)->matr[(_state)->boundaries->pinfo.matIndex]++; \
                    if ((_state)->distLeft > (_state)->overRight)           \
                    {                                                       \
                        (_state)->overRight = (_state)->distLeft;           \
                    }                                                       \
                }                                                           \
                else                                                        \
                {                                                           \
                    (_state)->nLeft++;                                      \
                    (_state)->matl[(_state)->boundaries->pinfo.matIndex]++; \
                    if ((_state)->distRight > (_state)->overLeft)           \
                    {                                                       \
                        (_state)->overLeft = (_state)->distRight;           \
                    }                                                       \
                }                                                           \
                                                                            \
                if ((_state)->boundaries->pinfo.hasAlpha)                   \
                {                                                           \
                    (_state)->alphaInOverlap = TRUE;                        \
                }                                                           \
                break;                                                      \
            }                                                               \
    }                                                                       \
}                                                                           \
MACRO_STOP

/****************************************************************************
 _rtBuildSectorGetDistStatistics

 On entry   : Build sector
            : Overlap(OUT)
            : Alphadist(OUT)
 */
void
_rtImportBuildSectorGetClipStatistics(RtWorldImportBuildSector *
                                      buildSector,
                                      RtBuildSectorClipStatistics *
                                      stats, RwInt32 plane,
                                      RwReal value)
{
    RwInt32             numBoundaries;
    RwInt32             nJ;
    RtBoundaryState     state;

    RWFUNCTION(RWSTRING("_rtImportBuildSectorGetClipStatistics"));
    RWASSERT(buildSector);
    RWASSERT(stats);

    state.overLeft = state.overRight = 0.0f;
    state.nLeft = 0;
    state.nRight = 0;
    state.nSplit = 0;
    state.alphaInOverlap = FALSE;

    state.matl = (RwUInt32 *) RwCalloc(sizeof(RwUInt32), MAXMATERIALS);
    state.matr = (RwUInt32 *) RwCalloc(sizeof(RwUInt32), MAXMATERIALS);

    numBoundaries = buildSector->numBoundaries;
    state.boundaries = buildSector->boundaries;

    InitBuildSectorGetClipStatistics(&state);

    for (nJ = 0; nJ < numBoundaries; nJ++)
    {

        RtWorldImportBuildVertexMode *const mode =
            &state.boundaries->mode;
        RtWorldImportVertex *const vpVert = mode->vpVert;

        if (!vpVert)
        {
            TerminatorBuildSectorGetClipStatistics(&state);
            InitBuildSectorGetClipStatistics(&state);
        }
        else
        {
            VertexBuildSectorGetClipStatistics(&state, vpVert,
                                               plane, value);
        }
        state.boundaries++;
    }

    /* how many materials used? */
    stats->numMaterialLeft = stats->numMaterialRight = 0;
    for (nJ = 0; nJ < MAXMATERIALS; nJ++)
    {
        if (state.matl[nJ])
            stats->numMaterialLeft++;
        if (state.matr[nJ])
            stats->numMaterialRight++;
    }
    RwFree(state.matr);
    RwFree(state.matl);

    /* and copy the rest of the stats */
    stats->overlapLeft = state.overLeft;
    stats->overlapRight = state.overRight;
    stats->nLeft = state.nLeft;
    stats->nRight = state.nRight;
    stats->nSplit = state.nSplit;
    stats->alphaInOverlap = state.alphaInOverlap;

    /* All done */

    RWRETURNVOID();
}
