
/****************************************************************************
 * 
 * VRML 2.0 to RW3.0 Converter
 * Copyright (C) 1997 Criterion Technologies
 *
 * Author  : Damian Scallan 
 *
 * Module  : Converter.c
 *                                                                         
 * Purpose : Takes the AbstractNode representation of a Vrml scene graph
 *           and converts it to a specific form
 *                                                                         
 ****************************************************************************/

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

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <float.h>

#include "rpplugin.h"
#include "converter.h"
#include "parser.h"
#include "appearance.h"
#include "material.h"
#include "namegen.h"
#include "builder.h"
#include "primitives.h"
#include "elevation.h"
#include "extrusion.h"
#include "faceset.h"
#include "groupnodes.h"
#include "nodestubs.h"
#include "texturetransform.h"
#include "rpvrmlanim.h"
#include "rpvrml.h"
#include "light.h"

static const char __RWUNUSED__ rcsid[] =
    "@@(#)$Id: converter.c,v 1.42 2001/02/05 11:50:43 johns Exp $";

/****************************************************************************
 Local defines
 */

#define MAXTOKENNAMELEN 20

/****************************************************************************
 Local types
 */

typedef             RwBool(*ConvertAbstractNodeFn) (AbstractNode * an);

typedef struct AnTypeListEntry AnTypeListEntry;
struct AnTypeListEntry
{
    const RwChar       *anIdentifier;
    ConvertAbstractNodeFn convertAn;
};

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

static void         Convert_SceneGraph(AbstractNode * an);
static RwBool       Convert_Shape(AbstractNode * an);
static RwBool       Convert_Geometry(AbstractNode * anChild);

/****************************************************************************
 Local (static) variables
 */

/* Dispatch tables for dispatching different types of abstract node */
static AnTypeListEntry anSceneGraphTypeList[] = {
    {RWSTRING("Anchor"), Anchor_Convert},
    {RWSTRING("Billboard"), Billboard_Convert},
    {RWSTRING("Collision"), Collision_Convert},
    {RWSTRING("Group"), Group_Convert},
    {RWSTRING("Shape"), Dummy_Convert},
    {RWSTRING("Transform"), Transform_Convert},
    {RWSTRING("Inline"), Inline_Convert}
};

static AnTypeListEntry anChildrenTypeList[] = {
    {RWSTRING("AudioClip"), AudioClip_Convert},
    {RWSTRING("Anchor"), Anchor_Convert},
    {RWSTRING("Background"), Background_Convert},
    {RWSTRING("Billboard"), Billboard_Convert},
    {RWSTRING("Collision"), Collision_Convert},
    {RWSTRING("ColorInterpolator"), ColorInterpolator_Convert},
    {RWSTRING("CoordinateInterpolator"),
     CoordinateInterpolator_Convert},
    {RWSTRING("CylinderSensor"), CylinderSensor_Convert},
    {RWSTRING("DirectionalLight"), DirectionalLight_Convert},
    {RWSTRING("Fog"), Fog_Convert},
    {RWSTRING("Group"), Group_Convert},
    {RWSTRING("Inline"), Inline_Convert},
    {RWSTRING("LOD"), LOD_Convert},
    {RWSTRING("NavigationInfo"), NavigationInfo_Convert},
    {RWSTRING("NormalInterpolator"), NormalInterpolator_Convert},

    {RWSTRING("OrientationInterpolator"),
     OrientationInterpolator_Convert},
    {RWSTRING("PlaneSensor"), PlaneSensor_Convert},
    {RWSTRING("PointLight"), PointLight_Convert},
    {RWSTRING("PositionInterpolator"), PositionInterpolator_Convert},
    {RWSTRING("ProximitySensor"), ProximitySensor_Convert},
    {RWSTRING("ScalarInterpolator"), ScalarInterpolator_Convert},
    {RWSTRING("Script"), Script_Convert},
    {RWSTRING("Shape"), Convert_Shape},
    {RWSTRING("Sound"), Sound_Convert},
    {RWSTRING("SpotLight"), SpotLight_Convert},
    {RWSTRING("SphereSensor"), SphereSensor_Convert},
    {RWSTRING("Switch"), Switch_Convert},
    {RWSTRING("TimeSensor"), TimeSensor_Convert},
    {RWSTRING("TouchSensor"), TouchSensor_Convert},
    {RWSTRING("Transform"), Transform_Convert},
    {RWSTRING("Viewpoint"), Viewpoint_Convert},
    {RWSTRING("VisibilitySensor"), VisibilitySensor_Convert},
    {RWSTRING("WorldInfo"), WorldInfo_Convert}
};

