//////////////////////////////////////////////////////////////////////
//
// Project  : BRender Demo Framework
//            Copyright (c) 1996 Argonaut Technologies Ltd.
//            All rights reserved.
//
// Author   : Steve Williams, October 1996
//
// File     : DEMOMENU.C
//
// Requires : BRender V1.3
//            Microsoft DirectX 3, Win95/NT
//
// Comments : Menu handling under Windows.
//
//////////////////////////////////////////////////////////////////////

#include "br_demo.h"
#include "resource.h"

#define MAX_DDRAW_DEVICES 5
#define DEVICE_BASE 700
#define MAX_DEVICE_OPTIONS 200
#define USER_OPTIONS_BASE 400
#define MAX_USER_OPTIONS 20

#define HOST_CAPS_MMX  0x00000400      /* Has MMX extensions  */


typedef struct BrDemoMenuItemTag
{
    br_uint_16 res_id ;
    br_uint_16 width ;
    br_uint_16 height ;
    br_uint_8 bpp ;
    br_boolean bWindow ;
    br_token tRenderMethod ;
    br_uint_8 DDrawDeviceNum ;
    br_uint_8 BRenderDeviceNum ;
    struct BrDemoMenuItemTag *next ;
} BRDEMOMENUITEM, * BRDEMOMENUITEMPTR ;


static BRDEMOMENUITEMPTR pMenuHead = NULL ;

// Handle to Device sub-menu

HMENU hDeviceMenu ;

// Handle to demo parent menu

static HMENU hBrDemoMenu ;

// Num of BRender devices we have found
static br_int_32 Num_BRender_Devices = 0 ;

static br_uint_32 Current_FullScreen_ID = 0;
static br_uint_16 current_menu_res_id ;

// Handle to the special menu, which contains demo specific options,
// currently only used by Forest.

static HMENU hSpecialMenu ;

static Num_DDraw_Devices = 0 ;
char *DDraw_Devices[MAX_DDRAW_DEVICES];
static char *DD_Device_Description[MAX_DDRAW_DEVICES];

// Handle to the current device's sub menu.

static HMENU hDeviceModesMenu ; 
static HMENU hThisDeviceMenu ;
static HMENU hCurrentMenu ;
static HMENU h8BitMenu = (HMENU) NULL ;
static HMENU h15BitMenu = (HMENU) NULL ;
static HMENU h16BitMenu = (HMENU) NULL ;
static HMENU h24BitMenu = (HMENU) NULL ;

extern br_uint_32 Current_Windowed_ID ;
extern char BrDemo_Device_Name[MAX_DEVICES][20];


// Demo specific menu handling
// ---------------------------

// Only one demo currently uses menu callbacks - Forest,
// for toggling between small and large textures.

static br_uint_16 NumUserMenuItems = 0 ;
static BRDEMO_MENU_CALLBACK UserCB[MAX_USER_OPTIONS];

// The following are just a couple of 'fun' callbacks to allow
// some interaction in the demos.

static br_uint_32 BR_CALLBACK ToggleTextures ( br_material *pMat, void *arg );
static br_uint_32 BR_CALLBACK SetActorRenderStyleCallback(br_actor *a, void *arg );
static br_uint_32 BR_CALLBACK ToggleMaterialSwitch( br_material *pMat, void *arg );

br_error BrDemo_Set_Valid_Display_Devices();
br_error BrDemo_Enumerate_Display_Devices(WIN_BITS_PTR pBrApp );
BRDEMOMENUITEMPTR Get_Mode_Details( br_uint_32 id );

// -----------------------------------------------------------------
// Function : Set_Default_Screen_Mode 
//
// Description : Chooses most appropriate initial full screen mode.
// -----------------------------------------------------------------

void Set_Default_Screen_Mode( br_int_32 width, br_int_32 height, br_int_32 bpp, br_uint_32 id )
{
        // Vars for holding default full screen mode

        static br_int_32 Default_Width = 0 ;
        static br_int_32 Default_Height = 0 ;
        static br_int_32 Default_BPP = 0 ;
        
        if ( ( Default_Width == 0 ) || ( bpp < Default_BPP ) ||
                 ( ( bpp == Default_BPP ) && width < Default_Width ) )
        {
                Default_Width = width ;
                Default_Height = height ;
                Default_BPP = bpp ;
                Current_FullScreen_ID = id ;
        }
}






