#include "pch.h"
#include "Embree.h"


	// {
	//
	// 	struct RTCRayHit rayhit;
	// 	glm::vec3 origin = glm::vec3(-10,0,0);
	// 	glm::vec3 dir = glm::vec3(1,0,0);
	// 	rayhit.ray.org_x = origin.x;
	// 	rayhit.ray.org_y = origin.y;
	// 	rayhit.ray.org_z = origin.z;
	// 	rayhit.ray.dir_x = dir.x;
	// 	rayhit.ray.dir_y = dir.y;
	// 	rayhit.ray.dir_z = dir.z;
	// 	rayhit.ray.tnear = 0;
	// 	rayhit.ray.tfar = std::numeric_limits<float>::infinity();
	// 	rayhit.ray.mask = -1;
	// 	rayhit.ray.flags = 0;
	// 	rayhit.hit.geomID = RTC_INVALID_GEOMETRY_ID;
	// 	rayhit.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
	//
	// 	/*
	// 	 * There are multiple variants of rtcIntersect. This one
	// 	 * intersects a single ray with the scene.
	// 	 */
	// 	rtcIntersect1(embree.scene, &rayhit);
	//
	// 	// printf("%f, %f, %f: ", ox, oy, oz);
	// 	if (rayhit.hit.geomID != RTC_INVALID_GEOMETRY_ID)
	// 	{
	// 		/* Note how geomID and primID identify the geometry we just hit.
	// 		 * We could use them here to interpolate geometry information,
	// 		 * compute shading, etc.
	// 		 * Since there is only a single triangle in this scene, we will
	// 		 * get geomID=0 / primID=0 for all hits.
	// 		 * There is also instID, used for instancing. See
	// 		 * the instancing tutorials for more information */
	// 		printf("Found intersection on geometry %d, primitive %d at tfar=%f\n",
	// 					 rayhit.hit.geomID,
	// 					 rayhit.hit.primID,
	// 					 rayhit.ray.tfar);
	// 	}
	// 	else
	// 		printf("Did not find any intersection.\n");
	//
	// }
// #include <embree4/rtcore_builder.h>
// #include <embree4/rtcore_buffer.h>
// #include <embree4/rtcore_common.h>

// #include <embree4/common/math/bbox.h>

