////////////////////////////////////////////////////////////////////////////////
//
//    
//
////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"

#include <GL\gl.h>
#include "cFrameEvent.h"

#pragma comment(lib, "opengl32.lib")
#pragma comment(lib, "glu32.lib")
#pragma comment(lib, "glaux.lib")

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

extern AFX_MODULE_STATE * pModuleState;

//extern cBaseEvent* NewDocumentEvent( reference doc );

int DocumentFrameEvent::redrawType = 0;

//-------------------------------------------------------------------------------
//      
// ---
cBaseEvent * NewDocumentFrameEvent( IDocumentFrame * documentFrame, reference doc, int redrawType = 0 ) 
{
  cBaseEvent * res = NULL;
  if ( doc && documentFrame ) {
    if ( !cBaseEvent::FindEvents( ntDocumentFrameNotify, doc, -1, documentFrame ) ) {
//      NewDocumentEvent( doc );
      res = new DocumentFrameEvent( documentFrame, doc );
      if ( !res->Advise() ) {
        delete res;
        res = NULL;
      }
    }
    DocumentFrameEvent::redrawType = redrawType;
  }
  return res;
}

//-------------------------------------------------------------------------------
//  
// ---
void RedrawFace( IPart * topPart, IPart * nextPart, IFaceDefinition * fDef0 )
{
  bool transform = topPart && topPart != nextPart;
  if ( fDef0 ) 
  {
    //   
    ITessellationPtr tess( fDef0->GetTessellation(), false );
    if ( tess ) 
    {
      _variant_t poins;
      _variant_t indexes;
      _variant_t normals;
      //     
      tess->GetFacetPoints( &poins, &indexes );
      tess->GetFacetNormals( &normals );
      if ( indexes.vt == (VT_ARRAY | VT_I4) && indexes.parray &&
           poins.vt   == (VT_ARRAY | VT_R8) && poins.parray   && 
           normals.vt == (VT_ARRAY | VT_R8) && normals.parray ) 
      {
        //           
        int count = indexes.parray->rgsabound[0].cElements - indexes.parray->rgsabound[0].lLbound;
        int HUGEP * pIndexes = NULL; //     
    
        if ( indexes.parray->cDims == 1 && count && !(count % 3) ) 
        {
          ::SafeArrayAccessData( indexes.parray, (void HUGEP* FAR*)&pIndexes );
        }

        int count1 = poins.parray->rgsabound[0].cElements - poins.parray->rgsabound[0].lLbound;
        double HUGEP * pPoints = NULL; //    
        if ( poins.parray->cDims == 1 && count1 && !(count1 % 3) ) 
        {
          ::SafeArrayAccessData( poins.parray, (void HUGEP* FAR*)&pPoints );
        }
    
        int count2 = normals.parray->rgsabound[0].cElements - normals.parray->rgsabound[0].lLbound;
        double HUGEP * pNormals = NULL; //    
        if ( normals.parray->cDims == 1 && count1 && !(count1 % 3) ) 
        {
          ::SafeArrayAccessData( normals.parray, (void HUGEP* FAR*)&pNormals );
        }

        if ( pIndexes && pPoints && pNormals )
        {
          int trianglesCount = count / 3;

          for ( int i = 0, j = 0; i < trianglesCount; i++, j++ ) 
          {
            glBegin( GL_TRIANGLES );
              double x, y, z;
              int index = pIndexes[j] * 3; //   
              //    
                x = pPoints[index++];      //   
                y = pPoints[index++];
                z = pPoints[index];
                if ( transform )
                  //          
                  topPart->TransformPoint( &x, &y, &z, nextPart ); 
                glColor3d( 1.0f, 0.0f, 0.0f );
                glVertex3d( x, y, z );
              index = pIndexes[j++] * 3;   //    
                x = pNormals[index++];     //    
                y = pNormals[index++];
                z = pNormals[index];
                glNormal3d( x, y, z );
              
              index = pIndexes[j] * 3;     //   
                x = pPoints[index++];      //   
                y = pPoints[index++];
                z = pPoints[index];
                if ( transform )
                  //          
                  topPart->TransformPoint( &x, &y, &z, nextPart );
                glColor3d( 0.0f, 1.0f, 0 );
                glVertex3d( x, y, z );
              index = pIndexes[j++] * 3;   //    
                x = pNormals[index++];     //    
                y = pNormals[index++];
                z = pNormals[index];
                glNormal3d( x, y, z );
        
              index = pIndexes[j] * 3;     //   
                x = pPoints[index++];      //   
                y = pPoints[index++];
                z = pPoints[index];
                if ( transform )
                  //          
                  topPart->TransformPoint( &x, &y, &z, nextPart );
                glColor3d( 0.0f, 0.0f, 1.0f );
                glVertex3d( x, y, z );
              index = pIndexes[j] * 3;     //    
                x = pNormals[index++];     //    
                y = pNormals[index++];
                z = pNormals[index];
                glNormal3d( x, y, z );
            glEnd();
          }
        }
        if ( pIndexes )
          ::SafeArrayUnaccessData( indexes.parray ); //     
        if ( pPoints )
          ::SafeArrayUnaccessData( poins.parray );   //    
        if ( pNormals )
          ::SafeArrayUnaccessData( normals.parray ); //    
      }
    }
  }
}