// -----------------------------------------------------------------
// Function : BrDemo_Attach_Menu
//
// Description : Attaches the demo menu to the app's window. Queries
// BRender devices available in order to generate the Device menu.
// -----------------------------------------------------------------

HMENU BrDemo_Load_And_Update_Menu( WIN_BITS_PTR pBrApp )
{
   br_error r ;
   br_token cpuType;
   br_uint_32 cpuFeatures;
   BRDEMOMENUITEMPTR pItem ;

    hBrDemoMenu = LoadMenu( GetModuleHandle(NULL), MAKEINTRESOURCE(IDR_BR_DEMO_MENU) );
    
    if ( !hBrDemoMenu )
    {
        BR_ERROR0("Could not load BRender demo framework menu.");
        return NULL ;
    }
        
    // Create Device sub-menu ...
    
    hDeviceMenu = CreateMenu();

    InsertMenu( hBrDemoMenu, 1, MF_BYPOSITION|MF_POPUP,
            (unsigned) hDeviceMenu, "&Device" );
    
    // Set the base id for items in the Device menu
    
    current_menu_res_id = DEVICE_BASE ;
    
    r = BrDemo_Enumerate_Display_Devices(pBrApp);

    if ( r != BRE_OK )
       return NULL ;

    // Tick initial device.
    
    if ( Current_Windowed_ID )
            CheckMenuItem( hBrDemoMenu, Current_Windowed_ID, MF_CHECKED );
    else
            CheckMenuItem( hBrDemoMenu, Current_FullScreen_ID, MF_CHECKED );

    pItem = Get_Mode_Details( Current_FullScreen_ID );

    if ( pItem )
    {
       pBrApp->Width = pItem->width ;
       pBrApp->Height = pItem->height;
       pBrApp->Fullscreen_BPP = pItem->bpp ;
       pBrApp->tRenderStyle = pItem->tRenderMethod ;
       pBrApp->DDraw_Device_Num = pItem->DDrawDeviceNum ;
    }
        
   // Check for MMX support, enable menu item if available

   CPUInfo(&cpuType, &cpuFeatures);
   if(cpuFeatures&HOST_CAPS_MMX){
//       pBrApp->useMmx = 1;

                EnableMenuItem(hBrDemoMenu,ID_FEATURES_MMX,MF_ENABLED);
   }

   return hBrDemoMenu ;
}


// -----------------------------------------------------------------
// Function : BrDemo_SetDeviceMenuChecks
//
// Description : Checks / unchecks the current full screen and
//               and windowed selections appropriatly.
// -----------------------------------------------------------------

br_error BrDemo_SetDeviceMenuChecks( WIN_BITS_PTR pBrApp )
{
   if ( pBrApp->bFullScreen )
   {
       CheckMenuItem( hBrDemoMenu, Current_Windowed_ID, MF_UNCHECKED );
           CheckMenuItem( hBrDemoMenu, Current_FullScreen_ID, MF_CHECKED );
   }
   else
   {
       CheckMenuItem( hBrDemoMenu, Current_Windowed_ID, MF_CHECKED );
           CheckMenuItem( hBrDemoMenu, Current_FullScreen_ID, MF_UNCHECKED );
   }

   return BRE_OK ;
}


// -----------------------------------------------------------------
// Function : BrDemoMenu_Select_Device
//
// Description : Handles selection of devices from the menu.
// -----------------------------------------------------------------


