/*
 *
 * VRML to RW converter plug-in
 */

/****************************************************************************
 *    
 * VRML 2.0 to RW3.0 Converter
 * Copyright (C) 1998 Criterion Technologies
 *
 * Author  : Damian Scallan 
 *
 * Module  : Material.c
 *                                                                         
 * Purpose : Keeps a record of all the created materials
 *          
 ****************************************************************************/

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

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

#include "rpplugin.h"
#include <rpdbgerr.h>
#include "rpvrmlanim.h"
#include "rpvrml.h"
#include "material.h"

static const char __RWUNUSED__ rcsid[] =
    "@@(#)$Id: material.c,v 1.32 2001/02/05 11:44:22 johns Exp $";

#define rpMaterialListGetNumMaterials(mlist) ((mlist)->numMaterials)

#if (0)

/*
 * These Prototypes are currently in <rpworld.h>
 */

/* Setting up and destroying material lists */
extern RpMaterialList *rpMaterialListInitialize(RpMaterialList *
                                                matList);
extern RpMaterialList *rpMaterialListDeinitialize(RpMaterialList *
                                                  matList);

/* Accessing material lists */
extern RpMaterial  *rpMaterialListGetMaterial(const RpMaterialList *
                                              matList,
                                              RwInt32 matIndex);
extern RpMaterialList *rpMaterialListCopy(RpMaterialList * matListOut,
                                          const RpMaterialList *
                                          matListIn);
extern RwInt32      rpMaterialListAppendMaterial(RpMaterialList *
                                                 matList,
                                                 RpMaterial * material);

#endif /* (0) */

/****************************************************************************
 Local (Static) Prototypes
 */

static RpMaterial  *Material_CreateWhite(void);

/****************************************************************************
 Local (static) Globals
 */

/* material list */
RpMaterialList      GmaterialList;

/* current node material */
int                 GcurrentMaterialIndex;

/* white material */
int                 GwhiteMaterialIndex;

/* current emissive color */
sfcolor             emissiveColor;

/* flag to say if a material node was encountered */
int                 matNodeFlag;

/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

    Material methods

   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */

VRMLBool
Material_Init(void)
{
    RWFUNCTION(RWSTRING("Material_Init"));

    GcurrentMaterialIndex = -1;
    GwhiteMaterialIndex = -1;

    emissiveColor.r = emissiveColor.g = emissiveColor.b = 0.0f;

    matNodeFlag = FALSE;

    if (!rpMaterialListInitialize(&GmaterialList))
    {
        RWRETURN((FALSE));
    }

    RWRETURN((TRUE));
}

void
Material_Destroy(void)
{
    RWFUNCTION(RWSTRING("Material_Destroy"));

    rpMaterialListDeinitialize(&GmaterialList);
    RWRETURNVOID();
}

VRMLBool
Material_SetCurrent(RpMaterial * material)
{
    int                 numMaterials;
    int                 materialNum;
    RpMaterial         *listMaterial;

    RWFUNCTION(RWSTRING("Material_SetCurrent"));

    if (!material)
    {
        GcurrentMaterialIndex = -1;

        RWRETURN((TRUE));
    }

    numMaterials = rpMaterialListGetNumMaterials(&GmaterialList);
    for (materialNum = 0; materialNum < numMaterials; materialNum++)
    {
        /* see if similar material is already in list */
        listMaterial =
            rpMaterialListGetMaterial(&GmaterialList, materialNum);

        /* are both textured */
        if (listMaterial->texture && material->texture)
        {
            /* do both have same texture */
            if (rwstrcmp(listMaterial->texture->name,
                         material->texture->name) != 0)
            {
                /* not equal */
                break;
            }

            /* do both have same color */
            if (!((listMaterial->color.red == material->color.red) &&
                  (listMaterial->color.green == material->color.green)
                  && (listMaterial->color.blue == material->color.blue)
                  && (listMaterial->color.alpha ==
                      material->color.alpha)))
            {
                /* not equal */
                break;
            }

            /* else equal */
            RpMaterialDestroy(material);
            GcurrentMaterialIndex = materialNum;

            RWRETURN((TRUE));
        }
        /* are both untextured */
        else if (!listMaterial->texture && !material->texture)
        {
            /* do both have same color */
            if (!((listMaterial->color.red == material->color.red) &&
                  (listMaterial->color.green == material->color.green)
                  && (listMaterial->color.blue == material->color.blue)
                  && (listMaterial->color.alpha ==
                      material->color.alpha)))
            {
                /* not equal */
                break;
            }

            /* else equal */
            RpMaterialDestroy(material);
            GcurrentMaterialIndex = materialNum;

            RWRETURN((TRUE));
        }
    }
    /* else not in list already so add */
    RpMaterialAddRef(material);
    rpMaterialListAppendMaterial(&GmaterialList, material);
    GcurrentMaterialIndex = numMaterials;

    RWRETURN((TRUE));
}

int
Material_GetCurrentIndex(void)
{
    RWFUNCTION(RWSTRING("Material_GetCurrentIndex"));

    if (GcurrentMaterialIndex == -1)
    {
        /* use a default white material instead */
        GcurrentMaterialIndex = Material_GetWhiteIndex();
    }

    RWRETURN((GcurrentMaterialIndex));
}

