/***********************************************************************/
/* Open Visualization Data Explorer                                    */
/* (C) Copyright IBM Corp. 1989,1999                                   */
/* ALL RIGHTS RESERVED                                                 */
/* This code licensed under the                                        */
/*    "IBM PUBLIC LICENSE - Open Visualization Data Explorer"          */
/***********************************************************************/

#include <dxconfig.h>


#define tdmInitScreen_c

#ifndef	lint
static char *rcsid[] = {"$Header: /home/gda/dxcvs/dx/src/exec/hwrender/hwInitScreen.c,v 1.3 1999/05/10 15:45:34 gda Exp $"};
#endif


/*
 * Environment:		Risc System 6000
 * Current Source:	$Source: /home/gda/dxcvs/dx/src/exec/hwrender/hwInitScreen.c,v $
 * Author:		Dave Owens
 *
 */

#include <stdio.h>
#ifdef DXD_WIN
#include <signal.h>
#else
#include <sys/signal.h>
#endif
#include <math.h>

#include "hwDeclarations.h"
#include "hwWindow.h"
#include "hwPortLayer.h"
#include "hwClientMessage.h"
#include "hwMemory.h"

#include "hwDebug.h"

typedef Error (*Handler)(int, Pointer);

extern _dxfCacheState(char *, dxObject, dxObject, int);

Error
_dxfInitRenderObject(WinP win)
{
  /*
   *  This function is called each time we are starting to render a new object.
   *  This means either the camera or the object has changed.
   */
  
  Vector up ;
  int projection, pixwidth, pixheight ;
  Point to, box[8], from, zaxis;
  float width, aspect, fov ;
  float mat[4][4], dist, Near, Far ;
  dxMatrix rot ;
  DEFWINDATA(win) ;
  DEFPORT(PORT_HANDLE) ;

  ENTRY(("_dxfInitRenderObject(0x%x)",win));

  /* mark the software image and approximation buffers invalid */
  SW_BUF_CURRENT = FALSE ;
  SAVE_BUF_VALID = FALSE ;


  /* get view coordinate system */
  if (! DXGetView(CAMERA, &from, &to, &up)) {
    EXIT(("ERROR: unable to get camara view"));
    DXErrorReturn (ERROR_INVALID_DATA, "unable to get camera view") ;
  }

  /* get camera resolution */
  DXGetCameraResolution(CAMERA, &pixwidth, &pixheight) ;

  /* get view orientation matrix */
  rot = DXGetCameraRotation(CAMERA) ;

  /* get projection parameters */
  if (DXGetOrthographic(CAMERA, &width, &aspect))
  {
      fov = 0.0;
      projection = 0 ;
  }
  else if (DXGetPerspective(CAMERA, &fov, &aspect))
  {
      width = 0.0;
      projection = 1 ;
  }
  else {
    EXIT(("ERROR: unable to get projection data"));
    DXErrorReturn (ERROR_INVALID_DATA, "unable to obtain projection data") ;
  }

  _dxfSetCurrentView(win, (float *)&to, (float *)&from, (float *)&up, fov, width);

  /* compute view zaxis */
  zaxis = DXSub(to, from) ;
  dist = (float)DXLength(zaxis) ;
  zaxis.x /= dist ; zaxis.y /= dist ; zaxis.z /= dist ;

  if (DXBoundingBox(OBJECT, box))
    {
      /* find suitable near and far clip plane distances */
      _dxfGetNearFar(projection, pixwidth, projection? fov: width,
		    (float *)&from, (float *)&zaxis, (float (*)[3])box,
		    &Near, &Far);

      /* set bounding box for interactors that need it */
      _dxfSetInteractorBox(INTERACTOR_DATA, (float (*)[3])box) ;
    }
  else
    {
      PRINT(("Could not obtain bounding box!")) ;
      DXResetError() ;
      Far =   10000.0 ;
      Near = -10000.0 ;
    }

  /* set up view projection */
  if (projection)
    {
      _dxf_SET_PERSPECTIVE_PROJECTION(PORT_CTX, fov, aspect, Near, Far) ;
      _dxfSetInteractorViewInfo(INTERACTOR_DATA,
			       (float *)&from, (float *)&to, (float *)&up,
			       dist, fov, 0, aspect, 1, Near, Far) ;

      PRINT(("set perspective fov = %f Near = %d Far = %f",
	     RAD2DEG(2 * atan(fov/2)), Near, Far));
    }
  else
    {
      _dxf_SET_ORTHO_PROJECTION(PORT_CTX, width, aspect, Near, Far) ;
      _dxfSetInteractorViewInfo(INTERACTOR_DATA,
			       (float *)&from, (float *)&to, (float *)&up,
			       dist, 0, width, aspect, 0, Near, Far) ;

      PRINT(("set ortho view width = %f height = %f Near = %f Far = %f",
	     width, width*aspect, Near, Far));
    }

  /* set up hardware viewing matrix and software shadow */
  mat[0][0] = rot.A[0][0] ; mat[0][1] = rot.A[0][1] ; mat[0][2] = rot.A[0][2] ;
  mat[1][0] = rot.A[1][0] ; mat[1][1] = rot.A[1][1] ; mat[1][2] = rot.A[1][2] ;
  mat[2][0] = rot.A[2][0] ; mat[2][1] = rot.A[2][1] ; mat[2][2] = rot.A[2][2] ;
  mat[3][0] =    rot.b[0] ; mat[3][1] =    rot.b[1] ; mat[3][2] =    rot.b[2] ;

  mat[0][3] = 0.0 ; mat[1][3] = 0.0 ; mat[2][3] = 0.0 ; mat[3][3] = 1.0 ;

  _dxf_LOAD_MATRIX (PORT_CTX, mat) ;
  if(projection)
    _dxfInitStack (MATRIX_STACK, pixwidth, mat, projection,
		   fov, aspect, Near, Far) ;
  else
    _dxfInitStack (MATRIX_STACK, pixwidth, mat, projection,
		   width, aspect, Near, Far) ;

  _dxfCacheState(ORIGINALWHERE, OBJECT, CAMERA, 1);

  PRINT(("View matrix:"));
  MPRINT(mat);
  EXIT(("OK"));
  return OK ;
}

