/********************************************************************************

		Konvertiert Cybersculpt 3D2-Files in das POV-Sourceformat.

		(c) Coderight Juni 1994:

									Jochen Knaus			EMail: knaus@mibm.ruf.uni-freiburg.de
									Nickeleshalde 19
									88400 Biberach

		Datum:				27.7.1994
		Update:				30.9.1994 (1.20): kleiner, schneller
									19.12.94  (1.3) : Objektsplitting, einh. Kommandozeile
		Version:			1.29

		Dieses Konvertierprogramm ist Freeware, im Geiste des POV.
		Irgendwann demn„chst wird's auf "smooth triangles" erweitert.

		Das ganze sehr unsauber, unstrukturiert, aber schnell gebastelt und
		sollte trotzdem schnell portabel sein.

		Aufruf:	CYB_POV -flags 3d2_file <Destfile> <objektname>
						Flags:	-v	: POV-1 File erzeugen.
										-b	: Automatisches berechnen der Objektgrenzen.
										-o	: Objektsplitting.

**********************************************************************************/

#include<stdio.h>
#include<string.h>
#include<portab.h>
#include<stdlib.h>
#include<limits.h>

#define _LF															/* Define for separate Linefeed 				*/

#define VERSION_A	1
#define VERSION_B 29
#define	PATHLEN	256+1										/* max. Pfadl„nge.											*/

#if !defined( _LF )											/* Zeilenabschluž wahlweise mit oder		*/
char	buffer3[3] = { '}', 13, 0 };			/* ohne separates Linefeed.							*/
#else
char	buffer3[4] = { '}', 13, 10, 0 };
#endif

int		abbruch( void );									/* Schliežt Files.											*/
void	write_bounds( void );							/* Bestimmt und schreibt Objektgrenzen.	*/

FILE 	*source, *destin;									/* Filehandles global...								*/
WORD	wandel[6], minmax[6];
int		pov_mode = 2, bounds = FALSE, obj_split = FALSE;
char	*vorzeichen[6], buffer[4000], minus[2] = { '-', 0 },
			nullos[2] = { 0 };

