/**************************************************************************
  Copyright (C) 1992 Guy Moreillon
  All rights reserved.

  This software may be freely copied, modified, and redistributed
  provided that this copyright notice is preserved on all copies.

  You may not distribute this software, in whole or in part, as part of
  any commercial product without the express consent of the authors.

  There is no warranty or other guarantee of fitness of this software
  for any purpose.  It is provided solely "as is".
**************************************************************************/
/**************************************************************************

			     PREPRAD
		     (Scene preparation program)
		    	    Version 1.0
			       1992		    	    
		    	    
		  
		    	  Guy Moreillon
		    	  
**************************************************************************/

/**************************************************************************
  Fichier	: write.c
  Description	: Routines d'ecriture de la description de la scene
**************************************************************************/

#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>

#include <types.h>
#include <macros.h>
#include <misc.h>
#include "forms.h"
#include "preprad.h"
#include "write.h"

BOOLEAN get_scene_dir(char *sdir, char *fname)
/**************************************************************************
  But	: Rend le nom du repertoire OFF pour cette scene
  Entree: sdir	    : le nom du repertoire rendu
	  fname	    : le nom de fichier de la scene
  Sortie: TRUE si l'operation reussit
**************************************************************************/
{
  char	*c;

  c = strrchr(fname, '/');
  c++;
  strcpy(sdir, c);
  c = strrchr(sdir, '.');
  if (!c)
    return FALSE;
  *c = '\0';
  return TRUE;
}

void get_obj_fname(char *fname, char *sname, char *name)
/**************************************************************************
  But	: Compose le nom de fichier pour un objet d'une scene
  Entree: fname	    : le nom de fichier rendu
	  sname	    : le nom du repertoire OFF pour la scene
	  name	    : le nom de l'objet
  Sortie: TRUE si l'operation reussit
**************************************************************************/
{
  char	*c;
  STR	dum;

  strcpy(dum, name);
  for(c = dum; *c != NULL; c++)
    if (((*c < 'A') || (*c > 'Z')) &&
	((*c < 'a') || (*c > 'z')) &&
	((*c < '0') || (*c > '9')))
      *c = '_';

  strcpy(fname, sname);
  strcat(fname, "/");
  strcat(fname, dum);
  strcat(fname, ".off");
}

BOOLEAN write_off(OBJECT_OP object, char *fname)
/**************************************************************************
  But	: Ecrit l'objet dans un fichier OFF de nom fname
  Entree: object    : l'objet
	  fname	    : le nom de fichier OFF de l'objet
  Sortie: TRUE si l'operation reussit
**************************************************************************/
{
  STR	name;
  int	i, j;
  FILE	*file;

  strcpy(name, off_path);
  strcat(name, "/");
  strcat(name, fname);

  if ((file = fopen(name, "w")) == NULL)
    {
      fl_show_message("Can't open OFF file for writing\n",
		      name, "");
      return FALSE;
    }

  fprintf(file, "%d %d %d\n",
		object->object.pure.nb_polys * 3,
		object->object.pure.nb_polys,
		object->object.pure.nb_polys * 3);

  for(i = 0; i < object->object.pure.nb_polys; i++)
    for(j = 0; j < 3; j++)
      fprintf(file, "%f %f %f\n",
	      object->object.pure.polys[i].tri.poly.vertex[j].point[0],
	      object->object.pure.polys[i].tri.poly.vertex[j].point[1],
	      object->object.pure.polys[i].tri.poly.vertex[j].point[2]);

  for(i = 0; i < object->object.pure.nb_polys; i++)
    fprintf(file, "3\t%d %d %d\n", i*3+1, i*3+2, i*3+3);

  fclose(file);

  return TRUE;
}

