/*===========================================================================
 *
 * File:	Dfrmb.H
 * Author:	Dave Humphrey (uesp@m0use.net)
 * Created On:	Friday, June 29, 2001
 *
 * Defines the CDFRmbFile and CDFRmbRecord used for loading records from
 * Daggerfall's BLOCKS.BSA file.
 *
 *=========================================================================*/
#ifndef __DFRMB_H
#define __DFRMB_H

/*===========================================================================
 *
 * Begin Required Include Files
 *
 *=========================================================================*/
  #include "uesp/dagger/df3dobj.h"
  #include "common/file/genfile.h"
  #include "uesp/dagger/df3dexpo.h"
/*===========================================================================
 *		End of Required Include Files
 *=========================================================================*/


/*===========================================================================
 *
 * Begin Definitions
 *
 *=========================================================================*/
 
	/* Number of records allowed in a RMB file */
  #define DFRMB_MAX_RECORDS 256

  	/* For loading RMB files via data found in MAPS.BSA */
  #define DFRMB_MAX_FILEINDEX  45
  #define DFRMB_MAX_FILENUMBER 57
  
	/* Options for exporting RMB records */
  #define DFRMB_FLAG_OUTSIDE   1
  #define DFRMB_FLAG_INSIDE    2
  #define DFRMB_FLAG_EXTRA     4
  #define DFRMB_FLAG_3DOBJECTS 8
  #define DFRMB_FLAG_FLATS     16
  #define DFRMB_FLAG_PEOPLE    32
  #define DFRMB_FLAG_DOORS     64
  #define DFRMB_FLAG_DEBUG     128
  #define DFRMB_FLAG_ISINSIDE  256 
  #define DFRMB_FLAG_DEFAULT   (1|2|8|16|32|64|128)

/*===========================================================================
 *		End of Definitions
 *=========================================================================*/


/*===========================================================================
 *
 * Begin Type and Structure Definitions
 *
 *=========================================================================*/
