
#ifndef __skelanim_h__
#define __skelanim_h__


#ifndef __skelmodel_h__
#include "skelmodel.h"
#endif

#ifndef PandaWave_XDYNARRAY
#include <XDynArray.h>
#endif


void defaultnew_skelanim( tag_entry *e );
void edit_skelanim( tag_entry *e );



#define MAX_SKAN_BONE_NAME MAX_SKMD_BONENAME
#define MAX_SKAN_ANIM_NAME 63
#define MAX_SKAN_STATE_NAME 63

//#define TIKI_BONE_QUAT_FRACTIONAL_BITS ( 15 )
#define TIKI_BONE_QUAT_MULTIPLIER ( 32767.0f )
#define TIKI_BONE_QUAT_MULTIPLIER_RECIPROCAL ( ( 1.0f ) / ( TIKI_BONE_QUAT_MULTIPLIER ) )

struct skan_bone_frame_pos {
	short shortOffset[3];
	short shortQuat[4];
};

extern byte_swap_code bs_skan_bone_frame_pos[];

enum {
	_skan_frame_action_first_bone_bit = 0,
	_skan_frame_action_bone_bit_count = 11,
	_skan_frame_action_keyframe_bit = _skan_frame_action_first_bone_bit+_skan_frame_action_bone_bit_count,
	_skan_frame_action_first_kind_bit,
	_skan_frame_action_kind_bit_count = 4,
	
	_skan_frame_action_kind_none = 0,
	_skan_frame_action_kind_sound,
	_skan_frame_action_kind_skmd,
	_skan_frame_action_kind_loli,
	_skan_frame_action_kind_lpgr,
	_skan_frame_action_kind_delete,
	_skan_frame_action_kind_project,
	_skan_frame_action_kind_footprint,
	_skan_frame_action_kind_giant_footprint,
	
	_skan_frame_action_bone_mask =
		((1 << (_skan_frame_action_first_bone_bit + _skan_frame_action_bone_bit_count)) -
		(1 << _skan_frame_action_first_bone_bit)),
	_skan_frame_action_keyframe_flag = FLAG(_skan_frame_action_keyframe_bit),
	_skan_frame_action_kind_mask =
		((1 << (_skan_frame_action_first_kind_bit + _skan_frame_action_kind_bit_count)) -
		(1 << _skan_frame_action_first_kind_bit))
};

struct skan_frame_v1 {
	float distance_delta;
	word frame_action;
	short action_tag_index;
	tag action_tag_id;
//	skan_bone_frame_pos bones[1 /* skan_tag_header.bone_bount */];
};

struct skan_frame {
	fixed fixed_distance_delta;
	word frame_action;
	short action_tag_index;
	tag action_tag_id;
//	skan_bone_frame_pos bones[1 /* skan_tag_header.bone_bount */];
};

extern byte_swap_code bs_skan_frame[];


enum {
	_skelanim_loopable_bit,
	_skelanim_distance_driven_bit,
	_skelanim_fast_interrupt_bit,
	_skelanim_turn_driven_bit,
	
	_skelanim_loopable_flag = FLAG(_skelanim_loopable_bit),
	_skelanim_distance_driven_flag = FLAG(_skelanim_distance_driven_bit),
	_skelanim_fast_interrupt_flag = FLAG(_skelanim_fast_interrupt_bit),
	_skelanim_turn_driven_flag = FLAG(_skelanim_turn_driven_bit)
};


struct skan_animation_v1 {
	char name[MAX_SKAN_ANIM_NAME+1];
	short keyframe;	// can be NONE
	unsigned short frame_count;
	short keybone;	// can be NONE
	unsigned short flags;
	float fps;
	float offset_scale;
	float crossfade_in_time;
	float crossfade_interrupted_time;
	float crossfade_finished_time;
};

struct skan_animation {
	char name[MAX_SKAN_ANIM_NAME+1];
	unsigned short frame_count;
	unsigned short flags;
	short_fixed fixed_fps;
	short offset_shift;
	float crossfade_in_time;
	float crossfade_interrupted_time;
	float crossfade_finished_time;
};

