/* writeray.c - dump the internal database to a Rayshade 4.0 input file
 *            - written by Glenn M. Lewis - 7/22/91
 */

static char rcs_id[] = "$Id: writeray.c,v 1.5 1991/09/05 17:51:13 glewis Exp glewis $";

#include <stdio.h>
#include <ctype.h>
#include "ttdddlib.h"

static void process_DESC();
static void process_EXTR();
static void process_INFO();
static void process_OBJ();

/* Two-space tabs */
#define TABSTOP "  "

static FILE *out;
static char tab[133];
static int num_OBJ, num_DESC, num_TOBJ;
static int cur_level, cur_objnum;
static int prntline;

static struct save_hier {
	int objnum;
	struct save_hier *next;
} *root = 0;
typedef struct save_hier HIER;

/* Here are a few necessary utilities */

static void indent()
{
	strcat(tab, TABSTOP);
}

static void outdent()
{
	register int i = strlen(tab) - strlen(TABSTOP);
	if (i<0) {
		fprintf(stderr, "Whoa, Glenn!  You blew it!\n");
		tab[0] = '\0';
		return;
	}
	tab[i] = '\0';
}

static void send_XYZ(f)			/* Print a common string */
XYZ_st *f;
{
/* I noticed that with a Ultrix C compiler, these in-line function calls were
 * not executed in the order specified.  Since I want this code to be portable,
 * and since some C compilers are broken, I seperated the following lines.
 * This goes for *all* in-line function calls in this source code.
 */
	fprintf(out, " %g",   f->val[0]);
	fprintf(out, " %g",   f->val[1]);
	fprintf(out, " %g\n", f->val[2]);
}

static void send_RGB(rgb)			/* Print a common string */
RGB_st *rgb;
{
	fprintf(out, " %g",   ((double)rgb->val[0])/255.0);
	fprintf(out, " %g",   ((double)rgb->val[1])/255.0);
	fprintf(out, " %g\n", ((double)rgb->val[2])/255.0);
}

/********************/
/* The MAIN section */
/********************/

int write_Rayshade(world, file)
WORLD *world;
FILE *file;
{
	register OBJECT *o;

	if (!(out=file)) return(0);	/* File not open */

	tab[0] = '\0';
	num_OBJ = num_DESC = num_TOBJ = 0;

	fputs("/* TTDDD library - Written by Glenn M. Lewis - 7/22/91*/\n\n", out);
	if (world->info) process_INFO(world->info);
	for (o=world->object; o; o=o->next)
		process_OBJ(o);
	return(1);
}

static void process_INFO(info)
INFO *info;
{
	fprintf(out, "%s/* INFO Begin */\n", tab);
	indent();
/*
	for (i=0; i<8; i++)
		if (info->brsh[i][0])
			fprintf(out, "%sBRSH[%d]=\"%s\"\n", tab, i, info->brsh[i]);

	for (i=0; i<8; i++)
		if (info->stnc[i][0])
			fprintf(out, "%sSTNC[%d]=\"%s\"\n", tab, i, info->stnc[i]);

	for (i=0; i<8; i++)
		if (info->txtr[i][0])
			fprintf(out, "%sTXTR[%d]=\"%s\"\n", tab, i, info->txtr[i]);
*/

	if (info->obsv) {
		fprintf(out, "%seyep", tab); send_XYZ(&info->obsv->came);
		fprintf(out, "%s/* OBSV Rotate", tab); send_XYZ(&info->obsv->rota);
		fprintf(out, "*/%sfocaldist  %g\n", tab, info->obsv->foca);
	}

/*	if (info->otrk[0]) fprintf(out, "%sOTRK \"%s\"\n", tab, info->otrk);	*/

/*
	if (info->ostr) {
		if (info->ostr->path[0])
			fprintf(out, "%sOSTR Path \"%s\"\n", tab, info->ostr->path);
		fprintf(out, "%sOSTR Translate", tab); send_XYZ(&info->ostr->tran);
		fprintf(out, "%sOSTR Rotate   ", tab); send_XYZ(&info->ostr->rota);
		fprintf(out, "%sOSTR Scale    ", tab); send_XYZ(&info->ostr->scal);
		i = info->ostr->info;
		strin[0] = '\0';
		if (i&(1<<0))  strcat(strin, " ABS_TRA");
		if (i&(1<<1))  strcat(strin, " ABS_ROT");
		if (i&(1<<2))  strcat(strin, " ABS_SCL");
		if (i&(1<<4))  strcat(strin, " LOC_TRA");
		if (i&(1<<5))  strcat(strin, " LOC_ROT");
		if (i&(1<<6))  strcat(strin, " LOC_SCL");
		if (i&(1<<8))  strcat(strin, " X_ALIGN");
		if (i&(1<<9))  strcat(strin, " Y_ALIGN");
		if (i&(1<<10)) strcat(strin, " Z_ALIGN");
		if (i&(1<<12)) strcat(strin, " FOLLOW_ME");
		fprintf(out, "%sOSTR Info%s\n", tab, strin);
	}
*/

	if (info->fade) {
		fprintf(out, "%s/* FADE FadeAt %g*/\n", tab, info->fade->at);
		fprintf(out, "%s/* FADE FadeBy %g*/\n", tab, info->fade->by);
		fprintf(out, "%s/* FADE FadeTo", tab); send_RGB(&info->fade->to);
		fprintf(out, "*/\n");
	}

	if (info->skyc) {
		fprintf(out, "%s/* SKYX Horizon", tab); send_RGB(&info->skyc->hori);
		fprintf(out, "*/\n");
		fprintf(out, "%s/* SKYC Zenith ", tab); send_RGB(&info->skyc->zeni);
		fprintf(out, "*/\n");
	}

	if (info->ambi)
		{ fprintf(out, "%sbackground", tab); send_RGB(info->ambi); }

/*
	if (info->glb0)
		for (i=0; i<8; i++)
			fprintf(out, "%sGLB0[%d]=%u\n", tab, i, info->glb0[i]);
*/

	outdent();
	fprintf(out, "%s/* End INFO */\n", tab);
}

