
#include <stdio.h>
#include <stdlib.h>

#include <CL/cl.h>
#include <CL/cl_gl.h>

#include "project_screen.h"
#include "project_volumes.h"
#include "project_opencl.h"
#include "math_vector3D.h"
#include "part_opencl1.h"

#include "fx_plasma.h"


Cclprog volprg1;

cl_mem memobj_screen1 = NULL;

cl_mem memobj_volume1 = NULL;


cl_mem memobj_colors1 = NULL;
cl_mem memobj_cam_pos1 = NULL;
cl_mem memobj_cam_dir1 = NULL;
cl_mem memobj_cam_up1 = NULL;
cl_mem memobj_cam_right1 = NULL;

unsigned int *bitmap1;

void opencl_example1_load_volume(Cvolume *vol)
{
//	int vol_size = vol->GetWidth() * vol->GetHeight() * vol->GetDepth();
//	unsigned char *volume = vol->GetDataPointer();
//    clEnqueueWriteBuffer(volprg1.command_queue, memobj_volume1, CL_TRUE, 0, vol_size * sizeof(unsigned char), volume, 0, NULL, NULL);
}

void opencl_example1_load_colors(unsigned int *cols)
{
    clEnqueueWriteBuffer(volprg1.command_queue, memobj_colors1, CL_TRUE, 0, 256 * sizeof(unsigned int), cols, 0, NULL, NULL);
}

void opencl_example1_init(Cvolume *vol)
{
	opencl_fx_plasma_init(vol);

	volprg1.init("./data/cl/volume1.cl", "volume1");

	bitmap1 = (unsigned int*)malloc(ScreenSize * sizeof(unsigned int));
	int vol_size = vol->GetWidth() * vol->GetHeight() * vol->GetDepth();

	/* Create Memory Buffer */
	memobj_screen1 = clCreateBuffer(volprg1.context, CL_MEM_READ_WRITE, ScreenSize * sizeof(unsigned int), NULL, &volprg1.err);

	memobj_volume1 = clCreateBuffer(volprg1.context, CL_MEM_READ_ONLY, vol_size * sizeof(unsigned char), NULL, &volprg1.err);
	memobj_colors1 = clCreateBuffer(volprg1.context, CL_MEM_READ_ONLY, 256 * sizeof(unsigned int), NULL, &volprg1.err);

	memobj_cam_pos1 = clCreateBuffer(volprg1.context, CL_MEM_READ_WRITE, VECTOR_SIZE * sizeof(float), NULL, &volprg1.err);
	memobj_cam_dir1 = clCreateBuffer(volprg1.context, CL_MEM_READ_WRITE, VECTOR_SIZE * sizeof(float), NULL, &volprg1.err);
	memobj_cam_up1 = clCreateBuffer(volprg1.context, CL_MEM_READ_WRITE, VECTOR_SIZE * sizeof(float), NULL, &volprg1.err);
	memobj_cam_right1 = clCreateBuffer(volprg1.context, CL_MEM_READ_WRITE, VECTOR_SIZE * sizeof(float), NULL, &volprg1.err);
}

unsigned int* opencl_example1_run(Cvector cam_pos, Cvector cam_dir, Cvector cam_up, Cvector cam_right, int vol_width, int iso_depth, int ptime)
{
//	unsigned char *vdata_fx = opencl_fx_plasma_run(vol_width, ptime);
	memobj_volume1 = opencl_fx_plasma_run(vol_width, ptime);

//	int vol_size = vol_width * vol_width * vol_width;
//	clEnqueueWriteBuffer(volprg1.command_queue, memobj_volume1, CL_TRUE, 0, vol_size * sizeof(unsigned char), vdata_fx, 0, NULL, NULL);

	/* Set OpenCL Kernel Arguments */
	clSetKernelArg(volprg1.kernel, 0, sizeof(cl_mem), (void *)&memobj_screen1);
	clSetKernelArg(volprg1.kernel, 1, sizeof(cl_mem), (void *)&memobj_volume1);
	clSetKernelArg(volprg1.kernel, 2, sizeof(cl_mem), (void *)&memobj_colors1);

    clEnqueueWriteBuffer(volprg1.command_queue, memobj_cam_pos1, CL_TRUE, 0, VECTOR_SIZE * sizeof(float), &cam_pos, 0, NULL, NULL);
    clEnqueueWriteBuffer(volprg1.command_queue, memobj_cam_dir1, CL_TRUE, 0, VECTOR_SIZE * sizeof(float), &cam_dir, 0, NULL, NULL);
    clEnqueueWriteBuffer(volprg1.command_queue, memobj_cam_up1, CL_TRUE, 0, VECTOR_SIZE * sizeof(float), &cam_up, 0, NULL, NULL);
    clEnqueueWriteBuffer(volprg1.command_queue, memobj_cam_right1, CL_TRUE, 0, VECTOR_SIZE * sizeof(float), &cam_right, 0, NULL, NULL);

	clSetKernelArg(volprg1.kernel, 3, sizeof(cl_mem), (void *)&memobj_cam_pos1);
	clSetKernelArg(volprg1.kernel, 4, sizeof(cl_mem), (void *)&memobj_cam_dir1);
	clSetKernelArg(volprg1.kernel, 5, sizeof(cl_mem), (void *)&memobj_cam_up1);
	clSetKernelArg(volprg1.kernel, 6, sizeof(cl_mem), (void *)&memobj_cam_right1);

	clSetKernelArg(volprg1.kernel, 7, sizeof(int), (void *)&ScreenWidth);
	clSetKernelArg(volprg1.kernel, 8, sizeof(int), (void *)&ScreenHeight);
	clSetKernelArg(volprg1.kernel, 9, sizeof(int), (void *)&vol_width);
	clSetKernelArg(volprg1.kernel, 10, sizeof(int), (void *)&iso_depth);

	clSetKernelArg(volprg1.kernel, 11, sizeof(int), (void *)&ptime);

	/* Execute OpenCL Kernel */

	size_t global_work_size[] = {ScreenWidth, ScreenHeight, 0};
	size_t local_work_size[] = {16, 8, 0};
	clEnqueueNDRangeKernel(volprg1.command_queue, volprg1.kernel, 2, NULL, global_work_size, local_work_size, 0, NULL, NULL);

	/* Copy results from the memory buffer */
	clEnqueueReadBuffer(volprg1.command_queue, memobj_screen1, CL_TRUE, 0, ScreenSize * sizeof(unsigned int),bitmap1, 0, NULL, NULL);

	return (unsigned int*)bitmap1;
}

void opencl_example1_deinit()
{
	opencl_fx_plasma_deinit();

	volprg1.deinit();

	clReleaseMemObject(memobj_screen1);
	clReleaseMemObject(memobj_volume1);
	clReleaseMemObject(memobj_colors1);
}
