www.pudn.com > RCApp-src.zip > GUI.cpp


/* 
	RedEye Project (http://members.ozemail.com.au/~ndmcevoy/) 
	Copyright (C) 2003  Nick McEvoy 
 
	This library is free software; you can redistribute it and/or 
	modify it under the terms of the GNU Library General Public 
	License as published by the Free Software Foundation; either 
	version 2 of the License, or (at your option) any later version. 
 
	This library is distributed in the hope that it will be useful, 
	but WITHOUT ANY WARRANTY; without even the implied warranty of 
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
	Library General Public License for more details. 
 
	You should have received a copy of the GNU Library General Public 
	License along with this library; if not, write to the Free 
	Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
 
	----------------------------------------------------------------- 
 
		Commented for use with Doxygen (http://www.doxygen.org) 
 
	----------------------------------------------------------------- 
*/ 
 
/*! \file GUI.cpp 
 *	\brief Game gui. 
 * 
 *		This file contains the game gui. 
 */ 
 
// GLUT includes 
#include  
 
// RedEye includes 
#include "GUI.h" 
#include "Engine.h" 
#include "SoundManager.h" 
 
const char* re_version = "1.0"; 
 
const char* credits_text = 
	"CREDITS\n\n" 
	"  Nick McEvoy                  : coding & design\n" 
	"\nSpecial thanks to:\n" 
	"  Steve Baker                  : for PLIB & example code\n" 
	"  Russell Smith                : for ODE physics engine\n" 
	"  Larry Ewing                  : for painting the original Tux image\n" 
	"  DigiBen                      : for 3D Triangle-Sphere overlap testing\n" 
	"  Tomas Akenine-Moller         : for fast 3D Triangle-Box overlap testing\n" 
	"\nAlso thanks to:\n" 
	"  Jarred McEvoy (my son 6 yrs) : game tester\n" 
	"  Owen McEvoy (my son 4 yrs)   : game tester\n" 
	"\nAnd finaly thanks to:\n" 
	"  Donna McEvoy (my wife)       : computer widow :)"; 
 
const char* about_text = 
	"ABOUT\n\n" 
	"todo:\n"; 
 
const char* help_text =  
	"HELP\n" 
	"\nControls:\n" 
	"  up arrow        : forward\n" 
	"  down arrow      : reverse\n" 
	"  left arrow      : steer left\n" 
	"  right arrow     : steer right\n" 
	"  <>              : roll left & right (jetski only)\n" 
	"\nView:\n" 
	"  f1              : player view\n" 
	"  f2              : external view attached\n" 
	"  f3              : external view detached\n" 
	"  f4              : tracking view\n" 
	"  shift+arrows    : rotate external camera\n" 
	"  page-up/down    : zoom in/out external camera\n" 
	"  home            : reset external camera\n" 
	"  t               : toggle tracking (closest) target\n" 
	"  n               : select next target\n" 
	"\nGame:\n" 
	"  r               : restart\n" 
	"  h               : help\n" 
	"  p               : pause\n" 
	"  escape          : quit\n"; 
 
//! The one and only instance 
reGameGUI* reGameGUI::mpInstance = NULL; 
 
static puMenuBar   *main_menu_bar; 
 
static puDialogBox *dialog_box; 
static reText      *dialog_box_message; 
static puOneShot   *dialog_box_ok_button; 
 
static puDialogBox *load_dialog_box; 
static puListBox   *load_dialog_box_list_box; 
static puOneShot   *load_dialog_box_ok_button; 
static puOneShot   *load_dialog_box_cancel_button; 
 
#define RE_MAX_LEVELS	20 
static char* level_desc[RE_MAX_LEVELS] = {0}; 
static char* level_dir[RE_MAX_LEVELS] = {0}; 
static int miNumLevels = 0; 
 
static void start_cb(puObject*) 
{ 
	int iIndex = load_dialog_box_list_box->getValue(); 
 
	char sLevelDir[RE_STRING_MAX]; 
	sprintf(sLevelDir, "%s", level_dir[iIndex]); 
 
	// Hide the dialog (see warning below) 
	load_dialog_box->hide(); 
 
	// Start the game 
	reGetGameEngine()->LoadLevel(sLevelDir); 
 
	// Delete dialog box 
	// warning: if deleted b4 loading level ... we get an 
	// exception due to puMouse(button, state, x, y) arriving 
	// after dialog is deleted !??? 
	puDeleteObject(load_dialog_box); 
	load_dialog_box = NULL; 
} 
 
