


/* Feel free to read this struct's members. Feel free to alter the contents of 
the isometry and the shape data. */
typedef struct bodyBody bodyBody;
struct bodyBody {
    isoIsometry isometry;
    int shapeDataSize;
    void *shapeData;
    /* Given a body with the specified modeling isometry and shape data. Given a 
    ray x(t) = p + t * u in world coordinates. Outputs the ray's intersection 
    with the body. */
    void (*getIntersection)(
        const isoIsometry *isom, const void *shapeData, const double p[3], 
        const double u[3], rayIntersection *inter);
    int materialDataSize;
    void *materialData;
	/* Given a body with the specified modeling isometry and material data. 
	Given a ray x(t) = p + t * u in world coordinates. Given that ray's 
	intersection with the body. Outputs the body's material at the point 
	corresponding to the intersection's start time. */
    void (*getMaterial)(
        const isoIsometry *isom, const void *materialData, const double p[3], 
        const double u[3], const rayIntersection *inter, rayMaterial *material);
};

/* Initializes the body, returning an error code (0 on success). On success, 
don't forget to bodyFinalize when you're done. The isometry is initialized to 
the trivial isometry. The shape data and material data are allocated but not 
initialized. */
int bodyInitialize(
        bodyBody *body, int shapeDataSize, 
        void (*getIntersection)(
        	const isoIsometry *isom, const void *shapeData, const double p[3], 
        	const double u[3], rayIntersection* inter), 
        int materialDataSize, 
        void (*getMaterial)(
        	const isoIsometry *isom, const void *materialData, 
        	const double p[3], const double u[3], const rayIntersection *inter, 
        	rayMaterial *material)) {
    if (shapeDataSize > 0) {
		body->shapeData = malloc(shapeDataSize);
		if (body->shapeData == NULL) {
			fprintf(stderr, "error: bodyInitialize: malloc failed\n");
			return 2;
		}
    }
    if (materialDataSize > 0) {
		body->materialData = malloc(materialDataSize);
		if (body->materialData == NULL) {
			fprintf(stderr, "error: bodyInitialize: malloc failed\n");
			if (body->shapeDataSize > 0)
				free(body->shapeData);
			return 1;
		}
    }
    body->shapeDataSize = shapeDataSize;
    body->getIntersection = getIntersection;
    body->materialDataSize = materialDataSize;
    body->getMaterial = getMaterial;
    double transl[3] = {0.0, 0.0, 0.0};
    isoSetTranslation(&(body->isometry), transl);
    double rot[3][3] = {{1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0}};
    isoSetRotation(&(body->isometry), rot);
    return 0;
}

/* Releases the resources backing the body. */
void bodyFinalize(bodyBody *body) {
	if (body->shapeDataSize > 0)
		free(body->shapeData);
	if (body->materialDataSize > 0)
		free(body->materialData);
}

/* Using the body's shape, outputs the appropriate rayIntersection. */
void bodyGetIntersection(
        const bodyBody *body, const double p[3], const double u[3], 
        rayIntersection* inter) {
    body->getIntersection(&(body->isometry), body->shapeData, p, u, inter);
}

/* Using the body's material, outputs the appropriate rayMaterial. */
void bodyGetMaterial(
        const bodyBody *body, const double p[3], const double u[3], 
        const rayIntersection *inter, rayMaterial *material) {
    body->getMaterial(
    	&(body->isometry), body->materialData, p, u, inter, material);
}


