/* write.c - dump the internal database to a TTDDD file
 *         - written by Glenn M. Lewis - 7/19/91
 */

static char rcs_id[] = "$Id: write.c,v 1.4 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], strin[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, " X=%g",   f->val[0]);
	fprintf(out, " Y=%g",   f->val[1]);
	fprintf(out, " Z=%g\n", f->val[2]);
}

static void send_RGB(rgb)			/* Print a common string */
RGB_st *rgb;
{
	fprintf(out, " R=%u",   rgb->val[0]);
	fprintf(out, " G=%u",   rgb->val[1]);
	fprintf(out, " B=%u\n", rgb->val[2]);
}

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

int write_TTDDD(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/19/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;
{
	register int i;

	fprintf(out, "%sINFO 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, "%sOBSV Camera", tab); send_XYZ(&info->obsv->came);
		fprintf(out, "%sOBSV Rotate", tab); send_XYZ(&info->obsv->rota);
		fprintf(out, "%sOBSV Focal  %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, "%sFADE FadeAt %g\n", tab, info->fade->at);
		fprintf(out, "%sFADE FadeBy %g\n", tab, info->fade->by);
		fprintf(out, "%sFADE FadeTo", tab); send_RGB(&info->fade->to);
	}

	if (info->skyc) {
		fprintf(out, "%sSKYC Horizon", tab); send_RGB(&info->skyc->hori);
		fprintf(out, "%sSKYC Zenith ", tab); send_RGB(&info->skyc->zeni);
	}

	if (info->ambi)
		{ fprintf(out, "%sAMBI", 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, "%sEnd INFO\n", tab);
}

static void process_OBJ(obj)
register OBJECT *obj;
{
	register HIER *p;
	num_OBJ++;
	fprintf(out, "%sOBJ 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, "%sEnd 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, "%sTOBJ       \"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, "%sEXTR Begin \"Object %d at level %d of hierarchy %d\"\n",
		tab, cur_objnum, num_DESC-num_TOBJ, num_OBJ);
	indent();
	fprintf(out, "%sMTRX Translate", tab); send_XYZ(&extr->mtrx.tran);
	fprintf(out, "%sMTRX Scale    ", tab); send_XYZ(&extr->mtrx.scal);
	fprintf(out, "%sMTRX Rotate", 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");

	fprintf(out, "%sLOAD \"%s\"\n", tab, extr->filename);
	outdent();
	fprintf(out, "%sEnd 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, "%sDESC Begin \"Object %d at level %d of hierarchy %d\"\n",
		tab, cur_objnum, num_DESC-num_TOBJ, num_OBJ);
	indent();

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

	if (desc->shap) {
		fprintf(out, "%sSHAP Shape = %u\n", tab, desc->shap[0]);
		fprintf(out, "%sSHAP Lamp  = %u\n", tab, desc->shap[1]);
	}

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

	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, "%sFACE 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]);
		}
	}

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

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

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

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

	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]);
		}
	}

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

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

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

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

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

	if (desc->prp1) {
		for (i=0; i<8; i++)
			fprintf(out, "%sPRP1[%u]=%u\n", tab, i, desc->prp1[i]);
	}

	if (desc->ints)
		fprintf(out, "%sINTS=%g\n", tab, desc->ints);

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

	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);
	}

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

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

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