//-------------------------------------------------------------------------------
//  
// ---
void RedrawFaces( IPart * topPart, IPart * nextPart, IEntityCollection * faces )
{
  for ( int ie = 0, count = faces ? faces->GetCount() : 0; ie < count; ie++ ) 
  {
    IEntityPtr face0( faces->GetByIndex(ie), false ); //    
    if ( (bool)face0 && face0->IsCreated() )                //   
    {
      //   
      IFaceDefinitionPtr fDef0( IUnknownPtr( face0->GetDefinition(), false ) );
      RedrawFace( topPart, nextPart, fDef0 );
    }
  }
}


//-------------------------------------------------------------------------------
//  
// ---
void RedrawFaces( IPart * topPart, IPart * nextPart, IFaceCollection * faces )
{
  for ( int ie = 0, count = faces ? faces->GetCount() : 0; ie < count; ie++ ) 
  {
    IFaceDefinitionPtr face( faces->GetByIndex(ie), false ); //    
    if ( (bool)face )                //   
    {
      RedrawFace( topPart, nextPart, face );
    }
  }
}

//-------------------------------------------------------------------------------
//       
// ---
void RedrawModelFaces( IPart * topPart, IPart * nextPart )
{
  if ( nextPart && nextPart->IsDetail() && !nextPart->GetHidden() && !nextPart->GetExcluded() )
  {
    switch ( DocumentFrameEvent::redrawType )
    {
      case 0: //    
      {
        IEntityCollectionPtr faces( nextPart->EntityCollection(o3d_face), false );
        RedrawFaces( topPart, nextPart, faces );
        break;
      }  
      case 1: //    
      {
        IFeaturePtr partFeature( nextPart->GetFeature(), false ); 
        //    
        IFeatureCollectionPtr featColl( partFeature->SubFeatureCollection(false   //    
                                                                       , true), //   
                                                                       false ); 
        if ( featColl )
        {
          for ( int i = 0, count = featColl->GetCount(); i < count; i++ )
          {
            IFeaturePtr nextFeature( featColl->GetByIndex(i), false );
            IEntityCollectionPtr faces( nextFeature->EntityCollection(o3d_face), false );
            if ( faces )
              RedrawFaces( topPart, nextPart, faces );
          }
        }
        break;
      }
      case 2: //      
      {
        IBodyCollectionPtr bodyColl( nextPart->BodyCollection(), false );
        if ( bodyColl )
        {
          for ( int i = 0, count = bodyColl->GetCount(); i < count; i++ )
          {
            IBodyPtr body( bodyColl->GetByIndex(i), false/*AddRef*/ );
            if ( body )
            {
              IFaceCollectionPtr faceColl( body->FaceCollection(), false/*AddRef*/ );
              RedrawFaces( topPart, nextPart, faceColl );
            }
          }
        }
        break;
      }
      case 3: //      
      {
        IBodyPtr body( nextPart->GetMainBody(), false );
        if ( body )
        {
          IFaceCollectionPtr faceColl( body->FaceCollection(), false/*AddRef*/ );
          RedrawFaces( topPart, nextPart, faceColl );
        }
        break;
      }
    }
  }
}


void RecursiveDraw( IPart * pTopPart, IFeatureCollection * coll );