#pragma pack(push, 1)

	/* RMB Fixed Length Data Header record */
  typedef struct {
    long Width;
    long Height;
    long XPos;
    long ZPos;
    long YPos;
   } dfrmbfld_position_t;

	/* RMB Fixed Length Data Section1 record */
  typedef struct {
    byte Unknowns[26];
   } dfrmbfld_section1_t;

	/* RMB Fixed Length Data Section2 record */
  typedef struct {
    byte Unknowns[4];
   } dfrmbfld_section2_t;

	/* RMB Fixed Length Data Block sizes record */
  typedef struct {
    long RecordSize;
   } dfrmbfld_blocksize_t;

	/* Bit structure for the small map type in the FLD */
  typedef struct {
    byte ImageIndex	: 6;
    byte RotateImage	: 1;
    byte FlipImage	: 1;
   } dfrmbfld_textureinfo_t;

   	/* RMB Fixed Length Data Small Map record */
  typedef struct {
    byte Header[8];

    union {
      dfrmbfld_textureinfo_t Textures[256];
      dfrmbfld_textureinfo_t TexturesXY[16][16];
     };
    union {
      byte Data[256];
      byte DataXY[16][16];

     };
   } dfrmbfld_smallmap_t;

   	/* RMB Fixed Length Data AutoMap record */
  typedef struct {
    union {
      byte Map[4096];
      byte MapXY[64][64];
     };
   } dfrmbfld_automap_t;

	/* RMB Fixed Length Data Filename record */
  typedef struct {
    char Filename[13];
   } dfrmbfld_filename_t;

	/* Main RMB Fixed length data record */
  typedef struct {
    byte		 NumBlocks;
    byte		 Num3DObjects;
    byte		 NumFlatObjects;
    dfrmbfld_position_t  PositionRecords[32];
    dfrmbfld_section1_t  Section1Records[32];
    dfrmbfld_section2_t  Section2Records[32];
    dfrmbfld_blocksize_t BlockSizes[32];
    dfrmbfld_smallmap_t  SmallMap;
    dfrmbfld_automap_t   AutoMap;
    dfrmbfld_filename_t  FilenameRecords[33];
   } dfrmbfld_t;

	/* RMB Record Header */
  typedef struct {
    byte   Num3DObjectRecords;
    byte   NumFlatObjectRecords;
    byte   NumSection3Records;
    byte   NumPeopleRecords;
    byte   NumDoorRecords;
    ushort Unknowns[6];
   } dfrmb_header_t;

	/* RMB 3D Object Type Record */
  typedef struct {
    ushort ObjectID1;
    byte   ObjectID2;
    byte   Unknown1;
    long   Unknown2;
    long   Unknown3;
    long   Unknown4;
    long   NullValue1;
    long   NullValue2;
    long   XPos1;
    long   YPos1;
    long   ZPos1;
    long   XPos2;
    long   YPos2;
    long   ZPos2;
    long   NullValue3;
    short  Angle;
    short  Unknown5;
    long   NullValue4;
    long   Unknown6;
    short  NullValue5;

		/* Method to compute 3D object ID value */
    long Get3DObjectValue (void) const { return ((long)ObjectID1 * 100l + (long)ObjectID2); }

		/* Translation methods */
    float Get3DObjectX (void) const { return ((float)XPos2); }
    float Get3DObjectY (void) const { return ((float)YPos2); }
    float Get3DObjectZ (void) const { return ((float)ZPos2); }

		/* Object angle in radians about the vertical axis */
    float Get3DObjectAngle (void) const { return (float) ((float)Angle/1024.0*M_PI); }

   } dfrmb_3dobject_t;

	/* RMB Flat Object Type Record */
  typedef struct {
    long   XPos;
    long   ZPos;
    long   YPos;
    ushort SubImageIndex	: 7;
    ushort TextureIndex		: 9;
    ushort FlatType;
    byte   Unknown3;
   } dfrmb_flatobject_t;

	/* RMB Section3 Type Record */
  typedef struct {
    long   XPos;
    long   YPos;
    long   ZPos;
    byte   Unknown1;
    byte   Unknown2;
    ushort Unknown3;
   } dfrmb_section3_t;

	/* RMB People Type Record */
  typedef struct {
    long   XPos;
    long   YPos;
    long   ZPos;
    ushort SubImageIndex	: 7;
    ushort TextureIndex		: 9;
    ushort NPCType;
    byte   Unknown3;
   } dfrmb_people_t;

	/* RMB Door Type Record */
  typedef struct {
    long   XPos;
    long   YPos;
    long   ZPos;
    ushort Unknown1;
    ushort Unknown2;
    ushort Unknown3;
    byte   Unknown4;
   } dfrmb_door_t;

#pragma pack(pop)
/*===========================================================================
 *		End of Structure and Type Definitions
 *=========================================================================*/


/*===========================================================================
 *
 * Class CDFRmbRecord Definition
 *
 * Defines one variable sized record in a RMB file.
 *
 *=========================================================================*/
class CDFRmbRecord : public CGenFile { 

  /*---------- Begin Protected Class Members --------------------*/
protected:
  dfrmb_header_t      m_Header;			/* Header data for variable length records */
  dfrmb_3dobject_t*   m_p3DObjectRecords;	/* Array of 3d Objects */
  dfrmb_flatobject_t* m_pFlatObjectRecords;	/* Array of flat objects */
  dfrmb_section3_t*   m_pSection3Records;	/* Array of unknown records */
  dfrmb_people_t*     m_pPeopleRecords;		/* Array of NPC objects */
  dfrmb_door_t*       m_pDoorRecords;		/* Array of door objects */

  boolean	      m_HasExtraByte;		/* Extra 1 byte at end of data */
  byte		      m_ExtraByte;


  /*---------- Begin Protected Class Members --------------------*/
protected:

	/* Helper export methods */
  boolean Export3DS_3DObjects (C3dsFile& File3DS, const char* pNameHeader, const df3dpoint_t* pTransPoint = NULL);

	/* Input helper methods */
  boolean ReadHeader      (void);
  boolean Read3DObjects   (void);
  boolean ReadFlatObjects (void);
  boolean ReadSection3    (void);
  boolean ReadPeople      (void);
  boolean ReadDoors       (void);


