#include <math.h>
#include "project_volumes.h"
#include "fx_colors.h"

#define blob_max_col 16383
#define blob_color_shift 6

#define num_blobs 128

unsigned short *bbuffer;
unsigned short *bimg;

int fxb_vsize, fxb_vvsize, fxb_vvvsize;
int fxb_bsize, fxb_bbsize, fxb_bbbsize;

unsigned int fxb_argb[256];

bool FxBlobsInit = false;

void InitFxBlobsColors()
{
    SetPalette(fxb_argb, GetColor(0,127,0,0), GetColor(255,255,255,255), 0, 255);
}

void SetFxBlobsColors(unsigned int *dest)
{
	for (int i=0; i<256; i++)
	{
		dest[i] = fxb_argb[i];
	}
}

void InitFxBlobs(Cvolume *vol)
{
	fxb_vsize = vol->GetWidth();
	fxb_vvsize = fxb_vsize * fxb_vsize;
	fxb_vvvsize = fxb_vvsize * fxb_vsize;

	fxb_bsize = fxb_vsize >> 2;
	fxb_bbsize = fxb_bsize * fxb_bsize;
	fxb_bbbsize = fxb_bbsize * fxb_bsize;

	bbuffer = new unsigned short[fxb_vvvsize];
	bimg = new unsigned short[fxb_bbbsize];


	int i = 0;
    for (int z=0; z<fxb_bsize; z++)
    {
        for (int y=0; y<fxb_bsize; y++)
        {
            for (int x=0; x<fxb_bsize; x++)
            {
                float dist = sqrt((float)((x-fxb_bsize/2)*(x-fxb_bsize/2) + (y-fxb_bsize/2)*(y-fxb_bsize/2) + (z-fxb_bsize/2)*(z-fxb_bsize/2)));

                unsigned short c = blob_max_col;
                if (dist!=0)
                    c = (unsigned short)(32768.0f / dist);
                if (c > blob_max_col) c = blob_max_col;
                if (c < (64 << blob_color_shift)) c = 0;

                bimg[i++] = c;
            }
        }
    }

	InitFxBlobsColors();

	FxBlobsInit = true;
}

void FxWriteBlob(int vx, int vy, int vz)
{
    int v0x = vx - fxb_bsize / 2;
    int v1x = vx + fxb_bsize / 2;
    int v0y = vy - fxb_bsize / 2;
    int v1y = vy + fxb_bsize / 2;
    int v0z = vz - fxb_bsize / 2;
    int v1z = vz + fxb_bsize / 2;

    if (v0x < 0) v0x = 0; if (v0x > fxb_vsize-1) v0x = fxb_vsize - 1;
    if (v1x < 0) v1x = 0; if (v1x > fxb_vsize-1) v1x = fxb_vsize - 1;
    if (v0y < 0) v0y = 0; if (v0y > fxb_vsize-1) v0y = fxb_vsize - 1;
    if (v1y < 0) v1y = 0; if (v1y > fxb_vsize-1) v1y = fxb_vsize - 1;
    if (v0z < 0) v0z = 0; if (v0z > fxb_vsize-1) v0z = fxb_vsize - 1;
    if (v1z < 0) v1z = 0; if (v1z > fxb_vsize-1) v1z = fxb_vsize - 1;

    int i = 0;
    for (int z = v0z; z < v1z; z++)
    {
        for (int y = v0y; y < v1y; y++)
        {
            for (int x = v0x; x < v1x; x++)
            {
                int bi = z * fxb_vvsize + y * fxb_vsize + x;
                unsigned short c = bbuffer[bi] + bimg[i++];
                if (c > blob_max_col) c = blob_max_col;
                bbuffer[bi] = c;
            }
        }
    }
}

void FxClearBlobBuffer()
{
    for (int i=0; i<fxb_vvvsize; i++)
        bbuffer[i] = 0;
}

void FxScriptBlobs(int ticks)
{
	int t = ticks >> 2;

    int cx = fxb_vsize / 2;
    int cy = fxb_vsize / 2;
    int cz = fxb_vsize / 2;

    for (int i=0; i<num_blobs; i++)
    {
        int vx = (int)(cx + sin((500 * i * i + t) / 314.0f) * (fxb_vsize / 3));
        int vy = (int)(cy + sin((300 * i * i * i + t) / 257.0f) * (fxb_vsize / 3));
        int vz = (int)(cz + sin((250 * i * i * i * i + t) / 400.0f) * (fxb_vsize / 3));
        FxWriteBlob(vx, vy, vz);
    }
}

void FxRenderBlobBuffer(Cvolume *vol)
{
	unsigned char *voxels = vol->GetDataPointer();

    for (int i=0; i<fxb_vvvsize; i++)
    {
        voxels[i] = bbuffer[i] >> blob_color_shift;
    }
}

void FxRunBlobs(Cvolume *vol, int ticks)
{
	if (!FxBlobsInit) InitFxBlobs(vol);

    FxClearBlobBuffer();
    FxScriptBlobs(ticks);
	FxRenderBlobBuffer(vol);
}