int	main( int argc, char *argv[] )
{
	WORD					header[128], anz_obj, anz_punkte, anz_facetten,
								*punkte, *facetten;
	char					obj_name[10],  buffer2[256],
								def_file[PATHLEN] = "STD.POV", def_name[64] = "DEFOBJ",
								source_file[PATHLEN];
	register WORD	i, j, m = 1;

	printf( "\n3D2->POV Converter vers. %d.%d, (c) 1994 by Jochen Knaus (AURA), Freeware.\n\n",
					VERSION_A, VERSION_B );

	if( argc <= 1 )
	{
		puts( "Kommandozeile: [-vob] sourcefile [destination] [objectname]" );
		return( FALSE );										/* Keine Parameter ?										*/
	}

	/* Alle Eintr„ge nach Optionen untersuchen.	*/
	if( (argv[1])[0] == '-' )										/* "-" beginnt Optionen. */
	{
		if( strlen( argv[1] ) > 1 )								/* Einzelnes "-" */
		{
			for( j=1 ; j < strlen( argv[1] ); j++ )	/* Alle Optionenzeichen. */
			{
				switch( (argv[1])[j] )
				{
					case	'v':	pov_mode = 1; break;		/* Umschalten auf Ver. 1 */
					case	'b':	bounds = TRUE ; break;	/* Autobounding. */
					case	'o':	obj_split = TRUE;				/* Objektsplitting. */
				}
			}
		}
	}
	else m = 0;																	/* Filenamen im ersten Argument. */

	/* Dateinamen und Objektnamen (wenn vorhanden) bernehmen. */
	if( argc > ( 1 + m ) )
	{
		strncpy( source_file, argv[1+m], 127 );
		if( argc > ( 2 + m ) )
		{
			strncpy( def_file, argv[2+m], 127 );
			if( argc > ( 3 + m ) ) strncpy( def_name, argv[3+m], 63 );
		}
	}
	else																				/* Kein zu konvertierendes File ?	*/
	{
		fprintf( stderr, "Kein Cybersculptfile angegeben !" );
		return( FALSE );
	}

	if( strlen( source_file ) == 0 )							/* Kein 3D2-File angegeben ? */
	{ fputs( "No source (3D2) file.", stderr );
		return( -1 ); }

	/* Quelldatei (bin„r) ”ffnen. */
	if( ( source = fopen( source_file, "rb" ) ) == NULL )
	{
		fprintf( stdout, "Cannot access sourcefile <%s>.", source_file );
		return( FALSE );
	}

	/* Zieldatei (ASCII) erzeugen. */
	if( ( destin = fopen( def_file, "w+" ) ) == NULL )
	{
		fprintf( stderr, "Cannot create or access destinationfile <%s>.", def_file );
		return( FALSE );
	}

	/* Header lesen, bei Fehler abbrechen. */
	if( fread( header, 256, 1, source ) < 0 ) return( abbruch() );

	if( header[0] != 15618 ) 											/* 3D2-File Kennung ?				*/
	{
		fputs( "Kein 3D2 File...", stderr );
		return( abbruch() );
	}

	anz_obj = header[1];													/* Anzahl Objekte.					*/
	printf( "%s: convert %d object(s).\n\n", source_file, anz_obj );

	/* #declare <objektnamen> erzeugen.	*/
	sprintf( buffer, "#declare %s = union {%s", def_name, &buffer3[1] );
	fwrite( buffer, strlen(buffer), 1, destin );

	if( !obj_split && bounds )									/* Grenzwerte initialisieren? */
	{																							/* Ohne Objektsplitting muž */
		minmax[0] = INT_MAX; minmax[1] = INT_MIN;		/* Box um ganzes Objekt be- */
		minmax[2] = INT_MAX; minmax[3] = INT_MIN;		/* rechnet werden.					*/
		minmax[4] = INT_MAX; minmax[5] = INT_MIN;
	}

	/* Alle Objekte umsetzen, Bufferstring initialisieren.	*/
	for( i=0, buffer[0] = '\0'; i<anz_obj ; i++ )						/* Alle Objekte !	*/
	{
		fread( obj_name, 9, 1, source );							/* Objektnamen.	*/
		fread( &anz_punkte, 2, 1, source );						/* Anzahl Punkte (2 Bytes).	*/

		if( obj_split )																/* Objektsplitting ?	*/
		{
			strcat( buffer, "union{ " ); /* strcat( buffer, &buffer3[1] ); */

			if( obj_split && bounds )								/* Grenzwerte initialisieren. */
			{																					/* Bei Objektsplitting fr	*/
				minmax[0] = INT_MAX; minmax[1] = INT_MIN;	/* jedes einzelne Objekt	*/
				minmax[2] = INT_MAX; minmax[3] = INT_MIN;		/* Boundbox berechnen.	*/
				minmax[4] = INT_MAX; minmax[5] = INT_MIN;
			}
		}

		if( anz_punkte > 0 )
		{
			/* Speicher fr Punkte reservieren. */
			if( ( punkte = malloc( (long) (anz_punkte * 6) ) ) == NULL )
				return( abbruch() );
			else
				fread( punkte, anz_punkte*2, 3, source );			/* Punkte einlesen.  */

			if( bounds )													/* Objektgrenzen feststellen ? */
			{
				for( j = 0 ; j < anz_punkte ; j++ )		/* Objektextremas festellen. */
				{
					if( punkte[j*3+0] < minmax[0] ) minmax[0] = punkte[j*3+0];
					if( punkte[j*3+0] > minmax[1] ) minmax[1] = punkte[j*3+0];
					if( punkte[j*3+1] < minmax[2] ) minmax[2] = punkte[j*3+1];
					if( punkte[j*3+1] > minmax[3] ) minmax[3] = punkte[j*3+1];
					if( punkte[j*3+2] < minmax[4] ) minmax[4] = punkte[j*3+2];
					if( punkte[j*3+2] > minmax[5] ) minmax[5] = punkte[j*3+2];
				}
			}

			/* Anzahl Facetten. */
			fread( &anz_facetten, 2, 1, source );

			/* Objekt und Anzahl Facetten ausgeben. */
			printf( "%8s: %4d faces: ", obj_name, anz_facetten );

			/* Facettenspeicher reservieren. */
			if( ( facetten = malloc( (long) (anz_facetten * 8) ) ) == NULL )
			{	free( punkte ); return( abbruch() ); }
			else
				/* Facetten einlesen. */
				fread( facetten, anz_facetten*4, 2, source );

			/* Objektnamen als Kommentar in Source einfgen. */
			sprintf( buffer2, "/* %s */", obj_name );
			strcat( buffer, buffer2 );	strcat( buffer, &buffer3[1] );

			for( j = 0; j<anz_facetten ; j++ )							/* Facetten konvertieren. */
			{
				strcat( buffer, " triangle{" );

				/* Punkte wandeln... 2 Stellen Nachkomma (/100) (3D2-Fixkommaformat!),
					 Verkleinerung mssen in POV durchgefhrt werden.	*/
				for( m=0 ; m<3 ; m++ )
				{
					wandel[0] = (punkte[facetten[j*4+m]*3+0]);			/* x */
					wandel[1] = (punkte[facetten[j*4+m]*3+1]);			/* y */
					wandel[2] = (punkte[facetten[j*4+m]*3+2]);			/* z */
					wandel[3] = abs( wandel[0] );										/* Fr Nachkomma... */
					wandel[4] = abs( wandel[1] );
					wandel[5] = abs( wandel[2] );
					if( wandel[0] < 0 ) vorzeichen[0] = minus; else vorzeichen[0] = nullos;
					if( wandel[1] < 0 ) vorzeichen[1] = minus; else vorzeichen[1] = nullos;
					if( wandel[2] < 0 ) vorzeichen[2] = minus; else vorzeichen[2] = nullos;

					if( pov_mode == 1 )										/* POV vers.1 : Keine Kommas */
						sprintf( buffer2, "<%s%d.%d %s%d.%d %s%d.%d>",
											vorzeichen[0], wandel[3] / 100, wandel[3] % 100,
											vorzeichen[1], wandel[4] / 100, wandel[4] % 100,
											vorzeichen[2], wandel[5] / 100, wandel[5] % 100 );
					else
						sprintf( buffer2, "<%s%d.%d,%s%d.%d,%s%d.%d>",
											vorzeichen[0], wandel[3] / 100, wandel[3] % 100,
											vorzeichen[1], wandel[4] / 100, wandel[4] % 100,
											vorzeichen[2], wandel[5] / 100, wandel[5] % 100 );

					strcat( buffer, buffer2 );
				}
				strcat( buffer, buffer3 );									/* "}" und CR/LF anh„ngen.				*/

				if( j%10 == 0 )															/* Alle 10 Dreiecke schreiben.		*/
				{
					printf( "." );			/* Der User sieht das Proggy arbeiten und freut sich... */
					fwrite( buffer, strlen(buffer), 1, destin );
					buffer[0] = '\0';													/* Buffer zurcksetzen.						*/
				}
			} 	/* N„chstes Facette */


			if( strlen( buffer ) > 0 )										/* Restlichen Facetten schreiben. */
			{		fwrite( buffer, strlen(buffer), 1, destin ); buffer[0] = '\0'; }

			if( obj_split )																	/* Objektsplitting ?						*/
			{
				if( bounds ) write_bounds();									/* even. Grenzen schreiben.			*/
				fwrite( buffer3, strlen(buffer3), 1, destin );/* "union" abschliessen.				*/
			}

			free(punkte); free(facetten);										/* Objektspeicher freigeben.		*/
		}  /* "endif"... */

		puts( " done." );
	}		/* N„chstes 3D2-Objekt. */

	/* Falls fr gesamtes Objekt "bounded" gewnscht wurde. */
	if( bounds && !obj_split ) write_bounds();

	fwrite( buffer3, strlen(buffer3), 1, destin );			/* declare-union abschliežen.		*/
	fclose( source ); fclose( destin );									/* Files schliežen.							*/
	return( TRUE );
}