static void go_away_cb(puObject*) 
{ 
	// Unpause game (if paused) 
	reGetGameEngine()->SetGamePaused(false); 
 
	// Delete dialog box 
	puDeleteObject(dialog_box); 
	dialog_box = NULL; 
} 
 
static void mk_dialog(int w, int h, const char *fmt, ...) 
{ 
	// Pause game (if running) 
	reGetGameEngine()->SetGamePaused(true); 
 
	static char sMsg[RE_GUI_STRING_MAX]; 
 
	int win_w = glutGet(GLUT_WINDOW_WIDTH); 
	int win_h = glutGet(GLUT_WINDOW_HEIGHT); 
	int cx = win_w/2; 
	int cy = win_h/2; 
	int dx = cx - w/2; 
	int dy = cy - h/2; 
 
	va_list argptr; 
	va_start(argptr, fmt); 
	vsprintf(sMsg, fmt, argptr); 
	va_end(argptr); 
 
	dialog_box = new puDialogBox(dx, dy); 
	{ 
		new puFrame(0, 0, w, h); 
		dialog_box_message = new reText(10, h-30); 
		dialog_box_message->SetLabel(sMsg); 
		dialog_box_ok_button = new puOneShot(w/2-30, 10, w/2+30, 50); 
		dialog_box_ok_button->setLegend("OK"); 
		dialog_box_ok_button->makeReturnDefault(TRUE); 
		dialog_box_ok_button->setCallback(go_away_cb); 
	} 
	dialog_box->close(); 
	dialog_box->reveal(); 
} 
 
static void mk_load_level_dialog(char** list, 
								 const char* ok_legend, 
								 const char* cancel_legend, 
								 puCallback ok_cb, 
								 puCallback cancel_cb) 
{ 
	// Pause game (if running) 
	reGetGameEngine()->SetGamePaused(true); 
 
	int w = 400; 
	int h = 400; 
	int win_w = glutGet(GLUT_WINDOW_WIDTH); 
	int win_h = glutGet(GLUT_WINDOW_HEIGHT); 
	int cx = win_w/2; 
	int cy = win_h/2; 
	int dx = cx - w/2; 
	int dy = cy - h/2; 
 
	load_dialog_box = new puDialogBox(dx, dy); 
	{ 
		new puFrame(0, 0, w, h); 
		load_dialog_box_list_box = new puListBox(w/2-150, 60, w/2+150, h-30, list); 
		load_dialog_box_list_box->setValue(0); 
		if (ok_legend) 
		{ 
			load_dialog_box_ok_button = new puOneShot(w/2-30, 10, w/2+30, 50); 
			load_dialog_box_ok_button->setLegend(ok_legend); 
			load_dialog_box_ok_button->makeReturnDefault(TRUE); 
			load_dialog_box_ok_button->setCallback(ok_cb); 
		} 
		if (cancel_legend) 
		{ 
			load_dialog_box_cancel_button = new puOneShot(w/2+60, 10, w/2+120, 50); 
			load_dialog_box_cancel_button->setLegend(cancel_legend); 
			load_dialog_box_cancel_button->makeReturnDefault(FALSE); 
			load_dialog_box_cancel_button->setCallback(cancel_cb); 
		} 
	} 
	load_dialog_box->close(); 
	load_dialog_box->reveal(); 
} 
 
static void exit_cb(puObject*) 
{ 
	delete reGetGameEngine(); 
	exit(0); 
} 
 
static void window_on_cb(puObject*) 
{ 
	reGetGameEngine()->SetFullscreen(false); 
} 
 
static void window_off_cb(puObject*) 
{ 
	reGetGameEngine()->SetFullscreen(true); 
} 
 
static void music_off_cb(puObject*) 
{ 
	reGetSoundManager()->SetMusicOn(false); 
} 
 
static void sfx_off_cb(puObject*) 
{ 
	reGetSoundManager()->SetSoundFxOn(false); 
} 
 
static void music_on_cb(puObject*) 
{ 
	reGetSoundManager()->SetMusicOn(true); 
} 
 
static void sfx_on_cb(puObject*) 
{ 
	reGetSoundManager()->SetSoundFxOn(true); 
} 
 
static void versions_cb(puObject*) 
{ 
	char sVersions[RE_GUI_STRING_MAX]; 
	sprintf(sVersions, 
		"VERSIONS\n\n" 
		"Reality Check Version : %s\n" 
		"PLIB Version          : %s\n" 
		"ODE Version           : %s\n" 
		"OpenGL Version        : %s\n" 
		"OpenGL Vendor         : %s\n" 
		"OpenGL Renderer       : %s\n", 
		re_version, 
		ssgGetVersion(), 
		"0.03", 
		glGetString(GL_VERSION), 
		glGetString(GL_VENDOR), 
		glGetString(GL_RENDERER)); 
	mk_dialog(500, 180, sVersions); 
} 
 