//-------------------------------------------------------------------------------
//    
// ---
void RecursiveDraw( IPart * pTopPart, IFeature * nextFeature )
{
  if ( pTopPart && nextFeature )
  {
    _bstr_t name( nextFeature->GetName() );
    IUnknownPtr unkObj( nextFeature->GetObject(), false );

    switch ( nextFeature->GetType() )
    {
      case o3d_part:
      {  
        IPartPtr pPart( unkObj );
        if ( (bool)pPart && pPart->IsDetail() )
        {
          RedrawModelFaces( pTopPart, pPart ); //   
        }
        else
        {
          //    
          IFeatureCollectionPtr featColl( nextFeature->SubFeatureCollection(false   //    
                                                                           , true), //    -   
                                                                           false );  
          RecursiveDraw( pTopPart, featColl ); //     
        }
        break;
      }
      case o3d_entity:
      {
        IEntityPtr entity( unkObj );
        if ( entity )
        {
          if ( entity->GetExcluded() || //  
               entity->GetHidden()  )   //  
            break;

          if ( DocumentFrameEvent::redrawType == 1 ) //   
          {
            //       
            IPartPtr parent( entity->GetParent(), false );
            if ( (bool)parent && !parent->IsDetail() )
            {
              IEntityCollectionPtr coll( nextFeature->EntityCollection(o3d_face), false );
              if ( (bool)coll )
              {
                for ( int i = 0, count = coll->GetCount(); i < count; i++ )
                {
                  //       
                  IEntityPtr entity( coll->GetByIndex(i), false );
                  if ( entity )
                  {
                    IPartPtr parent( entity->GetParent(), false );
                    if ( parent )
                    {
                      IFaceDefinitionPtr faceDef( IUnknownPtr( entity->GetDefinition(), false ) );
                      RedrawFace( pTopPart, parent, faceDef );
                    }
                  }
                }
                break;
              }
            }
          }
        }

        //    SubFeatureCollection
        IFeatureCollectionPtr featColl( nextFeature->SubFeatureCollection( false, //    
                                                                           true   //    -   
                                                                           ), false );
        if ( featColl )
        {
          RecursiveDraw( pTopPart, featColl );
          break;
        }
        break;
      }
      case o3d_unknown:
      { 
        //    SubFeatureCollection
        IFeatureCollectionPtr featColl( nextFeature->SubFeatureCollection( false, //    
                                                                           true ),
                                                                           false );
        if ( featColl )
        {
          RecursiveDraw( pTopPart, featColl );
        }
      }
    }
  }
}


//-------------------------------------------------------------------------------
//   
// ---
void RecursiveDraw( IPart * pTopPart, IFeatureCollection * coll )
{
  if ( coll )
    for ( int i = 0, count = coll->GetCount(); i < count; i++ )
    {
      IFeaturePtr nextFeature( coll->GetByIndex(i), false );
      if ( !nextFeature->GetExcluded() )
        RecursiveDraw( pTopPart, nextFeature );
    }
}


////////////////////////////////////////////////////////////////////////////////
//
// DocumentEvent  -    
//
////////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------
//
// ---
DocumentFrameEvent::DocumentFrameEvent(LPUNKNOWN I, reference doc ):
    cBaseEvent(ntDocumentFrameNotify, NULL , 0, I, doc ), down( false )
{
  m_params.pContainer = doc;
}


//-------------------------------------------------------------------------------
//
// ---
DocumentFrameEvent::~DocumentFrameEvent()
{
}

//-----------------------------------------------------------------------------
//
// ---
LPUNKNOWN DocumentFrameEvent::GetUnknown(){
  m_xDocumentFrameNotify.AddRef();
  return &m_xDocumentFrameNotify;
}

//-----------------------------------------------------------------------------
//
// ---
STDMETHODIMP_(ULONG) DocumentFrameEvent::XDocumentFrameNotify::Release()
{
	METHOD_PROLOGUE_EX_(DocumentFrameEvent, DocumentFrameNotify)
	return (ULONG)pThis->InternalRelease();
}

//-----------------------------------------------------------------------------
//
// ---
STDMETHODIMP_(ULONG) DocumentFrameEvent::XDocumentFrameNotify::AddRef()
{
	METHOD_PROLOGUE_EX_(DocumentFrameEvent, DocumentFrameNotify)
	return (ULONG)pThis->InternalAddRef();
}


