/*
 *			GPAC - MPEG-4 Systems C Development Kit
 *
 *			Copyright (c) Jean Le Feuvre 2000-2005
 *					All rights reserved
 *
 *  This file is part of GPAC / 3D rendering plugin
 *
 *  GPAC is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *   
 *  GPAC is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *   
 *  You should have received a copy of the GNU General Public License
 *  along with GNU Make; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
 *
 */



#include "render3d_nodes.h"

Bool r3d_is_light(SFNode *n, Bool local_only)
{
	switch (Node_GetTag(n)) {
	case TAG_MPEG4_DirectionalLight: 
	case TAG_X3D_DirectionalLight: 
		return 1;
	case TAG_MPEG4_PointLight:
	case TAG_MPEG4_SpotLight:
		return local_only ? 0 : 1;
	default: 
		return 0;
	}
}


static void RenderSpotLight(SFNode *n, void *rs)
{
	M_SpotLight *sl = (M_SpotLight *)n;
	RenderEffect3D *eff = (RenderEffect3D *) rs;

	if (!sl->on) return;

	/*store local bounds for culling*/
	if (eff->traversing_mode==TRAVERSE_GET_BOUNDS) {
		/*how crude - refine to only have the light cone :)*/
		SFVec3f size;
		size.x = size.y = size.z = sl->radius;
		m4_vec_add(eff->bbox.max_edge, sl->location, size);
		m4_vec_diff(eff->bbox.min_edge, sl->location, size);
		m4_bbox_refresh(&eff->bbox);
		return;
	}
	else if (eff->traversing_mode == TRAVERSE_LIGHTING) {
		VS3D_PushMatrix(eff->surface);
		VS3D_MultMatrix(eff->surface, eff->model_matrix.m);
		
		VS3D_AddSpotLight(eff->surface, sl->ambientIntensity, sl->attenuation, sl->beamWidth, 
					   sl->color, sl->cutOffAngle, sl->direction, sl->intensity, sl->location);
		
		VS3D_PopMatrix(eff->surface);
	}
}

void R3D_InitSpotLight(Render3D *sr, SFNode *node)
{
	/*no need for a stck*/
	Node_SetRenderFunction(node, RenderSpotLight);
}

static void RenderPointLight(SFNode *n, void *rs)
{
	M_PointLight *pl = (M_PointLight *)n;
	RenderEffect3D *eff = (RenderEffect3D *) rs;

	if (!pl->on) return;

	/*store local bounds for culling*/
	if (eff->traversing_mode==TRAVERSE_GET_BOUNDS) {
		SFVec3f size;
		size.x = size.y = size.z = pl->radius;
		m4_vec_add(eff->bbox.max_edge, pl->location, size);
		m4_vec_diff(eff->bbox.min_edge, pl->location, size);
		m4_bbox_refresh(&eff->bbox);
		return;
	}
	else if (eff->traversing_mode == TRAVERSE_LIGHTING) {
		VS3D_PushMatrix(eff->surface);
		VS3D_MultMatrix(eff->surface, eff->model_matrix.m);

		VS3D_AddPointLight(eff->surface, pl->ambientIntensity, pl->attenuation, pl->color, 
					pl->intensity, pl->location);

		VS3D_PopMatrix(eff->surface);
	}
}

void R3D_InitPointLight(Render3D *sr, SFNode *node)
{
	/*no need for a stck*/
	Node_SetRenderFunction(node, RenderPointLight);
}




static void DestroyDirectionalLight(SFNode *n)
{
	Bool *stack = Node_GetPrivate(n);
	free(stack);
}

static void RenderDirectionalLight(SFNode *n, void *rs)
{
	Bool *stack = Node_GetPrivate(n);
	M_DirectionalLight *dl = (M_DirectionalLight *)n;
	RenderEffect3D *eff = (RenderEffect3D *) rs;

	if ((eff->trav_flags & TF_SWITCHED_OFF) || !dl->on) return;

	/*1- DL only lights the parent group, no need for culling it*/
	/*DL is set dynamically while rendering, the only mode that interest us is draw*/
	if (eff->traversing_mode) return;

	if (eff->local_light_on) {
		*stack = VS3D_AddDirectionalLight(eff->surface, dl->ambientIntensity, dl->color, dl->intensity, dl->direction);
	} else {
		if (*stack) VS3D_RemoveLastLight(eff->surface);
		*stack = 0;
	}
}

void R3D_InitDirectionalLight(Render3D *sr, SFNode *node)
{
	/*our stack is just a boolean used to store whether the light was turned on successfully*/
	Bool *stack = malloc(sizeof(Bool));
	*stack = 0;
	Node_SetPrivate(node, stack);
	Node_SetPreDestroyFunction(node, DestroyDirectionalLight);
	Node_SetRenderFunction(node, RenderDirectionalLight);
}