static void credits_cb(puObject*) 
{ 
	mk_dialog(650, 290, credits_text); 
	// todo: would be good to read from xml ... but need \n tags converted, etc... 
	//mk_dialog(650, 290, reGetXMLChildValue(reGetGameEngine()->GetXMLConfigNode(), "Credits", "")); 
} 
 
static void about_cb(puObject*) 
{ 
	mk_dialog(600, 300, about_text); 
	// todo: would be good to read from xml ... but need \n tags converted, etc... 
	//mk_dialog(650, 290, reGetXMLChildValue(reGetGameEngine()->GetXMLConfigNode(), "About", "")); 
} 
 
static void help_cb(puObject*) 
{ 
	mk_dialog(600, 350, help_text); 
	// todo: would be good to read from xml ... but need \n tags converted, etc... 
	//mk_dialog(650, 290, reGetXMLChildValue(reGetGameEngine()->GetXMLConfigNode(), "Help", "")); 
} 
 
// Menu bar entries 
static char      *file_submenu    [] = {  "Exit", NULL } ; 
static puCallback file_submenu_cb [] = { exit_cb, NULL } ; 
 
static char      *view_submenu    [] = { "Windowed"  , "Fullscreen" , NULL } ; 
static puCallback view_submenu_cb [] = { window_on_cb, window_off_cb, NULL } ; 
 
static char      *sound_submenu    [] = { "Turn off Music", "Turn off Sounds", "Turn on Music", "Turn on Sounds", NULL } ; 
static puCallback sound_submenu_cb [] = { music_off_cb, sfx_off_cb, music_on_cb, sfx_on_cb, NULL } ; 
 
