freeglut_structure.c
上传用户:gb3593
上传日期:2022-01-07
资源大小:3028k
文件大小:18k
源码类别:

游戏引擎

开发平台:

Visual C++

  1. /*
  2.  * freeglut_structure.c
  3.  *
  4.  * Windows and menus need tree structure
  5.  *
  6.  * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
  7.  * Written by Pawel W. Olszta, <olszta@sourceforge.net>
  8.  * Creation date: Sat Dec 18 1999
  9.  *
  10.  * Permission is hereby granted, free of charge, to any person obtaining a
  11.  * copy of this software and associated documentation files (the "Software"),
  12.  * to deal in the Software without restriction, including without limitation
  13.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  14.  * and/or sell copies of the Software, and to permit persons to whom the
  15.  * Software is furnished to do so, subject to the following conditions:
  16.  *
  17.  * The above copyright notice and this permission notice shall be included
  18.  * in all copies or substantial portions of the Software.
  19.  *
  20.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  21.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  22.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  23.  * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  24.  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  25.  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  26.  */
  27. #include <GL/freeglut.h>
  28. #include "freeglut_internal.h"
  29. /* -- GLOBAL EXPORTS ------------------------------------------------------- */
  30. /*
  31.  * The SFG_Structure container holds information about windows and menus
  32.  * created between glutInit() and glutMainLoop() return.
  33.  */
  34. SFG_Structure fgStructure = { { NULL, NULL },  /* The list of windows       */
  35.                               { NULL, NULL },  /* The list of menus         */
  36.                               { NULL, NULL },  /* Windows to Destroy list   */
  37.                               NULL,            /* The current window        */
  38.                               NULL,            /* The current menu          */
  39.                               NULL,            /* The menu OpenGL context   */
  40.                               NULL,            /* The game mode window      */
  41.                               0,               /* The current new window ID */
  42.                               0 };             /* The current new menu ID   */
  43. /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */
  44. static void fghClearCallBacks( SFG_Window *window )
  45. {
  46.     if( window )
  47.     {
  48.         int i;
  49.         for( i = 0; i < TOTAL_CALLBACKS; ++i )
  50.             window->CallBacks[ i ] = NULL;
  51.     }
  52. }
  53. /*
  54.  * This private function creates, opens and adds to the hierarchy
  55.  * a freeglut window complete with OpenGL context and stuff...
  56.  *
  57.  * If parent is set to NULL, the window created will be a topmost one.
  58.  */
  59. SFG_Window* fgCreateWindow( SFG_Window* parent, const char* title,
  60.                             GLboolean positionUse, int x, int y,
  61.                             GLboolean sizeUse, int w, int h,
  62.                             GLboolean gameMode, GLboolean isMenu )
  63. {
  64.     /* Have the window object created */
  65.     SFG_Window *window = (SFG_Window *)calloc( sizeof(SFG_Window), 1 );
  66. #if TARGET_HOST_UNIX_X11
  67.     window->Window.FBConfig = NULL;
  68. #endif
  69.     fghClearCallBacks( window );
  70.     /* Initialize the object properties */
  71.     window->ID = ++fgStructure.WindowID;
  72.     window->State.OldHeight = window->State.OldWidth = -1;
  73.     fgListInit( &window->Children );
  74.     if( parent )
  75.     {
  76.         fgListAppend( &parent->Children, &window->Node );
  77.         window->Parent = parent;
  78.     }
  79.     else
  80.         fgListAppend( &fgStructure.Windows, &window->Node );
  81.     /* Set the default mouse cursor and reset the modifiers value */
  82.     window->State.Cursor    = GLUT_CURSOR_INHERIT;
  83.     window->IsMenu = isMenu;
  84.     window->State.IgnoreKeyRepeat = GL_FALSE;
  85.     window->State.KeyRepeating    = GL_FALSE;
  86.     window->State.IsFullscreen    = GL_FALSE;
  87.     /*
  88.      * Open the window now. The fgOpenWindow() function is system
  89.      * dependant, and resides in freeglut_window.c. Uses fgState.
  90.      */
  91.     fgOpenWindow( window, title, positionUse, x, y, sizeUse, w, h, gameMode,
  92.                   (GLboolean)(parent ? GL_TRUE : GL_FALSE) );
  93.     return window;
  94. }
  95. /*
  96.  * This private function creates a menu and adds it to the menus list
  97.  */
  98. SFG_Menu* fgCreateMenu( FGCBMenu menuCallback )
  99. {
  100.     int x = 100, y = 100, w = 100, h = 100;
  101.     SFG_Window *current_window = fgStructure.CurrentWindow;
  102.     /* Have the menu object created */
  103.     SFG_Menu* menu = (SFG_Menu *)calloc( sizeof(SFG_Menu), 1 );
  104.     menu->ParentWindow = NULL;
  105.     /* Create a window for the menu to reside in. */
  106.     fgCreateWindow( NULL, "freeglut menu", GL_TRUE, x, y, GL_TRUE, w, h,
  107.                     GL_FALSE, GL_TRUE );
  108.     menu->Window = fgStructure.CurrentWindow;
  109.     glutDisplayFunc( fgDisplayMenu );
  110.     glutHideWindow( );  /* Hide the window for now */
  111.     fgSetWindow( current_window );
  112.     /* Initialize the object properties: */
  113.     menu->ID       = ++fgStructure.MenuID;
  114.     menu->Callback = menuCallback;
  115.     menu->ActiveEntry = NULL;
  116.     fgListInit( &menu->Entries );
  117.     fgListAppend( &fgStructure.Menus, &menu->Node );
  118.     /* Newly created menus implicitly become current ones */
  119.     fgStructure.CurrentMenu = menu;
  120.     return menu;
  121. }
  122. /*
  123.  * Function to add a window to the linked list of windows to destroy.
  124.  * Subwindows are automatically added because they hang from the window
  125.  * structure.
  126.  */
  127. void fgAddToWindowDestroyList( SFG_Window* window )
  128. {
  129.     SFG_WindowList *new_list_entry =
  130.         ( SFG_WindowList* )malloc( sizeof(SFG_WindowList ) );
  131.     new_list_entry->window = window;
  132.     fgListAppend( &fgStructure.WindowsToDestroy, &new_list_entry->node );
  133.     /* Check if the window is the current one... */
  134.     if( fgStructure.CurrentWindow == window )
  135.         fgStructure.CurrentWindow = NULL;
  136.     /*
  137.      * Clear all window callbacks except Destroy, which will
  138.      * be invoked later.  Right now, we are potentially carrying
  139.      * out a freeglut operation at the behest of a client callback,
  140.      * so we are reluctant to re-enter the client with the Destroy
  141.      * callback, right now.  The others are all wiped out, however,
  142.      * to ensure that they are no longer called after this point.
  143.      */
  144.     {
  145.         FGCBDestroy destroy = (FGCBDestroy)FETCH_WCB( *window, Destroy );
  146.         fghClearCallBacks( window );
  147.         SET_WCB( *window, Destroy, destroy );
  148.     }
  149. }
  150. /*
  151.  * Function to close down all the windows in the "WindowsToDestroy" list
  152.  */
  153. void fgCloseWindows( )
  154. {
  155.     while( fgStructure.WindowsToDestroy.First )
  156.     {
  157.         SFG_WindowList *window_ptr = fgStructure.WindowsToDestroy.First;
  158.         fgDestroyWindow( window_ptr->window );
  159.         fgListRemove( &fgStructure.WindowsToDestroy, &window_ptr->node );
  160.         free( window_ptr );
  161.     }
  162. }
  163. /*
  164.  * This function destroys a window and all of its subwindows. Actually,
  165.  * another function, defined in freeglut_window.c is called, but this is
  166.  * a whole different story...
  167.  */
  168. void fgDestroyWindow( SFG_Window* window )
  169. {
  170.     FREEGLUT_INTERNAL_ERROR_EXIT ( window, "Window destroy function called with null window",
  171.                                    "fgDestroyWindow" );
  172.     while( window->Children.First )
  173.         fgDestroyWindow( ( SFG_Window * )window->Children.First );
  174.     {
  175.         SFG_Window *activeWindow = fgStructure.CurrentWindow;
  176.         INVOKE_WCB( *window, Destroy, ( ) );
  177.         fgSetWindow( activeWindow );
  178.     }
  179.     if( window->Parent )
  180.         fgListRemove( &window->Parent->Children, &window->Node );
  181.     else
  182.         fgListRemove( &fgStructure.Windows, &window->Node );
  183.     if( window->ActiveMenu )
  184.       fgDeactivateMenu( window );
  185.     fghClearCallBacks( window );
  186.     fgCloseWindow( window );
  187.     free( window );
  188.     if( fgStructure.CurrentWindow == window )
  189.         fgStructure.CurrentWindow = NULL;
  190. }
  191. /*
  192.  * This is a helper static function that removes a menu (given its pointer)
  193.  * from any windows that can be accessed from a given parent...
  194.  */
  195. static void fghRemoveMenuFromWindow( SFG_Window* window, SFG_Menu* menu )
  196. {
  197.     SFG_Window *subWindow;
  198.     int i;
  199.     /* Check whether this is the active menu in the window */
  200.     if ( menu == window->ActiveMenu )
  201.         window->ActiveMenu = NULL ;
  202.     /*
  203.      * Check if the menu is attached to the current window,
  204.      * if so, have it detached (by overwriting with a NULL):
  205.      */
  206.     for( i = 0; i < FREEGLUT_MAX_MENUS; i++ )
  207.         if( window->Menu[ i ] == menu )
  208.             window->Menu[ i ] = NULL;
  209.     /* Call this function for all of the window's children recursively: */
  210.     for( subWindow = (SFG_Window *)window->Children.First;
  211.          subWindow;
  212.          subWindow = (SFG_Window *)subWindow->Node.Next)
  213.         fghRemoveMenuFromWindow( subWindow, menu );
  214. }
  215. /*
  216.  * This is a static helper function that removes menu references
  217.  * from another menu, given two pointers to them...
  218.  */
  219. static void fghRemoveMenuFromMenu( SFG_Menu* from, SFG_Menu* menu )
  220. {
  221.     SFG_MenuEntry *entry;
  222.     for( entry = (SFG_MenuEntry *)from->Entries.First;
  223.          entry;
  224.          entry = ( SFG_MenuEntry * )entry->Node.Next )
  225.         if( entry->SubMenu == menu )
  226.             entry->SubMenu = NULL;
  227. }
  228. /*
  229.  * This function destroys a menu specified by the parameter. All menus
  230.  * and windows are updated to make sure no ill pointers hang around.
  231.  */
  232. void fgDestroyMenu( SFG_Menu* menu )
  233. {
  234.     SFG_Window *window;
  235.     SFG_Menu *from;
  236.     FREEGLUT_INTERNAL_ERROR_EXIT ( menu, "Menu destroy function called with null menu",
  237.                                    "fgDestroyMenu" );
  238.     /* First of all, have all references to this menu removed from all windows: */
  239.     for( window = (SFG_Window *)fgStructure.Windows.First;
  240.          window;
  241.          window = (SFG_Window *)window->Node.Next )
  242.         fghRemoveMenuFromWindow( window, menu );
  243.     /* Now proceed with removing menu entries that lead to this menu */
  244.     for( from = ( SFG_Menu * )fgStructure.Menus.First;
  245.          from;
  246.          from = ( SFG_Menu * )from->Node.Next )
  247.         fghRemoveMenuFromMenu( from, menu );
  248.     /*
  249.      * If the programmer defined a destroy callback, call it
  250.      * A. Donev: But first make this the active menu
  251.      */
  252.     if( menu->Destroy )
  253.     {
  254.         SFG_Menu *activeMenu=fgStructure.CurrentMenu;
  255.         fgStructure.CurrentMenu = menu;
  256.         menu->Destroy( );
  257.         fgStructure.CurrentMenu = activeMenu;
  258.     }
  259.     /*
  260.      * Now we are pretty sure the menu is not used anywhere
  261.      * and that we can remove all of its entries
  262.      */
  263.     while( menu->Entries.First )
  264.     {
  265.         SFG_MenuEntry *entry = ( SFG_MenuEntry * ) menu->Entries.First;
  266.         fgListRemove( &menu->Entries, &entry->Node );
  267.         if( entry->Text )
  268.             free( entry->Text );
  269.         entry->Text = NULL;
  270.         free( entry );
  271.     }
  272.     if( fgStructure.CurrentWindow == menu->Window )
  273.         fgSetWindow( NULL );
  274.     fgDestroyWindow( menu->Window );
  275.     fgListRemove( &fgStructure.Menus, &menu->Node );
  276.     if( fgStructure.CurrentMenu == menu )
  277.         fgStructure.CurrentMenu = NULL;
  278.     free( menu );
  279. }
  280. /*
  281.  * This function should be called on glutInit(). It will prepare the internal
  282.  * structure of freeglut to be used in the application. The structure will be
  283.  * destroyed using fgDestroyStructure() on glutMainLoop() return. In that
  284.  * case further use of freeglut should be preceeded with a glutInit() call.
  285.  */
  286. void fgCreateStructure( void )
  287. {
  288.     /*
  289.      * We will be needing two lists: the first containing windows,
  290.      * and the second containing the user-defined menus.
  291.      * Also, no current window/menu is set, as none has been created yet.
  292.      */
  293.     fgListInit(&fgStructure.Windows);
  294.     fgListInit(&fgStructure.Menus);
  295.     fgListInit(&fgStructure.WindowsToDestroy);
  296.     fgStructure.CurrentWindow = NULL;
  297.     fgStructure.CurrentMenu = NULL;
  298.     fgStructure.MenuContext = NULL;
  299.     fgStructure.GameModeWindow = NULL;
  300.     fgStructure.WindowID = 0;
  301.     fgStructure.MenuID = 0;
  302. }
  303. /*
  304.  * This function is automatically called on glutMainLoop() return.
  305.  * It should deallocate and destroy all remnants of previous
  306.  * glutInit()-enforced structure initialization...
  307.  */
  308. void fgDestroyStructure( void )
  309. {
  310.     /* Clean up the WindowsToDestroy list. */
  311.     fgCloseWindows( );
  312.     /* Make sure all windows and menus have been deallocated */
  313.     while( fgStructure.Menus.First )
  314.         fgDestroyMenu( ( SFG_Menu * )fgStructure.Menus.First );
  315.     while( fgStructure.Windows.First )
  316.         fgDestroyWindow( ( SFG_Window * )fgStructure.Windows.First );
  317. }
  318. /*
  319.  * Helper function to enumerate through all registered top-level windows
  320.  */
  321. void fgEnumWindows( FGCBenumerator enumCallback, SFG_Enumerator* enumerator )
  322. {
  323.     SFG_Window *window;
  324.     FREEGLUT_INTERNAL_ERROR_EXIT ( enumCallback && enumerator,
  325.                                    "Enumerator or callback missing from window enumerator call",
  326.                                    "fgEnumWindows" );
  327.     /* Check every of the top-level windows */
  328.     for( window = ( SFG_Window * )fgStructure.Windows.First;
  329.          window;
  330.          window = ( SFG_Window * )window->Node.Next )
  331.     {
  332.         enumCallback( window, enumerator );
  333.         if( enumerator->found )
  334.             return;
  335.     }
  336. }
  337. /*
  338.  * Helper function to enumerate through all a window's subwindows
  339.  * (single level descent)
  340.  */
  341. void fgEnumSubWindows( SFG_Window* window, FGCBenumerator enumCallback,
  342.                        SFG_Enumerator* enumerator )
  343. {
  344.     SFG_Window *child;
  345.     FREEGLUT_INTERNAL_ERROR_EXIT ( enumCallback && enumerator,
  346.                                    "Enumerator or callback missing from subwindow enumerator call",
  347.                                    "fgEnumSubWindows" );
  348.     FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Window Enumeration" );
  349.     for( child = ( SFG_Window * )window->Children.First;
  350.          child;
  351.          child = ( SFG_Window * )child->Node.Next )
  352.     {
  353.         enumCallback( child, enumerator );
  354.         if( enumerator->found )
  355.             return;
  356.     }
  357. }
  358. /*
  359.  * A static helper function to look for a window given its handle
  360.  */
  361. static void fghcbWindowByHandle( SFG_Window *window,
  362.                                  SFG_Enumerator *enumerator )
  363. {
  364.     if ( enumerator->found )
  365.         return;
  366.     /* Check the window's handle. Hope this works. Looks ugly. That's for sure. */
  367.     if( window->Window.Handle == (SFG_WindowHandleType) (enumerator->data) )
  368.     {
  369.         enumerator->found = GL_TRUE;
  370.         enumerator->data = window;
  371.         return;
  372.     }
  373.     /* Otherwise, check this window's children */
  374.     fgEnumSubWindows( window, fghcbWindowByHandle, enumerator );
  375. }
  376. /*
  377.  * fgWindowByHandle returns a (SFG_Window *) value pointing to the
  378.  * first window in the queue matching the specified window handle.
  379.  * The function is defined in freeglut_structure.c file.
  380.  */
  381. SFG_Window* fgWindowByHandle ( SFG_WindowHandleType hWindow )
  382. {
  383.     SFG_Enumerator enumerator;
  384.     /* This is easy and makes use of the windows enumeration defined above */
  385.     enumerator.found = GL_FALSE;
  386.     enumerator.data = (void *)hWindow;
  387.     fgEnumWindows( fghcbWindowByHandle, &enumerator );
  388.     if( enumerator.found )
  389.         return( SFG_Window *) enumerator.data;
  390.     return NULL;
  391. }
  392. /*
  393.  * A static helper function to look for a window given its ID
  394.  */
  395. static void fghcbWindowByID( SFG_Window *window, SFG_Enumerator *enumerator )
  396. {
  397.     /* Make sure we do not overwrite our precious results... */
  398.     if( enumerator->found )
  399.         return;
  400.     /* Check the window's handle. Hope this works. Looks ugly. That's for sure. */
  401.     if( window->ID == *( int *)(enumerator->data) )
  402.     {
  403.         enumerator->found = GL_TRUE;
  404.         enumerator->data = window;
  405.         return;
  406.     }
  407.     /* Otherwise, check this window's children */
  408.     fgEnumSubWindows( window, fghcbWindowByID, enumerator );
  409. }
  410. /*
  411.  * This function is similiar to the previous one, except it is
  412.  * looking for a specified (sub)window identifier. The function
  413.  * is defined in freeglut_structure.c file.
  414.  */
  415. SFG_Window* fgWindowByID( int windowID )
  416. {
  417.     SFG_Enumerator enumerator;
  418.     /* Uses a method very similiar for fgWindowByHandle... */
  419.     enumerator.found = GL_FALSE;
  420.     enumerator.data = ( void * )&windowID;
  421.     fgEnumWindows( fghcbWindowByID, &enumerator );
  422.     if( enumerator.found )
  423.         return ( SFG_Window * )enumerator.data;
  424.     return NULL;
  425. }
  426. /*
  427.  * Looks up a menu given its ID. This is easier that fgWindowByXXX
  428.  * as all menus are placed in one doubly linked list...
  429.  */
  430. SFG_Menu* fgMenuByID( int menuID )
  431. {
  432.     SFG_Menu *menu = NULL;
  433.     /* It's enough to check all entries in fgStructure.Menus... */
  434.     for( menu = (SFG_Menu *)fgStructure.Menus.First;
  435.          menu;
  436.          menu = (SFG_Menu *)menu->Node.Next )
  437.         if( menu->ID == menuID )
  438.             return menu;
  439.     return NULL;
  440. }
  441. /*
  442.  * List functions...
  443.  */
  444. void fgListInit(SFG_List *list)
  445. {
  446.     list->First = NULL;
  447.     list->Last = NULL;
  448. }
  449. void fgListAppend(SFG_List *list, SFG_Node *node)
  450. {
  451.     if ( list->Last )
  452.     {
  453.         SFG_Node *ln = (SFG_Node *) list->Last;
  454.         ln->Next = node;
  455.         node->Prev = ln;
  456.     }
  457.     else
  458.     {
  459.         node->Prev = NULL;
  460.         list->First = node;
  461.     }
  462.     node->Next = NULL;
  463.     list->Last = node;
  464. }
  465. void fgListRemove(SFG_List *list, SFG_Node *node)
  466. {
  467.     if( node->Next )
  468.         ( ( SFG_Node * )node->Next )->Prev = node->Prev;
  469.     if( node->Prev )
  470.         ( ( SFG_Node * )node->Prev )->Next = node->Next;
  471.     if( ( ( SFG_Node * )list->First ) == node )
  472.         list->First = node->Next;
  473.     if( ( ( SFG_Node * )list->Last ) == node )
  474.         list->Last = node->Prev;
  475. }
  476. int fgListLength(SFG_List *list)
  477. {
  478.     SFG_Node *node;
  479.     int length = 0;
  480.     for( node =( SFG_Node * )list->First;
  481.          node;
  482.          node = ( SFG_Node * )node->Next )
  483.         ++length;
  484.     return length;
  485. }
  486. void fgListInsert(SFG_List *list, SFG_Node *next, SFG_Node *node)
  487. {
  488.     SFG_Node *prev;
  489.     if( (node->Next = next) )
  490.     {
  491.         prev = next->Prev;
  492.         next->Prev = node;
  493.     }
  494.     else
  495.     {
  496.         prev = list->Last;
  497.         list->Last = node;
  498.     }
  499.     if( (node->Prev = prev) )
  500.         prev->Next = node;
  501.     else
  502.         list->First = node;
  503. }
  504. /*** END OF FILE ***/