/* scene.h */

#pragma once

#include "geo.h"
#include "illum.h"

/* Object entries */

enum object_types {
	OBJ_TYPE_PLANE,
	OBJ_TYPE_TRIANGLE,
	OBJ_TYPE_QUAD,
	OBJ_TYPE_MODEL,
	OBJ_TYPE_BOX,
	OBJ_TYPE_SPHERE,
	/*OBJ_TYPE_M_TRANSFORM,*/
	OBJ_TYPE_CSG
};

enum object_csg_operations {
	OBJ_CSG_UNION,
	OBJ_CSG_SUBTRACT,
	OBJ_CSG_INTERSECTION
};

#define OBJ_HIT_FIRST  (0x0)
#define OBJ_HIT_SECOND (0x1)
#define OBJ_HIT_NEAR   (0x2)
#define OBJ_HIT_FAR    (0x4)

typedef struct {
	int        object_type;
	void*      data;
	material_t mat;
} object_entry;

typedef struct {
	object_entry* obj;
	tuple         p;
	tuple         norm;
} object_intersection;

/* Object data collections */

typedef struct {
	tuple point, normal;
} object_plane;

typedef struct {
	tuple v[3];
} object_triangle;

typedef struct {
	tuple v[4];
} object_quad;

typedef struct {
	tuple centre, dimensions;
} object_box;

typedef struct {
	tuple centre;
	num radius;
} object_sphere;

/* Meta-object data collections */

typedef struct {
	object_triangle* t;
	int count;
} object_model;

/*
typedef struct {
	num transform[16];
	int object_type;
	void* data;	
} object_meta_transform;
*/

typedef struct {
	int csg_operation;
	object_entry *obj1, *obj2;
} object_meta_csg;

/* Public object functions */

//tuple object_normal(object_entry* obj, tuple p);
//num	  object_intersect(object_entry* obj, ray r ); /* -1 on failure */

int object_search(object_entry* items, int item_count, ray r, object_intersection* ret);

tuple object_diffuse_colour(object_entry* obj, tuple p);

/* Construction / Deconstruction */

object_entry* object_new_plane   (material_t mat, tuple point, tuple normal);
object_entry* object_new_triangle(material_t mat, tuple v1, tuple v2, tuple v3);
object_entry* object_new_quad    (material_t mat, tuple v1, tuple v2, tuple v3, tuple v4);
object_entry* object_new_box     (material_t mat, tuple centre, tuple dimensions);
object_entry* object_new_sphere  (material_t mat, tuple centre, num radius);
object_entry* object_new_csg     (material_t mat, int operation, object_entry* o1, object_entry* o2);
void          object_free(object_entry* oe);