static char      *help_submenu    [] = { "Versions...", "Credits...", "About...",  "Help...", NULL } ; 
static puCallback help_submenu_cb [] = { versions_cb, credits_cb, about_cb, help_cb, NULL } ; 
 
 
 
 
reGameGUI::reGameGUI() 
:	mNotifyText(0,0), 
	mStatusText(0,0), 
	mPlayerText(0,0), 
	mDebugText(0,0) 
{ 
	puSetDefaultStyle(PUSTYLE_SMALL_SHADED); 
	puSetDefaultColourScheme(0.3f, 0.4f, 0.6f, 1.0f); 
 
	mNotifyText.setColour(PUCOL_LABEL, 1.0, 1.0, 1.0); 
	mNotifyText.hide(); 
 
	mStatusText.setColour(PUCOL_LABEL, 1.0, 1.0, 1.0); 
	mStatusText.hide(); 
 
	mPlayerText.setColour(PUCOL_LABEL, 1.0, 1.0, 1.0); 
	mPlayerText.setColour(PUCOL_BACKGROUND, 0.0, 0.0, 0.8, 0.5); 
	mPlayerText.hide(); 
 
	mDebugText.setColour(PUCOL_LABEL, 1.0, 1.0, 1.0); 
	mDebugText.hide(); 
 
	main_menu_bar = new puMenuBar(); 
	main_menu_bar->add_submenu("Game", file_submenu, file_submenu_cb); 
	main_menu_bar->add_submenu("View", view_submenu, view_submenu_cb); 
	main_menu_bar->add_submenu("Sound", sound_submenu, sound_submenu_cb); 
	main_menu_bar->add_submenu("Help", help_submenu, help_submenu_cb); 
	main_menu_bar->close(); 
	main_menu_bar->reveal(); 
} 
 
 
 
 
reGameGUI::~reGameGUI() 
{ 
	mpInstance = NULL; 
} 
 
 
 
 
reGameGUI* 
reGameGUI::GetInstance() 
{ 
	if (mpInstance == NULL) 
	{ 
		mpInstance = new reGameGUI; 
	} 
	return mpInstance; 
} 
 
 
 
 
void 
reGameGUI::Display() 
{ 
	puDisplay(); 
} 
 
 
 
 
void 
reGameGUI::Reshape(int w, int h) 
{ 
	int cx = w/2; 
	int cy = h/2; 
 
	mNotifyText.setPosition(cx-150, cy); 
	mStatusText.setPosition(10, 10); 
	mPlayerText.setPosition(10, h-80); 
	mDebugText.setPosition(w-120, h-20); 
 
	if (dialog_box) 
	{ 
		int dw, dh; 
		dialog_box->getSize(&dw, &dh); 
		dialog_box->setPosition(cx - dw/2, cy - dh/2); 
	} 
	if (load_dialog_box) 
	{ 
		int dw, dh; 
		load_dialog_box->getSize(&dw, &dh); 
		load_dialog_box->setPosition(cx - dw/2, cy - dh/2); 
	} 
} 
 
 
 
 
void 
reGameGUI::Keyboard(unsigned char key, int x, int y, bool bKeyDown) 
{ 
	if (bKeyDown) 
		puKeyboard(key, PU_DOWN); 
} 
 
 
 
 
void 
reGameGUI::KeyboardSpecial(int key, int x, int y, bool bKeyDown) 
{ 
} 
 
 
 
 
void 
reGameGUI::MouseFunc(int button, int state, int x, int y) 
{ 
	puMouse(button, state, x, y); 
} 
 
 
 
 
void 
reGameGUI::MotionFunc(int x, int y) 
{ 
	puMouse(x, y); 
} 
 
 
 
 
void 
reGameGUI::PassiveMotionFunc(int x, int y) 
{ 
	puMouse(x, y); 
} 
 
 
 
 
void 
reGameGUI::ShowLoadLevel() 
{ 
	int i; 
 
	// Tidy-up 
	for (i = 0; i < miNumLevels; i++) 
	{ 
		delete [] level_desc[i]; 
		delete [] level_dir[i]; 
	} 
	miNumLevels = 0; 
 
	// Get levels 
	i = 0; 
	TiXmlNode* pNode = reGetGameEngine()->GetXMLConfigNode(); 
	pNode = pNode->FirstChild("Levels"); 
	pNode = pNode->FirstChild("Level"); 
	TiXmlNode* pElement = pNode->ToElement(); 
	while (pElement && i < RE_MAX_LEVELS) 
	{ 
		const char* psName = reGetXMLAttribute(pElement, "name", ""); 
		const char* psDesc = reGetXMLAttribute(pElement, "desc", ""); 
		const char* psFile = reGetXMLAttribute(pElement, "file", ""); 
 
		printf("Level %s,%s,%s\n", psName, psDesc, psFile); 
 
		level_desc[i] = new char[strlen(psDesc)+1]; 
		strcpy(level_desc[i], psDesc); 
		level_dir[i] = new char[strlen(psFile)+1]; 
		strcpy(level_dir[i], psFile); 
 
		pElement = pElement->NextSiblingElement(); 
		i++; 
	} 
	miNumLevels = i; 
	 
	level_desc[miNumLevels+1] = NULL; 
	level_dir[miNumLevels+1] = NULL; 
 
	mk_load_level_dialog( 
		level_desc, 
		"Start", 
		"Quit", 
		start_cb, 
		exit_cb); 
} 
 
 
 
 
void 
reGameGUI::ShowHelp() 
{ 
	help_cb(NULL); 
} 
 
 
 
 
void 
reGameGUI::SetTextOff() 
{ 
	SetTextOn(eNotifyText, false); 
	SetTextOn(eStatusText, false); 
	SetTextOn(ePlayerText, false); 
	SetTextOn(eDebugText, false); 
} 
 
 
 
 
void 
reGameGUI::SetText(eGUIText eText, const char* sText, bool bOn) 
{ 
	reText* pText = NULL; 
 
	switch (eText) 
	{ 
	case eNotifyText: 
		pText = &mNotifyText; 
		break; 
	case eStatusText: 
		pText = &mStatusText; 
		break; 
	case ePlayerText: 
		pText = &mPlayerText; 
		break; 
	case eDebugText: 
		pText = &mDebugText; 
		break; 
	default: 
		pText = NULL; 
		break; 
	} 
 
	if (pText) 
	{ 
		pText->SetLabel(sText); 
		if (bOn) 
			pText->reveal(); 
		else 
			pText->hide(); 
	} 
} 
 
 
 
 
void 
reGameGUI::SetTextOn(eGUIText eText, bool bOn) 
{ 
	reText* pText = NULL; 
 
	switch (eText) 
	{ 
	case eNotifyText: 
		pText = &mNotifyText; 
		break; 
	case eStatusText: 
		pText = &mStatusText; 
		break; 
	case ePlayerText: 
		pText = &mPlayerText; 
		break; 
	case eDebugText: 
		pText = &mDebugText; 
		break; 
	default: 
		pText = NULL; 
		break; 
	} 
 
	if (pText) 
	{ 
		if (bOn) 
			pText->reveal(); 
		else 
			pText->hide(); 
	} 
}