/* importance.c */

#include "importance.h"
#include "globals.h"
#include "scene.h"
#include "render.h"
#include "hrefine.h"
#include "Memory.h"

/* first argument is a pointer to the patch of which the directly received importance
 * has to be updated. The second argument is an array of which the i-th float
 * is the new directly received importance of the patch with id i */
static void (*PatchUpdateDirectImportance)(PATCH *, float *);

/* call this routine before UpdateDirectImportance to specify a routine
 * to set the new directly received importance for a patch. This is different for
 * shooting or gathering. */
void SetPatchDirectImportanceUpdateRoutine(void (*routine)(PATCH *, float *))
{
	PatchUpdateDirectImportance = routine;
}

/* we approximate the directly received importance by the number of pixels a patch
 * takes on the screen. The number of pixels is computed by ID-rendering the scene 
 * (preferably in the background) and making counting in how many pixels each patch 
 * is visible. By dividing the number of pixels for each patch by the total number 
 * of pixels on the screen we get nice numbers between 0 and 1 for the patches'
 * directly received importance. */
void UpdateDirectImportance(void)
{
	unsigned long *ids, *id, *patchpixels;
	float *newimp;
	long i, x, y, nrpixels, lostpixels;
	int maxpatchid;
	clock_t t;

	maxpatchid = PatchGetNextID(); /* IDs count from 1: ID 0 = background */
	patchpixels = (unsigned long *)Alloc(maxpatchid * sizeof(unsigned long));
	for (i=0; i<maxpatchid; i++)
		patchpixels[i] = 0;

	t = clock();
	ids = GetIDs(&x, &y);
	usecs_last_id_rendering = clock() - t;

/* this should never happen, but you never know for sure ... */
	if (ids == (unsigned long *)NULL)
		return;

	nrpixels = x*y; lostpixels=0;
	for (i=0, id=ids; i<nrpixels; i++, id++) {
		if (((*id)&0xffffff) >= maxpatchid) {
/* this should never happen as well, but sometimes there are problems caused
 * by pulldown menus that overlap the canvas window. */
/*			fprintf(stderr, "Ongeldig ID %ld op (%ld,%ld)\n",
				(*id)&0xffffff, i%x, (y-1)-i/x); */
			lostpixels++; continue;
		}
		patchpixels[(*id)&0xffffff] ++;	
	}

if (lostpixels > 0) {
	fprintf(stderr, "%ld pixels out of %ld (%2d%%) with invalid patch id\n",
		lostpixels, nrpixels, (int)(lostpixels*100/nrpixels));
}

	newimp = (float *)Alloc(maxpatchid * sizeof(float));
	for (i=0; i<maxpatchid; i++)
		newimp[i] = (float)patchpixels[i]/(float)nrpixels;

	PatchListIterate1A(Patches, PatchUpdateDirectImportance, newimp);

	Free((char *)ids, x * y *sizeof(unsigned long));
	Free((char *)patchpixels, maxpatchid * sizeof(unsigned long));
	Free((char *)newimp, maxpatchid * sizeof(float));
}