static void process_OBJ(obj)
register OBJECT *obj;
{
	register HIER *p;
	num_OBJ++;
	fprintf(out, "%s/* OBJ Begin \"Hierarchy %d\" */\n", tab, num_OBJ);
	num_DESC = num_TOBJ = 0;		/* Reset counters */
	cur_level = 0;
	cur_objnum = 1;
	prntline = 1;

	if (obj->extr) process_EXTR(obj->extr);
	else process_DESC(obj);

	while (root) {				/* This should happen at most once. */
		p = root->next;
		free((char *)root);		/* Delete this from list */
		root = p;
		outdent();
	}

	fprintf(out, "%s/* End OBJ   \"Hierarchy %d\" */\n", tab, num_OBJ);
}

static int process_TOBJ()
{
	register HIER *p;
	if (num_DESC-num_TOBJ < cur_level) {	/* Pop old level off HIER */
		cur_level--;
		cur_objnum = root->objnum;
		p = root->next;
		free((char *)root);	/* Delete from list */
		root = p;
		outdent();	/* Pretty file formatting */
	}
	fprintf(out, "%s/* TOBJ       \"Object %d at level %d of hierarchy %d\" */\n",
		tab, cur_objnum-1, num_DESC-num_TOBJ, num_OBJ);
	num_TOBJ++;
	prntline = 1;
}

static void process_EXTR(extr)
EXTR *extr;
{
	register int i;

	if (!prntline) fprintf(out, "\n");	/* Print one anyway */
	indent();
	num_DESC++;

	fprintf(out, "%s/* EXTR Begin \"Object %d at level %d of hierarchy %d\" */\n",
		tab, cur_objnum, num_DESC-num_TOBJ, num_OBJ);
	indent();
	fprintf(out, "%s/* LOAD \"%s\" */\n", tab, extr->filename);
	fprintf(out, "#include \"%s\"\n", extr->filename);
	fprintf(out, "%stranslate", tab); send_XYZ(&extr->mtrx.tran);
	fprintf(out, "%sscale    ", tab); send_XYZ(&extr->mtrx.scal);
	fprintf(out, "%stransform", tab);
	for (i=0; i<3; i++) fprintf(out, " %g", extr->mtrx.rota1.val[i]);
	for (i=0; i<3; i++) fprintf(out, " %g", extr->mtrx.rota2.val[i]);
	for (i=0; i<3; i++) fprintf(out, " %g", extr->mtrx.rota3.val[i]);
	fprintf(out, "\n");

	outdent();
	fprintf(out, "%s/* End EXTR   \"Object %d at level %d of hierarchy %d\" */\n",
		tab, cur_objnum, num_DESC-num_TOBJ, num_OBJ);

	num_TOBJ++;
	cur_objnum++;
	outdent();
	prntline = 1;
}

