//////////////////////////////////////////////////////////////////////
//
// Project  : BRender Microsoft Windows Direct Draw Minimal Example
//            Copyright (c) 1996 Argonaut Technologies Ltd.
//            All rights reserved.
//
// Author   : Steve Williams, October 1996
//
// File     : BRDD_MIN.C
//
// Requires : BRender V1.3
//            Microsoft DirectX 3, Win95/NT
//
// Comments : Example code, demonstrating how to use the BRender
//            DirectDraw driver.
//
//////////////////////////////////////////////////////////////////////

#include <stdio.h>
#include <windows.h>
#include <brender.h>

// Application defaults ...

#define PALETTE_FILENAME "winstd.pal"

#define BR_DEVICE_NAME "DDRAW"
#define USE_DIRTY_RECTANGLES 1

br_actor *observer, *world ;
br_actor *actor = NULL ;
br_pixelmap *pPalette = NULL ;
br_pixelmap *screen = NULL, *colour_buffer = NULL, *depth_buffer = NULL ;

// Release pixelmaps

void ReleasePixelmaps()
{
   if ( depth_buffer )
      BrPixelmapFree(depth_buffer);
   
   if ( colour_buffer )   
       BrPixelmapFree(colour_buffer);
   
   if ( screen )
      BrPixelmapFree(screen);

   screen = NULL ;
   colour_buffer = NULL ;
   depth_buffer = NULL ;
}



void Remove_Device()
{
   ReleasePixelmaps();
   BrEnd();
}


// Window procedure
   
static LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
   switch(message) 
   {
   case WM_CLOSE:
      Remove_Device();
      DestroyWindow(hWnd);
      PostQuitMessage(0);
      break ;

   // Don't erase background

   case WM_ERASEBKGND:
      return 1;

   case WM_PALETTECHANGED:
      if((HWND)wParam == hWnd)
         break;

   // Realise palette

   case WM_QUERYNEWPALETTE:
      if( screen )
         BrPixelmapPaletteSet( screen, pPalette );
      break;

   default:
      return DefWindowProc(hWnd, message, wParam, lParam);
   }

   return 0;
}



BOOL Setup_World_Light_And_Camera()
{
   br_camera *pCamera ;
   br_actor *light_actor ;
   
   // Build a world

   world = BrActorAllocate(BR_ACTOR_NONE,NULL);
   observer = BrActorAdd(world,BrActorAllocate(BR_ACTOR_CAMERA,NULL));
   
   pCamera = ( br_camera*) observer->type_data ;
   
   pCamera->type          = BR_CAMERA_PERSPECTIVE_OLD;
   pCamera->field_of_view = BR_ANGLE_DEG(45.0);
   pCamera->hither_z      = BR_SCALAR(0.01); 
   pCamera->yon_z         = BR_SCALAR(20.0); 
   pCamera->aspect        = BR_SCALAR(1.46);

   light_actor = BrActorAdd(world,BrActorAllocate(BR_ACTOR_LIGHT,NULL));

   ((br_light*)light_actor->type_data)->type= BR_LIGHT_DIRECT ;
   ((br_light*)light_actor->type_data)->attenuation_c = BR_SCALAR(1.0);
   
   BrLightEnable(light_actor);

   return TRUE ;
}


BOOL Build_BRender_Scene()
{
   // Add actor
   
   actor = BrActorAdd(world,BrActorAllocate(BR_ACTOR_MODEL,NULL));
   BrMatrix34Translate( &actor->t.t.mat, BR_SCALAR(0), BR_SCALAR(0), BR_SCALAR(-5) );
      
   return TRUE ;
}


void Render_Loop()
{
   br_matrix34 Mat ;

   if ( !screen )
       return ;

   if ( colour_buffer )                    
      BrPixelmapFill( colour_buffer, 0 );

   if ( depth_buffer )
        BrPixelmapFill( depth_buffer, 0xFFFFFFFF );
   
   if ( colour_buffer && depth_buffer )
      BrZbSceneRender( world, observer, colour_buffer, depth_buffer );

   BrPixelmapDoubleBuffer( screen, colour_buffer );
            
   // Rotate test object ...
   
   if ( actor )
   {
      BrMatrix34PreRotateX( &actor->t.t.mat, BR_ANGLE_DEG(1.0) );
      BrMatrix34PreRotateY( &actor->t.t.mat, BR_ANGLE_DEG(2.0) );
      BrMatrix34PreRotateZ( &actor->t.t.mat, BR_ANGLE_DEG(3.0) );
      BrMatrix34Copy( &Mat, &actor->t.t.mat );
      BrMatrix34LPNormalise( &actor->t.t.mat, &Mat );
   }
}



int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
                        LPSTR lpCmdLine, int nCmdShow)

{
   MSG msg ;
   HWND hWnd ;
   WNDCLASS wclass;
   br_error r ;   

   // Register a new window class for BRender output.

   wclass.style = CS_HREDRAW | CS_VREDRAW;
   wclass.lpfnWndProc = WindowProc;
   wclass.cbClsExtra = 0;
   wclass.cbWndExtra = 0;
   wclass.hInstance = hInstance;
   wclass.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
   wclass.hCursor = LoadCursor(NULL, IDC_ARROW);
   wclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
   wclass.lpszMenuName = NULL;
   wclass.lpszClassName = "BrDDMinClass";
   RegisterClass(&wclass);
 
   // Create a window

   hWnd = CreateWindowEx(0, "BrDDMinClass", "BRender DirectDraw Minimal", WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, GetModuleHandle(NULL), NULL);

   if ( hWnd == NULL )
       return FALSE ;
   else
   {
	   // Show and update window

       ShowWindow( hWnd, SW_SHOWDEFAULT );
       UpdateWindow( hWnd );
   }

   // Initiallise BRender

   BrBegin();
   
   // Create BRender device. Note : If you want a full screen app,
   // you need to specify width, height, and colour depth in the
   // BrDevBeginVar call. See demos\misc\win_bits.c for an example.

   r = BrDevBeginVar( &screen, BR_DEVICE_NAME,
                  BRT_WINDOW_HANDLE_H, hWnd,
                  BRT_WINDOW_FULLSCREEN_B, BR_FALSE,
                  BR_NULL_TOKEN );

   if ( (!screen) || (r != BRE_OK) )
       return FALSE ;

   pPalette = BrPixelmapLoad( PALETTE_FILENAME );

   if ( !pPalette )
      return 0 ;
   
   colour_buffer = BrPixelmapMatch( screen, BR_PMMATCH_OFFSCREEN );
   
   if ( colour_buffer == NULL)
       return 0 ;

   depth_buffer = BrPixelmapMatch( colour_buffer, BR_PMMATCH_DEPTH_16 );
   
   if ( depth_buffer == NULL )
      return 0 ;

   if ( pPalette )
      BrPixelmapPaletteSet( screen, pPalette );

   BrZbBegin( screen->type, BR_PMT_DEPTH_16 );

   Setup_World_Light_And_Camera();
   Build_BRender_Scene();

   while (1)
   {
        if ( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
        {
            if( !GetMessage( &msg, NULL, 0, 0 ) )
            {
               Remove_Device();
               return msg.wParam;
            }   

            TranslateMessage(&msg); 
            DispatchMessage(&msg);
        }

      Render_Loop();
   }
}
