/* Autor: Leandro Bernsmuller
Cria uma janela de aplicao que exibe imagens de cenarios do D3DRM.
A janela funciona de forma integrada com os cenarios que exibe.
Usada para criar a janela principal da aplicacao.
Essa classe eh derivada de CJanela. */



#include <windows.h>
#include <windowsx.h>
#include <ddraw.h>
#include <d3drmwin.h>
#include "..\princip\defs.h"
#include "..\extra\ddutil.h"
#include "..\extra\ddmm.h"
#include "..\cenario\cenario.h"
#include "..\cenario\cenfis.h"
#include "..\cenario\gr.h"
#include "janela.h"
#include "jancen.h"



long FAR PASCAL WindowProc ( HWND hWnd, UINT uMsg, 
                             WPARAM wParam, LPARAM lParam );


  
/* Cria janela.
Ver CJanela::mCria
return TRUE - certo / FALSE - erro
**********************************************************/
BOOL CJanelaCenario::mCria ( DWORD dwMenu, char* szTitulo, HINSTANCE hInstance )
{
   // cria pela classe base
   if ( ! CJanela::mCria ( dwMenu, szTitulo, hInstance ) )
      return FALSE;

   // sem cenario
   m_pstCenario.poCenario = NULL;

   return TRUE;
}



/* destroi janela
**********************************************************/
void CJanelaCenario::mDestroi ()
{
   ::PostQuitMessage ( 0 );
}



/* Adiciona um cenario a janela
fPropXIni, fPropXFim, fPropYIni, fPropYFim - posicao da
viewport do cenario em relacao as bordas da janela. Ex.:
se janela 1000x1000 e fPropXIni = 0.2 entao o inicio
a viewport serah em 1000 * 0.2 = 200.
Se fPropXFim = 0.2 entao final serah em 1000 * (1 - 0.2)=800.
            
            fPropXIni |
                      |
                      V
                 *--------*
    fPropYIni -> |        | <- fPropYFim
                 *--------*
                      A
                      |
                      | fPropXFim

oCen - cenario a ser incluido
**********************************************************/
void CJanelaCenario::mIncluiCenario ( float fPropXIni, float fPropYIni,
                                      float fPropXFim, float fPropYFim,
                                      CCenarioFisico& oCen )
{
   m_pstCenario.poCenario = &oCen;
   m_pstCenario.fPropXIni = fPropXIni;
   m_pstCenario.fPropXFim = fPropXFim;
   m_pstCenario.fPropYIni = fPropYIni;
   m_pstCenario.fPropYFim = fPropYFim;
}



/* Exibe cenarios da janela (executa as animacoes programadas no DX)
bMover - se TRUE - move objetos / FALSE - apenas desenha na janela
**********************************************************/
void CJanelaCenario::mProcessaCenario ( BOOL bMover )
{
   // verifica se programa estah operacional (se nao estah nao roda)
   if ( m_bMinimizou )
      return;

   // nao tem cenario
   if ( m_pstCenario.poCenario == NULL )
      return;

   if ( m_pstCenario.poCenario->m_bFuncionando )
      m_pstCenario.poCenario->mProcessaCena ( bMover );

   // redefine a palette
   //if ( m_oBmps.m_lpDDPal )
     //m_oBmps.m_lpDDSOnde->SetPalette ( m_oBmps.m_lpDDPal );
}



/* Redesenha bitmap do cenario (recria dispositivo e viewport do
cenario conforme tamanho da janela). Nao executa programacao do DX.
**********************************************************/
void CJanelaCenario::mRedesenha ()
{
   CJanela::mRedesenha ();

   // nao tem cenario
   if ( m_pstCenario.poCenario == NULL )
      return;

   // verifica se cenario nao estah disponivel
   if ( ! m_pstCenario.poCenario->m_bFuncionando )
      return;

   m_pstCenario.poCenario->m_bFuncionando = FALSE;

   // desaloca
   m_pstCenario.poCenario->m_lpJanVis->Release ();
   //m_pstCenario.poCenario->m_lpDisp->Release ();

   // define dimensoes e desenha
   RECT
      stRect;
   ::GetClientRect ( m_hWnd, &stRect );
   int
      nXIni = (int) ( stRect.right  * m_pstCenario.fPropXIni ),
      nYIni = (int) ( stRect.bottom * m_pstCenario.fPropYIni ),
      nXFim = (int) ( stRect.right  * m_pstCenario.fPropXFim ),
      nYFim = (int) ( stRect.bottom * m_pstCenario.fPropYFim ),
      nL = stRect.right -  ( nXIni + nXFim ),
      nA = stRect.bottom - ( nYIni + nYFim );

   // No primeiro redesenho eh criado o dispositivo e a janela de
   // visualizacao. Nos subsequentes apenas a janela de visualizacao.
   // Isso diminui o tempo em que o programa fica "congelado" quando
   // a janela principal eh descoberta/encoberta por alguma outra.
   static BOOL
      bCriaJanVisApenas = FALSE;

   // recria janela de visualizacao
   if ( ! m_pstCenario.poCenario->mCriaDispVis ( nXIni, nYIni, nL, nA, bCriaJanVisApenas ) ) {

      // se nao conseguiu usar configuracao atual tenta anterior mais simples
      m_pstCenario.poCenario->m_nDrvSel = 0;

      if ( ! m_pstCenario.poCenario->mCriaDispVis ( nXIni, nYIni, nL, nA, bCriaJanVisApenas ) ) {
         MSGSTR ( STR_ERRO_CRIANDOVIEW );
         return;
      }
   }

   m_pstCenario.poCenario->m_bFuncionando = TRUE;

   // nos proximos apenas cria janela de visualizacao   
   bCriaJanVisApenas = TRUE;
}



