/* surfedit.c: surface editing */

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "mymath.h"

#include <Xm/Xm.h>
#include <Xm/MessageB.h>
#include "xmenu.h"

#include "surfedit.h"
#include "canvas.h"
#include "select.h"
#include "error.h"
#include "patch.h"
#include "Memory.h"
#include "defaults.h"
#include "globals.h"
#include "defaults.h"

/* declared in main.c */
extern Arg visargs[];
extern int nrvisargs;
extern Widget topLevel;

/* all the necessary information for the callback procedures below */
typedef struct PATCHMAT {
	MATERIAL *material;
	PATCH *patch;
} PATCHMAT;

static void EditMaterialOKCallback(Widget w, XtPointer client_data, XtPointer call_data)
{
	Widget editMaterialShell = XtParent(w);
	PATCHMAT *patmat = (PATCHMAT *)client_data;
	PATCH *P = ToplevelPatch(patmat->patch);
	COLOR diff;

/* change in emissivity */
	COLORSUBSTRACT(patmat->material->Ed, P->surface->material->Ed, diff);
	if (diff.r*diff.r + diff.g*diff.g + diff.b*diff.b > EPSILON) {
/* if the user fills in (100,100,100) he wants a white light source emitting 100W/m^2 */
		COLORSCALEINVERSE(COLORNRCHANNELS*M_PI, diff, diff);
		P->basis->PushPullEmissivityChange(P, diff);
	}
	
/* change in reflectivity */
	COLORSUBSTRACT(patmat->material->Kd, P->surface->material->Kd, diff);
	if (diff.r*diff.r + diff.g*diff.g + diff.b*diff.b > EPSILON) {
		COLOR oldrho = P->surface->material->Kd, 
		      newrho = patmat->material->Kd, delrho;

		COLORRELATIVEDIFFERENCE(newrho, oldrho, delrho);
		P->basis->PushPullReflectivityChange(P, delrho);
	}

	MaterialCopy(patmat->material, P->surface->material);

	XtDestroyWidget(editMaterialShell);
	MaterialDestroy(patmat->material);
	Free((char *)patmat, sizeof(PATCHMAT));

	PatchComputeVertexColors(P);
	RenderScene();
}

static void EditMaterialCancelCallback(Widget w, XtPointer client_data, XtPointer call_data)
{
	Widget editMaterialShell = XtParent(w);
	PATCHMAT *patmat = (PATCHMAT *)client_data;

	XtDestroyWidget(editMaterialShell);
	MaterialDestroy(patmat->material);
	Free((char *)patmat, sizeof(PATCHMAT));
}

static void ShowEditSurfacePanel(PATCH *patch, POINT *hitp)
{
	MATERIAL *material;
	PATCHMAT *patmat;
	Widget editMaterialShell, editMaterialBox, editMaterialForm;
	
	editMaterialShell = XtAppCreateShell("Material",
					     APP_CLASS_NAME,
					     topLevelShellWidgetClass,
					     XtDisplay(topLevel),
					     visargs,
					     nrvisargs);
	
	editMaterialBox = XmCreateMessageBox(editMaterialShell, "editMaterialBox", NULL, 0);
	XtVaSetValues(editMaterialBox,
		      XmNdialogType, XmDIALOG_TEMPLATE,
		      NULL);	

	material = MaterialDuplicate(patch->surface->material);

{
	XFORMFIELD editMaterialFormFields[] = {
	{XFORMFLOAT,	(char *)&material->Kd.r,	"Reflectivity red"},
	{XFORMFLOAT,	(char *)&material->Kd.g,	"Reflectivity green"},
	{XFORMFLOAT,	(char *)&material->Kd.b,	"Reflectivity blue"},
	{XFORMFLOAT,	(char *)&material->Ed.r,	"Emissivity red"},
	{XFORMFLOAT,	(char *)&material->Ed.g,	"Emissivity green"},
	{XFORMFLOAT,	(char *)&material->Ed.b,	"Emissivity blue"},
	{0,		NULL,				NULL}
	};
	editMaterialForm = XFormCreate(editMaterialBox, editMaterialFormFields);
}

	patmat = (PATCHMAT *)Alloc(sizeof(PATCHMAT));
	patmat->material = material;
	patmat->patch = patch;

        XtAddCallback(editMaterialBox, XmNokCallback, EditMaterialOKCallback, (XtPointer)patmat);
        XtAddCallback(editMaterialBox, XmNcancelCallback, EditMaterialCancelCallback, (XtPointer)patmat);

        XtManageChild(editMaterialBox);
        XtRealizeWidget(editMaterialShell);
}

void EditSurface(void)
{
/* informs what to do with the selected patch: after the selection a form 
 * for editing the surface characteristics of the patch should be shown */
	SelectPatchSetCallback(ShowEditSurfacePanel);

/* changes the cursor to a crosshair cursor and waits for the user to select
 * something */
	CanvasPushMode(CANVASMODE_SELECT_PATCH);
}