br_error BrDemoMenu_Select_Device( WIN_BITS_PTR pBrApp, br_uint_32 Menu_ID )
{
        int new_bpp ;
        br_error r ;
        br_uint_8 Selected_Device ;
        static br_uint_32 Last_Menu_ID ;
        static br_boolean bFirstTime = BR_TRUE ;
        BRDEMOMENUITEMPTR pItem ;

        pItem = Get_Mode_Details( Menu_ID );

        if ( pItem )
        {
           Selected_Device = pItem->BRenderDeviceNum ;
           pBrApp->Fullscreen_BPP = pItem->bpp ;
           pBrApp->tRenderStyle = pItem->tRenderMethod ;
           pBrApp->DDraw_Device_Num = pItem->DDrawDeviceNum ;
           pBrApp->bFullScreen = !pItem->bWindow ;
           pBrApp->Width = pItem->width ;
           pBrApp->Height = pItem->height;
        }
        
        // Get new mode dimensions from setup string

        if ( pItem->bWindow )
        {    
                Current_Windowed_ID = Menu_ID ;
            new_bpp = pBrApp->Windowed_BPP  ;
        }
        else
        {
                new_bpp = pBrApp->Fullscreen_BPP  ;
                Current_FullScreen_ID = Menu_ID ;
        }

   // If the new mode is on the same device and has the same bit depth,
   // we only need to reallocate the pixelmaps, otherwise, we must restart 
   // the application.

   // Set new device

   pBrApp->Current_Device = Selected_Device ;

   // Remove old device. and kill app

   BrDemo_Remove_Device(pBrApp);
   BrDemo_ClearAppMenuItems();

   // Restart app using new device.

   r = BrDemo_Initiallise_BRender();

   if ( r != BRE_OK )
   {
      BR_ERROR0("Could not start device !");
      return r ;
   }
   
   // Uncheck last device

        if ( !bFirstTime )
                CheckMenuItem( hBrDemoMenu, Last_Menu_ID, MF_UNCHECKED );
        else
           bFirstTime = BR_FALSE ;
                
        Last_Menu_ID = Menu_ID ;

    BrDemo_SetDeviceMenuChecks( pBrApp );
        
        return r ;
}


// -----------------------------------------------------------------
// Function : BrDemo_HandleMenuSelection
//
// Description : Handles user menu item selection.
// -----------------------------------------------------------------


