/*
* Copyright 2023, Ali Arya
* Anyone Can Code: Algorithmic Thinking
* Example 6.9c
*/

#include "Main.h"

#define SCREEN_W 640
#define SCREEN_H 480

class GameObject
{
	int x;
	int y;
	SDLX_Bitmap* shape;
	int visible;
	int vy;
	int vx;
public:
	GameObject()
	{
		shape = NULL;
		x = y = vx = vy = 0;
		visible = 100;
	}
	void Init(int xx, int yy)
	{
		x = xx;
		y = yy;
		visible = 100;
	}
	void Init(SDLX_Bitmap* bmp, int xx, int yy, int v = 100)
	{
		shape = bmp;
		x = xx;
		y = yy;
		if (v >= 0 && v <= 100)
			visible = v;
	}
	void Init(char* fname, int xx, int yy, int v=100)
	{
		shape = SDLX_LoadBitmap(fname);
		x = xx;
		y = yy;
		if (v >= 0 && v <= 100)
			visible = v;
	}
	void Move(bool random=false)
	{
		if (random)
		{
			x += rand() % 5 - 2;
			y += rand() % 5 - 2;
		}
		else
		{
			x += vx;
			y += vy;
		}
	}
	void Move(int dx, int dy)
	{
		x += dx;
		y += dy;
	}
	void Draw()
	{
		SDLX_DrawBitmap(shape, x, y, visible);
	}
	int GetVisible()
	{
		return visible;
	}
	void SetVisible(int v)
	{
		if (v >= 0 && v <= 100)
			visible = v;
	}
	int GetX()
	{
		return x;
	}
	int GetY()
	{
		return y;
	}
	SDLX_Bitmap* GetShape()
	{
		return shape;
	}
};

class Filter
{
public:
	void Gray(GameObject* obj)
	{
		//image to apply filter
		SDLX_Bitmap* img = obj->GetShape();

		//image dimensions
		int w = img->width;
		int h = img->height;

		//color
		SDLX_Color c;

		//loop
		for (int i = 0; i < w; i++)
			for (int j = 0; j < h; j++)
			{
				SDLX_GetPixel(img, i, j, &c);
				int g = (c.b + c.g + c.r) / 3; //a simplified algorithm for changing to gray scale
				c.r = c.g = c.b = g;
				SDLX_PutPixel(img, i, j, &c);
			}
	}
	void Blur(GameObject* obj)
	{
		//image to apply filter
		SDLX_Bitmap* img = obj->GetShape();

		//image dimensions
		int w = img->width;
		int h = img->height;

		//color
		SDLX_Color c;
		SDLX_Color cr;
		SDLX_Color cl;

		//loop
		//this code only considers the neighbouring pixels on the left and right
		for (int i = 1; i < w-1; i++) //the pixels at the edge don't have two neighbours
			for (int j = 0; j < h; j++)
			{
				SDLX_GetPixel(img, i, j, &c);
				//the following if statements are to make sure we don't conisder masked(transparent) pixles
				if ((c.r != color_mask.r || c.g != color_mask.g || c.b != color_mask.b) && c.a != 0)
				{
					int n = 1;
					SDLX_GetPixel(img, i + 1, j, &cr);
					if ((cr.r != color_mask.r || cr.g != color_mask.g || cr.b != color_mask.b) && cr.a != 0)
					{
						n++;
						c.r += cr.r;
						c.g += cr.g;
						c.b += cr.b;
						SDLX_GetPixel(img, i - 1, j, &cl);
						if ((cl.r != color_mask.r || cl.g != color_mask.g || cl.b != color_mask.b) && cl.a != 0)
						{
							n++;
							c.r += cl.r;
							c.g += cl.g;
							c.b += cl.b;
						}
					}
					c.r /= n;
					c.g /= n;
					c.b /= n;
					SDLX_PutPixel(img, i, j, &c);
				}
			}
	}
	void BrightUp(GameObject* obj)
	{
		//change RGB levels. Make sure we don't exceed 0-255 range
	}
	void BrightDown(GameObject* obj)
	{
		//change RGB levels. Make sure we don't exceed 0-255 range
	}
};
class Game
{
	SDLX_Bitmap* map;
	GameObject player;
	Filter filter;
	bool quit;
	bool left;
	bool right;
	bool up;
	bool down;
public:
	Game()	//same as Init()
	{
		//init SDL library and graphics window
		SDLX_Init("Simple 2D Game", 640, 480, true);

		//background
		map = SDLX_LoadBitmap("map.bmp");

		//player
		player.Init((char*)"Player.bmp", 320, 240);

		//control variables
		quit = false;
		down = up = right = left = false;
	}
	void Update()
	{
		SDLX_Event e;
		if (SDLX_PollEvent(&e))
		{
			if (e.type == SDL_KEYDOWN)
			{
				if (e.keycode == SDLK_ESCAPE)
					quit = true;
				//apply filter
				if (e.keycode == SDLK_1)
					filter.Gray(&player);
				if (e.keycode == SDLK_2)
					filter.Blur(&player);
				//update player position
				if (e.keycode == SDLK_RIGHT)
					right = true;
				if (e.keycode == SDLK_LEFT)
					left = true;
				if (e.keycode == SDLK_UP)
					up = true;
				if (e.keycode == SDLK_DOWN)
					down = true;
			}
			if (e.type == SDL_KEYUP)
			{
				if (e.keycode == SDLK_RIGHT)
					right = false;
				if (e.keycode == SDLK_LEFT)
					left = false;
				if (e.keycode == SDLK_UP)
					up = false;
				if (e.keycode == SDLK_DOWN)
					down = false;
			}
		}

		//update particle system
		int dx = 0;
		if (right)
			dx += 3;
		if (left)
			dx -= 3;
		int dy = 0;
		if (up)
			dy -= 3;
		if (down)
			dy += 3;
		player.Move(dx, dy);
	}
	void Draw()
	{
		SDLX_DrawBitmap(map,0,0);
		player.Draw();
		SDLX_Render();
	}
	void Run()
	{
		while (!quit)
		{
			Update();
			Draw();
			SDLX_Delay(1);
		}
	}
};

int main(int argc, char* argv[])
{
	Game game;
	game.Run();
	return 0;
}