/*
 *
 * VRML to RW converter plug-in
 */
/****************************************************************************
 *    
 * VRML 2.0 to RW3.0 Converter
 * Copyright (C) 1998 Criterion Technologies
 *
 * Author  : Damian Scallan 
 *
 * Module  : light.c
 *                                                                         
 * Purpose : creating lights
 *
 ****************************************************************************/

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

#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <math.h>

#include "rpplugin.h"
#include "light.h"
#include "abstractnode.h"
#include "builder.h"
#include "rpvrmlanim.h"
#include "rpvrml.h"
#include "utilities.h"

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

static RwFrame     *Light_CreateLocalFrame(RwV3d * dir, RwV3d * pos);

RwBool
DirectionalLight_Convert(AbstractNode * an)
{
    char               *nodeName;

    RWFUNCTION(RWSTRING("DirectionalLight_Convert"));
    RWASSERT(an);

    if (an)
    {
        AbstractField      *af;
        Field              *field;
        sfcolor            *color = (sfcolor *) NULL;
        sfvec3f            *direction = (sfvec3f *) NULL;
        RwFrame            *frame;
        RpLight            *light;
        RwRGBAReal          rgba;
        RwV3d               dir, pos;

        nodeName = AbstractNode_GetBaseName(an);
        /*RWASSERT(strcmp(nodeName, "DirectionalLight") == 0); */

        af = AbstractNode_GetAbstractField(an, "color");
        if (af)
        {
            field = AbstractField_GetField(af);
            color = FieldSfcolor_GetValue(field);
        }

        af = AbstractNode_GetAbstractField(an, "direction");
        if (af)
        {
            field = AbstractField_GetField(af);
            direction = FieldSfvec3f_GetValue(field);
        }

        /* create the light's frame */
        dir = *(RwV3d *) direction;
        pos.x = pos.y = pos.z = (RwReal) (0);
        frame = Light_CreateLocalFrame(&dir, &pos);
        if (!frame)
        {
            RWRETURN(FALSE);
        }

        /* create the light */
        light = RpLightCreate(rpLIGHTDIRECTIONAL);
        if (!light)
        {
            RwFrameDestroy(frame);

            RWRETURN(FALSE);
        }

        /* set the light's frame */
        RpLightSetFrame(light, frame);

        /* set the light's color */
        rgba.red = (RwReal) (color->r);
        rgba.green = (RwReal) (color->g);
        rgba.blue = (RwReal) (color->b);
        RpLightSetColor(light, &rgba);

        /* add to the world's light list */
        if (!Build_SceneAddLight(light))
        {
            RwFrameDestroy(frame);
            RpLightDestroy(light);

            RWRETURN(FALSE);
        }

        RWRETURN(TRUE);
    }

    RWRETURN(FALSE);
}

RwBool
PointLight_Convert(AbstractNode * an)
{
    char               *nodeName;

    RWFUNCTION(RWSTRING("PointLight_Convert"));
    RWASSERT(an);

    if (an)
    {
        AbstractField      *af;
        Field              *field;
        sfcolor            *color = (sfcolor *) NULL;
        sfvec3f            *location = (sfvec3f *) NULL;
        sffloat            *radius = (sffloat *) NULL;
        RwFrame            *frame;
        RpLight            *light;
        RwRGBAReal          rgba;
        RwV3d               dir, pos;
        RwReal              rad;

        nodeName = AbstractNode_GetBaseName(an);
        /*RWASSERT(strcmp(nodeName, "PointLight") == 0); */

        af = AbstractNode_GetAbstractField(an, "color");
        if (af)
        {
            field = AbstractField_GetField(af);
            color = FieldSfcolor_GetValue(field);
        }

        af = AbstractNode_GetAbstractField(an, "location");
        if (af)
        {
            field = AbstractField_GetField(af);
            location = FieldSfvec3f_GetValue(field);
        }

        af = AbstractNode_GetAbstractField(an, "radius");
        if (af)
        {
            field = AbstractField_GetField(af);
            radius = FieldSffloat_GetValue(field);
        }

        /* create the light's frame */
        dir.x = (RwReal) (1);
        dir.y = (RwReal) (0);
        dir.y = (RwReal) (0);
        pos = *(RwV3d *) location;
        frame = Light_CreateLocalFrame(&dir, &pos);
        if (!frame)
        {
            RWRETURN(FALSE);
        }

        /* create the light */
        light = RpLightCreate(rpLIGHTPOINT);
        if (!light)
        {
            RwFrameDestroy(frame);

            RWRETURN(FALSE);
        }

        /* set the light's frame */
        RpLightSetFrame(light, frame);

        /* set the light's color */
        rgba.red = (RwReal) (color->r);
        rgba.green = (RwReal) (color->g);
        rgba.blue = (RwReal) (color->b);
        RpLightSetColor(light, &rgba);

        /* set the lights radius */
        rad = (RwReal) (*radius * Build_GetScaleFactor());
        RpLightSetRadius(light, rad);

        /* add to the world's light list */
        if (!Build_SceneAddLight(light))
        {
            RwFrameDestroy(frame);
            RpLightDestroy(light);

            RWRETURN(FALSE);
        }

        RWRETURN(TRUE);
    }

    RWRETURN(FALSE);
}