br_error BrDemo_HandleMenuSelection( WIN_BITS_PTR pBrApp, br_uint_16 Menu_Selection )
{
    br_error r ;

    // Handle user specific options
    
    if ( ( Menu_Selection >= USER_OPTIONS_BASE ) && ( Menu_Selection <= USER_OPTIONS_BASE + MAX_USER_OPTIONS ) )
    {
        if ( UserCB[Menu_Selection-USER_OPTIONS_BASE] )
                    r = UserCB[Menu_Selection-USER_OPTIONS_BASE]();

            return r ;
    }

    else if ( ( Menu_Selection >= DEVICE_BASE ) && (Menu_Selection < ( DEVICE_BASE + MAX_DEVICE_OPTIONS ) ) )
    {
        r = BrDemoMenu_Select_Device( pBrApp, Menu_Selection );
        return r ;
    }

    else if ( Menu_Selection == ID_VIEW_NORMAL )
    {
       pBrApp->bStretch = BR_FALSE ;
       BrDemo_ResizeOffScreenBuffers( pBrApp, pBrApp->screen->width, pBrApp->screen->height );
    }
    else if ( Menu_Selection == ID_STRETCH100X100 )
    {
       pBrApp->bStretch = BR_TRUE ;
       BrDemo_ResizeOffScreenBuffers( pBrApp, 100, 100 );
    }
    else if ( Menu_Selection == ID_STRETCH200X200 )
    {
       pBrApp->bStretch = BR_TRUE ;
       BrDemo_ResizeOffScreenBuffers( pBrApp, 200, 200 );
    }
    else if ( Menu_Selection == ID_STRETCH300X300 )
    {
       pBrApp->bStretch = BR_TRUE ;
       BrDemo_ResizeOffScreenBuffers( pBrApp, 300, 300 );
    }
    else if ( Menu_Selection == ID_FILE_OPEN )
    {
        BrDemo_HandleNewFile();
    }
    else if ( Menu_Selection == ID_FILE_EXIT )
    {
        BrDemo_Remove_Device(pBrApp);
        DestroyWindow(pBrApp->hWnd);
        PostQuitMessage(0);
    }
    else if ( Menu_Selection == IDR_HELP  )
    {
       MessageBox( pBrApp->hWnd, "Press ALT-ENTER to toggle windowed/full screen", "BRender Demo Framework", MB_OK );
    }

    else if ( ( Menu_Selection == ID_FEATURES_SOLID ) && pBrApp->pRoot )
    {
       BrActorEnum( pBrApp->pRoot, SetActorRenderStyleCallback, (void*) BR_RSTYLE_FACES ); 
       CheckMenuItem( hBrDemoMenu, ID_FEATURES_SOLID, MF_CHECKED );
       CheckMenuItem( hBrDemoMenu, ID_FEATURES_WIREFRAME, MF_UNCHECKED );
       CheckMenuItem( hBrDemoMenu, ID_FEATURES_POINTS, MF_UNCHECKED );
    }
            
    else if ( ( Menu_Selection == ID_FEATURES_WIREFRAME ) && pBrApp->pRoot )
    {
       BrActorEnum( pBrApp->pRoot, SetActorRenderStyleCallback, (void*) BR_RSTYLE_EDGES ); 
       CheckMenuItem( hBrDemoMenu, ID_FEATURES_SOLID, MF_UNCHECKED );
       CheckMenuItem( hBrDemoMenu, ID_FEATURES_WIREFRAME, MF_CHECKED );
       CheckMenuItem( hBrDemoMenu, ID_FEATURES_POINTS, MF_UNCHECKED );
    }
    else if ( ( Menu_Selection == ID_FEATURES_POINTS ) && pBrApp->pRoot )
    {
       BrActorEnum( pBrApp->pRoot, SetActorRenderStyleCallback, (void*) BR_RSTYLE_POINTS ); 
       CheckMenuItem( hBrDemoMenu, ID_FEATURES_SOLID, MF_UNCHECKED );
       CheckMenuItem( hBrDemoMenu, ID_FEATURES_WIREFRAME, MF_UNCHECKED );
       CheckMenuItem( hBrDemoMenu, ID_FEATURES_POINTS, MF_CHECKED );
    }
    else if ( Menu_Selection == ID_FEATURES_BILINEAR )
    {
       BrMaterialEnum( NULL, ToggleMaterialSwitch, (void*) BR_MATF_MAP_INTERPOLATION );
    } 
    else if ( Menu_Selection == ID_FEATURES_TWO_SIDED )
    {
       BrMaterialEnum( NULL, ToggleMaterialSwitch, (void*) BR_MATF_TWO_SIDED );
    } 
    else if ( Menu_Selection == ID_FEATURES_TEXTURE_MAPPING )
    {
       static bEnabled = BR_TRUE ;
         
       bEnabled ^= 1;
       BrMaterialEnum( NULL, ToggleTextures, (void*) bEnabled );
    }
    else if (Menu_Selection == ID_FEATURES_MMX)
    {
       static bEnabled = BR_FALSE;
       bEnabled ^= 1;

       if(bEnabled)
       {
          CheckMenuItem(hBrDemoMenu,ID_FEATURES_MMX,MF_CHECKED);
       }
       else
       {
          CheckMenuItem(hBrDemoMenu,ID_FEATURES_MMX,MF_UNCHECKED);
       }
       
       pBrApp->useMmx ^= 1;
       BrDemo_Restart();
    }

    return BRE_OK ;
}


// -----------------------------------------------------------------
// Function : BrDemo_ClearAppMenuItems
//
// Description : Tidied up menu ready for restart.
// -----------------------------------------------------------------

br_error BrDemo_ClearAppMenuItems()
{
        int i ;
        
        // Remove user menu options
        
        for ( i = 0 ; i < NumUserMenuItems ; i ++ )
        {
           RemoveMenu( hBrDemoMenu, USER_OPTIONS_BASE+i, MF_BYCOMMAND );
        }

        NumUserMenuItems = 0 ;

    return BRE_OK ;
}


// -----------------------------------------------------------------
// Function : BrDemo_AddMenuItem
//
// Description : Adds demo specific option to the Special menu.
//               Records a callback function which is called when
//               that menu option is selected.
// -----------------------------------------------------------------


