
#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_opencl0.h"


Cclprog volprg0;

cl_mem memobj_screen0 = NULL;
cl_mem memobj_volume0 = NULL;
cl_mem memobj_cam_pos0 = NULL;
cl_mem memobj_cam_dir0 = NULL;
cl_mem memobj_cam_up0 = NULL;
cl_mem memobj_cam_right0 = NULL;

unsigned int *bitmap0;

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

void opencl_example0_init(Cvolume *vol)
{
	volprg0.init("./data/cl/volume0.cl", "volume0");

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

	/* Create Memory Buffer */
	memobj_screen0 = clCreateBuffer(volprg0.context, CL_MEM_READ_WRITE, ScreenSize * sizeof(unsigned int), NULL, &volprg0.err);
	//memobj_screen0 = clCreateFromGLTexture2D(volprg0.context, CL_MEM_READ_WRITE, GL_TEXTURE_2D, 0, texture_id, &volprg0.err);

	memobj_volume0 = clCreateBuffer(volprg0.context, CL_MEM_READ_ONLY, vol_size * sizeof(unsigned char), NULL, &volprg0.err);

	memobj_cam_pos0 = clCreateBuffer(volprg0.context, CL_MEM_READ_WRITE, VECTOR_SIZE * sizeof(float), NULL, &volprg0.err);
	memobj_cam_dir0 = clCreateBuffer(volprg0.context, CL_MEM_READ_WRITE, VECTOR_SIZE * sizeof(float), NULL, &volprg0.err);
	memobj_cam_up0 = clCreateBuffer(volprg0.context, CL_MEM_READ_WRITE, VECTOR_SIZE * sizeof(float), NULL, &volprg0.err);
	memobj_cam_right0 = clCreateBuffer(volprg0.context, CL_MEM_READ_WRITE, VECTOR_SIZE * sizeof(float), NULL, &volprg0.err);

//	sampler = clCreateSampler(volprg0.context, CL_FALSE, CL_ADDRESS_CLAMP_TO_EDGE, CL_FILTER_NEAREST, &volprg0.err);
}

unsigned int* opencl_example0_run(Cvector cam_pos, Cvector cam_dir, Cvector cam_up, Cvector cam_right, int vol_width, int iso_depth, int ptime)
{
	/* Set OpenCL Kernel Arguments */
	clSetKernelArg(volprg0.kernel, 0, sizeof(cl_mem), (void *)&memobj_screen0);
	clSetKernelArg(volprg0.kernel, 1, sizeof(cl_mem), (void *)&memobj_volume0);

    clEnqueueWriteBuffer(volprg0.command_queue, memobj_cam_pos0, CL_TRUE, 0, VECTOR_SIZE * sizeof(float), &cam_pos, 0, NULL, NULL);
    clEnqueueWriteBuffer(volprg0.command_queue, memobj_cam_dir0, CL_TRUE, 0, VECTOR_SIZE * sizeof(float), &cam_dir, 0, NULL, NULL);
    clEnqueueWriteBuffer(volprg0.command_queue, memobj_cam_up0, CL_TRUE, 0, VECTOR_SIZE * sizeof(float), &cam_up, 0, NULL, NULL);
    clEnqueueWriteBuffer(volprg0.command_queue, memobj_cam_right0, CL_TRUE, 0, VECTOR_SIZE * sizeof(float), &cam_right, 0, NULL, NULL);

	clSetKernelArg(volprg0.kernel, 2, sizeof(cl_mem), (void *)&memobj_cam_pos0);
	clSetKernelArg(volprg0.kernel, 3, sizeof(cl_mem), (void *)&memobj_cam_dir0);
	clSetKernelArg(volprg0.kernel, 4, sizeof(cl_mem), (void *)&memobj_cam_up0);
	clSetKernelArg(volprg0.kernel, 5, sizeof(cl_mem), (void *)&memobj_cam_right0);

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

	clSetKernelArg(volprg0.kernel, 10, sizeof(int), (void *)&ptime);

	/* Execute OpenCL Kernel */

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

	/* Copy results from the memory buffer */
	clEnqueueReadBuffer(volprg0.command_queue, memobj_screen0, CL_TRUE, 0, ScreenSize * sizeof(unsigned int),bitmap0, 0, NULL, NULL);

	return (unsigned int*)bitmap0;
}

void opencl_example0_deinit()
{
	volprg0.deinit();

	clReleaseMemObject(memobj_screen0);
	clReleaseMemObject(memobj_volume0);
}
