/* raycast.c */
#include <stdio.h>
#include <math.h>

#include "raycast.h"
#include "ray.h"
#include "mymath.h"
#include "render.h"
#include "Memory.h"
#include "radiance.h"
#include "globals.h"

void RayCast(GEOMLIST *world, CAMERA *camera, FILE *fp)
{
	RAY ray;
	int i, j, count, total;
	float v, h, x, y, dist, up, vp;
	PATCH *hit, *lasthit=(PATCH *)NULL, *lowestlevelhit;
	POINT hitp;
	COLOR rad, ambient_rad;
	RGB *rgb;

	if (render_ambient)
		ambient_rad = *GetAmbientRadiance();

	fprintf(fp, "P6\n%d %d\n255\n", camera->hres, camera->vres);

	rgb = (RGB *)Alloc(camera->hres * sizeof(RGB));

      	h = 2. * tan(camera->hfov * M_PI/180.) / (float)(camera->hres-1);
       	v = 2. * tan(camera->vfov * M_PI/180.) / (float)(camera->vres-1);

	total = camera->hres * camera->vres; count = 0;
	ray.pos = camera->eyep;
	for (j=0, y=-v * (float)(camera->vres-1)/2.; j<camera->vres; j++, y+=v) {
		for (i=0, x=-h * (float)(camera->hres-1)/2.; i<camera->hres; i++, x+=h) {
			VECTORCOMB3(camera->Z, x, camera->X, y, camera->Y, ray.dir);
			VECTORNORMALIZE(ray.dir);

			dist = HUGE;
			if ((hit = GeomListIntersect(world, &ray, 0., &dist, FALSE)) 
			    && (hit->twosided || VECTORDOTPRODUCT(hit->norm, ray.dir) < 0.) ) {
				VECTORSUMSCALED(ray.pos, dist, ray.dir, hitp);
				if (hit != lasthit)
					PatchUV(hit, &hitp, &up, &vp);
				else	/* use cached data about the hit patch */
					PatchUV((PATCH *)NULL, &hitp, &up, &vp);
				lowestlevelhit = LowestLevelPatch(hit, &up, &vp);
				rad = lowestlevelhit->basis->GetValueAtPoint(lowestlevelhit->radiance, up, vp);
				
				if (render_ambient) {
					COLOR a;
					COLORPROD(hit->surface->material->Kd, ambient_rad, a);
					COLORADD(rad, a, rad);
				}

				RadianceToRGB(rad, &rgb[i]);
				lasthit = hit;
			} else 
				rgb[i] = camera->background;

			fputc((int)(rgb[i].r * 255.), fp);
			fputc((int)(rgb[i].g * 255.), fp);
			fputc((int)(rgb[i].b * 255.), fp);
	        }

		RenderPixels(0, camera->vres-1-j, camera->hres, rgb);
	}

	Free((char *)rgb, camera->hres * sizeof(RGB));
}