RpMaterial         *
Material_GetCurrent(void)
{
    int                 currentMaterialIndex;

    RWFUNCTION(RWSTRING("Material_GetCurrent"));

    currentMaterialIndex = Material_GetCurrentIndex();

    if (currentMaterialIndex != -1)
    {
        RpMaterial         *currentMaterial;

        currentMaterial =
            rpMaterialListGetMaterial(&GmaterialList,
                                      currentMaterialIndex);

        RWRETURN((currentMaterial));
    }

    RWRETURN(((RpMaterial *)NULL));
}

/*******************************************************************
white
********************************************************************/

static RpMaterial  *
Material_CreateWhite(void)
{
    RpMaterial         *white;
    RwRGBAReal          nColour;
    RwRGBA              cColour;

    RWFUNCTION(RWSTRING("Material_CreateWhite"));

    white = RpMaterialCreate();
    if (!white)
    {
        RWRETURN(((RpMaterial *)NULL));
    }
    nColour.red = (RwReal) (1);
    nColour.green = (RwReal) (1);
    nColour.blue = (RwReal) (1);
    nColour.alpha = (RwReal) (1);

    RwRGBAFromRwRGBAReal(&cColour, &nColour);

    RpMaterialSetColor(white, &cColour);

    RWRETURN((white));
}

int
Material_GetWhiteIndex(void)
{
    int                 whiteIndex;
    RpMaterial         *white;

    RWFUNCTION(RWSTRING("Material_GetWhiteIndex"));

    /* is current material textured */
    if (Material_IsCurrentTextured())
    {
        /* if so create a white material with the current texture */
        RpMaterial         *current = Material_GetCurrent();

        if (current)
        {
            RwTexture          *texture = RpMaterialGetTexture(current);

            if (texture)
            {
                white = Material_CreateWhite();
                if (white)
                {
                    RpMaterialSetTexture(white, texture);
                    Material_SetCurrent(white);
                    whiteIndex = Material_GetCurrentIndex();

                    RWRETURN((whiteIndex));
                }
            }
        }
    }

    if (GwhiteMaterialIndex == -1)
    {
        white = Material_CreateWhite();
        if (white)
        {
            Material_SetCurrent(white);
            GwhiteMaterialIndex = Material_GetCurrentIndex();
        }
    }

    RWRETURN((GwhiteMaterialIndex));
}

RpMaterial         *
Material_GetWhite(void)
{
    int                 whiteMaterialIndex;

    RWFUNCTION(RWSTRING("Material_GetWhite"));

    whiteMaterialIndex = Material_GetWhiteIndex();

    if (whiteMaterialIndex != -1)
    {
        RpMaterial         *white;

        white =
            rpMaterialListGetMaterial(&GmaterialList,
                                      whiteMaterialIndex);

        RWRETURN((white));
    }

    RWRETURN(((RpMaterial *)NULL));
}

VRMLBool
Material_CopyList(RpMaterialList * materialList)
{
    VRMLBool            result;
    RpMaterialList     *list;

    RWFUNCTION(RWSTRING("Material_CopyList"));
    RWASSERT(materialList);

    list = rpMaterialListCopy(materialList, &GmaterialList);
    result = (NULL != list);

    RWRETURN(result);
}

VRMLBool
Material_IsCurrentTextured(void)
{
    RWFUNCTION(RWSTRING("Material_IsCurrentTextured"));

    if (GcurrentMaterialIndex != -1)
    {
        RpMaterial         *currentMaterial;

        currentMaterial =
            rpMaterialListGetMaterial(&GmaterialList,
                                      GcurrentMaterialIndex);

        if (RpMaterialGetTexture(currentMaterial))
        {
            RWRETURN((TRUE));
        }
    }

    RWRETURN((FALSE));
}

void
Material_SetDefault(void)
{
    RWFUNCTION(RWSTRING("Material_SetDefault"));

    /* reset old state */
    emissiveColor.r = emissiveColor.g = emissiveColor.b = 0.0f;
    matNodeFlag = FALSE;

    GcurrentMaterialIndex = -1;

    RWRETURNVOID();
}

RwBool
Material_IsSet(void)
{
    RWFUNCTION(RWSTRING("Material_IsSet"));

    if (GcurrentMaterialIndex == -1)
    {
        RWRETURN((FALSE));
    }

    RWRETURN((TRUE));
}

void
Material_SetCurrentEmissiveColor(sfcolor * sfc)
{
    RWFUNCTION(RWSTRING("Material_SetCurrentEmissiveColor"));

    if (sfc)
    {
        emissiveColor = *sfc;
    }
    else
    {
        emissiveColor.r = emissiveColor.g = emissiveColor.b = 0.0f;
    }
    RWRETURNVOID();
}

sfcolor            *
Material_GetCurrentEmissiveColor(void)
{
    RWFUNCTION(RWSTRING("Material_GetCurrentEmissiveColor"));

    RWRETURN((&emissiveColor));
}

void
Material_SetMatNodeFlag(RwBool flag)
{
    RWFUNCTION(RWSTRING("Material_SetMatNodeFlag"));

    matNodeFlag = flag;
    RWRETURNVOID();
}

RwBool
Material_GetMatNodeFlag(void)
{
    RWFUNCTION(RWSTRING("Material_GetMatNodeFlag"));

    RWRETURN((matNodeFlag));
}
