#include "ai.h"

AI_SHADER_NODE_EXPORT_METHODS(apMicrofacetRefractionBSDF)

enum apMicrofacetRefractionBSDFParams
{
	p_weight,
	p_distribution,
	p_eta,
	p_roughness_u,
	p_roughness_v,
	p_dispersion,
	p_use_fresnel,
	p_interior,
	p_exit_type,
	p_opacity
};

static const char* DistributionNames[]
{
	"MICROFACET_BECKMANN",
	"MICROFACET_GGX",
	NULL
};

static const char* ExitTypeNames[]
{
	"Zero",
	"Background",
	"White",
	NULL
};

struct ShaderData
{
	int distribution;
	float eta;
	float ru;
	float rv;
	float dispersion;
	bool use_fresnel;
	int exit_type;
};

node_parameters
{
	AiParameterRGB("weight", 0.5, 0.5, 0.5);
	AiParameterEnum("distribution", 0, DistributionNames);
	AiParameterFlt("eta", 0);
	AiParameterFlt("roughness_u", 0);
	AiParameterFlt("roughness_v", 0);
	AiParameterFlt("dispersion", 0);
	AiParameterBool("use_fresnel", 0);
	AiParameterClosure("interior");
	AiParameterEnum("exit_type", 0, ExitTypeNames);
	AiParameterRGB("opacity", 1, 1, 1);
}

node_initialize
{
	ShaderData *data = (ShaderData *)AiMalloc(sizeof(ShaderData));
	AiNodeSetLocalData(node, data);
}

node_update
{
	ShaderData *data = (ShaderData *)AiNodeGetLocalData(node);
	data->distribution = AiNodeGetInt(node, "distribution");
	data->eta = AiNodeGetFlt(node, "eta");
	data->ru = AiNodeGetFlt(node, "roughness_u");
	data->rv = AiNodeGetFlt(node, "roughness_v");
	data->dispersion = AiNodeGetFlt(node, "dispersion");
	data->use_fresnel = AiNodeGetBool(node, "use_fresnel");
	data->exit_type = AiNodeGetInt(node, "exit_type");
}

node_finish
{
	ShaderData *data = (ShaderData *)AiNodeGetLocalData(node);
	AiFree(data);
}

shader_evaluate
{
	ShaderData *data = (ShaderData *)AiNodeGetLocalData(node);
	AtRGB weight = AiShaderEvalParamRGB(p_weight);
	AtRGB opacity = AiShaderEvalParamRGB(p_opacity);
	int distribution = data->distribution ? AI_MICROFACET_BECKMANN : AI_MICROFACET_GGX;
	int exit_type = 0;
	if (data->exit_type == 1) exit_type = AI_BSDF_LOBE_EXIT_BACKGROUND;
	if (data->exit_type == 2) exit_type = AI_BSDF_LOBE_EXIT_WHITE;
	AtClosureList interior;
	interior.add(AiShaderEvalParamClosure(p_interior));
	AtBSDF *bsdf = AiMicrofacetRefractionBSDF(sg, weight * opacity,
									distribution,
									sg->Nf, &sg->dPdu, data->eta,
									data->ru, data->rv, data->dispersion,
									data->use_fresnel,
									interior,
									exit_type);
	AtClosureList closures;
	closures.add(bsdf);
	closures.add(AiClosureTransparent(sg, 1.0 - opacity));
	sg->out.CLOSURE() = closures;
}

node_loader
{
	if (i > 0)
	return false;

	node->methods = apMicrofacetRefractionBSDF;
	node->output_type = AI_TYPE_CLOSURE;
	node->name = "apMicrofacetRefractionBSDF";
	node->node_type = AI_NODE_SHADER;
	strcpy(node->version, AI_VERSION);
	return true;
}