
#ifndef __WFX_SCENE_STUDIOLOADER_H__
#define __WFX_SCENE_STUDIOLOADER_H__

#include <WFX/WFXIncludes.h>
#include <WFX/io/File.h>
#include <WFX/scene/GeometryLoader.h>
#include <WFX/scene/Node.h>
#include <WFX/scene/TriMesh.h>

namespace WFX {

    namespace scene {

        /** chunk description */
#pragma pack(2)
        class ChunkDesc {
            public:
                UShort short Flag;
                Long Size;
        };
#pragma pack()

        /** face description */
        class Face3DS {
            public:
                Short vert1, vert2, vert3;
                Short Flags;
        };

        /** Mesh Material Group */
        class MatGroup3DS {
            public:
                std::string MatName;
                Short VertexCount;
                Short* VertIndices;

        };

        /**
         * .3ds loader, inspired by wotsit.org and c3ds by Andrea Ingegneri
         */
        class StudioLoader : public GeometryLoader {
            public:
                /** chunk types */
                enum ChunkType {
                    CT_VERSION              = 0x0002,
                    CT_COLORFLOAT           = 0x0010,
                    CT_COLORBYTE            = 0x0011,
                    CT_LINCOLORBYTE         = 0x0012,
                    CT_PERCENTINT           = 0x0030,
                    CT_MASTERSCALE          = 0x0100,

                    CT_AMBIENTLIGHT         = 0x2100,
                    
                    CT_OBJMESH              = 0x3D3D,
                    CT_MESHVER              = 0x3D3E,

                    CT_NAMEDOBJECT          = 0x4000,
                    CT_TRIMESH              = 0x4100,
                    CT_POINTARRAY           = 0x4110,
                    CT_FACEARRAY            = 0x4120,
                    CT_MESHMATGRP           = 0x4130,
                    CT_TEXVERTS             = 0x4140,
                    CT_SMOOTHGROUP          = 0x4150,
                    CT_MESHMATRIX           = 0x4160,
                    CT_MAIN                 = 0x4D4D,

                    CT_MATENTRY             = 0xAFFF,
                    CT_MATNAME              = 0xA000,
                    CT_MATAMBIENT           = 0xA010,
                    CT_MATDIFFUSE           = 0xA020,
                    CT_MATSPECULAR          = 0xA030,
                    CT_MATSHININESS         = 0xA040,
                    CT_MATSHINSTR           = 0xA041,
                    CT_MATALPHA             = 0xA050,
                    CT_MATALPHAFALLOFF      = 0xA052,
                    CT_REFLECTBLUR          = 0xA053,
                    CT_MATSELFILPCT         = 0xA084,
                    CT_MATWIRESIZE          = 0xA087,
                    CT_MATALPHAFALLOFFIN    = 0xA08A,
                    CT_MATSHADING           = 0xA100, // [1=flat 2=gour. 3=phong 4=metal]
                    CT_MATTEXMAP            = 0xA200,
                    CT_MATMAPFILE           = 0xA300,
                    CT_MATMAPTILING         = 0xA351,
                    CT_MATMAPBLUR           = 0xA353,

                    CT_KFDATA               = 0xB000
                };

                /** Ctor */
                StudioLoader();
                virtual ~StudioLoader() {} 
                
                /**
                 * tries to parse the given X3D File and returns a
                 * Node*
                 */
                Node* loadFromFile(const WFX::io::File& f, bool r = false);

            protected:
            
            private:
                /** rotate verts? */
                bool Rotate;
                /** input stream */
                std::istream* Input;
                /** output node */
                Node* Output;
                /** current Mesh */
                TriMesh* CurrentMesh;
                /** current Material */
                Material* CurrentMaterial;
                /** MesMatGroups */
                std::vector<MatGroup3DS> MatGroups;
                /** Master Scale */
                Real MasterScale;

                /** current ChunkDesc */
                ChunkDesc CurrentChunk;

                /** checks version */
                void checkVersion();
                /** creates a new Mesh */
                void newMesh();
                /** creates a new Material */
                void newMaterial();
                /** finalizes a Mesh */
                void finalizeMesh();
                
                /** 
                 * parse a chunk - the "kernel" 
                 * calls itself recursively
                 */
                bool parseChunk();
                /** 
                 * skips current chunk 
                 */
                void skipChunk();
              
                /** reads a color */
                Color readColor();
                /** reads a percentage chunk */
                Real readPercent();
                /** reads a mesh material group */
                void readMatGroup();
                /** reads a point array*/
                void readPointArray();
                /** reads an uv array */
                void readUVArray();
                /** reads faces */
                void readFaces();
                /** read a Real */
                Real readReal();
                /** read a Short */
                Short readShort();
                /** read an UChar */
                UChar readUChar();
                /** read an Int */
                Int readInt();
                /** read a cstr */
                std::string readStr();
                /** 
                 * reads size bytes from Input and stores it at dest
                 */
                bool readBlock(Char* dest, Long size);

        };

    }

}


#endif //include guard