//-----------------------------------------------------------------------------
//
// ---
STDMETHODIMP DocumentFrameEvent::XDocumentFrameNotify::QueryInterface(
	REFIID iid, LPVOID* ppvObj )
{
	METHOD_PROLOGUE_EX_(DocumentFrameEvent, DocumentFrameNotify)

	ASSERT(AfxIsValidAddress(ppvObj, sizeof(LPVOID), FALSE));

	if ( IsEqualIID(iid, IID_IUnknown) ||
		   IsEqualIID(iid, IID_IDocumentFrameNotify) )
	{
		*ppvObj = this;
		AddRef();
		return S_OK;
	}

	return E_NOINTERFACE;
}

//-----------------------------------------------------------------------------
//      notifyType
// ---
STDMETHODIMP_(VARIANT_BOOL) DocumentFrameEvent::XDocumentFrameNotify::IsNotifyProcess( int notifyType )
{
	return  notifyType >= frBeginPaint && notifyType <= frCloseFrame;
}


//-----------------------------------------------------------------------------
//    (  3D   )
// ---
VARIANT_BOOL STDMETHODCALLTYPE DocumentFrameEvent::XDocumentFrameNotify::BeginPaint( IUnknown __RPC_FAR * paintObj ) {
  return true;
}  

double  xMax = 0;


//-----------------------------------------------------------------------------
//    (  3D   )
// ---
VARIANT_BOOL STDMETHODCALLTYPE DocumentFrameEvent::XDocumentFrameNotify::ClosePaint( IUnknown __RPC_FAR * paintObj ) {
  return true;
}


//-----------------------------------------------------------------------------
//   
// ---
VARIANT_BOOL STDMETHODCALLTYPE DocumentFrameEvent::XDocumentFrameNotify::MouseDown( 
    /* [in] */ short nButton,
    /* [in] */ short nShiftState,
    /* [in] */ long x,
    /* [in] */ long y ) {
	METHOD_PROLOGUE_EX_(DocumentFrameEvent, DocumentFrameNotify)
  pThis->down = true;
  return true;
}


//-----------------------------------------------------------------------------
//   
// ---
VARIANT_BOOL STDMETHODCALLTYPE DocumentFrameEvent::XDocumentFrameNotify::MouseUp( 
    /* [in] */ short nButton,
    /* [in] */ short nShiftState,
    /* [in] */ long x,
    /* [in] */ long y ) {
	METHOD_PROLOGUE_EX_(DocumentFrameEvent, DocumentFrameNotify) //    
  pThis->down = false; 
  return true;
}


//-----------------------------------------------------------------------------
//   
// ---
VARIANT_BOOL STDMETHODCALLTYPE DocumentFrameEvent::XDocumentFrameNotify::MouseDblClick( 
    /* [in] */ short nButton,
    /* [in] */ short nShiftState,
    /* [in] */ long x,
    /* [in] */ long y ) {
  return true;
}


//-----------------------------------------------------------------------------
//     
// ---
VARIANT_BOOL STDMETHODCALLTYPE DocumentFrameEvent::XDocumentFrameNotify::BeginPaintGL( long drawMode )
{
	METHOD_PROLOGUE_EX_(DocumentFrameEvent, DocumentFrameNotify) //    
  VARIANT_BOOL res = TRUE;
  if ( drawMode == vm_Shaded ) 
  {
    IDocument3DPtr doc3D( ksGetActive3dDocument(), false/*AddRef*/ );
    IPartPtr pTopPart( doc3D ? doc3D->GetPart(pTop_Part) : NULL, false/*AddRef*/ );
    if ( (bool)doc3D && (bool)pTopPart ) 
    {

      //   
      ::glPushAttrib( GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT );

      //   
      ::glClearColor( 1.0f, 1.0f, 1.0f, 1.0f );    
      ::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
      ::glDisable( GL_LIGHTING );
      ::glEnable( GL_DEPTH_TEST );

      int start = GetTickCount();
      if ( doc3D->IsDetail() ) 
        RedrawModelFaces( pTopPart, pTopPart );            //   
      else
      {
        IFeaturePtr partFeature( pTopPart->GetFeature(), false/*AddRef*/ );
        if ( partFeature )
          RecursiveDraw( pTopPart, partFeature );          //    
      }
      int end = GetTickCount();
      TRACE( _T("ClosePaintGL %i"), end - start );
/*
      glBegin(GL_LINES);
        glColor3d(0.0, 1.0, 0.0);
        glVertex3d( 0, 0, 0 );
        glVertex3d( 0, 1000, 0 );   
      glEnd();
*/      
      ::glEnable( GL_LIGHTING );

      //   
      ::glPopAttrib();
      res = FALSE;
    }
//         ,     GabaritModifying
//            AddGabarit
//      IDocumentFramePtr documentFrame(pThis->m_params.iObj);
//      if ( documentFrame ) {
//        documentFrame->SetGabaritModifying();
//      }

  }

  return res;
}


