/* *INDENT-OFF* */

/*
 * objAllInOne
 * default per-object callback functions for PS2-specific object pipelines
 * 
 * Copyright (c) Criterion Software Limited
 */
/****************************************************************************
 *                                                                          *
 * module : objallinone.c                                                   *
 *                                                                          *
 * purpose: yawn...                                                         *
 *                                                                          *
 ****************************************************************************/

/*
#### SYNCHRONISATION
####
#### UP TO DATE WITH VERSION 1.90 OF nodePS2ObjAllInOne.c
####
#### SYNCHRONISATION
*/

/****************************************************************************
 includes
 */

#include "nodeps2objallinone.h"
#include "objallinone.h"

#if (!defined(DOXYGEN))
static const char rcsid[] __RWUNUSED__ = 
    "@@@@(#)$Id: objallinone.c,v 1.20 2001/09/20 12:56:53 iestynb Exp $";
#endif /* (!defined(DOXYGEN)) */



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

   Functions

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


/****************************************************************************
 PS2AllSkyWorldApplyLight

 apply light function from skywrins.c
*/
void
PS2AllSkyWorldApplyLight(const void *voidLight, const RwMatrix *inverseMat,
                        RwReal invScale, const RwSurfaceProperties *surfaceProps)
{
    const RpLight       *light = (const RpLight *)voidLight;
    RpLightType         type = RpLightGetType(light);
    const RwRGBAReal    *color = RpLightGetColor(light);
    RwFrame             *frame = RpLightGetFrame(light);
    const RwV3d         *pos, *at;

    RWFUNCTION(RWSTRING("PS2AllSkyWorldApplyLight"));

/* TODO[5][7]: THIS FUNCTION SHOULD BE ABLE TO TAKE AN ARRAY OF LIGHTS SO IT
 *    ONLY GETS CALLED ONCE (LIGHTS SHOULD BE IN A KNOWN ORDER TO AVOID THE
 *   SWITCH STATEMENT, JUST DO A SERIES OF WHILE LOOPS) */


    /* Only if we have a lightblock, and have sufficient space left for the
     * light and a termination word (4 qwords)
     */

    /* We quietly ignore the fact the the matrix is 4 qwords, since this
     * happens on the first light only, and we know the buffer is big
     * enough for this and a light and a termination word
     */
    if (_skyLightQWordsWritten < (LIGHTBLOCKQWORDS-4))
    {
        /* Capture the matrix and lighting coefficients on the first light */
        if (!_skyLightQWordsWritten)
        {
            if (inverseMat)
            {
                RWASSERT(RWMATRIXALIGNMENT(inverseMat));

                /* Use the inverse matrix given */
                *_skyLightFillPos++ = inverseMat->right.x;
                *_skyLightFillPos++ = inverseMat->right.y;
                *_skyLightFillPos++ = inverseMat->right.z;
                *_skyLightFillPos++ = invScale;
                *_skyLightFillPos++ = inverseMat->up.x;
                *_skyLightFillPos++ = inverseMat->up.y;
                *_skyLightFillPos++ = inverseMat->up.z;
                *_skyLightFillPos++ = invScale;
                *_skyLightFillPos++ = inverseMat->at.x;
                *_skyLightFillPos++ = inverseMat->at.y;
                *_skyLightFillPos++ = inverseMat->at.z;
                *_skyLightFillPos++ = invScale;
                *_skyLightFillPos++ = inverseMat->pos.x;
                *_skyLightFillPos++ = inverseMat->pos.y;
                *_skyLightFillPos++ = inverseMat->pos.z;
                *_skyLightFillPos++ = invScale;
            }
            else
            {
                /* Else use identity matrix */
                *_skyLightFillPos++ = (RwReal)(1.0f);
                *_skyLightFillPos++ = (RwReal)(0.0f);
                *_skyLightFillPos++ = (RwReal)(0.0f);
                *_skyLightFillPos++ = invScale;
                *_skyLightFillPos++ = (RwReal)(0.0f);
                *_skyLightFillPos++ = (RwReal)(1.0f);
                *_skyLightFillPos++ = (RwReal)(0.0f);
                *_skyLightFillPos++ = invScale;
                *_skyLightFillPos++ = (RwReal)(0.0f);
                *_skyLightFillPos++ = (RwReal)(0.0f);
                *_skyLightFillPos++ = (RwReal)(1.0f);
                *_skyLightFillPos++ = invScale;
                *_skyLightFillPos++ = (RwReal)(0.0f);
                *_skyLightFillPos++ = (RwReal)(0.0f);
                *_skyLightFillPos++ = (RwReal)(0.0f);
                *_skyLightFillPos++ = invScale;
            }
            _skyLightQWordsWritten += 4;

            /* Capture lighting coefficients too */
            ((RwReal *)&surfLightCoeffs)[0] =
                surfaceProps->ambient * (RwReal)(255.0f);
            ((RwReal *)&surfLightCoeffs)[1] =
                surfaceProps->specular * (RwReal)(255.0f);
            ((RwReal *)&surfLightCoeffs)[2] =
                surfaceProps->diffuse * (RwReal)(255.0f);
        }

        if (frame)
        {
            RwMatrix *matrix = RwFrameGetLTM(frame);

            RWASSERT(RWMATRIXALIGNMENT(matrix));

            at = RwMatrixGetAt(matrix);
            pos = RwMatrixGetPos(matrix);
        }
        else
        {
            at = pos = NULL;
        }

        /* Add the light to the light buffer (first the generic bit) */
        _skyLightFillPos[0] = color->red;
        _skyLightFillPos[1] = color->green;
        _skyLightFillPos[2] = color->blue;
        ((RwUInt32 *)(&_skyLightFillPos[3]))[0] = (RwUInt32)type;

        /* Then the light specific bit */
        switch (type)
        {
            case (rpLIGHTDIRECTIONAL):
            {
                _skyLightFillPos += 4;
                *_skyLightFillPos++ = at->x;
                *_skyLightFillPos++ = at->y;
                *_skyLightFillPos++ = at->z;
                *_skyLightFillPos++ = (RwReal)(0.0f);
                _skyLightQWordsWritten += 2;
                break;
            }
            case (rpLIGHTAMBIENT):
            {
                _skyLightFillPos += 4;
                _skyLightQWordsWritten++;
                break;
            }
            case (rpLIGHTPOINT):
            {
                _skyLightFillPos += 4;
                *_skyLightFillPos++ = pos->x;
                *_skyLightFillPos++ = pos->y;
                *_skyLightFillPos++ = pos->z;
                *_skyLightFillPos++ = light->radius;
                _skyLightQWordsWritten += 2;
                break;
            }
            case (rpLIGHTSPOT):
            case (rpLIGHTSPOTSOFT):
            {
                _skyLightFillPos += 4;
                *_skyLightFillPos++ = pos->x;
                *_skyLightFillPos++ = pos->y;
                *_skyLightFillPos++ = pos->z;
                *_skyLightFillPos++ = light->radius;
                *_skyLightFillPos++ = at->x;
                *_skyLightFillPos++ = at->y;
                *_skyLightFillPos++ = at->z;
                *_skyLightFillPos++ = light->minusCosAngle;
                _skyLightQWordsWritten += 3;
                break;
            }
            case (rpNALIGHTTYPE):
            default:
            {
                break;
            }
        }
    }

    RWRETURNVOID();
}

