#ifndef JESHADERinfo_H
#define JESHADERinfo_H

#include "BaseType.h"
#include "jeTypes.h"

#define JE_SHADER_NAME_LEN				128 // shader and map names can be up to 128 characters
#define JE_SHADER_TOKEN_LEN				(JE_SHADER_NAME_LEN+1)
#define JE_SHADER_NUMBER_LEN			11 
#define JE_SHADER_MAX_STAGES			8 // there can be up to 8 cloud layers
#define JE_SHADER_MAX_TCMODS			4 // this could change at anytime
#define JE_SHADER_MAX_VXMODS			4 // ditto
#define JE_SHADER_MAX_BONES				6

#define JE_SHADER_MAX_ANIMAP 30 //30 frames. 30 fps. get the idea?

// number stored with original string
typedef struct sh_num_s {
   float value;
   char  string[JE_SHADER_NUMBER_LEN+1];
} sh_num_t;

typedef struct sh_vxmod_s {
   int func;

   union {
      // deformVertexes wave
      struct {
         sh_num_t div;
         int      form;
         sh_num_t base;
         sh_num_t amp;
         sh_num_t phase;
         sh_num_t freq;
      } wave;

      // deformVertexes normal
      struct {
         sh_num_t amp;
         sh_num_t freq;
      } normal;

      // deformVertexes bulge
      struct {
         sh_num_t width, height;
         sh_num_t speed;
      } bulge;

      // deformVertexes move
      struct {
         sh_num_t x, y, z;
         int      form;
         sh_num_t base;
         sh_num_t amp;
         sh_num_t phase;
         sh_num_t freq;
      } move;
   } args;
} sh_vxmod_t;

typedef struct sh_tcgen_s {
   int func;

   union {
      // tcGen vector
      struct {
         sh_num_t sx, sy, sz;
         sh_num_t tx, ty, tz;
      } vector;

      // tcGen _sky
      struct {
         sh_num_t cloud_height;
      } sky;

   } args;
} sh_tcgen_t;

typedef struct sh_matrix3x2_s {
   sh_num_t m00, m01, t0;
   sh_num_t m10, m11, t1;
} sh_matrix3x2_t;

typedef struct sh_tcmod_s {
   int func;

   union {
      // tcMod rotate
      struct {
         sh_num_t speed;
      } rotate;

      // tcMod scale
      struct {
         sh_num_t s, t;
      } scale;

      // tcMod scroll
      struct {
         sh_num_t s, t;
      } scroll;
    
      // tcMod stretch
      struct {
         int      form;
         sh_num_t base;
         sh_num_t amp;
         sh_num_t phase;
         sh_num_t freq;
      } stretch;

      // tcMod transform
      sh_matrix3x2_t transform;

      // tcMod turb
      struct {
         sh_num_t base;
         sh_num_t amp;
         sh_num_t phase;
         sh_num_t freq;
      } turb;
    } args;
} sh_tcmod_t;

typedef struct sh_rgbagen_s {
   int func;

   union {
      // rgbGen wave, alphaGen wave
      struct {
         int      form;
         sh_num_t base;
         sh_num_t amp;
         sh_num_t phase;
         sh_num_t freq;
      } wave;

      // alphaGen portal
      struct {
         sh_num_t dist_to_opaque;
      } portal;

      // alphaGen _one_minus_portal
      struct {
         sh_num_t dist_to_clear;
      } one_minus_portal;

      // rgbGen const, alphaGen const
      struct {
         sh_num_t color[3];
      } constant;

   } args;
} sh_rgbagen_t;

//-------------------------------------------------------------
//-------------------------------------------------------------

// map, clampmap, animMap
typedef struct sh_map_s {
   char     name[JE_SHADER_NAME_LEN+1];
   unsigned flags;
} sh_map_t;

