/*
======================================================================
lwmod.h

Ernie Wright  01 Jun 05

LightWave Modeler interface.
====================================================================== */

#include <stdio.h>
#include <stdlib.h>
#define CS_MACROS 1
#include "lwmod.h"
#include "lib.h"
#include "def.h"


static ModData md;


static int ginit( GlobalFunc *global )
{
   unsigned long info;
   int major, minor;

   md.global = global;

   info = ( unsigned long ) global( LWPRODUCTINFO_GLOBAL, GFUSE_TRANSIENT );
   if ( !info ) return 0;

   md.build = LWINF_GETBUILD( info );
   md.product = info & LWINF_PRODUCT;

   major = LWINF_GETMAJOR( info );
   minor = LWINF_GETMINOR( info );
   md.version = ( float )( major + minor / 10.0 );

   info = ( unsigned long ) global( LWSYSTEMID_GLOBAL, GFUSE_TRANSIENT );
   md.serialno = info & LWSYS_SERIALBITS;

   md.locale = ( unsigned long ) global( LWLOCALEINFO_GLOBAL, GFUSE_TRANSIENT );

   md.monf    = global( LWDYNAMONITORFUNCS_GLOBAL, GFUSE_TRANSIENT );
   md.query   = global( LWSTATEQUERYFUNCS_GLOBAL, GFUSE_TRANSIENT );
   md.surface = global( LWSURFACEFUNCS_GLOBAL, GFUSE_TRANSIENT );
   md.font    = global( LWFONTLISTFUNCS_GLOBAL, GFUSE_TRANSIENT );
   md.hdi     = global( LWHOSTDISPLAYINFO_GLOBAL, GFUSE_TRANSIENT );
   md.filereq = global( LWFILEREQFUNC_GLOBAL, GFUSE_TRANSIENT );
   md.message = global( LWMESSAGEFUNCS_GLOBAL, GFUSE_TRANSIENT );
   md.dirinfo = global( LWDIRINFOFUNC_GLOBAL, GFUSE_TRANSIENT );

   return md.monf && md.query && md.surface && md.font && md.hdi && md.filereq
      && md.message && md.dirinfo;
}


ModData *lwInit( GlobalFunc *global, LWModCommand *local, int teslvl )
{
   if ( !ginit( global )) return NULL;

   md.local = local;
   md.cmderror = CSERR_NONE;
   md.opsel = OPSEL_GLOBAL;
   lib_set_polygonalization( teslvl, teslvl );

   lwInitScene();

   return &md;
}


/*
======================================================================
lwDone()

Finish up the session.  We make sure the mesh edit and the monitor are
closed if they're open.
====================================================================== */

void lwDone( void )
{
   lwMeshDone( EDERR_NONE, 0 );
   lwMonitorDone();
   return;
}


int lwMeshBegin( int pntbufsize, int polbufsize, EltOpSelect select )
{
   if ( !md.edit )
      md.edit = md.local->editBegin( pntbufsize, polbufsize, select );
   return md.edit != NULL;
}


void lwMeshDone( EDError ederror, int selm )
{
   if ( md.edit ) {
      md.edit->done( md.edit->state, ederror, selm );
      md.edit = NULL;
   }
}


static int edit_state( int editing )
{
   if ( editing && !md.edit )
      return lwMeshBegin( 0, 0, OPSEL_GLOBAL );
   else if ( !editing && md.edit ) {
      lwMeshDone( EDERR_NONE, 0 );
      return 1;
   }
}


const char *lwGetCurrentObject( void )
{
   return md.query->object();
}


LWSurfaceID *lwGetSurfacesByName( char *objname, char *surfname )
{
   return md.surface->byName( surfname, objname );
}


LWSurfaceID lwCreateSurface( char *objname, char *surfname )
{
   edit_state( 0 );
   return md.surface->create( objname, surfname );
}


int lwSetDefaultSurface( char *surfname )
{
   static LWCommandCode ccode;
   DynaValue argv;

   edit_state( 0 );

   argv.type = DY_SURFACE;
   argv.str.buf = surfname;
   argv.str.bufLen = 0;

   LOOKUP( "SURFACE" );
   EXECUTE( 1, &argv );
   return OK;
}


int lwSetSurfEdSurface( char *objname, char *surfname )
{
   char cmd[ 128 ];

   edit_state( 0 );

   sprintf( cmd, "Surf_SetSurf \"%s\" \"%s\"", surfname, objname );
   md.cmderror = md.local->evaluate( md.local->data, cmd );
   return !md.cmderror;
}


int lwSetSurfaceColor( char *channel, double color[ 3 ] )
{
   char cmd[ 128 ];

   edit_state( 0 );

   sprintf( cmd, "Surf_SetColor %s %g %g %g", channel,
      color[ 0 ], color[ 1 ], color[ 2 ] );
   md.cmderror = md.local->evaluate( md.local->data, cmd );
   return !md.cmderror;
}


int lwSetSurfaceFloat( char *channel, double val )
{
   char cmd[ 128 ];

   edit_state( 0 );

   sprintf( cmd, "Surf_SetFloat %s %g", channel, val );
   md.cmderror = md.local->evaluate( md.local->data, cmd );
   return !md.cmderror;
}


LWPntID lwAddPoint( double *coord )
{
   edit_state( 1 );
   return md.edit->addPoint( md.edit->state, coord );
}


LWPolID lwAddFace( int npoints, LWPntID *ptarray )
{
   edit_state( 1 );
   return md.edit->addFace( md.edit->state, NULL, npoints, ptarray );
}


int lwMergePoints( double d )
{
   static LWCommandCode ccode;
   DynaValue argv;

   edit_state( 0 );

   if ( d >= 0.0 ) {
      argv.type = DY_FLOAT;
      argv.flt.value = d;
   }
   else argv.type = DY_NULL;

   LOOKUP( "MERGEPOINTS" );
   EXECUTE( 1, &argv );
   return OK;
}


void lwMonitorBegin( char *title, char *caption, int total )
{
   if ( md.mon ) return;
   if ( md.mon = md.monf->create( title, caption ))
      md.mon->init( md.mon->data, total );
}


int lwMonitorStep( int step )
{
   if ( !md.mon ) return 0;
   return md.mon->step( md.mon->data, step );
}


void lwMonitorDone( void )
{
   if ( !md.mon ) return;
   md.mon->done( md.mon->data );
   md.monf->destroy( md.mon );
   md.mon = NULL;
}