br_error BrDemo_AddMenuItem( char *Name, BRDEMO_MENU_CALLBACK pCallback )
{
        static BOOL bFirstTime = BR_TRUE ;
        
        if ( bFirstTime )
        {
                hSpecialMenu = CreateMenu();

            InsertMenu( hBrDemoMenu, 4, MF_BYPOSITION|MF_POPUP,
                    (unsigned) hSpecialMenu, "&Special" );
        bFirstTime = BR_FALSE;
        }
        
        AppendMenu(     hSpecialMenu, MF_STRING , USER_OPTIONS_BASE+NumUserMenuItems, Name );

        UserCB[NumUserMenuItems] = pCallback ;

        if ( NumUserMenuItems > MAX_USER_OPTIONS )
        {
                BR_ERROR0("Too many user options");
                return BRE_FAIL ;
        }
        else
           NumUserMenuItems++ ;

    return BRE_OK ;
}



// -----------------------------------------------------------------
// Function : SetActorRenderStyleCallback
//
// Description : Sets current actor and it's children's render style
// to specified style. 
// -----------------------------------------------------------------


static br_uint_32 BR_CALLBACK SetActorRenderStyleCallback(br_actor *a, void *arg )
{
        a->render_style = (br_uint_8) arg ;

        return BrActorEnum(a,SetActorRenderStyleCallback,arg);
}


// -----------------------------------------------------------------
// Function : ToggleMaterialSwitch
//
// Description : Toggles specified material flag on all materials.
// -----------------------------------------------------------------
  

static br_uint_32 BR_CALLBACK ToggleMaterialSwitch( br_material *pMat, void *arg )
{
   br_uint_32 Flag = (br_uint_32) arg ;

   pMat->flags ^= Flag ;        
   BrMaterialUpdate( pMat, BR_MATU_ALL );

   return 0 ;
}


// -----------------------------------------------------------------
// Function : ToggleTexture
//
// Description : Toggles texture on/off on all materials.
// -----------------------------------------------------------------

static br_uint_32 BR_CALLBACK ToggleTextures ( br_material *pMat, void *arg )
{
   br_boolean Flag = (br_boolean) arg ;

   if ( !Flag )
   {
           if ( pMat->user != NULL )
           {
                   BR_ERROR0("Cannot perform operation, app uses material 'user' field");
                   return 1 ;
           }

           pMat->user = pMat->colour_map ;
           pMat->colour_map = NULL ;
   }
   else
   {
           pMat->colour_map  = (br_pixelmap*) pMat->user ;
           pMat->user = NULL ;
   }

   BrMaterialUpdate( pMat, BR_MATU_ALL );

   return 0 ;
}


BRDEMOMENUITEMPTR Get_Mode_Details( br_uint_32 res_id )
{
   BRDEMOMENUITEMPTR ptr = pMenuHead ; 

   while ( ptr )
   {
       if ( ptr->res_id == res_id )
             break ;
	   ptr = ptr->next ;
   }

   return ptr ;
}


void AddMenuItemToList( br_uint_16 res_id, br_uint_8 DDrawDeviceNum,
                        br_uint_8 BRenderDeviceNum,
                        br_token tRenderMethod, br_uint_16 width,
                        br_uint_16 height, br_uint_8 bpp, 
                        br_boolean bWindow )
{
   static BRDEMOMENUITEMPTR last_ptr ;
  
   BRDEMOMENUITEMPTR ptr ;

   ptr = (BRDEMOMENUITEMPTR) BrMemAllocate( sizeof(BRDEMOMENUITEM), BR_MEMORY_APPLICATION );

   if ( pMenuHead == NULL )
      pMenuHead = ptr ;
   else
      last_ptr->next = ptr ;

   last_ptr = ptr ;

   ptr->next = NULL ;

   ptr->res_id = res_id ;

   ptr->DDrawDeviceNum = DDrawDeviceNum ;
   ptr->BRenderDeviceNum = BRenderDeviceNum ;

   ptr->tRenderMethod = tRenderMethod  ;
   ptr->width = width ;
   ptr->height = height ;
   ptr->bpp = bpp ;
   ptr->bWindow = bWindow ;
}