static AnTypeListEntry anGeometryTypeList[] = {
    {RWSTRING("Box"), Box_Create},
    {RWSTRING("Cone"), Cone_Create},
    {RWSTRING("Cylinder"), Cylinder_Create},
    {RWSTRING("ElevationGrid"), ElevationGrid_Create},
    {RWSTRING("Extrusion"), Extrusion_Create},
    {RWSTRING("IndexedFaceSet"), FaceSet_Create},
    {RWSTRING("IndexedLineSet"), IndexedLineSet_Create},
    {RWSTRING("PointSet"), PointSet_Create},
    {RWSTRING("Sphere"), Sphere_Create},
    {RWSTRING("Text"), Text_Create}
};

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

    Converter methods

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

static              RwBool
Convert_Init(void)
{
    RWFUNCTION(RWSTRING("Convert_Init"));

    Build_Init();
    Material_Init();
    NameGen_Init();

    RWRETURN(TRUE);
}

static void
Convert_Destroy(void)
{
    RWFUNCTION(RWSTRING("Convert_Destroy"));

    Build_Destroy();
    Material_Destroy();
    NameGen_Destroy();

    RWRETURNVOID();
}

RwBool
Convert_AbstractNodeList(LLinkList * abstractNodeList)
{
    AbstractNode       *anChild;

    RWFUNCTION(RWSTRING("Convert_AbstractNodeList"));

    if (!Convert_Init())
    {
        RWRETURN(FALSE);
    }

    LLinkList_IteratorReset(abstractNodeList);
    while ((anChild =
            (AbstractNode *) LLinkList_IteratorPrev(abstractNodeList)))
    {
        AbstractNode       *anInstance;

        anInstance = AbstractNodeTree_InstanceProto(anChild);
        if (anInstance)
        {
            Convert_SceneGraph(anChild);
        }
    }
    LLinkList_Destroy(abstractNodeList,
                      (linkCallback) AbstractNode_Destroy);

    Build_ConvertScene();

    Convert_Destroy();

    RWRETURN(TRUE);
}

static void
Convert_SceneGraph(AbstractNode * an)
{
    RwInt32             i;
    RwChar             *baseName;
    AnTypeListEntry    *anType;

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

    baseName = AbstractNode_GetBaseName(an);

    /* Search the table for a function to dispatch to */
    i = sizeof(anSceneGraphTypeList) / sizeof(AnTypeListEntry);
    anType = anSceneGraphTypeList;
    while (i--)
    {
        if (rwstrcmp(baseName, anType->anIdentifier) == 0)
        {
            /* Found it, dispatch it */
            anType->convertAn(an);
            RWRETURNVOID();
        }

        /* try next one */
        anType++;
    }

    /* Didn't find it */
    RWASSERT(FALSE);
    RWRETURNVOID();
}

RwBool
Convert_Children(AbstractNode * an)
{
    RwInt32             i;
    RwChar             *baseName;
    AnTypeListEntry    *anType;

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

    baseName = AbstractNode_GetBaseName(an);

    /* Search the table for a function to dispatch to */
    i = sizeof(anChildrenTypeList) / sizeof(AnTypeListEntry);
    anType = anChildrenTypeList;
    while (i--)
    {
        if (rwstrcmp(baseName, anType->anIdentifier) == 0)
        {
            /* Found it, dispatch it */
            anType->convertAn(an);
            RWRETURN(TRUE);
        }

        /* try next one */
        anType++;
    }

    /* Didn't find it */
    RWASSERT(FALSE);
    RWRETURN(FALSE);
}

static              RwBool
Convert_Shape(AbstractNode * an)
{
    AbstractNode       *anChild;
    RwChar             *baseName;

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

    baseName = AbstractNode_GetBaseName(an);
    /*RWASSERT(rwstrcmp(baseName, "Shape") == 0); */

    /* reset the pivot point */
    Transform_ResetOffset();

    /* set an initial default material state */
    Material_SetDefault();

    /* reset the current texture transform */
    TextureTransform_Reset();

    if ((anChild = AbstractNode_GetChildNode(an, "appearance")))
    {
        RpMaterial         *material = Appearance_Convert(anChild);

        Material_SetCurrent(material);
    }
    else
    {
        Material_SetCurrent((RpMaterial *)NULL);
    }

    if ((anChild = AbstractNode_GetChildNode(an, "geometry")))
    {
        Convert_Geometry(anChild);
    }

    RWRETURN(TRUE);
}

static              RwBool
Convert_Geometry(AbstractNode * an)
{
    RwInt32             i;
    RwChar             *baseName;
    AnTypeListEntry    *anType;

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

    baseName = AbstractNode_GetBaseName(an);

    /* Search the table for a function to dispatch to */
    i = sizeof(anGeometryTypeList) / sizeof(AnTypeListEntry);
    anType = anGeometryTypeList;
    while (i--)
    {
        if (rwstrcmp(baseName, anType->anIdentifier) == 0)
        {
            /* Found it, dispatch it */
            RWRETURN(anType->convertAn(an));
        }

        /* try next one */
        anType++;
    }

    /* Didn't find it */
    RWASSERT(FALSE);
    RWRETURN(FALSE);
}