// void errorFunction(void* userPtr, enum RTCError error, const char* str)
// {
// 	printf("error %d: %s\n", error, str);
// }
// /* This function is called by the builder to signal progress and to
//  * report memory consumption. */
// bool memoryMonitor(void* userPtr, ssize_t bytes, bool post) {
// 	return true;
// }
//
// bool buildProgress (void* userPtr, double f) {
// 	return true;
// }
//
// struct Node {
// 	virtual float sah() = 0;
// };
// //
// // struct InnerNode : public Node {
// // 	embree::BBox3fa bounds[2];
// // 	Node* children[2];
// //
// // 	InnerNode() {
// // 		bounds[0] = bounds[1] = embree::empty;
// // 		children[0] = children[1] = nullptr;
// // 	}
// //
// // 	float sah() {
// // 		return 1.0f + (embree::area(bounds[0])*children[0]->sah() + embree::area(bounds[1])*children[1]->sah())/embree::area(embree::merge(bounds[0],bounds[1]));
// // 	}
// //
// // 	static void* create (RTCThreadLocalAllocator alloc, unsigned int numChildren, void* userPtr)
// // 	{
// // 		assert(numChildren == 2);
// // 		void* ptr = rtcThreadLocalAlloc(alloc,sizeof(InnerNode),16);
// // 		return (void*) new (ptr) InnerNode;
// // 	}
// //
// // 	static void  setChildren (void* nodePtr, void** childPtr, unsigned int numChildren, void* userPtr)
// // 	{
// // 		assert(numChildren == 2);
// // 		for (size_t i=0; i<2; i++)
// // 			((InnerNode*)nodePtr)->children[i] = (Node*) childPtr[i];
// // 	}
// //
// // 	static void  setBounds (void* nodePtr, const RTCBounds** bounds, unsigned int numChildren, void* userPtr)
// // 	{
// // 		assert(numChildren == 2);
// // 		for (size_t i=0; i<2; i++)
// // 			((InnerNode*)nodePtr)->bounds[i] = *(const embree::BBox3fa*) bounds[i];
// // 	}
// // };
// //
// // struct LeafNode : public Node
// // {
// // 	unsigned id;
// // 	embree::BBox3fa bounds;
// //
// // 	LeafNode (unsigned id, const embree::BBox3fa& bounds)
// // 		: id(id), bounds(bounds) {}
// //
// // 	float sah() {
// // 		return 1.0f;
// // 	}
// //
// // 	static void* create (RTCThreadLocalAllocator alloc, const RTCBuildPrimitive* prims, size_t numPrims, void* userPtr)
// // 	{
// // 		assert(numPrims == 1);
// // 		void* ptr = rtcThreadLocalAlloc(alloc,sizeof(LeafNode),16);
// // 		return (void*) new (ptr) LeafNode(prims->primID,*(embree::BBox3fa*)prims);
// // 	}
// // };
// //
// // void splitPrimitive (const RTCBuildPrimitive* prim, unsigned int dim, float pos, RTCBounds* lprim, RTCBounds* rprim, void* userPtr)
// // {
// // 	assert(dim < 3);
// // 	assert(prim->geomID == 0);
// // 	*(embree::BBox3fa*) lprim = *(embree::BBox3fa*) prim;
// // 	*(embree::BBox3fa*) rprim = *(embree::BBox3fa*) prim;
// // 	(&lprim->upper_x)[dim] = pos;
// // 	(&rprim->lower_x)[dim] = pos;
// // }
//
// class Embree {
// public:
// 	RTCDevice device;
// 	RTCScene scene;
// 	std::vector<RTCGeometry> geoms;
//
// 	Embree () {
// 		device = rtcNewDevice(NULL);
// 		geoms.reserve(1000);
//
// 		if (!device) {
// 			printf("error %d: cannot create device\n", rtcGetDeviceError(NULL));
// 		}
//
// 		scene = rtcNewScene(device);
//
// 		rtcSetDeviceErrorFunction(device, errorFunction, NULL);
// 	}
// 	void build_bvh() {
// 		rtcSetDeviceMemoryMonitorFunction(this->device,memoryMonitor,nullptr);
//
// 		RTCBVH bvh = rtcNewBVH(this->device);
//
// 		// std::vector<RTCBuildPrimitive> prims_i;
// 		// std::vector<RTCBuildPrimitive> prims;
//
// 		RTCBuildArguments arguments = rtcDefaultBuildArguments();
// 		arguments.byteSize = sizeof(arguments);
// 		arguments.buildFlags = RTC_BUILD_FLAG_DYNAMIC;
// 		arguments.buildQuality = RTC_BUILD_QUALITY_LOW;
// 		arguments.maxBranchingFactor = 2;
// 		arguments.maxDepth = 1024;
// 		arguments.sahBlockSize = 1;
// 		arguments.minLeafSize = 1;
// 		arguments.maxLeafSize = 1;
// 		arguments.traversalCost = 1.0f;
// 		arguments.intersectionCost = 1.0f;
// 		arguments.bvh = bvh;
// 		// arguments.primitives = prims.data();
// 		// arguments.primitiveCount = prims.size();
// 		// arguments.primitiveArrayCapacity = prims.capacity();
// 		// arguments.createNode = InnerNode::create;
// 		// arguments.setNodeChildren = InnerNode::setChildren;
// 		// arguments.setNodeBounds = InnerNode::setBounds;
// 		// arguments.createLeaf = LeafNode::create;
// 		// arguments.splitPrimitive = splitPrimitive;
// 		// arguments.buildProgress = buildProgress;
// 		// arguments.userPtr = nullptr;
//
// 		/* we recreate the prims array here, as the builders modify this array */
// 		// for (size_t j=0; j<prims.size(); j++) prims[j] = prims_i[j];
//
// 		// std::cout << "iteration " << i << ": building BVH over " << prims.size() << " primitives, " << std::flush;
// 		// double t0 = getSeconds();
// 		Node* root = (Node*) rtcBuildBVH(&arguments);
// 		// rtcBuildBVH(&arguments);
// 		// double t1 = getSeconds();
// 		const float sah = root ? root->sah() : 0.0f;
// 		// std::cout << 1000.0f*(t1-t0) << "ms, " << 1E-6*double(prims.size())/(t1-t0) << " Mprims/s, sah = " << sah << " [DONE]" << std::endl;
//
// 		// rtcReleaseBVH(bvh);
//
// 	}
// 	void build_scene() {
// 		for(auto id_and_game_obj : WEngine->game_objects) {
// 			GameObject* game_obj = id_and_game_obj.second;
// 			if(game_obj->model_node) {
// 				ModelNode* model_node = game_obj->model_node;
// 				for(Mesh* mesh : model_node->meshes) {
// 					std::vector<int>& indicesList = mesh->indicesList;
// 					std::vector<float>& posList = mesh->posList;
//
// 					RTCGeometry geom = rtcNewGeometry(device, RTC_GEOMETRY_TYPE_TRIANGLE);
// 					geoms.push_back(geom);
//
// 					float* vertices = (float*) rtcSetNewGeometryBuffer(
// 						geom,
// 						RTC_BUFFER_TYPE_VERTEX,
// 						0,
// 						RTC_FORMAT_FLOAT3,
// 						3*sizeof(float),
// 						mesh->posList.size() / 4
// 					 );
//
// 					unsigned* indices = (unsigned*) rtcSetNewGeometryBuffer(
// 						geom,
// 						RTC_BUFFER_TYPE_INDEX,
// 						0,
// 						RTC_FORMAT_UINT3,
// 						3*sizeof(unsigned),
// 						mesh->indicesList.size() / 3
// 					);
//
// 					// int vert_idx = 0;
// 					// for(int i = 0; i < mesh->posList.size();){
// 					// 	vertices[vert_idx++] = mesh->posList[i++];
// 					// 	vertices[vert_idx++] = mesh->posList[i++];
// 					// 	vertices[vert_idx++] = mesh->posList[i++];
// 					// 	i++;
// 					// }
//
// 					// int vert_idx = 0;
//
// 					auto pos_list_ptr = &posList[0];
// 					auto pos_list_end = &posList[posList.size()-1];
// 					pos_list_end++;
// 					for(; pos_list_ptr != pos_list_end;){
// 						*vertices++ = *pos_list_ptr++;
// 						*vertices++ = *pos_list_ptr++;
// 						*vertices++ = *pos_list_ptr++;
// 						pos_list_ptr++;
// 					}
//
// 					int idx_idx = 0;
// 					for(int i = 0; i < mesh->indicesList.size();){
// 						indices[idx_idx++] = mesh->indicesList[i++];
// 					}
//
// 					/*
// 					 * You must commit geometry objects when you are done setting them up,
// 					 * or you will not get any intersections.
// 					 */
// 					rtcCommitGeometry(geom);
//
// 					/*
// 					 * In rtcAttachGeometry(...), the scene takes ownership of the geom
// 					 * by increasing its reference count. This means that we don't have
// 					 * to hold on to the geom handle, and may release it. The geom object
// 					 * will be released automatically when the scene is destroyed.
// 					 *
// 					 * rtcAttachGeometry() returns a geometry ID. We could use this to
// 					 * identify intersected objects later on.
// 					 */
// 					rtcAttachGeometry(scene, geom);
// 					rtcReleaseGeometry(geom);
//
// 					/*
// 					 * Like geometry objects, scenes must be committed. This lets
// 					 * Embree know that it may start building an acceleration structure.
// 					 */
// 					rtcCommitScene(scene);
// 				}
// 			}
// 		}
// 	}
//
// };