// stage
typedef struct sh_stage_s {
   // map, clampmap, animMap
   sh_map_t maps[JE_SHADER_MAX_ANIMAP];
   int      anim_map_count;
   sh_num_t anim_map_fps;

   // blendFunc
   int blend_src;
   int blend_dst;

   // alphaFunc
   int alphafunc;

   // depthFunc
   int depthfunc;

   // tcMod
   int        tcmod_count;
   sh_tcmod_t tcmods[JE_SHADER_MAX_TCMODS];

   // tcGen
   sh_tcgen_t tcgen;

   // rgbGen
   sh_rgbagen_t rgbgen;

   // alphaGen
   sh_rgbagen_t alphagen;

   // detail, depthWrite
   unsigned flags;

   // _filter
   int min_filter;
   int mag_filter;
} sh_stage_t;

// shader
typedef struct shader_s {
   char name[JE_SHADER_NAME_LEN+1];

   // nopicmip, nomipmaps, polygonOffset, entityMergable
   unsigned flags;

   // skyparms
   char     far_box_basename[JE_SHADER_NAME_LEN+1];
   sh_map_t far_box[6];

   sh_num_t cloud_height;

   char     near_box_basename[JE_SHADER_NAME_LEN+1];
   sh_map_t near_box[6];

   // cull
   int cull_face;

   // deformVertexes
   int        vxmod_count;
   sh_vxmod_t vxmods[JE_SHADER_MAX_VXMODS];

   // fogparms
   sh_num_t fog_color[3];
   sh_num_t fog_distance_to_opaque;

   // sort
   int sort_priority;

   // stages
   int        stage_count;
   sh_stage_t stages[JE_SHADER_MAX_STAGES];
} shader_t;

//-------------------------------------------------------------
//-------------------------------------------------------------
typedef struct shader_info_s	shader_info_t;
typedef struct Procedural Procedural;

typedef Procedural*	(*proceng_create)(jeBitmap **ppBitmap, shader_info_t *info);
typedef void		(*proceng_destroy)(Procedural * P);
typedef jeBoolean	(*proceng_animate)(Procedural * P, float ElapsedTime);

typedef enum
{
	JE_SHADER_TOKEN_EOF = 256,
	JE_SHADER_TOKEN_STRING,
} JE_SHADER_TOKEN;

typedef struct shader_token_s {
   char string[JE_SHADER_TOKEN_LEN+1];
   jeBoolean is_newline;
} shader_token_t;


typedef struct shader_particle_s
{
	int					particle_origin;
	int					particle_type;
} shader_particle_t;

typedef struct ProcVarTable	ProcVarTable;

typedef struct shader_proceng_s
{
	jeBoolean			hasProc;
	char				*proc_name;
	proceng_create		Create;
	proceng_destroy		Destroy;
	proceng_animate		Animate;
	uint32				type_flags;
	int					initialized;
	Procedural			*P;
	ProcVarTable		*userdata;
} shader_proceng_t;


typedef struct shader_vars_s
{
	char *				actor_var;
	char *				bone_var[JE_SHADER_MAX_BONES];
	char *				texture_maps[JE_SHADER_MAX_ANIMAP];
	int					used_bones;
	int					used_maps;
	uint32				shader_type_flags;
	shader_particle_t	particle_system;
	shader_proceng_t	proceng;

} shader_vars_t;

typedef struct shader_info_s
{
	FILE*				shader_file;
	sh_stage_t			ignored_stage;
	JE_SHADER_TOKEN		lookahead;
	shader_t*			shader;
	sh_stage_t			stage;
	jeBoolean			parse_stop;

	shader_token_t			token;
	int					jet_shader_line_count;
	int					brace_count;
	int					next_line_count;
	int					uninput_cin;
	jeBoolean			uninputted;

	shader_vars_t		shader_vars;

} shader_info_t;

typedef struct jeShader_
{
	shader_info_t		*userdata;
	char				tag[3];
	float				TimeAlpha;

} jeShader;

#endif