// Wild Magic Source Code
// David Eberly
// http://www.geometrictools.com
// Copyright (c) 1998-2007
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or (at
// your option) any later version.  The license is available for reading at
// either of the locations:
//     http://www.gnu.org/copyleft/lgpl.html
//     http://www.geometrictools.com/License/WildMagicLicense.pdf
//
// Version: 4.0.0 (2006/06/28)

#ifndef WSCENEBUILDER_H
#define WSCENEBUILDER_H

#include "Wm4Foundation.h"
#include "Wm4Graphics.h"
#include "WExportSettings.h"
#include "WMaterials.h"
#include "WMaterialTree.h"
#include "WUnimaterialMesh.h"
#include "max.h"
#include "stdmat.h"
#include <vector>

class WSceneBuilder
{
public:
    WSceneBuilder (const TCHAR* acFilename, BOOL bExportSelected, 
        WExportSettings* pkSettings, ExpInterface* pkExport, Interface* pkMax,
        INode* pkRootNode);

    ~WSceneBuilder();

private:
    class AnimationTiming
    {
    public:
        AnimationTiming () : Active(FALSE), Start(0), End(0) { /**/ }

        BOOL Active;
        TimeValue Start;
        TimeValue End;
    };

    class ModifierInfo
    {
    public:
        INode* Node;
        std::vector<Modifier*> Modifiers;
    };

    enum KeyType
    {
        KT_TRANSLATION,
        KT_ROTATION,
        KT_SCALE
    };

    class KeyInfo
    {
    public:
        KeyInfo (TimeValue iTime, KeyType eType)
        {
            Time = iTime;
            Type = eType;
        }

        TimeValue Time;
        KeyType Type; 
    };

    // scene traversal
    bool Traverse (INode* pkMaxNode, Wm4::Spatial* pkWm4Node);

    // node processing
    Wm4::Spatial* BuildGeometry (INode* pkMaxNode, Wm4::Spatial* pkWm4Node);
    Wm4::Spatial* BuildSpatial (INode* pkMaxNode, Wm4::Spatial* pkWm4Node);
    Wm4::Spatial* BuildMesh (INode* pkMaxNode, Wm4::Spatial* pkWm4Node);
    Wm4::Transformation GetLocalTransform (INode* pkNode, TimeValue iTime);

    // mesh processing
    TriObject* GetTriObject (INode* pkNode, bool* pbNeedDel);
    void SplitGeometry (Mesh* pkMaxMesh, int iMtlID,
        std::vector<WUnimaterialMesh*>& rkUMeshes);
    Wm4::Vector3f GetVertexNormal (Mesh* pkMaxMesh, int iFace, int iVertex);  
    void PackColors (WUnimaterialMesh* pkMesh, Mesh* pkMaxMesh,
        std::vector<int>& rkPartition);
    void PackTextures (WUnimaterialMesh* pkUniMesh, Mesh* pkMaxMesh,
        std::vector<int>& rkPartition);
    void PackVertices (WUnimaterialMesh* pkUniMesh, Mesh* pkMaxMesh,
        std::vector<int>& rkPartition, Wm4::Vector3f* akNormal);

    // material processing
    void ConvertMaterials (INode* pkTopNode);
    void CollectMaterials (INode* pkNode);
    void ConvertMaterial (Mtl& rkMtl, int iMtlID, int iSubNo,
        WMaterialTree& rkTree);
    void ConvertTexture (Texmap& rkTex, Class_ID kClassID, int iSubNo,
        WTextureTree& rkTree);

    WMaterials m_kMtlList;
    std::vector<WMaterialTree> m_kMtlTree;
    static const TCHAR* ms_aacMapName[NTEXMAPS];
    static const char* ms_aacEnvName[5];
    static const TCHAR* ms_acMapEnvironment;
    static const TCHAR* ms_acMapGeneric;

    // light processing
    void BuildAmbientLight ();
    void BuildLight (INode* pkMaxNode, Wm4::Spatial* pkWm4Node);
    Wm4::Vector3f GetLightLocation (INode* pkNode);
    Wm4::Light* BuildPointLight (INode* pkNode);
    Wm4::Light* BuildSpotLight (INode* pkNode, LightState& rkLightState);
    Wm4::Light* BuildDirectionalLight (INode* pkNode);

    // animation processing
    static bool AreEqual (const Point3& rkPoint1, const Point3& rkPoint2);
    static bool AreEqual (const Quat& rkQuat1, const Quat& rkQuat2);
    static bool CompareKeyTimes (KeyInfo* pkFirst, KeyInfo* pkSecond);
    void BuildKeyFrameController (INode* pkMaxNode, Wm4::Spatial* pkWm4Node);
    void BuildFrameController (INode* pkNode, Wm4::Spatial* pkWm4Node);
    bool GetAnimationTiming (INode* pkNode, AnimationTiming& rkTTiming, 
        AnimationTiming& rkRTiming, AnimationTiming& rkSTiming);
    void GetTrnKeyInfo (int &riNumKeys, Class_ID& rkClassID,
        IKeyControl* pkKeyCon, AnimationTiming& rkTTiming,
        std::vector<KeyInfo*>& rkKeyInfo);
    void GetRotKeyInfo (int& riNumKeys, Class_ID& rkClassID,
        IKeyControl* pkKeyCon, AnimationTiming& rkRTiming,
        std::vector<KeyInfo*>& rkKeyInfo);
    void GetScaleKeyInfo (int& riNumKeys, Class_ID& rkClassID,
        IKeyControl* pkKeyCon, AnimationTiming& rkSTiming,
        std::vector<KeyInfo*>& rkKeyInfo);

    // modifier processing
    void ApplyModifiers ();
    void FindModifiers (INode* pkNode, std::vector<Modifier*>& rkModifiers);
    void ProcessSkin (INode* pkNode, Modifier* pkSkinMod);
    void ProcessMorpher (INode* pkNode, Modifier* pkMorpherMod);

    TCHAR* m_acFilename;
    BOOL m_bExportSelected;
    WExportSettings* m_pkSettings;
    ExpInterface* m_pkExport;
    Interface* m_pkMax;
    INode* m_pkRootNode;
    int m_iTicksPerFrame;
    TimeValue m_iTimeStart;
    TimeValue m_iTimeEnd;
    TimeValue m_iTimeOffset;
    Wm4::NodePtr m_spkScene;
    std::vector<ModifierInfo*> m_kModList;

    static const float ATTENUATION;
    static const float MIN_DIFFERENCE;
};

#endif