extern byte_swap_code bs_skan_animation[];


enum {
	_skelstate_pauses_at_end_bit,
	_skelstate_keeps_animation_when_cycling_bit,
	
	_skelstate_pauses_at_end_flag= FLAG(_skelstate_pauses_at_end_bit),
	_skelstate_keeps_animation_when_cycling_flag= FLAG(_skelstate_keeps_animation_when_cycling_bit)
};


struct skan_state {
	char name[MAX_SKAN_STATE_NAME+1];
	word anim_count;
	word flags;
	unsigned total_probability;
	word animations[1 /* state_count */][2];
};

extern byte_swap_code bs_skan_state[];


struct skan_bone_base {
	char name[MAX_SKAN_BONE_NAME+1];
	float offset[3];
	float quat[4];
	signed int parent;
};

extern byte_swap_code bs_skan_bone_base[];


struct skan_tag_header_v1 {
	unsigned bone_count;
	unsigned anim_count;
	unsigned state_count;
	skan_bone_base *baseframe;
	skan_animation_v1 **animations;
	skan_state **states;
};

struct skan_tag_header {
	unsigned bone_count;
	unsigned anim_count;
	unsigned state_count;
	skan_bone_base *baseframe;
	skan_animation **animations;
	skan_state **states;
};

extern byte_swap_code bs_skan_tag_header[];
void *setup_skan_ptrs( skan_tag_header *skan );

bool ExtractSKANNames( tag_entry *e, XGStringList *out );

class TTreeView;

class TskanEditForm: public TTagEditForm {
	public:
							TskanEditForm( struct tag_entry *e );
							~TskanEditForm();
				
		DECLAREDISPATCH
		virtual long		DoControlClick( long arg, void *ptr );
		virtual long		DoTreeClick( long arg, void *ptr );
		virtual long		DoKeyClick( long arg, void *ptr );
		virtual long		DoTreeCanDrop( long arg, void *ptr );
		virtual long		DoTreeDrop( long arg, void *ptr );
		virtual long		DoPopValue( long arg, void *ptr );
		
		virtual void		DoFormInitialize();
		
		virtual void		CommitToTag();
		virtual void		ReloadTag();
		virtual bool		NeedCommit();
		
	private:
		TTreeView	*stateView;
		TTreeView 	*animView;
		bool		fModified;
		
		void free_data();
		void reload_states();
		void reload_animations();
		
		struct statedata {
			skan_state header;
			XGSDynArray<int> probabilities;
			XGPDynArray<skan_animation> animations;
		};
		
		struct skanTreeData {
			statedata *state;
			skan_animation *anim;
		};
		
		
		struct OriginPickData {
			int bone_num;
			bool want_offset_settings;
			int offset_setting[4];
			bool loopable;
		};
		
		struct FrameAttachEdit {
			int kind;	// 0 == none, 1 == sound, 2 == attach, etc...
			int bone;
			bool keyframe;
			tag id;
		};
		
		struct AttachEdit {
			tag_file *source;
			XGSDynArray<skan_bone_base> *bones;
			int frame_count;
			FrameAttachEdit *frames;
		};
		
		
		XGFileSpecifier *GetSkl();
		static long BonePickProc( class XGDialog *dlog, void *data, long msg, long arg, void * /*parg*/ );
		int LoadAndPickOrigin( XGFileSpecifier *fs, OriginPickData *pd );
		void SetSelect( statedata *state, skan_animation *anim, bool force_update = false );
		statedata *NewState();
		void DeleteSelected();
		void RebuildBonePop();
		void EditAttachments( skan_animation *anim );
		static const char *FrameActionText( int frame, AttachEdit *ae );
		static void SetActionControls( XGDialog *d, FrameAttachEdit *f );
		static long AttachProc( XGDialog *dlog, void *data, long msg, long arg, void * /*parg*/ );
		
		
		
		XGSDynArray<skan_bone_base> basebones;
		XGPDynArray<statedata> states;
		XGPDynArray<skan_animation> animations;
		
		statedata *selectedState;
		skan_animation *selectedAnimation;
};

#endif