int BrDemo_Parse_Direct3D_Driver_Identifier( char *identifier, br_token *ptRenderMethod, char *RenderDesc )
{
   char *ptr ;
   int Current_DD_Device = -1 ;
   int i ;
   
   *ptRenderMethod = BR_NULL_TOKEN ;

    ptr = strtok( identifier, ";" );

    if ( !ptr )
       return -1 ;
        
     while ( ptr ) 
     {
        if ( !strncmp( ptr, "Name=", 5 ) )
                {
         br_boolean bFound = BR_FALSE ;
 
         for ( i = 0 ; i < Num_DDraw_Devices ; i ++ )
            if ( !strcmp( ptr+5, DDraw_Devices[i] ) )
            {
               bFound = BR_TRUE ;
               break ;
            }

         if ( !bFound  )
         {
            DDraw_Devices[i] = BrMemStrDup( ptr+5 );
            Num_DDraw_Devices++ ;
         }

         Current_DD_Device = i ;
      }

                if ( !strncmp( ptr, "Description=", 12 ) )
                        DD_Device_Description[Num_DDraw_Devices-1] = BrMemStrDup( ptr+12 );

                if ( !strncmp( ptr, "Render=", 7 ) )
                {
         strcpy( RenderDesc, ptr + 7 );
 
         if ( !strcmp( RenderDesc, "Ramp Emulation" ) )
           *ptRenderMethod = BRT_DIRECT3D_RAMP ;
         else if ( !strcmp( RenderDesc, "RGB Emulation" ) )
           *ptRenderMethod = BRT_DIRECT3D_RGB ;
         else if ( !strcmp( RenderDesc, "Direct3D HAL" ) )
           *ptRenderMethod = BRT_DIRECT3D_HAL  ;
         else
            BR_ERROR0("Found unknown render method");
      }

                ptr = strtok( NULL, ";" );
        }

        return Current_DD_Device ;
}


void Menu_Direct3D_Driver_Stuff( int DDraw_DeviceNum, br_token tRenderMethod, char *RenderDesc )
{
   static HMENU hDDrawDeviceMenu ;
   static int LastDDraw_DeviceNum = -1 ;
   static br_token tLastRenderMethod = BR_NULL_TOKEN ;

   if ( DDraw_DeviceNum != LastDDraw_DeviceNum )
   {
      // Add menu for this DDraw Device.

                hDDrawDeviceMenu = CreateMenu();
                AppendMenu( hThisDeviceMenu, MF_POPUP, (unsigned int) hDDrawDeviceMenu, DD_Device_Description[DDraw_DeviceNum] );
                LastDDraw_DeviceNum = DDraw_DeviceNum ;
   }

   if ( tRenderMethod != tLastRenderMethod )
   {
        HMENU hRenderMenu ;

        // Add menu for this DDraw Device.

                hRenderMenu = CreateMenu();
                AppendMenu( hDDrawDeviceMenu, MF_POPUP, (unsigned int) hRenderMenu, RenderDesc );

        hCurrentMenu = hRenderMenu ;
                tLastRenderMethod = tRenderMethod ;

                h8BitMenu = (HMENU) NULL ;
                h15BitMenu = (HMENU) NULL ;
                h16BitMenu = (HMENU) NULL ;
                h24BitMenu = (HMENU) NULL ;
   }
}


// -----------------------------------------------------------------
// Function : OutputFacilityEnumCb
//
// Description : Enumerates available output facilities on the current
// device, and adds the description to the appropriate menu. Creates
// sub-menus where required.
// -----------------------------------------------------------------


