#ifdef G_OS_WIN32 #define WIN32_LEAN_AND_MEAN 1 #include #else #define FALSE 0 #define TRUE !FALSE #endif #include #include #include #include #include "menu.h" #include "button.h" #include "font.h" #define MENU_MAX_BUTTONS 16 enum MenuState { MENU_OFF, MENU_MAIN, MENU_START, MENU_OPTIONS }; struct MenuStruct { enum MenuState m_iMenuId; int m_iButtonCount; struct ButtonStruct m_sButtons[MENU_MAX_BUTTONS]; }; struct MenuStruct g_sMenuOff; // definition of the menu when it's disabled (empty menu) struct MenuStruct g_sMenuMain; // definition of the main menu struct MenuStruct g_sMenuStart; // definition of the start menu struct MenuStruct g_sMenuOptions; // definition of the options menu struct MenuStruct *g_pCurMenu; // current menu struct BitmapStruct g_sCursorImage; // bitmap struct of the cursor int g_iWinWidth; int g_iWinHeight; int g_iXPos; // last cursor pos int g_iYPos; void MenuEnableGroup(int f_iGroup) { struct ButtonStruct l_sButton; int l_iType, l_iGroup; int i = 0; // enable first radio button in this group while (i < g_pCurMenu->m_iButtonCount) { l_sButton = g_pCurMenu->m_sButtons[i]; l_iType = l_sButton.m_iType; l_iGroup = l_sButton.m_iGroup; if (l_iType == BUTTON_RADIO && l_iGroup == f_iGroup) { ButtonEnable(&g_pCurMenu->m_sButtons[i]); return; } i++; } } // MenuEnableGroup void MenuAddButton(int f_dXPos, int f_dYPos, int f_dWidth, int f_dHeight, char *f_pcTitle, int f_iType, int f_iGroup) { int i = g_pCurMenu->m_iButtonCount; if (i > MENU_MAX_BUTTONS - 1) return; // create the button with the right parameters g_pCurMenu->m_sButtons[i] = ButtonCreate(f_dXPos, f_dYPos, f_dWidth, f_dHeight, f_pcTitle, f_iType, f_iGroup, i); g_pCurMenu->m_iButtonCount = i + 1; } // MenuAddButton void MenuClear(void) { g_pCurMenu->m_iButtonCount = 0; memset(&g_pCurMenu->m_sButtons, 0, sizeof(g_pCurMenu->m_sButtons)); } // MenuClear void MenuBuild (void) { int l_iMenuId = g_pCurMenu->m_iMenuId; switch (l_iMenuId) { default: case MENU_OFF: // no buttons break; case MENU_MAIN: MenuAddButton(200, 150, 256, 128, "START", BUTTON_CLICK, BUTTON_NO_GROUP); break; case MENU_START: MenuAddButton(50, 50, 250, 64, "Button 1", BUTTON_CLICK, BUTTON_NO_GROUP); MenuAddButton(50, 150, 250, 64, "Button 2", BUTTON_CLICK, BUTTON_NO_GROUP); MenuAddButton(350, 50, 64, 64, "Radio 1", BUTTON_RADIO, BUTTON_GROUP1); MenuAddButton(350, 150, 64, 64, "Radio 2", BUTTON_RADIO, BUTTON_GROUP1); MenuEnableGroup(BUTTON_GROUP1); MenuAddButton(50, 250, 256, 64, "Button 3", BUTTON_CLICK, BUTTON_NO_GROUP); MenuAddButton(50, 350, 256, 64, "Button 4", BUTTON_CLICK, BUTTON_NO_GROUP); MenuAddButton(350, 250, 64, 64, "Radio A", BUTTON_RADIO, BUTTON_GROUP2); MenuAddButton(350, 350, 64, 64, "Radio B", BUTTON_RADIO, BUTTON_GROUP2); MenuEnableGroup(BUTTON_GROUP2); break; case MENU_OPTIONS: MenuAddButton(50, 150, 250, 64, "Start", BUTTON_CLICK, BUTTON_NO_GROUP); MenuAddButton(50, 250, 250, 64, "Back", BUTTON_CLICK, BUTTON_NO_GROUP); MenuAddButton(350, 150, 64, 64, "Try first!", BUTTON_RADIO, BUTTON_GROUP1); MenuAddButton(350, 250, 64, 64, "10 games", BUTTON_RADIO, BUTTON_GROUP1); MenuEnableGroup(BUTTON_GROUP1); break; } } // MenuBuild void MenuNext(void) { int l_iMenuId = g_pCurMenu->m_iMenuId; l_iMenuId = (l_iMenuId + 1) % 4; switch (l_iMenuId) { default: case MENU_OFF: g_pCurMenu = &g_sMenuOff; break; case MENU_MAIN: g_pCurMenu = &g_sMenuMain; break; case MENU_START: g_pCurMenu = &g_sMenuStart; break; case MENU_OPTIONS: g_pCurMenu = &g_sMenuOptions; break; } } // MenuNext void MenuInit(int f_iWinWidth, int f_iWinHeight) { // init menu props g_iWinWidth = f_iWinWidth; g_iWinHeight = f_iWinHeight; g_iXPos = -100; g_iYPos = -100; // init main off g_sMenuOff.m_iMenuId = MENU_OFF; g_pCurMenu = &g_sMenuOff; MenuBuild(); // init main menu g_sMenuMain.m_iMenuId = MENU_MAIN; g_pCurMenu = &g_sMenuMain; MenuBuild(); // init start menu g_sMenuStart.m_iMenuId = MENU_START; g_pCurMenu = &g_sMenuStart; MenuBuild(); // init options menu g_sMenuOptions.m_iMenuId = MENU_OPTIONS; g_pCurMenu = &g_sMenuOptions; MenuBuild(); // init font FontInit(f_iWinWidth, f_iWinHeight); g_pCurMenu = &g_sMenuOff; // load cursor image g_sCursorImage = BitmapLoad("img/cursor.bmp"); } // MenuInit void MenuRender(void) { int i = 0; glClearColor(0.9, 0.9, 0.9, 1); glDisable(GL_DEPTH_TEST); glEnable(GL_TEXTURE_2D); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(0, g_iWinWidth, g_iWinHeight, 0, 0, 1); glMatrixMode(GL_MODELVIEW); glEnable(GL_BLEND); if (g_pCurMenu->m_iMenuId != MENU_OFF) { glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR); glColor3d(0.6, 0.6, 0.7); glBegin(GL_TRIANGLE_STRIP); glVertex2i(0, 0); glVertex2i(g_iWinWidth, 0); glVertex2i(0, g_iWinHeight); glVertex2i(g_iWinWidth, g_iWinHeight); glEnd(); } glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // render the buttons of the current menu for (i; i < g_pCurMenu->m_iButtonCount; i++) { glColor4d(1, 1, 1, 1); ButtonRender(&g_pCurMenu->m_sButtons[i]); } // render cursor glColor3d(1, 1, 1); BitmapRender(g_iXPos, g_iYPos, 64, //g_sCursorImage.m_iWidth, 64, //g_sCursorImage.m_iHeight, g_sCursorImage.m_iImageId); glDisable(GL_BLEND); //restore the previous projection matrix glMatrixMode(GL_PROJECTION); glPopMatrix(); } // MenuRender int MenuCollision(struct ButtonStruct *f_sButton, int f_iXPos, int f_iYPos) { int l_bCollision; int l_iButtonX, l_iButtonY; int l_iButtonWidth, l_iButtonHeight; l_iButtonX = f_sButton->m_iXPos; l_iButtonY = f_sButton->m_iYPos; l_iButtonWidth = f_sButton->m_iWidth; l_iButtonHeight = f_sButton->m_iHeight; l_bCollision = f_iXPos >= l_iButtonX; l_bCollision &= f_iYPos >= l_iButtonY; l_bCollision &= f_iXPos <= l_iButtonX + l_iButtonWidth; l_bCollision &= f_iYPos <= l_iButtonY + l_iButtonHeight; if (l_bCollision) return TRUE; return FALSE; } // MenuCollision void MenuMouseClick(int f_iGlutButton, int f_iGlutState, int f_iXPos, int f_iYPos) { int i = 0; int l_iXPos, l_iYPos; int l_iWidth, l_iHeight; int l_iType, l_iId, l_iGroup; struct ButtonStruct l_sButton; // button released if (f_iGlutButton == GLUT_LEFT_BUTTON && f_iGlutState == GLUT_UP) { // post a button released event to all buttons for (i; i < g_pCurMenu->m_iButtonCount; i++) { l_iType = g_pCurMenu->m_sButtons[i].m_iType; ButtonRelease(&g_pCurMenu->m_sButtons[i]); } } // check if any button needs attention from the mouse i = g_pCurMenu->m_iButtonCount; for (i; i >= 0; i--) { l_sButton = g_pCurMenu->m_sButtons[i]; l_iXPos = l_sButton.m_iXPos; l_iYPos = l_sButton.m_iYPos; l_iWidth = l_sButton.m_iWidth; l_iHeight = l_sButton.m_iHeight; l_iType = l_sButton.m_iType; l_iId = l_sButton.m_iId; l_iGroup = l_sButton.m_iGroup; if (MenuCollision(&l_sButton, f_iXPos, f_iYPos)) { // button pressed? if (f_iGlutButton == GLUT_LEFT_BUTTON && f_iGlutState == GLUT_DOWN) { ButtonPress(&g_pCurMenu->m_sButtons[i]); if (l_iType == BUTTON_RADIO) { i = 0; while (i < g_pCurMenu->m_iButtonCount) { if (l_iId != g_pCurMenu->m_sButtons[i].m_iId && l_iType == g_pCurMenu->m_sButtons[i].m_iType && l_iGroup == g_pCurMenu->m_sButtons[i].m_iGroup) { ButtonDisable(&g_pCurMenu->m_sButtons[i]); } i++; } } return; } } } } // MenuMouseClick void MenuMouseMove(int f_iXPos, int f_iYPos) { int i = 0; struct ButtonStruct l_sButton; g_iXPos = f_iXPos; g_iYPos = f_iYPos; // check if any button needs attention from the mouse for (i; i < g_pCurMenu->m_iButtonCount; i++) { l_sButton = g_pCurMenu->m_sButtons[i]; if (MenuCollision(&l_sButton, f_iXPos, f_iYPos)) { ButtonEnter(&g_pCurMenu->m_sButtons[i]); } else // mouse leaves button { ButtonExit(&g_pCurMenu->m_sButtons[i]); } } } // MenuMouseMove