/* 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. GtkRadiant is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. GtkRadiant 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 General Public License for more details. You should have received a copy of the GNU General Public License along with GtkRadiant; if not, write to the Free Software 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 "defaults.h" #include "qe3.h" #include "globaldefs.h" #include #include "debugging/debugging.h" #include "ifilesystem.h" //#include "imap.h" #include #include #include "stream/textfilestream.h" #include "cmdlib.h" #include "stream/stringstream.h" #include "os/path.h" #include "scenelib.h" #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" QEGlobals_t g_qeglobals; #if GDEF_OS_WINDOWS #define PATH_MAX 260 #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 const char *gamename = gamename_get(); const char *basegame = basegame_get(); const char *userRoot = g_qeglobals.m_userEnginePath.c_str(); const char *globalRoot = EnginePath_get(); // editor builtin VFS StringOutputStream editorGamePath(256); editorGamePath << GlobalRadiant().getAppPath() << DEFAULT_EDITORVFS_DIRNAME; GlobalFileSystem().initDirectory(editorGamePath.c_str()); // if we have a mod dir if (!string_equal(gamename, basegame)) { // ~/./ if (userRoot && !g_disableHomePath) { StringOutputStream userGamePath(256); userGamePath << userRoot << gamename << '/'; GlobalFileSystem().initDirectory(userGamePath.c_str()); } // / if (!g_disableEnginePath) { StringOutputStream globalGamePath(256); globalGamePath << globalRoot << gamename << '/'; GlobalFileSystem().initDirectory(globalGamePath.c_str()); } } // ~/./ if (userRoot && !g_disableHomePath) { StringOutputStream userBasePath(256); userBasePath << userRoot << basegame << '/'; GlobalFileSystem().initDirectory(userBasePath.c_str()); } // / if (!g_disableEnginePath) { StringOutputStream globalBasePath(256); globalBasePath << globalRoot << basegame << '/'; GlobalFileSystem().initDirectory(globalBasePath.c_str()); } // extra pakpaths for (int i = 0; i < g_pakPathCount; i++) { if (g_strcmp0(g_strPakPath[i].c_str(), "")) { GlobalFileSystem().initDirectory(g_strPakPath[i].c_str()); } } } int g_numbrushes = 0; int g_numentities = 0; 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); } SimpleCounter g_brushCount; void QE_brushCountChanged() { g_numbrushes = int(g_brushCount.get()); QE_UpdateStatusBar(); } SimpleCounter g_entityCount; void QE_entityCountChanged() { g_numentities = int(g_entityCount.get()); QE_UpdateStatusBar(); } bool ConfirmModified(const char *title) { if (!Map_Modified(g_map)) { return true; } auto result = ui::alert(MainFrame_getWindow(), "The current map has changed since it was last saved.\nDo you want to save the current map before continuing?", title, ui::alert_type::YESNOCANCEL, ui::alert_icon::Question); if (result == ui::alert_response::CANCEL) { return false; } if (result == ui::alert_response::YES) { if (Map_Unnamed(g_map)) { return Map_SaveAs(); } else { return Map_Save(); } } 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()); StringBuffer ExtraQ3map2Args; // extra pakpaths for (int i = 0; i < g_pakPathCount; i++) { if (g_strcmp0(g_strPakPath[i].c_str(), "")) { ExtraQ3map2Args.push_string(" -fs_pakpath \""); ExtraQ3map2Args.push_string(g_strPakPath[i].c_str()); ExtraQ3map2Args.push_string("\""); } } // extra switches if (g_disableEnginePath) { ExtraQ3map2Args.push_string(" -fs_nobasepath "); } if (g_disableHomePath) { ExtraQ3map2Args.push_string(" -fs_nohomepath "); } build_set_variable("ExtraQ3map2Args", ExtraQ3map2Args.c_str()); const char *mapname = Map_Name(g_map); StringOutputStream name(256); name << StringRange(mapname, path_get_filename_base_end(mapname)) << ".bsp"; build_set_variable("MapFile", mapname); build_set_variable("BspFile", name.c_str()); } void bsp_shutdown() { build_clear_variables(); } class ArrayCommandListener : public CommandListener { GPtrArray *m_array; public: ArrayCommandListener() { m_array = g_ptr_array_new(); } ~ArrayCommandListener() { g_ptr_array_free(m_array, TRUE); } void execute(const char *command) { g_ptr_array_add(m_array, g_strdup(command)); } GPtrArray *array() const { return m_array; } }; 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) { } void execute(const char *command) { m_file << command; if (m_commandCount == 0) { m_file << " > "; } else { m_file << " >> "; } m_file << "\"" << m_outputRedirect << "\""; m_file << "\n"; ++m_commandCount; } }; bool Region_cameraValid() { Vector3 vOrig(vector3_snapped(Camera_getOrigin(*g_pParentWnd->GetCamWnd()))); for (int i = 0; i < 3; i++) { if (vOrig[i] > region_maxs[i] || vOrig[i] < region_mins[i]) { return false; } } return true; } 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; } SaveMap(); if (Map_Unnamed(g_map)) { globalOutputStream() << "build cancelled\n"; return; } if (g_SnapShots_Enabled && !Map_Unnamed(g_map) && Map_Modified(g_map)) { Map_Snapshot(); } 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()); } Pointfile_Delete(); bsp_init(); 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()); } else { char junkpath[PATH_MAX]; strcpy(junkpath, SettingsPath_get()); strcat(junkpath, "junk.txt"); char batpath[PATH_MAX]; #if GDEF_OS_POSIX strcpy(batpath, SettingsPath_get()); strcat(batpath, "qe3bsp.sh"); #elif GDEF_OS_WINDOWS strcpy( batpath, SettingsPath_get() ); strcat( batpath, "qe3bsp.bat" ); #else #error "unsupported platform" #endif bool written = false; { TextFileOutputStream batchFile(batpath); if (!batchFile.failed()) { #if GDEF_OS_POSIX batchFile << "#!/bin/sh \n\n"; #endif BatchCommandListener listener(batchFile, junkpath); build_run(name, listener); written = true; } } if (written) { #if GDEF_OS_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); } } bsp_shutdown(); } // ============================================================================= // Sys_ functions void Sys_SetTitle(const char *text, bool modified) { StringOutputStream title; title << text; if (modified) { title << " *"; } gtk_window_set_title(MainFrame_getWindow(), title.c_str()); } bool g_bWaitCursor = false; void Sys_BeginWait(void) { ScreenUpdates_Disable("Processing...", "Please Wait"); GdkCursor *cursor = gdk_cursor_new(GDK_WATCH); gdk_window_set_cursor(gtk_widget_get_window(MainFrame_getWindow()), cursor); gdk_cursor_unref(cursor); g_bWaitCursor = true; } void Sys_EndWait(void) { ScreenUpdates_Enable(); gdk_window_set_cursor(gtk_widget_get_window(MainFrame_getWindow()), 0); g_bWaitCursor = false; } void Sys_Beep(void) { gdk_beep(); }