br_boolean BR_CALLBACK BrDemoOutputFacilityEnumCb(char *identifier,
    br_outfcty_desc *desc, void *args)
{
   char MenuText[100];
   WIN_BITS_PTR pBrApp = (WIN_BITS_PTR) args ;
   HMENU *pBppMenu ;
   int DDraw_DeviceNum ;
   br_token tRenderMethod ;
   char RenderDesc[50] ;
   
   DDraw_DeviceNum = BrDemo_Parse_Direct3D_Driver_Identifier( identifier, &tRenderMethod, RenderDesc );

   AddMenuItemToList( (br_uint_16) current_menu_res_id, (br_uint_8) DDraw_DeviceNum, 
                      (br_uint_8) Num_BRender_Devices,
                      tRenderMethod, 
                      (br_uint_16) desc->width, (br_uint_16) desc->height, (br_uint_8) desc->pmbits,
                      (br_boolean) !desc->fullscreen );
   
   if ( DDraw_DeviceNum >= 0 )
   {
      Menu_Direct3D_Driver_Stuff( DDraw_DeviceNum, tRenderMethod, RenderDesc );
   }
   else
      hCurrentMenu = hThisDeviceMenu ;
   
   if ( !desc->fullscreen )
   {
        BrSprintf( MenuText, "Windowed ( %d bpp )", desc->pmbits );

        pBrApp->Windowed_BPP = (br_uint_8) desc->pmbits ;

        AppendMenu( hCurrentMenu, MF_STRING ,current_menu_res_id, MenuText );

        if ( Num_BRender_Devices == pBrApp->Current_Device )
        {
            Current_Windowed_ID = current_menu_res_id ;
            
            // If current device supports windowed mode, set this
            // as the initial mode.
            
            pBrApp->bFullScreen = BR_FALSE ;
        }
   }
   else
   {
       BrSprintf( MenuText, "%dx%d", desc->width, desc->height );
           
           switch( desc->pmbits )
           {
              case 8 : pBppMenu = &h8BitMenu ; break ;
              case 15 : pBppMenu = &h15BitMenu ; break ;
              case 16 : pBppMenu = &h16BitMenu ; break ;
              case 24 : pBppMenu = &h24BitMenu ; break ;
              default : return 0 ;  // Ignore any other modes, we don't support them.
           }

           if ( BrDemo_ValidateScreenMode(desc)!=BRE_OK)
           {
              return 0;
           }

           if ( *pBppMenu == NULL )
           {
                   char MenuName[30];

                   BrSprintf( MenuName, "%d bits per pixel", desc->pmbits );
                   *pBppMenu = CreateMenu();
                   AppendMenu( hCurrentMenu, MF_POPUP, (unsigned int) *pBppMenu, MenuName );
           }

           if ( Num_BRender_Devices == pBrApp->Current_Device )
              Set_Default_Screen_Mode( desc->width, desc->height, desc->pmbits, current_menu_res_id );
           
           AppendMenu( *pBppMenu, MF_STRING, current_menu_res_id, MenuText );
    }

    current_menu_res_id ++ ;
        return 0 ;
}


// -----------------------------------------------------------------
// Function : BrDemoDeviceCallback
//
// Description : Enumerates available BRender devices, creating a
// sub menu for this devices, and enumerates output facilities 
// the device ( which in turn adds sub menus to hDeviceMenu ). 
// -----------------------------------------------------------------


br_boolean BR_CALLBACK BrDemoDeviceCallback( char *identifier,
    br_uint_32 version, char *creator, char *title, char *product,
    char *product_version, void *args)
{
	char *name ;
	if ( title )
		name = title ;
	else
		name = "Not specified" ;

	strncpy( BrDemo_Device_Name[Num_BRender_Devices], identifier, 20 );

	hThisDeviceMenu = CreateMenu() ;
	hCurrentMenu = hThisDeviceMenu ;
	h8BitMenu = NULL ;
    h15BitMenu = NULL ;
    h16BitMenu = NULL ;
    h24BitMenu = NULL ;
	
	// Query device for modes supported, these are added to hDeviceModesMenu
	
	BrOutputFacilityEnum( identifier, BrDemoOutputFacilityEnumCb, args );

	// Add hDeviceModesMenu submenu to current device submenu.

	InsertMenu( hDeviceMenu, Num_BRender_Devices, MF_BYPOSITION|MF_POPUP,
                (unsigned) hThisDeviceMenu, name );
	
	Num_BRender_Devices ++ ;
	
	return 0 ;
}





// -----------------------------------------------------------------
// Function : BrDemo_Check_Display_Device_Dependencies
//
// Description : Checks that the necessary Windows DLLs are present.
// -----------------------------------------------------------------