static void process_DESC(object)
OBJECT *object;
{
	register int i;
	register HIER *p;
	register OBJECT *obj;
	register DESC *desc = object->desc;

	num_DESC++;
	if (num_DESC-num_TOBJ > cur_level) {	/* Push new level in HIER */
		if (!prntline) fprintf(out, "\n");	/* Print one anyway */
		if (!(p = (HIER*)malloc(sizeof(HIER)))) {
			fprintf(stderr, "ERROR!  Out of memory.\n*** ABORT ***\n");
			exit(20);
		}
		p->next = root;		/* Insert into list */
		root = p;
		root->objnum = cur_objnum;
		cur_level++;
		cur_objnum = 1;
		indent();	/* Pretty file formatting */
	}

	fprintf(out, "%s/* DESC Begin \"Object %d at level %d of hierarchy %d\" */\n",
		tab, cur_objnum, num_DESC-num_TOBJ, num_OBJ);
	fprintf(out, "%sgrid 20 20 20\n", tab);
	indent();

	if (desc->name[0]) fprintf(out, "%s/* name \"%s\" */\n", tab, desc->name);

	if (desc->shap) {
		fprintf(out, "%s/* SHAP Shape = %u */\n", tab, desc->shap[0]);
		if (desc->shap==0 && !desc->shap[1]) {	/* Sphere */
			fprintf(out, "%ssphere %g", tab, desc->size->val[0]);
			send_XYZ(desc->posi);
			goto SKIP_REST;
		}
		fprintf(out, "%s/* SHAP Lamp  = %u */\n", tab, desc->shap[1]);
		if (desc->shap[1]) {
			fprintf(out, "%slight", tab);
			if (desc->colr) send_RGB(desc->colr); else fprintf(out, " 1.0 ");
			if (desc->shap[1]==1)	/* Sunlight */
				fprintf(out, "directional %g %g %g\n",
					-(desc->posi->val[0]),
					-(desc->posi->val[1]),
					-(desc->posi->val[2]));
			else	/* Like a lamp */
				fprintf(out, "point %g %g %g\n",
					desc->posi->val[0],
					desc->posi->val[1],
					desc->posi->val[2]);
			goto SKIP_REST;
		}
	}

/*
	if (desc->axis) {
		fprintf(out, "%sAXIS XAxis", tab); send_XYZ(&desc->axis->xaxi);
		fprintf(out, "%sAXIS YAxis", tab); send_XYZ(&desc->axis->yaxi);
		fprintf(out, "%sAXIS ZAxis", tab); send_XYZ(&desc->axis->zaxi);
	}

	if (desc->size)
		{ fprintf(out, "%sSIZE", tab); send_XYZ(desc->size); }

	if (desc->pcount) {
		fprintf(out, "%sPNTS PCount %u\n", tab, desc->pcount);
		for (i=0; i<desc->pcount; i++) {
			fprintf(out, "%sPNTS Point[%d]", tab, i);
			send_XYZ(&desc->pnts[i]);
		}
	}

	if (desc->ecount) {
		fprintf(out, "%sEDGE ECount %u\n", tab, desc->ecount);
		for (i=0; i<desc->ecount; i++) {
			fprintf(out, "%sEDGE Edge[%d] %u %u\n", tab, i,
				desc->edge[i<<1], desc->edge[(i<<1)+1]);
		}
	}
*/

	if (desc->fcount) {
		fprintf(out, "%s/* FACE TCount %u */\n", tab, desc->fcount);
		for (i=0; i<desc->fcount; i++) {
/*			fprintf(out, "%sFACE Connect[%u] %u %u %u\n", tab, i,
				desc->face[i*3], desc->face[i*3+1], desc->face[i*3+2]);
*/
			fprintf(out, "%striangle", tab);
			send_XYZ(&desc->pnts[desc->edge[(desc->face[i*3])<<1]]);
			send_XYZ(&desc->pnts[desc->edge[((desc->face[i*3])<<1)+1]]);
			if (desc->edge[(desc->face[i*3+2])<<1] ==
				desc->edge[(desc->face[i*3])<<1] ||
				desc->edge[(desc->face[i*3+2])<<1] ==
				desc->edge[((desc->face[i*3])<<1)+1])
				send_XYZ(&desc->pnts[desc->edge[((desc->face[i*3+2])<<1)+1]]);
			else
				send_XYZ(&desc->pnts[desc->edge[(desc->face[i*3+2])<<1]]);
		}
	}

SKIP_REST:

	for (obj=object->child; obj; obj=obj->next) {
		if (obj->extr) process_EXTR(obj->extr);
		else process_DESC(obj);
	}

	outdent();
	fprintf(out, "%send /* End DESC   \"Object %d at level %d of hierarchy %d\" */\n",
		tab, cur_objnum, num_DESC-num_TOBJ, num_OBJ);

	if (desc->posi)
		{ fprintf(out, "%stranslate", tab); send_XYZ(desc->posi); }

	if (desc->colr) { fprintf(out, "%sambient", tab); send_RGB(desc->colr); }

	if (desc->refl) { fprintf(out, "%sspecular", tab); send_RGB(desc->refl); }

	if (desc->tran) { fprintf(out, "%s/* TRAN", tab); send_RGB(desc->tran);
		fprintf(out, "*/\n");
	}

#ifdef WRITETTDDD
	if (desc->fcount) {
		fprintf(out, "%sCLST Count %u\n", tab, i);
		for (i=0; i<desc->fcount; i++) {
			if (desc->colr) {
				if (desc->clst[i*3  ]==desc->colr->val[0] &&
					desc->clst[i*3+1]==desc->colr->val[1] &&
					desc->clst[i*3+2]==desc->colr->val[2]) continue; /* Skip */
			} else {
				if (desc->clst[i*3  ]==240 &&
					desc->clst[i*3+1]==240 &&
					desc->clst[i*3+2]==240) continue;	/* Skip this one */
			}
			fprintf(out, "%sCLST Color[%u]", tab, i);
			send_RGB((RGB_st*)&desc->clst[i*3]);
		}
		fprintf(out, "%sRLST Count %u\n", tab, i);
		for (i=0; i<desc->fcount; i++) {
			if (desc->refl) {
				if (desc->rlst[i*3  ]==desc->refl->val[0] &&
					desc->rlst[i*3+1]==desc->refl->val[1] &&
					desc->rlst[i*3+2]==desc->refl->val[2]) continue; /* Skip */
			} else {
				if (desc->rlst[i*3  ]==0 &&
					desc->rlst[i*3+1]==0 &&
					desc->rlst[i*3+2]==0) continue;	/* Skip this one */
			}
			fprintf(out, "%sRLST Color[%u]", tab, i);
			send_RGB((RGB_st*)&desc->rlst[i*3]);
		}
		fprintf(out, "%sTLST Count %u\n", tab, i);
		for (i=0; i<desc->fcount; i++) {
			if (desc->tran) {
				if (desc->tlst[i*3  ]==desc->tran->val[0] &&
					desc->tlst[i*3+1]==desc->tran->val[1] &&
					desc->tlst[i*3+2]==desc->tran->val[2]) continue; /* Skip */
			} else {
				if (desc->tlst[i*3  ]==0 &&
					desc->tlst[i*3+1]==0 &&
					desc->tlst[i*3+2]==0) continue;	/* Skip this one */
			}
			fprintf(out, "%sTLST Color[%u]", tab, i);
			send_RGB((RGB_st*)&desc->tlst[i*3]);
		}
	}
#endif

	if (desc->tpar) {
		for (i=0; i<16; i++)
			fprintf(out, "%s/* TPAR[%u]=%g */\n", tab, i, desc->tpar[i]);
	}

	if (desc->surf) {
		for (i=0; i<5; i++)
			fprintf(out, "%s/* SURF[%u]=%d */\n", tab, i, desc->surf[i]);
	}

	if (desc->mttr) {
		fprintf(out, "%s/* MTTR Type =%u */\n", tab, desc->mttr->type);
		fprintf(out, "%s/* MTTR Index=%g */\n", tab, (double)desc->mttr->indx);
	}

	if (desc->spec) {
		fprintf(out, "%s/* SPEC Spec=%u */\n", tab, desc->spec[0]);
		fprintf(out, "%s/* SPEC Hard=%u */\n", tab, desc->spec[1]);
	}

	if (desc->prp0) {
		for (i=0; i<6; i++)
			fprintf(out, "%s/* PRP0[%u]=%u */\n", tab, i, desc->prp0[i]);
	}

	if (desc->ints)
		fprintf(out, "%s/* INTS=%g */\n", tab, desc->ints);

#ifdef WRITETDDD
	if (desc->stry) {
		fprintf(out, "%sSTRY Path \"%s\"\n", tab, desc->stry->path);
		fprintf(out, "%sSTRY Translate", tab); send_XYZ(&desc->stry->tran);
		fprintf(out, "%sSTRY Rotate   ", tab); send_XYZ(&desc->stry->rota);
		fprintf(out, "%sSTRY Scale    ", tab); send_XYZ(&desc->stry->scal);
		i = desc->stry->info;
		strin[0] = '\0';
		if (i&(1<<0))  strcat(strin, " ABS_TRA");
		if (i&(1<<1))  strcat(strin, " ABS_ROT");
		if (i&(1<<2))  strcat(strin, " ABS_SCL");
		if (i&(1<<4))  strcat(strin, " LOC_TRA");
		if (i&(1<<5))  strcat(strin, " LOC_ROT");
		if (i&(1<<6))  strcat(strin, " LOC_SCL");
		if (i&(1<<8))  strcat(strin, " X_ALIGN");
		if (i&(1<<9))  strcat(strin, " Y_ALIGN");
		if (i&(1<<10)) strcat(strin, " Z_ALIGN");
		if (i&(1<<12)) strcat(strin, " FOLLOW_ME");
		fprintf(out, "%sSTRY Info%s\n", tab, strin);
	}
#endif

	cur_objnum++;
	prntline = 0;
	process_TOBJ();
}

