#ifndef VOXEL_IFACE_H
#define VOXEL_IFACE_H

#include <string>
#include <vector>
#include <set>
#include <map>
#include <stdio.h>
#include <stdlib.h>
#include <cmath>

#define XSIZE		640
#define YSIZE		320
#define PANEL_H		160
#define DELAY		(1./30)
#define WIND_N		256

#define FIELD_N		128
#define FIELD_H		64

#define EPS			0.0001f

typedef unsigned char uchar;

namespace voxel
{
	struct T
	{
		float x, y, z;
		T( float _x=0, float _y=0, float _z=0 ):x(_x),y(_y),z(_z){}
		float get_w()
		{
			return sqrt(x*x+y*y+z*z);
		}
		void normalize()
		{
			float d = 1.f/get_w();
			x *= d;
			y *= d;
			z *= d;
		}
	};

	class ZGen
	{
		void gen1(uchar * h, uchar * clr, uchar * top, uchar * pal);
		void gen2(uchar * h, uchar * clr, uchar * top, uchar * pal);
		void gen3(uchar * h, uchar * clr, uchar * top, uchar * pal);
	public:
		void gen(uchar * h, uchar * clr, uchar * top, uchar * pal, int type);
	};

	struct ZPlayer
	{
		int pos_x, pos_y;
		int money;
		int hp;
		uchar r, g, b;

		int alpha, beta, power, X, Y;
		int weapon;

		ZPlayer(int _px=0, int _py=0, uchar _r=0, uchar _g=0, uchar _b=0);
		void do_ai( T your_pos, T enemy, T wind );
	};

	struct ZBall
	{
		T c;
		float r;
		int life_time;
		int cur_time;
		int speed; // speed if life

		ZBall( T _c=0, float _r=0, int _life_time=0, int _speed=0 )
		{
			c = _c;
			r = _r;
			life_time = _life_time;
			cur_time = 0;
			speed = _speed;
		}

		void get_color( uchar & r, uchar & g, uchar & b )
		{
			r = 128; g = 128; b = 128;
			if (cur_time < 256)
			{
				r = 255; g = 255; b = 255;
			}
			else if (256 <= cur_time && cur_time < 512)
			{
				r = 255;
				g = 255;
				b = 255 - (cur_time-256);
			}
			else if (cur_time < 512+256)
			{
				r = 255;
				g = 255 - (cur_time-512);
				b = 0;
			}
			else if (cur_time < 1024)
			{
				r = 255 - ((cur_time-512-256)>>1);
				g = ((cur_time-512-256)>>1);
				b = ((cur_time-512-256)>>1);
			}
		}
	};

	struct ZBullet
	{
		T pos;
		T v;
		int type;
		bool dead;
	};

	class ZGame
	{
		uchar pixbuf[YSIZE][XSIZE][3];
		float zbuf[YSIZE][XSIZE];
		uchar h[FIELD_N][FIELD_N];
		uchar pal[256][3];
		uchar clr[FIELD_N][FIELD_N][FIELD_H];
		uchar top[FIELD_N][FIELD_N];

		int X[FIELD_N*2+10], Y[FIELD_N*2+10];
		T cam, dir;

		T bb, cc;

		T wind[WIND_N];
		float wx, wy;

		std::vector< ZBall > balls;
		std::vector< ZBullet > bullets;

		int frame;

		void clear();
		void pset( int x, int y, float z, uchar r, uchar g, uchar b );
		float fast_rsqrt( float number );
		T p_to_scr( T p );
		void draw_ball( T ce, float R, uchar r, uchar g, uchar b );
		void draw_line( T A, T B, uchar r, uchar g, uchar b );

		void do_damage( T c, float r, int damage );
		void erase_ball( int x, int y, int z, int r );
	public:
		ZPlayer pp[2];
		bool locked;
		int cur_pl;

		ZGame();

		void gen( ZGen * g, int type );

		void do_move( int i );
		void do_anim();

		void set_cam( int alpha, int beta );
		void render();
		uchar * get_pixbuf();
	};
};

#endif