void write_obj(FILE *fout, OBJECT_OP object, char *sdir, SCENE_OP scene)
/**************************************************************************
  But	: Ecrit la description d'un objet sur fichier
  Entree: fout	    : le fichier
	  object    : l'objet
	  sdir	    : le nom du repertoire OFF de la scene
	  scene	    : la scene
  Sortie: neant
**************************************************************************/
{
  STR	    obj_fname;
  int	    i;
  OBJECT_OP obj;

  fprintf(fout, "\nObject \"%s\" ", object->name);

  switch(object->type) {
    case assembly_type :
      fprintf(fout, "Assembly {\n");
      for(obj = object->object.assembly.sons; obj != NULL; obj = obj->next)
	write_obj(fout, obj, sdir, scene);
      fprintf(fout, "}\n");
      break;
    case composite_type :
      fprintf(fout, "Composite {\n");
      for(obj = object->object.composite.sons; obj != NULL; obj = obj->next)
	write_obj(fout, obj, sdir, scene);
      fprintf(fout, "}\n");
      break;
    case pure_type :
      get_obj_fname(obj_fname, sdir, object->name);
      write_off(object, obj_fname);
      fprintf(fout, "Pure {\n");
      if (object->object.pure.texmap.index > 0)
	{
	  VECTOR dir;

	  fprintf(fout, "  Texture\tFile\t\t%s\n",
		  get_short_name(
		    scene->textures[object->object.pure.texmap.index].name));
	  V_cross(dir, object->object.pure.texmap.t,
		       object->object.pure.texmap.s);
	  fprintf(fout, "\t\tDirection\t<%f %f %f>\n",
			dir[0], dir[1], dir[2]);
	  fprintf(fout, "\t\tViewUp\t\t<%f %f %f>\n",
			object->object.pure.texmap.t[0],
			object->object.pure.texmap.t[1],
			object->object.pure.texmap.t[2]);
	  fprintf(fout, "\t\tScale\t\t%f\n",
			1.0/object->object.pure.texmap.scale);
	}
      fprintf(fout, "  Reflectivity\t%f\n", object->object.pure.ro);
      fprintf(fout, "  Color\t\t<%f %f %f>\n",
		    object->object.pure.color[0],
		    object->object.pure.color[1],
		    object->object.pure.color[2]);
      fprintf(fout, "  Emission\t%f\n", object->object.pure.E);
      fprintf(fout, "  Shadows\t");
      if (object->object.pure.shadows)
	fprintf(fout, "On\n");
      else
	fprintf(fout, "Off\n");
      fprintf(fout, "  File\t\t%s\n", obj_fname);
      fprintf(fout, "}\n");
      break;
    default :
      break;
  }
}

BOOLEAN write_scene(SCENE_OP scene, char *filename)
/**************************************************************************
  But	: Ecrit la description de la scene sur fichier
  Entree: scene	    : la scene
	  filename  : le nom du fichier
  Sortie: TRUE si l'operation reussit
**************************************************************************/
{
  FILE	    *fout;
  DIR	    *dir;
  OBJECT_OP obj;
  STR	    scene_dir, path;

  if ((fout = fopen(filename, "w")) == NULL)
    {
      fl_show_message("Can't open file for writing :", filename, "");
      return FALSE;
    }

  fprintf(fout, "; This file was generated by Preprad,\n");
  fprintf(fout, "; a scene hierarchy preparation program for Rad\n\n");

  fprintf(fout, "\"%s\"\n", scene->scene->name);
  if (scene->state.visu.mod[0][0] == 0.0)
    fprintf(fout, "UpAxis x_axis\n");
  else if (scene->state.visu.mod[0][0] == -1.0)
    fprintf(fout, "UpAxis z_axis\n");
  else
    fprintf(fout, "UpAxis y_axis\n");

  if (!get_scene_dir(scene_dir, filename))
    {
      fclose(fout);
      fl_show_message("Can't figure out scene's directory name",
		      "Nothing saved", "");
      return FALSE;
    }

  strcpy(path, off_path);
  strcat(path, "/");
  strcat(path, scene_dir);

  if ((dir = opendir(path)) == NULL)
    {
      if (mkdir(path, 0755))
	{
	  fl_show_message("Can't create new OFF directory:",
			  path, "");
	  return FALSE;
	}
    }
  else
    closedir(dir);

  for(obj = scene->scene->object.assembly.sons; obj != NULL; obj = obj->next)
    write_obj(fout, obj, scene_dir, scene);

  fclose(fout);

  return TRUE;
}