  /*---------- Begin Public Class Methods -----------------------*/
public:

	/* Class Constructor/Destructor */
  CDFRmbRecord();
  virtual ~CDFRmbRecord() { Destroy(); }
  virtual void Destroy (void);

	/* Export record to a 3DS/DXF file */
  boolean Export3DS (C3dsFile& File3DS, const int Flags = DFRMB_FLAG_DEFAULT,
		     const df3dpoint_t* pTransPoint = NULL);

	/* Read in the record data from the current position in the file stream */
  boolean ReadRecord (void);

	/* Set class members */
  void SetExtraByte (const byte Byte);

 };
/*===========================================================================
 *		End of Class CDFRmbRecord Definition
 *=========================================================================*/


/*===========================================================================
 *
 * Class CDFRmbFile Definition
 *
 * Handles manipulation of RMB files contained within Daggerfall's BLOCKS.BSA
 * file.  RMB files contain 3D object object information.
 *
 *=========================================================================*/
class CDFRmbFile : public CGenFile { 

  /*---------- Begin Protected Class Members --------------------*/
protected:
  dfrmbfld_t		m_FLDData;		/* The Fixed Length Data */
  long			m_RecordOffset;		/* Offset of record in file */
  long			m_RecordSize;		/* Size of record in file */

  CDFRmbRecord*		m_pOutsideRecords;	/* Array of output records */
  CDFRmbRecord*		m_pInsideRecords;	/* Array of inside records */

  dfrmb_3dobject_t*	m_p3DObjects;		/* Array of 3D Objects */	
  dfrmb_flatobject_t*	m_pFlatObjects;		/* Array of flat objects */
  

  /*---------- Begin Protected Class Members --------------------*/
protected:

	/* Input helper functions */
  boolean ReadFLD         (void);
  boolean ReadBlocks      (void);
  boolean Read3DObjects   (void);
  boolean ReadFlatObjects (void); 


  /*---------- Begin Public Class Methods -----------------------*/
public:

	/* Class Constructor/Destructors */
  CDFRmbFile();
  virtual ~CDFRmbFile() { Destroy(); }
  virtual void Destroy (void);

	/* Export file to a 3DS/DXF file */
  boolean Export3DS (C3dsFile& File3DS, const int Flags = DFRMB_FLAG_DEFAULT);

	/* Attempt to read in the file from the current position in the file stream */
  boolean ReadRMB (const long RecordSize);

	/* Set class members */
  void SetRecordOffset (const long Offset);
  void SetRecordSize   (const long Size);

 };
/*===========================================================================
 *		End of Class CDFRMBFile Definition
 *=========================================================================*/


/*===========================================================================
 *
 * Begin CDFRmbRecord Inline Methods
 *
 *=========================================================================*/

	/* Set class members */
inline void CDFRmbRecord::SetExtraByte (const byte Byte) { 
  m_HasExtraByte = TRUE; 
  m_ExtraByte = Byte; 
 }

/*===========================================================================
 *		End of CDFRmbRecord Inline Methods
 *=========================================================================*/


/*===========================================================================
 *
 * Begin CDFRmbFile Inline Methods
 *
 *=========================================================================*/

	/* Set class members */
inline void CDFRmbFile::SetRecordOffset (const long Offset) { m_RecordOffset = Offset; }
inline void CDFRmbFile::SetRecordSize   (const long Size)   { m_RecordSize   = Size; }

/*===========================================================================
 *		End of CDFRmbFile Inline Methods
 *=========================================================================*/


/*===========================================================================
 *
 * Begin Function Prototypes
 *
 *=========================================================================*/

	/* Convert a 4-byte RMB filename based on the index */
  boolean GetDFRmbFilename (char* pString, const int Index);

  	/* Convert an RMB character index to a 2-byte string */
  boolean GetDFRmbFileChar (char* pString, const int CharIndex);

/*===========================================================================
 *		End of Function Prototypes
 *=========================================================================*/


#endif
/*===========================================================================
 *		End of File Dfrmb.H
 *=========================================================================*/