int
_dxfEndRenderPass (WinP win)
{
  DEFWINDATA(win) ;
  DEFPORT(PORT_HANDLE) ;

  ENTRY(("_dxfEndRenderPass(0x%x)",win));

  if ( _dxfTrySaveBuffer(win))
  {
      SAVEBUFCAMERATAG = CAMERA_TAG;
      SAVEBUFOBJECTTAG = OBJECT_TAG;
  }


  /*
   *  Redraw any defined interactor echos.  The echos can't be saved by
   *  _dxfTrySaveBuffer() since they are updated more frequently than once
   *  per rendering pass.
   */
  
  _dxfRedrawInteractorEchos(INTERACTOR_DATA) ;

  EXIT((""));
}

int
_dxfEndSWRenderPass (WinP win, Field image)
{
  DEFWINDATA(win) ;

  ENTRY(("_dxfEndSWRenderPass(0x%x, 0x%x)",win,image));

  if (image)
    DXDelete((Pointer)image);

  _dxfRedrawInteractorEchos(INTERACTOR_DATA) ;

  EXIT((""));
}

static int
_HandleExitErrors (Display *dpy, XErrorEvent *rep)
{
  ENTRY(("_HandleExitErrors (0x%x, 0x%x)",dpy, rep));

  if (rep->error_code == BadWindow)
    {
      EXIT(("ERROR: BadWindow error ignored"));
      return 1 ;
    }

  if((rep->error_code == 8) && (rep->request_code == 2))
  {
     EXIT(("ERROR: BadMatch error ignored\n"));
     return(1);
  }

  _dxfSetXError (dpy, rep) ;

  EXIT((""));
  return 1;
}

Error
_dxfEndRenderModule (tdmChildGlobalP globals)
{
  int i ;
  DEFGLOBALDATA(globals) ;
  DEFPORT(PORT_HANDLE) ;

  /*
   *  This function is called whenever the global variable cache entry is
   *  deleted.
   */

  DEBUG_MARKER("_dxfEndRenderModule ENTRY");
  ENTRY(("_dxfEndRenderModule(0x%x)",globals));

  /* the window is sometimes already destroyed before calling gexit() */
  XSetErrorHandler(_HandleExitErrors) ;

  if (globals->cacheId)
    {
      tdmFree(globals->cacheId) ;
      globals->cacheId = NULL ;
    }
      
  _dxfDestroyAllInteractors(INTERACTOR_DATA) ;
  
  if (OBJECT)
    {
      DXDelete(OBJECT) ;
      OBJECT = NULL ;
    }

  if (GATHER)
    {
      DXDelete(GATHER);
      GATHER = NULL;
    }

  if (CAMERA)
    {
      DXDelete(CAMERA) ;
      CAMERA = NULL ;
    }

  if (SW_BUF)
    {
      tdmFree(SW_BUF);
      SW_BUF = NULL;
    }
  if (MATRIX_STACK)
    {
      _dxfFreeStack(MATRIX_STACK) ;
      MATRIX_STACK = NULL ;
    }

  /* delete graphics API's data structures */
   _dxf_DESTROY_WINDOW(LWIN) ;

  _dxfSendClientMessage (DPY, PARENT_WINDOW, GLShutdown, 0) ;
  
  /* delete callback for display's connection */
  PRINT(("deleting callback for display connection %d",
	 ConnectionNumber(DPY)));

  DXRegisterInputHandler
    ((Handler) NULL, ConnectionNumber(DPY), NULL) ;
  
  if (PORT_HANDLE)
    {
      _dxfDeletePortHandle(PORT_HANDLE);
    }

  if (MESHHASH)
    _dxf_DeleteObjectHash(MESHHASH);

  if (TEXTUREHASH)
    _dxf_DeleteObjectHash(TEXTUREHASH);

  /* goodbye render instance */
  tdmFree(globals) ; 

  tdmCheckAllocTable(3);

  EXIT(("OK"));
  DEBUG_MARKER("_dxfEndRenderModule EXIT");
  return OK ;
}

#undef tdmInitScreen_c