br_boolean BrDemo_Check_Display_Device_Dependencies( char *identifier )
{
	void *fp;
	br_boolean bFound = BR_FALSE ;
   char *ptr ;
	char line[256];
 
	// Check if DLLs for this driver are present. 
   // If not then ignore this device.

   fp = BrFileOpenRead("BRDRVDEP.TXT", 0, NULL, NULL);
 
	if (fp == NULL)
	{
	   BR_ERROR0("BRender device driver dependency file BRDRVDEP.TXT missing.\n");
	   return BRE_FAIL ;
	}

   for ( ;; )
   {
      if ( BrFileGetLine(line, 256, fp) == 0 )
          break ;

	   // Ignore comments
	   
	   if ( line[0] == '#' )
		  continue ;

	   // Remove carriage return.
	   
	   line[strlen(line)-1] = '\0' ;

	   ptr = strtok( line, ":" );

       if ( !ptr )
         continue ;

      if ( !stricmp( identifier, ptr ) )
      {
         bFound = BR_TRUE ;
         break ;
      }
   }

   BrFileClose(fp);

   if ( !bFound )
   {
      BR_ERROR1("Entry for device %s is missing from BRDRVDEP.TXT. Contact Argonaut.", identifier );
      return BRE_FAIL ;
   }

   // Check if all required DLLs are present

	for( ;; )
	{
		OFSTRUCT os ;
		HFILE hFile ;

		ptr = strtok( NULL, "," );

        if ( !ptr )
          break ;

	    hFile = OpenFile( ptr, &os,	OF_EXIST);
   
       if ( hFile == HFILE_ERROR )
          return BRE_FAIL ;
   } 

   return BRE_OK ;
}






// -----------------------------------------------------------------
// Function : BrDemo_Set_Valid_Display_Devices
//
// Description : Removes display drivers whose necessary Windows DLLs 
// are not present from the list of devices to stop BRender
// complaining about them.
// -----------------------------------------------------------------



br_error BrDemo_Set_Valid_Display_Devices()
{
   char devstr[256];
   char valid_devstr[256];
   br_error r ;
   char *ptr, *this_device ;
   
   valid_devstr[0] = '\0' ;

   BrSystemConfigQueryString(BRT_BRENDER_DEVICES_STR, devstr,
                              BR_ASIZE(devstr));

   // If BRENDER_DEVICES is not set, use whatever value is
   // in BRENDER_DEFAULT_DEVICE instead.
	
   if ( *devstr == '\0' )
      BrSystemConfigQueryString( BRT_DEFAULT_DEVICE_STR, 
	                             devstr, BR_ASIZE(devstr) );

   this_device = devstr ;
   
   do
   {
	   ptr = strchr( this_device, ';' );

       if ( ptr )
     	 *ptr = '\0' ;
	   
	   r = BrDemo_Check_Display_Device_Dependencies( this_device );  

       if ( r == BRE_OK )
       {   
          strcat( valid_devstr, this_device );
          strcat( valid_devstr, ";" );
	   }

       if ( ptr )
	     this_device = ptr + 1 ;
    } while ( ptr );

    // Remove final semi-colon
   
    valid_devstr[strlen(valid_devstr)-1] = '\0' ;
   
    // Set updated device string

    BrSystemConfigSetString( BRT_BRENDER_DEVICES_STR, valid_devstr );
                           
    return BRE_OK ;
}  




br_error BrDemo_Enumerate_Display_Devices(WIN_BITS_PTR pBrApp ) 
{
   // Remove display drivers whose necessary Windows DLLs are 
   // not present from the list of devices to stop BRender
   // complaining about them.

   BrDemo_Set_Valid_Display_Devices();

   // Query BRender for devices available. This adds devices and
   // screen modes to the Device menu.

   BrDeviceEnum( BrDemoDeviceCallback, (void*) pBrApp );

   if ( Num_BRender_Devices == 0 )
   {
       BR_ERROR0("Could not load any BRender devices. Cannot continue.");
       return BRE_FAIL ;
   }

   return BRE_OK ;
}