RwBool
SpotLight_Convert(AbstractNode * an)
{
    char               *nodeName;

    RWFUNCTION(RWSTRING("SpotLight_Convert"));
    RWASSERT(an);

    if (an)
    {
        AbstractField      *af;
        Field              *field;
        sfcolor            *color = (sfcolor *) NULL;
        sffloat            *cutOffAngle = (sffloat *) NULL;
        sfvec3f            *direction = (sfvec3f *) NULL;
        sfvec3f            *location = (sfvec3f *) NULL;
        sffloat            *radius = (sffloat *) NULL;
        RwFrame            *frame;
        RpLight            *light;
        RwRGBAReal          rgba;
        RwV3d               dir, pos;
        RwReal              rad, ang;

        nodeName = AbstractNode_GetBaseName(an);
        /*RWASSERT(strcmp(nodeName, "SpotLight") == 0); */

        af = AbstractNode_GetAbstractField(an, "color");
        if (af)
        {
            field = AbstractField_GetField(af);
            color = FieldSfcolor_GetValue(field);
        }

        af = AbstractNode_GetAbstractField(an, "cutOffAngle");
        if (af)
        {
            field = AbstractField_GetField(af);
            cutOffAngle = FieldSffloat_GetValue(field);
        }

        af = AbstractNode_GetAbstractField(an, "direction");
        if (af)
        {
            field = AbstractField_GetField(af);
            direction = FieldSfvec3f_GetValue(field);
        }

        af = AbstractNode_GetAbstractField(an, "location");
        if (af)
        {
            field = AbstractField_GetField(af);
            location = FieldSfvec3f_GetValue(field);
        }

        af = AbstractNode_GetAbstractField(an, "radius");
        if (af)
        {
            field = AbstractField_GetField(af);
            radius = FieldSffloat_GetValue(field);
        }

        /* create the light's frame */
        dir = *(RwV3d *) direction;
        pos = *(RwV3d *) location;
        frame = Light_CreateLocalFrame(&dir, &pos);
        if (!frame)
        {
            RWRETURN(FALSE);
        }

        /* create the light */
        light = RpLightCreate(rpLIGHTSPOT);
        if (!light)
        {
            RwFrameDestroy(frame);

            RWRETURN(FALSE);
        }

        /* set the light's frame */
        RpLightSetFrame(light, frame);

        /* set the light's color */
        rgba.red = (RwReal) (color->r);
        rgba.green = (RwReal) (color->g);
        rgba.blue = (RwReal) (color->b);
        RpLightSetColor(light, &rgba);

        /* set the light's cone angle */
        ang = (RwReal) (*cutOffAngle);
        RpLightSetConeAngle(light, ang);

        /* set the light's radius */
        rad = (RwReal) (*radius * Build_GetScaleFactor());
        RpLightSetRadius(light, rad);

        /* add to the world's light list */
        if (!Build_SceneAddLight(light))
        {
            RwFrameDestroy(frame);
            RpLightDestroy(light);

            RWRETURN(FALSE);
        }

        RWRETURN(TRUE);
    }

    RWRETURN(FALSE);
}

static RwFrame     *
Light_CreateLocalFrame(RwV3d * dir, RwV3d * pos)
{
    RwV3d               scalePos;
    RwMatrix           *matrix;
    RwFrame            *frame;

    RWFUNCTION(RWSTRING("Light_CreateLocalFrame"));

    frame = RwFrameCreate();
    if (!frame)
    {
        RWRETURN((RwFrame *)NULL);
    }

    /* get the frame's matrix */
    matrix = RwFrameGetMatrix(frame);

    /* scale the position vector */
    scalePos = *pos;
    RwV3dScale(&scalePos, &scalePos, (RwReal) (Build_GetScaleFactor()));

    /* set the lookAt & pos */
    MatrixSetAtPos(matrix, dir, &scalePos);

    RWRETURN(frame);
}