/* Bestimmt Grenzen und fgt diese an. */
VOID write_bounds()
{
	wandel[0] = abs( minmax[0] ); wandel[1] = abs( minmax[1] );
	wandel[2] = abs( minmax[2] ); wandel[3] = abs( minmax[3] );
	wandel[4] = abs( minmax[4] ); wandel[5] = abs( minmax[5] );
	if( minmax[0] < 0 ) vorzeichen[0] = minus; else vorzeichen[0] = nullos;
	if( minmax[1] < 0 ) vorzeichen[1] = minus; else vorzeichen[1] = nullos;
	if( minmax[2] < 0 ) vorzeichen[2] = minus; else vorzeichen[2] = nullos;
	if( minmax[3] < 0 ) vorzeichen[3] = minus; else vorzeichen[3] = nullos;
	if( minmax[4] < 0 ) vorzeichen[4] = minus; else vorzeichen[4] = nullos;
	if( minmax[5] < 0 ) vorzeichen[5] = minus; else vorzeichen[5] = nullos;

	if( pov_mode == 1 )
		sprintf( buffer, " bounded_by{box{<%s%d.%d %s%d.%d %s%d.%d><%s%d.%d %s%d.%d %s%d.%d>}}",
							vorzeichen[0], wandel[0] / 100, wandel[0] % 100,
							vorzeichen[2], wandel[2] / 100, wandel[2] % 100,
							vorzeichen[4], wandel[4] / 100, wandel[4] % 100,
							vorzeichen[1], wandel[1] / 100, wandel[1] % 100,
							vorzeichen[3], wandel[3] / 100, wandel[3] % 100,
							vorzeichen[5], wandel[5] / 100, wandel[5] % 100 );
	else
		sprintf( buffer, " bounded_by{box{<%s%d.%d,%s%d.%d,%s%d.%d><%s%d.%d,%s%d.%d,%s%d.%d>}}",
							vorzeichen[0], wandel[0] / 100, wandel[0] % 100,
							vorzeichen[2], wandel[2] / 100, wandel[2] % 100,
							vorzeichen[4], wandel[4] / 100, wandel[4] % 100,
							vorzeichen[1], wandel[1] / 100, wandel[1] % 100,
							vorzeichen[3], wandel[3] / 100, wandel[3] % 100,
							vorzeichen[5], wandel[5] / 100, wandel[5] % 100 );

	fwrite( buffer, strlen(buffer), 1, destin );	buffer[0] = '\0';
}

int abbruch()
{
	fclose( source );	fclose( destin );
	return( FALSE );
}