//-----------------------------------------------------------------------------
//   
// ---
VARIANT_BOOL STDMETHODCALLTYPE DocumentFrameEvent::XDocumentFrameNotify::ClosePaintGL(  long drawMode )
{
	METHOD_PROLOGUE_EX_(DocumentFrameEvent, DocumentFrameNotify) //    
/*
  if ( drawMode == vm_Shaded ) 
  {
    IDocument3DPtr doc3D( ksGetActive3dDocument(), false );
    if ( (bool)doc3D ) 
    {
    //   
    ::glPushAttrib( GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT );

//      ::glClearColor( 1.0f, 1.0f, 1.0f, 1.0f);    
//      ::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
//      ::glDisable( GL_LIGHTING );
      int start = GetTickCount();
      if ( doc3D->IsDetail() ) 
      {
        IPartPtr pPart( doc3D->GetPart( pTop_Part ) , false );
        if ( pPart ) 
          RedrawModelFaces( pPart, pPart );
      }
      else
      {
        IPartPtr pTopPart( doc3D->GetPart( pTop_Part ) , false );
        IFeaturePtr partFeature( pTopPart->GetFeature(), false );
        if ( partFeature )
        {
          RecursiveDraw( pTopPart, partFeature );
        }
      }
      int end = GetTickCount();
      TRACE( _T("ClosePaintGL %i"), end - start );
//      ::glEnable( GL_LIGHTING );

      //   
      ::glPopAttrib();

    }
//      IDocumentFramePtr documentFrame(pThis->m_params.iObj);
//      if ( documentFrame ) {
//        documentFrame->SetGabaritModifying();
//    }

  }
*/
  return true;
}


//-----------------------------------------------------------------------------
//   
// ---
VARIANT_BOOL STDMETHODCALLTYPE DocumentFrameEvent::XDocumentFrameNotify::AddGabarit( IUnknown __RPC_FAR *gabObj)
{
   METHOD_PROLOGUE(DocumentFrameEvent, DocumentFrameNotify)  //    
/*  IGabaritObjectPtr gabaritObject(gabObj);
  if(gabaritObject){
    double x1;
    double y1;
    double z1;
    double x2;
    double y2;
    double z2;
    VARIANT_BOOL res = gabaritObject->GetCurrentGabarit( 0, &x1, &y1, &z1, &x2, &y2, &z2 );
    if ( res ) {
      x2 += 1000;    
      xMax = x2;
      res = gabaritObject->AddGabarit( x1, y1, z1, x2, y2, z2 );
    }
  }
*/
  return false;
}


//-----------------------------------------------------------------------------
// 
// ---
VARIANT_BOOL STDMETHODCALLTYPE DocumentFrameEvent::XDocumentFrameNotify::Activate( void) 
{
  return true;
}


//-----------------------------------------------------------------------------
// 
// ---
VARIANT_BOOL STDMETHODCALLTYPE DocumentFrameEvent::XDocumentFrameNotify::Deactivate( void )
{
  return true;
}


//-----------------------------------------------------------------------------
//  
// ---
VARIANT_BOOL STDMETHODCALLTYPE DocumentFrameEvent::XDocumentFrameNotify::CloseFrame( void ) 
{
  METHOD_PROLOGUE(DocumentFrameEvent, DocumentFrameNotify)  //    
  pThis->Disconnect();
  return true;
}


//-------------------------------------------------------------------------------
//  
// ---
VARIANT_BOOL STDMETHODCALLTYPE DocumentFrameEvent::XDocumentFrameNotify::MouseMove(
           short nShiftState,
           long x,
           long y ) {
  return true; 
}


//-----------------------------------------------------------------------------
//
// ---
VARIANT_BOOL STDMETHODCALLTYPE DocumentFrameEvent::XDocumentFrameNotify::ShowOcxTree (
                                                    IUnknown * tree,
                                                    VARIANT_BOOL show )
{
  return true; 
}
