X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=radiant%2Fqe3.cpp;h=1bce60b9a38acb676709ad12a4edcefa765c3a2d;hb=f806ac65b11eb35a8ffd5df61ac1aed06763d49e;hp=201154ecb48cc393494685fc1377c56c26ebd5b2;hpb=830125fad042fad35dc029b6eb57c8156ad7e176;p=xonotic%2Fnetradiant.git diff --git a/radiant/qe3.cpp b/radiant/qe3.cpp index 201154ec..1bce60b9 100644 --- a/radiant/qe3.cpp +++ b/radiant/qe3.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 1999-2007 id Software, Inc. and contributors. + Copyright (C) 1999-2006 Id Software, Inc. and contributors. For a list of contributors, see the accompanying CONTRIBUTORS file. This file is part of GtkRadiant. @@ -19,1697 +19,330 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +/* + The following source code is licensed by Id Software and subject to the terms of + its LIMITED USE SOFTWARE LICENSE AGREEMENT, a copy of which is included with + GtkRadiant. If you did not receive a LIMITED USE SOFTWARE LICENSE AGREEMENT, + please contact Id Software immediately at info@idsoftware.com. + */ + // // Linux stuff // // Leonardo Zide (leo@lokigames.com) // -#include "stdafx.h" -#include -#include -#include "gtkmisc.h" -#include -#if defined ( __linux__ ) || defined ( __APPLE__ ) -#include -#include -#include -#include -#endif -// for the logging part -#include -#include - -QEGlobals_t g_qeglobals; -QEGlobals_GUI_t g_qeglobals_gui; - -// leo: Track memory allocations for debugging -// NOTE TTimo this was never used and probably not relevant -// there are tools to do that -#ifdef MEM_DEBUG +#include "qe3.h" -static GList *memblocks; +#include "debugging/debugging.h" -void* debug_malloc( size_t size, const char* file, int line ){ - void *buf = g_malloc( size + 8 ); +#include "ifilesystem.h" +//#include "imap.h" - *( (const char**)buf ) = file; - buf = (char*)buf + 4; - *( (int*)buf ) = line; - buf = (char*)buf + 4; +#include - memblocks = g_list_append( memblocks, buf ); +#include - return buf; -} +#include "stream/textfilestream.h" +#include "cmdlib.h" +#include "stream/stringstream.h" +#include "os/path.h" +#include "scenelib.h" -void debug_free( void *buf, const char* file, int line ){ - const char *f; - int l; +#include "gtkutil/messagebox.h" +#include "error.h" +#include "map.h" +#include "build.h" +#include "points.h" +#include "camwindow.h" +#include "mainframe.h" +#include "preferences.h" +#include "watchbsp.h" +#include "autosave.h" +#include "convert.h" - if ( g_list_find( memblocks, buf ) ) { - memblocks = g_list_remove( memblocks, buf ); +QEGlobals_t g_qeglobals; - buf = (char*)buf - 4; - l = *( (int*)buf ); - buf = (char*)buf - 4; - f = *( (const char**)buf ); - Sys_FPrintf( SYS_DBG, "free: %s %d", file, line ); - Sys_FPrintf( SYS_DBG, " allocated: %s %d\n", f, l ); +#if defined( WIN32 ) +#define PATH_MAX 260 +#endif - g_free( buf ); - } -// else -// free (buf); // from qmalloc, will leak unless we add this same hack to cmdlib -} -#endif +void QE_InitVFS(){ + // VFS initialization ----------------------- + // we will call GlobalFileSystem().initDirectory, giving the directories to look in (for files in pk3's and for standalone files) + // we need to call in order, the mod ones first, then the base ones .. they will be searched in this order + // *nix systems have a dual filesystem in ~/.q3a, which is searched first .. so we need to add that too -vec_t Rad_rint( vec_t in ){ - if ( g_PrefsDlg.m_bNoClamp ) { - return in; - } - else{ - return (float)floor( in + 0.5 ); - } -} + const char* gamename = gamename_get(); + const char* basegame = basegame_get(); + const char* userRoot = g_qeglobals.m_userEnginePath.c_str(); + const char* globalRoot = EnginePath_get(); -void WINAPI QE_CheckOpenGLForErrors( void ){ - char strMsg[1024]; - int i = qglGetError(); - if ( i != GL_NO_ERROR ) { - if ( i == GL_OUT_OF_MEMORY ) { - sprintf( strMsg, "OpenGL out of memory error %s\nDo you wish to save before exiting?", qgluErrorString( (GLenum)i ) ); - if ( gtk_MessageBox( g_pParentWnd->m_pWidget, strMsg, "Radiant Error", MB_YESNO ) == IDYES ) { - Map_SaveFile( NULL, false ); - } - _exit( 1 ); + // if we have a mod dir + if ( !string_equal( gamename, basegame ) ) { + // ~/./ + if ( userRoot ) { + StringOutputStream userGamePath( 256 ); + userGamePath << userRoot << gamename << '/'; + GlobalFileSystem().initDirectory( userGamePath.c_str() ); } - else + + // / { - Sys_Printf( "Warning: OpenGL Error %s\n", qgluErrorString( (GLenum)i ) ); + StringOutputStream globalGamePath( 256 ); + globalGamePath << globalRoot << gamename << '/'; + GlobalFileSystem().initDirectory( globalGamePath.c_str() ); } } -} -// NOTE: don't this function, use VFS instead -char *ExpandReletivePath( char *p ){ - static char temp[1024]; - const char *base; - - if ( !p || !p[0] ) { - return NULL; - } - if ( p[0] == '/' || p[0] == '\\' ) { - return p; + // ~/./ + if ( userRoot ) { + StringOutputStream userBasePath( 256 ); + userBasePath << userRoot << basegame << '/'; + GlobalFileSystem().initDirectory( userBasePath.c_str() ); } - base = ValueForKey( g_qeglobals.d_project_entity, "basepath" ); - sprintf( temp, "%s/%s", base, p ); - return temp; -} - -char *copystring( char *s ){ - char *b; - b = (char*)malloc( strlen( s ) + 1 ); - strcpy( b,s ); - return b; -} - - -bool DoesFileExist( const char* pBuff, long& lSize ){ - FileStream file; - if ( file.Open( pBuff, "r" ) ) { - lSize += file.GetLength(); - file.Close(); - return true; + // / + { + StringOutputStream globalBasePath( 256 ); + globalBasePath << globalRoot << basegame << '/'; + GlobalFileSystem().initDirectory( globalBasePath.c_str() ); } - return false; } +int g_numbrushes = 0; +int g_numentities = 0; -void Map_Snapshot(){ - CString strMsg; - - // I hope the modified flag is kept correctly up to date - if ( !modified ) { - return; - } +void QE_UpdateStatusBar(){ + char buffer[128]; + sprintf( buffer, "Brushes: %d Entities: %d", g_numbrushes, g_numentities ); + g_pParentWnd->SetStatusText( g_pParentWnd->m_brushcount_status, buffer ); +} - // we need to do the following - // 1. make sure the snapshot directory exists (create it if it doesn't) - // 2. find out what the lastest save is based on number - // 3. inc that and save the map - CString strOrgPath, strOrgFile; - ExtractPath_and_Filename( currentmap, strOrgPath, strOrgFile ); - AddSlash( strOrgPath ); - strOrgPath += "snapshots"; - bool bGo = true; - struct stat Stat; - if ( stat( strOrgPath, &Stat ) == -1 ) { -#ifdef _WIN32 - bGo = ( _mkdir( strOrgPath ) != -1 ); -#endif +SimpleCounter g_brushCount; -#if defined ( __linux__ ) || defined ( __APPLE__ ) - bGo = ( mkdir( strOrgPath,0755 ) != -1 ); -#endif - } - AddSlash( strOrgPath ); - if ( bGo ) { - int nCount = 0; - long lSize = 0; - CString strNewPath; - strNewPath = strOrgPath; - strNewPath += strOrgFile; - CString strFile; - while ( bGo ) - { - char buf[PATH_MAX]; - sprintf( buf, "%s.%i", strNewPath.GetBuffer(), nCount ); - strFile = buf; - bGo = DoesFileExist( strFile, lSize ); - nCount++; - } - // strFile has the next available slot - Map_SaveFile( strFile, false ); - // it is still a modified map (we enter this only if this is a modified map) - Sys_SetTitle( currentmap ); - Sys_MarkMapModified(); - if ( lSize > 12 * 1024 * 1024 ) { // total size of saves > 4 mb - Sys_Printf( "The snapshot files in %s total more than 4 megabytes. You might consider cleaning up.", strOrgPath.GetBuffer() ); - } - } - else - { - strMsg.Format( "Snapshot save failed.. unabled to create directory\n%s", strOrgPath.GetBuffer() ); - gtk_MessageBox( g_pParentWnd->m_pWidget, strMsg ); - } - strOrgPath = ""; - strOrgFile = ""; +void QE_brushCountChanged(){ + g_numbrushes = int(g_brushCount.get() ); + QE_UpdateStatusBar(); } -/* - =============== - QE_CheckAutoSave - - If five minutes have passed since making a change - and the map hasn't been saved, save it out. - =============== - */ +SimpleCounter g_entityCount; -void QE_CheckAutoSave( void ){ - static time_t s_start; - time_t now; - time( &now ); +void QE_entityCountChanged(){ + g_numentities = int(g_entityCount.get() ); + QE_UpdateStatusBar(); +} - if ( modified != 1 || !s_start ) { - s_start = now; - return; +bool ConfirmModified( const char* title ){ + if ( !Map_Modified( g_map ) ) { + return true; } - if ( ( now - s_start ) > ( 60 * g_PrefsDlg.m_nAutoSave ) ) { - if ( g_PrefsDlg.m_bAutoSave ) { - CString strMsg; - strMsg = g_PrefsDlg.m_bSnapShots ? "Autosaving snapshot..." : "Autosaving..."; - Sys_Printf( strMsg ); - Sys_Printf( "\n" ); - Sys_Status( strMsg,0 ); - - // only snapshot if not working on a default map - if ( g_PrefsDlg.m_bSnapShots && stricmp( currentmap, "unnamed.map" ) != 0 ) { - Map_Snapshot(); - } - else - { - Map_SaveFile( ValueForKey( g_qeglobals.d_project_entity, "autosave" ), false ); - } - - Sys_Status( "Autosaving...Saved.", 0 ); - modified = 2; + EMessageBoxReturn result = gtk_MessageBox( GTK_WIDGET( MainFrame_getWindow() ), "The current map has changed since it was last saved.\nDo you want to save the current map before continuing?", title, eMB_YESNOCANCEL, eMB_ICONQUESTION ); + if ( result == eIDCANCEL ) { + return false; + } + if ( result == eIDYES ) { + if ( Map_Unnamed( g_map ) ) { + return Map_SaveAs(); } else { - Sys_Printf( "Autosave skipped...\n" ); - Sys_Status( "Autosave skipped...", 0 ); + return Map_Save(); } - s_start = now; } + return true; } +void bsp_init(){ + build_set_variable( "RadiantPath", AppPath_get() ); + build_set_variable( "ExecutableType", RADIANT_EXECUTABLE ); + build_set_variable( "EnginePath", EnginePath_get() ); + build_set_variable( "UserEnginePath", g_qeglobals.m_userEnginePath.c_str() ); + build_set_variable( "MonitorAddress", ( g_WatchBSP_Enabled ) ? "127.0.0.1:39000" : "" ); + build_set_variable( "GameName", gamename_get() ); -// NOTE TTimo we don't like that BuildShortPathName too much -// the VFS provides a vfsCleanFileName which should perform the cleanup tasks -// in the long run I'd like to completely get rid of this + const char* mapname = Map_Name( g_map ); + StringOutputStream name( 256 ); + name << StringRange( mapname, path_get_filename_base_end( mapname ) ) << ".bsp"; -// used to be disabled, but caused problems - -// can't work with long win32 names until the BSP commands are not working differently -#ifdef _WIN32 -int BuildShortPathName( const char* pPath, char* pBuffer, int nBufferLen ){ - char *pFile = NULL; - int nResult = GetFullPathName( pPath, nBufferLen, pBuffer, &pFile ); - nResult = GetShortPathName( pPath, pBuffer, nBufferLen ); - if ( nResult == 0 ) { - strcpy( pBuffer, pPath ); // Use long filename - } - return nResult; + build_set_variable( "MapFile", mapname ); + build_set_variable( "BspFile", name.c_str() ); } -#endif - -#if defined ( __linux__ ) || defined ( __APPLE__ ) -int BuildShortPathName( const char* pPath, char* pBuffer, int nBufferLen ){ - // remove /../ from directories - const char *scr = pPath; char *dst = pBuffer; - for ( int i = 0; ( i < nBufferLen ) && ( *scr != 0 ); i++ ) - { - if ( *scr == '/' && *( scr + 1 ) == '.' && *( scr + 2 ) == '.' ) { - scr += 3; - while ( dst != pBuffer && *( --dst ) != '/' ) - { - i--; - } - } - - *dst = *scr; - scr++; dst++; - } - *dst = 0; - - return strlen( pBuffer ); +void bsp_shutdown(){ + build_clear_variables(); } -#endif - -/* - const char *g_pPathFixups[]= - { - "basepath", - "autosave", - }; - - const int g_nPathFixupCount = sizeof(g_pPathFixups) / sizeof(const char*); - - void QE_CheckProjectEntity() - { - char *pFile; - char pBuff[PATH_MAX]; - char pNewPath[PATH_MAX]; - for (int i = 0; i < g_nPathFixupCount; i++) - { - char *pPath = ValueForKey (g_qeglobals.d_project_entity, g_pPathFixups[i]); - - strcpy (pNewPath, pPath); - if (pPath[0] != '\\' && pPath[0] != '/') - if (GetFullPathName(pPath, PATH_MAX, pBuff, &pFile)) - strcpy (pNewPath, pBuff); - BuildShortPathName (pNewPath, pBuff, PATH_MAX); - - // check it's not ending with a filename seperator - if (pBuff[strlen(pBuff)-1] == '/' || pBuff[strlen(pBuff)-1] == '\\') - { - Sys_FPrintf(SYS_WRN, "WARNING: \"%s\" path in the project file has an ending file seperator, fixing.\n", g_pPathFixups[i]); - pBuff[strlen(pBuff)-1]=0; - } - - SetKeyValue(g_qeglobals.d_project_entity, g_pPathFixups[i], pBuff); - } - } - */ - -void HandleXMLError( void* ctxt, const char* text, ... ){ - va_list argptr; - static char buf[32768]; - - va_start( argptr,text ); - vsprintf( buf, text, argptr ); - Sys_FPrintf( SYS_ERR, "XML %s\n", buf ); - va_end( argptr ); +class ArrayCommandListener : public CommandListener +{ +GPtrArray* m_array; +public: +ArrayCommandListener(){ + m_array = g_ptr_array_new(); } - -#define DTD_BUFFER_LENGTH 1024 -xmlDocPtr ParseXMLStream( IDataStream *stream, bool validate = false ){ - xmlDocPtr doc = NULL; - bool wellFormed = false, valid = false; - int res, size = 1024; - char chars[1024]; - xmlParserCtxtPtr ctxt; - - //if(validate) - // xmlDoValidityCheckingDefaultValue = 1; - //else - xmlDoValidityCheckingDefaultValue = 0; - xmlSetGenericErrorFunc( NULL, HandleXMLError ); - - // SPoG - // HACK: use AppPath to resolve DTD location - // do a buffer-safe string copy and concatenate - int i; - char* w; - const char* r; - char buf[DTD_BUFFER_LENGTH]; - - w = buf; - i = 0; - // copy - //assert(g_strAppPath.GetBuffer() != NULL); - for ( r = g_strAppPath.GetBuffer(); i < DTD_BUFFER_LENGTH && *r != '\0'; i++, r++ ) w[i] = *r; - // concatenate - for ( r = "dtds/"; i < DTD_BUFFER_LENGTH && *r != '\0'; i++, r++ ) w[i] = *r; - // terminate - w[i] = '\0'; - - if ( i == DTD_BUFFER_LENGTH ) { - HandleXMLError( NULL, "ERROR: buffer overflow: DTD path length too large\n" ); - return NULL; - } - - res = stream->Read( chars, 4 ); - if ( res > 0 ) { - ctxt = xmlCreatePushParserCtxt( NULL, NULL, chars, res, buf ); - - while ( ( res = stream->Read( chars, size ) ) > 0 ) - { - xmlParseChunk( ctxt, chars, res, 0 ); - } - xmlParseChunk( ctxt, chars, 0, 1 ); - doc = ctxt->myDoc; - - wellFormed = ( ctxt->wellFormed == 1 ); - valid = ( ctxt->valid == 1 ); - - xmlFreeParserCtxt( ctxt ); - } - - if ( wellFormed && ( !validate || ( validate && valid ) ) ) { - return doc; - } - - if ( doc != NULL ) { - xmlFreeDoc( doc ); - } - - return NULL; +~ArrayCommandListener(){ + g_ptr_array_free( m_array, TRUE ); } -xmlDocPtr ParseXMLFile( const char* filename, bool validate = false ){ - FileStream stream; - if ( stream.Open( filename, "r" ) ) { - return ParseXMLStream( &stream, validate ); - } - - Sys_FPrintf( SYS_ERR, "Failed to open file: %s\n",filename ); - return NULL; +void execute( const char* command ){ + g_ptr_array_add( m_array, g_strdup( command ) ); } -// copy a string r to a buffer w -// replace $string as appropriate -void ReplaceTemplates( char* w, const char* r ){ - const char *p; - const char *__ENGINEPATH = "TEMPLATEenginepath"; - const char *__USERHOMEPATH = "TEMPLATEuserhomepath"; - const char *__TOOLSPATH = "TEMPLATEtoolspath"; - const char *__BASEDIR = "TEMPLATEbasedir"; - const char *__APPPATH = "TEMPLATEapppath"; - - // iterate through string r - while ( *r != '\0' ) - { - // check for special character - if ( *r == '$' ) { - if ( strncmp( r + 1, __ENGINEPATH, strlen( __ENGINEPATH ) ) == 0 ) { - r += strlen( __ENGINEPATH ) + 1; - p = g_pGameDescription->mEnginePath.GetBuffer(); - } - else if ( strncmp( r + 1, __USERHOMEPATH, strlen( __USERHOMEPATH ) ) == 0 ) { - r += strlen( __USERHOMEPATH ) + 1; - p = g_qeglobals.m_strHomeGame.GetBuffer(); - } - else if ( strncmp( r + 1, __BASEDIR, strlen( __BASEDIR ) ) == 0 ) { - r += strlen( __BASEDIR ) + 1; - p = g_pGameDescription->mBaseGame; - } - else if ( strncmp( r + 1, __TOOLSPATH, strlen( __TOOLSPATH ) ) == 0 ) { - r += strlen( __TOOLSPATH ) + 1; - p = g_strGameToolsPath.GetBuffer(); - } - else if ( strncmp( r + 1, __APPPATH, strlen( __APPPATH ) ) == 0 ) { - r += strlen( __APPPATH ) + 1; - p = g_strAppPath.GetBuffer(); - } - else - { - r++; - p = "$"; - } - - while ( *p != '\0' ) *w++ = *p++; - } - else{ *w++ = *r++; } - } - *w = '\0'; +GPtrArray* array() const { + return m_array; } +}; -/* - =========== - QE_LoadProject - TODO TODO TODO (don't think this got fully merged in) - TTimo: added project file "version", version 2 adds '#' chars to the BSP command strings - version 3 was .. I don't remember .. version 4 adds q3map2 commands - TTimo: when QE_LoadProject is called, the prefs are updated with path to the latest project and saved on disk - =========== - */ -/*\todo decide on a sensible location/name for project files.*/ -bool QE_LoadProject( const char *projectfile ){ - char buf[1024]; - xmlDocPtr doc; - xmlNodePtr node, project; - - Sys_Printf( "Loading project file: \"%s\"\n", projectfile ); - doc = ParseXMLFile( projectfile, true ); - - if ( doc == NULL ) { - return false; - } - - node = doc->children; - while ( node != NULL && node->type != XML_DTD_NODE ) node = node->next; - if ( node == NULL || strcmp( (char*)node->name, "project" ) != 0 ) { - Sys_FPrintf( SYS_ERR, "ERROR: invalid file type\n" ); - return false; - } - - while ( node->type != XML_ELEMENT_NODE ) node = node->next; - // - project = node; - - if ( g_qeglobals.d_project_entity != NULL ) { - Entity_Free( g_qeglobals.d_project_entity ); - } - g_qeglobals.d_project_entity = Entity_Alloc(); - - for ( node = project->children; node != NULL; node = node->next ) - { - if ( node->type != XML_ELEMENT_NODE ) { - continue; - } - - // - ReplaceTemplates( buf, (char*)node->properties->next->children->content ); - - SetKeyValue( g_qeglobals.d_project_entity, (char*)node->properties->children->content, buf ); - } - - xmlFreeDoc( doc ); - - // project file version checking - // add a version checking to avoid people loading later versions of the project file and bitching - int ver = IntForKey( g_qeglobals.d_project_entity, "version" ); - if ( ver > PROJECT_VERSION ) { - char strMsg[1024]; - sprintf( strMsg, "This is a version %d project file. This build only supports <=%d project files.\n" - "Please choose another project file or upgrade your version of Radiant.", ver, PROJECT_VERSION ); - gtk_MessageBox( g_pParentWnd->m_pWidget, strMsg, "Can't load project file", MB_ICONERROR | MB_OK ); - // set the project file to nothing so we are sure we'll ask next time? - g_PrefsDlg.m_strLastProject = ""; - g_PrefsDlg.SavePrefs(); - return false; - } - - // set here some default project settings you need - if ( strlen( ValueForKey( g_qeglobals.d_project_entity, "brush_primit" ) ) == 0 ) { - SetKeyValue( g_qeglobals.d_project_entity, "brush_primit", "0" ); - } - - g_qeglobals.m_bBrushPrimitMode = IntForKey( g_qeglobals.d_project_entity, "brush_primit" ); - - g_qeglobals.m_strHomeMaps = g_qeglobals.m_strHomeGame; - const char* str = ValueForKey( g_qeglobals.d_project_entity, "gamename" ); - if ( str[0] == '\0' ) { - str = g_pGameDescription->mBaseGame.GetBuffer(); - } - g_qeglobals.m_strHomeMaps += str; - g_qeglobals.m_strHomeMaps += '/'; - - // don't forget to create the dirs - Q_mkdir( g_qeglobals.m_strHomeGame.GetBuffer(), 0775 ); - Q_mkdir( g_qeglobals.m_strHomeMaps.GetBuffer(), 0775 ); - - // usefull for the log file and debuggin fucked up configurations from users: - // output the basic information of the .qe4 project file - // SPoG - // all these paths should be unix format, with a trailing slash at the end - // if not.. to debug, check that the project file paths are set up correctly - Sys_Printf( "basepath : %s\n", ValueForKey( g_qeglobals.d_project_entity, "basepath" ) ); - Sys_Printf( "entitypath : %s\n", ValueForKey( g_qeglobals.d_project_entity, "entitypath" ) ); - - - // check whether user_project key exists.. - // if not, save the current project under a new name - if ( ValueForKey( g_qeglobals.d_project_entity, "user_project" )[0] == '\0' ) { - Sys_Printf( "Loaded a template project file\n" ); - - // create the user_project key - SetKeyValue( g_qeglobals.d_project_entity, "user_project", "1" ); - - if ( IntForKey( g_qeglobals.d_project_entity, "version" ) != PROJECT_VERSION ) { - char strMsg[2048]; - sprintf( strMsg, - "The template project '%s' has version %d. The editor binary is configured for version %d.\n" - "This indicates a problem in your setup.\n" - "I will keep going with this project till you fix this", - projectfile, IntForKey( g_qeglobals.d_project_entity, "version" ), PROJECT_VERSION ); - gtk_MessageBox( g_pParentWnd->m_pWidget, strMsg, "Can't load project file", MB_ICONERROR | MB_OK ); - } +class BatchCommandListener : public CommandListener +{ +TextOutputStream& m_file; +std::size_t m_commandCount; +const char* m_outputRedirect; +public: +BatchCommandListener( TextOutputStream& file, const char* outputRedirect ) : m_file( file ), m_commandCount( 0 ), m_outputRedirect( outputRedirect ){ +} - // create the writable project file path - strcpy( buf, g_qeglobals.m_strHomeGame.GetBuffer() ); - strcat( buf, g_pGameDescription->mBaseGame.GetBuffer() ); - strcat( buf, "/scripts/" ); - // while the filename is already in use, increment the number we add to the end - int counter = 0; - char pUser[PATH_MAX]; - while ( 1 ) - { - sprintf( pUser, "%suser%d." PROJECT_FILETYPE, buf, counter ); - counter++; - if ( access( pUser, R_OK ) != 0 ) { - // this is the one - strcpy( buf, pUser ); - break; - } - } - // saving project will cause a save prefs - g_PrefsDlg.m_strLastProject = buf; - g_PrefsDlg.m_nLastProjectVer = IntForKey( g_qeglobals.d_project_entity, "version" ); - QE_SaveProject( buf ); +void execute( const char* command ){ + m_file << command; + if ( m_commandCount == 0 ) { + m_file << " > "; } else { - // update preferences::LastProject with path of this successfully-loaded project - // save preferences - Sys_Printf( "Setting current project in prefs to \"%s\"\n", g_PrefsDlg.m_strLastProject.GetBuffer() ); - g_PrefsDlg.m_strLastProject = projectfile; - g_PrefsDlg.SavePrefs(); + m_file << " >> "; } - - return true; + m_file << "\"" << m_outputRedirect << "\""; + m_file << "\n"; + ++m_commandCount; } +}; -/* - =========== - QE_SaveProject - TTimo: whenever QE_SaveProject is called, prefs are updated and saved with the path to the project - =========== - */ -qboolean QE_SaveProject( const char* filename ){ - Sys_Printf( "Save project file '%s'\n", filename ); - - xmlNodePtr node; - xmlDocPtr doc = xmlNewDoc( (xmlChar *)"1.0" ); - // create DTD node - xmlCreateIntSubset( doc, (xmlChar *)"project", NULL, (xmlChar *)"project.dtd" ); - // create project node - doc->children->next = xmlNewDocNode( doc, NULL, (xmlChar *)"project", NULL ); - - for ( epair_t* epair = g_qeglobals.d_project_entity->epairs; epair != NULL; epair = epair->next ) - { - node = xmlNewChild( doc->children->next, NULL, (xmlChar *)"key", NULL ); - xmlSetProp( node, (xmlChar*)"name", (xmlChar*)epair->key ); - xmlSetProp( node, (xmlChar*)"value", (xmlChar*)epair->value ); - } +bool Region_cameraValid(){ + Vector3 vOrig( vector3_snapped( Camera_getOrigin( *g_pParentWnd->GetCamWnd() ) ) ); - CreateDirectoryPath( filename ); - if ( xmlSaveFormatFile( filename, doc, 1 ) != -1 ) { - xmlFreeDoc( doc ); - Sys_Printf( "Setting current project in prefs to \"%s\"\n", filename ); - g_PrefsDlg.m_strLastProject = filename; - g_PrefsDlg.SavePrefs(); - return TRUE; - } - else + for ( int i = 0 ; i < 3 ; i++ ) { - xmlFreeDoc( doc ); - Sys_FPrintf( SYS_ERR, "failed to save project file: \"%s\"\n", filename ); - return FALSE; + if ( vOrig[i] > region_maxs[i] || vOrig[i] < region_mins[i] ) { + return false; + } } + return true; } - -/* - =========== - QE_KeyDown - =========== - */ -#define SPEED_MOVE 32 -#define SPEED_TURN 22.5 - - -/* - =============== - ConnectEntities - - Sets target / targetname on the two entities selected - from the first selected to the secon - =============== - */ -void ConnectEntities( void ){ - entity_t *e1, *e2; - const char *target; - char *newtarg = NULL; - - if ( g_qeglobals.d_select_count != 2 ) { - Sys_Status( "Must have two brushes selected", 0 ); - Sys_Beep(); +void RunBSP( const char* name ){ + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=503 + // make sure we don't attempt to region compile a map with the camera outside the region + if ( region_active && !Region_cameraValid() ) { + globalErrorStream() << "The camera must be in the region to start a region compile.\n"; return; } - e1 = g_qeglobals.d_select_order[0]->owner; - e2 = g_qeglobals.d_select_order[1]->owner; - - if ( e1 == world_entity || e2 == world_entity ) { - Sys_Status( "Can't connect to the world", 0 ); - Sys_Beep(); - return; - } + SaveMap(); - if ( e1 == e2 ) { - Sys_Status( "Brushes are from same entity", 0 ); - Sys_Beep(); + if ( Map_Unnamed( g_map ) ) { + globalOutputStream() << "build cancelled\n"; return; } - target = ValueForKey( e1, "target" ); - if ( target && target[0] ) { - newtarg = g_strdup( target ); - } - else - { - target = ValueForKey( e2, "targetname" ); - if ( target && target[0] ) { - newtarg = g_strdup( target ); - } - else{ - Entity_Connect( e1, e2 ); - } - } - - if ( newtarg != NULL ) { - SetKeyValue( e1, "target", newtarg ); - SetKeyValue( e2, "targetname", newtarg ); - g_free( newtarg ); + if ( g_SnapShots_Enabled && !Map_Unnamed( g_map ) && Map_Modified( g_map ) ) { + Map_Snapshot(); } - Sys_UpdateWindows( W_XY | W_CAMERA ); - - Select_Deselect(); - Select_Brush( g_qeglobals.d_select_order[1] ); -} - -qboolean QE_SingleBrush( bool bQuiet ){ - if ( ( selected_brushes.next == &selected_brushes ) - || ( selected_brushes.next->next != &selected_brushes ) ) { - if ( !bQuiet ) { - Sys_Printf( "Error: you must have a single brush selected\n" ); - } - return false; - } - if ( selected_brushes.next->owner->eclass->fixedsize ) { - if ( !bQuiet ) { - Sys_Printf( "Error: you cannot manipulate fixed size entities\n" ); - } - return false; + if ( region_active ) { + const char* mapname = Map_Name( g_map ); + StringOutputStream name( 256 ); + name << StringRange( mapname, path_get_filename_base_end( mapname ) ) << ".reg"; + Map_SaveRegion( name.c_str() ); } - return true; -} - -void QE_InitVFS( void ){ - // VFS initialization ----------------------- - // we will call vfsInitDirectory, giving the directories to look in (for files in pk3's and for standalone files) - // we need to call in order, the mod ones first, then the base ones .. they will be searched in this order - // *nix systems have a dual filesystem in ~/.q3a, which is searched first .. so we need to add that too - Str directory,prefabs; + Pointfile_Delete(); - // TTimo: let's leave this to HL mode for now - if ( g_pGameDescription->mGameFile == "hl.game" ) { - // Hydra: we search the "gametools" path first so that we can provide editor - // specific pk3's wads and misc files for use by the editor. - // the relevant map compiler tools will NOT use this directory, so this helps - // to ensure that editor files are not used/required in release versions of maps - // it also helps keep your editor files all in once place, with the editor modules, - // plugins, scripts and config files. - // it also helps when testing maps, as you'll know your files won't/can't be used - // by the game engine itself. + bsp_init(); - // - directory = g_pGameDescription->mGameToolsPath; - vfsInitDirectory( directory.GetBuffer() ); + if ( g_WatchBSP_Enabled ) { + ArrayCommandListener listener; + build_run( name, listener ); + // grab the file name for engine running + const char* fullname = Map_Name( g_map ); + StringOutputStream bspname( 64 ); + bspname << StringRange( path_get_filename_start( fullname ), path_get_filename_base_end( fullname ) ); + BuildMonitor_Run( listener.array(), bspname.c_str() ); } - - // NOTE TTimo about the mymkdir calls .. this is a bit dirty, but a safe thing on *nix - - // if we have a mod dir - if ( *ValueForKey( g_qeglobals.d_project_entity, "gamename" ) != '\0' ) { - -#if defined ( __linux__ ) || defined ( __APPLE__ ) - // ~/./ - directory = g_qeglobals.m_strHomeGame.GetBuffer(); - Q_mkdir( directory.GetBuffer(), 0775 ); - directory += ValueForKey( g_qeglobals.d_project_entity, "gamename" ); - Q_mkdir( directory.GetBuffer(), 0775 ); - vfsInitDirectory( directory.GetBuffer() ); - AddSlash( directory ); - prefabs = directory; - // also create the maps dir, it will be used as prompt for load/save - directory += "/maps"; - Q_mkdir( directory, 0775 ); - // and the prefabs dir - prefabs += "/prefabs"; - Q_mkdir( prefabs, 0775 ); - + else + { + char junkpath[PATH_MAX]; + strcpy( junkpath, SettingsPath_get() ); + strcat( junkpath, "junk.txt" ); + + char batpath[PATH_MAX]; +#if defined( POSIX ) + strcpy( batpath, SettingsPath_get() ); + strcat( batpath, "qe3bsp.sh" ); +#elif defined( WIN32 ) + strcpy( batpath, SettingsPath_get() ); + strcat( batpath, "qe3bsp.bat" ); +#else +#error "unsupported platform" #endif - - // / - directory = g_pGameDescription->mEnginePath; - directory += ValueForKey( g_qeglobals.d_project_entity, "gamename" ); - Q_mkdir( directory.GetBuffer(), 0775 ); - vfsInitDirectory( directory.GetBuffer() ); - AddSlash( directory ); - prefabs = directory; - // also create the maps dir, it will be used as prompt for load/save - directory += "/maps"; - Q_mkdir( directory.GetBuffer(), 0775 ); - // and the prefabs dir - prefabs += "/prefabs"; - Q_mkdir( prefabs, 0775 ); - } - -#if defined ( __linux__ ) || defined ( __APPLE__ ) - // ~/./ - directory = g_qeglobals.m_strHomeGame.GetBuffer(); - directory += g_pGameDescription->mBaseGame; - vfsInitDirectory( directory.GetBuffer() ); + bool written = false; + { + TextFileOutputStream batchFile( batpath ); + if ( !batchFile.failed() ) { +#if defined ( POSIX ) + batchFile << "#!/bin/sh \n\n"; #endif - - // / - directory = g_pGameDescription->mEnginePath; - directory += g_pGameDescription->mBaseGame; - vfsInitDirectory( directory.GetBuffer() ); -} - -void QE_Init( void ){ - /* - ** initialize variables - */ - g_qeglobals.d_gridsize = 8; - g_qeglobals.d_showgrid = true; - - QE_InitVFS(); - - Eclass_Init(); - FillClassList(); // list in entity window - Map_Init(); - - FillTextureMenu(); - FillBSPMenu(); - - /* - ** other stuff - */ - Z_Init(); -} - -void WINAPI QE_ConvertDOSToUnixName( char *dst, const char *src ){ - while ( *src ) - { - if ( *src == '\\' ) { - *dst = '/'; + BatchCommandListener listener( batchFile, junkpath ); + build_run( name, listener ); + written = true; + } } - else{ - *dst = *src; + if ( written ) { +#if defined ( POSIX ) + chmod( batpath, 0744 ); +#endif + globalOutputStream() << "Writing the compile script to '" << batpath << "'\n"; + globalOutputStream() << "The build output will be saved in '" << junkpath << "'\n"; + Q_Exec( batpath, NULL, NULL, true, false ); } - dst++; src++; } - *dst = 0; -} -int g_numbrushes, g_numentities; - -void QE_CountBrushesAndUpdateStatusBar( void ){ - static int s_lastbrushcount, s_lastentitycount; - static qboolean s_didonce; + bsp_shutdown(); +} - //entity_t *e; - brush_t *b, *next; +// ============================================================================= +// Sys_ functions - g_numbrushes = 0; - g_numentities = 0; +void Sys_SetTitle( const char *text, bool modified ){ + StringOutputStream title; + title << text; - if ( active_brushes.next != NULL ) { - for ( b = active_brushes.next ; b != NULL && b != &active_brushes ; b = next ) - { - next = b->next; - if ( b->brush_faces ) { - if ( !b->owner->eclass->fixedsize ) { - g_numbrushes++; - } - else{ - g_numentities++; - } - } - } + if ( modified ) { + title << " *"; } -/* - if ( entities.next != NULL ) - { - for ( e = entities.next ; e != &entities && g_numentities != MAX_MAP_ENTITIES ; e = e->next) - { - g_numentities++; - } - } - */ - if ( ( ( g_numbrushes != s_lastbrushcount ) || ( g_numentities != s_lastentitycount ) ) || ( !s_didonce ) ) { - Sys_UpdateStatusBar(); - s_lastbrushcount = g_numbrushes; - s_lastentitycount = g_numentities; - s_didonce = true; - } + gtk_window_set_title( MainFrame_getWindow(), title.c_str() ); } -char com_token[1024]; -qboolean com_eof; - -/* - ================ - I_FloatTime - ================ - */ -double I_FloatTime( void ){ - time_t t; - - time( &t ); - - return t; -#if 0 -// more precise, less portable - struct timeval tp; - struct timezone tzp; - static int secbase; - - gettimeofday( &tp, &tzp ); - - if ( !secbase ) { - secbase = tp.tv_sec; - return tp.tv_usec / 1000000.0; - } +bool g_bWaitCursor = false; - return ( tp.tv_sec - secbase ) + tp.tv_usec / 1000000.0; -#endif +void Sys_BeginWait( void ){ + ScreenUpdates_Disable( "Processing...", "Please Wait" ); + GdkCursor *cursor = gdk_cursor_new( GDK_WATCH ); + gdk_window_set_cursor( GTK_WIDGET( MainFrame_getWindow() )->window, cursor ); + gdk_cursor_unref( cursor ); + g_bWaitCursor = true; } - -/* - ============== - COM_Parse - - Parse a token out of a string - ============== - */ -char *COM_Parse( char *data ){ - int c; - int len; - - len = 0; - com_token[0] = 0; - - if ( !data ) { - return NULL; - } - -// skip whitespace -skipwhite: - while ( ( c = *data ) <= ' ' ) - { - if ( c == 0 ) { - com_eof = true; - return NULL; // end of file; - } - data++; - } - -// skip // comments - if ( c == '/' && data[1] == '/' ) { - while ( *data && *data != '\n' ) - data++; - goto skipwhite; - } - - -// handle quoted strings specially - if ( c == '\"' ) { - data++; - do - { - c = *data++; - if ( c == '\"' ) { - com_token[len] = 0; - return data; - } - com_token[len] = c; - len++; - } while ( 1 ); - } - -// parse single characters - if ( c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ':' ) { - com_token[len] = c; - len++; - com_token[len] = 0; - return data + 1; - } - -// parse a regular word - do - { - com_token[len] = c; - data++; - len++; - c = *data; - if ( c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ':' ) { - break; - } - } while ( c > 32 ); - - com_token[len] = 0; - return data; -} - -char* Get_COM_Token(){ - return com_token; -} - -/* - ============================================================================= - - MISC FUNCTIONS - - ============================================================================= - */ - - -int argc; -char *argv[MAX_NUM_ARGVS]; - -/* - ============ - ParseCommandLine - ============ - */ -void ParseCommandLine( char *lpCmdLine ){ - argc = 1; - argv[0] = "programname"; - - while ( *lpCmdLine && ( argc < MAX_NUM_ARGVS ) ) - { - while ( *lpCmdLine && ( ( *lpCmdLine <= 32 ) || ( *lpCmdLine > 126 ) ) ) - lpCmdLine++; - - if ( *lpCmdLine ) { - argv[argc] = lpCmdLine; - argc++; - - while ( *lpCmdLine && ( ( *lpCmdLine > 32 ) && ( *lpCmdLine <= 126 ) ) ) - lpCmdLine++; - - if ( *lpCmdLine ) { - *lpCmdLine = 0; - lpCmdLine++; - } - - } - } -} - - - -/* - ================= - CheckParm - - Checks for the given parameter in the program's command line arguments - Returns the argument number (1 to argc-1) or 0 if not present - ================= - */ -int CheckParm( const char *check ){ - int i; - - for ( i = 1; i < argc; i++ ) - { - if ( stricmp( check, argv[i] ) ) { - return i; - } - } - - return 0; -} - - - - -/* - ============== - ParseNum / ParseHex - ============== - */ -int ParseHex( const char *hex ){ - const char *str; - int num; - - num = 0; - str = hex; - - while ( *str ) - { - num <<= 4; - if ( *str >= '0' && *str <= '9' ) { - num += *str - '0'; - } - else if ( *str >= 'a' && *str <= 'f' ) { - num += 10 + *str - 'a'; - } - else if ( *str >= 'A' && *str <= 'F' ) { - num += 10 + *str - 'A'; - } - else{ - Error( "Bad hex number: %s",hex ); - } - str++; - } - - return num; -} - - -int ParseNum( const char *str ){ - if ( str[0] == '$' ) { - return ParseHex( str + 1 ); - } - if ( str[0] == '0' && str[1] == 'x' ) { - return ParseHex( str + 2 ); - } - return atol( str ); -} - -// BSP frontend plugin -// global flag for BSP frontend plugin is g_qeglobals.bBSPFrontendPlugin -_QERPlugBSPFrontendTable g_BSPFrontendTable; - -// ============================================================================= -// Sys_ functions - -bool Sys_AltDown(){ -#ifdef _WIN32 - return ( GetKeyState( VK_MENU ) & 0x8000 ) != 0; -#endif - -#if defined ( __linux__ ) || defined ( __APPLE__ ) - char keys[32]; - int x; - - XQueryKeymap( GDK_DISPLAY(), keys ); - - x = XKeysymToKeycode( GDK_DISPLAY(), XK_Alt_L ); - if ( keys[x / 8] & ( 1 << ( x % 8 ) ) ) { - return true; - } - - x = XKeysymToKeycode( GDK_DISPLAY(), XK_Alt_R ); - if ( keys[x / 8] & ( 1 << ( x % 8 ) ) ) { - return true; - } - - return false; -#endif -} - -bool Sys_ShiftDown(){ -#ifdef _WIN32 - return ( GetKeyState( VK_SHIFT ) & 0x8000 ) != 0; -#endif - -#if defined ( __linux__ ) || defined ( __APPLE__ ) - char keys[32]; - int x; - - XQueryKeymap( GDK_DISPLAY(), keys ); - - x = XKeysymToKeycode( GDK_DISPLAY(), XK_Shift_L ); - if ( keys[x / 8] & ( 1 << ( x % 8 ) ) ) { - return true; - } - - x = XKeysymToKeycode( GDK_DISPLAY(), XK_Shift_R ); - if ( keys[x / 8] & ( 1 << ( x % 8 ) ) ) { - return true; - } - - return false; -#endif -} - -void Sys_MarkMapModified( void ){ - char title[PATH_MAX]; - - if ( modified != 1 ) { - modified = true; // mark the map as changed - sprintf( title, "%s *", currentmap ); - - QE_ConvertDOSToUnixName( title, title ); - Sys_SetTitle( title ); - } -} - -void Sys_SetTitle( const char *text ){ - gtk_window_set_title( GTK_WINDOW( g_qeglobals_gui.d_main_window ), text ); -} - -bool g_bWaitCursor = false; - -void WINAPI Sys_BeginWait( void ){ - GdkCursor *cursor = gdk_cursor_new( GDK_WATCH ); - gdk_window_set_cursor( g_pParentWnd->m_pWidget->window, cursor ); - gdk_cursor_unref( cursor ); - g_bWaitCursor = true; -} - -void WINAPI Sys_EndWait( void ){ - GdkCursor *cursor = gdk_cursor_new( GDK_LEFT_PTR ); - gdk_window_set_cursor( g_pParentWnd->m_pWidget->window, cursor ); - gdk_cursor_unref( cursor ); - g_bWaitCursor = false; -} - -void Sys_GetCursorPos( int *x, int *y ){ - // FIXME: not multihead safe - gdk_window_get_pointer( NULL, x, y, NULL ); -} - -void Sys_SetCursorPos( int x, int y ){ - // NOTE: coordinates are in GDK space, not OS space -#ifdef _WIN32 - int sys_x = x - g_pParentWnd->GetGDKOffsetX(); - int sys_y = y - g_pParentWnd->GetGDKOffsetY(); - - SetCursorPos( sys_x, sys_y ); -#endif - -#if defined ( __linux__ ) || defined ( __APPLE__ ) - XWarpPointer( GDK_DISPLAY(), None, GDK_ROOT_WINDOW(), 0, 0, 0, 0, x, y ); -#endif -} +void Sys_EndWait( void ){ + ScreenUpdates_Enable(); + gdk_window_set_cursor( GTK_WIDGET( MainFrame_getWindow() )->window, 0 ); + g_bWaitCursor = false; +} void Sys_Beep( void ){ -#if defined ( __linux__ ) || defined ( __APPLE__ ) gdk_beep(); -#else - MessageBeep( MB_ICONASTERISK ); -#endif -} - -double Sys_DoubleTime( void ){ - return clock() / 1000.0; -} - -/* - =============================================================== - - STATUS WINDOW - - =============================================================== - */ - -void Sys_UpdateStatusBar( void ){ - extern int g_numbrushes, g_numentities; - - char numbrushbuffer[100] = ""; - - sprintf( numbrushbuffer, "Brushes: %d Entities: %d", g_numbrushes, g_numentities ); - g_pParentWnd->SetStatusText( 2, numbrushbuffer ); - //Sys_Status( numbrushbuffer, 2 ); -} - -void Sys_Status( const char *psz, int part ){ - g_pParentWnd->SetStatusText( part, psz ); -} - -// ============================================================================= -// MRU - -#define MRU_MAX 4 -static GtkWidget *MRU_items[MRU_MAX]; -static int MRU_used; -typedef char MRU_filename_t[PATH_MAX]; -MRU_filename_t MRU_filenames[MRU_MAX]; - -static char* MRU_GetText( int index ){ - return MRU_filenames[index]; -} - -void buffer_write_escaped_mnemonic( char* buffer, const char* string ){ - while ( *string != '\0' ) - { - if ( *string == '_' ) { - *buffer++ = '_'; - } - - *buffer++ = *string++; - } - *buffer = '\0'; -} - -static void MRU_SetText( int index, const char *filename ){ - strcpy( MRU_filenames[index], filename ); - - char mnemonic[PATH_MAX * 2 + 4]; - mnemonic[0] = '_'; - sprintf( mnemonic + 1, "%d", index + 1 ); - mnemonic[2] = '-'; - mnemonic[3] = ' '; - buffer_write_escaped_mnemonic( mnemonic + 4, filename ); - gtk_label_set_text_with_mnemonic( GTK_LABEL( GTK_BIN( MRU_items[index] )->child ), mnemonic ); -} - -void MRU_Load(){ - int i = g_PrefsDlg.m_nMRUCount; - - if ( i > 4 ) { - i = 4; //FIXME: make this a define - - } - for (; i > 0; i-- ) - MRU_AddFile( g_PrefsDlg.m_strMRUFiles[i - 1].GetBuffer() ); -} - -void MRU_Save(){ - g_PrefsDlg.m_nMRUCount = MRU_used; - - for ( int i = 0; i < MRU_used; i++ ) - g_PrefsDlg.m_strMRUFiles[i] = MRU_GetText( i ); -} - -void MRU_AddWidget( GtkWidget *widget, int pos ){ - if ( pos < MRU_MAX ) { - MRU_items[pos] = widget; - } -} - -void MRU_AddFile( const char *str ){ - int i; - char* text; - - // check if file is already in our list - for ( i = 0; i < MRU_used; i++ ) - { - text = MRU_GetText( i ); - - if ( strcmp( text, str ) == 0 ) { - // reorder menu - for (; i > 0; i-- ) - MRU_SetText( i, MRU_GetText( i - 1 ) ); - - MRU_SetText( 0, str ); - - return; - } - } - - if ( MRU_used < MRU_MAX ) { - MRU_used++; - } - - // move items down - for ( i = MRU_used - 1; i > 0; i-- ) - MRU_SetText( i, MRU_GetText( i - 1 ) ); - - MRU_SetText( 0, str ); - gtk_widget_set_sensitive( MRU_items[0], TRUE ); - gtk_widget_show( MRU_items[MRU_used - 1] ); -} - -void MRU_Activate( int index ){ - char *text = MRU_GetText( index ); - - if ( access( text, R_OK ) == 0 ) { - text = strdup( text ); - MRU_AddFile( text ); - Map_LoadFile( text ); - free( text ); - } - else - { - MRU_used--; - - for ( int i = index; i < MRU_used; i++ ) - MRU_SetText( i, MRU_GetText( i + 1 ) ); - - if ( MRU_used == 0 ) { - gtk_label_set_text( GTK_LABEL( GTK_BIN( MRU_items[0] )->child ), "Recent Files" ); - gtk_widget_set_sensitive( MRU_items[0], FALSE ); - } - else - { - gtk_widget_hide( MRU_items[MRU_used] ); - } - } -} - -/* - ====================================================================== - - FILE DIALOGS - - ====================================================================== - */ - -qboolean ConfirmModified(){ - if ( !modified ) { - return true; - } - - if ( gtk_MessageBox( g_pParentWnd->m_pWidget, "This will lose changes to the map", "warning", MB_OKCANCEL ) == IDCANCEL ) { - return false; - } - return true; -} - -void ProjectDialog(){ - const char *filename; - char buffer[NAME_MAX]; - - /* - * Obtain the system directory name and - * store it in buffer. - */ - - strcpy( buffer, g_qeglobals.m_strHomeGame.GetBuffer() ); - strcat( buffer, g_pGameDescription->mBaseGame.GetBuffer() ); - strcat( buffer, "/scripts/" ); - - // Display the Open dialog box - filename = file_dialog( NULL, TRUE, _( "Open File" ), buffer, "project" ); - - if ( filename == NULL ) { - return; // canceled - - } - // Open the file. - // NOTE: QE_LoadProject takes care of saving prefs with new path to the project file - if ( !QE_LoadProject( filename ) ) { - Sys_Printf( "Failed to load project from file: %s\n", filename ); - } - else{ - // FIXME TTimo QE_Init is probably broken if you don't call it during startup right now .. - QE_Init(); - } -} - -/* - ======================================================= - - Menu modifications - - ======================================================= - */ - -/* - ================== - FillBSPMenu - - ================== - */ -char *bsp_commands[256]; - -void FillBSPMenu(){ - GtkWidget *item, *menu; // menu points to a GtkMenu (not an item) - epair_t *ep; - GList *lst; - int i; - - menu = GTK_WIDGET( g_object_get_data( G_OBJECT( g_qeglobals_gui.d_main_window ), "menu_bsp" ) ); - - while ( ( lst = gtk_container_children( GTK_CONTAINER( menu ) ) ) != NULL ) - gtk_container_remove( GTK_CONTAINER( menu ), GTK_WIDGET( lst->data ) ); - - if ( g_PrefsDlg.m_bDetachableMenus ) { - item = gtk_tearoff_menu_item_new(); - gtk_menu_append( GTK_MENU( menu ), item ); - gtk_widget_set_sensitive( item, TRUE ); - gtk_widget_show( item ); - } - - if ( g_qeglobals.bBSPFrontendPlugin ) { - CString str = g_BSPFrontendTable.m_pfnGetBSPMenu(); - char cTemp[1024]; - strcpy( cTemp, str ); - char* token = strtok( cTemp, ",;" ); - if ( token && *token == ' ' ) { - while ( *token == ' ' ) - token++; - } - i = 0; - - // first token is menu name - item = gtk_menu_get_attach_widget( GTK_MENU( menu ) ); - gtk_label_set_text( GTK_LABEL( GTK_BIN( item )->child ), token ); - - token = strtok( NULL, ",;" ); - while ( token != NULL ) - { - g_BSPFrontendCommands = g_slist_append( g_BSPFrontendCommands, g_strdup( token ) ); - item = gtk_menu_item_new_with_label( token ); - gtk_widget_show( item ); - gtk_container_add( GTK_CONTAINER( menu ), item ); - gtk_signal_connect( GTK_OBJECT( item ), "activate", - GTK_SIGNAL_FUNC( HandleCommand ), GINT_TO_POINTER( CMD_BSPCOMMAND + i ) ); - token = strtok( NULL, ",;" ); - i++; - } - } - else - { - i = 0; - for ( ep = g_qeglobals.d_project_entity->epairs; ep; ep = ep->next ) - { - if ( strncmp( ep->key, "bsp_", 4 ) == 0 ) { - bsp_commands[i] = ep->key; - item = gtk_menu_item_new_with_label( ep->key + 4 ); - gtk_widget_show( item ); - gtk_container_add( GTK_CONTAINER( menu ), item ); - gtk_signal_connect( GTK_OBJECT( item ), "activate", - GTK_SIGNAL_FUNC( HandleCommand ), GINT_TO_POINTER( CMD_BSPCOMMAND + i ) ); - i++; - } - } - } -} - -//============================================== - -void AddSlash( CString& strPath ){ - if ( strPath.GetLength() > 0 ) { - if ( ( strPath.GetAt( strPath.GetLength() - 1 ) != '/' ) && - ( strPath.GetAt( strPath.GetLength() - 1 ) != '\\' ) ) { - strPath += '/'; - } - } -} - -bool ExtractPath_and_Filename( const char* pPath, CString& strPath, CString& strFilename ){ - CString strPathName; - strPathName = pPath; - int nSlash = strPathName.ReverseFind( '\\' ); - if ( nSlash == -1 ) { - // TTimo: try forward slash, some are using forward - nSlash = strPathName.ReverseFind( '/' ); - } - if ( nSlash >= 0 ) { - strPath = strPathName.Left( nSlash + 1 ); - strFilename = strPathName.Right( strPathName.GetLength() - nSlash - 1 ); - } - // TTimo: try forward slash, some are using forward - else{ - strFilename = pPath; - } - return true; -} - -//=========================================== - -//++timo FIXME: no longer used .. remove! -char *TranslateString( char *buf ){ - static char buf2[32768]; - int i, l; - char *out; - - l = strlen( buf ); - out = buf2; - for ( i = 0 ; i < l ; i++ ) - { - if ( buf[i] == '\n' ) { - *out++ = '\r'; - *out++ = '\n'; - } - else{ - *out++ = buf[i]; - } - } - *out++ = 0; - - return buf2; -} - -// called whenever we need to open/close/check the console log file -void Sys_LogFile( void ){ - if ( g_PrefsDlg.mGamesDialog.m_bLogConsole && !g_qeglobals.hLogFile ) { - // settings say we should be logging and we don't have a log file .. so create it - // open a file to log the console (if user prefs say so) - // the file handle is g_qeglobals.hLogFile - // the log file is erased - Str name; - name = g_strTempPath; - name += "radiant.log"; -#if defined ( __linux__ ) || defined ( __APPLE__ ) - g_qeglobals.hLogFile = open( name.GetBuffer(), O_TRUNC | O_CREAT | O_WRONLY, S_IREAD | S_IWRITE ); -#endif -#ifdef _WIN32 - g_qeglobals.hLogFile = _open( name.GetBuffer(), _O_TRUNC | _O_CREAT | _O_WRONLY, _S_IREAD | _S_IWRITE ); -#endif - if ( g_qeglobals.hLogFile ) { - Sys_Printf( "Started logging to %s\n", name.GetBuffer() ); - time_t localtime; - time( &localtime ); - Sys_Printf( "Today is: %s", ctime( &localtime ) ); - Sys_Printf( "This is radiant '" RADIANT_VERSION "' compiled " __DATE__ "\n" ); - Sys_Printf( RADIANT_ABOUTMSG "\n" ); - } - else{ - gtk_MessageBox( NULL, "Failed to create log file, check write permissions in Radiant directory.\n", - "Console logging", MB_OK ); - } - } - else if ( !g_PrefsDlg.mGamesDialog.m_bLogConsole && g_qeglobals.hLogFile ) { - // settings say we should not be logging but still we have an active logfile .. close it - time_t localtime; - time( &localtime ); - Sys_Printf( "Closing log file at %s\n", ctime( &localtime ) ); - #ifdef _WIN32 - _close( g_qeglobals.hLogFile ); - #endif - #if defined ( __linux__ ) || defined ( __APPLE__ ) - close( g_qeglobals.hLogFile ); - #endif - g_qeglobals.hLogFile = 0; - } -} - -void Sys_ClearPrintf( void ){ - GtkTextBuffer* buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW( g_qeglobals_gui.d_edit ) ); - gtk_text_buffer_set_text( buffer, "", -1 ); -} - -// used to be around 32000, that should be way enough already -#define BUFFER_SIZE 4096 - -extern "C" void Sys_FPrintf_VA( int level, const char *text, va_list args ) { - char buf[BUFFER_SIZE]; - - buf[0] = 0; - vsnprintf( buf, BUFFER_SIZE, text, args ); - buf[BUFFER_SIZE - 1] = 0; - const unsigned int length = strlen( buf ); - - if ( g_qeglobals.hLogFile ) { -#ifdef _WIN32 - _write( g_qeglobals.hLogFile, buf, length ); - _commit( g_qeglobals.hLogFile ); -#endif -#if defined ( __linux__ ) || defined ( __APPLE__ ) - write( g_qeglobals.hLogFile, buf, length ); -#endif - } - - if ( level != SYS_NOCON ) { - // TTimo: FIXME: killed the console to avoid GDI leak fuckup - if ( g_qeglobals_gui.d_edit != NULL ) { - GtkTextBuffer* buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW( g_qeglobals_gui.d_edit ) ); - - GtkTextIter iter; - gtk_text_buffer_get_end_iter( buffer, &iter ); - - static GtkTextMark* end = gtk_text_buffer_create_mark( buffer, "end", &iter, FALSE ); - - const GdkColor yellow = { 0, 0xb0ff, 0xb0ff, 0x0000 }; - const GdkColor red = { 0, 0xffff, 0x0000, 0x0000 }; - const GdkColor black = { 0, 0x0000, 0x0000, 0x0000 }; - - static GtkTextTag* error_tag = gtk_text_buffer_create_tag( buffer, "red_foreground", "foreground-gdk", &red, NULL ); - static GtkTextTag* warning_tag = gtk_text_buffer_create_tag( buffer, "yellow_foreground", "foreground-gdk", &yellow, NULL ); - static GtkTextTag* standard_tag = gtk_text_buffer_create_tag( buffer, "black_foreground", "foreground-gdk", &black, NULL ); - GtkTextTag* tag; - switch ( level ) - { - case SYS_WRN: - tag = warning_tag; - break; - case SYS_ERR: - tag = error_tag; - break; - case SYS_STD: - case SYS_VRB: - default: - tag = standard_tag; - break; - } - gtk_text_buffer_insert_with_tags( buffer, &iter, buf, length, tag, NULL ); - - gtk_text_view_scroll_mark_onscreen( GTK_TEXT_VIEW( g_qeglobals_gui.d_edit ), end ); - - // update console widget immediatly if we're doing something time-consuming - if ( !g_bScreenUpdates && GTK_WIDGET_REALIZED( g_qeglobals_gui.d_edit ) ) { - gtk_grab_add( g_qeglobals_gui.d_edit ); - - while ( gtk_events_pending() ) - gtk_main_iteration(); - - gtk_grab_remove( g_qeglobals_gui.d_edit ); - } - } - } -} - -// NOTE: this is the handler sent to synapse -// must match PFN_SYN_PRINTF_VA -extern "C" void Sys_Printf_VA( const char *text, va_list args ){ - Sys_FPrintf_VA( SYS_STD, text, args ); -} - -extern "C" void Sys_Printf( const char *text, ... ) { - va_list args; - - va_start( args, text ); - Sys_FPrintf_VA( SYS_STD, text, args ); - va_end( args ); -} - -extern "C" void Sys_FPrintf( int level, const char *text, ... ){ - va_list args; - - va_start( args, text ); - Sys_FPrintf_VA( level, text, args ); - va_end( args ); }