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

#include <rwcore.h>
#include "baworld.h"
#include "p2stdclsw.h"

#include "skyisms.h"
#include "ps2clusterattribs.h"
                  
#include "matputil.h"
#include "nodeps2matinstance.h"

#if (!defined(DOXYGEN))
static const char rcsid[] __RWUNUSED__ = 
    "@@(#)$Id: matputil.c,v 1.27 2001/07/11 11:48:29 iestynb Exp $";
#endif /* (!defined(DOXYGEN)) */


/****************************************************************************
 rpObjectGetMeshCache()
 */

void 
rpObjectDestroyMeshCache(RwMeshCache *meshCache)
{
    RwInt32 i;

    RWFUNCTION(RWSTRING("rpObjectDestroyMeshCache"));
    RWASSERT(meshCache);

    /* First free up any allocated res entries */
    i = meshCache->lengthOfMeshesArray;
    while (i--)
    {
        RwResEntry  * const  mesh = meshCache->meshes[i];
        
        if (mesh)
        {
            if ((NULL == mesh->link.next) &&
                (NULL == mesh->link.prev))
            {
                /* It's persistent gotts clean up now so wait for the entry to be finished with */
                /* Wait for resEntry to be finished with before modifying */
                reDestroyCallback(mesh);

                RwResourcesFreeResEntry(mesh);
            }
            else
            {
                /* Disconnect resource entry to be garbage-collected
                 * once DMA is done with it */
                mesh->ownerRef = (RwResEntry **)NULL;
            }
        }
    }

    /* Then free up the table */
    RwFree(meshCache);

    RWRETURNVOID();
}

/****************************************************************************
 rpObjectAllocMeshCache()
 */

RwMeshCache **
rpObjectGetMeshCache(RwMeshCache **meshCacheRef, RwUInt32 numMeshes)
{
    RWFUNCTION(RWSTRING("rpObjectGetMeshCache"));

    if ( *meshCacheRef != NULL )
    {
        if ( (*meshCacheRef)->lengthOfMeshesArray != numMeshes )
        {
            rpObjectDestroyMeshCache(*meshCacheRef);
            *meshCacheRef = (RwMeshCache *)NULL;
        }
    }

    if ( *meshCacheRef == NULL )
    {
        *meshCacheRef = (RwMeshCache *)
            RwMalloc( sizeof(RwMeshCache) +
                      (numMeshes - 1) * sizeof((*meshCacheRef)->meshes[0]) );
        if ( *meshCacheRef != NULL )
        {
            (*meshCacheRef)->lengthOfMeshesArray = numMeshes;
            memset((*meshCacheRef)->meshes, 0x00U,
                   numMeshes * sizeof((*meshCacheRef)->meshes[0]));
        }
    }

    RWRETURN(meshCacheRef);
}

#if ( defined(RWDEBUG) || defined(RWSUPPRESSINLINE) )

/****************************************************************************
 rpGeometryGetMeshCache()
 */

RwMeshCache *
rpGeometryGetMeshCache(RpGeometry *geometry, RwUInt32 numMeshes)
{
    RwMeshCache **meshCacheRef;

    RWFUNCTION(RWSTRING("rpGeometryGetMeshCache"));

    meshCacheRef = &RWMESHCACHEFROMGEOMETRY(geometry);

    /* Make sure the cache is present and valid */
    RWRETURN(*rpObjectGetMeshCache(meshCacheRef, numMeshes));
}

/****************************************************************************
 rpAtomicGetMeshCache()
 */

RwMeshCache *
rpAtomicGetMeshCache(RpAtomic *atomic, RwUInt32 numMeshes)
{
    RwMeshCache **meshCacheRef;

    RWFUNCTION(RWSTRING("rpAtomicGetMeshCache"));

    meshCacheRef = &RWMESHCACHEFROMATOMIC(atomic);

    /* Make sure the cache is present and valid */
    RWRETURN(*rpObjectGetMeshCache(meshCacheRef, numMeshes));
}

/****************************************************************************
 rpWorldSectorGetMeshCache()
 */

RwMeshCache *
rpWorldSectorGetMeshCache(RpWorldSector *worldSector, RwUInt32 numMeshes)
{
    RwMeshCache **meshCacheRef;

    RWFUNCTION(RWSTRING("rpWorldSectorGetMeshCache"));

    meshCacheRef = &RWMESHCACHEFROMWORLDSECTOR(worldSector);

    /* Make sure the cache is present and valid */
    RWRETURN(*rpObjectGetMeshCache(meshCacheRef, numMeshes));
}

/****************************************************************************
 rwMeshCacheGetEntryRef
 */

RwResEntry **
rwMeshCacheGetEntryRef(const RwMeshCache *meshCache, RwUInt32 meshIndex)
{
    RwResEntry **result = (RwResEntry **)NULL; /* failure */

    RWFUNCTION(RWSTRING("rwMeshCacheGetEntryRef"));

    RWASSERT(meshCache != NULL);
    RWASSERT(meshIndex < meshCache->lengthOfMeshesArray);

    result = (RwResEntry **)
        &meshCache->meshes[meshIndex]; /* success */

    RWRETURN(result);
}

#endif /* ( defined(RWDEBUG) || defined(RWSUPPRESSINLINE) ) */