/* Trata mensagens do windows
return TRUE - certo / FALSE - erro
**********************************************************/
BOOL CJanelaCenario::mTrataMensagensWindows ( HWND& hWnd, UINT& uMsg,
                                       WPARAM& wParam, LPARAM& lParam )
{
   // classifica mensagens
   switch ( uMsg ) {

      case WM_DISPLAYCHANGE:         // se alterou o video
         mWinAlteraVideo ( hWnd, uMsg, wParam, lParam );
         break;

      case WM_SIZE:
         mWinAlteraTamanhoJanela ( hWnd, uMsg, wParam, lParam );
         break;

      case WM_MOVE:
         break;

      case WM_PALETTECHANGED:
         if ( (HWND) wParam == hWnd )
            break;
      
      case WM_QUERYNEWPALETTE:
         // reconfigura palette
         //if ( m_oBmps.m_lpDDPal )
            //m_oBmps.m_lpDDSOnde->SetPalette ( m_oBmps.m_lpDDPal );
         // recarrega bitmaps, porque palette mudou
         //m_oBmps.mRecarregaBmps ();
         mWinAtivo ( hWnd, uMsg, wParam, lParam );
         break;

      case WM_ACTIVATE:
      case WM_ACTIVATEAPP:
         mWinAtivo ( hWnd, uMsg, wParam, lParam );
         break;

      case WM_PAINT:
         mWinPintar ( hWnd, uMsg, wParam, lParam );
         break;

      case WM_DESTROY:
         mDestroi ();
         break;

      case WM_GETMINMAXINFO:
         ( (MINMAXINFO*) lParam ) -> ptMinTrackSize.x = MINIMOJANX;
         ( (MINMAXINFO*) lParam ) -> ptMinTrackSize.y = MINIMOJANY;
         return 0;
   }

   return TRUE;
}



/* Executado se a mensagem de video foi alterado for
gerada pelo Windows
**********************************************************/
void CJanelaCenario::mWinAlteraVideo ( HWND& hWnd, UINT& uMsg,
                                       WPARAM& wParam, LPARAM& lParam )
{
   CJanela::mWinAlteraVideo ( hWnd, uMsg, wParam, lParam );

   // reconfigura dispositivo de saida (seleciona driver)
   mRedesenha ();
}



/* Executado se a mensagem tamanho de jabela alterada for
gerada pelo Windows
**********************************************************/
void CJanelaCenario::mWinAlteraTamanhoJanela ( HWND& hWnd, UINT& uMsg,
                                       WPARAM& wParam, LPARAM& lParam )
{
   CJanela::mWinAlteraTamanhoJanela ( hWnd, uMsg, wParam, lParam );

   int
      nResX = LOWORD ( lParam ),
      nResY = HIWORD ( lParam );

   // reconfigura D3D, se mensagem eh de alteracao do tamanho
   if ( nResX && nResY ) {

      // ativa cenario
      if ( m_pstCenario.poCenario != NULL )
         m_pstCenario.poCenario->m_bFuncionando = TRUE;

      mRedesenha ();
   }
   else      // se mensagem informa minimizacao
      // desabilita cenario
      if ( m_pstCenario.poCenario != NULL )
         m_pstCenario.poCenario->m_bFuncionando = FALSE;
}



/* Executado se a mensagem de aplicativo ativo
for gerada pelo Windows
**********************************************************/
void CJanelaCenario::mWinAtivo ( HWND& hWnd, UINT& uMsg,
                                       WPARAM& wParam, LPARAM& lParam )
{
   // nao tem cenario
   if ( m_pstCenario.poCenario == NULL )
      return;
   
   // verifica se cenario nao estah disponivel
   if ( ! m_pstCenario.poCenario->m_bFuncionando )
      return;

   if ( ! m_pstCenario.poCenario->m_lpDisp )
      return;

   // cria dispositivo de contexto ??
   LPDIRECT3DRMWINDEVICE 
      lpWindev;
   if ( SUCCEEDED ( m_pstCenario.poCenario->m_lpDisp->QueryInterface ( IID_IDirect3DRMWinDevice,
                                                      (void **) &lpWindev ) ) )
        lpWindev->Release();

   // invalida area de cliente para forcar redesenho
   RECT
      stRect;
   ::GetClientRect ( m_hWnd, &stRect );
   ::InvalidateRect ( m_hWnd, &stRect, TRUE );

   //mRedesenha ();
}



/* Executado se a mensagem de pintar janela
for gerada pelo Windows
**********************************************************/
BOOL CJanelaCenario::mWinPintar ( HWND& hWnd, UINT& uMsg,
                                       WPARAM& wParam, LPARAM& lParam )
{
   // nao tem cenario
   if ( m_pstCenario.poCenario == NULL )
      return FALSE;
   
   // verifica se nao ha condicoes para pintar
   if ( ! m_pstCenario.poCenario->m_bFuncionando ||
        ! m_pstCenario.poCenario->m_lpDisp )
      return FALSE;

   // pinta (apenas altera dispositivo??)
   RECT
      stRect;
   PAINTSTRUCT
      stPs;
   if ( GetUpdateRect ( hWnd, &stRect, FALSE ) ) {

      ::BeginPaint ( hWnd, &stPs );

      // cria dispositivo especifico
      LPDIRECT3DRMWINDEVICE 
         lpWindev;
      if ( SUCCEEDED ( m_pstCenario.poCenario->m_lpDisp->QueryInterface ( IID_IDirect3DRMWinDevice,
                                                         (void **) &lpWindev ) ) )
           lpWindev->Release ();

      ::EndPaint( hWnd, &stPs );
   }

   mRedesenha ();

   return TRUE;
}
