The GtkRadiant sources as originally released under the GPL license.

This commit is contained in:
Travis Bradshaw
2012-01-31 15:20:35 -06:00
commit 0991a5ce8b
1590 changed files with 431941 additions and 0 deletions

16
radiant/.cvsignore Normal file
View File

@@ -0,0 +1,16 @@
Debug
Release
radiant
*.d
*.o
*.opt
*.ncb
*.BAK
*.00*
*.plg
radiant
q3map
unnamed.map
.snprj
tools
*.gcse

1082
radiant/GtkRadiant.dsp Normal file

File diff suppressed because it is too large Load Diff

712
radiant/GtkRadiant.vcproj Normal file
View File

@@ -0,0 +1,712 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="GtkRadiant"
ProjectGUID="{8E70385C-223A-4DD1-9B99-28FF2331A2B5}"
RootNamespace="GtkRadiant"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="1"
CharacterSet="0">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../include;../libs;&quot;../../STLPort-4.6/stlport&quot;;&quot;../../libxml2-2.6/include&quot;;&quot;../../gtk2-2.4/lib/glib-2.0/include&quot;;&quot;../../gtk2-2.4/include/glib-2.0&quot;;&quot;../../gtk2-2.4/lib/gtk-2.0/include&quot;;&quot;../../gtk2-2.4/include/gtk-2.0&quot;;&quot;../../gtk2-2.4/include/gtk-2.0/gdk&quot;;&quot;../../gtk2-2.4/include/pango-1.0&quot;;&quot;../../gtk2-2.4/include/atk-1.0&quot;;&quot;../../gtk2-2.4/lib/gtkglext-1.0/include&quot;;&quot;../../gtk2-2.4/include/gtkglext-1.0&quot;"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
StringPooling="TRUE"
MinimalRebuild="TRUE"
ExceptionHandling="FALSE"
BasicRuntimeChecks="0"
RuntimeLibrary="3"
BufferSecurityCheck="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
BrowseInformation="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"
DisableSpecificWarnings="4610;4510;4512;4505;4100;4127"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="msvcrtd.lib oldnames.lib winmm.lib kernel32.lib user32.lib gdi32.lib shfolder.lib wsock32.lib dbghelp.lib glib-2.0.lib gobject-2.0.lib gdk-win32-2.0.lib gdk_pixbuf-2.0.lib gtk-win32-2.0.lib pango-1.0.lib gtkglext-win32-1.0.lib gdkglext-win32-1.0.lib opengl32.lib libxml2.lib profile.lib"
OutputFile="$(OutDir)/$(ProjectName).exe"
LinkIncremental="1"
AdditionalLibraryDirectories="&quot;../../gtk2-2.4/lib&quot;;&quot;../../libxml2-2.6/win32/lib&quot;;&quot;../libs/profile/debug/&quot;"
IgnoreAllDefaultLibraries="TRUE"
IgnoreDefaultLibraryNames="msvcprtd.lib"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"
StripPrivateSymbols="$(OutDir)/$(ProjectName)_stripped.pdb"
GenerateMapFile="FALSE"
SubSystem="2"
EntryPointSymbol="mainCRTStartup"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"
CommandLine="copy &quot;$(TargetPath)&quot; &quot;$(SolutionDir)install&quot;
copy &quot;$(TargetDir)$(TargetName).pdb&quot; &quot;$(SolutionDir)install&quot;
"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="_DEBUG"
Culture="1033"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="1"
CharacterSet="0"
WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
GlobalOptimizations="TRUE"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="TRUE"
FavorSizeOrSpeed="1"
OptimizeForWindowsApplication="TRUE"
AdditionalIncludeDirectories="../include;../libs;&quot;../../STLPort-4.6/stlport&quot;;&quot;../../libxml2-2.6/include&quot;;&quot;../../gtk2-2.4/lib/glib-2.0/include&quot;;&quot;../../gtk2-2.4/include/glib-2.0&quot;;&quot;../../gtk2-2.4/lib/gtk-2.0/include&quot;;&quot;../../gtk2-2.4/include/gtk-2.0&quot;;&quot;../../gtk2-2.4/include/gtk-2.0/gdk&quot;;&quot;../../gtk2-2.4/include/pango-1.0&quot;;&quot;../../gtk2-2.4/include/atk-1.0&quot;;&quot;../../gtk2-2.4/lib/gtkglext-1.0/include&quot;;&quot;../../gtk2-2.4/include/gtkglext-1.0&quot;"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
StringPooling="TRUE"
ExceptionHandling="FALSE"
RuntimeLibrary="2"
BufferSecurityCheck="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"
DisableSpecificWarnings="4610;4510;4512;4505;4100;4127"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="msvcrt.lib oldnames.lib winmm.lib kernel32.lib user32.lib gdi32.lib shfolder.lib wsock32.lib dbghelp.lib glib-2.0.lib gobject-2.0.lib gdk-win32-2.0.lib gdk_pixbuf-2.0.lib gtk-win32-2.0.lib pango-1.0.lib gtkglext-win32-1.0.lib gdkglext-win32-1.0.lib opengl32.lib libxml2.lib profile.lib"
OutputFile="$(OutDir)/$(ProjectName).exe"
LinkIncremental="1"
AdditionalLibraryDirectories="&quot;../../gtk2-2.4/lib&quot;;&quot;../../libxml2-2.6/win32/lib&quot;;&quot;../libs/profile/release/&quot;"
IgnoreAllDefaultLibraries="TRUE"
IgnoreDefaultLibraryNames="msvcprt.lib"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"
StripPrivateSymbols="$(OutDir)/$(ProjectName)_stripped.pdb"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
EntryPointSymbol="mainCRTStartup"
TargetMachine="1"
FixedBaseAddress="0"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"
CommandLine="copy &quot;$(TargetPath)&quot; &quot;$(SolutionDir)install&quot;
copy &quot;$(TargetDir)$(TargetName).pdb&quot; &quot;$(SolutionDir)install&quot;
"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"
Culture="1033"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="src"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
<File
RelativePath=".\autosave.cpp">
</File>
<File
RelativePath=".\autosave.h">
</File>
<File
RelativePath="..\radiant\brush.cpp">
</File>
<File
RelativePath="..\radiant\brush.h">
</File>
<File
RelativePath="..\radiant\brush_primit.cpp">
</File>
<File
RelativePath="..\radiant\brush_primit.h">
</File>
<File
RelativePath=".\brushmanip.cpp">
</File>
<File
RelativePath=".\brushmanip.h">
</File>
<File
RelativePath=".\brushmodule.cpp">
</File>
<File
RelativePath=".\brushmodule.h">
</File>
<File
RelativePath=".\brushnode.cpp">
</File>
<File
RelativePath=".\brushnode.h">
</File>
<File
RelativePath=".\brushtokens.cpp">
</File>
<File
RelativePath=".\brushtokens.h">
</File>
<File
RelativePath=".\brushxml.cpp">
</File>
<File
RelativePath=".\brushxml.h">
</File>
<File
RelativePath=".\build.cpp">
</File>
<File
RelativePath=".\build.h">
</File>
<File
RelativePath="..\radiant\camwindow.cpp">
</File>
<File
RelativePath="..\radiant\camwindow.h">
</File>
<File
RelativePath=".\clippertool.cpp">
</File>
<File
RelativePath=".\clippertool.h">
</File>
<File
RelativePath=".\commands.cpp">
</File>
<File
RelativePath=".\commands.h">
</File>
<File
RelativePath=".\console.cpp">
</File>
<File
RelativePath=".\console.h">
</File>
<File
RelativePath="..\radiant\csg.cpp">
</File>
<File
RelativePath="..\radiant\csg.h">
</File>
<File
RelativePath="..\radiant\dialog.cpp">
</File>
<File
RelativePath="..\radiant\dialog.h">
</File>
<File
RelativePath="..\radiant\eclass.cpp">
</File>
<File
RelativePath="..\radiant\eclass.h">
</File>
<File
RelativePath="..\radiant\eclass_def.cpp">
</File>
<File
RelativePath="..\radiant\eclass_def.h">
</File>
<File
RelativePath=".\eclass_doom3.cpp">
</File>
<File
RelativePath=".\eclass_doom3.h">
</File>
<File
RelativePath=".\eclass_fgd.cpp">
</File>
<File
RelativePath=".\eclass_fgd.h">
</File>
<File
RelativePath=".\eclass_xml.cpp">
</File>
<File
RelativePath=".\eclass_xml.h">
</File>
<File
RelativePath=".\entity.cpp">
</File>
<File
RelativePath=".\entity.h">
</File>
<File
RelativePath="..\radiant\entityinspector.cpp">
</File>
<File
RelativePath="..\radiant\entityinspector.h">
</File>
<File
RelativePath=".\entitylist.cpp">
</File>
<File
RelativePath=".\entitylist.h">
</File>
<File
RelativePath=".\environment.cpp">
</File>
<File
RelativePath=".\environment.h">
</File>
<File
RelativePath="..\radiant\error.cpp">
</File>
<File
RelativePath="..\radiant\error.h">
</File>
<File
RelativePath="..\radiant\feedback.cpp">
</File>
<File
RelativePath="..\radiant\feedback.h">
</File>
<File
RelativePath="..\radiant\filetypes.cpp">
</File>
<File
RelativePath="..\radiant\filetypes.h">
</File>
<File
RelativePath="..\radiant\filters.cpp">
</File>
<File
RelativePath="..\radiant\filters.h">
</File>
<File
RelativePath="..\radiant\findtexturedialog.cpp">
</File>
<File
RelativePath="..\radiant\findtexturedialog.h">
</File>
<File
RelativePath="..\radiant\glwidget.cpp">
</File>
<File
RelativePath="..\radiant\glwidget.h">
</File>
<File
RelativePath=".\grid.cpp">
</File>
<File
RelativePath=".\grid.h">
</File>
<File
RelativePath="..\radiant\groupdialog.cpp">
</File>
<File
RelativePath="..\radiant\groupdialog.h">
</File>
<File
RelativePath="..\radiant\gtkdlgs.cpp">
</File>
<File
RelativePath="..\radiant\gtkdlgs.h">
</File>
<File
RelativePath="..\radiant\gtkmisc.cpp">
</File>
<File
RelativePath="..\radiant\gtkmisc.h">
</File>
<File
RelativePath=".\help.cpp">
</File>
<File
RelativePath=".\help.h">
</File>
<File
RelativePath="..\radiant\image.cpp">
</File>
<File
RelativePath="..\radiant\image.h">
</File>
<File
RelativePath="..\radiant\main.cpp">
</File>
<File
RelativePath="..\radiant\main.h">
</File>
<File
RelativePath="..\radiant\mainframe.cpp">
</File>
<File
RelativePath="..\radiant\mainframe.h">
</File>
<File
RelativePath="..\radiant\map.cpp">
</File>
<File
RelativePath="..\radiant\map.h">
</File>
<File
RelativePath=".\mru.cpp">
</File>
<File
RelativePath=".\mru.h">
</File>
<File
RelativePath="..\radiant\multimon.cpp">
</File>
<File
RelativePath="..\radiant\multimon.h">
</File>
<File
RelativePath="..\radiant\nullmodel.cpp">
</File>
<File
RelativePath="..\radiant\nullmodel.h">
</File>
<File
RelativePath="..\radiant\parse.cpp">
</File>
<File
RelativePath="..\radiant\parse.h">
</File>
<File
RelativePath="..\radiant\patch.cpp">
</File>
<File
RelativePath="..\radiant\patch.h">
</File>
<File
RelativePath="..\radiant\patchdialog.cpp">
</File>
<File
RelativePath="..\radiant\patchdialog.h">
</File>
<File
RelativePath="..\radiant\patchmanip.cpp">
</File>
<File
RelativePath="..\radiant\patchmanip.h">
</File>
<File
RelativePath=".\patchmodule.cpp">
</File>
<File
RelativePath=".\patchmodule.h">
</File>
<File
RelativePath="..\radiant\plugin.cpp">
</File>
<File
RelativePath="..\radiant\plugin.h">
</File>
<File
RelativePath="..\radiant\pluginapi.cpp">
</File>
<File
RelativePath="..\radiant\pluginapi.h">
</File>
<File
RelativePath="..\radiant\pluginmanager.cpp">
</File>
<File
RelativePath="..\radiant\pluginmanager.h">
</File>
<File
RelativePath=".\pluginmenu.cpp">
</File>
<File
RelativePath=".\pluginmenu.h">
</File>
<File
RelativePath=".\plugintoolbar.cpp">
</File>
<File
RelativePath=".\plugintoolbar.h">
</File>
<File
RelativePath="..\radiant\points.cpp">
</File>
<File
RelativePath="..\radiant\points.h">
</File>
<File
RelativePath=".\preferencedictionary.cpp">
</File>
<File
RelativePath="..\radiant\preferencedictionary.h">
</File>
<File
RelativePath="..\radiant\preferences.cpp">
</File>
<File
RelativePath="..\radiant\preferences.h">
</File>
<File
RelativePath="..\radiant\qe3.cpp">
</File>
<File
RelativePath="..\radiant\qe3.h">
</File>
<File
RelativePath="..\radiant\qgl.cpp">
</File>
<File
RelativePath="..\radiant\qgl.h">
</File>
<File
RelativePath="..\radiant\referencecache.cpp">
</File>
<File
RelativePath="..\radiant\referencecache.h">
</File>
<File
RelativePath=".\renderer.cpp">
</File>
<File
RelativePath="..\radiant\renderer.h">
</File>
<File
RelativePath="..\radiant\renderstate.cpp">
</File>
<File
RelativePath="..\radiant\renderstate.h">
</File>
<File
RelativePath="..\radiant\scenegraph.cpp">
</File>
<File
RelativePath="..\radiant\scenegraph.h">
</File>
<File
RelativePath="..\radiant\select.cpp">
</File>
<File
RelativePath="..\radiant\select.h">
</File>
<File
RelativePath="..\radiant\selection.cpp">
</File>
<File
RelativePath="..\radiant\selection.h">
</File>
<File
RelativePath="..\radiant\server.cpp">
</File>
<File
RelativePath="..\radiant\server.h">
</File>
<File
RelativePath=".\shaders.cpp">
</File>
<File
RelativePath=".\shaders.h">
</File>
<File
RelativePath=".\stacktrace.cpp">
</File>
<File
RelativePath=".\stacktrace.h">
</File>
<File
RelativePath="..\radiant\surfacedialog.cpp">
</File>
<File
RelativePath="..\radiant\surfacedialog.h">
</File>
<File
RelativePath="..\radiant\texmanip.cpp">
</File>
<File
RelativePath="..\radiant\texmanip.h">
</File>
<File
RelativePath=".\textureentry.cpp">
</File>
<File
RelativePath=".\textureentry.h">
</File>
<File
RelativePath="..\radiant\textures.cpp">
</File>
<File
RelativePath="..\radiant\textures.h">
</File>
<File
RelativePath="..\radiant\texwindow.cpp">
</File>
<File
RelativePath="..\radiant\texwindow.h">
</File>
<File
RelativePath="..\radiant\timer.cpp">
</File>
<File
RelativePath="..\radiant\timer.h">
</File>
<File
RelativePath="..\radiant\treemodel.cpp">
</File>
<File
RelativePath="..\radiant\treemodel.h">
</File>
<File
RelativePath="..\radiant\undo.cpp">
</File>
<File
RelativePath="..\radiant\undo.h">
</File>
<File
RelativePath=".\url.cpp">
</File>
<File
RelativePath=".\url.h">
</File>
<File
RelativePath="..\radiant\view.cpp">
</File>
<File
RelativePath="..\radiant\view.h">
</File>
<File
RelativePath="..\radiant\watchbsp.cpp">
</File>
<File
RelativePath="..\radiant\watchbsp.h">
</File>
<File
RelativePath="..\radiant\winding.cpp">
</File>
<File
RelativePath="..\radiant\winding.h">
</File>
<File
RelativePath=".\windowobservers.cpp">
</File>
<File
RelativePath=".\windowobservers.h">
</File>
<File
RelativePath=".\xmlstuff.cpp">
</File>
<File
RelativePath="..\radiant\xmlstuff.h">
</File>
<File
RelativePath="..\radiant\xywindow.cpp">
</File>
<File
RelativePath="..\radiant\xywindow.h">
</File>
</Filter>
<File
RelativePath="..\docs\developer\Changes">
</File>
<File
RelativePath="..\debug.py">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCustomBuildTool"
CommandLine="python &quot;$(SolutionDir)debug.py&quot;
"
AdditionalDependencies="&quot;$(SolutionDir)install\$(TargetName).pdb&quot;"
Outputs="&quot;$(TargetDir)$(TargetName).pdb&quot;"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCustomBuildTool"
CommandLine="python &quot;$(SolutionDir)debug.py&quot;
"
AdditionalDependencies="&quot;$(SolutionDir)install\$(TargetName).pdb&quot;"
Outputs="&quot;$(TargetDir)$(TargetName).pdb&quot;"/>
</FileConfiguration>
</File>
<File
RelativePath=".\radiant.ico">
</File>
<File
RelativePath=".\radiant.rc">
</File>
<File
RelativePath="..\radiant\resource.h">
</File>
<File
RelativePath="..\SConscript">
</File>
<File
RelativePath="..\SConstruct">
</File>
<File
RelativePath="..\docs\developer\Todo">
</File>
<File
RelativePath="..\touch.py">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCustomBuildTool"
CommandLine="python &quot;$(SolutionDir)touch.py&quot;
"
AdditionalDependencies="&quot;$(SolutionDir)install\$(TargetFileName)&quot;"
Outputs="&quot;$(TargetPath)&quot;"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCustomBuildTool"
CommandLine="python &quot;$(SolutionDir)touch.py&quot;
"
AdditionalDependencies="&quot;$(SolutionDir)install\$(TargetFileName)&quot;"
Outputs="&quot;$(TargetPath)&quot;"/>
</FileConfiguration>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

224
radiant/autosave.cpp Normal file
View File

@@ -0,0 +1,224 @@
/*
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
*/
#include "autosave.h"
#include "os/file.h"
#include "os/path.h"
#include "cmdlib.h"
#include "stream/stringstream.h"
#include "gtkutil/messagebox.h"
#include "scenelib.h"
#include "mapfile.h"
#include "map.h"
#include "mainframe.h"
#include "qe3.h"
#include "preferences.h"
#if defined(WIN32)
#define PATH_MAX 260
#endif
bool DoesFileExist(const char* name, std::size_t& size)
{
if(file_exists(name))
{
size += file_size(name);
return true;
}
return false;
}
void Map_Snapshot()
{
// 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
const char* path = Map_Name(g_map);
const char* name = path_get_filename_start(path);
StringOutputStream snapshotsDir(256);
snapshotsDir << StringRange(path, name) << "snapshots";
if(file_exists(snapshotsDir.c_str()) || Q_mkdir(snapshotsDir.c_str()))
{
std::size_t lSize = 0;
StringOutputStream strNewPath(256);
strNewPath << snapshotsDir.c_str() << '/' << name;
StringOutputStream snapshotFilename(256);
for(int nCount = 0; ; ++nCount)
{
// The original map's filename is "<path>/<name>.<ext>"
// The snapshot's filename will be "<path>/snapshots/<name>.<count>.<ext>"
const char* end = path_get_filename_base_end(strNewPath.c_str());
snapshotFilename << StringRange(strNewPath.c_str(), end) << '.' << nCount << end;
if(!DoesFileExist(snapshotFilename.c_str(), lSize))
{
break;
}
snapshotFilename.clear();
}
// save in the next available slot
Map_SaveFile(snapshotFilename.c_str());
if (lSize > 50 * 1024 * 1024) // total size of saves > 50 mb
{
globalOutputStream() << "The snapshot files in " << snapshotsDir.c_str() << " total more than 50 megabytes. You might consider cleaning up.";
}
}
else
{
StringOutputStream strMsg(256);
strMsg << "Snapshot save failed.. unabled to create directory\n" << snapshotsDir.c_str();
gtk_MessageBox(GTK_WIDGET(MainFrame_getWindow()), strMsg.c_str());
}
}
/*
===============
QE_CheckAutoSave
If five minutes have passed since making a change
and the map hasn't been saved, save it out.
===============
*/
bool g_AutoSave_Enabled = true;
int m_AutoSave_Frequency = 5;
bool g_SnapShots_Enabled = false;
namespace
{
time_t s_start = 0;
std::size_t s_changes = 0;
}
void AutoSave_clear()
{
s_changes = 0;
}
scene::Node& Map_Node()
{
return GlobalSceneGraph().root();
}
void QE_CheckAutoSave( void )
{
if(!Map_Valid(g_map) || !ScreenUpdates_Enabled())
{
return;
}
time_t now;
time(&now);
if(s_start == 0 || s_changes == Node_getMapFile(Map_Node())->changes())
{
s_start = now;
}
if((now - s_start) > (60 * m_AutoSave_Frequency))
{
s_start = now;
s_changes = Node_getMapFile(Map_Node())->changes();
if (g_AutoSave_Enabled)
{
const char* strMsg = g_SnapShots_Enabled ? "Autosaving snapshot..." : "Autosaving...";
globalOutputStream() << strMsg << "\n";
//Sys_Status(strMsg);
// only snapshot if not working on a default map
if (g_SnapShots_Enabled && !Map_Unnamed(g_map))
{
Map_Snapshot();
}
else
{
if(Map_Unnamed(g_map))
{
StringOutputStream autosave(256);
autosave << g_qeglobals.m_userGamePath.c_str() << "maps/";
Q_mkdir(autosave.c_str());
autosave << "autosave.map";
Map_SaveFile(autosave.c_str());
}
else
{
const char* name = Map_Name(g_map);
const char* extension = path_get_filename_base_end(name);
StringOutputStream autosave(256);
autosave << StringRange(name, extension) << ".autosave" << extension;
Map_SaveFile(autosave.c_str());
}
}
}
else
{
globalOutputStream() << "Autosave skipped...\n";
//Sys_Status ("Autosave skipped...");
}
}
}
void Autosave_constructPreferences(PreferencesPage& page)
{
GtkWidget* autosave_enabled = page.appendCheckBox("Autosave", "Enable Autosave", g_AutoSave_Enabled);
GtkWidget* autosave_frequency = page.appendSpinner("Autosave Frequency (minutes)", m_AutoSave_Frequency, 1, 1, 60);
Widget_connectToggleDependency(autosave_frequency, autosave_enabled);
page.appendCheckBox("", "Save Snapshots", g_SnapShots_Enabled);
}
void Autosave_constructPage(PreferenceGroup& group)
{
PreferencesPage page(group.createPage("Autosave", "Autosave Preferences"));
Autosave_constructPreferences(page);
}
void Autosave_registerPreferencesPage()
{
PreferencesDialog_addSettingsPage(FreeCaller1<PreferenceGroup&, Autosave_constructPage>());
}
#include "preferencesystem.h"
#include "stringio.h"
void Autosave_Construct()
{
GlobalPreferenceSystem().registerPreference("Autosave", BoolImportStringCaller(g_AutoSave_Enabled), BoolExportStringCaller(g_AutoSave_Enabled));
GlobalPreferenceSystem().registerPreference("AutosaveMinutes", IntImportStringCaller(m_AutoSave_Frequency), IntExportStringCaller(m_AutoSave_Frequency));
GlobalPreferenceSystem().registerPreference("Snapshots", BoolImportStringCaller(g_SnapShots_Enabled), BoolExportStringCaller(g_SnapShots_Enabled));
Autosave_registerPreferencesPage();
}
void Autosave_Destroy()
{
}

35
radiant/autosave.h Normal file
View File

@@ -0,0 +1,35 @@
/*
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
*/
#if !defined(INCLUDED_AUTOSAVE_H)
#define INCLUDED_AUTOSAVE_H
extern bool g_SnapShots_Enabled;
void AutoSave_clear();
void QE_CheckAutoSave( void );
void Map_Snapshot();
void Autosave_Construct();
void Autosave_Destroy();
#endif

415
radiant/brush.cpp Normal file
View File

@@ -0,0 +1,415 @@
/*
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
*/
#include "brush.h"
std::set<Callback> g_brushTextureChangedCallbacks;
void Brush_addTextureChangedCallback(const Callback& callback)
{
g_brushTextureChangedCallbacks.insert(callback);
}
void Brush_textureChanged()
{
std::for_each(g_brushTextureChangedCallbacks.begin(), g_brushTextureChangedCallbacks.end(), CallbackInvoke());
}
QuantiseFunc Face::m_quantise;
EBrushType Face::m_type;
EBrushType FacePlane::m_type;
bool g_brush_texturelock_enabled = false;
EBrushType Brush::m_type;
double Brush::m_maxWorldCoord = 0;
Shader* Brush::m_state_point;
Shader* BrushClipPlane::m_state = 0;
Shader* BrushInstance::m_state_selpoint;
Counter* BrushInstance::m_counter = 0;
FaceInstanceSet g_SelectedFaceInstances;
struct SListNode
{
SListNode* m_next;
};
class ProximalVertex
{
public:
const SListNode* m_vertices;
ProximalVertex(const SListNode* next)
: m_vertices(next)
{
}
bool operator<(const ProximalVertex& other) const
{
if(!(operator==(other)))
{
return m_vertices < other.m_vertices;
}
return false;
}
bool operator==(const ProximalVertex& other) const
{
const SListNode* v = m_vertices;
std::size_t DEBUG_LOOP = 0;
do
{
if(v == other.m_vertices)
return true;
v = v->m_next;
//ASSERT_MESSAGE(DEBUG_LOOP < c_brush_maxFaces, "infinite loop");
if(!(DEBUG_LOOP < c_brush_maxFaces))
{
break;
}
++DEBUG_LOOP;
}
while(v != m_vertices);
return false;
}
};
typedef Array<SListNode> ProximalVertexArray;
std::size_t ProximalVertexArray_index(const ProximalVertexArray& array, const ProximalVertex& vertex)
{
return vertex.m_vertices - array.data();
}
inline bool Brush_isBounded(const Brush& brush)
{
for(Brush::const_iterator i = brush.begin(); i != brush.end(); ++i)
{
if(!(*i)->is_bounded())
{
return false;
}
}
return true;
}
void Brush::buildBRep()
{
bool degenerate = buildWindings();
std::size_t faces_size = 0;
std::size_t faceVerticesCount = 0;
for(Faces::const_iterator i = m_faces.begin(); i != m_faces.end(); ++i)
{
if((*i)->contributes())
{
++faces_size;
}
faceVerticesCount += (*i)->getWinding().numpoints;
}
if(degenerate || faces_size < 4 || faceVerticesCount != (faceVerticesCount>>1)<<1) // sum of vertices for each face of a valid polyhedron is always even
{
m_uniqueVertexPoints.resize(0);
vertex_clear();
edge_clear();
m_edge_indices.resize(0);
m_edge_faces.resize(0);
m_faceCentroidPoints.resize(0);
m_uniqueEdgePoints.resize(0);
m_uniqueVertexPoints.resize(0);
for(Faces::iterator i = m_faces.begin(); i != m_faces.end(); ++i)
{
(*i)->getWinding().resize(0);
}
}
else
{
{
typedef std::vector<FaceVertexId> FaceVertices;
FaceVertices faceVertices;
faceVertices.reserve(faceVerticesCount);
{
for(std::size_t i = 0; i != m_faces.size(); ++i)
{
for(std::size_t j = 0; j < m_faces[i]->getWinding().numpoints; ++j)
{
faceVertices.push_back(FaceVertexId(i, j));
}
}
}
IndexBuffer uniqueEdgeIndices;
typedef VertexBuffer<ProximalVertex> UniqueEdges;
UniqueEdges uniqueEdges;
uniqueEdgeIndices.reserve(faceVertices.size());
uniqueEdges.reserve(faceVertices.size());
{
ProximalVertexArray edgePairs;
edgePairs.resize(faceVertices.size());
{
for(std::size_t i=0; i<faceVertices.size(); ++i)
{
edgePairs[i].m_next = edgePairs.data() + absoluteIndex(next_edge(m_faces, faceVertices[i]));
}
}
{
UniqueVertexBuffer<ProximalVertex> inserter(uniqueEdges);
for(ProximalVertexArray::iterator i = edgePairs.begin(); i != edgePairs.end(); ++i)
{
uniqueEdgeIndices.insert(inserter.insert(ProximalVertex(&(*i))));
}
}
{
edge_clear();
m_select_edges.reserve(uniqueEdges.size());
for(UniqueEdges::iterator i = uniqueEdges.begin(); i != uniqueEdges.end(); ++i)
{
edge_push_back(faceVertices[ProximalVertexArray_index(edgePairs, *i)]);
}
}
{
m_edge_faces.resize(uniqueEdges.size());
for(std::size_t i=0; i<uniqueEdges.size(); ++i)
{
FaceVertexId faceVertex = faceVertices[ProximalVertexArray_index(edgePairs, uniqueEdges[i])];
m_edge_faces[i] = EdgeFaces(faceVertex.getFace(), m_faces[faceVertex.getFace()]->getWinding()[faceVertex.getVertex()].adjacent);
}
}
{
m_uniqueEdgePoints.resize(uniqueEdges.size());
for(std::size_t i=0; i<uniqueEdges.size(); ++i)
{
FaceVertexId faceVertex = faceVertices[ProximalVertexArray_index(edgePairs, uniqueEdges[i])];
const Winding& w = m_faces[faceVertex.getFace()]->getWinding();
Vector3 edge = vector3_mid(w[faceVertex.getVertex()].vertex, w[Winding_next(w, faceVertex.getVertex())].vertex);
m_uniqueEdgePoints[i] = pointvertex_for_windingpoint(edge, colour_vertex);
}
}
}
IndexBuffer uniqueVertexIndices;
typedef VertexBuffer<ProximalVertex> UniqueVertices;
UniqueVertices uniqueVertices;
uniqueVertexIndices.reserve(faceVertices.size());
uniqueVertices.reserve(faceVertices.size());
{
ProximalVertexArray vertexRings;
vertexRings.resize(faceVertices.size());
{
for(std::size_t i=0; i<faceVertices.size(); ++i)
{
vertexRings[i].m_next = vertexRings.data() + absoluteIndex(next_vertex(m_faces, faceVertices[i]));
}
}
{
UniqueVertexBuffer<ProximalVertex> inserter(uniqueVertices);
for(ProximalVertexArray::iterator i = vertexRings.begin(); i != vertexRings.end(); ++i)
{
uniqueVertexIndices.insert(inserter.insert(ProximalVertex(&(*i))));
}
}
{
vertex_clear();
m_select_vertices.reserve(uniqueVertices.size());
for(UniqueVertices::iterator i = uniqueVertices.begin(); i != uniqueVertices.end(); ++i)
{
vertex_push_back(faceVertices[ProximalVertexArray_index(vertexRings, (*i))]);
}
}
{
m_uniqueVertexPoints.resize(uniqueVertices.size());
for(std::size_t i=0; i<uniqueVertices.size(); ++i)
{
FaceVertexId faceVertex = faceVertices[ProximalVertexArray_index(vertexRings, uniqueVertices[i])];
const Winding& winding = m_faces[faceVertex.getFace()]->getWinding();
m_uniqueVertexPoints[i] = pointvertex_for_windingpoint(winding[faceVertex.getVertex()].vertex, colour_vertex);
}
}
}
ASSERT_MESSAGE((uniqueVertices.size() + faces_size) - uniqueEdges.size() == 2, "Final B-Rep: inconsistent vertex count");
#if BRUSH_CONNECTIVITY_DEBUG
if((uniqueVertices.size() + faces_size) - uniqueEdges.size() != 2)
{
for(Faces::iterator i = m_faces.begin(); i != m_faces.end(); ++i)
{
std::size_t faceIndex = std::distance(m_faces.begin(), i);
if(!(*i)->contributes())
{
globalOutputStream() << "face: " << Unsigned(faceIndex) << " does not contribute\n";
}
Winding_printConnectivity((*i)->getWinding());
}
}
#endif
// edge-index list for wireframe rendering
{
m_edge_indices.resize(uniqueEdgeIndices.size());
for(std::size_t i=0, count=0; i<m_faces.size(); ++i)
{
const Winding& winding = m_faces[i]->getWinding();
for(std::size_t j = 0; j < winding.numpoints; ++j)
{
const RenderIndex edge_index = uniqueEdgeIndices[count+j];
m_edge_indices[edge_index].first = uniqueVertexIndices[count + j];
m_edge_indices[edge_index].second = uniqueVertexIndices[count + Winding_next(winding, j)];
}
count += winding.numpoints;
}
}
}
{
m_faceCentroidPoints.resize(m_faces.size());
for(std::size_t i=0; i<m_faces.size(); ++i)
{
m_faces[i]->construct_centroid();
m_faceCentroidPoints[i] = pointvertex_for_windingpoint(m_faces[i]->centroid(), colour_vertex);
}
}
}
}
class FaceFilterWrapper : public Filter
{
FaceFilter& m_filter;
bool m_active;
bool m_invert;
public:
FaceFilterWrapper(FaceFilter& filter, bool invert) :
m_filter(filter),
m_invert(invert)
{
}
void setActive(bool active)
{
m_active = active;
}
bool active()
{
return m_active;
}
bool filter(const Face& face)
{
return m_invert ^ m_filter.filter(face);
}
};
typedef std::list<FaceFilterWrapper> FaceFilters;
FaceFilters g_faceFilters;
void add_face_filter(FaceFilter& filter, int mask, bool invert)
{
g_faceFilters.push_back(FaceFilterWrapper(filter, invert));
GlobalFilterSystem().addFilter(g_faceFilters.back(), mask);
}
bool face_filtered(Face& face)
{
for(FaceFilters::iterator i = g_faceFilters.begin(); i != g_faceFilters.end(); ++i)
{
if((*i).active() && (*i).filter(face))
{
return true;
}
}
return false;
}
class BrushFilterWrapper : public Filter
{
bool m_active;
bool m_invert;
BrushFilter& m_filter;
public:
BrushFilterWrapper(BrushFilter& filter, bool invert) : m_invert(invert), m_filter(filter)
{
}
void setActive(bool active)
{
m_active = active;
}
bool active()
{
return m_active;
}
bool filter(const Brush& brush)
{
return m_invert ^ m_filter.filter(brush);
}
};
typedef std::list<BrushFilterWrapper> BrushFilters;
BrushFilters g_brushFilters;
void add_brush_filter(BrushFilter& filter, int mask, bool invert)
{
g_brushFilters.push_back(BrushFilterWrapper(filter, invert));
GlobalFilterSystem().addFilter(g_brushFilters.back(), mask);
}
bool brush_filtered(Brush& brush)
{
for(BrushFilters::iterator i = g_brushFilters.begin(); i != g_brushFilters.end(); ++i)
{
if((*i).active() && (*i).filter(brush))
{
return true;
}
}
return false;
}

4018
radiant/brush.h Normal file

File diff suppressed because it is too large Load Diff

1600
radiant/brush_primit.cpp Normal file

File diff suppressed because it is too large Load Diff

137
radiant/brush_primit.h Normal file
View File

@@ -0,0 +1,137 @@
/*
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
*/
#if !defined(INCLUDED_BRUSH_PRIMIT_H)
#define INCLUDED_BRUSH_PRIMIT_H
#include "math/vector.h"
#include "itexdef.h"
// Timo
// new brush primitive texdef
struct brushprimit_texdef_t
{
brushprimit_texdef_t()
{
coords[0][0] = 2.0f;
coords[0][1] = 0.f;
coords[0][2] = 0.f;
coords[1][0] = 0.f;
coords[1][1] = 2.0f;
coords[1][2] = 0.f;
}
void removeScale(std::size_t width, std::size_t height)
{
#if 1
coords[0][0] *= width;
coords[0][1] *= width;
coords[0][2] *= width;
coords[1][0] *= height;
coords[1][1] *= height;
coords[1][2] *= height;
#endif
}
void addScale(std::size_t width, std::size_t height)
{
#if 1
coords[0][0] /= width;
coords[0][1] /= width;
coords[0][2] /= width;
coords[1][0] /= height;
coords[1][1] /= height;
coords[1][2] /= height;
#endif
}
float coords[2][3];
};
class TextureProjection
{
public:
texdef_t m_texdef;
brushprimit_texdef_t m_brushprimit_texdef;
Vector3 m_basis_s;
Vector3 m_basis_t;
TextureProjection()
{
}
TextureProjection(
const texdef_t& texdef,
const brushprimit_texdef_t& brushprimit_texdef,
const Vector3& basis_s,
const Vector3& basis_t
) :
m_texdef(texdef),
m_brushprimit_texdef(brushprimit_texdef),
m_basis_s(basis_s),
m_basis_t(basis_t)
{
}
};
float Texdef_getDefaultTextureScale();
class texdef_t;
struct Winding;
template<typename Element> class BasicVector3;
typedef BasicVector3<float> Vector3;
template<typename Element> class BasicVector4;
typedef BasicVector4<float> Vector4;
typedef Vector4 Quaternion;
class Matrix4;
class Plane3;
void Normal_GetTransform(const Vector3& normal, Matrix4& transform);
void TexDef_Construct_Default(TextureProjection& projection);
void Texdef_Assign(TextureProjection& projection, const TextureProjection& other);
void Texdef_Shift(TextureProjection& projection, float s, float t);
void Texdef_Scale(TextureProjection& projection, float s, float t);
void Texdef_Rotate(TextureProjection& projection, float angle);
void Texdef_FitTexture(TextureProjection& projection, std::size_t width, std::size_t height, const Vector3& normal, const Winding& w, float s_repeat, float t_repeat);
void Texdef_EmitTextureCoordinates(const TextureProjection& projection, std::size_t width, std::size_t height, Winding& w, const Vector3& normal, const Matrix4& localToWorld);
void ShiftScaleRotate_fromFace(texdef_t& shiftScaleRotate, const TextureProjection& projection);
void ShiftScaleRotate_toFace(const texdef_t& shiftScaleRotate, TextureProjection& projection);
void Texdef_transformLocked(TextureProjection& projection, std::size_t width, std::size_t height, const Plane3& plane, const Matrix4& transform);
void Texdef_normalise(TextureProjection& projection, float width, float height);
enum TexdefTypeId
{
TEXDEFTYPEID_QUAKE,
TEXDEFTYPEID_BRUSHPRIMITIVES,
TEXDEFTYPEID_HALFLIFE,
};
struct bp_globals_t
{
// tells if we are internally using brush primitive (texture coordinates and map format)
// this is a shortcut for IntForKey( g_qeglobals.d_project_entity, "brush_primit" )
// NOTE: must keep the two ones in sync
TexdefTypeId m_texdefTypeId;
};
extern bp_globals_t g_bp_globals;
extern float g_texdef_default_scale;
#endif

1756
radiant/brushmanip.cpp Normal file

File diff suppressed because it is too large Load Diff

84
radiant/brushmanip.h Normal file
View File

@@ -0,0 +1,84 @@
/*
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
*/
#if !defined (INCLUDED_BRUSHWRAPPER_H)
#define INCLUDED_BRUSHWRAPPER_H
#include "string/string.h"
enum EBrushPrefab
{
eBrushCuboid,
eBrushPrism,
eBrushCone,
eBrushSphere,
};
class TextureProjection;
class ContentsFlagsValue;
namespace scene
{
class Graph;
}
void Scene_BrushConstructPrefab(scene::Graph& graph, EBrushPrefab type, std::size_t sides, const char* shader);
class AABB;
void Scene_BrushResize_Selected(scene::Graph& graph, const AABB& bounds, const char* shader);
void Scene_BrushSetTexdef_Selected(scene::Graph& graph, const TextureProjection& projection);
void Scene_BrushSetTexdef_Component_Selected(scene::Graph& graph, const TextureProjection& projection);
void Scene_BrushGetTexdef_Selected(scene::Graph& graph, TextureProjection& projection);
void Scene_BrushGetTexdef_Component_Selected(scene::Graph& graph, TextureProjection& projection);
void Scene_BrushSetFlags_Selected(scene::Graph& graph, const ContentsFlagsValue& flags);
void Scene_BrushSetFlags_Component_Selected(scene::Graph& graph, const ContentsFlagsValue& flags);
void Scene_BrushGetFlags_Selected(scene::Graph& graph, ContentsFlagsValue& flags);
void Scene_BrushGetFlags_Component_Selected(scene::Graph& graph, ContentsFlagsValue& flags);
void Scene_BrushShiftTexdef_Selected(scene::Graph& graph, float s, float t);
void Scene_BrushShiftTexdef_Component_Selected(scene::Graph& graph, float s, float t);
void Scene_BrushScaleTexdef_Selected(scene::Graph& graph, float s, float t);
void Scene_BrushScaleTexdef_Component_Selected(scene::Graph& graph, float s, float t);
void Scene_BrushRotateTexdef_Selected(scene::Graph& graph, float angle);
void Scene_BrushRotateTexdef_Component_Selected(scene::Graph& graph, float angle);
void Scene_BrushSetShader_Selected(scene::Graph& graph, const char* name);
void Scene_BrushSetShader_Component_Selected(scene::Graph& graph, const char* name);
void Scene_BrushGetShader_Selected(scene::Graph& graph, CopiedString& shader);
void Scene_BrushGetShader_Component_Selected(scene::Graph& graph, CopiedString& shader);
void Scene_BrushFindReplaceShader(scene::Graph& graph, const char* find, const char* replace);
void Scene_BrushFindReplaceShader_Selected(scene::Graph& graph, const char* find, const char* replace);
void Scene_BrushFindReplaceShader_Component_Selected(scene::Graph& graph, const char* find, const char* replace);
void Scene_BrushSelectByShader(scene::Graph& graph, const char* name);
void Scene_BrushSelectByShader_Component(scene::Graph& graph, const char* name);
void Scene_BrushFitTexture_Selected(scene::Graph& graph, float s_repeat, float t_repeat);
void Scene_BrushFitTexture_Component_Selected(scene::Graph& graph, float s_repeat, float t_repeat);
class Callback;
typedef struct _GtkMenu GtkMenu;
void Brush_constructMenu(GtkMenu* menu);
extern Callback g_texture_lock_status_changed;
void SelectedFaces_copyTexture();
void SelectedFaces_pasteTexture();
void FaceTextureClipboard_setDefault();
void BrushFilters_construct();
void Brush_registerCommands();
#endif

361
radiant/brushmodule.cpp Normal file
View File

@@ -0,0 +1,361 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#include "brushmodule.h"
#include "qerplugin.h"
#include "brushnode.h"
#include "brushmanip.h"
#include "preferencesystem.h"
#include "stringio.h"
#include "map.h"
#include "qe3.h"
#include "mainframe.h"
#include "preferences.h"
LatchedBool g_useAlternativeTextureProjection(false, "Use alternative texture-projection");
bool g_showAlternativeTextureProjectionOption = false;
bool getTextureLockEnabled()
{
return g_brush_texturelock_enabled;
}
void Face_importSnapPlanes(bool value)
{
Face::m_quantise = value ? quantiseInteger : quantiseFloating;
}
typedef FreeCaller1<bool, Face_importSnapPlanes> FaceImportSnapPlanesCaller;
void Face_exportSnapPlanes(const BoolImportCallback& importer)
{
importer(Face::m_quantise == quantiseInteger);
}
typedef FreeCaller1<const BoolImportCallback&, Face_exportSnapPlanes> FaceExportSnapPlanesCaller;
void Brush_constructPreferences(PreferencesPage& page)
{
page.appendCheckBox(
"", "Snap planes to integer grid",
FaceImportSnapPlanesCaller(),
FaceExportSnapPlanesCaller()
);
page.appendEntry(
"Default texture scale",
g_texdef_default_scale
);
if(g_showAlternativeTextureProjectionOption)
{
page.appendCheckBox(
"", "Use alternative texture-projection",
LatchedBoolImportCaller(g_useAlternativeTextureProjection),
BoolExportCaller(g_useAlternativeTextureProjection.m_latched)
);
}
}
void Brush_constructPage(PreferenceGroup& group)
{
PreferencesPage page(group.createPage("Brush", "Brush Settings"));
Brush_constructPreferences(page);
}
void Brush_registerPreferencesPage()
{
PreferencesDialog_addSettingsPage(FreeCaller1<PreferenceGroup&, Brush_constructPage>());
}
void Brush_Construct(EBrushType type)
{
if(type == eBrushTypeQuake3)
{
g_showAlternativeTextureProjectionOption = true;
GlobalPreferenceSystem().registerPreference(
"AlternativeTextureProjection",
BoolImportStringCaller(g_useAlternativeTextureProjection.m_latched),
BoolExportStringCaller(g_useAlternativeTextureProjection.m_latched)
);
g_useAlternativeTextureProjection.useLatched();
if(g_useAlternativeTextureProjection.m_value)
{
type = eBrushTypeQuake3BP;
}
}
Brush_registerCommands();
Brush_registerPreferencesPage();
BrushFilters_construct();
BrushClipPlane::constructStatic();
BrushInstance::constructStatic();
Brush::constructStatic(type);
Brush::m_maxWorldCoord = g_MaxWorldCoord;
BrushInstance::m_counter = &g_brushCount;
g_texdef_default_scale = 0.5f;
const char* value = g_pGameDescription->getKeyValue("default_scale");
if(!string_empty(value))
{
float scale = static_cast<float>(atof(value));
if(scale != 0)
{
g_texdef_default_scale = scale;
}
else
{
globalErrorStream() << "error parsing \"default_scale\" attribute\n";
}
}
FaceTextureClipboard_setDefault();
GlobalPreferenceSystem().registerPreference("TextureLock", BoolImportStringCaller(g_brush_texturelock_enabled), BoolExportStringCaller(g_brush_texturelock_enabled));
GlobalPreferenceSystem().registerPreference("BrushSnapPlanes", makeBoolStringImportCallback(FaceImportSnapPlanesCaller()), makeBoolStringExportCallback(FaceExportSnapPlanesCaller()));
GlobalPreferenceSystem().registerPreference("TexdefDefaultScale", FloatImportStringCaller(g_texdef_default_scale), FloatExportStringCaller(g_texdef_default_scale));
GridStatus_getTextureLockEnabled = getTextureLockEnabled;
g_texture_lock_status_changed = FreeCaller<GridStatus_onTextureLockEnabledChanged>();
}
void Brush_Destroy()
{
Brush::m_maxWorldCoord = 0;
BrushInstance::m_counter = 0;
Brush::destroyStatic();
BrushInstance::destroyStatic();
BrushClipPlane::destroyStatic();
}
void Brush_clipperColourChanged()
{
BrushClipPlane::destroyStatic();
BrushClipPlane::constructStatic();
}
class Quake3BrushCreator : public BrushCreator
{
public:
scene::Node& createBrush()
{
return (new BrushNode)->node();
}
bool useAlternativeTextureProjection() const
{
return g_useAlternativeTextureProjection.m_value;
}
};
Quake3BrushCreator g_Quake3BrushCreator;
BrushCreator& GetBrushCreator()
{
return g_Quake3BrushCreator;
}
#include "modulesystem/singletonmodule.h"
#include "modulesystem/moduleregistry.h"
class BrushDependencies :
public GlobalRadiantModuleRef,
public GlobalSceneGraphModuleRef,
public GlobalShaderCacheModuleRef,
public GlobalSelectionModuleRef,
public GlobalOpenGLModuleRef,
public GlobalUndoModuleRef,
public GlobalFilterModuleRef
{
};
class BrushDoom3API : public TypeSystemRef
{
BrushCreator* m_brushdoom3;
public:
typedef BrushCreator Type;
STRING_CONSTANT(Name, "doom3");
BrushDoom3API()
{
Brush_Construct(eBrushTypeDoom3);
m_brushdoom3 = &GetBrushCreator();
}
~BrushDoom3API()
{
Brush_Destroy();
}
BrushCreator* getTable()
{
return m_brushdoom3;
}
};
typedef SingletonModule<BrushDoom3API, BrushDependencies> BrushDoom3Module;
typedef Static<BrushDoom3Module> StaticBrushDoom3Module;
StaticRegisterModule staticRegisterBrushDoom3(StaticBrushDoom3Module::instance());
class BrushQuake4API : public TypeSystemRef
{
BrushCreator* m_brushquake4;
public:
typedef BrushCreator Type;
STRING_CONSTANT(Name, "quake4");
BrushQuake4API()
{
Brush_Construct(eBrushTypeQuake4);
m_brushquake4 = &GetBrushCreator();
}
~BrushQuake4API()
{
Brush_Destroy();
}
BrushCreator* getTable()
{
return m_brushquake4;
}
};
typedef SingletonModule<BrushQuake4API, BrushDependencies> BrushQuake4Module;
typedef Static<BrushQuake4Module> StaticBrushQuake4Module;
StaticRegisterModule staticRegisterBrushQuake4(StaticBrushQuake4Module::instance());
class BrushQuake3API : public TypeSystemRef
{
BrushCreator* m_brushquake3;
public:
typedef BrushCreator Type;
STRING_CONSTANT(Name, "quake3");
BrushQuake3API()
{
Brush_Construct(eBrushTypeQuake3);
m_brushquake3 = &GetBrushCreator();
}
~BrushQuake3API()
{
Brush_Destroy();
}
BrushCreator* getTable()
{
return m_brushquake3;
}
};
typedef SingletonModule<BrushQuake3API, BrushDependencies> BrushQuake3Module;
typedef Static<BrushQuake3Module> StaticBrushQuake3Module;
StaticRegisterModule staticRegisterBrushQuake3(StaticBrushQuake3Module::instance());
class BrushQuake2API : public TypeSystemRef
{
BrushCreator* m_brushquake2;
public:
typedef BrushCreator Type;
STRING_CONSTANT(Name, "quake2");
BrushQuake2API()
{
Brush_Construct(eBrushTypeQuake2);
m_brushquake2 = &GetBrushCreator();
}
~BrushQuake2API()
{
Brush_Destroy();
}
BrushCreator* getTable()
{
return m_brushquake2;
}
};
typedef SingletonModule<BrushQuake2API, BrushDependencies> BrushQuake2Module;
typedef Static<BrushQuake2Module> StaticBrushQuake2Module;
StaticRegisterModule staticRegisterBrushQuake2(StaticBrushQuake2Module::instance());
class BrushQuake1API : public TypeSystemRef
{
BrushCreator* m_brushquake1;
public:
typedef BrushCreator Type;
STRING_CONSTANT(Name, "quake");
BrushQuake1API()
{
Brush_Construct(eBrushTypeQuake);
m_brushquake1 = &GetBrushCreator();
}
~BrushQuake1API()
{
Brush_Destroy();
}
BrushCreator* getTable()
{
return m_brushquake1;
}
};
typedef SingletonModule<BrushQuake1API, BrushDependencies> BrushQuake1Module;
typedef Static<BrushQuake1Module> StaticBrushQuake1Module;
StaticRegisterModule staticRegisterBrushQuake1(StaticBrushQuake1Module::instance());
class BrushHalfLifeAPI : public TypeSystemRef
{
BrushCreator* m_brushhalflife;
public:
typedef BrushCreator Type;
STRING_CONSTANT(Name, "halflife");
BrushHalfLifeAPI()
{
Brush_Construct(eBrushTypeHalfLife);
m_brushhalflife = &GetBrushCreator();
}
~BrushHalfLifeAPI()
{
Brush_Destroy();
}
BrushCreator* getTable()
{
return m_brushhalflife;
}
};
typedef SingletonModule<BrushHalfLifeAPI, BrushDependencies> BrushHalfLifeModule;
typedef Static<BrushHalfLifeModule> StaticBrushHalfLifeModule;
StaticRegisterModule staticRegisterBrushHalfLife(StaticBrushHalfLifeModule::instance());

27
radiant/brushmodule.h Normal file
View File

@@ -0,0 +1,27 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#if !defined(INCLUDED_BRUSHMODULE_H)
#define INCLUDED_BRUSHMODULE_H
void Brush_clipperColourChanged();
#endif

23
radiant/brushnode.cpp Normal file
View File

@@ -0,0 +1,23 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#include "brushnode.h"

167
radiant/brushnode.h Normal file
View File

@@ -0,0 +1,167 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#if !defined(INCLUDED_BRUSHNODE_H)
#define INCLUDED_BRUSHNODE_H
#include "instancelib.h"
#include "brush.h"
#include "brushtokens.h"
#include "brushxml.h"
class BrushNode :
public scene::Node::Symbiot,
public scene::Instantiable,
public scene::Cloneable
{
class TypeCasts
{
NodeTypeCastTable m_casts;
public:
TypeCasts()
{
NodeStaticCast<BrushNode, scene::Instantiable>::install(m_casts);
NodeStaticCast<BrushNode, scene::Cloneable>::install(m_casts);
NodeContainedCast<BrushNode, Snappable>::install(m_casts);
NodeContainedCast<BrushNode, TransformNode>::install(m_casts);
NodeContainedCast<BrushNode, Brush>::install(m_casts);
NodeContainedCast<BrushNode, XMLImporter>::install(m_casts);
NodeContainedCast<BrushNode, XMLExporter>::install(m_casts);
NodeContainedCast<BrushNode, MapImporter>::install(m_casts);
NodeContainedCast<BrushNode, MapExporter>::install(m_casts);
NodeContainedCast<BrushNode, Nameable>::install(m_casts);
NodeContainedCast<BrushNode, BrushDoom3>::install(m_casts);
}
NodeTypeCastTable& get()
{
return m_casts;
}
};
scene::Node m_node;
InstanceSet m_instances;
Brush m_brush;
BrushTokenImporter m_mapImporter;
BrushTokenExporter m_mapExporter;
BrushXMLImporter m_xmlImporter;
BrushXMLExporter m_xmlExporter;
public:
typedef LazyStatic<TypeCasts> StaticTypeCasts;
Snappable& get(NullType<Snappable>)
{
return m_brush;
}
TransformNode& get(NullType<TransformNode>)
{
return m_brush;
}
Brush& get(NullType<Brush>)
{
return m_brush;
}
XMLImporter& get(NullType<XMLImporter>)
{
return m_xmlImporter;
}
XMLExporter& get(NullType<XMLExporter>)
{
return m_xmlExporter;
}
MapImporter& get(NullType<MapImporter>)
{
return m_mapImporter;
}
MapExporter& get(NullType<MapExporter>)
{
return m_mapExporter;
}
Nameable& get(NullType<Nameable>)
{
return m_brush;
}
BrushDoom3& get(NullType<BrushDoom3>)
{
return m_brush;
}
BrushNode() :
m_node(this, this, StaticTypeCasts::instance().get()),
m_brush(m_node, InstanceSetEvaluateTransform<BrushInstance>::Caller(m_instances), InstanceSet::BoundsChangedCaller(m_instances)),
m_mapImporter(m_brush),
m_mapExporter(m_brush),
m_xmlImporter(m_brush),
m_xmlExporter(m_brush)
{
}
BrushNode(const BrushNode& other) :
scene::Node::Symbiot(other),
scene::Instantiable(other),
scene::Cloneable(other),
m_node(this, this, StaticTypeCasts::instance().get()),
m_brush(other.m_brush, m_node, InstanceSetEvaluateTransform<BrushInstance>::Caller(m_instances), InstanceSet::BoundsChangedCaller(m_instances)),
m_mapImporter(m_brush),
m_mapExporter(m_brush),
m_xmlImporter(m_brush),
m_xmlExporter(m_brush)
{
}
void release()
{
delete this;
}
scene::Node& node()
{
return m_node;
}
scene::Node& clone() const
{
return (new BrushNode(*this))->node();
}
scene::Instance* create(const scene::Path& path, scene::Instance* parent)
{
return new BrushInstance(path, parent, m_brush);
}
void forEachInstance(const scene::Instantiable::Visitor& visitor)
{
m_instances.forEachInstance(visitor);
}
void insert(scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance)
{
m_instances.insert(observer, path, instance);
}
scene::Instance* erase(scene::Instantiable::Observer* observer, const scene::Path& path)
{
return m_instances.erase(observer, path);
}
};
inline Brush* Node_getBrush(scene::Node& node)
{
return NodeTypeCast<Brush>::cast(node);
}
#endif

23
radiant/brushtokens.cpp Normal file
View File

@@ -0,0 +1,23 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#include "brushtokens.h"

738
radiant/brushtokens.h Normal file
View File

@@ -0,0 +1,738 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#if !defined(INCLUDED_BRUSHTOKENS_H)
#define INCLUDED_BRUSHTOKENS_H
#include "stringio.h"
#include "stream/stringstream.h"
#include "brush.h"
inline bool FaceShader_importContentsFlagsValue(FaceShader& faceShader, Tokeniser& tokeniser)
{
// parse the optional contents/flags/value
RETURN_FALSE_IF_FAIL(Tokeniser_getInteger(tokeniser, faceShader.m_flags.m_contentFlags));
RETURN_FALSE_IF_FAIL(Tokeniser_getInteger(tokeniser, faceShader.m_flags.m_surfaceFlags));
RETURN_FALSE_IF_FAIL(Tokeniser_getInteger(tokeniser, faceShader.m_flags.m_value));
return true;
}
inline bool FaceTexdef_importTokens(FaceTexdef& texdef, Tokeniser& tokeniser)
{
// parse texdef
RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_texdef.shift[0]));
RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_texdef.shift[1]));
RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_texdef.rotate));
RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_texdef.scale[0]));
RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_texdef.scale[1]));
ASSERT_MESSAGE(texdef_sane(texdef.m_projection.m_texdef), "FaceTexdef_importTokens: bad texdef");
return true;
}
inline bool FaceTexdef_BP_importTokens(FaceTexdef& texdef, Tokeniser& tokeniser)
{
// parse alternate texdef
RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
{
RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_brushprimit_texdef.coords[0][0]));
RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_brushprimit_texdef.coords[0][1]));
RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_brushprimit_texdef.coords[0][2]));
RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
}
{
RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_brushprimit_texdef.coords[1][0]));
RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_brushprimit_texdef.coords[1][1]));
RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_brushprimit_texdef.coords[1][2]));
RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
}
RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
return true;
}
inline bool FaceTexdef_HalfLife_importTokens(FaceTexdef& texdef, Tokeniser& tokeniser)
{
// parse texdef
RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "["));
RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_basis_s.x()));
RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_basis_s.y()));
RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_basis_s.z()));
RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_texdef.shift[0]));
RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "]"));
RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "["));
RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_basis_t.x()));
RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_basis_t.y()));
RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_basis_t.z()));
RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_texdef.shift[1]));
RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "]"));
RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_texdef.rotate));
RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_texdef.scale[0]));
RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, texdef.m_projection.m_texdef.scale[1]));
texdef.m_projection.m_texdef.rotate = -texdef.m_projection.m_texdef.rotate;
ASSERT_MESSAGE(texdef_sane(texdef.m_projection.m_texdef), "FaceTexdef_importTokens: bad texdef");
return true;
}
inline bool FacePlane_importTokens(FacePlane& facePlane, Tokeniser& tokeniser)
{
// parse planepts
for(std::size_t i = 0; i<3; i++)
{
RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
for(std::size_t j = 0; j < 3; ++j)
{
RETURN_FALSE_IF_FAIL(Tokeniser_getDouble(tokeniser, facePlane.planePoints()[i][j]));
}
RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
}
facePlane.MakePlane();
return true;
}
inline bool FacePlane_Doom3_importTokens(FacePlane& facePlane, Tokeniser& tokeniser)
{
Plane3 plane;
// parse plane equation
RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
RETURN_FALSE_IF_FAIL(Tokeniser_getDouble(tokeniser, plane.a));
RETURN_FALSE_IF_FAIL(Tokeniser_getDouble(tokeniser, plane.b));
RETURN_FALSE_IF_FAIL(Tokeniser_getDouble(tokeniser, plane.c));
RETURN_FALSE_IF_FAIL(Tokeniser_getDouble(tokeniser, plane.d));
plane.d = -plane.d;
RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
facePlane.setDoom3Plane(plane);
return true;
}
inline bool FaceShader_Doom3_importTokens(FaceShader& faceShader, Tokeniser& tokeniser)
{
const char *shader = tokeniser.getToken();
if(shader == 0)
{
Tokeniser_unexpectedError(tokeniser, shader, "#shader-name");
return false;
}
if(string_equal(shader, "_emptyname"))
{
shader = texdef_name_default();
}
faceShader.setShader(shader);
return true;
}
inline bool FaceShader_importTokens(FaceShader& faceShader, Tokeniser& tokeniser)
{
const char* texture = tokeniser.getToken();
if(texture == 0)
{
Tokeniser_unexpectedError(tokeniser, texture, "#texture-name");
return false;
}
if(string_equal(texture, "NULL"))
{
faceShader.setShader(texdef_name_default());
}
else
{
StringOutputStream shader(string_length(GlobalTexturePrefix_get()) + string_length(texture));
shader << GlobalTexturePrefix_get() << texture;
faceShader.setShader(shader.c_str());
}
return true;
}
class Doom3FaceTokenImporter
{
Face& m_face;
public:
Doom3FaceTokenImporter(Face& face) : m_face(face)
{
}
bool importTokens(Tokeniser& tokeniser)
{
RETURN_FALSE_IF_FAIL(FacePlane_Doom3_importTokens(m_face.getPlane(), tokeniser));
RETURN_FALSE_IF_FAIL(FaceTexdef_BP_importTokens(m_face.getTexdef(), tokeniser));
RETURN_FALSE_IF_FAIL(FaceShader_Doom3_importTokens(m_face.getShader(), tokeniser));
RETURN_FALSE_IF_FAIL(FaceShader_importContentsFlagsValue(m_face.getShader(), tokeniser));
m_face.getTexdef().m_projectionInitialised = true;
m_face.getTexdef().m_scaleApplied = true;
return true;
}
};
class Quake4FaceTokenImporter
{
Face& m_face;
public:
Quake4FaceTokenImporter(Face& face) : m_face(face)
{
}
bool importTokens(Tokeniser& tokeniser)
{
RETURN_FALSE_IF_FAIL(FacePlane_Doom3_importTokens(m_face.getPlane(), tokeniser));
RETURN_FALSE_IF_FAIL(FaceTexdef_BP_importTokens(m_face.getTexdef(), tokeniser));
RETURN_FALSE_IF_FAIL(FaceShader_Doom3_importTokens(m_face.getShader(), tokeniser));
m_face.getTexdef().m_projectionInitialised = true;
m_face.getTexdef().m_scaleApplied = true;
return true;
}
};
class Quake2FaceTokenImporter
{
Face& m_face;
public:
Quake2FaceTokenImporter(Face& face) : m_face(face)
{
}
bool importTokens(Tokeniser& tokeniser)
{
RETURN_FALSE_IF_FAIL(FacePlane_importTokens(m_face.getPlane(), tokeniser));
RETURN_FALSE_IF_FAIL(FaceShader_importTokens(m_face.getShader(), tokeniser));
RETURN_FALSE_IF_FAIL(FaceTexdef_importTokens(m_face.getTexdef(), tokeniser));
if(Tokeniser_nextTokenIsDigit(tokeniser))
{
m_face.getShader().m_flags.m_specified = true;
RETURN_FALSE_IF_FAIL(FaceShader_importContentsFlagsValue(m_face.getShader(), tokeniser));
}
m_face.getTexdef().m_scaleApplied = true;
return true;
}
};
class Quake3FaceTokenImporter
{
Face& m_face;
public:
Quake3FaceTokenImporter(Face& face) : m_face(face)
{
}
bool importTokens(Tokeniser& tokeniser)
{
RETURN_FALSE_IF_FAIL(FacePlane_importTokens(m_face.getPlane(), tokeniser));
RETURN_FALSE_IF_FAIL(FaceShader_importTokens(m_face.getShader(), tokeniser));
RETURN_FALSE_IF_FAIL(FaceTexdef_importTokens(m_face.getTexdef(), tokeniser));
RETURN_FALSE_IF_FAIL(FaceShader_importContentsFlagsValue(m_face.getShader(), tokeniser));
m_face.getTexdef().m_scaleApplied = true;
return true;
}
};
class Quake3BPFaceTokenImporter
{
Face& m_face;
public:
Quake3BPFaceTokenImporter(Face& face) : m_face(face)
{
}
bool importTokens(Tokeniser& tokeniser)
{
RETURN_FALSE_IF_FAIL(FacePlane_importTokens(m_face.getPlane(), tokeniser));
RETURN_FALSE_IF_FAIL(FaceTexdef_BP_importTokens(m_face.getTexdef(), tokeniser));
RETURN_FALSE_IF_FAIL(FaceShader_importTokens(m_face.getShader(), tokeniser));
RETURN_FALSE_IF_FAIL(FaceShader_importContentsFlagsValue(m_face.getShader(), tokeniser));
m_face.getTexdef().m_projectionInitialised = true;
m_face.getTexdef().m_scaleApplied = true;
return true;
}
};
class QuakeFaceTokenImporter
{
Face& m_face;
public:
QuakeFaceTokenImporter(Face& face) : m_face(face)
{
}
bool importTokens(Tokeniser& tokeniser)
{
RETURN_FALSE_IF_FAIL(FacePlane_importTokens(m_face.getPlane(), tokeniser));
RETURN_FALSE_IF_FAIL(FaceShader_importTokens(m_face.getShader(), tokeniser));
RETURN_FALSE_IF_FAIL(FaceTexdef_importTokens(m_face.getTexdef(), tokeniser));
m_face.getTexdef().m_scaleApplied = true;
return true;
}
};
class HalfLifeFaceTokenImporter
{
Face& m_face;
public:
HalfLifeFaceTokenImporter(Face& face) : m_face(face)
{
}
bool importTokens(Tokeniser& tokeniser)
{
RETURN_FALSE_IF_FAIL(FacePlane_importTokens(m_face.getPlane(), tokeniser));
RETURN_FALSE_IF_FAIL(FaceShader_importTokens(m_face.getShader(), tokeniser));
RETURN_FALSE_IF_FAIL(FaceTexdef_HalfLife_importTokens(m_face.getTexdef(), tokeniser));
m_face.getTexdef().m_scaleApplied = true;
return true;
}
};
inline void FacePlane_Doom3_exportTokens(const FacePlane& facePlane, TokenWriter& writer)
{
// write plane equation
writer.writeToken("(");
writer.writeFloat(facePlane.getDoom3Plane().a);
writer.writeFloat(facePlane.getDoom3Plane().b);
writer.writeFloat(facePlane.getDoom3Plane().c);
writer.writeFloat(-facePlane.getDoom3Plane().d);
writer.writeToken(")");
}
inline void FacePlane_exportTokens(const FacePlane& facePlane, TokenWriter& writer)
{
// write planepts
for(std::size_t i=0; i<3; i++)
{
writer.writeToken("(");
for(std::size_t j=0; j<3; j++)
{
writer.writeFloat(Face::m_quantise(facePlane.planePoints()[i][j]));
}
writer.writeToken(")");
}
}
inline void FaceTexdef_BP_exportTokens(const FaceTexdef& faceTexdef, TokenWriter& writer)
{
// write alternate texdef
writer.writeToken("(");
{
writer.writeToken("(");
for(std::size_t i=0;i<3;i++)
{
writer.writeFloat(faceTexdef.m_projection.m_brushprimit_texdef.coords[0][i]);
}
writer.writeToken(")");
}
{
writer.writeToken("(");
for(std::size_t i=0;i<3;i++)
{
writer.writeFloat(faceTexdef.m_projection.m_brushprimit_texdef.coords[1][i]);
}
writer.writeToken(")");
}
writer.writeToken(")");
}
inline void FaceTexdef_exportTokens(const FaceTexdef& faceTexdef, TokenWriter& writer)
{
ASSERT_MESSAGE(texdef_sane(faceTexdef.m_projection.m_texdef), "FaceTexdef_exportTokens: bad texdef");
// write texdef
writer.writeFloat(faceTexdef.m_projection.m_texdef.shift[0]);
writer.writeFloat(faceTexdef.m_projection.m_texdef.shift[1]);
writer.writeFloat(faceTexdef.m_projection.m_texdef.rotate);
writer.writeFloat(faceTexdef.m_projection.m_texdef.scale[0]);
writer.writeFloat(faceTexdef.m_projection.m_texdef.scale[1]);
}
inline void FaceTexdef_HalfLife_exportTokens(const FaceTexdef& faceTexdef, TokenWriter& writer)
{
ASSERT_MESSAGE(texdef_sane(faceTexdef.m_projection.m_texdef), "FaceTexdef_exportTokens: bad texdef");
// write texdef
writer.writeToken("[");
writer.writeFloat(faceTexdef.m_projection.m_basis_s.x());
writer.writeFloat(faceTexdef.m_projection.m_basis_s.y());
writer.writeFloat(faceTexdef.m_projection.m_basis_s.z());
writer.writeFloat(faceTexdef.m_projection.m_texdef.shift[0]);
writer.writeToken("]");
writer.writeToken("[");
writer.writeFloat(faceTexdef.m_projection.m_basis_t.x());
writer.writeFloat(faceTexdef.m_projection.m_basis_t.y());
writer.writeFloat(faceTexdef.m_projection.m_basis_t.z());
writer.writeFloat(faceTexdef.m_projection.m_texdef.shift[1]);
writer.writeToken("]");
writer.writeFloat(-faceTexdef.m_projection.m_texdef.rotate);
writer.writeFloat(faceTexdef.m_projection.m_texdef.scale[0]);
writer.writeFloat(faceTexdef.m_projection.m_texdef.scale[1]);
}
inline void FaceShader_ContentsFlagsValue_exportTokens(const FaceShader& faceShader, TokenWriter& writer)
{
// write surface flags
writer.writeInteger(faceShader.m_flags.m_contentFlags);
writer.writeInteger(faceShader.m_flags.m_surfaceFlags);
writer.writeInteger(faceShader.m_flags.m_value);
}
inline void FaceShader_exportTokens(const FaceShader& faceShader, TokenWriter& writer)
{
// write shader name
if(string_empty(shader_get_textureName(faceShader.getShader())))
{
writer.writeToken("NULL");
}
else
{
writer.writeToken(shader_get_textureName(faceShader.getShader()));
}
}
inline void FaceShader_Doom3_exportTokens(const FaceShader& faceShader, TokenWriter& writer)
{
// write shader name
if(string_empty(shader_get_textureName(faceShader.getShader())))
{
writer.writeString("_emptyname");
}
else
{
writer.writeString(faceShader.getShader());
}
}
class Doom3FaceTokenExporter
{
const Face& m_face;
public:
Doom3FaceTokenExporter(const Face& face) : m_face(face)
{
}
void exportTokens(TokenWriter& writer) const
{
FacePlane_Doom3_exportTokens(m_face.getPlane(), writer);
FaceTexdef_BP_exportTokens(m_face.getTexdef(), writer);
FaceShader_Doom3_exportTokens(m_face.getShader(), writer);
FaceShader_ContentsFlagsValue_exportTokens(m_face.getShader(), writer);
writer.nextLine();
}
};
class Quake4FaceTokenExporter
{
const Face& m_face;
public:
Quake4FaceTokenExporter(const Face& face) : m_face(face)
{
}
void exportTokens(TokenWriter& writer) const
{
FacePlane_Doom3_exportTokens(m_face.getPlane(), writer);
FaceTexdef_BP_exportTokens(m_face.getTexdef(), writer);
FaceShader_Doom3_exportTokens(m_face.getShader(), writer);
writer.nextLine();
}
};
class Quake2FaceTokenExporter
{
const Face& m_face;
public:
Quake2FaceTokenExporter(const Face& face) : m_face(face)
{
}
void exportTokens(TokenWriter& writer) const
{
FacePlane_exportTokens(m_face.getPlane(), writer);
FaceShader_exportTokens(m_face.getShader(), writer);
FaceTexdef_exportTokens(m_face.getTexdef(), writer);
if(m_face.getShader().m_flags.m_specified || m_face.isDetail())
{
FaceShader_ContentsFlagsValue_exportTokens(m_face.getShader(), writer);
}
writer.nextLine();
}
};
class Quake3FaceTokenExporter
{
const Face& m_face;
public:
Quake3FaceTokenExporter(const Face& face) : m_face(face)
{
}
void exportTokens(TokenWriter& writer) const
{
FacePlane_exportTokens(m_face.getPlane(), writer);
FaceShader_exportTokens(m_face.getShader(), writer);
FaceTexdef_exportTokens(m_face.getTexdef(), writer);
FaceShader_ContentsFlagsValue_exportTokens(m_face.getShader(), writer);
writer.nextLine();
}
};
class Quake3BPFaceTokenExporter
{
const Face& m_face;
public:
Quake3BPFaceTokenExporter(const Face& face) : m_face(face)
{
}
void exportTokens(TokenWriter& writer) const
{
FacePlane_exportTokens(m_face.getPlane(), writer);
FaceTexdef_BP_exportTokens(m_face.getTexdef(), writer);
FaceShader_exportTokens(m_face.getShader(), writer);
FaceShader_ContentsFlagsValue_exportTokens(m_face.getShader(), writer);
writer.nextLine();
}
};
class QuakeFaceTokenExporter
{
const Face& m_face;
public:
QuakeFaceTokenExporter(const Face& face) : m_face(face)
{
}
void exportTokens(TokenWriter& writer) const
{
FacePlane_exportTokens(m_face.getPlane(), writer);
FaceShader_exportTokens(m_face.getShader(), writer);
FaceTexdef_exportTokens(m_face.getTexdef(), writer);
writer.nextLine();
}
};
class HalfLifeFaceTokenExporter
{
const Face& m_face;
public:
HalfLifeFaceTokenExporter(const Face& face) : m_face(face)
{
}
void exportTokens(TokenWriter& writer) const
{
FacePlane_exportTokens(m_face.getPlane(), writer);
FaceShader_exportTokens(m_face.getShader(), writer);
FaceTexdef_HalfLife_exportTokens(m_face.getTexdef(), writer);
writer.nextLine();
}
};
class BrushTokenImporter : public MapImporter
{
Brush& m_brush;
public:
BrushTokenImporter(Brush& brush) : m_brush(brush)
{
}
bool importTokens(Tokeniser& tokeniser)
{
if(Brush::m_type == eBrushTypeQuake3BP || Brush::m_type == eBrushTypeDoom3 || Brush::m_type == eBrushTypeQuake4)
{
tokeniser.nextLine();
RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "{"));
}
while(1)
{
// check for end of brush
tokeniser.nextLine();
const char* token = tokeniser.getToken();
if(string_equal(token, "}"))
{
break;
}
tokeniser.ungetToken();
m_brush.push_back(FaceSmartPointer(new Face(&m_brush)));
//!todo BP support
tokeniser.nextLine();
Face& face = *m_brush.back();
switch(Brush::m_type)
{
case eBrushTypeDoom3:
{
Doom3FaceTokenImporter importer(face);
RETURN_FALSE_IF_FAIL(importer.importTokens(tokeniser));
}
break;
case eBrushTypeQuake4:
{
Quake4FaceTokenImporter importer(face);
RETURN_FALSE_IF_FAIL(importer.importTokens(tokeniser));
}
break;
case eBrushTypeQuake2:
{
Quake2FaceTokenImporter importer(face);
RETURN_FALSE_IF_FAIL(importer.importTokens(tokeniser));
}
break;
case eBrushTypeQuake3:
{
Quake3FaceTokenImporter importer(face);
RETURN_FALSE_IF_FAIL(importer.importTokens(tokeniser));
}
break;
case eBrushTypeQuake3BP:
{
Quake3BPFaceTokenImporter importer(face);
RETURN_FALSE_IF_FAIL(importer.importTokens(tokeniser));
}
break;
case eBrushTypeQuake:
{
QuakeFaceTokenImporter importer(face);
RETURN_FALSE_IF_FAIL(importer.importTokens(tokeniser));
}
break;
case eBrushTypeHalfLife:
{
HalfLifeFaceTokenImporter importer(face);
RETURN_FALSE_IF_FAIL(importer.importTokens(tokeniser));
}
break;
}
face.planeChanged();
}
if(Brush::m_type == eBrushTypeQuake3BP || Brush::m_type == eBrushTypeDoom3 || Brush::m_type == eBrushTypeQuake4)
{
tokeniser.nextLine();
RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "}"));
}
m_brush.planeChanged();
m_brush.shaderChanged();
return true;
}
};
class BrushTokenExporter : public MapExporter
{
const Brush& m_brush;
public:
BrushTokenExporter(const Brush& brush) : m_brush(brush)
{
}
void exportTokens(TokenWriter& writer) const
{
m_brush.evaluateBRep(); // ensure b-rep is up-to-date, so that non-contributing faces can be identified.
if(!m_brush.hasContributingFaces())
{
return;
}
writer.writeToken("{");
writer.nextLine();
if(Brush::m_type == eBrushTypeQuake3BP)
{
writer.writeToken("brushDef");
writer.nextLine();
writer.writeToken("{");
writer.nextLine();
}
if(Brush::m_type == eBrushTypeDoom3 || Brush::m_type == eBrushTypeQuake4)
{
writer.writeToken("brushDef3");
writer.nextLine();
writer.writeToken("{");
writer.nextLine();
}
for(Brush::const_iterator i = m_brush.begin(); i != m_brush.end(); ++i)
{
const Face& face = *(*i);
if(face.contributes())
{
switch(Brush::m_type)
{
case eBrushTypeDoom3:
{
Doom3FaceTokenExporter exporter(face);
exporter.exportTokens(writer);
}
break;
case eBrushTypeQuake4:
{
Quake4FaceTokenExporter exporter(face);
exporter.exportTokens(writer);
}
break;
case eBrushTypeQuake2:
{
Quake2FaceTokenExporter exporter(face);
exporter.exportTokens(writer);
}
break;
case eBrushTypeQuake3:
{
Quake3FaceTokenExporter exporter(face);
exporter.exportTokens(writer);
}
break;
case eBrushTypeQuake3BP:
{
Quake3BPFaceTokenExporter exporter(face);
exporter.exportTokens(writer);
}
break;
case eBrushTypeQuake:
{
QuakeFaceTokenExporter exporter(face);
exporter.exportTokens(writer);
}
break;
case eBrushTypeHalfLife:
{
HalfLifeFaceTokenExporter exporter(face);
exporter.exportTokens(writer);
}
break;
}
}
}
if(Brush::m_type == eBrushTypeQuake3BP || Brush::m_type == eBrushTypeDoom3 || Brush::m_type == eBrushTypeQuake4)
{
writer.writeToken("}");
writer.nextLine();
}
writer.writeToken("}");
writer.nextLine();
}
};
#endif

23
radiant/brushxml.cpp Normal file
View File

@@ -0,0 +1,23 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#include "brushxml.h"

413
radiant/brushxml.h Normal file
View File

@@ -0,0 +1,413 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#if !defined(INCLUDED_BRUSHXML_H)
#define INCLUDED_BRUSHXML_H
#include "stream/stringstream.h"
#include "xml/xmlelement.h"
#include "brush.h"
inline void FaceTexdef_BP_importXML(FaceTexdef& texdef, const char* xmlContent)
{
StringTokeniser content(xmlContent);
texdef.m_projection.m_brushprimit_texdef.coords[0][0] = static_cast<float>(atof(content.getToken()));
texdef.m_projection.m_brushprimit_texdef.coords[0][1] = static_cast<float>(atof(content.getToken()));
texdef.m_projection.m_brushprimit_texdef.coords[0][2] = static_cast<float>(atof(content.getToken()));
texdef.m_projection.m_brushprimit_texdef.coords[1][0] = static_cast<float>(atof(content.getToken()));
texdef.m_projection.m_brushprimit_texdef.coords[1][1] = static_cast<float>(atof(content.getToken()));
texdef.m_projection.m_brushprimit_texdef.coords[1][2] = static_cast<float>(atof(content.getToken()));
}
inline void FaceTexdef_importXML(FaceTexdef& texdef, const char* xmlContent)
{
StringTokeniser content(xmlContent);
texdef.m_projection.m_texdef.shift[0] = static_cast<float>(atof(content.getToken()));
texdef.m_projection.m_texdef.shift[1] = static_cast<float>(atof(content.getToken()));
texdef.m_projection.m_texdef.rotate = static_cast<float>(atof(content.getToken()));
texdef.m_projection.m_texdef.scale[0] = static_cast<float>(atof(content.getToken()));
texdef.m_projection.m_texdef.scale[1] = static_cast<float>(atof(content.getToken()));
ASSERT_MESSAGE(texdef_sane(texdef.m_projection.m_texdef), "FaceTexdef_importXML: bad texdef");
}
inline void FacePlane_importXML(FacePlane& facePlane, const char* xmlContent)
{
StringTokeniser content(xmlContent);
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 3; ++j)
{
facePlane.planePoints()[i][j] = atof(content.getToken());
}
}
facePlane.MakePlane();
}
class FaceXMLImporter
{
struct xml_state_t
{
enum EState
{
eDefault,
ePlanePts,
eTexdef,
eBPMatrix,
eFlags,
eShader,
};
EState m_state;
StringOutputStream m_content;
xml_state_t(EState state)
: m_state(state)
{}
EState state() const
{
return m_state;
}
const char* content() const
{
return m_content.c_str();
}
std::size_t write(const char* buffer, std::size_t length)
{
return m_content.write(buffer, length);
}
};
std::vector<xml_state_t> m_xml_state;
Face& m_face;
public:
FaceXMLImporter(Face& face) : m_face(face)
{
m_xml_state.push_back(xml_state_t::eDefault);
}
~FaceXMLImporter()
{
m_face.planeChanged();
}
void pushElement(const XMLElement& element)
{
ASSERT_MESSAGE(m_xml_state.back().state() == xml_state_t::eDefault, "parse error");
if(strcmp(element.name(), "planepts") == 0)
{
m_xml_state.push_back(xml_state_t::ePlanePts);
}
else if(strcmp(element.name(), "texdef") == 0)
{
m_xml_state.push_back(xml_state_t::eTexdef);
}
else if(strcmp(element.name(), "bpmatrix") == 0)
{
m_xml_state.push_back(xml_state_t::eBPMatrix);
}
else if(strcmp(element.name(), "flags") == 0)
{
m_xml_state.push_back(xml_state_t::eFlags);
}
else if(strcmp(element.name(), "shader") == 0)
{
m_xml_state.push_back(xml_state_t::eShader);
}
}
void popElement(const char* name)
{
ASSERT_MESSAGE(m_xml_state.back().state() != xml_state_t::eDefault, "parse error");
switch(m_xml_state.back().state())
{
case xml_state_t::ePlanePts:
{
FacePlane_importXML(m_face.getPlane(), m_xml_state.back().content());
}
break;
case xml_state_t::eTexdef:
{
FaceTexdef_importXML(m_face.getTexdef(), m_xml_state.back().content());
}
break;
case xml_state_t::eBPMatrix:
{
FaceTexdef_BP_importXML(m_face.getTexdef(), m_xml_state.back().content());
}
break;
case xml_state_t::eFlags:
{
StringTokeniser content(m_xml_state.back().content());
m_face.getShader().m_flags.m_contentFlags = atoi(content.getToken());
m_face.getShader().m_flags.m_surfaceFlags = atoi(content.getToken());
m_face.getShader().m_flags.m_value = atoi(content.getToken());
}
break;
case xml_state_t::eShader:
{
m_face.getShader().setShader(m_xml_state.back().content());
}
break;
default:
break;
}
m_xml_state.pop_back();
}
std::size_t write(const char* data, std::size_t length)
{
ASSERT_MESSAGE(!m_xml_state.empty(), "parse error");
return m_xml_state.back().write(data, length);
}
};
inline void FaceTexdef_exportXML(const FaceTexdef& texdef, XMLImporter& importer)
{
StaticElement element("texdef");
importer.pushElement(element);
ASSERT_MESSAGE(texdef_sane(texdef.m_projection.m_texdef), "FaceTexdef_exportXML: bad texdef");
importer << texdef.m_projection.m_texdef.shift[0]
<< ' ' << texdef.m_projection.m_texdef.shift[1]
<< ' ' << texdef.m_projection.m_texdef.rotate
<< ' ' << texdef.m_projection.m_texdef.scale[0]
<< ' ' << texdef.m_projection.m_texdef.scale[1];
importer.popElement(element.name());
}
inline void FaceTexdef_BP_exportXML(const FaceTexdef& texdef, XMLImporter& importer)
{
StaticElement element("texdef");
importer.pushElement(element);
for(int i = 0; i < 2; ++i)
{
for(int j = 0; j < 3; ++j)
{
importer << texdef.m_projection.m_brushprimit_texdef.coords[i][j] << ' ';
}
}
importer.popElement(element.name());
}
inline void FaceShader_ContentsFlagsValue_exportXML(const FaceShader& faceShader, XMLImporter& importer)
{
StaticElement element("flags");
importer.pushElement(element);
{
importer << faceShader.m_flags.m_contentFlags
<< ' ' << faceShader.m_flags.m_surfaceFlags
<< ' ' << faceShader.m_flags.m_value;
}
importer.popElement(element.name());
}
inline void FacePlane_exportXML(const FacePlane& facePlane, XMLImporter& importer)
{
StaticElement element("planepts");
importer.pushElement(element);
{
// write planepts
for (int i=0 ; i<3 ; i++)
{
for (int j=0 ; j<3 ; j++)
{
importer << Face::m_quantise(facePlane.planePoints()[i][j]) << ' ';
}
}
}
importer.popElement(element.name());
}
class FaceXMLExporter
{
const Face& m_face;
public:
FaceXMLExporter(const Face& face) : m_face(face)
{
}
void exportXML(XMLImporter& importer)
{
bool bAlternateTexdef = (Face::m_type == eBrushTypeQuake3BP || Face::m_type == eBrushTypeDoom3 || Face::m_type == eBrushTypeQuake4);
// write shader
{
StaticElement element("shader");
importer.pushElement(element);
importer << m_face.getShader().getShader();
importer.popElement(element.name());
}
FacePlane_exportXML(m_face.getPlane(), importer);
if(!bAlternateTexdef)
{
FaceTexdef_exportXML(m_face.getTexdef(), importer);
}
else
{
FaceTexdef_BP_exportXML(m_face.getTexdef(), importer);
}
FaceShader_ContentsFlagsValue_exportXML(m_face.getShader(), importer);
}
};
class BrushXMLImporter : public XMLImporter
{
class xml_state_t
{
public:
enum EState
{
eDefault,
eBrush,
eFace,
};
private:
EState m_state;
public:
xml_state_t(EState state)
: m_state(state)
{
}
EState state() const
{
return m_state;
}
};
std::vector<xml_state_t> m_xml_state;
char m_faceImporter[sizeof(FaceXMLImporter)];
Brush& m_brush;
FaceXMLImporter& faceImporter()
{
return *reinterpret_cast<FaceXMLImporter*>(m_faceImporter);
}
public:
BrushXMLImporter(Brush& brush) : m_brush(brush)
{
m_xml_state.push_back(xml_state_t::eDefault);
}
void pushElement(const XMLElement& element)
{
switch(m_xml_state.back().state())
{
case xml_state_t::eDefault:
ASSERT_MESSAGE(strcmp(element.name(), "brush") == 0, "parse error");
m_xml_state.push_back(xml_state_t::eBrush);
break;
case xml_state_t::eBrush:
ASSERT_MESSAGE(strcmp(element.name(), "plane") == 0, "parse error");
m_xml_state.push_back(xml_state_t::eFace);
m_brush.push_back(FaceSmartPointer(new Face(&m_brush)));
constructor(faceImporter(), makeReference(*m_brush.back()));
m_brush.planeChanged();
m_brush.shaderChanged();
break;
case xml_state_t::eFace:
m_xml_state.push_back(xml_state_t::eFace);
faceImporter().pushElement(element);
break;
}
}
void popElement(const char* name)
{
ASSERT_MESSAGE(!m_xml_state.empty(), "parse error");
m_xml_state.pop_back();
switch(m_xml_state.back().state())
{
case xml_state_t::eDefault:
break;
case xml_state_t::eBrush:
destructor(faceImporter());
break;
case xml_state_t::eFace:
faceImporter().popElement(name);
break;
}
}
std::size_t write(const char* data, std::size_t length)
{
switch(m_xml_state.back().state())
{
case xml_state_t::eFace:
return faceImporter().write(data, length);
break;
default:
break;
}
return length;
}
};
class BrushXMLExporter : public XMLExporter
{
const Brush& m_brush;
public:
BrushXMLExporter(const Brush& brush) : m_brush(brush)
{
}
void exportXML(XMLImporter& importer)
{
m_brush.evaluateBRep(); // ensure b-rep is up-to-date, so that non-contributing faces can be identified.
ASSERT_MESSAGE(m_brush.hasContributingFaces(), "exporting an empty brush");
const StaticElement brushElement("brush");
importer.pushElement(brushElement);
for(Brush::const_iterator i = m_brush.begin(); i != m_brush.end(); ++i)
{
if((*i)->contributes())
{
const StaticElement element("plane");
importer.pushElement(element);
FaceXMLExporter(*(*i)).exportXML(importer);
importer.popElement(element.name());
}
}
importer.popElement(brushElement.name());
}
};
#endif

1158
radiant/build.cpp Normal file

File diff suppressed because it is too large Load Diff

44
radiant/build.h Normal file
View File

@@ -0,0 +1,44 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#if !defined(INCLUDED_BUILD_H)
#define INCLUDED_BUILD_H
void build_set_variable(const char* name, const char* value);
void build_clear_variables();
class CommandListener
{
public:
virtual void execute(const char* command) = 0;
};
void build_run(const char* name, CommandListener& listener);
void DoBuildMenu();
void BuildMenu_Construct();
void BuildMenu_Destroy();
typedef struct _GtkMenu GtkMenu;
void Build_constructMenu(GtkMenu* menu);
extern GtkMenu* g_bsp_menu;
#endif

1982
radiant/camwindow.cpp Normal file

File diff suppressed because it is too large Load Diff

87
radiant/camwindow.h Normal file
View File

@@ -0,0 +1,87 @@
/*
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
*/
#if !defined(INCLUDED_CAMWINDOW_H)
#define INCLUDED_CAMWINDOW_H
#include "math/vector.h"
typedef struct _GtkWidget GtkWidget;
typedef struct _GtkWindow GtkWindow;
class CamWnd;
CamWnd* NewCamWnd();
void DeleteCamWnd(CamWnd* camwnd);
class Callback;
void AddCameraMovedCallback(const Callback& callback);
void CamWnd_Update(CamWnd& camwnd);
GtkWidget* CamWnd_getWidget(CamWnd& camwnd);
void CamWnd_setParent(CamWnd& camwnd, GtkWindow* parent);
void GlobalCamera_setCamWnd(CamWnd& camwnd);
typedef struct _GtkMenu GtkMenu;
void fill_view_camera_menu(GtkMenu* menu);
typedef struct _GtkToolbar GtkToolbar;
void CamWnd_constructToolbar(GtkToolbar* toolbar);
void CamWnd_registerShortcuts();
void GlobalCamera_Benchmark();
const Vector3& Camera_getOrigin(CamWnd& camwnd);
void Camera_setOrigin(CamWnd& camwnd, const Vector3& origin);
enum
{
CAMERA_PITCH = 0, // up / down
CAMERA_YAW = 1, // left / right
CAMERA_ROLL = 2, // fall over
};
const Vector3& Camera_getAngles(CamWnd& camwnd);
void Camera_setAngles(CamWnd& camwnd, const Vector3& angles);
struct camwindow_globals_t
{
Vector3 color_cameraback;
Vector3 color_selbrushes3d;
int m_nCubicScale;
camwindow_globals_t() :
color_cameraback(0.25f, 0.25f, 0.25f),
color_selbrushes3d(1.0f, 0.f, 0.f),
m_nCubicScale(13)
{
}
};
extern camwindow_globals_t g_camwindow_globals;
void CamWnd_Construct();
void CamWnd_Destroy();
#endif

23
radiant/clippertool.cpp Normal file
View File

@@ -0,0 +1,23 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#include "clippertool.h"

25
radiant/clippertool.h Normal file
View File

@@ -0,0 +1,25 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#if !defined(INCLUDED_CLIPPERTOOL_H)
#define INCLUDED_CLIPPERTOOL_H
#endif

546
radiant/commands.cpp Normal file
View File

@@ -0,0 +1,546 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#include "commands.h"
#include "debugging/debugging.h"
#include "warnings.h"
#include <map>
#include "string/string.h"
#include "versionlib.h"
typedef std::pair<Accelerator, bool> ShortcutValue; // accelerator, isRegistered
typedef std::map<CopiedString, ShortcutValue> Shortcuts;
void Shortcuts_foreach(Shortcuts& shortcuts, CommandVisitor& visitor)
{
for(Shortcuts::iterator i = shortcuts.begin(); i != shortcuts.end(); ++i)
{
visitor.visit((*i).first.c_str(), (*i).second.first);
}
}
Shortcuts g_shortcuts;
const Accelerator& GlobalShortcuts_insert(const char* name, const Accelerator& accelerator)
{
return (*g_shortcuts.insert(Shortcuts::value_type(name, ShortcutValue(accelerator, false))).first).second.first;
}
void GlobalShortcuts_foreach(CommandVisitor& visitor)
{
Shortcuts_foreach(g_shortcuts, visitor);
}
void GlobalShortcuts_register(const char* name)
{
Shortcuts::iterator i = g_shortcuts.find(name);
if(i != g_shortcuts.end())
{
(*i).second.second = true;
}
}
void GlobalShortcuts_reportUnregistered()
{
for(Shortcuts::iterator i = g_shortcuts.begin(); i != g_shortcuts.end(); ++i)
{
if((*i).second.first.key != 0 && !(*i).second.second)
{
globalOutputStream() << "shortcut not registered: " << (*i).first.c_str() << "\n";
}
}
}
typedef std::map<CopiedString, Command> Commands;
Commands g_commands;
void GlobalCommands_insert(const char* name, const Callback& callback, const Accelerator& accelerator)
{
bool added = g_commands.insert(Commands::value_type(name, Command(callback, GlobalShortcuts_insert(name, accelerator)))).second;
ASSERT_MESSAGE(added, "command already registered: " << makeQuoted(name));
}
const Command& GlobalCommands_find(const char* command)
{
Commands::iterator i = g_commands.find(command);
ASSERT_MESSAGE(i != g_commands.end(), "failed to lookup command " << makeQuoted(command));
return (*i).second;
}
typedef std::map<CopiedString, Toggle> Toggles;
Toggles g_toggles;
void GlobalToggles_insert(const char* name, const Callback& callback, const BoolExportCallback& exportCallback, const Accelerator& accelerator)
{
bool added = g_toggles.insert(Toggles::value_type(name, Toggle(callback, GlobalShortcuts_insert(name, accelerator), exportCallback))).second;
ASSERT_MESSAGE(added, "toggle already registered: " << makeQuoted(name));
}
const Toggle& GlobalToggles_find(const char* name)
{
Toggles::iterator i = g_toggles.find(name);
ASSERT_MESSAGE(i != g_toggles.end(), "failed to lookup toggle " << makeQuoted(name));
return (*i).second;
}
typedef std::map<CopiedString, KeyEvent> KeyEvents;
KeyEvents g_keyEvents;
void GlobalKeyEvents_insert(const char* name, const Accelerator& accelerator, const Callback& keyDown, const Callback& keyUp)
{
bool added = g_keyEvents.insert(KeyEvents::value_type(name, KeyEvent(GlobalShortcuts_insert(name, accelerator), keyDown, keyUp))).second;
ASSERT_MESSAGE(added, "command already registered: " << makeQuoted(name));
}
const KeyEvent& GlobalKeyEvents_find(const char* name)
{
KeyEvents::iterator i = g_keyEvents.find(name);
ASSERT_MESSAGE(i != g_keyEvents.end(), "failed to lookup keyEvent " << makeQuoted(name));
return (*i).second;
}
#include <gdk/gdkkeysyms.h>
#include <ctype.h>
#ifdef __APPLE__
#define __toascii(c) ((c) & 0x7f)
#endif
inline char ascii_for_keyval(int keyval)
{
return __toascii(keyval);
}
struct SKeyInfo
{
const char* m_strName;
unsigned int m_nVKKey;
};
SKeyInfo g_Keys[] =
{
{"Space", GDK_space},
{"Backspace", GDK_BackSpace},
{"Escape", GDK_Escape},
{"End", GDK_End},
{"Insert", GDK_Insert},
{"Delete", GDK_Delete},
{"PageUp", GDK_Prior},
{"PageDown", GDK_Next},
{"Up", GDK_Up},
{"Down", GDK_Down},
{"Left", GDK_Left},
{"Right", GDK_Right},
{"F1", GDK_F1},
{"F2", GDK_F2},
{"F3", GDK_F3},
{"F4", GDK_F4},
{"F5", GDK_F5},
{"F6", GDK_F6},
{"F7", GDK_F7},
{"F8", GDK_F8},
{"F9", GDK_F9},
{"F10", GDK_F10},
{"F11", GDK_F11},
{"F12", GDK_F12},
{"Tab", GDK_Tab},
{"Return", GDK_Return},
{"Comma", GDK_comma},
{"Period", GDK_period},
{"Plus", GDK_KP_Add},
{"Multiply", GDK_multiply},
{"Minus", GDK_KP_Subtract},
{"NumPad0", GDK_KP_0},
{"NumPad1", GDK_KP_1},
{"NumPad2", GDK_KP_2},
{"NumPad3", GDK_KP_3},
{"NumPad4", GDK_KP_4},
{"NumPad5", GDK_KP_5},
{"NumPad6", GDK_KP_6},
{"NumPad7", GDK_KP_7},
{"NumPad8", GDK_KP_8},
{"NumPad9", GDK_KP_9},
{"[", 219},
{"]", 221},
{"\\", 220},
{"Home", GDK_Home}
};
int g_nKeyCount = sizeof(g_Keys) / sizeof(SKeyInfo);
const char* global_keys_find(unsigned int key)
{
for(int i = 0; i < g_nKeyCount; ++i)
{
if(g_Keys[i].m_nVKKey == key)
{
return g_Keys[i].m_strName;
}
}
return "";
}
unsigned int global_keys_find(const char* name)
{
for(int i = 0; i < g_nKeyCount; ++i)
{
if(string_equal_nocase(g_Keys[i].m_strName, name))
{
return g_Keys[i].m_nVKKey;
}
}
return 0;
}
#include <gtk/gtkbox.h>
#include <gtk/gtkliststore.h>
#include <gtk/gtktreemodel.h>
#include <gtk/gtktreeview.h>
#include <gtk/gtkcellrenderertext.h>
#include "gtkutil/dialog.h"
#include "mainframe.h"
#include "stream/textfilestream.h"
#include "stream/stringstream.h"
struct command_list_dialog_t : public ModalDialog
{
command_list_dialog_t()
: m_close_button(*this, eIDCANCEL)
{
}
ModalDialogButton m_close_button;
};
template<typename TextOutputStreamType>
TextOutputStreamType& ostream_write(TextOutputStreamType& ostream, const Accelerator& accelerator)
{
if(accelerator.modifiers & GDK_SHIFT_MASK)
{
ostream << "Shift + ";
}
if(accelerator.modifiers & GDK_MOD1_MASK)
{
ostream << "Alt + ";
}
if(accelerator.modifiers & GDK_CONTROL_MASK)
{
ostream << "Control + ";
}
const char* keyName = global_keys_find(accelerator.key);
if(!string_empty(keyName))
{
ostream << keyName;
}
else
{
ostream << static_cast<char>(accelerator.key);
}
return ostream;
}
void DoCommandListDlg()
{
command_list_dialog_t dialog;
GtkWindow* window = create_modal_dialog_window(MainFrame_getWindow(), "Mapped Commands", dialog, -1, 400);
GtkAccelGroup* accel = gtk_accel_group_new();
gtk_window_add_accel_group(window, accel);
GtkHBox* hbox = create_dialog_hbox(4, 4);
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(hbox));
{
GtkScrolledWindow* scr = create_scrolled_window(GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(scr), TRUE, TRUE, 0);
{
GtkListStore* store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING);
GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
{
GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Command", renderer, "text", 0, 0);
gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
}
{
GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Key", renderer, "text", 1, 0);
gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
}
gtk_widget_show(view);
gtk_container_add(GTK_CONTAINER (scr), view);
{
// Initialize dialog
StringOutputStream path(256);
path << SettingsPath_get() << "commandlist.txt";
globalOutputStream() << "Writing the command list to " << path.c_str() << "\n";
class BuildCommandList : public CommandVisitor
{
TextFileOutputStream m_commandList;
GtkListStore* m_store;
public:
BuildCommandList(const char* filename, GtkListStore* store) : m_commandList(filename), m_store(store)
{
}
void visit(const char* name, Accelerator& accelerator)
{
StringOutputStream modifiers;
modifiers << accelerator;
{
GtkTreeIter iter;
gtk_list_store_append(m_store, &iter);
gtk_list_store_set(m_store, &iter, 0, name, 1, modifiers.c_str(), -1);
}
if(!m_commandList.failed())
{
m_commandList << makeLeftJustified(name, 25) << " " << modifiers.c_str() << '\n';
}
}
} visitor(path.c_str(), store);
GlobalShortcuts_foreach(visitor);
}
g_object_unref(G_OBJECT(store));
}
}
GtkVBox* vbox = create_dialog_vbox(4);
gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox), FALSE, FALSE, 0);
{
GtkButton* button = create_modal_dialog_button("Close", dialog.m_close_button);
gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0);
widget_make_default(GTK_WIDGET(button));
gtk_widget_grab_focus(GTK_WIDGET(button));
gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0);
gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0);
}
modal_dialog_show(window, dialog);
gtk_widget_destroy(GTK_WIDGET(window));
}
#include "profile/profile.h"
const char* const COMMANDS_VERSION = "1.0";
void SaveCommandMap(const char* path)
{
StringOutputStream strINI(256);
strINI << path << "shortcuts.ini";
TextFileOutputStream file(strINI.c_str());
if(!file.failed())
{
file << "[Version]\n";
file << "number=" << COMMANDS_VERSION << "\n";
file << "\n";
file << "[Commands]\n";
class WriteCommandMap : public CommandVisitor
{
TextFileOutputStream& m_file;
public:
WriteCommandMap(TextFileOutputStream& file) : m_file(file)
{
}
void visit(const char* name, Accelerator& accelerator)
{
m_file << name << "=";
const char* key = global_keys_find(accelerator.key);
if(!string_empty(key))
{
m_file << key;
}
else if(accelerator.key != 0)
{
m_file << ascii_for_keyval(accelerator.key);
}
if(accelerator.modifiers & GDK_MOD1_MASK)
{
m_file << "+Alt";
}
if(accelerator.modifiers & GDK_CONTROL_MASK)
{
m_file << "+Ctrl";
}
if(accelerator.modifiers & GDK_SHIFT_MASK)
{
m_file << "+Shift";
}
m_file << "\n";
}
} visitor(file);
GlobalShortcuts_foreach(visitor);
}
}
const char* stringrange_find(const char* first, const char* last, char c)
{
const char* p = strchr(first, '+');
if(p == 0)
{
return last;
}
return p;
}
class ReadCommandMap : public CommandVisitor
{
const char* m_filename;
std::size_t m_count;
public:
ReadCommandMap(const char* filename) : m_filename(filename), m_count(0)
{
}
void visit(const char* name, Accelerator& accelerator)
{
char value[1024];
if (read_var(m_filename, "Commands", name, value ))
{
if(string_empty(value))
{
accelerator.key = 0;
accelerator.modifiers = (GdkModifierType)0;
return;
}
int modifiers = 0;
const char* last = value + string_length(value);
const char* keyEnd = stringrange_find(value, last, '+');
for(const char* modifier = keyEnd; modifier != last;)
{
const char* next = stringrange_find(modifier + 1, last, '+');
if(next - modifier == 4
&& string_equal_nocase_n(modifier, "+alt", 4))
{
modifiers |= GDK_MOD1_MASK;
}
else if(next - modifier == 5
&& string_equal_nocase_n(modifier, "+ctrl", 5) != 0)
{
modifiers |= GDK_CONTROL_MASK;
}
else if(next - modifier == 6
&& string_equal_nocase_n(modifier, "+shift", 6) != 0)
{
modifiers |= GDK_SHIFT_MASK;
}
else
{
globalOutputStream() << "WARNING: failed to parse user command " << makeQuoted(value) << ": unknown modifier " << makeQuoted(StringRange(modifier, next)) << "\n";
}
modifier = next;
}
accelerator.modifiers = (GdkModifierType)modifiers;
// strBuff has been cleaned of it's modifiers .. switch between a regular key and a virtual one
// based on length
if(keyEnd - value == 1) // most often case.. deal with first
{
accelerator.key = std::toupper(value[0]);
++m_count;
}
else // special key
{
CopiedString keyName(value, keyEnd);
accelerator.key = global_keys_find(keyName.c_str());
if(accelerator.key != 0)
{
++m_count;
}
else
{
globalOutputStream() << "WARNING: failed to parse user command " << makeQuoted(value) << ": unknown key " << makeQuoted(keyName.c_str()) << "\n";
}
}
}
}
std::size_t count() const
{
return m_count;
}
};
void LoadCommandMap(const char* path)
{
StringOutputStream strINI(256);
strINI << path << "shortcuts.ini";
FILE* f = fopen (strINI.c_str(), "r");
if (f != 0)
{
fclose(f);
globalOutputStream() << "loading custom shortcuts list from " << makeQuoted(strINI.c_str()) << "\n";
Version version = version_parse(COMMANDS_VERSION);
Version dataVersion = { 0, 0 };
{
char value[1024];
if(read_var(strINI.c_str(), "Version", "number", value))
{
dataVersion = version_parse(value);
}
}
if(version_compatible(version, dataVersion))
{
globalOutputStream() << "commands import: data version " << dataVersion << " is compatible with code version " << version << "\n";
ReadCommandMap visitor(strINI.c_str());
GlobalShortcuts_foreach(visitor);
globalOutputStream() << "parsed " << Unsigned(visitor.count()) << " custom shortcuts\n";
}
else
{
globalOutputStream() << "commands import: data version " << dataVersion << " is not compatible with code version " << version << "\n";
}
}
else
{
globalOutputStream() << "failed to load custom shortcuts from " << makeQuoted(strINI.c_str()) << "\n";
}
}

54
radiant/commands.h Normal file
View File

@@ -0,0 +1,54 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#if !defined(INCLUDED_COMMANDS_H)
#define INCLUDED_COMMANDS_H
#include "gtkutil/accelerator.h"
const Accelerator& GlobalShortcuts_insert(const char* name, const Accelerator& accelerator);
void GlobalShortcuts_register(const char* name);
void GlobalShortcuts_reportUnregistered();
class CommandVisitor
{
public:
virtual void visit(const char* name, Accelerator& accelerator) = 0;
};
void GlobalCommands_insert(const char* name, const Callback& callback, const Accelerator& accelerator = accelerator_null());
const Command& GlobalCommands_find(const char* name);
void GlobalToggles_insert(const char* name, const Callback& callback, const BoolExportCallback& exportCallback, const Accelerator& accelerator = accelerator_null());
const Toggle& GlobalToggles_find(const char* name);
void GlobalKeyEvents_insert(const char* name, const Accelerator& accelerator, const Callback& keyDown, const Callback& keyUp);
const KeyEvent& GlobalKeyEvents_find(const char* name);
void DoCommandListDlg();
void LoadCommandMap(const char* path);
void SaveCommandMap(const char* path);
#endif

253
radiant/console.cpp Normal file
View File

@@ -0,0 +1,253 @@
/*
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
*/
#include "console.h"
#include <time.h>
#include <gtk/gtktextbuffer.h>
#include <gtk/gtktextview.h>
#include <gtk/gtkmenuitem.h>
#include <gtk/gtkscrolledwindow.h>
#include "gtkutil/accelerator.h"
#include "gtkutil/messagebox.h"
#include "gtkutil/container.h"
#include "gtkutil/menu.h"
#include "gtkutil/nonmodal.h"
#include "stream/stringstream.h"
#include "convert.h"
#include "version.h"
#include "aboutmsg.h"
#include "gtkmisc.h"
#include "mainframe.h"
// handle to the console log file
namespace
{
FILE* g_hLogFile;
}
bool g_Console_enableLogging = false;
// called whenever we need to open/close/check the console log file
void Sys_LogFile(bool enable)
{
if (enable && !g_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_hLogFile
// the log file is erased
StringOutputStream name(256);
name << SettingsPath_get() << "radiant.log";
g_hLogFile = fopen( name.c_str(), "w" );
if (g_hLogFile != 0)
{
globalOutputStream() << "Started logging to " << name.c_str() << "\n";
time_t localtime;
time(&localtime);
globalOutputStream() << "Today is: " << ctime(&localtime)
<< "This is GtkRadiant '" RADIANT_VERSION "' compiled " __DATE__ "\n" RADIANT_ABOUTMSG "\n";
}
else
gtk_MessageBox (0, "Failed to create log file, check write permissions in Radiant directory.\n",
"Console logging", eMB_OK, eMB_ICONERROR );
}
else if (!enable && g_hLogFile != 0)
{
// settings say we should not be logging but still we have an active logfile .. close it
time_t localtime;
time(&localtime);
globalOutputStream() << "Closing log file at " << ctime(&localtime) << "\n";
fclose( g_hLogFile );
g_hLogFile = 0;
}
}
GtkWidget* g_console = 0;
void console_clear()
{
GtkTextBuffer* buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(g_console));
gtk_text_buffer_set_text(buffer, "", -1);
}
void console_populate_popup(GtkTextView* textview, GtkMenu* menu, gpointer user_data)
{
menu_separator(menu);
GtkWidget* item = gtk_menu_item_new_with_label ("Clear");
g_signal_connect(G_OBJECT (item), "activate", G_CALLBACK(console_clear), 0);
gtk_widget_show (item);
container_add_widget(GTK_CONTAINER(menu), item);
}
gboolean destroy_set_null(GtkWindow* widget, GtkWidget** p)
{
*p = 0;
return FALSE;
}
GtkWidget* Console_constructWindow(GtkWindow* toplevel)
{
GtkWidget* scr = gtk_scrolled_window_new (0, 0);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scr), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN);
gtk_widget_show(scr);
{
GtkWidget* text = gtk_text_view_new();
gtk_widget_set_size_request(text, 0, -1); // allow shrinking
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text), GTK_WRAP_WORD);
gtk_text_view_set_editable(GTK_TEXT_VIEW(text), FALSE);
gtk_container_add(GTK_CONTAINER (scr), text);
gtk_widget_show(text);
g_console = text;
//globalExtendedASCIICharacterSet().print();
widget_connect_escape_clear_focus_widget(g_console);
g_signal_connect(G_OBJECT(g_console), "populate-popup", G_CALLBACK(console_populate_popup), 0);
g_signal_connect(G_OBJECT(g_console), "destroy", G_CALLBACK(destroy_set_null), &g_console);
}
gtk_container_set_focus_chain(GTK_CONTAINER(scr), NULL);
return scr;
}
std::size_t Sys_Print(int level, const char* buf, std::size_t length)
{
bool contains_newline = strchr(buf, '\n') != 0;
if(level == SYS_ERR)
{
Sys_LogFile(true);
}
if (g_hLogFile != 0)
{
fwrite(buf, 1, length, g_hLogFile);
if(contains_newline)
{
fflush(g_hLogFile);
}
}
if (level != SYS_NOCON)
{
if (g_console != 0)
{
GtkTextBuffer* buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(g_console));
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, 0);
static GtkTextTag* warning_tag = gtk_text_buffer_create_tag (buffer, "yellow_foreground", "foreground-gdk", &yellow, 0);
static GtkTextTag* standard_tag = gtk_text_buffer_create_tag (buffer, "black_foreground", "foreground-gdk", &black, 0);
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;
}
StringOutputStream converted;
if(!globalCharacterSet().isUTF8())
{
converted << ConvertLocaleToUTF8(StringRange(buf, buf + length));
}
else
{
converted << StringRange(buf, buf + length);
}
gtk_text_buffer_insert_with_tags(buffer, &iter, converted.c_str(), gint(string_length(converted.c_str())), tag, 0);
// update console widget immediatly if we're doing something time-consuming
if(contains_newline)
{
gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(g_console), end);
if(!ScreenUpdates_Enabled() && GTK_WIDGET_REALIZED(g_console))
{
ScreenUpdates_process();
}
}
}
}
return length;
}
class SysPrintOutputStream : public TextOutputStream
{
public:
std::size_t write(const char* buffer, std::size_t length)
{
return Sys_Print(SYS_STD, buffer, length);
}
};
class SysPrintErrorStream : public TextOutputStream
{
public:
std::size_t write(const char* buffer, std::size_t length)
{
return Sys_Print(SYS_ERR, buffer, length);
}
};
SysPrintOutputStream g_outputStream;
TextOutputStream& getSysPrintOutputStream()
{
return g_outputStream;
}
SysPrintErrorStream g_errorStream;
TextOutputStream& getSysPrintErrorStream()
{
return g_errorStream;
}

47
radiant/console.h Normal file
View File

@@ -0,0 +1,47 @@
/*
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
*/
#if !defined(INCLUDED_CONSOLE_H)
#define INCLUDED_CONSOLE_H
#include <cstddef>
#define SYS_VRB 0 ///< verbose support (on/off)
#define SYS_STD 1 ///< standard print level - this is the default
#define SYS_WRN 2 ///< warnings
#define SYS_ERR 3 ///< error
#define SYS_NOCON 4 ///< no console, only print to the file (useful whenever Sys_Printf and output IS the problem)
std::size_t Sys_Print(int level, const char* buf, std::size_t length);
class TextOutputStream;
TextOutputStream& getSysPrintOutputStream();
TextOutputStream& getSysPrintErrorStream();
typedef struct _GtkWidget GtkWidget;
typedef struct _GtkWindow GtkWindow;
GtkWidget* Console_constructWindow(GtkWindow* toplevel);
// will open/close the log file based on the parameter
void Sys_LogFile(bool enable);
extern bool g_Console_enableLogging;
#endif

575
radiant/csg.cpp Normal file
View File

@@ -0,0 +1,575 @@
/*
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
*/
#include "csg.h"
#include "debugging/debugging.h"
#include <list>
#include "map.h"
#include "brushmanip.h"
#include "brushnode.h"
#include "grid.h"
void Brush_makeHollow(const Brush& brush, brush_vector_t& out, float offset)
{
for(Brush::const_iterator i(brush.begin()); i != brush.end(); ++i)
{
if((*i)->contributes())
{
out.push_back(new Brush(brush));
Face* newFace = out.back()->addFace(*(*i));
if(newFace != 0)
{
newFace->flipWinding();
newFace->getPlane().offset(offset);
newFace->planeChanged();
}
}
}
}
class BrushHollowSelectedWalker : public scene::Graph::Walker
{
float m_offset;
public:
BrushHollowSelectedWalker(float offset)
: m_offset(offset)
{
}
bool pre(const scene::Path& path, scene::Instance& instance) const
{
if(path.top().get().visible())
{
Brush* brush = Node_getBrush(path.top());
if(brush != 0
&& Instance_getSelectable(instance)->isSelected()
&& path.size() > 1)
{
brush_vector_t out;
Brush_makeHollow(*brush, out, m_offset);
for(brush_vector_t::const_iterator i = out.begin(); i != out.end(); ++i)
{
NodeSmartReference node((new BrushNode())->node());
(*i)->removeEmptyFaces();
Node_getBrush(node)->copy(*(*i));
delete (*i);
Node_getTraversable(path.parent())->insert(node);
}
}
}
return true;
}
};
typedef std::list<Brush*> brushlist_t;
class BrushGatherSelected : public scene::Graph::Walker
{
brush_vector_t& m_brushlist;
public:
BrushGatherSelected(brush_vector_t& brushlist)
: m_brushlist(brushlist)
{
}
bool pre(const scene::Path& path, scene::Instance& instance) const
{
if(path.top().get().visible())
{
Brush* brush = Node_getBrush(path.top());
if(brush != 0
&& Instance_getSelectable(instance)->isSelected())
{
m_brushlist.push_back(brush);
}
}
return true;
}
};
class BrushDeleteSelected : public scene::Graph::Walker
{
public:
bool pre(const scene::Path& path, scene::Instance& instance) const
{
return true;
}
void post(const scene::Path& path, scene::Instance& instance) const
{
if(path.top().get().visible())
{
Brush* brush = Node_getBrush(path.top());
if(brush != 0
&& Instance_getSelectable(instance)->isSelected()
&& path.size() > 1)
{
Path_deleteTop(path);
}
}
}
};
void Scene_BrushMakeHollow_Selected(scene::Graph& graph)
{
GlobalSceneGraph().traverse(BrushHollowSelectedWalker(GetGridSize()));
GlobalSceneGraph().traverse(BrushDeleteSelected());
}
/*
=============
CSG_MakeHollow
=============
*/
void CSG_MakeHollow (void)
{
UndoableCommand undo("brushHollow");
Scene_BrushMakeHollow_Selected(GlobalSceneGraph());
SceneChangeNotify();
}
/// \brief Returns true if
/// \li !flipped && brush is BACK or ON
/// \li flipped && brush is FRONT or ON
bool Brush_testPlane(const Brush& brush, const Plane3& plane, bool flipped)
{
brush.evaluateBRep();
for(Brush::const_iterator i(brush.begin()); i != brush.end(); ++i)
{
if((*i)->contributes() && !Winding_TestPlane((*i)->getWinding(), plane, flipped))
{
return false;
}
}
return true;
}
brushsplit_t Brush_classifyPlane(const Brush& brush, const Plane3& plane)
{
brush.evaluateBRep();
brushsplit_t split;
for(Brush::const_iterator i(brush.begin()); i != brush.end(); ++i)
{
if((*i)->contributes())
{
split += Winding_ClassifyPlane((*i)->getWinding(), plane);
}
}
return split;
}
bool Brush_subtract(const Brush& brush, const Brush& other, brush_vector_t& ret_fragments)
{
if(aabb_intersects_aabb(brush.localAABB(), other.localAABB()))
{
brush_vector_t fragments;
fragments.reserve(other.size());
Brush back(brush);
for(Brush::const_iterator i(other.begin()); i != other.end(); ++i)
{
if((*i)->contributes())
{
brushsplit_t split = Brush_classifyPlane(back, (*i)->plane3());
if(split.counts[ePlaneFront] != 0
&& split.counts[ePlaneBack] != 0)
{
fragments.push_back(new Brush(back));
Face* newFace = fragments.back()->addFace(*(*i));
if(newFace != 0)
{
newFace->flipWinding();
}
back.addFace(*(*i));
}
else if(split.counts[ePlaneBack] == 0)
{
for(brush_vector_t::iterator i = fragments.begin(); i != fragments.end(); ++i)
{
delete(*i);
}
return false;
}
}
}
ret_fragments.insert(ret_fragments.end(), fragments.begin(), fragments.end());
return true;
}
return false;
}
class SubtractBrushesFromUnselected : public scene::Graph::Walker
{
const brush_vector_t& m_brushlist;
std::size_t& m_before;
std::size_t& m_after;
public:
SubtractBrushesFromUnselected(const brush_vector_t& brushlist, std::size_t& before, std::size_t& after)
: m_brushlist(brushlist), m_before(before), m_after(after)
{
}
bool pre(const scene::Path& path, scene::Instance& instance) const
{
return true;
}
void post(const scene::Path& path, scene::Instance& instance) const
{
if(path.top().get().visible())
{
Brush* brush = Node_getBrush(path.top());
if(brush != 0
&& !Instance_getSelectable(instance)->isSelected())
{
brush_vector_t buffer[2];
bool swap = false;
Brush* original = new Brush(*brush);
buffer[static_cast<std::size_t>(swap)].push_back(original);
{
for(brush_vector_t::const_iterator i(m_brushlist.begin()); i != m_brushlist.end(); ++i)
{
for(brush_vector_t::iterator j(buffer[static_cast<std::size_t>(swap)].begin()); j != buffer[static_cast<std::size_t>(swap)].end(); ++j)
{
if(Brush_subtract(*(*j), *(*i), buffer[static_cast<std::size_t>(!swap)]))
{
delete (*j);
}
else
{
buffer[static_cast<std::size_t>(!swap)].push_back((*j));
}
}
buffer[static_cast<std::size_t>(swap)].clear();
swap = !swap;
}
}
brush_vector_t& out = buffer[static_cast<std::size_t>(swap)];
if(out.size() == 1 && out.back() == original)
{
delete original;
}
else
{
++m_before;
for(brush_vector_t::const_iterator i = out.begin(); i != out.end(); ++i)
{
++m_after;
NodeSmartReference node((new BrushNode())->node());
(*i)->removeEmptyFaces();
ASSERT_MESSAGE(!(*i)->empty(), "brush left with no faces after subtract");
Node_getBrush(node)->copy(*(*i));
delete (*i);
Node_getTraversable(path.parent())->insert(node);
}
Path_deleteTop(path);
}
}
}
}
};
void CSG_Subtract()
{
brush_vector_t selected_brushes;
GlobalSceneGraph().traverse(BrushGatherSelected(selected_brushes));
if (selected_brushes.empty())
{
globalOutputStream() << "CSG Subtract: No brushes selected.\n";
}
else
{
globalOutputStream() << "CSG Subtract: Subtracting " << Unsigned(selected_brushes.size()) << " brushes.\n";
UndoableCommand undo("brushSubtract");
// subtract selected from unselected
std::size_t before = 0;
std::size_t after = 0;
GlobalSceneGraph().traverse(SubtractBrushesFromUnselected(selected_brushes, before, after));
globalOutputStream() << "CSG Subtract: Result: "
<< Unsigned(after) << " fragment" << (after == 1 ? "" : "s")
<< " from " << Unsigned(before) << " brush" << (before == 1? "" : "es") << ".\n";
SceneChangeNotify();
}
}
class BrushSplitByPlaneSelected : public scene::Graph::Walker
{
const Vector3& m_p0;
const Vector3& m_p1;
const Vector3& m_p2;
const char* m_shader;
const TextureProjection& m_projection;
EBrushSplit m_split;
public:
BrushSplitByPlaneSelected(const Vector3& p0, const Vector3& p1, const Vector3& p2, const char* shader, const TextureProjection& projection, EBrushSplit split)
: m_p0(p0), m_p1(p1), m_p2(p2), m_shader(shader), m_projection(projection), m_split(split)
{
}
bool pre(const scene::Path& path, scene::Instance& instance) const
{
return true;
}
void post(const scene::Path& path, scene::Instance& instance) const
{
if(path.top().get().visible())
{
Brush* brush = Node_getBrush(path.top());
if(brush != 0
&& Instance_getSelectable(instance)->isSelected())
{
Plane3 plane(plane3_for_points(m_p0, m_p1, m_p2));
if(plane3_valid(plane))
{
brushsplit_t split = Brush_classifyPlane(*brush, m_split == eFront ? plane3_flipped(plane) : plane);
if(split.counts[ePlaneBack] && split.counts[ePlaneFront])
{
// the plane intersects this brush
if(m_split == eFrontAndBack)
{
NodeSmartReference node((new BrushNode())->node());
Brush* fragment = Node_getBrush(node);
fragment->copy(*brush);
Face* newFace = fragment->addPlane(m_p0, m_p1, m_p2, m_shader, m_projection);
if(newFace != 0 && m_split != eFront)
{
newFace->flipWinding();
}
fragment->removeEmptyFaces();
ASSERT_MESSAGE(!fragment->empty(), "brush left with no faces after split");
Node_getTraversable(path.parent())->insert(node);
{
scene::Path fragmentPath = path;
fragmentPath.top() = makeReference(node.get());
selectPath(fragmentPath, true);
}
}
Face* newFace = brush->addPlane(m_p0, m_p1, m_p2, m_shader, m_projection);
if(newFace != 0 && m_split == eFront)
{
newFace->flipWinding();
}
brush->removeEmptyFaces();
ASSERT_MESSAGE(!brush->empty(), "brush left with no faces after split");
}
else
// the plane does not intersect this brush
if(m_split != eFrontAndBack && split.counts[ePlaneBack] != 0)
{
// the brush is "behind" the plane
Path_deleteTop(path);
}
}
}
}
}
};
void Scene_BrushSplitByPlane(scene::Graph& graph, const Vector3& p0, const Vector3& p1, const Vector3& p2, const char* shader, EBrushSplit split)
{
TextureProjection projection;
TexDef_Construct_Default(projection);
graph.traverse(BrushSplitByPlaneSelected(p0, p1, p2, shader, projection, split));
SceneChangeNotify();
}
class BrushInstanceSetClipPlane : public scene::Graph::Walker
{
Plane3 m_plane;
public:
BrushInstanceSetClipPlane(const Plane3& plane)
: m_plane(plane)
{
}
bool pre(const scene::Path& path, scene::Instance& instance) const
{
BrushInstance* brush = Instance_getBrush(instance);
if(brush != 0
&& path.top().get().visible()
&& brush->isSelected())
{
BrushInstance& brushInstance = *brush;
brushInstance.setClipPlane(m_plane);
}
return true;
}
};
void Scene_BrushSetClipPlane(scene::Graph& graph, const Plane3& plane)
{
graph.traverse(BrushInstanceSetClipPlane(plane));
}
/*
=============
CSG_Merge
=============
*/
bool Brush_merge(Brush& brush, const brush_vector_t& in, bool onlyshape)
{
// gather potential outer faces
{
typedef std::vector<const Face*> Faces;
Faces faces;
for(brush_vector_t::const_iterator i(in.begin()); i != in.end(); ++i)
{
(*i)->evaluateBRep();
for(Brush::const_iterator j((*i)->begin()); j != (*i)->end(); ++j)
{
if(!(*j)->contributes())
{
continue;
}
const Face& face1 = *(*j);
bool skip = false;
// test faces of all input brushes
//!\todo SPEEDUP: Flag already-skip faces and only test brushes from i+1 upwards.
for(brush_vector_t::const_iterator k(in.begin()); !skip && k != in.end(); ++k)
{
if(k != i) // don't test a brush against itself
{
for(Brush::const_iterator l((*k)->begin()); !skip && l != (*k)->end(); ++l)
{
const Face& face2 = *(*l);
// face opposes another face
if(plane3_opposing(face1.plane3(), face2.plane3()))
{
// skip opposing planes
skip = true;
break;
}
}
}
}
// check faces already stored
for(Faces::const_iterator m = faces.begin(); !skip && m != faces.end(); ++m)
{
const Face& face2 = *(*m);
// face equals another face
if (plane3_equal(face1.plane3(), face2.plane3()))
{
//if the texture/shader references should be the same but are not
if (!onlyshape && !shader_equal(face1.getShader().getShader(), face2.getShader().getShader()))
{
return false;
}
// skip duplicate planes
skip = true;
break;
}
// face1 plane intersects face2 winding or vice versa
if (Winding_PlanesConcave(face1.getWinding(), face2.getWinding(), face1.plane3(), face2.plane3()))
{
// result would not be convex
return false;
}
}
if(!skip)
{
faces.push_back(&face1);
}
}
}
for(Faces::const_iterator i = faces.begin(); i != faces.end(); ++i)
{
if(!brush.addFace(*(*i)))
{
// result would have too many sides
return false;
}
}
}
brush.removeEmptyFaces();
return true;
}
void CSG_Merge(void)
{
brush_vector_t selected_brushes;
// remove selected
GlobalSceneGraph().traverse(BrushGatherSelected(selected_brushes));
if (selected_brushes.empty())
{
globalOutputStream() << "CSG Merge: No brushes selected.\n";
return;
}
if (selected_brushes.size() < 2)
{
globalOutputStream() << "CSG Merge: At least two brushes have to be selected.\n";
return;
}
globalOutputStream() << "CSG Merge: Merging " << Unsigned(selected_brushes.size()) << " brushes.\n";
UndoableCommand undo("brushMerge");
scene::Path merged_path = GlobalSelectionSystem().ultimateSelected().path();
NodeSmartReference node((new BrushNode())->node());
Brush* brush = Node_getBrush(node);
// if the new brush would not be convex
if(!Brush_merge(*brush, selected_brushes, true))
{
globalOutputStream() << "CSG Merge: Failed - result would not be convex.\n";
}
else
{
ASSERT_MESSAGE(!brush->empty(), "brush left with no faces after merge");
// free the original brushes
GlobalSceneGraph().traverse(BrushDeleteSelected());
merged_path.pop();
Node_getTraversable(merged_path.top())->insert(node);
merged_path.push(makeReference(node.get()));
selectPath(merged_path, true);
globalOutputStream() << "CSG Merge: Succeeded.\n";
SceneChangeNotify();
}
}

46
radiant/csg.h Normal file
View File

@@ -0,0 +1,46 @@
/*
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
*/
#if !defined(INCLUDED_CSG_H)
#define INCLUDED_CSG_H
void CSG_MakeHollow (void);
void CSG_Subtract (void);
void CSG_Merge (void);
namespace scene
{
class Graph;
}
template<typename Element> class BasicVector3;
typedef BasicVector3<float> Vector3;
class Plane3;
void Scene_BrushSetClipPlane(scene::Graph& graph, const Plane3& plane);
enum EBrushSplit
{
eFront,
eBack,
eFrontAndBack,
};
void Scene_BrushSplitByPlane(scene::Graph& graph, const Vector3& p0, const Vector3& p1, const Vector3& p2, const char* shader, EBrushSplit split);
#endif

740
radiant/dialog.cpp Normal file
View File

@@ -0,0 +1,740 @@
/*
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
*/
//
// Base dialog class, provides a way to run modal dialogs and
// set/get the widget values in member variables.
//
// Leonardo Zide (leo@lokigames.com)
//
#include "dialog.h"
#include "debugging/debugging.h"
#include "mainframe.h"
#include <stdlib.h>
#include <gtk/gtkmain.h>
#include <gtk/gtkvbox.h>
#include <gtk/gtkhbox.h>
#include <gtk/gtktogglebutton.h>
#include <gtk/gtkspinbutton.h>
#include <gtk/gtkradiobutton.h>
#include <gtk/gtkentry.h>
#include <gtk/gtkcombobox.h>
#include <gtk/gtklabel.h>
#include <gtk/gtktable.h>
#include <gtk/gtkhscale.h>
#include <gtk/gtkalignment.h>
#include "stream/stringstream.h"
#include "convert.h"
#include "gtkutil/dialog.h"
#include "gtkutil/button.h"
#include "gtkutil/entry.h"
#include "gtkutil/image.h"
#include "gtkmisc.h"
GtkEntry* DialogEntry_new()
{
GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
gtk_widget_show(GTK_WIDGET(entry));
gtk_widget_set_size_request(GTK_WIDGET(entry), 64, -1);
return entry;
}
class DialogEntryRow
{
public:
DialogEntryRow(GtkWidget* row, GtkEntry* entry) : m_row(row), m_entry(entry)
{
}
GtkWidget* m_row;
GtkEntry* m_entry;
};
DialogEntryRow DialogEntryRow_new(const char* name)
{
GtkWidget* alignment = gtk_alignment_new(0.0, 0.5, 0.0, 0.0);
gtk_widget_show(alignment);
GtkEntry* entry = DialogEntry_new();
gtk_container_add(GTK_CONTAINER(alignment), GTK_WIDGET(entry));
return DialogEntryRow(GTK_WIDGET(DialogRow_new(name, alignment)), entry);
}
GtkSpinButton* DialogSpinner_new(double value, double lower, double upper, int fraction)
{
double step = 1.0 / double(fraction);
unsigned int digits = 0;
for(;fraction > 1; fraction /= 10)
{
++digits;
}
GtkSpinButton* spin = GTK_SPIN_BUTTON(gtk_spin_button_new(GTK_ADJUSTMENT(gtk_adjustment_new(value, lower, upper, step, 10, 10)), step, digits));
gtk_widget_show(GTK_WIDGET(spin));
gtk_widget_set_size_request(GTK_WIDGET(spin), 64, -1);
return spin;
}
class DialogSpinnerRow
{
public:
DialogSpinnerRow(GtkWidget* row, GtkSpinButton* spin) : m_row(row), m_spin(spin)
{
}
GtkWidget* m_row;
GtkSpinButton* m_spin;
};
DialogSpinnerRow DialogSpinnerRow_new(const char* name, double value, double lower, double upper, int fraction)
{
GtkWidget* alignment = gtk_alignment_new(0.0, 0.5, 0.0, 0.0);
gtk_widget_show(alignment);
GtkSpinButton* spin = DialogSpinner_new(value, lower, upper, fraction);
gtk_container_add(GTK_CONTAINER(alignment), GTK_WIDGET(spin));
return DialogSpinnerRow(GTK_WIDGET(DialogRow_new(name, alignment)), spin);
}
template<
typename Type_,
typename Other_,
void(*Import)(Type_&, Other_),
void(*Export)(Type_&, const Callback1<Other_>&)
>
class ImportExport
{
public:
typedef Type_ Type;
typedef Other_ Other;
typedef ReferenceCaller1<Type, Other, Import> ImportCaller;
typedef ReferenceCaller1<Type, const Callback1<Other>&, Export> ExportCaller;
};
typedef ImportExport<bool, bool, BoolImport, BoolExport> BoolImportExport;
typedef ImportExport<int, int, IntImport, IntExport> IntImportExport;
typedef ImportExport<std::size_t, std::size_t, SizeImport, SizeExport> SizeImportExport;
typedef ImportExport<float, float, FloatImport, FloatExport> FloatImportExport;
typedef ImportExport<CopiedString, const char*, StringImport, StringExport> StringImportExport;
void BoolToggleImport(GtkToggleButton& widget, bool value)
{
gtk_toggle_button_set_active(&widget, value);
}
void BoolToggleExport(GtkToggleButton& widget, const BoolImportCallback& importCallback)
{
importCallback(gtk_toggle_button_get_active(&widget) != FALSE);
}
typedef ImportExport<GtkToggleButton, bool, BoolToggleImport, BoolToggleExport> BoolToggleImportExport;
void IntRadioImport(GtkRadioButton& widget, int index)
{
radio_button_set_active(&widget, index);
}
void IntRadioExport(GtkRadioButton& widget, const IntImportCallback& importCallback)
{
importCallback(radio_button_get_active(&widget));
}
typedef ImportExport<GtkRadioButton, int, IntRadioImport, IntRadioExport> IntRadioImportExport;
void TextEntryImport(GtkEntry& widget, const char* text)
{
StringOutputStream value(64);
value << ConvertLocaleToUTF8(text);
gtk_entry_set_text(&widget, value.c_str());
}
void TextEntryExport(GtkEntry& widget, const StringImportCallback& importCallback)
{
StringOutputStream value(64);
value << ConvertUTF8ToLocale(gtk_entry_get_text(&widget));
importCallback(value.c_str());
}
typedef ImportExport<GtkEntry, const char*, TextEntryImport, TextEntryExport> TextEntryImportExport;
void IntEntryImport(GtkEntry& widget, int value)
{
entry_set_int(&widget, value);
}
void IntEntryExport(GtkEntry& widget, const IntImportCallback& importCallback)
{
importCallback(atoi(gtk_entry_get_text (&widget)));
}
typedef ImportExport<GtkEntry, int, IntEntryImport, IntEntryExport> IntEntryImportExport;
void SizeEntryImport(GtkEntry& widget, std::size_t value)
{
entry_set_int(&widget, int(value));
}
void SizeEntryExport(GtkEntry& widget, const SizeImportCallback& importCallback)
{
int value = atoi(gtk_entry_get_text(&widget));
if(value < 0)
{
value = 0;
}
importCallback(value);
}
typedef ImportExport<GtkEntry, std::size_t, SizeEntryImport, SizeEntryExport> SizeEntryImportExport;
void FloatEntryImport(GtkEntry& widget, float value)
{
entry_set_float(&widget, value);
}
void FloatEntryExport(GtkEntry& widget, const FloatImportCallback& importCallback)
{
importCallback((float)atof(gtk_entry_get_text(&widget)));
}
typedef ImportExport<GtkEntry, float, FloatEntryImport, FloatEntryExport> FloatEntryImportExport;
void FloatSpinnerImport(GtkSpinButton& widget, float value)
{
gtk_spin_button_set_value(&widget, value);
}
void FloatSpinnerExport(GtkSpinButton& widget, const FloatImportCallback& importCallback)
{
importCallback(float(gtk_spin_button_get_value_as_float(&widget)));
}
typedef ImportExport<GtkSpinButton, float, FloatSpinnerImport, FloatSpinnerExport> FloatSpinnerImportExport;
void IntSpinnerImport(GtkSpinButton& widget, int value)
{
gtk_spin_button_set_value(&widget, value);
}
void IntSpinnerExport(GtkSpinButton& widget, const IntImportCallback& importCallback)
{
importCallback(gtk_spin_button_get_value_as_int(&widget));
}
typedef ImportExport<GtkSpinButton, int, IntSpinnerImport, IntSpinnerExport> IntSpinnerImportExport;
void IntAdjustmentImport(GtkAdjustment& widget, int value)
{
gtk_adjustment_set_value(&widget, value);
}
void IntAdjustmentExport(GtkAdjustment& widget, const IntImportCallback& importCallback)
{
importCallback((int)gtk_adjustment_get_value(&widget));
}
typedef ImportExport<GtkAdjustment, int, IntAdjustmentImport, IntAdjustmentExport> IntAdjustmentImportExport;
void IntComboImport(GtkComboBox& widget, int value)
{
gtk_combo_box_set_active(&widget, value);
}
void IntComboExport(GtkComboBox& widget, const IntImportCallback& importCallback)
{
importCallback(gtk_combo_box_get_active(&widget));
}
typedef ImportExport<GtkComboBox, int, IntComboImport, IntComboExport> IntComboImportExport;
template<typename FirstArgument>
class CallbackDialogData : public DLG_DATA
{
public:
typedef Callback1<FirstArgument> ImportCallback;
typedef Callback1<const ImportCallback&> ExportCallback;
private:
ImportCallback m_importWidget;
ExportCallback m_exportWidget;
ImportCallback m_importViewer;
ExportCallback m_exportViewer;
public:
CallbackDialogData(const ImportCallback& importWidget, const ExportCallback& exportWidget, const ImportCallback& importViewer, const ExportCallback& exportViewer)
: m_importWidget(importWidget), m_exportWidget(exportWidget), m_importViewer(importViewer), m_exportViewer(exportViewer)
{
}
void release()
{
delete this;
}
void importData() const
{
m_exportViewer(m_importWidget);
}
void exportData() const
{
m_exportWidget(m_importViewer);
}
};
template<typename Widget, typename Viewer>
class AddData
{
DialogDataList& m_data;
public:
AddData(DialogDataList& data) : m_data(data)
{
}
void apply(typename Widget::Type& widget, typename Viewer::Type& viewer) const
{
m_data.push_back(
new CallbackDialogData<typename Widget::Other>(
typename Widget::ImportCaller(widget),
typename Widget::ExportCaller(widget),
typename Viewer::ImportCaller(viewer),
typename Viewer::ExportCaller(viewer)
)
);
}
};
template<typename Widget>
class AddCustomData
{
DialogDataList& m_data;
public:
AddCustomData(DialogDataList& data) : m_data(data)
{
}
void apply(
typename Widget::Type& widget,
const Callback1<typename Widget::Other>& importViewer,
const Callback1<const Callback1<typename Widget::Other>&>& exportViewer
) const
{
m_data.push_back(
new CallbackDialogData<typename Widget::Other>(
typename Widget::ImportCaller(widget),
typename Widget::ExportCaller(widget),
importViewer,
exportViewer
)
);
}
};
// =============================================================================
// Dialog class
Dialog::Dialog() : m_window(0), m_parent(0)
{
}
Dialog::~Dialog()
{
for(DialogDataList::iterator i = m_data.begin(); i != m_data.end(); ++i)
{
(*i)->release();
}
ASSERT_MESSAGE(m_window == 0, "dialog window not destroyed");
}
void Dialog::ShowDlg()
{
ASSERT_MESSAGE(m_window != 0, "dialog was not constructed")
importData();
gtk_widget_show(GTK_WIDGET(m_window));
}
void Dialog::HideDlg()
{
ASSERT_MESSAGE(m_window != 0, "dialog was not constructed")
exportData();
gtk_widget_hide(GTK_WIDGET(m_window));
}
static gint delete_event_callback(GtkWidget *widget, GdkEvent* event, gpointer data)
{
reinterpret_cast<Dialog*>(data)->HideDlg();
reinterpret_cast<Dialog*>(data)->EndModal(eIDCANCEL);
return TRUE;
}
void Dialog::Create()
{
ASSERT_MESSAGE(m_window == 0, "dialog cannot be constructed")
m_window = BuildDialog();
g_signal_connect(G_OBJECT(m_window), "delete_event", G_CALLBACK(delete_event_callback), this);
}
void Dialog::Destroy()
{
ASSERT_MESSAGE(m_window != 0, "dialog cannot be destroyed");
gtk_widget_destroy(GTK_WIDGET(m_window));
m_window = 0;
}
void Dialog::AddBoolToggleData(GtkToggleButton& widget, const BoolImportCallback& importViewer, const BoolExportCallback& exportViewer)
{
AddCustomData<BoolToggleImportExport>(m_data).apply(widget, importViewer, exportViewer);
}
void Dialog::AddIntRadioData(GtkRadioButton& widget, const IntImportCallback& importViewer, const IntExportCallback& exportViewer)
{
AddCustomData<IntRadioImportExport>(m_data).apply(widget, importViewer, exportViewer);
}
void Dialog::AddTextEntryData(GtkEntry& widget, const StringImportCallback& importViewer, const StringExportCallback& exportViewer)
{
AddCustomData<TextEntryImportExport>(m_data).apply(widget, importViewer, exportViewer);
}
void Dialog::AddIntEntryData(GtkEntry& widget, const IntImportCallback& importViewer, const IntExportCallback& exportViewer)
{
AddCustomData<IntEntryImportExport>(m_data).apply(widget, importViewer, exportViewer);
}
void Dialog::AddSizeEntryData(GtkEntry& widget, const SizeImportCallback& importViewer, const SizeExportCallback& exportViewer)
{
AddCustomData<SizeEntryImportExport>(m_data).apply(widget, importViewer, exportViewer);
}
void Dialog::AddFloatEntryData(GtkEntry& widget, const FloatImportCallback& importViewer, const FloatExportCallback& exportViewer)
{
AddCustomData<FloatEntryImportExport>(m_data).apply(widget, importViewer, exportViewer);
}
void Dialog::AddFloatSpinnerData(GtkSpinButton& widget, const FloatImportCallback& importViewer, const FloatExportCallback& exportViewer)
{
AddCustomData<FloatSpinnerImportExport>(m_data).apply(widget, importViewer, exportViewer);
}
void Dialog::AddIntSpinnerData(GtkSpinButton& widget, const IntImportCallback& importViewer, const IntExportCallback& exportViewer)
{
AddCustomData<IntSpinnerImportExport>(m_data).apply(widget, importViewer, exportViewer);
}
void Dialog::AddIntAdjustmentData(GtkAdjustment& widget, const IntImportCallback& importViewer, const IntExportCallback& exportViewer)
{
AddCustomData<IntAdjustmentImportExport>(m_data).apply(widget, importViewer, exportViewer);
}
void Dialog::AddIntComboData(GtkComboBox& widget, const IntImportCallback& importViewer, const IntExportCallback& exportViewer)
{
AddCustomData<IntComboImportExport>(m_data).apply(widget, importViewer, exportViewer);
}
void Dialog::AddDialogData(GtkToggleButton& widget, bool& data)
{
AddData<BoolToggleImportExport, BoolImportExport>(m_data).apply(widget, data);
}
void Dialog::AddDialogData(GtkRadioButton& widget, int& data)
{
AddData<IntRadioImportExport, IntImportExport>(m_data).apply(widget, data);
}
void Dialog::AddDialogData(GtkEntry& widget, CopiedString& data)
{
AddData<TextEntryImportExport, StringImportExport>(m_data).apply(widget, data);
}
void Dialog::AddDialogData(GtkEntry& widget, int& data)
{
AddData<IntEntryImportExport, IntImportExport>(m_data).apply(widget, data);
}
void Dialog::AddDialogData(GtkEntry& widget, std::size_t& data)
{
AddData<SizeEntryImportExport, SizeImportExport>(m_data).apply(widget, data);
}
void Dialog::AddDialogData(GtkEntry& widget, float& data)
{
AddData<FloatEntryImportExport, FloatImportExport>(m_data).apply(widget, data);
}
void Dialog::AddDialogData(GtkSpinButton& widget, float& data)
{
AddData<FloatSpinnerImportExport, FloatImportExport>(m_data).apply(widget, data);
}
void Dialog::AddDialogData(GtkSpinButton& widget, int& data)
{
AddData<IntSpinnerImportExport, IntImportExport>(m_data).apply(widget, data);
}
void Dialog::AddDialogData(GtkAdjustment& widget, int& data)
{
AddData<IntAdjustmentImportExport, IntImportExport>(m_data).apply(widget, data);
}
void Dialog::AddDialogData(GtkComboBox& widget, int& data)
{
AddData<IntComboImportExport, IntImportExport>(m_data).apply(widget, data);
}
void Dialog::exportData()
{
for(DialogDataList::iterator i = m_data.begin(); i != m_data.end(); ++i)
{
(*i)->exportData();
}
}
void Dialog::importData()
{
for(DialogDataList::iterator i = m_data.begin(); i != m_data.end(); ++i)
{
(*i)->importData();
}
}
void Dialog::EndModal (EMessageBoxReturn code)
{
m_modal.loop = 0;
m_modal.ret = code;
}
EMessageBoxReturn Dialog::DoModal()
{
importData();
PreModal();
EMessageBoxReturn ret = modal_dialog_show(m_window, m_modal);
ASSERT_NOTNULL(m_window);
if(ret == eIDOK)
{
exportData();
}
gtk_widget_hide(GTK_WIDGET(m_window));
PostModal(m_modal.ret);
return m_modal.ret;
}
GtkWidget* Dialog::addCheckBox(GtkWidget* vbox, const char* name, const char* flag, const BoolImportCallback& importViewer, const BoolExportCallback& exportViewer)
{
GtkWidget* check = gtk_check_button_new_with_label(flag);
gtk_widget_show(check);
AddBoolToggleData(*GTK_TOGGLE_BUTTON(check), importViewer, exportViewer);
DialogVBox_packRow(GTK_VBOX(vbox), GTK_WIDGET(DialogRow_new(name, check)));
return check;
}
GtkWidget* Dialog::addCheckBox(GtkWidget* vbox, const char* name, const char* flag, bool& data)
{
return addCheckBox(vbox, name, flag, BoolImportCaller(data), BoolExportCaller(data));
}
void Dialog::addCombo(GtkWidget* vbox, const char* name, StringArrayRange values, const IntImportCallback& importViewer, const IntExportCallback& exportViewer)
{
GtkWidget* alignment = gtk_alignment_new(0.0, 0.5, 0.0, 0.0);
gtk_widget_show(alignment);
{
GtkWidget* combo = gtk_combo_box_new_text();
for(StringArrayRange::Iterator i = values.begin; i != values.end; ++i)
{
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), *i);
}
AddIntComboData(*GTK_COMBO_BOX(combo), importViewer, exportViewer);
gtk_widget_show (combo);
gtk_container_add(GTK_CONTAINER(alignment), combo);
}
GtkTable* row = DialogRow_new(name, alignment);
DialogVBox_packRow(GTK_VBOX(vbox), GTK_WIDGET(row));
}
void Dialog::addCombo(GtkWidget* vbox, const char* name, int& data, StringArrayRange values)
{
addCombo(vbox, name, values, IntImportCaller(data), IntExportCaller(data));
}
void Dialog::addSlider(GtkWidget* vbox, const char* name, int& data, gboolean draw_value, const char* low, const char* high, double value, double lower, double upper, double step_increment, double page_increment, double page_size)
{
#if 0
if(draw_value == FALSE)
{
GtkWidget* hbox2 = gtk_hbox_new (FALSE, 0);
gtk_widget_show (hbox2);
gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox2), FALSE, FALSE, 0);
{
GtkWidget* label = gtk_label_new (low);
gtk_widget_show (label);
gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, FALSE, 0);
}
{
GtkWidget* label = gtk_label_new (high);
gtk_widget_show (label);
gtk_box_pack_end (GTK_BOX (hbox2), label, FALSE, FALSE, 0);
}
}
#endif
// adjustment
GtkObject* adj = gtk_adjustment_new(value, lower, upper, step_increment, page_increment, page_size);
AddIntAdjustmentData(*GTK_ADJUSTMENT(adj), IntImportCaller(data), IntExportCaller(data));
// scale
GtkWidget* alignment = gtk_alignment_new(0.0, 0.5, 1.0, 0.0);
gtk_widget_show(alignment);
GtkWidget* scale = gtk_hscale_new(GTK_ADJUSTMENT(adj));
gtk_scale_set_value_pos(GTK_SCALE(scale), GTK_POS_LEFT);
gtk_widget_show(scale);
gtk_container_add(GTK_CONTAINER(alignment), scale);
gtk_scale_set_draw_value(GTK_SCALE (scale), draw_value);
gtk_scale_set_digits(GTK_SCALE (scale), 0);
GtkTable* row = DialogRow_new(name, alignment);
DialogVBox_packRow(GTK_VBOX(vbox), GTK_WIDGET(row));
}
void Dialog::addRadio(GtkWidget* vbox, const char* name, StringArrayRange names, const IntImportCallback& importViewer, const IntExportCallback& exportViewer)
{
GtkWidget* alignment = gtk_alignment_new(0.0, 0.5, 0.0, 0.0);
gtk_widget_show(alignment);
{
RadioHBox radioBox = RadioHBox_new(names);
gtk_container_add(GTK_CONTAINER(alignment), GTK_WIDGET(radioBox.m_hbox));
AddIntRadioData(*GTK_RADIO_BUTTON(radioBox.m_radio), importViewer, exportViewer);
}
GtkTable* row = DialogRow_new(name, alignment);
DialogVBox_packRow(GTK_VBOX(vbox), GTK_WIDGET(row));
}
void Dialog::addRadio(GtkWidget* vbox, const char* name, int& data, StringArrayRange names)
{
addRadio(vbox, name, names, IntImportCaller(data), IntExportCaller(data));
}
void Dialog::addRadioIcons(GtkWidget* vbox, const char* name, StringArrayRange icons, const IntImportCallback& importViewer, const IntExportCallback& exportViewer)
{
GtkWidget* table = gtk_table_new (2, static_cast<guint>(icons.end - icons.begin), FALSE);
gtk_widget_show (table);
gtk_table_set_row_spacings (GTK_TABLE (table), 5);
gtk_table_set_col_spacings (GTK_TABLE (table), 5);
GSList* group = 0;
GtkWidget* radio = 0;
for(StringArrayRange::Iterator icon = icons.begin; icon != icons.end; ++icon)
{
guint pos = static_cast<guint>(icon - icons.begin);
GtkImage* image = new_local_image(*icon);
gtk_widget_show(GTK_WIDGET(image));
gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(image), pos, pos+1, 0, 1,
(GtkAttachOptions) (0),
(GtkAttachOptions) (0), 0, 0);
radio = gtk_radio_button_new(group);
gtk_widget_show (radio);
gtk_table_attach (GTK_TABLE (table), radio, pos, pos+1, 1, 2,
(GtkAttachOptions) (0),
(GtkAttachOptions) (0), 0, 0);
group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radio));
}
AddIntRadioData(*GTK_RADIO_BUTTON(radio), importViewer, exportViewer);
DialogVBox_packRow(GTK_VBOX(vbox), GTK_WIDGET(DialogRow_new(name, table)));
}
void Dialog::addRadioIcons(GtkWidget* vbox, const char* name, int& data, StringArrayRange icons)
{
addRadioIcons(vbox, name, icons, IntImportCaller(data), IntExportCaller(data));
}
GtkWidget* Dialog::addEntry(GtkWidget* vbox, const char* name, const IntImportCallback& importViewer, const IntExportCallback& exportViewer)
{
DialogEntryRow row(DialogEntryRow_new(name));
AddIntEntryData(*row.m_entry, importViewer, exportViewer);
DialogVBox_packRow(GTK_VBOX(vbox), row.m_row);
return row.m_row;
}
GtkWidget* Dialog::addEntry(GtkWidget* vbox, const char* name, const SizeImportCallback& importViewer, const SizeExportCallback& exportViewer)
{
DialogEntryRow row(DialogEntryRow_new(name));
AddSizeEntryData(*row.m_entry, importViewer, exportViewer);
DialogVBox_packRow(GTK_VBOX(vbox), row.m_row);
return row.m_row;
}
GtkWidget* Dialog::addEntry(GtkWidget* vbox, const char* name, const FloatImportCallback& importViewer, const FloatExportCallback& exportViewer)
{
DialogEntryRow row(DialogEntryRow_new(name));
AddFloatEntryData(*row.m_entry, importViewer, exportViewer);
DialogVBox_packRow(GTK_VBOX(vbox), row.m_row);
return row.m_row;
}
GtkWidget* Dialog::addPathEntry(GtkWidget* vbox, const char* name, bool browse_directory, const StringImportCallback& importViewer, const StringExportCallback& exportViewer)
{
PathEntry pathEntry = PathEntry_new();
g_signal_connect(G_OBJECT(pathEntry.m_button), "clicked", G_CALLBACK(browse_directory ? button_clicked_entry_browse_directory : button_clicked_entry_browse_file), pathEntry.m_entry);
AddTextEntryData(*GTK_ENTRY(pathEntry.m_entry), importViewer, exportViewer);
GtkTable* row = DialogRow_new(name, GTK_WIDGET(pathEntry.m_frame));
DialogVBox_packRow(GTK_VBOX(vbox), GTK_WIDGET(row));
return GTK_WIDGET(row);
}
GtkWidget* Dialog::addPathEntry(GtkWidget* vbox, const char* name, CopiedString& data, bool browse_directory)
{
return addPathEntry(vbox, name, browse_directory, StringImportCallback(StringImportCaller(data)), StringExportCallback(StringExportCaller(data)));
}
GtkWidget* Dialog::addSpinner(GtkWidget* vbox, const char* name, double value, double lower, double upper, const IntImportCallback& importViewer, const IntExportCallback& exportViewer)
{
DialogSpinnerRow row(DialogSpinnerRow_new(name, value, lower, upper, 1));
AddIntSpinnerData(*row.m_spin, importViewer, exportViewer);
DialogVBox_packRow(GTK_VBOX(vbox), row.m_row);
return row.m_row;
}
GtkWidget* Dialog::addSpinner(GtkWidget* vbox, const char* name, int& data, double value, double lower, double upper)
{
return addSpinner(vbox, name, value, lower, upper, IntImportCallback(IntImportCaller(data)), IntExportCallback(IntExportCaller(data)));
}
GtkWidget* Dialog::addSpinner(GtkWidget* vbox, const char* name, double value, double lower, double upper, const FloatImportCallback& importViewer, const FloatExportCallback& exportViewer)
{
DialogSpinnerRow row(DialogSpinnerRow_new(name, value, lower, upper, 10));
AddFloatSpinnerData(*row.m_spin, importViewer, exportViewer);
DialogVBox_packRow(GTK_VBOX(vbox), row.m_row);
return row.m_row;
}

208
radiant/dialog.h Normal file
View File

@@ -0,0 +1,208 @@
/*
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
*/
#if !defined(INCLUDED_DIALOG_H)
#define INCLUDED_DIALOG_H
#include <list>
#include "gtkutil/dialog.h"
#include "generic/callback.h"
#include "string/string.h"
template<typename Environment, typename FirstArgument, void(*func)(Environment&, FirstArgument)>
class ReferenceCaller1;
inline void BoolImport(bool& self, bool value)
{
self = value;
}
typedef ReferenceCaller1<bool, bool, BoolImport> BoolImportCaller;
inline void BoolExport(bool& self, const BoolImportCallback& importCallback)
{
importCallback(self);
}
typedef ReferenceCaller1<bool, const BoolImportCallback&, BoolExport> BoolExportCaller;
inline void IntImport(int& self, int value)
{
self = value;
}
typedef ReferenceCaller1<int, int, IntImport> IntImportCaller;
inline void IntExport(int& self, const IntImportCallback& importCallback)
{
importCallback(self);
}
typedef ReferenceCaller1<int, const IntImportCallback&, IntExport> IntExportCaller;
inline void SizeImport(std::size_t& self, std::size_t value)
{
self = value;
}
typedef ReferenceCaller1<std::size_t, std::size_t, SizeImport> SizeImportCaller;
inline void SizeExport(std::size_t& self, const SizeImportCallback& importCallback)
{
importCallback(self);
}
typedef ReferenceCaller1<std::size_t, const SizeImportCallback&, SizeExport> SizeExportCaller;
inline void FloatImport(float& self, float value)
{
self = value;
}
typedef ReferenceCaller1<float, float, FloatImport> FloatImportCaller;
inline void FloatExport(float& self, const FloatImportCallback& importCallback)
{
importCallback(self);
}
typedef ReferenceCaller1<float, const FloatImportCallback&, FloatExport> FloatExportCaller;
inline void StringImport(CopiedString& self, const char* value)
{
self = value;
}
typedef ReferenceCaller1<CopiedString, const char*, StringImport> StringImportCaller;
inline void StringExport(CopiedString& self, const StringImportCallback& importCallback)
{
importCallback(self.c_str());
}
typedef ReferenceCaller1<CopiedString, const StringImportCallback&, StringExport> StringExportCaller;
struct DLG_DATA
{
virtual void release() = 0;
virtual void importData() const = 0;
virtual void exportData() const = 0;
};
typedef struct _GtkWindow GtkWindow;
typedef struct _GtkToggleButton GtkToggleButton;
typedef struct _GtkRadioButton GtkRadioButton;
typedef struct _GtkSpinButton GtkSpinButton;
typedef struct _GtkComboBox GtkComboBox;
typedef struct _GtkEntry GtkEntry;
typedef struct _GtkAdjustment GtkAdjustment;
template<typename FirstArgument>
class CallbackDialogData;
typedef std::list<DLG_DATA*> DialogDataList;
class Dialog
{
GtkWindow* m_window;
DialogDataList m_data;
public:
ModalDialog m_modal;
GtkWindow* m_parent;
Dialog();
virtual ~Dialog();
/*!
start modal dialog box
you need to use AddModalButton to select eIDOK eIDCANCEL buttons
*/
EMessageBoxReturn DoModal();
void EndModal (EMessageBoxReturn code);
virtual GtkWindow* BuildDialog() = 0;
virtual void exportData();
virtual void importData();
virtual void PreModal() { };
virtual void PostModal (EMessageBoxReturn code) { };
virtual void ShowDlg();
virtual void HideDlg();
void Create();
void Destroy();
GtkWindow* GetWidget()
{
return m_window;
}
const GtkWindow* GetWidget() const
{
return m_window;
}
GtkWidget* addCheckBox(GtkWidget* vbox, const char* name, const char* flag, const BoolImportCallback& importCallback, const BoolExportCallback& exportCallback);
GtkWidget* addCheckBox(GtkWidget* vbox, const char* name, const char* flag, bool& data);
void addCombo(GtkWidget* vbox, const char* name, StringArrayRange values, const IntImportCallback& importCallback, const IntExportCallback& exportCallback);
void addCombo(GtkWidget* vbox, const char* name, int& data, StringArrayRange values);
void addSlider(GtkWidget* vbox, const char* name, int& data, gboolean draw_value, const char* low, const char* high, double value, double lower, double upper, double step_increment, double page_increment, double page_size);
void addRadio(GtkWidget* vbox, const char* name, StringArrayRange names, const IntImportCallback& importCallback, const IntExportCallback& exportCallback);
void addRadio(GtkWidget* vbox, const char* name, int& data, StringArrayRange names);
void addRadioIcons(GtkWidget* vbox, const char* name, StringArrayRange icons, const IntImportCallback& importCallback, const IntExportCallback& exportCallback);
void addRadioIcons(GtkWidget* vbox, const char* name, int& data, StringArrayRange icons);
GtkWidget* addEntry(GtkWidget* vbox, const char* name, const IntImportCallback& importCallback, const IntExportCallback& exportCallback);
GtkWidget* addEntry(GtkWidget* vbox, const char* name, int& data)
{
return addEntry(vbox, name, IntImportCaller(data), IntExportCaller(data));
}
GtkWidget* addEntry(GtkWidget* vbox, const char* name, const SizeImportCallback& importCallback, const SizeExportCallback& exportCallback);
GtkWidget* addEntry(GtkWidget* vbox, const char* name, std::size_t& data)
{
return addEntry(vbox, name, SizeImportCaller(data), SizeExportCaller(data));
}
GtkWidget* addEntry(GtkWidget* vbox, const char* name, const FloatImportCallback& importCallback, const FloatExportCallback& exportCallback);
GtkWidget* addEntry(GtkWidget* vbox, const char* name, float& data)
{
return addEntry(vbox, name, FloatImportCaller(data), FloatExportCaller(data));
}
GtkWidget* addPathEntry(GtkWidget* vbox, const char* name, bool browse_directory, const StringImportCallback& importCallback, const StringExportCallback& exportCallback);
GtkWidget* addPathEntry(GtkWidget* vbox, const char* name, CopiedString& data, bool directory);
GtkWidget* addSpinner(GtkWidget* vbox, const char* name, int& data, double value, double lower, double upper);
GtkWidget* addSpinner(GtkWidget* vbox, const char* name, double value, double lower, double upper, const IntImportCallback& importCallback, const IntExportCallback& exportCallback);
GtkWidget* addSpinner(GtkWidget* vbox, const char* name, double value, double lower, double upper, const FloatImportCallback& importCallback, const FloatExportCallback& exportCallback);
protected:
void AddBoolToggleData(GtkToggleButton& object, const BoolImportCallback& importCallback, const BoolExportCallback& exportCallback);
void AddIntRadioData(GtkRadioButton& object, const IntImportCallback& importCallback, const IntExportCallback& exportCallback);
void AddTextEntryData(GtkEntry& object, const StringImportCallback& importCallback, const StringExportCallback& exportCallback);
void AddIntEntryData(GtkEntry& object, const IntImportCallback& importCallback, const IntExportCallback& exportCallback);
void AddSizeEntryData(GtkEntry& object, const SizeImportCallback& importCallback, const SizeExportCallback& exportCallback);
void AddFloatEntryData(GtkEntry& object, const FloatImportCallback& importCallback, const FloatExportCallback& exportCallback);
void AddFloatSpinnerData(GtkSpinButton& object, const FloatImportCallback& importCallback, const FloatExportCallback& exportCallback);
void AddIntSpinnerData(GtkSpinButton& object, const IntImportCallback& importCallback, const IntExportCallback& exportCallback);
void AddIntAdjustmentData(GtkAdjustment& object, const IntImportCallback& importCallback, const IntExportCallback& exportCallback);
void AddIntComboData(GtkComboBox& object, const IntImportCallback& importCallback, const IntExportCallback& exportCallback);
void AddDialogData(GtkToggleButton& object, bool& data);
void AddDialogData(GtkRadioButton& object, int& data);
void AddDialogData(GtkEntry& object, CopiedString& data);
void AddDialogData(GtkEntry& object, int& data);
void AddDialogData(GtkEntry& object, std::size_t& data);
void AddDialogData(GtkEntry& object, float& data);
void AddDialogData(GtkSpinButton& object, float& data);
void AddDialogData(GtkSpinButton& object, int& data);
void AddDialogData(GtkAdjustment& object, int& data);
void AddDialogData(GtkComboBox& object, int& data);
};
#endif

398
radiant/eclass.cpp Normal file
View File

@@ -0,0 +1,398 @@
/*
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
*/
#include "eclass.h"
#include "debugging/debugging.h"
#include <map>
#include "ifilesystem.h"
#include "string/string.h"
#include "eclasslib.h"
#include "os/path.h"
#include "os/dir.h"
#include "stream/stringstream.h"
#include "moduleobservers.h"
#include "cmdlib.h"
#include "preferences.h"
#include "mainframe.h"
namespace
{
typedef std::map<const char*, EntityClass*, RawStringLessNoCase> EntityClasses;
EntityClasses g_entityClasses;
EntityClass *eclass_bad = 0;
char eclass_directory[1024];
typedef std::map<CopiedString, ListAttributeType> ListAttributeTypes;
ListAttributeTypes g_listTypes;
}
/*!
implementation of the EClass manager API
*/
void CleanEntityList(EntityClasses& entityClasses)
{
for(EntityClasses::iterator i = entityClasses.begin(); i != entityClasses.end(); ++i)
{
(*i).second->free((*i).second);
}
entityClasses.clear();
}
void Eclass_Clear()
{
CleanEntityList(g_entityClasses);
g_listTypes.clear();
}
EntityClass* EClass_InsertSortedList(EntityClasses& entityClasses, EntityClass *entityClass)
{
std::pair<EntityClasses::iterator, bool> result = entityClasses.insert(EntityClasses::value_type(entityClass->name(), entityClass));
if(!result.second)
{
entityClass->free(entityClass);
}
return (*result.first).second;
}
EntityClass* Eclass_InsertAlphabetized (EntityClass *e)
{
return EClass_InsertSortedList(g_entityClasses, e);
}
void Eclass_forEach(EntityClassVisitor& visitor)
{
for(EntityClasses::iterator i = g_entityClasses.begin(); i != g_entityClasses.end(); ++i)
{
visitor.visit((*i).second);
}
}
class RadiantEclassCollector : public EntityClassCollector
{
public:
void insert(EntityClass* eclass)
{
Eclass_InsertAlphabetized(eclass);
}
void insert(const char* name, const ListAttributeType& list)
{
g_listTypes.insert(ListAttributeTypes::value_type(name, list));
}
};
RadiantEclassCollector g_collector;
const ListAttributeType* EntityClass_findListType(const char* name)
{
ListAttributeTypes::iterator i = g_listTypes.find(name);
if(i != g_listTypes.end())
{
return &(*i).second;
}
return 0;
}
class EntityClassFilterMode
{
public:
bool filter_mp_sp;
const char* mp_ignore_prefix;
const char* sp_ignore_prefix;
EntityClassFilterMode() :
filter_mp_sp(!string_empty(g_pGameDescription->getKeyValue("eclass_filter_gamemode"))),
mp_ignore_prefix(g_pGameDescription->getKeyValue("eclass_sp_prefix")),
sp_ignore_prefix(g_pGameDescription->getKeyValue("eclass_mp_prefix"))
{
if(string_empty(mp_ignore_prefix))
{
mp_ignore_prefix = "sp_";
}
if(string_empty(sp_ignore_prefix))
{
sp_ignore_prefix = "mp_";
}
}
};
class EntityClassesLoadFile
{
const char* m_directory;
public:
EntityClassesLoadFile(const char* directory) : m_directory(directory)
{
}
void operator()(const char* name) const
{
EntityClassFilterMode filterMode;
if(filterMode.filter_mp_sp)
{
if(string_empty(GlobalRadiant().getGameMode()) || string_equal(GlobalRadiant().getGameMode(), "sp"))
{
if(string_equal_n(name, filterMode.sp_ignore_prefix, strlen(filterMode.sp_ignore_prefix)))
{
globalOutputStream() << "Ignoring '" << name << "'\n";
return;
}
}
else
{
if(string_equal_n(name, filterMode.mp_ignore_prefix, strlen(filterMode.mp_ignore_prefix)))
{
globalOutputStream() << "Ignoring '" << name << "'\n";
return;
}
}
}
// for a given name, we grab the first .def in the vfs
// this allows to override baseq3/scripts/entities.def for instance
StringOutputStream relPath(256);
relPath << m_directory << name;
GlobalEClassLoader().scanFile(g_collector, relPath.c_str());
}
};
struct PathLess
{
bool operator()(const CopiedString& path, const CopiedString& other) const
{
return path_less(path.c_str(), other.c_str());
}
};
typedef std::map<CopiedString, const char*, PathLess> Paths;
class PathsInsert
{
Paths& m_paths;
const char* m_directory;
public:
PathsInsert(Paths& paths, const char* directory) : m_paths(paths), m_directory(directory)
{
}
void operator()(const char* name) const
{
m_paths.insert(Paths::value_type(name, m_directory));
}
};
#if 0
void EntityClassQuake3_constructDirectory(const char* directory, const char* extension)
{
globalOutputStream() << "EntityClass: searching " << makeQuoted(directory) << " for *." << extension << '\n';
Directory_forEach(directory, matchFileExtension(extension, EntityClassesLoadFile(directory)));
}
#else
void EntityClassQuake3_constructDirectory(const char* directory, const char* extension, Paths& paths)
{
globalOutputStream() << "EntityClass: searching " << makeQuoted(directory) << " for *." << extension << '\n';
Directory_forEach(directory, matchFileExtension(extension, PathsInsert(paths, directory)));
}
#endif
void EntityClassQuake3_Construct()
{
#if 1
StringOutputStream baseDirectory(256);
StringOutputStream gameDirectory(256);
const char* basegame = GlobalRadiant().getRequiredGameDescriptionKeyValue("basegame");
const char* gamename = GlobalRadiant().getGameName();
baseDirectory << GlobalRadiant().getGameToolsPath() << basegame << '/';
gameDirectory << GlobalRadiant().getGameToolsPath() << gamename << '/';
Paths paths;
EntityClassQuake3_constructDirectory(baseDirectory.c_str(), GlobalEClassLoader().getExtension(), paths);
if(!string_equal(basegame, gamename))
{
EntityClassQuake3_constructDirectory(gameDirectory.c_str(), GlobalEClassLoader().getExtension(), paths);
}
for(Paths::iterator i = paths.begin(); i != paths.end(); ++i)
{
EntityClassesLoadFile((*i).second)((*i).first.c_str());
}
#else
StringOutputStream directory(256);
directory << GlobalRadiant().getGameToolsPath() << GlobalRadiant().getGameName() << '/';
EntityClassQuake3_constructDirectory(directory.c_str(), GlobalEClassLoader().getExtension());
#endif
}
EntityClass *Eclass_ForName(const char *name, bool has_brushes)
{
ASSERT_NOTNULL(name);
if(string_empty(name))
{
return eclass_bad;
}
EntityClasses::iterator i = g_entityClasses.find(name);
if(i != g_entityClasses.end() && string_equal((*i).first, name))
{
return (*i).second;
}
EntityClass* e = EntityClass_Create_Default(name, has_brushes);
return Eclass_InsertAlphabetized(e);
}
class EntityClassQuake3 : public ModuleObserver
{
std::size_t m_unrealised;
ModuleObservers m_observers;
public:
EntityClassQuake3() : m_unrealised(4)
{
}
void realise()
{
if(--m_unrealised == 0)
{
//globalOutputStream() << "Entity Classes: realise\n";
EntityClassQuake3_Construct();
m_observers.realise();
}
}
void unrealise()
{
if(++m_unrealised == 1)
{
m_observers.unrealise();
//globalOutputStream() << "Entity Classes: unrealise\n";
Eclass_Clear();
}
}
void attach(ModuleObserver& observer)
{
m_observers.attach(observer);
}
void detach(ModuleObserver& observer)
{
m_observers.detach(observer);
}
};
EntityClassQuake3 g_EntityClassQuake3;
void EntityClass_attach(ModuleObserver& observer)
{
g_EntityClassQuake3.attach(observer);
}
void EntityClass_detach(ModuleObserver& observer)
{
g_EntityClassQuake3.detach(observer);
}
void EntityClass_realise()
{
g_EntityClassQuake3.realise();
}
void EntityClass_unrealise()
{
g_EntityClassQuake3.unrealise();
}
void EntityClassQuake3_construct()
{
// start by creating the default unknown eclass
eclass_bad = EClass_Create("UNKNOWN_CLASS", Vector3(0.0f, 0.5f, 0.0f), "");
EntityClass_realise();
}
void EntityClassQuake3_destroy()
{
EntityClass_unrealise();
eclass_bad->free(eclass_bad);
}
class EntityClassQuake3Dependencies :
public GlobalRadiantModuleRef,
public GlobalFileSystemModuleRef,
public GlobalShaderCacheModuleRef,
public GlobalEClassModuleRef
{
public:
EntityClassQuake3Dependencies() :
GlobalEClassModuleRef(GlobalRadiant().getRequiredGameDescriptionKeyValue("entityclasstype"))
{
}
};
class EclassManagerAPI
{
EntityClassManager m_eclassmanager;
public:
typedef EntityClassManager Type;
STRING_CONSTANT(Name, "quake3");
EclassManagerAPI()
{
EntityClassQuake3_construct();
m_eclassmanager.findOrInsert = &Eclass_ForName;
m_eclassmanager.findListType = &EntityClass_findListType;
m_eclassmanager.forEach = &Eclass_forEach;
m_eclassmanager.attach = &EntityClass_attach;
m_eclassmanager.detach = &EntityClass_detach;
m_eclassmanager.realise = &EntityClass_realise;
m_eclassmanager.unrealise = &EntityClass_unrealise;
GlobalRadiant().attachGameToolsPathObserver(g_EntityClassQuake3);
GlobalRadiant().attachGameModeObserver(g_EntityClassQuake3);
GlobalRadiant().attachGameNameObserver(g_EntityClassQuake3);
}
~EclassManagerAPI()
{
GlobalRadiant().detachGameNameObserver(g_EntityClassQuake3);
GlobalRadiant().detachGameModeObserver(g_EntityClassQuake3);
GlobalRadiant().detachGameToolsPathObserver(g_EntityClassQuake3);
EntityClassQuake3_destroy();
}
EntityClassManager* getTable()
{
return &m_eclassmanager;
}
};
#include "modulesystem/singletonmodule.h"
#include "modulesystem/moduleregistry.h"
typedef SingletonModule<EclassManagerAPI, EntityClassQuake3Dependencies> EclassManagerModule;
typedef Static<EclassManagerModule> StaticEclassManagerModule;
StaticRegisterModule staticRegisterEclassManager(StaticEclassManagerModule::instance());

25
radiant/eclass.h Normal file
View File

@@ -0,0 +1,25 @@
/*
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
*/
#if !defined(INCLUDED_ECLASS_H)
#define INCLUDED_ECLASS_H
#endif

407
radiant/eclass_def.cpp Normal file
View File

@@ -0,0 +1,407 @@
/*
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
*/
#include "eclass_def.h"
#include "iscriplib.h"
#include "ifilesystem.h"
#include "iarchive.h"
#include "eclasslib.h"
#include "stream/stringstream.h"
#include "stream/textfilestream.h"
#include "modulesystem/moduleregistry.h"
#include "os/path.h"
const char* EClass_GetExtension()
{
return "def";
}
void Eclass_ScanFile (EntityClassCollector& collector, const char *filename);
#include "modulesystem/singletonmodule.h"
class EntityClassDefDependencies : public GlobalShaderCacheModuleRef, public GlobalScripLibModuleRef
{
};
class EclassDefAPI
{
EntityClassScanner m_eclassdef;
public:
typedef EntityClassScanner Type;
STRING_CONSTANT(Name, "def");
EclassDefAPI()
{
m_eclassdef.scanFile = &Eclass_ScanFile;
m_eclassdef.getExtension = &EClass_GetExtension;
}
EntityClassScanner* getTable()
{
return &m_eclassdef;
}
};
typedef SingletonModule<EclassDefAPI, EntityClassDefDependencies> EclassDefModule;
typedef Static<EclassDefModule> StaticEclassDefModule;
StaticRegisterModule staticRegisterEclassDef(StaticEclassDefModule::instance());
#include "string/string.h"
#include <stdlib.h>
char com_token[1024];
bool com_eof;
/*
==============
COM_Parse
Parse a token out of a string
==============
*/
const char *COM_Parse (const char *data)
{
int c;
int len;
len = 0;
com_token[0] = 0;
if (!data)
return 0;
// skip whitespace
skipwhite:
while ( (c = *data) <= ' ')
{
if (c == 0)
{
com_eof = true;
return 0; // 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;
}
const char* Get_COM_Token()
{
return com_token;
}
const char *debugname;
void setSpecialLoad(EntityClass *e, const char* pWhat, CopiedString& p)
{
// Hydra: removed some amazingly bad cstring usage, whoever wrote that
// needs to be taken out and shot.
char *pText = 0;
char *where = 0;
where = strstr(e->comments(),pWhat);
if (!where)
return;
pText = where + strlen(pWhat);
if (*pText == '\"')
pText++;
where = strchr(pText,'\"');
if (where)
{
p = CopiedString(pText, where);
}
else
{
p = pText;
}
}
#include "eclasslib.h"
/*
the classname, color triple, and bounding box are parsed out of comments
A ? size means take the exact brush size.
/ *QUAKED <classname> (0 0 0) ?
/ *QUAKED <classname> (0 0 0) (-8 -8 -8) (8 8 8)
Flag names can follow the size description:
/ *QUAKED func_door (0 .5 .8) ? START_OPEN STONE_SOUND DOOR_DONT_LINK GOLD_KEY SILVER_KEY
*/
EntityClass *Eclass_InitFromText (const char *text)
{
EntityClass* e = Eclass_Alloc();
e->free = &Eclass_Free;
// grab the name
text = COM_Parse (text);
e->m_name = Get_COM_Token();
debugname = e->name();
{
// grab the color, reformat as texture name
int r = sscanf (text," (%f %f %f)", &e->color[0], &e->color[1], &e->color[2]);
if (r != 3)
return e;
eclass_capture_state(e);
}
while (*text != ')')
{
if (!*text) {
return 0;
}
text++;
}
text++;
// get the size
text = COM_Parse (text);
if (Get_COM_Token()[0] == '(')
{ // parse the size as two vectors
e->fixedsize = true;
int r = sscanf (text,"%f %f %f) (%f %f %f)", &e->mins[0], &e->mins[1], &e->mins[2],
&e->maxs[0], &e->maxs[1], &e->maxs[2]);
if (r != 6) {
return 0;
}
for (int i=0 ; i<2 ; i++)
{
while (*text != ')')
{
if (!*text) {
return 0;
}
text++;
}
text++;
}
}
char parms[256];
// get the flags
{
// copy to the first /n
char* p = parms;
while (*text && *text != '\n')
*p++ = *text++;
*p = 0;
text++;
}
{
// any remaining words are parm flags
const char* p = parms;
for (std::size_t i=0 ; i<MAX_FLAGS ; i++)
{
p = COM_Parse (p);
if (!p)
break;
strcpy (e->flagnames[i], Get_COM_Token());
}
}
e->m_comments = text;
setSpecialLoad(e, "model=", e->m_modelpath);
StringOutputStream buffer(string_length(e->m_modelpath.c_str()));
buffer << PathCleaned(e->m_modelpath.c_str());
e->m_modelpath = buffer.c_str();
if(!e->fixedsize)
{
EntityClass_insertAttribute(*e, "angle", EntityClassAttribute("direction", "Direction", "0"));
}
else
{
EntityClass_insertAttribute(*e, "angle", EntityClassAttribute("angle", "Yaw Angle", "0"));
}
EntityClass_insertAttribute(*e, "model", EntityClassAttribute("model", "Model"));
EntityClass_insertAttribute(*e, "noise", EntityClassAttribute("sound", "Sound"));
return e;
}
void Eclass_ScanFile (EntityClassCollector& collector, const char *filename)
{
EntityClass *e;
TextFileInputStream inputFile(filename);
if(inputFile.failed())
{
globalErrorStream() << "ScanFile: " << filename << " not found\n";
return;
}
globalOutputStream() << "ScanFile: " << filename << "\n";
enum EParserState
{
eParseDefault,
eParseSolidus,
eParseComment,
eParseQuakeED,
eParseEntityClass,
eParseEntityClassEnd,
} state = eParseDefault;
const char* quakeEd = "QUAKED";
const char* p = 0;
StringBuffer buffer;
SingleCharacterInputStream<TextFileInputStream> bufferedInput(inputFile);
for(;;)
{
char c;
if(!bufferedInput.readChar(c))
{
break;
}
switch(state)
{
case eParseDefault:
if(c == '/')
{
state = eParseSolidus;
}
break;
case eParseSolidus:
if(c == '/')
{
state = eParseComment;
}
else if(c == '*')
{
p = quakeEd;
state = eParseQuakeED;
}
break;
case eParseComment:
if(c == '\n')
{
state = eParseDefault;
}
break;
case eParseQuakeED:
if(c == *p)
{
if(*(++p) == '\0')
{
state = eParseEntityClass;
}
}
else
{
state = eParseDefault;
}
break;
case eParseEntityClass:
if(c == '*')
{
state = eParseEntityClassEnd;
}
else
{
buffer.push_back(c);
}
break;
case eParseEntityClassEnd:
if(c == '/')
{
e = Eclass_InitFromText(buffer.c_str());
state = eParseDefault;
if (e)
collector.insert(e);
else
globalErrorStream() << "Error parsing: " << debugname << " in " << filename << "\n";
buffer.clear();
state = eParseDefault;
}
else
{
buffer.push_back('*');
buffer.push_back(c);
state = eParseEntityClass;
}
break;
}
}
}

25
radiant/eclass_def.h Normal file
View File

@@ -0,0 +1,25 @@
/*
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
*/
#if !defined(INCLUDED_ECLASS_DEF_H)
#define INCLUDED_ECLASS_DEF_H
#endif

812
radiant/eclass_doom3.cpp Normal file
View File

@@ -0,0 +1,812 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#include "eclass_doom3.h"
#include "debugging/debugging.h"
#include <map>
#include "ifilesystem.h"
#include "iscriplib.h"
#include "iarchive.h"
#include "qerplugin.h"
#include "generic/callback.h"
#include "string/string.h"
#include "eclasslib.h"
#include "os/path.h"
#include "os/dir.h"
#include "stream/stringstream.h"
#include "moduleobservers.h"
#include "stringio.h"
class RawString
{
const char* m_value;
public:
RawString(const char* value) : m_value(value)
{
}
const char* c_str() const
{
return m_value;
}
};
inline bool operator<(const RawString& self, const RawString& other)
{
return string_less_nocase(self.c_str(), other.c_str());
}
typedef std::map<RawString, EntityClass*> EntityClasses;
EntityClasses g_EntityClassDoom3_classes;
EntityClass *g_EntityClassDoom3_bad = 0;
void EntityClassDoom3_clear()
{
for(EntityClasses::iterator i = g_EntityClassDoom3_classes.begin(); i != g_EntityClassDoom3_classes.end(); ++i)
{
(*i).second->free((*i).second);
}
g_EntityClassDoom3_classes.clear();
}
// entityClass will be inserted only if another of the same name does not already exist.
// if entityClass was inserted, the same object is returned, otherwise the already-existing object is returned.
EntityClass* EntityClassDoom3_insertUnique(EntityClass* entityClass)
{
return (*g_EntityClassDoom3_classes.insert(EntityClasses::value_type(entityClass->name(), entityClass)).first).second;
}
void EntityClassDoom3_forEach(EntityClassVisitor& visitor)
{
for(EntityClasses::iterator i = g_EntityClassDoom3_classes.begin(); i != g_EntityClassDoom3_classes.end(); ++i)
{
visitor.visit((*i).second);
}
}
void EntityClassDoom3_parseUnknown(Tokeniser& tokeniser)
{
//const char* name =
tokeniser.getToken();
//globalOutputStream() << "parsing unknown block " << makeQuoted(name) << "\n";
const char* token = tokeniser.getToken();
ASSERT_MESSAGE(string_equal(token, "{"), "error parsing entity definition");
tokeniser.nextLine();
std::size_t depth = 1;
for(;;)
{
const char* token = tokeniser.getToken();
if(string_equal(token, "}"))
{
if(--depth == 0)
{
tokeniser.nextLine();
break;
}
}
else if(string_equal(token, "{"))
{
++depth;
}
tokeniser.nextLine();
}
}
class Model
{
public:
bool m_resolved;
CopiedString m_mesh;
CopiedString m_skin;
CopiedString m_parent;
typedef std::map<CopiedString, CopiedString> Anims;
Anims m_anims;
Model() : m_resolved(false)
{
}
};
typedef std::map<CopiedString, Model> Models;
Models g_models;
void Model_resolveInheritance(const char* name, Model& model)
{
if(model.m_resolved == false)
{
model.m_resolved = true;
if(!string_empty(model.m_parent.c_str()))
{
Models::iterator i = g_models.find(model.m_parent);
if(i == g_models.end())
{
globalErrorStream() << "model " << name << " inherits unknown model " << model.m_parent.c_str() << "\n";
}
else
{
Model_resolveInheritance((*i).first.c_str(), (*i).second);
model.m_mesh = (*i).second.m_mesh;
model.m_skin = (*i).second.m_skin;
}
}
}
}
void EntityClassDoom3_parseModel(Tokeniser& tokeniser)
{
const char* name = tokeniser.getToken();
Model& model = g_models[name];
const char* token = tokeniser.getToken();
ASSERT_MESSAGE(string_equal(token, "{"), "error parsing model definition");
tokeniser.nextLine();
for(;;)
{
const char* parameter = tokeniser.getToken();
if(string_equal(parameter, "}"))
{
tokeniser.nextLine();
break;
}
else if(string_equal(parameter, "inherit"))
{
model.m_parent = tokeniser.getToken();
}
else if(string_equal(parameter, "remove"))
{
//const char* remove =
tokeniser.getToken();
}
else if(string_equal(parameter, "mesh"))
{
model.m_mesh = tokeniser.getToken();
}
else if(string_equal(parameter, "skin"))
{
model.m_skin = tokeniser.getToken();
}
else if(string_equal(parameter, "offset"))
{
tokeniser.getToken(); // (
tokeniser.getToken();
tokeniser.getToken();
tokeniser.getToken();
tokeniser.getToken(); // )
tokeniser.nextLine();
}
else if(string_equal(parameter, "channel"))
{
//const char* channelName =
tokeniser.getToken();
tokeniser.getToken(); // (
for(;;)
{
const char* end = tokeniser.getToken();
if(string_equal(end, ")"))
{
tokeniser.nextLine();
break;
}
}
}
else if(string_equal(parameter, "anim"))
{
CopiedString animName(tokeniser.getToken());
const char* animFile = tokeniser.getToken();
model.m_anims.insert(Model::Anims::value_type(animName, animFile));
const char* token = tokeniser.getToken();
while(string_equal(token, ","))
{
animFile = tokeniser.getToken();
token = tokeniser.getToken();
}
if(string_equal(token, "{"))
{
for(;;)
{
const char* end = tokeniser.getToken();
if(string_equal(end, "}"))
{
tokeniser.nextLine();
break;
}
tokeniser.nextLine();
}
}
else
{
tokeniser.ungetToken();
}
}
else
{
ERROR_MESSAGE("unknown model parameter: " << makeQuoted(parameter));
}
tokeniser.nextLine();
}
}
inline bool char_isSpaceOrTab(char c)
{
return c == ' ' || c == '\t';
}
inline bool char_isNotSpaceOrTab(char c)
{
return !char_isSpaceOrTab(c);
}
template<typename Predicate>
inline const char* string_find_if(const char* string, Predicate predicate)
{
for(; *string != 0; ++string)
{
if(predicate(*string))
{
return string;
}
}
return string;
}
inline const char* string_findFirstSpaceOrTab(const char* string)
{
return string_find_if(string, char_isSpaceOrTab);
}
inline const char* string_findFirstNonSpaceOrTab(const char* string)
{
return string_find_if(string, char_isNotSpaceOrTab);
}
void EntityClassDoom3_parseEntityDef(Tokeniser& tokeniser)
{
EntityClass* entityClass = Eclass_Alloc();
entityClass->free = &Eclass_Free;
entityClass->m_name = tokeniser.getToken();
const char* token = tokeniser.getToken();
ASSERT_MESSAGE(string_equal(token, "{"), "error parsing entity definition");
tokeniser.nextLine();
StringOutputStream usage(256);
StringOutputStream description(256);
CopiedString* currentDescription = 0;
StringOutputStream* currentString = 0;
for(;;)
{
const char* key = tokeniser.getToken();
const char* last = string_findFirstSpaceOrTab(key);
CopiedString first(key, last);
if(!string_empty(last))
{
last = string_findFirstNonSpaceOrTab(last);
}
if(currentString != 0 && string_equal(key, "\\"))
{
tokeniser.nextLine();
*currentString << " " << tokeniser.getToken();
continue;
}
if(currentDescription != 0)
{
*currentDescription = description.c_str();
description.clear();
currentDescription = 0;
}
currentString = 0;
if(string_equal(key, "}"))
{
tokeniser.nextLine();
break;
}
else if(string_equal(key, "model"))
{
entityClass->fixedsize = true;
StringOutputStream buffer(256);
buffer << PathCleaned(tokeniser.getToken());
entityClass->m_modelpath = buffer.c_str();
}
else if(string_equal(key, "editor_color"))
{
const char* value = tokeniser.getToken();
if(!string_empty(value))
{
entityClass->colorSpecified = true;
bool success = string_parse_vector3(value, entityClass->color);
ASSERT_MESSAGE(success, "editor_color: parse error");
}
}
else if(string_equal(key, "editor_ragdoll"))
{
//bool ragdoll = atoi(tokeniser.getToken()) != 0;
tokeniser.getToken();
}
else if(string_equal(key, "editor_mins"))
{
entityClass->sizeSpecified = true;
const char* value = tokeniser.getToken();
if(!string_empty(value) && !string_equal(value, "?"))
{
entityClass->fixedsize = true;
bool success = string_parse_vector3(value, entityClass->mins);
ASSERT_MESSAGE(success, "editor_mins: parse error");
}
}
else if(string_equal(key, "editor_maxs"))
{
entityClass->sizeSpecified = true;
const char* value = tokeniser.getToken();
if(!string_empty(value) && !string_equal(value, "?"))
{
entityClass->fixedsize = true;
bool success = string_parse_vector3(value, entityClass->maxs);
ASSERT_MESSAGE(success, "editor_maxs: parse error");
}
}
else if(string_equal(key, "editor_usage"))
{
const char* value = tokeniser.getToken();
usage << value;
currentString = &usage;
}
else if(string_equal_n(key, "editor_usage", 12))
{
const char* value = tokeniser.getToken();
usage << "\n" << value;
currentString = &usage;
}
else if(string_equal(key, "editor_rotatable")
|| string_equal(key, "editor_showangle")
|| string_equal(key, "editor_mover")
|| string_equal(key, "editor_model")
|| string_equal(key, "editor_material")
|| string_equal(key, "editor_combatnode")
|| (!string_empty(last) && string_equal(first.c_str(), "editor_gui"))
|| string_equal_n(key, "editor_copy", 11))
{
tokeniser.getToken();
}
else if(!string_empty(last) && (string_equal(first.c_str(), "editor_var") || string_equal(first.c_str(), "editor_string")))
{
EntityClassAttribute& attribute = EntityClass_insertAttribute(*entityClass, last).second;
attribute.m_type = "string";
currentDescription = &attribute.m_description;
currentString = &description;
description << tokeniser.getToken();
}
else if(!string_empty(last) && string_equal(first.c_str(), "editor_float"))
{
EntityClassAttribute& attribute = EntityClass_insertAttribute(*entityClass, last).second;
attribute.m_type = "string";
currentDescription = &attribute.m_description;
currentString = &description;
description << tokeniser.getToken();
}
else if(!string_empty(last) && string_equal(first.c_str(), "editor_snd"))
{
EntityClassAttribute& attribute = EntityClass_insertAttribute(*entityClass, last).second;
attribute.m_type = "sound";
currentDescription = &attribute.m_description;
currentString = &description;
description << tokeniser.getToken();
}
else if(!string_empty(last) && string_equal(first.c_str(), "editor_bool"))
{
EntityClassAttribute& attribute = EntityClass_insertAttribute(*entityClass, last).second;
attribute.m_type = "boolean";
currentDescription = &attribute.m_description;
currentString = &description;
description << tokeniser.getToken();
}
else if(!string_empty(last) && string_equal(first.c_str(), "editor_int"))
{
EntityClassAttribute& attribute = EntityClass_insertAttribute(*entityClass, last).second;
attribute.m_type = "integer";
currentDescription = &attribute.m_description;
currentString = &description;
description << tokeniser.getToken();
}
else if(!string_empty(last) && string_equal(first.c_str(), "editor_model"))
{
EntityClassAttribute& attribute = EntityClass_insertAttribute(*entityClass, last).second;
attribute.m_type = "model";
currentDescription = &attribute.m_description;
currentString = &description;
description << tokeniser.getToken();
}
else if(!string_empty(last) && string_equal(first.c_str(), "editor_color"))
{
EntityClassAttribute& attribute = EntityClass_insertAttribute(*entityClass, last).second;
attribute.m_type = "color";
currentDescription = &attribute.m_description;
currentString = &description;
description << tokeniser.getToken();
}
else if(!string_empty(last) && (string_equal(first.c_str(), "editor_material") || string_equal(first.c_str(), "editor_mat")))
{
EntityClassAttribute& attribute = EntityClass_insertAttribute(*entityClass, last).second;
attribute.m_type = "shader";
currentDescription = &attribute.m_description;
currentString = &description;
description << tokeniser.getToken();
}
else if(string_equal(key, "inherit"))
{
entityClass->inheritanceResolved = false;
ASSERT_MESSAGE(entityClass->m_parent.empty(), "only one 'inherit' supported per entityDef");
entityClass->m_parent.push_back(tokeniser.getToken());
}
// begin quake4-specific keys
else if(string_equal(key, "editor_targetonsel"))
{
//const char* value =
tokeniser.getToken();
}
else if(string_equal(key, "editor_menu"))
{
//const char* value =
tokeniser.getToken();
}
else if(string_equal(key, "editor_ignore"))
{
//const char* value =
tokeniser.getToken();
}
// end quake4-specific keys
else
{
ASSERT_MESSAGE(!string_equal_n(key, "editor_", 7), "unsupported editor key: " << makeQuoted(key));
EntityClassAttribute& attribute = EntityClass_insertAttribute(*entityClass, key).second;
attribute.m_type = "string";
attribute.m_value = tokeniser.getToken();
}
tokeniser.nextLine();
}
entityClass->m_comments = usage.c_str();
if(string_equal(entityClass->m_name.c_str(), "light"))
{
{
EntityClassAttribute& attribute = EntityClass_insertAttribute(*entityClass, "light_radius").second;
attribute.m_type = "vector3";
attribute.m_value = "300 300 300";
}
{
EntityClassAttribute& attribute = EntityClass_insertAttribute(*entityClass, "light_center").second;
attribute.m_type = "vector3";
}
{
EntityClassAttribute& attribute = EntityClass_insertAttribute(*entityClass, "noshadows").second;
attribute.m_type = "boolean";
attribute.m_value = "0";
}
{
EntityClassAttribute& attribute = EntityClass_insertAttribute(*entityClass, "nospecular").second;
attribute.m_type = "boolean";
attribute.m_value = "0";
}
{
EntityClassAttribute& attribute = EntityClass_insertAttribute(*entityClass, "nodiffuse").second;
attribute.m_type = "boolean";
attribute.m_value = "0";
}
{
EntityClassAttribute& attribute = EntityClass_insertAttribute(*entityClass, "falloff").second;
attribute.m_type = "real";
}
}
EntityClass* inserted = EntityClassDoom3_insertUnique(entityClass);
if(inserted != entityClass)
{
globalErrorStream() << "entityDef " << entityClass->name() << " is already defined, second definition ignored\n";
eclass_capture_state(entityClass); // finish constructing the entity so that it can be destroyed cleanly.
entityClass->free(entityClass);
}
}
void EntityClassDoom3_parse(TextInputStream& inputStream)
{
Tokeniser& tokeniser = GlobalScriptLibrary().m_pfnNewScriptTokeniser(inputStream);
tokeniser.nextLine();
for(;;)
{
const char* blockType = tokeniser.getToken();
if(blockType == 0)
{
break;
}
if(string_equal(blockType, "entityDef"))
{
EntityClassDoom3_parseEntityDef(tokeniser);
}
else if(string_equal(blockType, "model"))
{
EntityClassDoom3_parseModel(tokeniser);
}
else
{
EntityClassDoom3_parseUnknown(tokeniser);
}
}
tokeniser.release();
}
void EntityClassDoom3_loadFile(const char* filename)
{
globalOutputStream() << "parsing entity classes from " << makeQuoted(filename) << "\n";
StringOutputStream fullname(256);
fullname << "def/" << filename;
ArchiveTextFile* file = GlobalFileSystem().openTextFile(fullname.c_str());
if(file != 0)
{
EntityClassDoom3_parse(file->getInputStream());
file->release();
}
}
EntityClass* EntityClassDoom3_findOrInsert(const char *name, bool has_brushes)
{
ASSERT_NOTNULL(name);
if(string_empty(name))
{
return g_EntityClassDoom3_bad;
}
EntityClasses::iterator i = g_EntityClassDoom3_classes.find(name);
if(i != g_EntityClassDoom3_classes.end()
//&& string_equal((*i).first, name)
)
{
return (*i).second;
}
EntityClass* e = EntityClass_Create_Default(name, has_brushes);
EntityClass* inserted = EntityClassDoom3_insertUnique(e);
ASSERT_MESSAGE(inserted == e, "");
return inserted;
}
const ListAttributeType* EntityClassDoom3_findListType(const char* name)
{
return 0;
}
void EntityClass_resolveInheritance(EntityClass* derivedClass)
{
if(derivedClass->inheritanceResolved == false)
{
derivedClass->inheritanceResolved = true;
EntityClasses::iterator i = g_EntityClassDoom3_classes.find(derivedClass->m_parent.front().c_str());
if(i == g_EntityClassDoom3_classes.end())
{
globalErrorStream() << "failed to find entityDef " << makeQuoted(derivedClass->m_parent.front().c_str()) << " inherited by " << makeQuoted(derivedClass->m_name.c_str()) << "\n";
}
else
{
EntityClass* parentClass = (*i).second;
EntityClass_resolveInheritance(parentClass);
if(!derivedClass->colorSpecified)
{
derivedClass->colorSpecified = parentClass->colorSpecified;
derivedClass->color = parentClass->color;
}
if(!derivedClass->sizeSpecified)
{
derivedClass->sizeSpecified = parentClass->sizeSpecified;
derivedClass->mins = parentClass->mins;
derivedClass->maxs = parentClass->maxs;
derivedClass->fixedsize = parentClass->fixedsize;
}
for(EntityClassAttributes::iterator j = parentClass->m_attributes.begin(); j != parentClass->m_attributes.end(); ++j)
{
EntityClass_insertAttribute(*derivedClass, (*j).first.c_str(), (*j).second);
}
}
}
}
class EntityClassDoom3 : public ModuleObserver
{
std::size_t m_unrealised;
ModuleObservers m_observers;
public:
EntityClassDoom3() : m_unrealised(2)
{
}
void realise()
{
if(--m_unrealised == 0)
{
globalOutputStream() << "searching vfs directory " << makeQuoted("def") << " for *.def\n";
GlobalFileSystem().forEachFile("def/", "def", FreeCaller1<const char*, EntityClassDoom3_loadFile>());
{
for(Models::iterator i = g_models.begin(); i != g_models.end(); ++i)
{
Model_resolveInheritance((*i).first.c_str(), (*i).second);
}
}
{
for(EntityClasses::iterator i = g_EntityClassDoom3_classes.begin(); i != g_EntityClassDoom3_classes.end(); ++i)
{
EntityClass_resolveInheritance((*i).second);
if(!string_empty((*i).second->m_modelpath.c_str()))
{
Models::iterator j = g_models.find((*i).second->m_modelpath);
if(j != g_models.end())
{
(*i).second->m_modelpath = (*j).second.m_mesh;
(*i).second->m_skin = (*j).second.m_skin;
}
}
eclass_capture_state((*i).second);
StringOutputStream usage(256);
usage << "-------- KEYS --------\n";
for(EntityClassAttributes::iterator j = (*i).second->m_attributes.begin(); j != (*i).second->m_attributes.end(); ++j)
{
const char* name = EntityClassAttributePair_getName(*j);
const char* description = EntityClassAttributePair_getDescription(*j);
if(!string_equal(name, description))
{
usage << EntityClassAttributePair_getName(*j) << " : " << EntityClassAttributePair_getDescription(*j) << "\n";
}
}
(*i).second->m_comments = usage.c_str();
}
}
m_observers.realise();
}
}
void unrealise()
{
if(++m_unrealised == 1)
{
m_observers.unrealise();
EntityClassDoom3_clear();
}
}
void attach(ModuleObserver& observer)
{
m_observers.attach(observer);
}
void detach(ModuleObserver& observer)
{
m_observers.detach(observer);
}
};
EntityClassDoom3 g_EntityClassDoom3;
void EntityClassDoom3_attach(ModuleObserver& observer)
{
g_EntityClassDoom3.attach(observer);
}
void EntityClassDoom3_detach(ModuleObserver& observer)
{
g_EntityClassDoom3.detach(observer);
}
void EntityClassDoom3_realise()
{
g_EntityClassDoom3.realise();
}
void EntityClassDoom3_unrealise()
{
g_EntityClassDoom3.unrealise();
}
void EntityClassDoom3_construct()
{
GlobalFileSystem().attach(g_EntityClassDoom3);
// start by creating the default unknown eclass
g_EntityClassDoom3_bad = EClass_Create("UNKNOWN_CLASS", Vector3(0.0f, 0.5f, 0.0f), "");
EntityClassDoom3_realise();
}
void EntityClassDoom3_destroy()
{
EntityClassDoom3_unrealise();
g_EntityClassDoom3_bad->free(g_EntityClassDoom3_bad);
GlobalFileSystem().detach(g_EntityClassDoom3);
}
class EntityClassDoom3Dependencies : public GlobalFileSystemModuleRef, public GlobalShaderCacheModuleRef
{
};
class EntityClassDoom3API
{
EntityClassManager m_eclassmanager;
public:
typedef EntityClassManager Type;
STRING_CONSTANT(Name, "doom3");
EntityClassDoom3API()
{
EntityClassDoom3_construct();
m_eclassmanager.findOrInsert = &EntityClassDoom3_findOrInsert;
m_eclassmanager.findListType = &EntityClassDoom3_findListType;
m_eclassmanager.forEach = &EntityClassDoom3_forEach;
m_eclassmanager.attach = &EntityClassDoom3_attach;
m_eclassmanager.detach = &EntityClassDoom3_detach;
m_eclassmanager.realise = &EntityClassDoom3_realise;
m_eclassmanager.unrealise = &EntityClassDoom3_unrealise;
}
~EntityClassDoom3API()
{
EntityClassDoom3_destroy();
}
EntityClassManager* getTable()
{
return &m_eclassmanager;
}
};
#include "modulesystem/singletonmodule.h"
#include "modulesystem/moduleregistry.h"
typedef SingletonModule<EntityClassDoom3API, EntityClassDoom3Dependencies> EntityClassDoom3Module;
typedef Static<EntityClassDoom3Module> StaticEntityClassDoom3Module;
StaticRegisterModule staticRegisterEntityClassDoom3(StaticEntityClassDoom3Module::instance());

25
radiant/eclass_doom3.h Normal file
View File

@@ -0,0 +1,25 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#if !defined(INCLUDED_ECLASS_DOOM3_H)
#define INCLUDED_ECLASS_DOOM3_H
#endif

807
radiant/eclass_fgd.cpp Normal file
View File

@@ -0,0 +1,807 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#include "eclass_fgd.h"
#include "debugging/debugging.h"
#include <map>
#include "ifilesystem.h"
#include "iscriplib.h"
#include "qerplugin.h"
#include "string/string.h"
#include "eclasslib.h"
#include "os/path.h"
#include "os/dir.h"
#include "stream/stringstream.h"
#include "moduleobservers.h"
#include "stringio.h"
#include "stream/textfilestream.h"
namespace
{
typedef std::map<const char*, EntityClass*, RawStringLessNoCase> EntityClasses;
EntityClasses g_EntityClassFGD_classes;
typedef std::map<const char*, EntityClass*, RawStringLess> BaseClasses;
BaseClasses g_EntityClassFGD_bases;
EntityClass *g_EntityClassFGD_bad = 0;
typedef std::map<CopiedString, ListAttributeType> ListAttributeTypes;
ListAttributeTypes g_listTypesFGD;
}
void EntityClassFGD_clear()
{
for(BaseClasses::iterator i = g_EntityClassFGD_bases.begin(); i != g_EntityClassFGD_bases.end(); ++i)
{
(*i).second->free((*i).second);
}
g_EntityClassFGD_bases.clear();
g_listTypesFGD.clear();
}
EntityClass* EntityClassFGD_insertUniqueBase(EntityClass* entityClass)
{
std::pair<BaseClasses::iterator, bool> result = g_EntityClassFGD_bases.insert(BaseClasses::value_type(entityClass->name(), entityClass));
if(!result.second)
{
globalErrorStream() << "duplicate base class: " << makeQuoted(entityClass->name()) << "\n";
//eclass_capture_state(entityClass);
//entityClass->free(entityClass);
}
return (*result.first).second;
}
EntityClass* EntityClassFGD_insertUnique(EntityClass* entityClass)
{
EntityClassFGD_insertUniqueBase(entityClass);
std::pair<EntityClasses::iterator, bool> result = g_EntityClassFGD_classes.insert(EntityClasses::value_type(entityClass->name(), entityClass));
if(!result.second)
{
globalErrorStream() << "duplicate entity class: " << makeQuoted(entityClass->name()) << "\n";
eclass_capture_state(entityClass);
entityClass->free(entityClass);
}
return (*result.first).second;
}
void EntityClassFGD_forEach(EntityClassVisitor& visitor)
{
for(EntityClasses::iterator i = g_EntityClassFGD_classes.begin(); i != g_EntityClassFGD_classes.end(); ++i)
{
visitor.visit((*i).second);
}
}
inline bool EntityClassFGD_parseToken(Tokeniser& tokeniser, const char* token)
{
return string_equal(tokeniser.getToken(), token);
}
#define PARSE_ERROR "error parsing entity class definition"
void EntityClassFGD_parseSplitString(Tokeniser& tokeniser, CopiedString& string)
{
StringOutputStream buffer(256);
for(;;)
{
buffer << tokeniser.getToken();
if(!string_equal(tokeniser.getToken(), "+"))
{
tokeniser.ungetToken();
string = buffer.c_str();
return;
}
}
}
void EntityClassFGD_parseClass(Tokeniser& tokeniser, bool fixedsize, bool isBase)
{
EntityClass* entityClass = Eclass_Alloc();
entityClass->free = &Eclass_Free;
entityClass->fixedsize = fixedsize;
entityClass->inheritanceResolved = false;
entityClass->mins = Vector3(-8, -8, -8);
entityClass->maxs = Vector3(8, 8, 8);
for(;;)
{
const char* property = tokeniser.getToken();
if(string_equal(property, "="))
{
break;
}
else if(string_equal(property, "base"))
{
ASSERT_MESSAGE(EntityClassFGD_parseToken(tokeniser, "("), PARSE_ERROR);
for(;;)
{
const char* base = tokeniser.getToken();
if(string_equal(base, ")"))
{
break;
}
else if(!string_equal(base, ","))
{
entityClass->m_parent.push_back(base);
}
}
}
else if(string_equal(property, "size"))
{
entityClass->sizeSpecified = true;
ASSERT_MESSAGE(EntityClassFGD_parseToken(tokeniser, "("), PARSE_ERROR);
Tokeniser_getFloat(tokeniser, entityClass->mins.x());
Tokeniser_getFloat(tokeniser, entityClass->mins.y());
Tokeniser_getFloat(tokeniser, entityClass->mins.z());
const char* token = tokeniser.getToken();
if(string_equal(token, ","))
{
Tokeniser_getFloat(tokeniser, entityClass->maxs.x());
Tokeniser_getFloat(tokeniser, entityClass->maxs.y());
Tokeniser_getFloat(tokeniser, entityClass->maxs.z());
ASSERT_MESSAGE(EntityClassFGD_parseToken(tokeniser, ")"), PARSE_ERROR);
}
else
{
entityClass->maxs = entityClass->mins;
vector3_negate(entityClass->mins);
ASSERT_MESSAGE(string_equal(token, ")"), "");
}
}
else if(string_equal(property, "color"))
{
entityClass->colorSpecified = true;
ASSERT_MESSAGE(EntityClassFGD_parseToken(tokeniser, "("), PARSE_ERROR);
Tokeniser_getFloat(tokeniser, entityClass->color.x());
entityClass->color.x() /= 256.0;
Tokeniser_getFloat(tokeniser, entityClass->color.y());
entityClass->color.y() /= 256.0;
Tokeniser_getFloat(tokeniser, entityClass->color.z());
entityClass->color.z() /= 256.0;
ASSERT_MESSAGE(EntityClassFGD_parseToken(tokeniser, ")"), PARSE_ERROR);
}
else if(string_equal(property, "iconsprite"))
{
ASSERT_MESSAGE(EntityClassFGD_parseToken(tokeniser, "("), PARSE_ERROR);
StringOutputStream buffer(256);
buffer << PathCleaned(tokeniser.getToken());
entityClass->m_modelpath = buffer.c_str();
ASSERT_MESSAGE(EntityClassFGD_parseToken(tokeniser, ")"), PARSE_ERROR);
}
else if(string_equal(property, "sprite")
|| string_equal(property, "decal")
// hl2 below
|| string_equal(property, "overlay")
|| string_equal(property, "light")
|| string_equal(property, "keyframe")
|| string_equal(property, "animator")
|| string_equal(property, "quadbounds"))
{
ASSERT_MESSAGE(EntityClassFGD_parseToken(tokeniser, "("), PARSE_ERROR);
ASSERT_MESSAGE(EntityClassFGD_parseToken(tokeniser, ")"), PARSE_ERROR);
}
// hl2 below
else if(string_equal(property, "sphere")
|| string_equal(property, "sweptplayerhull")
|| string_equal(property, "studio")
|| string_equal(property, "studioprop")
|| string_equal(property, "lightprop")
|| string_equal(property, "lightcone")
|| string_equal(property, "sidelist"))
{
ASSERT_MESSAGE(EntityClassFGD_parseToken(tokeniser, "("), PARSE_ERROR);
if(string_equal(tokeniser.getToken(), ")"))
{
tokeniser.ungetToken();
}
ASSERT_MESSAGE(EntityClassFGD_parseToken(tokeniser, ")"), PARSE_ERROR);
}
else if(string_equal(property, "line")
|| string_equal(property, "cylinder"))
{
ASSERT_MESSAGE(EntityClassFGD_parseToken(tokeniser, "("), PARSE_ERROR);
//const char* r =
tokeniser.getToken();
//const char* g =
tokeniser.getToken();
//const char* b =
tokeniser.getToken();
for(;;)
{
if(string_equal(tokeniser.getToken(), ")"))
{
tokeniser.ungetToken();
break;
}
//const char* name =
tokeniser.getToken();
}
ASSERT_MESSAGE(EntityClassFGD_parseToken(tokeniser, ")"), PARSE_ERROR);
}
else if(string_equal(property, "wirebox"))
{
ASSERT_MESSAGE(EntityClassFGD_parseToken(tokeniser, "("), PARSE_ERROR);
//const char* mins =
tokeniser.getToken();
ASSERT_MESSAGE(EntityClassFGD_parseToken(tokeniser, ","), PARSE_ERROR);
//const char* maxs =
tokeniser.getToken();
ASSERT_MESSAGE(EntityClassFGD_parseToken(tokeniser, ")"), PARSE_ERROR);
}
else if(string_equal(property, "halfgridsnap"))
{
}
else
{
ERROR_MESSAGE(PARSE_ERROR);
}
}
entityClass->m_name = tokeniser.getToken();
if(!isBase)
{
ASSERT_MESSAGE(EntityClassFGD_parseToken(tokeniser, ":"), PARSE_ERROR);
EntityClassFGD_parseSplitString(tokeniser, entityClass->m_comments);
}
tokeniser.nextLine();
ASSERT_MESSAGE(EntityClassFGD_parseToken(tokeniser, "["), PARSE_ERROR);
tokeniser.nextLine();
for(;;)
{
CopiedString key = tokeniser.getToken();
if(string_equal(key.c_str(), "]"))
{
tokeniser.nextLine();
break;
}
if(string_equal_nocase(key.c_str(), "input")
|| string_equal_nocase(key.c_str(), "output"))
{
const char* name = tokeniser.getToken();
if(!string_equal(name, "("))
{
ASSERT_MESSAGE(EntityClassFGD_parseToken(tokeniser, "("), PARSE_ERROR);
//const char* type =
tokeniser.getToken();
ASSERT_MESSAGE(EntityClassFGD_parseToken(tokeniser, ")"), PARSE_ERROR);
const char* descriptionSeparator = tokeniser.getToken();
if(string_equal(descriptionSeparator, ":"))
{
CopiedString description;
EntityClassFGD_parseSplitString(tokeniser, description);
}
else
{
tokeniser.ungetToken();
}
tokeniser.nextLine();
continue;
}
}
ASSERT_MESSAGE(EntityClassFGD_parseToken(tokeniser, "("), PARSE_ERROR);
CopiedString type = tokeniser.getToken();
ASSERT_MESSAGE(EntityClassFGD_parseToken(tokeniser, ")"), PARSE_ERROR);
if(string_equal_nocase(type.c_str(), "flags"))
{
EntityClassAttribute attribute;
ASSERT_MESSAGE(EntityClassFGD_parseToken(tokeniser, "="), PARSE_ERROR);
tokeniser.nextLine();
ASSERT_MESSAGE(EntityClassFGD_parseToken(tokeniser, "["), PARSE_ERROR);
tokeniser.nextLine();
for(;;)
{
const char* flag = tokeniser.getToken();
if(string_equal(flag, "]"))
{
tokeniser.nextLine();
break;
}
else
{
ASSERT_MESSAGE(EntityClassFGD_parseToken(tokeniser, ":"), PARSE_ERROR);
//const char* name =
tokeniser.getToken();
{
const char* defaultSeparator = tokeniser.getToken();
if(string_equal(defaultSeparator, ":"))
{
tokeniser.getToken();
{
const char* descriptionSeparator = tokeniser.getToken();
if(string_equal(descriptionSeparator, ":"))
{
EntityClassFGD_parseSplitString(tokeniser, attribute.m_description);
}
else
{
tokeniser.ungetToken();
}
}
}
else
{
tokeniser.ungetToken();
}
}
}
tokeniser.nextLine();
}
EntityClass_insertAttribute(*entityClass, key.c_str(), attribute);
}
else if(string_equal_nocase(type.c_str(), "choices"))
{
EntityClassAttribute attribute;
ASSERT_MESSAGE(EntityClassFGD_parseToken(tokeniser, ":"), PARSE_ERROR);
attribute.m_name = tokeniser.getToken();
const char* valueSeparator = tokeniser.getToken();
if(string_equal(valueSeparator, ":"))
{
const char* value = tokeniser.getToken();
if(!string_equal(value, ":"))
{
attribute.m_value = value;
}
else
{
tokeniser.ungetToken();
}
{
const char* descriptionSeparator = tokeniser.getToken();
if(string_equal(descriptionSeparator, ":"))
{
EntityClassFGD_parseSplitString(tokeniser, attribute.m_description);
}
else
{
tokeniser.ungetToken();
}
}
}
else
{
tokeniser.ungetToken();
}
ASSERT_MESSAGE(EntityClassFGD_parseToken(tokeniser, "="), PARSE_ERROR);
tokeniser.nextLine();
ASSERT_MESSAGE(EntityClassFGD_parseToken(tokeniser, "["), PARSE_ERROR);
tokeniser.nextLine();
StringOutputStream listTypeName(64);
listTypeName << entityClass->m_name.c_str() << "_" << attribute.m_name.c_str();
attribute.m_type = listTypeName.c_str();
ListAttributeType& listType = g_listTypesFGD[listTypeName.c_str()];
for(;;)
{
const char* value = tokeniser.getToken();
if(string_equal(value, "]"))
{
tokeniser.nextLine();
break;
}
else
{
CopiedString tmp(value);
ASSERT_MESSAGE(EntityClassFGD_parseToken(tokeniser, ":"), PARSE_ERROR);
const char* name = tokeniser.getToken();
listType.push_back(name, tmp.c_str());
}
tokeniser.nextLine();
}
for(ListAttributeType::const_iterator i = listType.begin(); i != listType.end(); ++i)
{
if(string_equal(attribute.m_value.c_str(), (*i).first.c_str()))
{
attribute.m_value = (*i).second.c_str();
}
}
EntityClass_insertAttribute(*entityClass, key.c_str(), attribute);
}
else if(string_equal_nocase(type.c_str(), "decal"))
{
}
else if(string_equal_nocase(type.c_str(), "string")
|| string_equal_nocase(type.c_str(), "integer")
|| string_equal_nocase(type.c_str(), "studio")
|| string_equal_nocase(type.c_str(), "sprite")
|| string_equal_nocase(type.c_str(), "color255")
|| string_equal_nocase(type.c_str(), "target_source")
|| string_equal_nocase(type.c_str(), "target_destination")
|| string_equal_nocase(type.c_str(), "sound")
// hl2 below
|| string_equal_nocase(type.c_str(), "angle")
|| string_equal_nocase(type.c_str(), "origin")
|| string_equal_nocase(type.c_str(), "float")
|| string_equal_nocase(type.c_str(), "node_dest")
|| string_equal_nocase(type.c_str(), "filterclass")
|| string_equal_nocase(type.c_str(), "vector")
|| string_equal_nocase(type.c_str(), "sidelist")
|| string_equal_nocase(type.c_str(), "material")
|| string_equal_nocase(type.c_str(), "vecline")
|| string_equal_nocase(type.c_str(), "axis")
|| string_equal_nocase(type.c_str(), "npcclass")
|| string_equal_nocase(type.c_str(), "target_name_or_class")
|| string_equal_nocase(type.c_str(), "pointentityclass")
|| string_equal_nocase(type.c_str(), "scene"))
{
if(!string_equal(tokeniser.getToken(), "readonly"))
{
tokeniser.ungetToken();
}
ASSERT_MESSAGE(EntityClassFGD_parseToken(tokeniser, ":"), PARSE_ERROR);
const char* attributeType = "string";
if(string_equal_nocase(type.c_str(), "studio"))
{
attributeType = "model";
}
EntityClassAttribute attribute;
attribute.m_type = attributeType;
attribute.m_name = tokeniser.getToken();
const char* defaultSeparator = tokeniser.getToken();
if(string_equal(defaultSeparator, ":"))
{
const char* value = tokeniser.getToken();
if(!string_equal(value, ":"))
{
attribute.m_value = value;
}
else
{
tokeniser.ungetToken();
}
{
const char* descriptionSeparator = tokeniser.getToken();
if(string_equal(descriptionSeparator, ":"))
{
EntityClassFGD_parseSplitString(tokeniser, attribute.m_description);
}
else
{
tokeniser.ungetToken();
}
}
}
else
{
tokeniser.ungetToken();
}
EntityClass_insertAttribute(*entityClass, key.c_str(), attribute);
}
else
{
ERROR_MESSAGE("unknown key type: " << makeQuoted(type.c_str()));
}
tokeniser.nextLine();
}
if(isBase)
{
EntityClassFGD_insertUniqueBase(entityClass);
}
else
{
EntityClassFGD_insertUnique(entityClass);
}
}
void EntityClassFGD_loadFile(const char* filename);
void EntityClassFGD_parse(TextInputStream& inputStream, const char* path)
{
Tokeniser& tokeniser = GlobalScriptLibrary().m_pfnNewScriptTokeniser(inputStream);
tokeniser.nextLine();
for(;;)
{
const char* blockType = tokeniser.getToken();
if(blockType == 0)
{
break;
}
if(string_equal(blockType, "@SolidClass"))
{
EntityClassFGD_parseClass(tokeniser, false, false);
}
else if(string_equal(blockType, "@BaseClass"))
{
EntityClassFGD_parseClass(tokeniser, false, true);
}
else if(string_equal(blockType, "@PointClass")
// hl2 below
|| string_equal(blockType, "@KeyFrameClass")
|| string_equal(blockType, "@MoveClass")
|| string_equal(blockType, "@FilterClass")
|| string_equal(blockType, "@NPCClass"))
{
EntityClassFGD_parseClass(tokeniser, true, false);
}
// hl2 below
else if(string_equal(blockType, "@include"))
{
StringOutputStream includePath(256);
includePath << StringRange(path, path_get_filename_start(path));
includePath << tokeniser.getToken();
EntityClassFGD_loadFile(includePath.c_str());
}
else if(string_equal(blockType, "@mapsize"))
{
ASSERT_MESSAGE(EntityClassFGD_parseToken(tokeniser, "("), PARSE_ERROR);
//const char* min =
tokeniser.getToken();
ASSERT_MESSAGE(EntityClassFGD_parseToken(tokeniser, ","), PARSE_ERROR);
//const char* max =
tokeniser.getToken();
ASSERT_MESSAGE(EntityClassFGD_parseToken(tokeniser, ")"), PARSE_ERROR);
}
else
{
ERROR_MESSAGE("unknown block type: " << makeQuoted(blockType));
}
}
tokeniser.release();
}
void EntityClassFGD_loadFile(const char* filename)
{
TextFileInputStream file(filename);
if(!file.failed())
{
globalOutputStream() << "parsing entity classes from " << makeQuoted(filename) << "\n";
EntityClassFGD_parse(file, filename);
}
}
EntityClass* EntityClassFGD_findOrInsert(const char *name, bool has_brushes)
{
ASSERT_NOTNULL(name);
if(string_empty(name))
{
return g_EntityClassFGD_bad;
}
EntityClasses::iterator i = g_EntityClassFGD_classes.find(name);
if(i != g_EntityClassFGD_classes.end()
//&& string_equal((*i).first, name)
)
{
return (*i).second;
}
EntityClass* e = EntityClass_Create_Default(name, has_brushes);
return EntityClassFGD_insertUnique(e);
}
const ListAttributeType* EntityClassFGD_findListType(const char *name)
{
ListAttributeTypes::iterator i = g_listTypesFGD.find(name);
if(i != g_listTypesFGD.end())
{
return &(*i).second;
}
return 0;
}
void EntityClassFGD_resolveInheritance(EntityClass* derivedClass)
{
if(derivedClass->inheritanceResolved == false)
{
derivedClass->inheritanceResolved = true;
for(StringList::iterator j = derivedClass->m_parent.begin(); j != derivedClass->m_parent.end(); ++j)
{
BaseClasses::iterator i = g_EntityClassFGD_bases.find((*j).c_str());
if(i == g_EntityClassFGD_bases.end())
{
globalErrorStream() << "failed to find entityDef " << makeQuoted((*j).c_str()) << " inherited by " << makeQuoted(derivedClass->m_name.c_str()) << "\n";
}
else
{
EntityClass* parentClass = (*i).second;
EntityClassFGD_resolveInheritance(parentClass);
if(!derivedClass->colorSpecified)
{
derivedClass->colorSpecified = parentClass->colorSpecified;
derivedClass->color = parentClass->color;
}
if(!derivedClass->sizeSpecified)
{
derivedClass->sizeSpecified = parentClass->sizeSpecified;
derivedClass->mins = parentClass->mins;
derivedClass->maxs = parentClass->maxs;
}
for(EntityClassAttributes::iterator k = parentClass->m_attributes.begin(); k != parentClass->m_attributes.end(); ++k)
{
EntityClass_insertAttribute(*derivedClass, (*k).first.c_str(), (*k).second);
}
}
}
}
}
class EntityClassFGD : public ModuleObserver
{
std::size_t m_unrealised;
ModuleObservers m_observers;
public:
EntityClassFGD() : m_unrealised(3)
{
}
void realise()
{
if(--m_unrealised == 0)
{
StringOutputStream filename(256);
filename << GlobalRadiant().getGameToolsPath() << GlobalRadiant().getGameName() << "/halflife.fgd";
EntityClassFGD_loadFile(filename.c_str());
{
for(EntityClasses::iterator i = g_EntityClassFGD_classes.begin(); i != g_EntityClassFGD_classes.end(); ++i)
{
EntityClassFGD_resolveInheritance((*i).second);
if((*i).second->fixedsize && string_empty((*i).second->m_modelpath.c_str()))
{
if(!(*i).second->sizeSpecified)
{
globalErrorStream() << "size not specified for entity class: " << makeQuoted((*i).second->m_name.c_str()) << '\n';
}
if(!(*i).second->colorSpecified)
{
globalErrorStream() << "color not specified for entity class: " << makeQuoted((*i).second->m_name.c_str()) << '\n';
}
}
}
}
{
for(BaseClasses::iterator i = g_EntityClassFGD_bases.begin(); i != g_EntityClassFGD_bases.end(); ++i)
{
eclass_capture_state((*i).second);
}
}
m_observers.realise();
}
}
void unrealise()
{
if(++m_unrealised == 1)
{
m_observers.unrealise();
EntityClassFGD_clear();
}
}
void attach(ModuleObserver& observer)
{
m_observers.attach(observer);
}
void detach(ModuleObserver& observer)
{
m_observers.detach(observer);
}
};
EntityClassFGD g_EntityClassFGD;
void EntityClassFGD_attach(ModuleObserver& observer)
{
g_EntityClassFGD.attach(observer);
}
void EntityClassFGD_detach(ModuleObserver& observer)
{
g_EntityClassFGD.detach(observer);
}
void EntityClassFGD_realise()
{
g_EntityClassFGD.realise();
}
void EntityClassFGD_unrealise()
{
g_EntityClassFGD.unrealise();
}
void EntityClassFGD_construct()
{
// start by creating the default unknown eclass
g_EntityClassFGD_bad = EClass_Create("UNKNOWN_CLASS", Vector3(0.0f, 0.5f, 0.0f), "");
EntityClassFGD_realise();
}
void EntityClassFGD_destroy()
{
EntityClassFGD_unrealise();
g_EntityClassFGD_bad->free(g_EntityClassFGD_bad);
}
class EntityClassFGDDependencies : public GlobalFileSystemModuleRef, public GlobalShaderCacheModuleRef, public GlobalRadiantModuleRef
{
};
class EntityClassFGDAPI
{
EntityClassManager m_eclassmanager;
public:
typedef EntityClassManager Type;
STRING_CONSTANT(Name, "halflife");
EntityClassFGDAPI()
{
EntityClassFGD_construct();
m_eclassmanager.findOrInsert = &EntityClassFGD_findOrInsert;
m_eclassmanager.findListType = &EntityClassFGD_findListType;
m_eclassmanager.forEach = &EntityClassFGD_forEach;
m_eclassmanager.attach = &EntityClassFGD_attach;
m_eclassmanager.detach = &EntityClassFGD_detach;
m_eclassmanager.realise = &EntityClassFGD_realise;
m_eclassmanager.unrealise = &EntityClassFGD_unrealise;
GlobalRadiant().attachGameToolsPathObserver(g_EntityClassFGD);
GlobalRadiant().attachGameNameObserver(g_EntityClassFGD);
}
~EntityClassFGDAPI()
{
GlobalRadiant().detachGameNameObserver(g_EntityClassFGD);
GlobalRadiant().detachGameToolsPathObserver(g_EntityClassFGD);
EntityClassFGD_destroy();
}
EntityClassManager* getTable()
{
return &m_eclassmanager;
}
};
#include "modulesystem/singletonmodule.h"
#include "modulesystem/moduleregistry.h"
typedef SingletonModule<EntityClassFGDAPI, EntityClassFGDDependencies> EntityClassFGDModule;
typedef Static<EntityClassFGDModule> StaticEntityClassFGDModule;
StaticRegisterModule staticRegisterEntityClassFGD(StaticEntityClassFGDModule::instance());

25
radiant/eclass_fgd.h Normal file
View File

@@ -0,0 +1,25 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#if !defined(INCLUDED_ECLASS_FGD_H)
#define INCLUDED_ECLASS_FGD_H
#endif

524
radiant/eclass_xml.cpp Normal file
View File

@@ -0,0 +1,524 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#include "eclass_xml.h"
#include "ieclass.h"
#include "irender.h"
#include "ifilesystem.h"
#include "iarchive.h"
#include "xml/xmlparser.h"
#include "generic/object.h"
#include "generic/reference.h"
#include "stream/stringstream.h"
#include "stream/textfilestream.h"
#include "os/path.h"
#include "eclasslib.h"
#include "modulesystem/moduleregistry.h"
#include "stringio.h"
#define PARSE_ERROR(elementName, name) makeQuoted(elementName) << " is not a valid child of " << makeQuoted(name)
class IgnoreBreaks
{
public:
const char* m_first;
const char* m_last;
IgnoreBreaks(const char* first, const char* last) : m_first(first), m_last(last)
{
}
};
template<typename TextOutputStreamType>
TextOutputStreamType& ostream_write(TextOutputStreamType& ostream, const IgnoreBreaks& ignoreBreaks)
{
for(const char* i = ignoreBreaks.m_first; i != ignoreBreaks.m_last; ++i)
{
if(*i != '\n')
{
ostream << *i;
}
}
return ostream;
}
namespace
{
class TreeXMLImporter : public TextOutputStream
{
public:
virtual TreeXMLImporter& pushElement(const XMLElement& element) = 0;
virtual void popElement(const char* name) = 0;
};
template<typename Type>
class Storage
{
char m_storage[sizeof(Type)];
public:
Type& get()
{
return *reinterpret_cast<Type*>(m_storage);
}
const Type& get() const
{
return *reinterpret_cast<const Type*>(m_storage);
}
};
class BreakImporter : public TreeXMLImporter
{
public:
BreakImporter(StringOutputStream& comment)
{
comment << '\n';
}
static const char* name()
{
return "n";
}
TreeXMLImporter& pushElement(const XMLElement& element)
{
ERROR_MESSAGE(PARSE_ERROR(element.name(), name()));
return *this;
}
void popElement(const char* elementName)
{
ERROR_MESSAGE(PARSE_ERROR(elementName, name()));
}
std::size_t write(const char* data, std::size_t length)
{
return length;
}
};
class AttributeImporter : public TreeXMLImporter
{
StringOutputStream& m_comment;
public:
AttributeImporter(StringOutputStream& comment, EntityClass* entityClass, const XMLElement& element) : m_comment(comment)
{
const char* type = element.name();
const char* key = element.attribute("key");
const char* name = element.attribute("name");
const char* value = element.attribute("value");
ASSERT_MESSAGE(!string_empty(key), "key attribute not specified");
ASSERT_MESSAGE(!string_empty(name), "name attribute not specified");
if(string_equal(type, "flag"))
{
std::size_t bit = atoi(element.attribute("bit"));
ASSERT_MESSAGE(bit < MAX_FLAGS, "invalid flag bit");
ASSERT_MESSAGE(string_empty(entityClass->flagnames[bit]), "non-unique flag bit");
strcpy(entityClass->flagnames[bit], key);
}
m_comment << key;
m_comment << " : ";
EntityClass_insertAttribute(*entityClass, key, EntityClassAttribute(type, name, value));
}
~AttributeImporter()
{
}
TreeXMLImporter& pushElement(const XMLElement& element)
{
ERROR_MESSAGE(PARSE_ERROR(element.name(), "attribute"));
return *this;
}
void popElement(const char* elementName)
{
ERROR_MESSAGE(PARSE_ERROR(elementName, "attribute"));
}
std::size_t write(const char* data, std::size_t length)
{
return m_comment.write(data, length);
}
};
bool attributeSupported(const char* name)
{
return string_equal(name, "real")
|| string_equal(name, "integer")
|| string_equal(name, "boolean")
|| string_equal(name, "string")
|| string_equal(name, "array")
|| string_equal(name, "flag")
|| string_equal(name, "real3")
|| string_equal(name, "integer3")
|| string_equal(name, "direction")
|| string_equal(name, "angle")
|| string_equal(name, "angles")
|| string_equal(name, "color")
|| string_equal(name, "target")
|| string_equal(name, "targetname")
|| string_equal(name, "sound")
|| string_equal(name, "texture")
|| string_equal(name, "model")
|| string_equal(name, "skin")
|| string_equal(name, "integer2");
}
typedef std::map<CopiedString, ListAttributeType> ListAttributeTypes;
bool listAttributeSupported(ListAttributeTypes& listTypes, const char* name)
{
return listTypes.find(name) != listTypes.end();
}
class ClassImporter : public TreeXMLImporter
{
EntityClassCollector& m_collector;
EntityClass* m_eclass;
StringOutputStream m_comment;
Storage<AttributeImporter> m_attribute;
ListAttributeTypes& m_listTypes;
public:
ClassImporter(EntityClassCollector& collector, ListAttributeTypes& listTypes, const XMLElement& element) : m_collector(collector), m_listTypes(listTypes)
{
m_eclass = Eclass_Alloc();
m_eclass->free = &Eclass_Free;
const char* name = element.attribute("name");
ASSERT_MESSAGE(!string_empty(name), "name attribute not specified for class");
m_eclass->m_name = name;
const char* color = element.attribute("color");
ASSERT_MESSAGE(!string_empty(name), "color attribute not specified for class " << name);
string_parse_vector3(color, m_eclass->color);
eclass_capture_state(m_eclass);
const char* model = element.attribute("model");
if(!string_empty(model))
{
StringOutputStream buffer(256);
buffer << PathCleaned(model);
m_eclass->m_modelpath = buffer.c_str();
}
const char* type = element.name();
if(string_equal(type, "point"))
{
const char* box = element.attribute("box");
ASSERT_MESSAGE(!string_empty(box), "box attribute not found for class " << name);
m_eclass->fixedsize = true;
string_parse_vector(box, &m_eclass->mins.x(), &m_eclass->mins.x() + 6);
}
}
~ClassImporter()
{
m_eclass->m_comments = m_comment.c_str();
m_collector.insert(m_eclass);
for(ListAttributeTypes::iterator i = m_listTypes.begin(); i != m_listTypes.end(); ++i)
{
m_collector.insert((*i).first.c_str(), (*i).second);
}
}
static const char* name()
{
return "class";
}
TreeXMLImporter& pushElement(const XMLElement& element)
{
if(attributeSupported(element.name()) || listAttributeSupported(m_listTypes, element.name()))
{
constructor(m_attribute.get(), makeReference(m_comment), m_eclass, element);
return m_attribute.get();
}
else
{
ERROR_MESSAGE(PARSE_ERROR(element.name(), name()));
return *this;
}
}
void popElement(const char* elementName)
{
if(attributeSupported(elementName) || listAttributeSupported(m_listTypes, elementName))
{
destructor(m_attribute.get());
}
else
{
ERROR_MESSAGE(PARSE_ERROR(elementName, name()));
}
}
std::size_t write(const char* data, std::size_t length)
{
return m_comment.write(data, length);
}
};
class ItemImporter : public TreeXMLImporter
{
public:
ItemImporter(ListAttributeType& list, const XMLElement& element)
{
const char* name = element.attribute("name");
const char* value = element.attribute("value");
list.push_back(name, value);
}
TreeXMLImporter& pushElement(const XMLElement& element)
{
ERROR_MESSAGE(PARSE_ERROR(element.name(), "item"));
return *this;
}
void popElement(const char* elementName)
{
ERROR_MESSAGE(PARSE_ERROR(elementName, "item"));
}
std::size_t write(const char* data, std::size_t length)
{
return length;
}
};
bool isItem(const char* name)
{
return string_equal(name, "item");
}
class ListAttributeImporter : public TreeXMLImporter
{
ListAttributeType* m_listType;
Storage<ItemImporter> m_item;
public:
ListAttributeImporter(ListAttributeTypes& listTypes, const XMLElement& element)
{
const char* name = element.attribute("name");
m_listType = &listTypes[name];
}
TreeXMLImporter& pushElement(const XMLElement& element)
{
if(isItem(element.name()))
{
constructor(m_item.get(), makeReference(*m_listType), element);
return m_item.get();
}
else
{
ERROR_MESSAGE(PARSE_ERROR(element.name(), "list"));
return *this;
}
}
void popElement(const char* elementName)
{
if(isItem(elementName))
{
destructor(m_item.get());
}
else
{
ERROR_MESSAGE(PARSE_ERROR(elementName, "list"));
}
}
std::size_t write(const char* data, std::size_t length)
{
return length;
}
};
bool classSupported(const char* name)
{
return string_equal(name, "group")
|| string_equal(name, "point");
}
bool listSupported(const char* name)
{
return string_equal(name, "list");
}
class ClassesImporter : public TreeXMLImporter
{
EntityClassCollector& m_collector;
Storage<ClassImporter> m_class;
Storage<ListAttributeImporter> m_list;
ListAttributeTypes m_listTypes;
public:
ClassesImporter(EntityClassCollector& collector) : m_collector(collector)
{
}
static const char* name()
{
return "classes";
}
TreeXMLImporter& pushElement(const XMLElement& element)
{
if(classSupported(element.name()))
{
constructor(m_class.get(), makeReference(m_collector), makeReference(m_listTypes), element);
return m_class.get();
}
else if(listSupported(element.name()))
{
constructor(m_list.get(), makeReference(m_listTypes), element);
return m_list.get();
}
else
{
ERROR_MESSAGE(PARSE_ERROR(element.name(), name()));
return *this;
}
}
void popElement(const char* elementName)
{
if(classSupported(elementName))
{
destructor(m_class.get());
}
else if(listSupported(elementName))
{
destructor(m_list.get());
}
else
{
ERROR_MESSAGE(PARSE_ERROR(elementName, name()));
}
}
std::size_t write(const char* data, std::size_t length)
{
return length;
}
};
class EclassXMLImporter : public TreeXMLImporter
{
EntityClassCollector& m_collector;
Storage<ClassesImporter> m_classes;
public:
EclassXMLImporter(EntityClassCollector& collector) : m_collector(collector)
{
}
static const char* name()
{
return "classes";
}
TreeXMLImporter& pushElement(const XMLElement& element)
{
if(string_equal(element.name(), ClassesImporter::name()))
{
constructor(m_classes.get(), makeReference(m_collector));
return m_classes.get();
}
else
{
ERROR_MESSAGE(PARSE_ERROR(element.name(), name()));
return *this;
}
}
void popElement(const char* elementName)
{
if(string_equal(elementName, ClassesImporter::name()))
{
destructor(m_classes.get());
}
else
{
ERROR_MESSAGE(PARSE_ERROR(elementName, name()));
}
}
std::size_t write(const char* data, std::size_t length)
{
return length;
}
};
class TreeXMLImporterStack : public XMLImporter
{
std::vector< Reference<TreeXMLImporter> > m_importers;
public:
TreeXMLImporterStack(TreeXMLImporter& importer)
{
m_importers.push_back(makeReference(importer));
}
void pushElement(const XMLElement& element)
{
m_importers.push_back(makeReference(m_importers.back().get().pushElement(element)));
}
void popElement(const char* name)
{
m_importers.pop_back();
m_importers.back().get().popElement(name);
}
std::size_t write(const char* buffer, std::size_t length)
{
return m_importers.back().get().write(buffer, length);
}
};
const char* GetExtension()
{
return "ent";
}
void ScanFile(EntityClassCollector& collector, const char *filename)
{
TextFileInputStream inputFile(filename);
if(!inputFile.failed())
{
XMLStreamParser parser(inputFile);
EclassXMLImporter importer(collector);
TreeXMLImporterStack stack(importer);
parser.exportXML(stack);
}
}
}
#include "modulesystem/singletonmodule.h"
class EntityClassXMLDependencies : public GlobalFileSystemModuleRef, public GlobalShaderCacheModuleRef
{
};
class EclassXMLAPI
{
EntityClassScanner m_eclassxml;
public:
typedef EntityClassScanner Type;
STRING_CONSTANT(Name, "xml");
EclassXMLAPI()
{
m_eclassxml.scanFile = &ScanFile;
m_eclassxml.getExtension = &GetExtension;
}
EntityClassScanner* getTable()
{
return &m_eclassxml;
}
};
typedef SingletonModule<EclassXMLAPI, EntityClassXMLDependencies> EclassXMLModule;
typedef Static<EclassXMLModule> StaticEclassXMLModule;
StaticRegisterModule staticRegisterEclassXML(StaticEclassXMLModule::instance());

25
radiant/eclass_xml.h Normal file
View File

@@ -0,0 +1,25 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#if !defined(INCLUDED_ECLASS_XML_H)
#define INCLUDED_ECLASS_XML_H
#endif

438
radiant/entity.cpp Normal file
View File

@@ -0,0 +1,438 @@
/*
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
*/
#include "entity.h"
#include "ientity.h"
#include "iselection.h"
#include "imodel.h"
#include "ifilesystem.h"
#include "iundo.h"
#include "editable.h"
#include "eclasslib.h"
#include "scenelib.h"
#include "os/path.h"
#include "os/file.h"
#include "stream/stringstream.h"
#include "stringio.h"
#include "gtkutil/filechooser.h"
#include "gtkmisc.h"
#include "select.h"
#include "map.h"
#include "preferences.h"
#include "gtkdlgs.h"
#include "mainframe.h"
#include "qe3.h"
#include "commands.h"
struct entity_globals_t
{
Vector3 color_entity;
entity_globals_t() :
color_entity(0.0f, 0.0f, 0.0f)
{
}
};
entity_globals_t g_entity_globals;
class EntitySetKeyValueSelected : public scene::Graph::Walker
{
const char* m_key;
const char* m_value;
public:
EntitySetKeyValueSelected(const char* key, const char* value)
: m_key(key), m_value(value)
{
}
bool pre(const scene::Path& path, scene::Instance& instance) const
{
return true;
}
void post(const scene::Path& path, scene::Instance& instance) const
{
Entity* entity = Node_getEntity(path.top());
if(entity != 0
&& (instance.childSelected() || Instance_getSelectable(instance)->isSelected()))
{
entity->setKeyValue(m_key, m_value);
}
}
};
class EntitySetClassnameSelected : public scene::Graph::Walker
{
const char* m_classname;
public:
EntitySetClassnameSelected(const char* classname)
: m_classname(classname)
{
}
bool pre(const scene::Path& path, scene::Instance& instance) const
{
return true;
}
void post(const scene::Path& path, scene::Instance& instance) const
{
Entity* entity = Node_getEntity(path.top());
if(entity != 0
&& (instance.childSelected() || Instance_getSelectable(instance)->isSelected()))
{
NodeSmartReference node(GlobalEntityCreator().createEntity(GlobalEntityClassManager().findOrInsert(m_classname, node_is_group(path.top()))));
EntityCopyingVisitor visitor(*Node_getEntity(node));
entity->forEachKeyValue(visitor);
NodeSmartReference child(path.top().get());
NodeSmartReference parent(path.parent().get());
Node_getTraversable(parent)->erase(child);
if(Node_getTraversable(child) != 0
&& Node_getTraversable(node) != 0
&& node_is_group(node))
{
parentBrushes(child, node);
}
Node_getTraversable(parent)->insert(node);
}
}
};
void Scene_EntitySetKeyValue_Selected(const char* key, const char* value)
{
GlobalSceneGraph().traverse(EntitySetKeyValueSelected(key, value));
}
void Scene_EntitySetClassname_Selected(const char* classname)
{
GlobalSceneGraph().traverse(EntitySetClassnameSelected(classname));
}
class EntityUngroupVisitor : public SelectionSystem::Visitor
{
const scene::Path& m_parent;
public:
EntityUngroupVisitor(const scene::Path& parent) : m_parent(parent)
{
}
void visit(scene::Instance& instance) const
{
if(Node_getEntity(instance.path().top()) != 0
&& node_is_group(instance.path().top()))
{
if(m_parent.top().get_pointer() != instance.path().top().get_pointer())
{
parentBrushes(instance.path().top(), m_parent.top());
Path_deleteTop(instance.path());
}
}
}
};
void Entity_ungroupSelected()
{
UndoableCommand undo("ungroupSelectedEntities");
scene::Path world_path(makeReference(GlobalSceneGraph().root()));
world_path.push(makeReference(Map_FindOrInsertWorldspawn(g_map)));
GlobalSelectionSystem().foreachSelected(EntityUngroupVisitor(world_path));
}
void Entity_connectSelected()
{
if(GlobalSelectionSystem().countSelected() == 2)
{
GlobalEntityCreator().connectEntities(
GlobalSelectionSystem().penultimateSelected().path(),
GlobalSelectionSystem().ultimateSelected().path()
);
}
else
{
globalErrorStream() << "entityConnectSelected: exactly two instances must be selected\n";
}
}
int g_iLastLightIntensity;
void Entity_createFromSelection(const char* name, const Vector3& origin)
{
#if 0
if(string_equal_nocase(name, "worldspawn"))
{
gtk_MessageBox(GTK_WIDGET(MainFrame_getWindow()), "Can't create an entity with worldspawn.", "info");
return;
}
#endif
EntityClass* entityClass = GlobalEntityClassManager().findOrInsert(name, true);
bool isModel = string_equal_nocase(name, "misc_model")
|| string_equal_nocase(name, "misc_gamemodel")
|| string_equal_nocase(name, "model_static")
|| (GlobalSelectionSystem().countSelected() == 0 && string_equal_nocase(name, "func_static"));
if(!(entityClass->fixedsize || isModel) && Scene_countSelectedBrushes(GlobalSceneGraph()) == 0)
{
globalErrorStream() << "failed to create a group entity - no brushes are selected\n";
return;
}
NodeSmartReference node(GlobalEntityCreator().createEntity(entityClass));
Node_getTraversable(GlobalSceneGraph().root())->insert(node);
scene::Path entitypath(makeReference(GlobalSceneGraph().root()));
entitypath.push(makeReference(node.get()));
scene::Instance& instance = findInstance(entitypath);
if(entityClass->fixedsize)
{
Select_Delete();
Transformable* transform = Instance_getTransformable(instance);
if(transform != 0)
{
transform->setType(TRANSFORM_PRIMITIVE);
transform->setTranslation(origin);
transform->freezeTransform();
}
GlobalSelectionSystem().setSelectedAll(false);
Instance_setSelected(instance, true);
}
else
{
Scene_parentSelectedBrushesToEntity(GlobalSceneGraph(), node);
Scene_forEachChildSelectable(SelectableSetSelected(true), instance.path());
}
// tweaking: when right clic dropping a light entity, ask for light value in a custom dialog box
// see SF bug 105383
if (g_pGameDescription->mGameType == "hl")
{
// FIXME - Hydra: really we need a combined light AND color dialog for halflife.
if (string_equal_nocase(name, "light")
|| string_equal_nocase(name, "light_environment")
|| string_equal_nocase(name, "light_spot"))
{
int intensity = g_iLastLightIntensity;
if (DoLightIntensityDlg (&intensity) == eIDOK)
{
g_iLastLightIntensity = intensity;
char buf[30];
sprintf( buf, "255 255 255 %d", intensity );
Node_getEntity(node)->setKeyValue("_light", buf);
}
}
}
else if(g_pGameDescription->mGameType != "doom3" && string_equal_nocase(name, "light"))
{
int intensity = g_iLastLightIntensity;
if (DoLightIntensityDlg (&intensity) == eIDOK)
{
g_iLastLightIntensity = intensity;
char buf[10];
sprintf( buf, "%d", intensity );
Node_getEntity(node)->setKeyValue("light", buf);
}
}
if(isModel)
{
const char* model = misc_model_dialog(GTK_WIDGET(MainFrame_getWindow()));
if(model != 0)
{
Node_getEntity(node)->setKeyValue("model", model);
}
}
}
bool DoNormalisedColor(Vector3& color)
{
if(!color_dialog(GTK_WIDGET(MainFrame_getWindow()), color))
return false;
/*
** scale colors so that at least one component is at 1.0F
*/
float largest = 0.0F;
if ( color[0] > largest )
largest = color[0];
if ( color[1] > largest )
largest = color[1];
if ( color[2] > largest )
largest = color[2];
if ( largest == 0.0F )
{
color[0] = 1.0F;
color[1] = 1.0F;
color[2] = 1.0F;
}
else
{
float scaler = 1.0F / largest;
color[0] *= scaler;
color[1] *= scaler;
color[2] *= scaler;
}
return true;
}
void Entity_setColour()
{
if(GlobalSelectionSystem().countSelected() != 0)
{
const scene::Path& path = GlobalSelectionSystem().ultimateSelected().path();
Entity* entity = Node_getEntity(path.top());
if(entity != 0)
{
const char* strColor = entity->getKeyValue("_color");
if(!string_empty(strColor))
{
Vector3 rgb;
if (string_parse_vector3(strColor, rgb))
{
g_entity_globals.color_entity = rgb;
}
}
if(g_pGameDescription->mGameType == "doom3"
? color_dialog(GTK_WIDGET(MainFrame_getWindow()), g_entity_globals.color_entity)
: DoNormalisedColor(g_entity_globals.color_entity))
{
char buffer[128];
sprintf(buffer, "%g %g %g", g_entity_globals.color_entity[0],
g_entity_globals.color_entity[1],
g_entity_globals.color_entity[2]);
Scene_EntitySetKeyValue_Selected("_color", buffer);
}
}
}
}
const char* misc_model_dialog(GtkWidget* parent)
{
StringOutputStream buffer(1024);
buffer << g_qeglobals.m_userGamePath.c_str() << "models/";
if(!file_readable(buffer.c_str()))
{
// just go to fsmain
buffer.clear();
buffer << g_qeglobals.m_userGamePath.c_str() << "/";
}
const char *filename = file_dialog (parent, TRUE, "Choose Model", buffer.c_str(), ModelLoader::Name());
if (filename != 0)
{
// use VFS to get the correct relative path
const char* relative = path_make_relative(filename, GlobalFileSystem().findRoot(filename));
if(relative == filename)
{
globalOutputStream() << "WARNING: could not extract the relative path, using full path instead\n";
}
return relative;
}
return 0;
}
void LightRadiiImport(EntityCreator& self, bool value)
{
self.setLightRadii(value);
}
typedef ReferenceCaller1<EntityCreator, bool, LightRadiiImport> LightRadiiImportCaller;
void LightRadiiExport(EntityCreator& self, const BoolImportCallback& importer)
{
importer(self.getLightRadii());
}
typedef ReferenceCaller1<EntityCreator, const BoolImportCallback&, LightRadiiExport> LightRadiiExportCaller;
void Entity_constructPreferences(PreferencesPage& page)
{
page.appendCheckBox(
"Show", "Light Radii",
LightRadiiImportCaller(GlobalEntityCreator()),
LightRadiiExportCaller(GlobalEntityCreator())
);
}
void Entity_constructPage(PreferenceGroup& group)
{
PreferencesPage page(group.createPage("Entities", "Entity Display Preferences"));
Entity_constructPreferences(page);
}
void Entity_registerPreferencesPage()
{
PreferencesDialog_addDisplayPage(FreeCaller1<PreferenceGroup&, Entity_constructPage>());
}
void Entity_constructMenu(GtkMenu* menu)
{
create_menu_item_with_mnemonic(menu, "_Ungroup", "UngroupSelection");
create_menu_item_with_mnemonic(menu, "_Connect", "ConnectSelection");
create_menu_item_with_mnemonic(menu, "_Select Color...", "EntityColor");
}
#include "preferencesystem.h"
#include "stringio.h"
void Entity_Construct()
{
GlobalCommands_insert("EntityColor", FreeCaller<Entity_setColour>(), Accelerator('K'));
GlobalCommands_insert("ConnectSelection", FreeCaller<Entity_connectSelected>(), Accelerator('K', (GdkModifierType)GDK_CONTROL_MASK));
GlobalCommands_insert("UngroupSelection", FreeCaller<Entity_ungroupSelected>());
GlobalPreferenceSystem().registerPreference("SI_Colors5", Vector3ImportStringCaller(g_entity_globals.color_entity), Vector3ExportStringCaller(g_entity_globals.color_entity));
GlobalPreferenceSystem().registerPreference("LastLightIntensity", IntImportStringCaller(g_iLastLightIntensity), IntExportStringCaller(g_iLastLightIntensity));
Entity_registerPreferencesPage();
}
void Entity_Destroy()
{
}

42
radiant/entity.h Normal file
View File

@@ -0,0 +1,42 @@
/*
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
*/
#if !defined(INCLUDED_ENTITY_H)
#define INCLUDED_ENTITY_H
template<typename Element> class BasicVector3;
typedef BasicVector3<float> Vector3;
void Entity_createFromSelection(const char* name, const Vector3& origin);
void Scene_EntitySetKeyValue_Selected(const char* key, const char* value);
void Scene_EntitySetClassname_Selected(const char* classname);
typedef struct _GtkWidget GtkWidget;
const char* misc_model_dialog(GtkWidget* parent);
typedef struct _GtkMenu GtkMenu;
void Entity_constructMenu(GtkMenu* menu);
void Entity_Construct();
void Entity_Destroy();
#endif

1748
radiant/entityinspector.cpp Normal file

File diff suppressed because it is too large Load Diff

31
radiant/entityinspector.h Normal file
View File

@@ -0,0 +1,31 @@
/*
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
*/
#if !defined(INCLUDED_ENTITYINSPECTOR_H)
#define INCLUDED_ENTITYINSPECTOR_H
typedef struct _GtkWidget GtkWidget;
typedef struct _GtkWindow GtkWindow;
GtkWidget* EntityInspector_constructWindow(GtkWindow* parent);
void EntityInspector_construct();
void EntityInspector_destroy();
#endif

429
radiant/entitylist.cpp Normal file
View File

@@ -0,0 +1,429 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#include "entitylist.h"
#include "iselection.h"
#include <gtk/gtktreemodel.h>
#include <gtk/gtktreeview.h>
#include <gtk/gtktreeselection.h>
#include <gtk/gtkcellrenderertext.h>
#include "string/string.h"
#include "scenelib.h"
#include "nameable.h"
#include "generic/callback.h"
#include "generic/object.h"
#include "gtkutil/widget.h"
#include "gtkutil/window.h"
#include "gtkutil/idledraw.h"
#include "gtkutil/accelerator.h"
#include "gtkutil/closure.h"
#include "treemodel.h"
void RedrawEntityList();
typedef FreeCaller<RedrawEntityList> RedrawEntityListCaller;
typedef struct _GtkTreeView GtkTreeView;
class EntityList
{
public:
enum EDirty
{
eDefault,
eSelection,
eInsertRemove,
};
EDirty m_dirty;
IdleDraw m_idleDraw;
WindowPositionTracker m_positionTracker;
GtkWindow* m_window;
GtkTreeView* m_tree_view;
GraphTreeModel* m_tree_model;
bool m_selection_disabled;
EntityList() :
m_dirty(EntityList::eDefault),
m_idleDraw(RedrawEntityListCaller()),
m_window(0),
m_selection_disabled(false)
{
}
bool visible() const
{
return GTK_WIDGET_VISIBLE(GTK_WIDGET(m_window));
}
};
namespace
{
EntityList* g_EntityList;
inline EntityList& getEntityList()
{
ASSERT_NOTNULL(g_EntityList);
return *g_EntityList;
}
}
inline Nameable* Node_getNameable(scene::Node& node)
{
return NodeTypeCast<Nameable>::cast(node);
}
const char* node_get_name(scene::Node& node)
{
Nameable* nameable = Node_getNameable(node);
return (nameable != 0)
? nameable->name()
: "node";
}
template<typename value_type>
inline void gtk_tree_model_get_pointer(GtkTreeModel* model, GtkTreeIter* iter, gint column, value_type** pointer)
{
GValue value = GValue_default();
gtk_tree_model_get_value(model, iter, column, &value);
*pointer = (value_type*)g_value_get_pointer(&value);
}
void entitylist_treeviewcolumn_celldatafunc(GtkTreeViewColumn* column, GtkCellRenderer* renderer, GtkTreeModel* model, GtkTreeIter* iter, gpointer data)
{
scene::Node* node;
gtk_tree_model_get_pointer(model, iter, 0, &node);
scene::Instance* instance;
gtk_tree_model_get_pointer(model, iter, 1, &instance);
if(node != 0)
{
gtk_cell_renderer_set_fixed_size(renderer, -1, -1);
char* name = const_cast<char*>(node_get_name(*node));
g_object_set(G_OBJECT(renderer), "text", name, "visible", TRUE, 0);
//globalOutputStream() << "rendering cell " << makeQuoted(name) << "\n";
GtkStyle* style = gtk_widget_get_style(GTK_WIDGET(getEntityList().m_tree_view));
if(instance->childSelected())
{
g_object_set(G_OBJECT(renderer), "cell-background-gdk", &style->base[GTK_STATE_ACTIVE], 0);
}
else
{
g_object_set(G_OBJECT(renderer), "cell-background-gdk", &style->base[GTK_STATE_NORMAL], 0);
}
}
else
{
gtk_cell_renderer_set_fixed_size(renderer, -1, 0);
g_object_set(G_OBJECT(renderer), "text", "", "visible", FALSE, 0);
}
}
static gboolean entitylist_tree_select(GtkTreeSelection *selection, GtkTreeModel *model, GtkTreePath *path, gboolean path_currently_selected, gpointer data)
{
GtkTreeIter iter;
gtk_tree_model_get_iter(model, &iter, path);
scene::Node* node;
gtk_tree_model_get_pointer(model, &iter, 0, &node);
scene::Instance* instance;
gtk_tree_model_get_pointer(model, &iter, 1, &instance);
Selectable* selectable = Instance_getSelectable(*instance);
if(node == 0)
{
if(path_currently_selected != FALSE)
{
getEntityList().m_selection_disabled = true;
GlobalSelectionSystem().setSelectedAll(false);
getEntityList().m_selection_disabled = false;
}
}
else if(selectable != 0)
{
getEntityList().m_selection_disabled = true;
selectable->setSelected(path_currently_selected == FALSE);
getEntityList().m_selection_disabled = false;
return TRUE;
}
return FALSE;
}
static gboolean entitylist_tree_select_null(GtkTreeSelection *selection, GtkTreeModel *model, GtkTreePath *path, gboolean path_currently_selected, gpointer data)
{
return TRUE;
}
void EntityList_ConnectSignals(GtkTreeView* view)
{
GtkTreeSelection* select = gtk_tree_view_get_selection(view);
gtk_tree_selection_set_select_function(select, entitylist_tree_select, NULL, 0);
}
void EntityList_DisconnectSignals(GtkTreeView* view)
{
GtkTreeSelection* select = gtk_tree_view_get_selection(view);
gtk_tree_selection_set_select_function(select, entitylist_tree_select_null, 0, 0);
}
gboolean treemodel_update_selection(GtkTreeModel* model, GtkTreePath* path, GtkTreeIter* iter, gpointer data)
{
GtkTreeView* view = reinterpret_cast<GtkTreeView*>(data);
scene::Instance* instance;
gtk_tree_model_get_pointer(model, iter, 1, &instance);
Selectable* selectable = Instance_getSelectable(*instance);
if(selectable != 0)
{
GtkTreeSelection* selection = gtk_tree_view_get_selection(view);
if(selectable->isSelected())
{
gtk_tree_selection_select_path(selection, path);
}
else
{
gtk_tree_selection_unselect_path(selection, path);
}
}
return FALSE;
}
void EntityList_UpdateSelection(GtkTreeModel* model, GtkTreeView* view)
{
EntityList_DisconnectSignals(view);
gtk_tree_model_foreach(model, treemodel_update_selection, view);
EntityList_ConnectSignals(view);
}
void RedrawEntityList()
{
switch(getEntityList().m_dirty)
{
case EntityList::eInsertRemove:
case EntityList::eSelection:
EntityList_UpdateSelection(GTK_TREE_MODEL(getEntityList().m_tree_model), getEntityList().m_tree_view);
default:
break;
}
getEntityList().m_dirty = EntityList::eDefault;
}
void entitylist_queue_draw()
{
getEntityList().m_idleDraw.queueDraw();
}
void EntityList_SelectionUpdate()
{
if(getEntityList().m_selection_disabled)
return;
if(getEntityList().m_dirty < EntityList::eSelection)
getEntityList().m_dirty = EntityList::eSelection;
entitylist_queue_draw();
}
void EntityList_SelectionChanged(const Selectable& selectable)
{
EntityList_SelectionUpdate();
}
void entitylist_treeview_rowcollapsed(GtkTreeView* view, GtkTreeIter* iter, GtkTreePath* path, gpointer user_data)
{
}
void entitylist_treeview_row_expanded(GtkTreeView* view, GtkTreeIter* iter, GtkTreePath* path, gpointer user_data)
{
EntityList_SelectionUpdate();
}
void EntityList_SetShown(bool shown)
{
widget_set_visible(GTK_WIDGET(getEntityList().m_window), shown);
}
void EntityList_toggleShown()
{
EntityList_SetShown(!getEntityList().visible());
}
gint graph_tree_model_compare_name(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data)
{
scene::Node* first;
gtk_tree_model_get(model, a, 0, (gpointer*)&first, -1);
scene::Node* second;
gtk_tree_model_get(model, b, 0, (gpointer*)&second, -1);
int result = 0;
if(first != 0 && second != 0)
{
result = string_compare(node_get_name(*first), node_get_name(*second));
}
if(result == 0)
{
return (first < second) ? -1 : (second < first) ? 1 : 0;
}
return result;
}
extern GraphTreeModel* scene_graph_get_tree_model();
void AttachEntityTreeModel()
{
getEntityList().m_tree_model = scene_graph_get_tree_model();
gtk_tree_view_set_model(getEntityList().m_tree_view, GTK_TREE_MODEL(getEntityList().m_tree_model));
}
void DetachEntityTreeModel()
{
getEntityList().m_tree_model = 0;
gtk_tree_view_set_model(getEntityList().m_tree_view, 0);
}
void EntityList_constructWindow(GtkWindow* main_window)
{
ASSERT_MESSAGE(getEntityList().m_window == 0, "error");
GtkWindow* window = create_persistent_floating_window("Entity List", main_window);
gtk_window_add_accel_group(window, global_accel);
getEntityList().m_positionTracker.connect(window);
getEntityList().m_window = window;
{
GtkScrolledWindow* scr = create_scrolled_window(GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(scr));
{
GtkWidget* view = gtk_tree_view_new();
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
GtkTreeViewColumn* column = gtk_tree_view_column_new();
gtk_tree_view_column_pack_start(column, renderer, TRUE);
gtk_tree_view_column_set_cell_data_func(column, renderer, entitylist_treeviewcolumn_celldatafunc, 0, 0);
GtkTreeSelection* select = gtk_tree_view_get_selection (GTK_TREE_VIEW(view));
gtk_tree_selection_set_mode(select, GTK_SELECTION_MULTIPLE);
g_signal_connect(G_OBJECT(view), "row_expanded", G_CALLBACK(entitylist_treeview_row_expanded), 0);
g_signal_connect(G_OBJECT(view), "row_collapsed", G_CALLBACK(entitylist_treeview_rowcollapsed), 0);
gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
gtk_widget_show(view);
gtk_container_add (GTK_CONTAINER(scr), view);
getEntityList().m_tree_view = GTK_TREE_VIEW(view);
}
}
EntityList_ConnectSignals(getEntityList().m_tree_view);
AttachEntityTreeModel();
}
void EntityList_destroyWindow()
{
DetachEntityTreeModel();
EntityList_DisconnectSignals(getEntityList().m_tree_view);
destroy_floating_window(getEntityList().m_window);
}
#include "preferencesystem.h"
#include "iselection.h"
namespace
{
scene::Node* nullNode = 0;
}
class NullSelectedInstance : public scene::Instance, public Selectable
{
class TypeCasts
{
InstanceTypeCastTable m_casts;
public:
TypeCasts()
{
InstanceStaticCast<NullSelectedInstance, Selectable>::install(m_casts);
}
InstanceTypeCastTable& get()
{
return m_casts;
}
};
public:
typedef LazyStatic<TypeCasts> StaticTypeCasts;
NullSelectedInstance() : Instance(scene::Path(makeReference(*nullNode)), 0, this, StaticTypeCasts::instance().get())
{
}
void setSelected(bool select)
{
ERROR_MESSAGE("error");
}
bool isSelected() const
{
return true;
}
};
typedef LazyStatic<NullSelectedInstance> StaticNullSelectedInstance;
void EntityList_Construct()
{
graph_tree_model_insert(scene_graph_get_tree_model(), StaticNullSelectedInstance::instance());
g_EntityList = new EntityList;
getEntityList().m_positionTracker.setPosition(c_default_window_pos);
GlobalPreferenceSystem().registerPreference("EntityInfoDlg", WindowPositionTrackerImportStringCaller(getEntityList().m_positionTracker), WindowPositionTrackerExportStringCaller(getEntityList().m_positionTracker));
GlobalSelectionSystem().addSelectionChangeCallback(FreeCaller1<const Selectable&, EntityList_SelectionChanged>());
}
void EntityList_Destroy()
{
delete g_EntityList;
graph_tree_model_erase(scene_graph_get_tree_model(), StaticNullSelectedInstance::instance());
}

33
radiant/entitylist.h Normal file
View File

@@ -0,0 +1,33 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#if !defined(INCLUDED_ENTITYLIST_H)
#define INCLUDED_ENTITYLIST_H
void EntityList_Construct();
void EntityList_Destroy();
typedef struct _GtkWindow GtkWindow;
void EntityList_constructWindow(GtkWindow* main_window);
void EntityList_destroyWindow();
void EntityList_toggleShown();
#endif

200
radiant/environment.cpp Normal file
View File

@@ -0,0 +1,200 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#include "environment.h"
#include "stream/textstream.h"
#include "string/string.h"
#include "stream/stringstream.h"
#include "debugging/debugging.h"
#include "os/path.h"
#include "cmdlib.h"
int g_argc;
char** g_argv;
void args_init(int argc, char* argv[])
{
int i, j, k;
for (i = 1; i < argc; i++)
{
for (k = i; k < argc; k++)
if (argv[k] != 0)
break;
if (k > i)
{
k -= i;
for (j = i + k; j < argc; j++)
argv[j-k] = argv[j];
argc -= k;
}
}
g_argc = argc;
g_argv = argv;
}
namespace
{
CopiedString home_path;
CopiedString app_path;
}
const char* environment_get_home_path()
{
return home_path.c_str();
}
const char* environment_get_app_path()
{
return app_path.c_str();
}
#if defined (__linux__) || defined (__APPLE__)
#include <stdlib.h>
#include <pwd.h>
#include <unistd.h>
#include <glib/gutils.h>
const char* LINK_NAME =
#if defined (__linux__)
"/proc/self/exe"
#else
"/proc/curproc/file"
#endif
;
/// brief Returns the filename of the executable belonging to the current process, or 0 if not found.
char* getexename(char *buf)
{
/* Now read the symbolic link */
int ret = readlink(LINK_NAME, buf, PATH_MAX);
if(ret == -1)
{
globalOutputStream() << "getexename: falling back to argv[0]: " << makeQuoted(g_argv[0]);
const char* path = realpath(g_argv[0], buf);
if(path == 0)
{
/* In case of an error, leave the handling up to the caller */
return "";
}
}
/* Ensure proper NUL termination */
buf[ret] = 0;
/* delete the program name */
*(strrchr(buf, '/')) = '\0';
// NOTE: we build app path with a trailing '/'
// it's a general convention in Radiant to have the slash at the end of directories
if (buf[strlen(buf)-1] != '/')
{
strcat(buf, "/");
}
return buf;
}
void environment_init(int argc, char* argv[])
{
// Give away unnecessary root privileges.
// Important: must be done before calling gtk_init().
char *loginname;
struct passwd *pw;
seteuid(getuid());
if (geteuid() == 0 && (loginname = getlogin()) != 0 &&
(pw = getpwnam(loginname)) != 0)
setuid(pw->pw_uid);
args_init(argc, argv);
{
StringOutputStream home(256);
home << DirectoryCleaned(g_get_home_dir()) << ".radiant/";
Q_mkdir(home.c_str());
home_path = home.c_str();
}
{
char real[PATH_MAX];
app_path = getexename(real);
ASSERT_MESSAGE(!string_empty(app_path.c_str()), "failed to deduce app path");
}
}
#endif
#ifdef WIN32
#include <windows.h>
#include <shfolder.h>
void environment_init(int argc, char* argv[])
{
args_init(argc, argv);
{
char appdata[MAX_PATH+1];
SHGetFolderPath(0, CSIDL_APPDATA, 0, 0, appdata);
StringOutputStream home(256);
if(string_empty(appdata))
{
ERROR_MESSAGE("Application Data folder not available.\n"
"Please install shfolder redistributable package.\n"
"Radiant will use C:\\ for user preferences.\n");
home << "C:";
}
else
{
home << PathCleaned(appdata);
}
home << "/RadiantSettings/";
Q_mkdir(home.c_str());
home_path = home.c_str();
}
{
// get path to the editor
char filename[MAX_PATH+1];
GetModuleFileName(0, filename, MAX_PATH);
char* last_separator = strrchr(filename, '\\');
if(last_separator != 0)
{
*(last_separator+1) = '\0';
}
else
{
filename[0] = '\0';
}
StringOutputStream app(256);
app << PathCleaned(filename);
app_path = app.c_str();
}
}
#endif

29
radiant/environment.h Normal file
View File

@@ -0,0 +1,29 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#if !defined(INCLUDED_ENVIRONMENT_H)
#define INCLUDED_ENVIRONMENT_H
void environment_init(int argc, char* argv[]);
const char* environment_get_home_path();
const char* environment_get_app_path();
#endif

141
radiant/error.cpp Normal file
View File

@@ -0,0 +1,141 @@
/*
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
*/
#include "error.h"
#include "debugging/debugging.h"
#include "igl.h"
#include "gtkutil/messagebox.h"
#include "console.h"
#include "preferences.h"
#ifdef WIN32
#define UNICODE
#include <windows.h>
#endif
#if defined (__linux__) || defined (__APPLE__)
#include <errno.h>
#include <unistd.h>
#endif
/*
=================
Error
For abnormal program terminations
=================
*/
/*!
\todo
FIXME the prompt wether to do prefs dialog, may not even be possible
if the crash happens before the game is loaded
*/
void Error (const char *error, ...)
{
va_list argptr;
char text[4096];
va_start (argptr,error);
vsprintf (text, error,argptr);
va_end (argptr);
strcat( text, "\n" );
#if defined (__linux__) || defined (__APPLE__)
if (errno != 0)
{
strcat( text, "errno: " );
strcat( text, strerror (errno));
strcat( text, "\n");
}
#endif
#ifdef WIN32
if (GetLastError() != 0)
{
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
0,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
0
);
strcat( text, "GetLastError: " );
/*
Gtk will only crunch 0<=char<=127
this is a bit hackish, but I didn't find useful functions in win32 API for this
http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=516
*/
TCHAR *scan, *next = (TCHAR*)lpMsgBuf;
do
{
scan = next;
text[strlen(text)+1] = '\0';
if ((scan[0] >= 0) && (scan[0] <= 127))
text[strlen(text)] = char(scan[0]);
else
text[strlen(text)] = '?';
next = CharNext(scan);
} while (next != scan);
strcat( text, "\n");
LocalFree( lpMsgBuf );
}
#endif
#if 0
// we need to have a current context to call glError()
if (g_glwindow_globals.d_glBase != 0)
{
// glGetError .. can record several errors, clears after calling
//++timo TODO: be able to deal with several errors if necessary, for now I'm just warning about pending error messages
// NOTE: forget that, most boards don't seem to follow the OpenGL standard
GLenum iGLError = glGetError();
if (iGLError != GL_NO_ERROR)
{
// use our own gluErrorString
strcat( text, "gluErrorString: " );
strcat( text, (char*)gluErrorString( iGLError ) );
strcat( text, "\n" );
}
}
#endif
strcat (text, "An unrecoverable error has occured.\n");
ERROR_MESSAGE(text);
// force close logging if necessary
Sys_LogFile(false);
_exit (1);
}

27
radiant/error.h Normal file
View File

@@ -0,0 +1,27 @@
/*
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
*/
#if !defined(INCLUDED_ERROR_H)
#define INCLUDED_ERROR_H
void Error(const char *error, ...);
#endif

372
radiant/feedback.cpp Normal file
View File

@@ -0,0 +1,372 @@
/*
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
*/
//-----------------------------------------------------------------------------
//
// DESCRIPTION:
// classes used for describing geometry information from q3map feedback
//
#include "feedback.h"
#include "debugging/debugging.h"
#include "igl.h"
#include "iselection.h"
#include <gtk/gtktreeview.h>
#include <gtk/gtktreeselection.h>
#include <gtk/gtkliststore.h>
#include <gtk/gtkcellrenderertext.h>
#include <gtk/gtkwindow.h>
#include <gtk/gtkscrolledwindow.h>
#include "map.h"
#include "dialog.h"
#include "mainframe.h"
CDbgDlg g_DbgDlg;
void Feedback_draw2D(VIEWTYPE viewType)
{
g_DbgDlg.draw2D(viewType);
}
void CSelectMsg::saxStartElement(message_info_t *ctx, const xmlChar *name, const xmlChar **attrs)
{
if(string_equal(reinterpret_cast<const char*>(name), "select"))
{
// read the message
ESelectState = SELECT_MESSAGE;
}
else
{
// read the brush
ASSERT_MESSAGE(string_equal(reinterpret_cast<const char*>(name), "brush"), "FEEDBACK PARSE ERROR");
ASSERT_MESSAGE(ESelectState == SELECT_MESSAGE, "FEEDBACK PARSE ERROR");
ESelectState = SELECT_BRUSH;
globalOutputStream() << message.c_str() << '\n';
}
}
void CSelectMsg::saxEndElement(message_info_t *ctx, const xmlChar *name)
{
if(string_equal(reinterpret_cast<const char*>(name), "select"))
{
}
}
void CSelectMsg::saxCharacters(message_info_t *ctx, const xmlChar *ch, int len)
{
if(ESelectState == SELECT_MESSAGE)
{
message.write(reinterpret_cast<const char*>(ch), len);
}
else
{
brush.write(reinterpret_cast<const char*>(ch), len);
}
}
IGL2DWindow* CSelectMsg::Highlight()
{
GlobalSelectionSystem().setSelectedAll(false);
int entitynum, brushnum;
if(sscanf(reinterpret_cast<const char*>(brush.c_str()), "%i %i", &entitynum, &brushnum) == 2)
{
SelectBrush (entitynum, brushnum);
}
return 0;
}
void CPointMsg::saxStartElement(message_info_t *ctx, const xmlChar *name, const xmlChar **attrs)
{
if(string_equal(reinterpret_cast<const char*>(name), "pointmsg"))
{
// read the message
EPointState = POINT_MESSAGE;
}
else
{
// read the brush
ASSERT_MESSAGE(string_equal(reinterpret_cast<const char*>(name), "point"), "FEEDBACK PARSE ERROR");
ASSERT_MESSAGE(EPointState == POINT_MESSAGE, "FEEDBACK PARSE ERROR");
EPointState = POINT_POINT;
globalOutputStream() << message.c_str() << '\n';
}
}
void CPointMsg::saxEndElement (message_info_t *ctx, const xmlChar *name)
{
if(string_equal(reinterpret_cast<const char*>(name), "pointmsg"))
{
}
else if(string_equal(reinterpret_cast<const char*>(name), "point"))
{
sscanf(point.c_str(), "%g %g %g", &(pt[0]), &(pt[1]), &(pt[2]));
point.clear();
}
}
void CPointMsg::saxCharacters (message_info_t *ctx, const xmlChar *ch, int len)
{
if(EPointState == POINT_MESSAGE)
{
message.write(reinterpret_cast<const char*>(ch), len);
}
else
{
ASSERT_MESSAGE(EPointState == POINT_POINT, "FEEDBACK PARSE ERROR");
point.write(reinterpret_cast<const char*>(ch), len);
}
}
IGL2DWindow* CPointMsg::Highlight()
{
return this;
}
void CPointMsg::DropHighlight()
{
}
void CPointMsg::Draw2D( VIEWTYPE vt )
{
int nDim1 = (vt == YZ) ? 1 : 0;
int nDim2 = (vt == XY) ? 1 : 2;
glPointSize(4);
glColor3f(1.0f,0.0f,0.0f);
glBegin (GL_POINTS);
glVertex2f (pt[nDim1], pt[nDim2]);
glEnd();
glBegin (GL_LINE_LOOP);
glVertex2f (pt[nDim1]-8, pt[nDim2]-8);
glVertex2f (pt[nDim1]+8, pt[nDim2]-8);
glVertex2f (pt[nDim1]+8, pt[nDim2]+8);
glVertex2f (pt[nDim1]-8, pt[nDim2]+8);
glEnd();
}
void CWindingMsg::saxStartElement(message_info_t *ctx, const xmlChar *name, const xmlChar **attrs)
{
if(string_equal(reinterpret_cast<const char*>(name), "windingmsg"))
{
// read the message
EPointState = WINDING_MESSAGE;
}
else
{
// read the brush
ASSERT_MESSAGE(string_equal(reinterpret_cast<const char*>(name), "winding"), "FEEDBACK PARSE ERROR");
ASSERT_MESSAGE(EPointState == WINDING_MESSAGE, "FEEDBACK PARSE ERROR");
EPointState = WINDING_WINDING;
globalOutputStream() << message.c_str() << '\n';
}
}
void CWindingMsg::saxEndElement(message_info_t *ctx, const xmlChar *name)
{
if(string_equal(reinterpret_cast<const char*>(name), "windingmsg"))
{
}
else if(string_equal(reinterpret_cast<const char*>(name), "winding"))
{
const char* c = winding.c_str();
sscanf(c, "%i ", &numpoints);
int i = 0;
for(; i < numpoints; i++)
{
c = strchr(c + 1, '(');
if(c) // even if we are given the number of points when the cycle begins .. don't trust it too much
sscanf(c, "(%g %g %g)", &wt[i][0], &wt[i][1], &wt[i][2]);
else
break;
}
numpoints = i;
}
}
void CWindingMsg::saxCharacters(message_info_t *ctx, const xmlChar *ch, int len)
{
if(EPointState == WINDING_MESSAGE)
{
message.write(reinterpret_cast<const char*>(ch), len);
}
else
{
ASSERT_MESSAGE(EPointState == WINDING_WINDING, "FEEDBACK PARSE ERROR");
winding.write(reinterpret_cast<const char*>(ch), len);
}
}
IGL2DWindow* CWindingMsg::Highlight()
{
return this;
}
void CWindingMsg::DropHighlight()
{
}
void CWindingMsg::Draw2D( VIEWTYPE vt )
{
int i;
int nDim1 = (vt == YZ) ? 1 : 0;
int nDim2 = (vt == XY) ? 1 : 2;
glColor3f(1.0f,0.f,0.0f);
glPointSize(4);
glBegin (GL_POINTS);
for(i = 0; i < numpoints; i++)
glVertex2f (wt[i][nDim1], wt[i][nDim2]);
glEnd();
glPointSize(1);
glEnable (GL_BLEND);
glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(0.133f,0.4f,1.0f,0.5f);
glBegin (GL_POLYGON);
for(i = 0; i < numpoints; i++)
glVertex2f (wt[i][nDim1], wt[i][nDim2]);
glEnd();
glDisable (GL_BLEND);
}
// triggered when the user selects an entry in the feedback box
static void feedback_selection_changed(GtkTreeSelection* selection, gpointer data)
{
g_DbgDlg.DropHighlight();
GtkTreeModel* model;
GtkTreeIter selected;
if(gtk_tree_selection_get_selected(selection, &model, &selected))
{
GtkTreePath* path = gtk_tree_model_get_path(model, &selected);
g_DbgDlg.SetHighlight(gtk_tree_path_get_indices(path)[0]);
gtk_tree_path_free(path);
}
}
void CDbgDlg::DropHighlight()
{
if(m_pHighlight != 0)
{
m_pHighlight->DropHighlight();
m_pHighlight = 0;
m_pDraw2D = 0;
}
}
void CDbgDlg::SetHighlight(gint row)
{
ISAXHandler *h = GetElement(row);
if(h != NULL)
{
m_pDraw2D = h->Highlight();
m_pHighlight = h;
}
}
ISAXHandler *CDbgDlg::GetElement (std::size_t row)
{
return static_cast<ISAXHandler *>(g_ptr_array_index(m_pFeedbackElements, gint(row)));
}
void CDbgDlg::Init()
{
DropHighlight();
// free all the ISAXHandler*, clean it
while (m_pFeedbackElements->len)
{
static_cast<ISAXHandler *>(g_ptr_array_index (m_pFeedbackElements, 0))->Release();
g_ptr_array_remove_index (m_pFeedbackElements, 0);
}
if(m_clist != NULL)
gtk_list_store_clear (m_clist);
}
void CDbgDlg::Push (ISAXHandler *pHandler)
{
// push in the list
g_ptr_array_add (m_pFeedbackElements, (void *)pHandler);
if(GetWidget() == 0)
{
Create();
}
// put stuff in the list
gtk_list_store_clear (m_clist);
for(std::size_t i = 0; i < static_cast<std::size_t>(m_pFeedbackElements->len); ++i)
{
GtkTreeIter iter;
gtk_list_store_append(m_clist, &iter);
gtk_list_store_set(m_clist, &iter, 0, GetElement(i)->getName(), -1);
}
ShowDlg();
}
GtkWindow* CDbgDlg::BuildDialog()
{
GtkWindow* window = create_floating_window("Q3Map debug window", MainFrame_getWindow());
GtkWidget* scr = gtk_scrolled_window_new (NULL, NULL);
gtk_widget_show (scr);
gtk_container_add (GTK_CONTAINER (window), GTK_WIDGET (scr));
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN);
{
GtkListStore* store = gtk_list_store_new(1, G_TYPE_STRING);
GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
{
GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("", renderer, "text", 0, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
}
{
GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE);
g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(feedback_selection_changed), NULL);
}
gtk_widget_show(view);
gtk_container_add(GTK_CONTAINER (scr), view);
g_object_unref(G_OBJECT(store));
m_clist = store;
}
return window;
}

186
radiant/feedback.h Normal file
View File

@@ -0,0 +1,186 @@
/*
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
*/
//-----------------------------------------------------------------------------
//
// DESCRIPTION:
// classes used for describing geometry information from q3map feedback
//
#ifndef __Q3MAP_FEEDBACK__
#define __Q3MAP_FEEDBACK__
#include "math/vector.h"
#include "stream/stringstream.h"
#include <glib/gstring.h>
#include "xmlstuff.h"
#include "dialog.h"
#include "xywindow.h"
// we use these classes to let plugins draw inside the Radiant windows
// 2D window like YZ XZ XY
class IGL2DWindow
{
public:
// Increment the number of references to this object
virtual void IncRef() = 0;
// Decrement the reference count
virtual void DecRef() = 0;
virtual void Draw2D( VIEWTYPE vt ) = 0;
};
// 3D window
class IGL3DWindow
{
public:
// Increment the number of references to this object
virtual void IncRef() = 0;
// Decrement the reference count
virtual void DecRef() = 0;
virtual void Draw3D() = 0;
};
// a select message with a brush/entity select information
class CSelectMsg : public ISAXHandler
{
enum { SELECT_MESSAGE, SELECT_BRUSH } ESelectState;
StringOutputStream message;
StringOutputStream brush;
public:
CSelectMsg() { ESelectState = SELECT_MESSAGE; }
// SAX interface
void saxStartElement (message_info_t *ctx, const xmlChar *name, const xmlChar **attrs);
void saxEndElement (message_info_t *ctx, const xmlChar *name);
void saxCharacters (message_info_t *ctx, const xmlChar *ch, int len);
// for use in the dialog window
const char* getName() { return message.c_str(); }
IGL2DWindow* Highlight();
void DropHighlight() { }
};
class CPointMsg : public ISAXHandler, public IGL2DWindow
{
enum { POINT_MESSAGE, POINT_POINT } EPointState;
StringOutputStream message;
StringOutputStream point;
Vector3 pt;
int refCount;
public:
CPointMsg() { EPointState = POINT_MESSAGE; refCount = 0; }
// SAX interface
void Release()
{
delete this;
}
void saxStartElement (message_info_t *ctx, const xmlChar *name, const xmlChar **attrs);
void saxEndElement (message_info_t *ctx, const xmlChar *name);
void saxCharacters (message_info_t *ctx, const xmlChar *ch, int len);
// for use in the dialog window
const char* getName() { return message.c_str(); }
IGL2DWindow* Highlight();
void DropHighlight();
// IGL2DWindow interface --------------------------------
// Increment the number of references to this object
void IncRef() { refCount++; }
// Decrement the reference count
void DecRef() { refCount--; if (refCount <= 0) delete this; }
void Draw2D( VIEWTYPE vt );
};
class CWindingMsg : public ISAXHandler, public IGL2DWindow
{
enum { WINDING_MESSAGE, WINDING_WINDING } EPointState;
StringOutputStream message;
StringOutputStream winding;
Vector3 wt[256];
int numpoints;
int refCount;
public:
CWindingMsg() { EPointState = WINDING_MESSAGE; refCount = 0; numpoints = 0; }
// SAX interface
void Release()
{
delete this;
}
void saxStartElement (message_info_t *ctx, const xmlChar *name, const xmlChar **attrs);
void saxEndElement (message_info_t *ctx, const xmlChar *name);
void saxCharacters (message_info_t *ctx, const xmlChar *ch, int len);
// for use in the dialog window
const char* getName() { return message.c_str(); }
IGL2DWindow* Highlight();
void DropHighlight();
// IGL2DWindow interface --------------------------------
// Increment the number of references to this object
void IncRef() { refCount++; }
// Decrement the reference count
void DecRef() { refCount--; if (refCount <= 0) delete this; }
void Draw2D( VIEWTYPE vt );
};
typedef struct _GtkListStore GtkListStore;
class CDbgDlg : public Dialog
{
GPtrArray *m_pFeedbackElements;
// the list widget we use in the dialog
GtkListStore* m_clist;
ISAXHandler *m_pHighlight;
IGL2DWindow* m_pDraw2D;
public:
CDbgDlg()
{
m_pFeedbackElements = g_ptr_array_new();
m_pHighlight = NULL;
m_pDraw2D = NULL;
}
// refresh items
void Push (ISAXHandler *);
// clean the debug window, release all ISAXHanlders we have
void Init();
ISAXHandler *GetElement(std::size_t row);
void SetHighlight(gint row);
void DropHighlight();
void draw2D(VIEWTYPE viewType)
{
if(m_pDraw2D != 0)
{
m_pDraw2D->Draw2D(viewType);
}
}
void destroyWindow()
{
if(GetWidget() != 0)
{
Destroy();
}
}
// void HideDlg();
protected:
GtkWindow* BuildDialog();
};
extern CDbgDlg g_DbgDlg;
void Feedback_draw2D(VIEWTYPE viewType);
#endif

139
radiant/filetypes.cpp Normal file
View File

@@ -0,0 +1,139 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#include "filetypes.h"
#include "debugging/debugging.h"
#include "ifiletypes.h"
#include "string/string.h"
#include "os/path.h"
#include <vector>
#include <map>
class RadiantFileTypeRegistry : public IFileTypeRegistry
{
struct filetype_copy_t
{
filetype_copy_t(const char* moduleName, const filetype_t other)
: m_moduleName(moduleName), m_name(other.name), m_pattern(other.pattern)
{
}
const char* getModuleName() const
{
return m_moduleName.c_str();
}
filetype_t getType() const
{
return filetype_t(m_name.c_str(), m_pattern.c_str());
}
private:
CopiedString m_moduleName;
CopiedString m_name;
CopiedString m_pattern;
};
typedef std::vector<filetype_copy_t> filetype_list_t;
std::map<CopiedString, filetype_list_t> m_typelists;
public:
RadiantFileTypeRegistry()
{
addType("*", "*", filetype_t("All Files", "*.*"));
}
void addType(const char* moduleType, const char* moduleName, filetype_t type)
{
m_typelists[moduleType].push_back(filetype_copy_t(moduleName, type));
}
void getTypeList(const char* moduleType, IFileTypeList* typelist)
{
filetype_list_t& list_ref = m_typelists[moduleType];
for(filetype_list_t::iterator i = list_ref.begin(); i != list_ref.end(); ++i)
{
typelist->addType((*i).getModuleName(), (*i).getType());
}
}
};
static RadiantFileTypeRegistry g_patterns;
IFileTypeRegistry* GetFileTypeRegistry()
{
return &g_patterns;
}
const char* findModuleName(IFileTypeRegistry* registry, const char* moduleType, const char* extension)
{
class SearchFileTypeList : public IFileTypeList
{
char m_pattern[128];
const char* m_moduleName;
public:
SearchFileTypeList(const char* ext)
: m_moduleName("")
{
m_pattern[0] = '*';
m_pattern[1] = '.';
strncpy(m_pattern + 2, ext, 125);
m_pattern[127] = '\0';
}
void addType(const char* moduleName, filetype_t type)
{
if(extension_equal(m_pattern, type.pattern))
{
m_moduleName = moduleName;
}
}
const char* getModuleName()
{
return m_moduleName;
}
} search(extension);
registry->getTypeList(moduleType, &search);
return search.getModuleName();
}
#include "modulesystem/singletonmodule.h"
#include "modulesystem/moduleregistry.h"
class FiletypesAPI
{
IFileTypeRegistry* m_filetypes;
public:
typedef IFileTypeRegistry Type;
STRING_CONSTANT(Name, "*");
FiletypesAPI()
{
m_filetypes = GetFileTypeRegistry();
}
IFileTypeRegistry* getTable()
{
return m_filetypes;
}
};
typedef SingletonModule<FiletypesAPI> FiletypesModule;
typedef Static<FiletypesModule> StaticFiletypesModule;
StaticRegisterModule staticRegisterFiletypes(StaticFiletypesModule::instance());

29
radiant/filetypes.h Normal file
View File

@@ -0,0 +1,29 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#if !defined(INCLUDED_FILETYPES_H)
#define INCLUDED_FILETYPES_H
class IFileTypeRegistry;
IFileTypeRegistry* GetFileTypeRegistry();
const char* findModuleName(IFileTypeRegistry* registry, const char* moduleType, const char* extension);
#endif

288
radiant/filters.cpp Normal file
View File

@@ -0,0 +1,288 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#include "filters.h"
#include "debugging/debugging.h"
#include "ifilter.h"
#include "scenelib.h"
#include <list>
#include <set>
#include "gtkutil/widget.h"
#include "gtkutil/menu.h"
#include "gtkmisc.h"
#include "mainframe.h"
#include "commands.h"
#include "preferences.h"
struct filters_globals_t
{
std::size_t exclude;
filters_globals_t() :
exclude(0)
{
}
};
filters_globals_t g_filters_globals;
inline bool filter_active(int mask)
{
return (g_filters_globals.exclude & mask) > 0;
}
class FilterWrapper
{
public:
FilterWrapper(Filter& filter, int mask) : m_filter(filter), m_mask(mask)
{
}
void update()
{
m_filter.setActive(filter_active(m_mask));
}
private:
Filter& m_filter;
int m_mask;
};
typedef std::list<FilterWrapper> Filters;
Filters g_filters;
typedef std::set<Filterable*> Filterables;
Filterables g_filterables;
void UpdateFilters()
{
{
for(Filters::iterator i = g_filters.begin(); i != g_filters.end(); ++i)
{
(*i).update();
}
}
{
for(Filterables::iterator i = g_filterables.begin(); i != g_filterables.end(); ++i)
{
(*i)->updateFiltered();
}
}
}
class BasicFilterSystem : public FilterSystem
{
public:
void addFilter(Filter& filter, int mask)
{
g_filters.push_back(FilterWrapper(filter, mask));
g_filters.back().update();
}
void registerFilterable(Filterable& filterable)
{
ASSERT_MESSAGE(g_filterables.find(&filterable) == g_filterables.end(), "filterable already registered");
filterable.updateFiltered();
g_filterables.insert(&filterable);
}
void unregisterFilterable(Filterable& filterable)
{
ASSERT_MESSAGE(g_filterables.find(&filterable) != g_filterables.end(), "filterable not registered");
g_filterables.erase(&filterable);
}
};
BasicFilterSystem g_FilterSystem;
FilterSystem& GetFilterSystem()
{
return g_FilterSystem;
}
void PerformFiltering()
{
UpdateFilters();
SceneChangeNotify();
}
class ToggleFilterFlag
{
const unsigned int m_mask;
public:
ToggleItem m_item;
ToggleFilterFlag(unsigned int mask) : m_mask(mask), m_item(ActiveCaller(*this))
{
}
ToggleFilterFlag(const ToggleFilterFlag& other) : m_mask(other.m_mask), m_item(ActiveCaller(*this))
{
}
void active(const BoolImportCallback& importCallback)
{
importCallback((g_filters_globals.exclude & m_mask) != 0);
}
typedef MemberCaller1<ToggleFilterFlag, const BoolImportCallback&, &ToggleFilterFlag::active> ActiveCaller;
void toggle()
{
g_filters_globals.exclude ^= m_mask;
m_item.update();
PerformFiltering();
}
typedef MemberCaller<ToggleFilterFlag, &ToggleFilterFlag::toggle> ToggleCaller;
};
typedef std::list<ToggleFilterFlag> ToggleFilterFlags;
ToggleFilterFlags g_filter_items;
void add_filter_command(unsigned int flag, const char* command, const Accelerator& accelerator)
{
g_filter_items.push_back(ToggleFilterFlag(flag));
GlobalToggles_insert(command, ToggleFilterFlag::ToggleCaller(g_filter_items.back()), ToggleItem::AddCallbackCaller(g_filter_items.back().m_item), accelerator);
}
void Filters_constructMenu(GtkMenu* menu_in_menu)
{
create_check_menu_item_with_mnemonic(menu_in_menu, "World", "FilterWorldBrushes");
create_check_menu_item_with_mnemonic(menu_in_menu, "Entities", "FilterEntities");
if(g_pGameDescription->mGameType == "doom3")
{
create_check_menu_item_with_mnemonic(menu_in_menu, "Visportals", "FilterVisportals");
}
else
{
create_check_menu_item_with_mnemonic(menu_in_menu, "Areaportals", "FilterAreaportals");
}
create_check_menu_item_with_mnemonic(menu_in_menu, "Translucent", "FilterTranslucent");
if(g_pGameDescription->mGameType != "doom3")
{
create_check_menu_item_with_mnemonic(menu_in_menu, "Liquids", "FilterLiquids");
}
create_check_menu_item_with_mnemonic(menu_in_menu, "Caulk", "FilterCaulk");
create_check_menu_item_with_mnemonic(menu_in_menu, "Clips", "FilterClips");
create_check_menu_item_with_mnemonic(menu_in_menu, "Paths", "FilterPaths");
if(g_pGameDescription->mGameType != "doom3")
{
create_check_menu_item_with_mnemonic(menu_in_menu, "Clusterportals", "FilterClusterportals");
}
create_check_menu_item_with_mnemonic(menu_in_menu, "Lights", "FilterLights");
create_check_menu_item_with_mnemonic(menu_in_menu, "Structural", "FilterStructural");
if(g_pGameDescription->mGameType != "doom3")
{
create_check_menu_item_with_mnemonic(menu_in_menu, "Lightgrid", "FilterLightgrid");
}
create_check_menu_item_with_mnemonic(menu_in_menu, "Patches", "FilterPatches");
create_check_menu_item_with_mnemonic(menu_in_menu, "Details", "FilterDetails");
create_check_menu_item_with_mnemonic(menu_in_menu, "Hints", "FilterHintsSkips");
create_check_menu_item_with_mnemonic(menu_in_menu, "Models", "FilterModels");
create_check_menu_item_with_mnemonic(menu_in_menu, "Triggers", "FilterTriggers");
if(g_pGameDescription->mGameType != "doom3")
{
create_check_menu_item_with_mnemonic(menu_in_menu, "Botclips", "FilterBotClips");
}
}
#include "preferencesystem.h"
#include "stringio.h"
void ConstructFilters()
{
GlobalPreferenceSystem().registerPreference("SI_Exclude", SizeImportStringCaller(g_filters_globals.exclude), SizeExportStringCaller(g_filters_globals.exclude));
add_filter_command(EXCLUDE_WORLD, "FilterWorldBrushes", Accelerator('1', (GdkModifierType)GDK_MOD1_MASK));
add_filter_command(EXCLUDE_ENT, "FilterEntities", Accelerator('2', (GdkModifierType)GDK_MOD1_MASK));
if(g_pGameDescription->mGameType == "doom3")
{
add_filter_command(EXCLUDE_VISPORTALS, "FilterVisportals", Accelerator('3', (GdkModifierType)GDK_MOD1_MASK));
}
else
{
add_filter_command(EXCLUDE_AREAPORTALS, "FilterAreaportals", Accelerator('3', (GdkModifierType)GDK_MOD1_MASK));
}
add_filter_command(EXCLUDE_TRANSLUCENT, "FilterTranslucent", Accelerator('4', (GdkModifierType)GDK_MOD1_MASK));
add_filter_command(EXCLUDE_LIQUIDS, "FilterLiquids", Accelerator('5', (GdkModifierType)GDK_MOD1_MASK));
add_filter_command(EXCLUDE_CAULK, "FilterCaulk", Accelerator('6', (GdkModifierType)GDK_MOD1_MASK ));
add_filter_command(EXCLUDE_CLIP, "FilterClips", Accelerator('7', (GdkModifierType)GDK_MOD1_MASK));
add_filter_command(EXCLUDE_PATHS, "FilterPaths", Accelerator('8', (GdkModifierType)GDK_MOD1_MASK));
if(g_pGameDescription->mGameType != "doom3")
{
add_filter_command(EXCLUDE_CLUSTERPORTALS, "FilterClusterportals", Accelerator('9', (GdkModifierType)GDK_MOD1_MASK));
}
add_filter_command(EXCLUDE_LIGHTS, "FilterLights", Accelerator('0', (GdkModifierType)GDK_MOD1_MASK));
add_filter_command(EXCLUDE_STRUCTURAL, "FilterStructural", Accelerator('D', (GdkModifierType)(GDK_SHIFT_MASK|GDK_CONTROL_MASK)));
if(g_pGameDescription->mGameType != "doom3")
{
add_filter_command(EXCLUDE_LIGHTGRID, "FilterLightgrid", accelerator_null());
}
add_filter_command(EXCLUDE_CURVES, "FilterPatches", Accelerator('P', (GdkModifierType)GDK_CONTROL_MASK));
add_filter_command(EXCLUDE_DETAILS, "FilterDetails", Accelerator('D', (GdkModifierType)GDK_CONTROL_MASK));
add_filter_command(EXCLUDE_HINTSSKIPS, "FilterHintsSkips", Accelerator('H', (GdkModifierType)GDK_CONTROL_MASK));
add_filter_command(EXCLUDE_MODELS, "FilterModels", Accelerator('M', (GdkModifierType)GDK_SHIFT_MASK));
add_filter_command(EXCLUDE_TRIGGERS, "FilterTriggers", Accelerator('T', (GdkModifierType)(GDK_SHIFT_MASK|GDK_CONTROL_MASK)));
if(g_pGameDescription->mGameType != "doom3")
{
add_filter_command(EXCLUDE_BOTCLIP, "FilterBotClips", Accelerator('M', (GdkModifierType)GDK_MOD1_MASK));
}
PerformFiltering();
}
void DestroyFilters()
{
g_filters.clear();
}
#include "modulesystem/singletonmodule.h"
#include "modulesystem/moduleregistry.h"
class FilterAPI
{
FilterSystem* m_filter;
public:
typedef FilterSystem Type;
STRING_CONSTANT(Name, "*");
FilterAPI()
{
ConstructFilters();
m_filter = &GetFilterSystem();
}
~FilterAPI()
{
DestroyFilters();
}
FilterSystem* getTable()
{
return m_filter;
}
};
typedef SingletonModule<FilterAPI> FilterModule;
typedef Static<FilterModule> StaticFilterModule;
StaticRegisterModule staticRegisterFilter(StaticFilterModule::instance());

28
radiant/filters.h Normal file
View File

@@ -0,0 +1,28 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#if !defined(INCLUDED_FILTERS_H)
#define INCLUDED_FILTERS_H
typedef struct _GtkMenu GtkMenu;
void Filters_constructMenu(GtkMenu* menu_in_menu);
#endif

View File

@@ -0,0 +1,299 @@
/*
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
*/
//
// Find/Replace textures dialogs
//
// Leonardo Zide (leo@lokigames.com)
//
#include "findtexturedialog.h"
#include "debugging/debugging.h"
#include "ishaders.h"
#include <gtk/gtkhbox.h>
#include <gtk/gtkentry.h>
#include <gtk/gtkvbox.h>
#include <gtk/gtkframe.h>
#include <gtk/gtklabel.h>
#include <gtk/gtktable.h>
#include <gtk/gtkbutton.h>
#include <gtk/gtktogglebutton.h>
#include <gtk/gtkcheckbutton.h>
#include <gtk/gtkmenuitem.h>
#include <gtk/gtkarrow.h>
#include "gtkutil/window.h"
#include "stream/stringstream.h"
#include "commands.h"
#include "dialog.h"
#include "select.h"
#include "textureentry.h"
class FindTextureDialog : public Dialog
{
public:
static void setReplaceStr(const char* name);
static void setFindStr(const char* name);
static bool isOpen();
static void show();
static void updateTextures(const char* name);
FindTextureDialog();
virtual ~FindTextureDialog();
GtkWindow* BuildDialog();
void constructWindow(GtkWindow* parent)
{
m_parent = parent;
Create();
}
void destroyWindow()
{
Destroy();
}
bool m_bSelectedOnly;
CopiedString m_strFind;
CopiedString m_strReplace;
};
FindTextureDialog g_FindTextureDialog;
static bool g_bFindActive = true;
namespace
{
void FindTextureDialog_apply()
{
StringOutputStream find(256);
find << "textures/" << g_FindTextureDialog.m_strFind.c_str();
StringOutputStream replace(256);
replace << "textures/" << g_FindTextureDialog.m_strReplace.c_str();
FindReplaceTextures(find.c_str(), replace.c_str(), g_FindTextureDialog.m_bSelectedOnly);
}
static void OnApply(GtkWidget* widget, gpointer data)
{
g_FindTextureDialog.exportData();
FindTextureDialog_apply();
}
static void OnFind(GtkWidget* widget, gpointer data)
{
g_FindTextureDialog.exportData();
FindTextureDialog_apply();
}
static void OnOK(GtkWidget* widget, gpointer data)
{
g_FindTextureDialog.exportData();
FindTextureDialog_apply();
g_FindTextureDialog.HideDlg();
}
static void OnClose(GtkWidget* widget, gpointer data)
{
g_FindTextureDialog.HideDlg();
}
static gint find_focus_in (GtkWidget* widget, GdkEventFocus *event, gpointer data)
{
g_bFindActive = true;
return FALSE;
}
static gint replace_focus_in (GtkWidget* widget, GdkEventFocus *event, gpointer data)
{
g_bFindActive = false;
return FALSE;
}
}
// =============================================================================
// FindTextureDialog class
FindTextureDialog::FindTextureDialog()
{
m_bSelectedOnly = FALSE;
}
FindTextureDialog::~FindTextureDialog()
{
}
GtkWindow* FindTextureDialog::BuildDialog()
{
GtkWidget* vbox, *hbox, *table, *label;
GtkWidget* button, *check, *entry;
GtkWindow* dlg = create_floating_window("Find / Replace Texture(s)", m_parent);
hbox = gtk_hbox_new (FALSE, 5);
gtk_widget_show (hbox);
gtk_container_add(GTK_CONTAINER(dlg), GTK_WIDGET(hbox));
gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
vbox = gtk_vbox_new (FALSE, 5);
gtk_widget_show (vbox);
gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox), TRUE, TRUE, 0);
table = gtk_table_new (2, 2, FALSE);
gtk_widget_show (table);
gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(table), TRUE, TRUE, 0);
gtk_table_set_row_spacings (GTK_TABLE (table), 5);
gtk_table_set_col_spacings (GTK_TABLE (table), 5);
label = gtk_label_new ("Find:");
gtk_widget_show (label);
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
(GtkAttachOptions) (GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
label = gtk_label_new ("Replace:");
gtk_widget_show (label);
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
(GtkAttachOptions) (GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
entry = gtk_entry_new();
gtk_widget_show (entry);
gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1,
(GtkAttachOptions) (GTK_EXPAND|GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
g_signal_connect(G_OBJECT(entry), "focus_in_event",
G_CALLBACK(find_focus_in), 0);
AddDialogData(*GTK_ENTRY(entry), m_strFind);
GlobalTextureEntryCompletion::instance().connect(GTK_ENTRY(entry));
entry = gtk_entry_new();
gtk_widget_show (entry);
gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2,
(GtkAttachOptions) (GTK_EXPAND|GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
g_signal_connect(G_OBJECT(entry), "focus_in_event",
G_CALLBACK(replace_focus_in), 0);
AddDialogData(*GTK_ENTRY(entry), m_strReplace);
GlobalTextureEntryCompletion::instance().connect(GTK_ENTRY(entry));
check = gtk_check_button_new_with_label ("Within selected brushes only");
gtk_widget_show (check);
gtk_box_pack_start(GTK_BOX(vbox), check, TRUE, TRUE, 0);
AddDialogData(*GTK_TOGGLE_BUTTON(check), m_bSelectedOnly);
vbox = gtk_vbox_new (FALSE, 5);
gtk_widget_show (vbox);
gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox), FALSE, FALSE, 0);
button = gtk_button_new_with_label ("Apply");
gtk_widget_show (button);
gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0);
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(OnApply), 0);
gtk_widget_set_usize (button, 60, -2);
button = gtk_button_new_with_label ("Close");
gtk_widget_show (button);
gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0);
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(OnClose), 0);
gtk_widget_set_usize (button, 60, -2);
return dlg;
}
void FindTextureDialog::updateTextures(const char* name)
{
if (isOpen())
{
if (g_bFindActive)
{
setFindStr(name + 9);
}
else
{
setReplaceStr(name + 9);
}
}
}
bool FindTextureDialog::isOpen()
{
return GTK_WIDGET_VISIBLE(g_FindTextureDialog.GetWidget()) == TRUE;
}
void FindTextureDialog::setFindStr(const char* name)
{
g_FindTextureDialog.exportData();
g_FindTextureDialog.m_strFind = name;
g_FindTextureDialog.importData();
}
void FindTextureDialog::setReplaceStr(const char* name)
{
g_FindTextureDialog.exportData();
g_FindTextureDialog.m_strReplace = name;
g_FindTextureDialog.importData();
}
void FindTextureDialog::show()
{
g_FindTextureDialog.ShowDlg();
}
void FindTextureDialog_constructWindow(GtkWindow* main_window)
{
g_FindTextureDialog.constructWindow(main_window);
}
void FindTextureDialog_destroyWindow()
{
g_FindTextureDialog.destroyWindow();
}
bool FindTextureDialog_isOpen()
{
return g_FindTextureDialog.isOpen();
}
void FindTextureDialog_selectTexture(const char* name)
{
g_FindTextureDialog.updateTextures(name);
}
void FindTextureDialog_Construct()
{
GlobalCommands_insert("FindReplaceTextures", FreeCaller<FindTextureDialog::show>());
}
void FindTextureDialog_Destroy()
{
}

View File

@@ -0,0 +1,34 @@
/*
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
*/
#if !defined(INCLUDED_FINDTEXTUREDIALOG_H)
#define INCLUDED_FINDTEXTUREDIALOG_H
void FindTextureDialog_Construct();
void FindTextureDialog_Destroy();
typedef struct _GtkWindow GtkWindow;
void FindTextureDialog_constructWindow(GtkWindow* main_window);
void FindTextureDialog_destroyWindow();
bool FindTextureDialog_isOpen();
void FindTextureDialog_selectTexture(const char* name);
#endif

55
radiant/glwidget.cpp Normal file
View File

@@ -0,0 +1,55 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#include "glwidget.h"
#include "igtkgl.h"
#include "modulesystem.h"
#include "gtkutil/glwidget.h"
class GtkGLAPI
{
_QERGtkGLTable m_gtkgl;
public:
typedef _QERGtkGLTable Type;
STRING_CONSTANT(Name, "*");
GtkGLAPI()
{
m_gtkgl.glwidget_new = &glwidget_new;
m_gtkgl.glwidget_swap_buffers = &glwidget_swap_buffers;
m_gtkgl.glwidget_make_current = &glwidget_make_current;
m_gtkgl.glwidget_destroy_context = &glwidget_destroy_context;
m_gtkgl.glwidget_create_context = &glwidget_create_context;
}
_QERGtkGLTable* getTable()
{
return &m_gtkgl;
}
};
#include "modulesystem/singletonmodule.h"
#include "modulesystem/moduleregistry.h"
typedef SingletonModule<GtkGLAPI> GtkGLModule;
typedef Static<GtkGLModule> StaticGtkGLModule;
StaticRegisterModule staticRegisterGtkGL(StaticGtkGLModule::instance());

25
radiant/glwidget.h Normal file
View File

@@ -0,0 +1,25 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#if !defined(INCLUDED_GLWIDGET_H)
#define INCLUDED_GLWIDGET_H
#endif

270
radiant/grid.cpp Normal file
View File

@@ -0,0 +1,270 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#include "grid.h"
#include <math.h>
#include <vector>
#include <algorithm>
#include "preferencesystem.h"
#include "gtkutil/widget.h"
#include "stringio.h"
#include "gtkmisc.h"
#include "commands.h"
#include "preferences.h"
std::vector<Callback> g_gridChange_callbacks;
void AddGridChangeCallback(const Callback& callback)
{
g_gridChange_callbacks.push_back(callback);
callback();
}
void GridChangeNotify()
{
std::for_each(g_gridChange_callbacks.begin(), g_gridChange_callbacks.end(), CallbackInvoke());
}
enum GridPower
{
GRIDPOWER_0125 = -3,
GRIDPOWER_025 = -2,
GRIDPOWER_05 = -1,
GRIDPOWER_1 = 0,
GRIDPOWER_2 = 1,
GRIDPOWER_4 = 2,
GRIDPOWER_8 = 3,
GRIDPOWER_16 = 4,
GRIDPOWER_32 = 5,
GRIDPOWER_64 = 6,
GRIDPOWER_128 = 7,
GRIDPOWER_256 = 8,
};
typedef const char* GridName;
// this must match the GridPower enumeration
const GridName g_gridnames[] = {
"0.125",
"0.25",
"0.5",
"1",
"2",
"4",
"8",
"16",
"32",
"64",
"128",
"256",
};
inline GridPower GridPower_forGridDefault(int gridDefault)
{
return static_cast<GridPower>(gridDefault - 3);
}
inline int GridDefault_forGridPower(GridPower gridPower)
{
return gridPower + 3;
}
int g_grid_default = GridDefault_forGridPower(GRIDPOWER_8);
int g_grid_power = GridPower_forGridDefault(g_grid_default);
int Grid_getPower()
{
return g_grid_power;
}
inline float GridSize_forGridPower(int gridPower)
{
return pow(2.0f, gridPower);
}
float g_gridsize = GridSize_forGridPower(g_grid_power);
float GetGridSize()
{
return g_gridsize;
}
void setGridPower(GridPower power);
class GridMenuItem
{
GridPower m_id;
GridMenuItem(const GridMenuItem& other); // NOT COPYABLE
GridMenuItem& operator=(const GridMenuItem& other); // NOT ASSIGNABLE
public:
ToggleItem m_item;
GridMenuItem(GridPower id) : m_id(id), m_item(ExportCaller(*this))
{
}
void set()
{
g_grid_power = m_id;
m_item.update();
setGridPower(m_id);
}
typedef MemberCaller<GridMenuItem, &GridMenuItem::set> SetCaller;
void active(const BoolImportCallback& importCallback)
{
importCallback(g_grid_power == m_id);
}
typedef MemberCaller1<GridMenuItem, const BoolImportCallback&, &GridMenuItem::active> ExportCaller;
};
GridMenuItem g_gridMenu0125(GRIDPOWER_0125);
GridMenuItem g_gridMenu025(GRIDPOWER_025);
GridMenuItem g_gridMenu05(GRIDPOWER_05);
GridMenuItem g_gridMenu1(GRIDPOWER_1);
GridMenuItem g_gridMenu2(GRIDPOWER_2);
GridMenuItem g_gridMenu4(GRIDPOWER_4);
GridMenuItem g_gridMenu8(GRIDPOWER_8);
GridMenuItem g_gridMenu16(GRIDPOWER_16);
GridMenuItem g_gridMenu32(GRIDPOWER_32);
GridMenuItem g_gridMenu64(GRIDPOWER_64);
GridMenuItem g_gridMenu128(GRIDPOWER_128);
GridMenuItem g_gridMenu256(GRIDPOWER_256);
void setGridPower(GridPower power)
{
g_gridsize = GridSize_forGridPower(power);
g_gridMenu0125.m_item.update();
g_gridMenu025.m_item.update();
g_gridMenu05.m_item.update();
g_gridMenu1.m_item.update();
g_gridMenu2.m_item.update();
g_gridMenu4.m_item.update();
g_gridMenu8.m_item.update();
g_gridMenu16.m_item.update();
g_gridMenu32.m_item.update();
g_gridMenu64.m_item.update();
g_gridMenu128.m_item.update();
g_gridMenu256.m_item.update();
GridChangeNotify();
}
void GridPrev()
{
if(g_grid_power > GRIDPOWER_0125)
{
setGridPower(static_cast<GridPower>(--g_grid_power));
}
}
void GridNext()
{
if(g_grid_power < GRIDPOWER_256)
{
setGridPower(static_cast<GridPower>(++g_grid_power));
}
}
void Grid_registerCommands()
{
GlobalCommands_insert("GridDown", FreeCaller<GridPrev>(), Accelerator('['));
GlobalCommands_insert("GridUp", FreeCaller<GridNext>(), Accelerator(']'));
GlobalToggles_insert("SetGrid0.125", GridMenuItem::SetCaller(g_gridMenu0125), ToggleItem::AddCallbackCaller(g_gridMenu0125.m_item));
GlobalToggles_insert("SetGrid0.25", GridMenuItem::SetCaller(g_gridMenu025), ToggleItem::AddCallbackCaller(g_gridMenu025.m_item));
GlobalToggles_insert("SetGrid0.5", GridMenuItem::SetCaller(g_gridMenu05), ToggleItem::AddCallbackCaller(g_gridMenu05.m_item));
GlobalToggles_insert("SetGrid1", GridMenuItem::SetCaller(g_gridMenu1), ToggleItem::AddCallbackCaller(g_gridMenu1.m_item), Accelerator('1'));
GlobalToggles_insert("SetGrid2", GridMenuItem::SetCaller(g_gridMenu2), ToggleItem::AddCallbackCaller(g_gridMenu2.m_item), Accelerator('2'));
GlobalToggles_insert("SetGrid4", GridMenuItem::SetCaller(g_gridMenu4), ToggleItem::AddCallbackCaller(g_gridMenu4.m_item), Accelerator('3'));
GlobalToggles_insert("SetGrid8", GridMenuItem::SetCaller(g_gridMenu8), ToggleItem::AddCallbackCaller(g_gridMenu8.m_item), Accelerator('4'));
GlobalToggles_insert("SetGrid16", GridMenuItem::SetCaller(g_gridMenu16), ToggleItem::AddCallbackCaller(g_gridMenu16.m_item), Accelerator('5'));
GlobalToggles_insert("SetGrid32", GridMenuItem::SetCaller(g_gridMenu32), ToggleItem::AddCallbackCaller(g_gridMenu32.m_item), Accelerator('6'));
GlobalToggles_insert("SetGrid64", GridMenuItem::SetCaller(g_gridMenu64), ToggleItem::AddCallbackCaller(g_gridMenu64.m_item), Accelerator('7'));
GlobalToggles_insert("SetGrid128", GridMenuItem::SetCaller(g_gridMenu128), ToggleItem::AddCallbackCaller(g_gridMenu128.m_item), Accelerator('8'));
GlobalToggles_insert("SetGrid256", GridMenuItem::SetCaller(g_gridMenu256), ToggleItem::AddCallbackCaller(g_gridMenu256.m_item), Accelerator('9'));
}
void Grid_constructMenu(GtkMenu* menu)
{
create_check_menu_item_with_mnemonic(menu, "Grid0.125", "SetGrid0.125");
create_check_menu_item_with_mnemonic(menu, "Grid0.25", "SetGrid0.25");
create_check_menu_item_with_mnemonic(menu, "Grid0.5", "SetGrid0.5");
create_check_menu_item_with_mnemonic(menu, "Grid1", "SetGrid1");
create_check_menu_item_with_mnemonic(menu, "Grid2", "SetGrid2");
create_check_menu_item_with_mnemonic(menu, "Grid4", "SetGrid4");
create_check_menu_item_with_mnemonic(menu, "Grid8", "SetGrid8");
create_check_menu_item_with_mnemonic(menu, "Grid16", "SetGrid16");
create_check_menu_item_with_mnemonic(menu, "Grid32", "SetGrid32");
create_check_menu_item_with_mnemonic(menu, "Grid64", "SetGrid64");
create_check_menu_item_with_mnemonic(menu, "Grid128", "SetGrid128");
create_check_menu_item_with_mnemonic(menu, "Grid256", "SetGrid256");
}
void Grid_registerShortcuts()
{
command_connect_accelerator("ToggleGrid");
command_connect_accelerator("GridDown");
command_connect_accelerator("GridUp");
}
void Grid_constructPreferences(PreferencesPage& page)
{
page.appendCombo(
"Default grid spacing",
g_grid_default,
ARRAY_RANGE(g_gridnames)
);
}
void Grid_constructPage(PreferenceGroup& group)
{
PreferencesPage page(group.createPage("Grid", "Grid Settings"));
Grid_constructPreferences(page);
}
void Grid_registerPreferencesPage()
{
PreferencesDialog_addSettingsPage(FreeCaller1<PreferenceGroup&, Grid_constructPage>());
}
void Grid_construct()
{
Grid_registerPreferencesPage();
g_grid_default = GridDefault_forGridPower(GRIDPOWER_8);
GlobalPreferenceSystem().registerPreference("GridDefault", IntImportStringCaller(g_grid_default), IntExportStringCaller(g_grid_default));
g_grid_power = GridPower_forGridDefault(g_grid_default);
g_gridsize = GridSize_forGridPower(g_grid_power);
}
void Grid_destroy()
{
}

40
radiant/grid.h Normal file
View File

@@ -0,0 +1,40 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#if !defined(INCLUDED_GRID_H)
#define INCLUDED_GRID_H
float GetGridSize();
int Grid_getPower();
class Callback;
void AddGridChangeCallback(const Callback& callback);
void Grid_registerCommands();
typedef struct _GtkMenu GtkMenu;
void Grid_constructMenu(GtkMenu* menu);
void Grid_registerShortcuts();
void Grid_construct();
void Grid_destroy();
#endif

232
radiant/groupdialog.cpp Normal file
View File

@@ -0,0 +1,232 @@
/*
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
*/
//
// Floating dialog that contains a notebook with at least Entities and Group tabs
// I merged the 2 MS Windows dialogs in a single class
//
// Leonardo Zide (leo@lokigames.com)
//
#include "groupdialog.h"
#include "debugging/debugging.h"
#include <vector>
#include <gtk/gtknotebook.h>
#include <gtk/gtktextview.h>
#include <gtk/gtklabel.h>
#include <gtk/gtkscrolledwindow.h>
#include "gtkutil/widget.h"
#include "gtkutil/accelerator.h"
#include "entityinspector.h"
#include "gtkmisc.h"
#include "multimon.h"
#include "console.h"
#include "commands.h"
#include <gtk/gtkwidget.h>
#include "gtkutil/window.h"
class GroupDlg
{
public:
GtkWidget* m_pNotebook;
GtkWindow* m_window;
GroupDlg();
void Create(GtkWindow* parent);
void Show()
{
// workaround for strange gtk behaviour - modifying the contents of a window while it is not visible causes the window position to change without sending a configure_event
m_position_tracker.sync(m_window);
gtk_widget_show(GTK_WIDGET(m_window));
}
void Hide()
{
gtk_widget_hide(GTK_WIDGET(m_window));
}
WindowPositionTracker m_position_tracker;
};
namespace
{
GroupDlg g_GroupDlg;
std::size_t g_current_page;
std::vector<StringExportCallback> g_pages;
}
void GroupDialog_updatePageTitle(GtkWindow* window, std::size_t pageIndex)
{
if(pageIndex < g_pages.size())
{
g_pages[pageIndex](PointerCaller1<GtkWindow, const char*, gtk_window_set_title>(window));
}
}
static gboolean switch_page(GtkNotebook *notebook, GtkNotebookPage *page, guint page_num, gpointer data)
{
GroupDialog_updatePageTitle(GTK_WINDOW(data), page_num);
g_current_page = page_num;
return FALSE;
}
GroupDlg::GroupDlg() : m_window(0)
{
m_position_tracker.setPosition(c_default_window_pos);
}
void GroupDlg::Create(GtkWindow* parent)
{
ASSERT_MESSAGE(m_window == 0, "dialog already created");
GtkWindow* window = create_persistent_floating_window("Entities", parent);
global_accel_connect_window(window);
window_connect_focus_in_clear_focus_widget(window);
m_window = window;
#ifdef WIN32
if( g_multimon_globals.m_bStartOnPrimMon )
{
WindowPosition pos(m_position_tracker.getPosition());
PositionWindowOnPrimaryScreen(pos);
m_position_tracker.setPosition(pos);
}
#endif
m_position_tracker.connect(window);
{
GtkWidget* notebook = gtk_notebook_new();
gtk_widget_show(notebook);
gtk_container_add (GTK_CONTAINER (window), notebook);
gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_BOTTOM);
m_pNotebook = notebook;
g_signal_connect(G_OBJECT(notebook), "switch_page", G_CALLBACK(switch_page), window);
}
}
GtkWidget* GroupDialog_addPage(const char* tabLabel, GtkWidget* widget, const StringExportCallback& title)
{
GtkWidget* w = gtk_label_new(tabLabel);
gtk_widget_show(w);
GtkWidget* page = gtk_notebook_get_nth_page(GTK_NOTEBOOK(g_GroupDlg.m_pNotebook), gtk_notebook_insert_page(GTK_NOTEBOOK(g_GroupDlg.m_pNotebook), widget, w, -1));
g_pages.push_back(title);
return page;
}
bool GroupDialog_isShown()
{
return widget_is_visible(GTK_WIDGET(g_GroupDlg.m_window));
}
void GroupDialog_setShown(bool shown)
{
shown ? g_GroupDlg.Show() : g_GroupDlg.Hide();
}
void GroupDialog_ToggleShow()
{
GroupDialog_setShown(!GroupDialog_isShown());
}
void GroupDialog_constructWindow(GtkWindow* main_window)
{
g_GroupDlg.Create(main_window);
}
void GroupDialog_destroyWindow()
{
ASSERT_NOTNULL(g_GroupDlg.m_window);
destroy_floating_window(g_GroupDlg.m_window);
g_GroupDlg.m_window = 0;
}
GtkWindow* GroupDialog_getWindow()
{
return g_GroupDlg.m_window;
}
void GroupDialog_show()
{
g_GroupDlg.Show();
}
GtkWidget* GroupDialog_getPage()
{
return gtk_notebook_get_nth_page(GTK_NOTEBOOK(g_GroupDlg.m_pNotebook), gint(g_current_page));
}
void GroupDialog_setPage(GtkWidget* page)
{
g_current_page = gtk_notebook_page_num(GTK_NOTEBOOK(g_GroupDlg.m_pNotebook), page);
gtk_notebook_set_current_page(GTK_NOTEBOOK(g_GroupDlg.m_pNotebook), gint(g_current_page));
}
void GroupDialog_showPage(GtkWidget* page)
{
if(GroupDialog_getPage() == page)
{
GroupDialog_ToggleShow();
}
else
{
gtk_widget_show(GTK_WIDGET(g_GroupDlg.m_window));
GroupDialog_setPage(page);
}
}
void GroupDialog_cycle()
{
g_current_page = (g_current_page + 1) % g_pages.size();
gtk_notebook_set_current_page(GTK_NOTEBOOK(g_GroupDlg.m_pNotebook), gint(g_current_page));
}
void GroupDialog_updatePageTitle(GtkWidget* page)
{
if(GroupDialog_getPage() == page)
{
GroupDialog_updatePageTitle(g_GroupDlg.m_window, g_current_page);
}
}
#include "preferencesystem.h"
void GroupDialog_Construct()
{
GlobalPreferenceSystem().registerPreference("EntityWnd", WindowPositionTrackerImportStringCaller(g_GroupDlg.m_position_tracker), WindowPositionTrackerExportStringCaller(g_GroupDlg.m_position_tracker));
GlobalCommands_insert("ViewEntityInfo", FreeCaller<GroupDialog_ToggleShow>(), Accelerator('N'));
}
void GroupDialog_Destroy()
{
}

48
radiant/groupdialog.h Normal file
View File

@@ -0,0 +1,48 @@
/*
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
*/
#if !defined(INCLUDED_GROUPDIALOG_H)
#define INCLUDED_GROUPDIALOG_H
#include "generic/callback.h"
typedef struct _GtkWidget GtkWidget;
typedef struct _GtkWindow GtkWindow;
void GroupDialog_Construct();
void GroupDialog_Destroy();
void GroupDialog_constructWindow(GtkWindow* main_window);
void GroupDialog_destroyWindow();
GtkWindow* GroupDialog_getWindow();
void GroupDialog_show();
inline void RawStringExport(const char* string, const StringImportCallback& importer)
{
importer(string);
}
typedef ConstPointerCaller1<char, const StringImportCallback&, RawStringExport> RawStringExportCaller;
GtkWidget* GroupDialog_addPage(const char* tabLabel, GtkWidget* widget, const StringExportCallback& title);
void GroupDialog_showPage(GtkWidget* page);
void GroupDialog_updatePageTitle(GtkWidget* page);
#endif

1074
radiant/gtkdlgs.cpp Normal file

File diff suppressed because it is too large Load Diff

57
radiant/gtkdlgs.h Normal file
View File

@@ -0,0 +1,57 @@
/*
Copyright (c) 2001, Loki software, inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
Neither the name of Loki software nor the names of its contributors may be used
to endorse or promote products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if !defined(INCLUDED_GTKDLGS_H)
#define INCLUDED_GTKDLGS_H
#include "qerplugin.h"
EMessageBoxReturn DoLightIntensityDlg (int *intensity);
EMessageBoxReturn DoTextureLayout (float *fx, float *fy);
void DoTextEditor (const char* filename, int cursorpos);
void DoProjectSettings();
void DoTextureListDlg();
void DoFind();
void DoSides(int type, int axis);
void DoAbout();
#ifdef WIN32
extern bool g_TextEditor_useWin32Editor;
#else
#include "string/stringfwd.h"
extern bool g_TextEditor_useCustomEditor;
extern CopiedString g_TextEditor_editorCommand;
#endif
#endif

164
radiant/gtkmisc.cpp Normal file
View File

@@ -0,0 +1,164 @@
/*
Copyright (c) 2001, Loki software, inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
Neither the name of Loki software nor the names of its contributors may be used
to endorse or promote products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//
// Small functions to help with GTK
//
#include "gtkmisc.h"
#include <gtk/gtkcolorseldialog.h>
#include <gtk/gtkentry.h>
#include "math/vector.h"
#include "os/path.h"
#include "gtkutil/dialog.h"
#include "gtkutil/filechooser.h"
#include "gtkutil/menu.h"
#include "gtkutil/toolbar.h"
#include "commands.h"
// =============================================================================
// Misc stuff
void command_connect_accelerator(const char* name)
{
const Command& command = GlobalCommands_find(name);
GlobalShortcuts_register(name);
command_connect_accelerator(command.m_accelerator, command.m_callback);
}
void command_disconnect_accelerator(const char* name)
{
const Command& command = GlobalCommands_find(name);
command_disconnect_accelerator(command.m_accelerator, command.m_callback);
}
void toggle_add_accelerator(const char* name)
{
const Toggle& toggle = GlobalToggles_find(name);
GlobalShortcuts_register(name);
command_connect_accelerator(toggle.m_command.m_accelerator, toggle.m_command.m_callback);
}
GtkCheckMenuItem* create_check_menu_item_with_mnemonic(GtkMenu* menu, const char* mnemonic, const char* commandName)
{
GlobalShortcuts_register(commandName);
const Toggle& toggle = GlobalToggles_find(commandName);
command_connect_accelerator(toggle.m_command.m_accelerator, toggle.m_command.m_callback);
return create_check_menu_item_with_mnemonic(menu, mnemonic, toggle);
}
GtkMenuItem* create_menu_item_with_mnemonic(GtkMenu* menu, const char *mnemonic, const char* commandName)
{
GlobalShortcuts_register(commandName);
const Command& command = GlobalCommands_find(commandName);
command_connect_accelerator(command.m_accelerator, command.m_callback);
return create_menu_item_with_mnemonic(menu, mnemonic, command);
}
GtkButton* toolbar_append_button(GtkToolbar* toolbar, const char* description, const char* icon, const char* commandName)
{
return toolbar_append_button(toolbar, description, icon, GlobalCommands_find(commandName));
}
GtkToggleButton* toolbar_append_toggle_button(GtkToolbar* toolbar, const char* description, const char* icon, const char* commandName)
{
return toolbar_append_toggle_button(toolbar, description, icon, GlobalToggles_find(commandName));
}
// =============================================================================
// File dialog
bool color_dialog (GtkWidget *parent, Vector3& color, const char* title)
{
GtkWidget* dlg;
double clr[3];
ModalDialog dialog;
clr[0] = color[0];
clr[1] = color[1];
clr[2] = color[2];
dlg = gtk_color_selection_dialog_new (title);
gtk_color_selection_set_color (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (dlg)->colorsel), clr);
g_signal_connect(G_OBJECT(dlg), "delete_event", G_CALLBACK(dialog_delete_callback), &dialog);
g_signal_connect(G_OBJECT(GTK_COLOR_SELECTION_DIALOG(dlg)->ok_button), "clicked", G_CALLBACK(dialog_button_ok), &dialog);
g_signal_connect(G_OBJECT(GTK_COLOR_SELECTION_DIALOG(dlg)->cancel_button), "clicked", G_CALLBACK(dialog_button_cancel), &dialog);
if (parent != 0)
gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (parent));
bool ok = modal_dialog_show(GTK_WINDOW(dlg), dialog) == eIDOK;
if(ok)
{
GdkColor gdkcolor;
gtk_color_selection_get_current_color (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (dlg)->colorsel), &gdkcolor);
clr[0] = gdkcolor.red / 65535.0;
clr[1] = gdkcolor.green / 65535.0;
clr[2] = gdkcolor.blue / 65535.0;
color[0] = (float)clr[0];
color[1] = (float)clr[1];
color[2] = (float)clr[2];
}
gtk_widget_destroy(dlg);
return ok;
}
void button_clicked_entry_browse_file(GtkWidget* widget, GtkEntry* entry)
{
const char *filename = file_dialog(gtk_widget_get_toplevel(widget), TRUE, "Choose File", gtk_entry_get_text(entry));
if(filename != 0)
{
gtk_entry_set_text(entry, filename);
}
}
void button_clicked_entry_browse_directory(GtkWidget* widget, GtkEntry* entry)
{
const char* text = gtk_entry_get_text(entry);
char *dir = dir_dialog(gtk_widget_get_toplevel(widget), "Choose Directory", path_is_absolute(text) ? text : "" );
if(dir != 0)
{
gchar* converted = g_filename_to_utf8(dir, -1, 0, 0, 0);
gtk_entry_set_text(entry, converted);
g_free(dir);
g_free(converted);
}
}

75
radiant/gtkmisc.h Normal file
View File

@@ -0,0 +1,75 @@
/*
Copyright (c) 2001, Loki software, inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
Neither the name of Loki software nor the names of its contributors may be used
to endorse or promote products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if !defined(INCLUDED_GTKMISC_H)
#define INCLUDED_GTKMISC_H
#include <gtk/gtkmain.h>
inline void process_gui()
{
while(gtk_events_pending())
{
gtk_main_iteration();
}
}
void command_connect_accelerator(const char* commandName);
void command_disconnect_accelerator(const char* commandName);
void toggle_add_accelerator(const char* commandName);
typedef struct _GtkMenu GtkMenu;
typedef struct _GtkMenuItem GtkMenuItem;
typedef struct _GtkCheckMenuItem GtkCheckMenuItem;
// this also sets up the shortcut using command_connect_accelerator
GtkMenuItem* create_menu_item_with_mnemonic(GtkMenu *menu, const char *mnemonic, const char* commandName);
// this also sets up the shortcut using command_connect_accelerator
GtkCheckMenuItem* create_check_menu_item_with_mnemonic(GtkMenu* menu, const char* mnemonic, const char* commandName);
typedef struct _GtkButton GtkButton;
typedef struct _GtkToggleButton GtkToggleButton;
typedef struct _GtkToolbar GtkToolbar;
// this DOES NOT set up the shortcut using command_connect_accelerator
GtkButton* toolbar_append_button(GtkToolbar* toolbar, const char* description, const char* icon, const char* commandName);
// this DOES NOT set up the shortcut using command_connect_accelerator
GtkToggleButton* toolbar_append_toggle_button(GtkToolbar* toolbar, const char* description, const char* icon, const char* commandName);
template<typename Element> class BasicVector3;
typedef BasicVector3<float> Vector3;
bool color_dialog (GtkWidget *parent, Vector3& color, const char* title = "Choose Color");
typedef struct _GtkEntry GtkEntry;
void button_clicked_entry_browse_file(GtkWidget* widget, GtkEntry* entry);
void button_clicked_entry_browse_directory(GtkWidget* widget, GtkEntry* entry);
#endif

138
radiant/help.cpp Normal file
View File

@@ -0,0 +1,138 @@
/*
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
*/
#include "help.h"
#include "debugging/debugging.h"
#include <vector>
#include <list>
#include "libxml/parser.h"
#include "generic/callback.h"
#include "gtkutil/menu.h"
#include "stream/stringstream.h"
#include "os/file.h"
#include "url.h"
#include "preferences.h"
#include "mainframe.h"
/*!
the urls to fire up in the game packs help menus
*/
namespace
{
std::list<CopiedString> mHelpURLs;
}
/*!
needed for hooking in Gtk+
*/
void HandleHelpCommand(CopiedString& str)
{
OpenURL(str.c_str());
}
void process_xlink(const char* filename, const char *menu_name, const char *base_url, GtkMenu *menu)
{
if(file_exists(filename))
{
xmlDocPtr pDoc = xmlParseFile(filename);
if (pDoc)
{
globalOutputStream() << "Processing .xlink file '" << filename << "'\n";
// create sub menu
GtkMenu* menu_in_menu = create_sub_menu_with_mnemonic(menu, menu_name);
// start walking the nodes, find the 'links' one
xmlNodePtr pNode = pDoc->children;
while (pNode && strcmp((const char*)pNode->name, "links"))
pNode=pNode->next;
if (pNode)
{
pNode = pNode->children;
while(pNode)
{
if(!strcmp((const char*)pNode->name, "item"))
{
// process the URL
CopiedString url;
xmlChar* prop = xmlGetProp(pNode, reinterpret_cast<const xmlChar*>("url"));
ASSERT_NOTNULL(prop);
if(strstr(reinterpret_cast<const char*>(prop), "http://"))
{
// complete URL
url = reinterpret_cast<const char*>(prop);
}
else
{
// relative URL
StringOutputStream full(256);
full << base_url << reinterpret_cast<const char*>(prop);
url = full.c_str();
}
mHelpURLs.push_back(url);
xmlFree(prop);
prop = xmlGetProp(pNode, reinterpret_cast<const xmlChar*>("name"));
ASSERT_NOTNULL(prop);
create_menu_item_with_mnemonic(menu_in_menu, reinterpret_cast<const char*>(prop), ReferenceCaller<CopiedString, HandleHelpCommand>(mHelpURLs.back()));
xmlFree(prop);
}
pNode=pNode->next;
}
}
xmlFreeDoc(pDoc);
}
else
{
globalOutputStream() << "'" << filename << "' parse failed\n";
}
}
else
{
globalOutputStream() << "'" << filename << "' not found\n";
}
}
void create_game_help_menu(GtkMenu *menu)
{
StringOutputStream filename(256);
filename << AppPath_get() << "global.xlink";
process_xlink(filename.c_str(), "General", AppPath_get(), menu);
#if 1
filename.clear();
filename << g_pGameDescription->mGameToolsPath.c_str() << "game.xlink";
process_xlink(filename.c_str(), g_pGameDescription->getRequiredKeyValue("name"), g_pGameDescription->mGameToolsPath.c_str(), menu);
#else
for(std::list<CGameDescription *>::iterator iGame = g_GamesDialog.mGames.begin(); iGame != g_GamesDialog.mGames.end(); ++iGame)
{
filename.clear();
filename << (*iGame)->mGameToolsPath.c_str() << "game.xlink";
process_xlink(filename.c_str(), (*iGame)->getRequiredKeyValue("name"), (*iGame)->mGameToolsPath.c_str(), menu);
}
#endif
}

28
radiant/help.h Normal file
View File

@@ -0,0 +1,28 @@
/*
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
*/
#if !defined(INCLUDED_HELP_H)
#define INCLUDED_HELP_H
typedef struct _GtkMenu GtkMenu;
void create_game_help_menu(GtkMenu *menu);
#endif

70
radiant/image.cpp Normal file
View File

@@ -0,0 +1,70 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#include "image.h"
#include "modulesystem.h"
#include "iimage.h"
#include "ifilesystem.h"
#include "iarchive.h"
#include "generic/reference.h"
#include "os/path.h"
#include "stream/stringstream.h"
typedef Modules<_QERPlugImageTable> ImageModules;
ImageModules& Textures_getImageModules();
/// \brief Returns a new image for the first file matching \p name in one of the available texture formats, or 0 if no file is found.
Image* QERApp_LoadImage(void* environment, const char* name)
{
Image* image = 0;
class LoadImageVisitor : public ImageModules::Visitor
{
const char* m_name;
Image*& m_image;
public:
LoadImageVisitor(const char* name, Image*& image)
: m_name(name), m_image(image)
{
}
void visit(const char* name, const _QERPlugImageTable& table)
{
if(m_image == 0)
{
StringOutputStream fullname(256);
fullname << m_name << '.' << name;
ArchiveFile* file = GlobalFileSystem().openFile(fullname.c_str());
if(file != 0)
{
m_image = table.loadImage(*file);
file->release();
}
}
}
} visitor(name, image);
Textures_getImageModules().foreachModule(visitor);
return image;
}

28
radiant/image.h Normal file
View File

@@ -0,0 +1,28 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#if !defined (INCLUDED_IMAGE_H)
#define INCLUDED_IMAGE_H
class Image;
Image* QERApp_LoadImage(void* environment, const char* name);
#endif

621
radiant/main.cpp Normal file
View File

@@ -0,0 +1,621 @@
/*
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
*/
/*! \mainpage GtkRadiant Documentation Index
\section intro_sec Introduction
This documentation is generated from comments in the source code.
\section links_sec Useful Links
\link include/itextstream.h include/itextstream.h \endlink - Global output and error message streams, similar to std::cout and std::cerr. \n
FileInputStream - similar to std::ifstream (binary mode) \n
FileOutputStream - similar to std::ofstream (binary mode) \n
TextFileInputStream - similar to std::ifstream (text mode) \n
TextFileOutputStream - similar to std::ofstream (text mode) \n
StringOutputStream - similar to std::stringstream \n
\link string/string.h string/string.h \endlink - C-style string comparison and memory management. \n
\link os/path.h os/path.h \endlink - Path manipulation for radiant's standard path format \n
\link os/file.h os/file.h \endlink - OS file-system access. \n
::CopiedString - automatic string memory management \n
Array - automatic array memory management \n
HashTable - generic hashtable, similar to std::hash_map \n
\link math/vector.h math/vector.h \endlink - Vectors \n
\link math/matrix.h math/matrix.h \endlink - Matrices \n
\link math/quaternion.h math/quaternion.h \endlink - Quaternions \n
\link math/plane.h math/plane.h \endlink - Planes \n
\link math/aabb.h math/aabb.h \endlink - AABBs \n
Callback MemberCaller FunctionCaller - callbacks similar to using boost::function with boost::bind \n
SmartPointer SmartReference - smart-pointer and smart-reference similar to Loki's SmartPtr \n
\link generic/bitfield.h generic/bitfield.h \endlink - Type-safe bitfield \n
\link generic/enumeration.h generic/enumeration.h \endlink - Type-safe enumeration \n
DefaultAllocator - Memory allocation using new/delete, compliant with std::allocator interface \n
\link debugging/debugging.h debugging/debugging.h \endlink - Debugging macros \n
*/
#include "main.h"
#include "version.h"
#include "debugging/debugging.h"
#include "iundo.h"
#include <gtk/gtkmain.h>
#include "cmdlib.h"
#include "os/file.h"
#include "os/path.h"
#include "stream/stringstream.h"
#include "stream/textfilestream.h"
#include "gtkutil/messagebox.h"
#include "gtkutil/image.h"
#include "console.h"
#include "texwindow.h"
#include "map.h"
#include "mainframe.h"
#include "commands.h"
#include "preferences.h"
#include "environment.h"
#include "referencecache.h"
#include "stacktrace.h"
void show_splash();
void hide_splash();
void error_redirect (const gchar *domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data)
{
gboolean in_recursion;
gboolean is_fatal;
char buf[256];
in_recursion = (log_level & G_LOG_FLAG_RECURSION) != 0;
is_fatal = (log_level & G_LOG_FLAG_FATAL) != 0;
log_level = (GLogLevelFlags) (log_level & G_LOG_LEVEL_MASK);
if (!message)
message = "(0) message";
if (domain)
strcpy (buf, domain);
else
strcpy (buf, "**");
strcat (buf, "-");
switch (log_level)
{
case G_LOG_LEVEL_ERROR:
if (in_recursion)
strcat (buf, "ERROR (recursed) **: ");
else
strcat (buf, "ERROR **: ");
break;
case G_LOG_LEVEL_CRITICAL:
if (in_recursion)
strcat (buf, "CRITICAL (recursed) **: ");
else
strcat (buf, "CRITICAL **: ");
break;
case G_LOG_LEVEL_WARNING:
if (in_recursion)
strcat (buf, "WARNING (recursed) **: ");
else
strcat (buf, "WARNING **: ");
break;
case G_LOG_LEVEL_MESSAGE:
if (in_recursion)
strcat (buf, "Message (recursed): ");
else
strcat (buf, "Message: ");
break;
case G_LOG_LEVEL_INFO:
if (in_recursion)
strcat (buf, "INFO (recursed): ");
else
strcat (buf, "INFO: ");
break;
case G_LOG_LEVEL_DEBUG:
if (in_recursion)
strcat (buf, "DEBUG (recursed): ");
else
strcat (buf, "DEBUG: ");
break;
default:
/* we are used for a log level that is not defined by GLib itself,
* try to make the best out of it.
*/
if (in_recursion)
strcat (buf, "LOG (recursed:");
else
strcat (buf, "LOG (");
if (log_level)
{
gchar string[] = "0x00): ";
gchar *p = string + 2;
guint i;
i = g_bit_nth_msf (log_level, -1);
*p = i >> 4;
p++;
*p = '0' + (i & 0xf);
if (*p > '9')
*p += 'A' - '9' - 1;
strcat (buf, string);
} else
strcat (buf, "): ");
}
strcat (buf, message);
if (is_fatal)
strcat (buf, "\naborting...\n");
else
strcat (buf, "\n");
printf ("%s\n", buf);
ERROR_MESSAGE("GTK+ error: " << buf);
}
#if defined (_DEBUG) && defined (WIN32) && defined (_MSC_VER)
#include "crtdbg.h"
#endif
void crt_init()
{
#if defined (_DEBUG) && defined (WIN32) && defined (_MSC_VER)
_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif
}
class Lock
{
bool m_locked;
public:
Lock() : m_locked(false)
{
}
void lock()
{
m_locked = true;
}
void unlock()
{
m_locked = false;
}
bool locked() const
{
return m_locked;
}
};
class ScopedLock
{
Lock& m_lock;
public:
ScopedLock(Lock& lock) : m_lock(lock)
{
m_lock.lock();
}
~ScopedLock()
{
m_lock.unlock();
}
};
class PopupDebugMessageHandler : public DebugMessageHandler
{
StringOutputStream m_buffer;
Lock m_lock;
public:
TextOutputStream& getOutputStream()
{
if(!m_lock.locked())
{
return m_buffer;
}
return globalErrorStream();
}
bool handleMessage()
{
getOutputStream() << "----------------\n";
write_stack_trace(getOutputStream());
getOutputStream() << "----------------\n";
if(!m_lock.locked())
{
ScopedLock lock(m_lock);
#if defined _DEBUG
m_buffer << "Break into the debugger?\n";
globalErrorStream() << m_buffer.c_str();
bool handled = gtk_MessageBox(0, m_buffer.c_str(), "Radiant - Runtime Error", eMB_YESNO, eMB_ICONERROR) == eIDNO;
m_buffer.clear();
return handled;
#else
m_buffer << "Please report this error to the developers\n";
globalErrorStream() << m_buffer.c_str();
gtk_MessageBox(0, m_buffer.c_str(), "Radiant - Runtime Error", eMB_OK, eMB_ICONERROR);
m_buffer.clear();
return true;
#endif
}
return false;
}
};
typedef Static<PopupDebugMessageHandler> GlobalPopupDebugMessageHandler;
void streams_init()
{
GlobalErrorStream::instance().setOutputStream(getSysPrintErrorStream());
GlobalOutputStream::instance().setOutputStream(getSysPrintOutputStream());
}
void paths_init()
{
const char* home = environment_get_home_path();
Q_mkdir(home);
{
StringOutputStream path(256);
path << home << RADIANT_VERSION << '/';
g_strSettingsPath = path.c_str();
}
Q_mkdir(g_strSettingsPath.c_str());
g_strAppPath = environment_get_app_path();
// radiant is installed in the parent dir of "tools/"
// NOTE: this is not very easy for debugging
// maybe add options to lookup in several places?
// (for now I had to create symlinks)
{
StringOutputStream path(256);
path << g_strAppPath.c_str() << "bitmaps/";
BitmapsPath_set(path.c_str());
}
// we will set this right after the game selection is done
g_strGameToolsPath = g_strAppPath;
}
bool check_version_file(const char* filename, const char* version)
{
TextFileInputStream file(filename);
if(!file.failed())
{
char buf[10];
buf[file.read(buf, 9)] = '\0';
// chomp it (the hard way)
int chomp = 0;
while(buf[chomp] >= '0' && buf[chomp] <= '9')
chomp++;
buf[chomp] = '\0';
return string_equal(buf, version);
}
return false;
}
bool check_version()
{
// a safe check to avoid people running broken installations
// (otherwise, they run it, crash it, and blame us for not forcing them hard enough to pay attention while installing)
// make something idiot proof and someone will make better idiots, this may be overkill
// let's leave it disabled in debug mode in any case
// http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=431
#ifndef _DEBUG
#define CHECK_VERSION
#endif
#ifdef CHECK_VERSION
// locate and open RADIANT_MAJOR and RADIANT_MINOR
bool bVerIsGood = true;
{
StringOutputStream ver_file_name(256);
ver_file_name << AppPath_get() << "RADIANT_MAJOR";
bVerIsGood = check_version_file(ver_file_name.c_str(), RADIANT_MAJOR_VERSION);
}
{
StringOutputStream ver_file_name(256);
ver_file_name << AppPath_get() << "RADIANT_MINOR";
bVerIsGood = check_version_file(ver_file_name.c_str(), RADIANT_MINOR_VERSION);
}
if (!bVerIsGood)
{
StringOutputStream msg(256);
msg << "This editor binary (" RADIANT_VERSION ") doesn't match what the latest setup has configured in this directory\n"
"Make sure you run the right/latest editor binary you installed\n"
<< AppPath_get();
gtk_MessageBox(0, msg.c_str(), "Radiant", eMB_OK, eMB_ICONDEFAULT);
}
return bVerIsGood;
#else
return true;
#endif
}
void create_global_pid()
{
/*!
the global prefs loading / game selection dialog might fail for any reason we don't know about
we need to catch when it happens, to cleanup the stateful prefs which might be killing it
and to turn on console logging for lookup of the problem
this is the first part of the two step .pid system
http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=297
*/
StringOutputStream g_pidFile(256); ///< the global .pid file (only for global part of the startup)
g_pidFile << SettingsPath_get() << "radiant.pid";
FILE *pid;
pid = fopen (g_pidFile.c_str(), "r");
if (pid != 0)
{
fclose (pid);
if (remove (g_pidFile.c_str()) == -1)
{
StringOutputStream msg(256);
msg << "WARNING: Could not delete " << g_pidFile.c_str();
gtk_MessageBox (0, msg.c_str(), "Radiant", eMB_OK, eMB_ICONERROR );
}
// in debug, never prompt to clean registry, turn console logging auto after a failed start
#if !defined(_DEBUG)
StringOutputStream msg(256);
msg << "Radiant failed to start properly the last time it was run.\n"
"The failure may be related to current global preferences.\n"
"Do you want to reset global preferences to defaults?";
if (gtk_MessageBox (0, msg.c_str(), "Radiant - Startup Failure", eMB_YESNO, eMB_ICONQUESTION) == eIDYES)
{
g_GamesDialog.Reset();
}
msg.clear();
msg << "Logging console output to " << SettingsPath_get() << "radiant.log\nRefer to the log if Radiant fails to start again.";
gtk_MessageBox (0, msg.c_str(), "Radiant - Console Log", eMB_OK);
#endif
// set without saving, the class is not in a coherent state yet
// just do the value change and call to start logging, CGamesDialog will pickup when relevant
g_GamesDialog.m_bForceLogConsole = true;
Sys_LogFile(true);
}
// create a primary .pid for global init run
pid = fopen (g_pidFile.c_str(), "w");
if (pid)
fclose (pid);
}
void remove_global_pid()
{
StringOutputStream g_pidFile(256);
g_pidFile << SettingsPath_get() << "radiant.pid";
// close the primary
if (remove (g_pidFile.c_str()) == -1)
{
StringOutputStream msg(256);
msg << "WARNING: Could not delete " << g_pidFile.c_str();
gtk_MessageBox (0, msg.c_str(), "Radiant", eMB_OK, eMB_ICONERROR );
}
}
/*!
now the secondary game dependant .pid file
http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=297
*/
void create_local_pid()
{
StringOutputStream g_pidGameFile(256); ///< the game-specific .pid file
g_pidGameFile << SettingsPath_get() << g_pGameDescription->mGameFile.c_str() << "/radiant-game.pid";
FILE *pid = fopen (g_pidGameFile.c_str(), "r");
if (pid != 0)
{
fclose (pid);
if (remove (g_pidGameFile.c_str()) == -1)
{
StringOutputStream msg;
msg << "WARNING: Could not delete " << g_pidGameFile.c_str();
gtk_MessageBox (0, msg.c_str(), "Radiant", eMB_OK, eMB_ICONERROR );
}
// in debug, never prompt to clean registry, turn console logging auto after a failed start
#if !defined(_DEBUG)
StringOutputStream msg;
msg << "Radiant failed to start properly the last time it was run.\n"
"The failure may be caused by current preferences.\n"
"Do you want to reset all preferences to defaults?";
if (gtk_MessageBox (0, msg.c_str(), "Radiant - Startup Failure", eMB_YESNO, eMB_ICONQUESTION) == eIDYES)
{
Preferences_Reset();
}
msg.clear();
msg << "Logging console output to " << SettingsPath_get() << "radiant.log\nRefer to the log if Radiant fails to start again.";
gtk_MessageBox (0, msg.c_str(), "Radiant - Console Log", eMB_OK);
#endif
// force console logging on! (will go in prefs too)
g_GamesDialog.m_bForceLogConsole = true;
Sys_LogFile(true);
}
else
{
// create one, will remove right after entering message loop
pid = fopen (g_pidGameFile.c_str(), "w");
if (pid)
fclose (pid);
}
}
/*!
now the secondary game dependant .pid file
http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=297
*/
void remove_local_pid()
{
StringOutputStream g_pidGameFile(256);
g_pidGameFile << SettingsPath_get() << g_pGameDescription->mGameFile.c_str() << "/radiant-game.pid";
remove(g_pidGameFile.c_str());
}
void user_shortcuts_init()
{
StringOutputStream path(256);
path << SettingsPath_get() << g_pGameDescription->mGameFile.c_str() << '/';
LoadCommandMap(path.c_str());
SaveCommandMap(path.c_str());
}
int main (int argc, char* argv[])
{
crt_init();
streams_init();
gtk_disable_setlocale();
gtk_init(&argc, &argv);
// redirect Gtk warnings to the console
g_log_set_handler ("Gdk", (GLogLevelFlags)(G_LOG_LEVEL_ERROR|G_LOG_LEVEL_CRITICAL|G_LOG_LEVEL_WARNING|
G_LOG_LEVEL_MESSAGE|G_LOG_LEVEL_INFO|G_LOG_LEVEL_DEBUG), error_redirect, 0);
g_log_set_handler ("Gtk", (GLogLevelFlags)(G_LOG_LEVEL_ERROR|G_LOG_LEVEL_CRITICAL|G_LOG_LEVEL_WARNING|
G_LOG_LEVEL_MESSAGE|G_LOG_LEVEL_INFO|G_LOG_LEVEL_DEBUG), error_redirect, 0);
g_log_set_handler ("GtkGLExt", (GLogLevelFlags)(G_LOG_LEVEL_ERROR|G_LOG_LEVEL_CRITICAL|G_LOG_LEVEL_WARNING|
G_LOG_LEVEL_MESSAGE|G_LOG_LEVEL_INFO|G_LOG_LEVEL_DEBUG), error_redirect, 0);
g_log_set_handler ("GLib", (GLogLevelFlags)(G_LOG_LEVEL_ERROR|G_LOG_LEVEL_CRITICAL|G_LOG_LEVEL_WARNING|
G_LOG_LEVEL_MESSAGE|G_LOG_LEVEL_INFO|G_LOG_LEVEL_DEBUG), error_redirect, 0);
g_log_set_handler (0, (GLogLevelFlags)(G_LOG_LEVEL_ERROR|G_LOG_LEVEL_CRITICAL|G_LOG_LEVEL_WARNING|
G_LOG_LEVEL_MESSAGE|G_LOG_LEVEL_INFO|G_LOG_LEVEL_DEBUG), error_redirect, 0);
GlobalDebugMessageHandler::instance().setHandler(GlobalPopupDebugMessageHandler::instance());
environment_init(argc, argv);
paths_init();
if(!check_version())
{
return EXIT_FAILURE;
}
show_splash();
create_global_pid();
GlobalPreferences_Init();
g_GamesDialog.Init();
g_strGameToolsPath = g_pGameDescription->mGameToolsPath;
remove_global_pid();
create_local_pid();
g_Preferences.Init();
// in a very particular post-.pid startup
// we may have the console turned on and want to keep it that way
// so we use a latching system
if (g_GamesDialog.m_bForceLogConsole)
{
Sys_LogFile(true);
g_Console_enableLogging = true;
g_GamesDialog.m_bForceLogConsole = false;
}
Radiant_Initialise();
global_accel_init();
user_shortcuts_init();
g_pParentWnd = 0;
g_pParentWnd = new MainFrame();
hide_splash();
if (g_bLoadLastMap && !g_strLastMap.empty())
{
Map_LoadFile(g_strLastMap.c_str());
}
else
{
Map_New();
}
// load up shaders now that we have the map loaded
// eviltypeguy
TextureBrowser_ShowStartupShaders(GlobalTextureBrowser());
remove_local_pid();
gtk_main();
// avoid saving prefs when the app is minimized
if (g_pParentWnd->IsSleeping())
{
globalOutputStream() << "Shutdown while sleeping, not saving prefs\n";
g_preferences_globals.disable_ini = true;
}
Map_Free();
if (!Map_Unnamed(g_map))
{
g_strLastMap = Map_Name(g_map);
}
delete g_pParentWnd;
global_accel_destroy();
Radiant_Shutdown();
// close the log file if any
Sys_LogFile(false);
return EXIT_SUCCESS;
}

25
radiant/main.h Normal file
View File

@@ -0,0 +1,25 @@
/*
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
*/
#if !defined(INCLUDED_MAIN_H)
#define INCLUDED_MAIN_H
#endif

3532
radiant/mainframe.cpp Normal file

File diff suppressed because it is too large Load Diff

279
radiant/mainframe.h Normal file
View File

@@ -0,0 +1,279 @@
/*
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
*/
#if !defined(INCLUDED_MAINFRAME_H)
#define INCLUDED_MAINFRAME_H
#include "gtkutil/window.h"
#include "gtkutil/idledraw.h"
#include "gtkutil/widget.h"
#include "string/string.h"
class IPlugIn;
class IToolbarButton;
class XYWnd;
class CamWnd;
class ZWnd;
typedef struct _GtkWidget GtkWidget;
typedef struct _GtkWindow GtkWindow;
const int c_command_status = 0;
const int c_position_status = 1;
const int c_brushcount_status = 2;
const int c_texture_status = 3;
const int c_grid_status = 4;
const int c_count_status = 5;
class MainFrame
{
public:
enum EViewStyle
{
eRegular = 0,
eFloating = 1,
eSplit = 2,
eRegularLeft = 3,
};
MainFrame();
~MainFrame();
GtkWindow* m_window;
CopiedString m_command_status;
CopiedString m_position_status;
CopiedString m_brushcount_status;
CopiedString m_texture_status;
CopiedString m_grid_status;
private:
void Create();
void SaveWindowInfo();
void Shutdown();
GtkWidget* m_vSplit;
GtkWidget* m_hSplit;
GtkWidget* m_vSplit2;
XYWnd* m_pXYWnd;
XYWnd* m_pYZWnd;
XYWnd* m_pXZWnd;
CamWnd* m_pCamWnd;
ZWnd* m_pZWnd;
XYWnd* m_pActiveXY;
bool m_bSleeping;
GtkWidget *m_pStatusLabel[c_count_status];
EViewStyle m_nCurrentStyle;
WindowPositionTracker m_position_tracker;
IdleDraw m_idleRedrawStatusText;
public:
bool IsSleeping()
{
return m_bSleeping;
}
void OnSleep();
void SetStatusText(CopiedString& status_text, const char* pText);
void UpdateStatusText();
void RedrawStatusText();
typedef MemberCaller<MainFrame, &MainFrame::RedrawStatusText> RedrawStatusTextCaller;
void SetGridStatus();
typedef MemberCaller<MainFrame, &MainFrame::SetGridStatus> SetGridStatusCaller;
void SetActiveXY(XYWnd* p);
XYWnd* ActiveXY()
{
return m_pActiveXY;
};
XYWnd* GetXYWnd()
{
return m_pXYWnd;
}
XYWnd* GetXZWnd()
{
return m_pXZWnd;
}
XYWnd* GetYZWnd()
{
return m_pYZWnd;
}
ZWnd* GetZWnd()
{
return m_pZWnd;
}
CamWnd* GetCamWnd()
{
return m_pCamWnd;
}
void ReleaseContexts();
void CreateContexts();
EViewStyle CurrentStyle()
{
return m_nCurrentStyle;
};
bool FloatingGroupDialog()
{
return CurrentStyle() == eFloating || CurrentStyle() == eSplit;
};
};
extern MainFrame* g_pParentWnd;
GtkWindow* MainFrame_getWindow();
enum EMouseButtonMode
{
ETwoButton = 0,
EThreeButton = 1,
};
struct glwindow_globals_t
{
int m_nMouseType;
glwindow_globals_t() :
m_nMouseType(EThreeButton)
{
}
};
void GLWindow_Construct();
void GLWindow_Destroy();
extern glwindow_globals_t g_glwindow_globals;
template<typename Value>
class LatchedValue;
typedef LatchedValue<bool> LatchedBool;
extern LatchedBool g_Layout_enableDetachableMenus;
void deleteSelection();
void Sys_Status(const char* status);
void ScreenUpdates_Disable(const char* message, const char* title = "");
void ScreenUpdates_Enable();
bool ScreenUpdates_Enabled();
void ScreenUpdates_process();
class ScopeDisableScreenUpdates
{
public:
ScopeDisableScreenUpdates(const char* message, const char* title = "")
{
ScreenUpdates_Disable(message, title);
}
~ScopeDisableScreenUpdates()
{
ScreenUpdates_Enable();
}
};
void EnginePath_Realise();
void EnginePath_Unrealise();
class ModuleObserver;
void Radiant_attachEnginePathObserver(ModuleObserver& observer);
void Radiant_detachEnginePathObserver(ModuleObserver& observer);
void Radiant_attachGameToolsPathObserver(ModuleObserver& observer);
void Radiant_detachGameToolsPathObserver(ModuleObserver& observer);
extern CopiedString g_strEnginePath;
void EnginePath_verify();
const char* EnginePath_get();
const char* QERApp_GetGamePath();
extern CopiedString g_strAppPath;
const char* AppPath_get();
extern CopiedString g_strSettingsPath;
const char* SettingsPath_get();
const char* const g_pluginsDir = "plugins/"; ///< name of plugins directory, always sub-directory of toolspath
const char* const g_modulesDir = "modules/"; ///< name of modules directory, always sub-directory of toolspath
extern CopiedString g_strGameToolsPath;
const char* GameToolsPath_get();
void Radiant_Initialise();
void Radiant_Shutdown();
void SaveMapAs();
void XY_UpdateAllWindows();
void UpdateAllWindows();
void ClipperChangeNotify();
void DefaultMode();
const char* basegame_get();
const char* gamename_get();
void gamename_set(const char* gamename);
void Radiant_attachGameNameObserver(ModuleObserver& observer);
void Radiant_detachGameNameObserver(ModuleObserver& observer);
const char* gamemode_get();
void gamemode_set(const char* gamemode);
void Radiant_attachGameModeObserver(ModuleObserver& observer);
void Radiant_detachGameModeObserver(ModuleObserver& observer);
void VFS_Construct();
void VFS_Destroy();
void HomePaths_Construct();
void HomePaths_Destroy();
void Radiant_attachHomePathsObserver(ModuleObserver& observer);
void Radiant_detachHomePathsObserver(ModuleObserver& observer);
void MainFrame_Construct();
void MainFrame_Destroy();
extern float (*GridStatus_getGridSize)();
extern int (*GridStatus_getRotateIncrement)();
extern int (*GridStatus_getFarClipDistance)();
extern bool (*GridStatus_getTextureLockEnabled)();
void GridStatus_onTextureLockEnabledChanged();
#endif

2297
radiant/map.cpp Normal file

File diff suppressed because it is too large Load Diff

169
radiant/map.h Normal file
View File

@@ -0,0 +1,169 @@
/*
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
*/
#if !defined(INCLUDED_MAP_H)
#define INCLUDED_MAP_H
#include "iscenegraph.h"
#include "generic/callback.h"
#include "string/stringfwd.h"
class Map;
extern Map g_map;
class MapFormat;
void Map_addValidCallback(Map& map, const Callback& callback);
bool Map_Valid(const Map& map);
class DeferredDraw
{
Callback m_draw;
bool m_defer;
bool m_deferred;
public:
DeferredDraw(const Callback& draw) : m_draw(draw), m_defer(false), m_deferred(false)
{
}
void defer()
{
m_defer = true;
}
void draw()
{
if(m_defer)
{
m_deferred = true;
}
else
{
m_draw();
}
}
void flush()
{
if(m_defer && m_deferred)
{
m_draw();
}
m_deferred = false;
m_defer = false;
}
};
inline void DeferredDraw_onMapValidChanged(DeferredDraw& self)
{
if(Map_Valid(g_map))
{
self.flush();
}
else
{
self.defer();
}
}
typedef ReferenceCaller<DeferredDraw, DeferredDraw_onMapValidChanged> DeferredDrawOnMapValidChangedCaller;
const char* Map_Name(const Map& map);
const MapFormat& Map_getFormat(const Map& map);
bool Map_Unnamed(const Map& map);
namespace scene
{
class Node;
class Graph;
}
scene::Node* Map_GetWorldspawn(const Map& map);
scene::Node* Map_FindWorldspawn(Map& map);
scene::Node& Map_FindOrInsertWorldspawn(Map& map);
template<typename Element> class BasicVector3;
typedef BasicVector3<float> Vector3;
extern Vector3 region_mins, region_maxs;
extern bool region_active;
// used to be #defines, multiple engine support suggests we should go towards dynamic
extern float g_MaxWorldCoord;
extern float g_MinWorldCoord;
void Map_LoadFile(const char* filename);
bool Map_SaveFile(const char* filename);
void Map_New();
void Map_Free();
void Map_RegionOff();
bool Map_SaveRegion(const char* filename);
class TextInputStream;
class TextOutputStream;
void Map_ImportSelected(TextInputStream& in, const MapFormat& format);
void Map_ExportSelected(TextOutputStream& out, const MapFormat& format);
bool Map_Modified(const Map& map);
void Map_SetModified(Map& map, bool modified);
bool Map_Save();
bool Map_SaveAs();
scene::Node& Node_Clone(scene::Node& node);
void DoMapInfo();
void Scene_parentSelectedBrushesToEntity(scene::Graph& graph, scene::Node& parent);
std::size_t Scene_countSelectedBrushes(scene::Graph& graph);
void Scene_parentSelected();
void OnUndoSizeChanged();
void NewMap();
void OpenMap();
void ImportMap();
void SaveMapAs();
void SaveMap();
void ExportMap();
void SaveRegion();
void Map_Traverse(scene::Node& root, const scene::Traversable::Walker& walker);
void SelectBrush (int entitynum, int brushnum);
extern CopiedString g_strLastMap;
extern bool g_bLoadLastMap;
void Map_Construct();
void Map_Destroy();
void Map_gatherNamespaced(scene::Node& root);
void Map_mergeClonedNames();
#endif

254
radiant/mru.cpp Normal file
View File

@@ -0,0 +1,254 @@
/*
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
*/
#include "mru.h"
#include <string.h>
#include <stdio.h>
#include <gtk/gtklabel.h>
#include "os/file.h"
#include "generic/callback.h"
#include "stream/stringstream.h"
#include "convert.h"
#include "gtkutil/menu.h"
#include "map.h"
#include "qe3.h"
#define MRU_MAX 4
namespace {
GtkMenuItem *MRU_items[MRU_MAX];
std::size_t MRU_used;
typedef CopiedString MRU_filename_t;
MRU_filename_t MRU_filenames[MRU_MAX];
typedef const char* MRU_key_t;
MRU_key_t MRU_keys[MRU_MAX] = { "File0", "File1", "File2", "File3" };
}
inline const char* MRU_GetText(std::size_t index)
{
return MRU_filenames[index].c_str();
}
class EscapedMnemonic
{
StringBuffer m_buffer;
public:
EscapedMnemonic(std::size_t capacity) : m_buffer(capacity)
{
m_buffer.push_back('_');
}
const char* c_str() const
{
return m_buffer.c_str();
}
void push_back(char c) // not escaped
{
m_buffer.push_back(c);
}
std::size_t write(const char* buffer, std::size_t length)
{
for(const char* end = buffer + length; buffer != end; ++buffer)
{
if(*buffer == '_')
{
m_buffer.push_back('_');
}
m_buffer.push_back(*buffer);
}
return length;
}
};
template<typename T>
inline EscapedMnemonic& operator<<(EscapedMnemonic& ostream, const T& t)
{
return ostream_write(ostream, t);
}
void MRU_updateWidget(std::size_t index, const char *filename)
{
EscapedMnemonic mnemonic(64);
mnemonic.push_back('_');
mnemonic << Unsigned(index + 1) << "- " << ConvertLocaleToUTF8(filename);
gtk_label_set_text_with_mnemonic(GTK_LABEL(gtk_bin_get_child(GTK_BIN(MRU_items[index]))), mnemonic.c_str());
}
void MRU_SetText(std::size_t index, const char *filename)
{
MRU_filenames[index] = filename;
MRU_updateWidget(index, filename);
}
void MRU_AddFile (const char *str)
{
std::size_t i;
const 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(GTK_WIDGET(MRU_items[0]), TRUE);
gtk_widget_show(GTK_WIDGET(MRU_items[MRU_used-1]));
}
void MRU_Init()
{
if(MRU_used > MRU_MAX)
MRU_used = MRU_MAX;
}
void MRU_AddWidget(GtkMenuItem *widget, std::size_t pos)
{
if(pos < MRU_MAX)
{
MRU_items[pos] = widget;
if(pos < MRU_used)
{
MRU_updateWidget(pos, MRU_GetText(pos));
gtk_widget_set_sensitive(GTK_WIDGET(MRU_items[0]), TRUE);
gtk_widget_show(GTK_WIDGET(MRU_items[pos]));
}
}
}
void MRU_Activate (std::size_t index)
{
char text[1024];
strcpy(text, MRU_GetText(index));
if (file_readable(text)) //\todo Test 'map load succeeds' instead of 'file is readable'.
{
MRU_AddFile (text);
Map_RegionOff();
Map_Free();
Map_LoadFile (text);
}
else
{
MRU_used--;
for (std::size_t 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(GTK_WIDGET(MRU_items[0]), FALSE);
}
else
{
gtk_widget_hide(GTK_WIDGET(MRU_items[MRU_used]));
}
}
}
class LoadMRU
{
std::size_t m_number;
public:
LoadMRU(std::size_t number)
: m_number(number)
{
}
void load()
{
if (ConfirmModified("Open Map"))
{
MRU_Activate(m_number - 1);
}
}
};
typedef MemberCaller<LoadMRU, &LoadMRU::load> LoadMRUCaller;
LoadMRU g_load_mru1(1);
LoadMRU g_load_mru2(2);
LoadMRU g_load_mru3(3);
LoadMRU g_load_mru4(4);
void MRU_constructMenu(GtkMenu* menu)
{
{
GtkMenuItem* item = create_menu_item_with_mnemonic(menu, "Recent Files", LoadMRUCaller(g_load_mru1));
gtk_widget_set_sensitive(GTK_WIDGET(item), FALSE);
MRU_AddWidget(item, 0);
}
{
GtkMenuItem* item = create_menu_item_with_mnemonic(menu, "2", LoadMRUCaller(g_load_mru2));
gtk_widget_hide(GTK_WIDGET(item));
MRU_AddWidget(item, 1);
}
{
GtkMenuItem* item = create_menu_item_with_mnemonic(menu, "3", LoadMRUCaller(g_load_mru3));
gtk_widget_hide(GTK_WIDGET(item));
MRU_AddWidget(item, 2);
}
{
GtkMenuItem* item = create_menu_item_with_mnemonic(menu, "4", LoadMRUCaller(g_load_mru4));
gtk_widget_hide(GTK_WIDGET(item));
MRU_AddWidget(item, 3);
}
}
#include "preferencesystem.h"
#include "stringio.h"
void MRU_Construct()
{
GlobalPreferenceSystem().registerPreference("Count", SizeImportStringCaller(MRU_used), SizeExportStringCaller(MRU_used));
for(std::size_t i = 0; i != MRU_MAX; ++i)
{
GlobalPreferenceSystem().registerPreference(MRU_keys[i], CopiedStringImportStringCaller(MRU_filenames[i]), CopiedStringExportStringCaller(MRU_filenames[i]));
}
MRU_Init();
}
void MRU_Destroy()
{
}

33
radiant/mru.h Normal file
View File

@@ -0,0 +1,33 @@
/*
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
*/
#if !defined(INCLUDED_MRU_H)
#define INCLUDED_MRU_H
void MRU_AddFile (const char *str);
typedef struct _GtkMenu GtkMenu;
void MRU_constructMenu(GtkMenu* menu);
void MRU_Construct();
void MRU_Destroy();
#endif

108
radiant/multimon.cpp Normal file
View File

@@ -0,0 +1,108 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#include "multimon.h"
#include "debugging/debugging.h"
#include "gtkutil/window.h"
#include "preferences.h"
multimon_globals_t g_multimon_globals;
LatchedBool g_Multimon_enableSysMenuPopups(false, "Floating windows sysmenu icons");
void MultiMonitor_constructPreferences(PreferencesPage& page)
{
GtkWidget* primary_monitor = page.appendCheckBox("Multi Monitor", "Start on Primary Monitor", g_multimon_globals.m_bStartOnPrimMon);
GtkWidget* popup = page.appendCheckBox(
"", "Disable system menu on popup windows",
LatchedBoolImportCaller(g_Multimon_enableSysMenuPopups),
BoolExportCaller(g_Multimon_enableSysMenuPopups.m_latched)
);
Widget_connectToggleDependency(popup, primary_monitor);
}
#include "preferencesystem.h"
#include "stringio.h"
#include <gdk/gdkdisplay.h>
namespace
{
GdkRectangle primaryMonitor;
}
void PositionWindowOnPrimaryScreen(WindowPosition& position)
{
if( position.w >= primaryMonitor.width - 12 )
{
position.w = primaryMonitor.width - 12;
}
if( position.h >= primaryMonitor.height - 24 )
{
position.h = primaryMonitor.height - 48;
}
if( position.x <= primaryMonitor.x || position.x + position.w >= (primaryMonitor.x + primaryMonitor.width) - 12 )
{
position.x = primaryMonitor.x + 6;
}
if( position.y <= primaryMonitor.y || position.y + position.h >= (primaryMonitor.y + primaryMonitor.height) - 48 )
{
position.y = primaryMonitor.y + 24;
}
}
void MultiMon_Construct()
{
// detect multiple monitors
GdkScreen* screen = gdk_display_get_default_screen(gdk_display_get_default());
gint m = gdk_screen_get_n_monitors(screen);
globalOutputStream() << "default screen has " << m << " monitors\n";
for(int j = 0; j != m; ++j)
{
GdkRectangle geom;
gdk_screen_get_monitor_geometry(screen, j, &geom);
globalOutputStream() << "monitor " << j << " geometry: " << geom.x << ", " << geom.y << ", " << geom.width << ", " << geom.height << "\n";
if(j == 0)
{
// I am making the assumption that monitor 0 is always the primary monitor on win32. Tested on WinXP with gtk+-2.4.
primaryMonitor = geom;
}
}
if(m > 1)
{
g_multimon_globals.m_bStartOnPrimMon = true;
}
GlobalPreferenceSystem().registerPreference("StartOnPrimMon", BoolImportStringCaller(g_multimon_globals.m_bStartOnPrimMon), BoolExportStringCaller(g_multimon_globals.m_bStartOnPrimMon));
GlobalPreferenceSystem().registerPreference("NoSysMenuPopups", BoolImportStringCaller(g_Multimon_enableSysMenuPopups.m_latched), BoolExportStringCaller(g_Multimon_enableSysMenuPopups.m_latched));
g_Multimon_enableSysMenuPopups.useLatched();
PreferencesDialog_addInterfacePreferences(FreeCaller1<PreferencesPage&, MultiMonitor_constructPreferences>());
}
void MultiMon_Destroy()
{
}

53
radiant/multimon.h Normal file
View File

@@ -0,0 +1,53 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#if !defined(INCLUDED_MULTIMON_H)
#define INCLUDED_MULTIMON_H
struct WindowPosition;
void PositionWindowOnPrimaryScreen(WindowPosition& position);
struct multimon_globals_t
{
bool m_bStartOnPrimMon;
multimon_globals_t() :
m_bStartOnPrimMon(false)
{
}
};
extern multimon_globals_t g_multimon_globals;
#if defined(WIN32)
void MultiMon_Construct();
void MultiMon_Destroy();
#else
inline void MultiMon_Construct()
{
}
inline void MultiMon_Destroy()
{
}
#endif
#endif

214
radiant/nullmodel.cpp Normal file
View File

@@ -0,0 +1,214 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#include "nullmodel.h"
#include "debugging/debugging.h"
#include "iscenegraph.h"
#include "irender.h"
#include "iselection.h"
#include "iundo.h"
#include "ientity.h"
#include "ireference.h"
#include "igl.h"
#include "cullable.h"
#include "renderable.h"
#include "selectable.h"
#include "math/frustum.h"
#include "scenelib.h"
#include "instancelib.h"
#include "entitylib.h"
class NullModel :
public Bounded,
public Cullable
{
Shader* m_state;
AABB m_aabb_local;
RenderableSolidAABB m_aabb_solid;
RenderableWireframeAABB m_aabb_wire;
public:
NullModel() : m_aabb_local(Vector3(0, 0, 0), Vector3(8, 8, 8)), m_aabb_solid(m_aabb_local), m_aabb_wire(m_aabb_local)
{
m_state = GlobalShaderCache().capture("");
}
~NullModel()
{
GlobalShaderCache().release("");
}
VolumeIntersectionValue intersectVolume(const VolumeTest& volume, const Matrix4& localToWorld) const
{
return volume.TestAABB(m_aabb_local, localToWorld);
}
const AABB& localAABB() const
{
return m_aabb_local;
}
void renderSolid(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
{
renderer.SetState(m_state, Renderer::eFullMaterials);
renderer.addRenderable(m_aabb_solid, localToWorld);
}
void renderWireframe(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
{
renderer.addRenderable(m_aabb_wire, localToWorld);
}
void testSelect(Selector& selector, SelectionTest& test, const Matrix4& localToWorld)
{
test.BeginMesh(localToWorld);
SelectionIntersection best;
aabb_testselect(m_aabb_local, test, best);
if(best.valid())
{
selector.addIntersection(best);
}
}
};
class NullModelInstance : public scene::Instance, public Renderable, public SelectionTestable
{
class TypeCasts
{
InstanceTypeCastTable m_casts;
public:
TypeCasts()
{
InstanceContainedCast<NullModelInstance, Bounded>::install(m_casts);
InstanceContainedCast<NullModelInstance, Cullable>::install(m_casts);
InstanceStaticCast<NullModelInstance, Renderable>::install(m_casts);
InstanceStaticCast<NullModelInstance, SelectionTestable>::install(m_casts);
}
InstanceTypeCastTable& get()
{
return m_casts;
}
};
NullModel& m_nullmodel;
public:
typedef LazyStatic<TypeCasts> StaticTypeCasts;
Bounded& get(NullType<Bounded>)
{
return m_nullmodel;
}
Cullable& get(NullType<Cullable>)
{
return m_nullmodel;
}
NullModelInstance(const scene::Path& path, scene::Instance* parent, NullModel& nullmodel) :
Instance(path, parent, this, StaticTypeCasts::instance().get()),
m_nullmodel(nullmodel)
{
}
void renderSolid(Renderer& renderer, const VolumeTest& volume) const
{
m_nullmodel.renderSolid(renderer, volume, Instance::localToWorld());
}
void renderWireframe(Renderer& renderer, const VolumeTest& volume) const
{
m_nullmodel.renderWireframe(renderer, volume, Instance::localToWorld());
}
void testSelect(Selector& selector, SelectionTest& test)
{
m_nullmodel.testSelect(selector, test, Instance::localToWorld());
}
};
class NullModelNode : public scene::Node::Symbiot, public scene::Instantiable
{
class TypeCasts
{
NodeTypeCastTable m_casts;
public:
TypeCasts()
{
NodeStaticCast<NullModelNode, scene::Instantiable>::install(m_casts);
}
NodeTypeCastTable& get()
{
return m_casts;
}
};
scene::Node m_node;
InstanceSet m_instances;
NullModel m_nullmodel;
public:
typedef LazyStatic<TypeCasts> StaticTypeCasts;
NullModelNode() : m_node(this, this, StaticTypeCasts::instance().get())
{
m_node.m_isRoot = true;
}
void release()
{
delete this;
}
scene::Node& node()
{
return m_node;
}
scene::Instance* create(const scene::Path& path, scene::Instance* parent)
{
return new NullModelInstance(path, parent, m_nullmodel);
}
void forEachInstance(const scene::Instantiable::Visitor& visitor)
{
m_instances.forEachInstance(visitor);
}
void insert(scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance)
{
m_instances.insert(observer, path, instance);
}
scene::Instance* erase(scene::Instantiable::Observer* observer, const scene::Path& path)
{
return m_instances.erase(observer, path);
}
};
NodeSmartReference NewNullModel()
{
return NodeSmartReference((new NullModelNode)->node());
}
void NullModel_construct()
{
}
void NullModel_destroy()
{
}

37
radiant/nullmodel.h Normal file
View File

@@ -0,0 +1,37 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#if !defined (INCLUDED_NULLMODEL_H)
#define INCLUDED_NULLMODEL_H
namespace scene
{
class Node;
}
#include "generic/referencecounted.h"
typedef SmartReference<scene::Node, IncRefDecRefCounter<scene::Node> > NodeSmartReference;
NodeSmartReference NewNullModel();
void NullModel_construct();
void NullModel_destroy();
#endif

51
radiant/parse.cpp Normal file
View File

@@ -0,0 +1,51 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#include "parse.h"
#include "script/scripttokeniser.h"
#include "script/scripttokenwriter.h"
class ScriptLibraryAPI
{
_QERScripLibTable m_scriptlibrary;
public:
typedef _QERScripLibTable Type;
STRING_CONSTANT(Name, "*");
ScriptLibraryAPI()
{
m_scriptlibrary.m_pfnNewScriptTokeniser = &NewScriptTokeniser;
m_scriptlibrary.m_pfnNewSimpleTokeniser = &NewSimpleTokeniser;
m_scriptlibrary.m_pfnNewSimpleTokenWriter = &NewSimpleTokenWriter;
}
_QERScripLibTable* getTable()
{
return &m_scriptlibrary;
}
};
#include "modulesystem/singletonmodule.h"
#include "modulesystem/moduleregistry.h"
typedef SingletonModule<ScriptLibraryAPI> ScriptLibraryModule;
typedef Static<ScriptLibraryModule> StaticScriptLibraryModule;
StaticRegisterModule staticRegisterScriptLibrary(StaticScriptLibraryModule::instance());

25
radiant/parse.h Normal file
View File

@@ -0,0 +1,25 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#if !defined(INCLUDED_PARSE_H)
#define INCLUDED_PARSE_H
#endif

2793
radiant/patch.cpp Normal file

File diff suppressed because it is too large Load Diff

2064
radiant/patch.h Normal file

File diff suppressed because it is too large Load Diff

1215
radiant/patchdialog.cpp Normal file

File diff suppressed because it is too large Load Diff

43
radiant/patchdialog.h Normal file
View File

@@ -0,0 +1,43 @@
/*
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
*/
#if !defined(INCLUDED_PATCHDIALOG_H)
#define INCLUDED_PATCHDIALOG_H
void PatchInspector_Construct();
void PatchInspector_Destroy();
typedef struct _GtkWidget GtkWidget;
typedef struct _GtkWindow GtkWindow;
void PatchInspector_constructWindow(GtkWindow* main_window);
void PatchInspector_destroyWindow();
namespace scene
{
class Graph;
}
void Scene_PatchTranslateTexture_Selected(scene::Graph& graph, float s, float t);
void Scene_PatchRotateTexture_Selected(scene::Graph& graph, float angle);
void Scene_PatchScaleTexture_Selected(scene::Graph& graph, float s, float t);
#endif

1070
radiant/patchmanip.cpp Normal file

File diff suppressed because it is too large Load Diff

57
radiant/patchmanip.h Normal file
View File

@@ -0,0 +1,57 @@
/*
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
*/
#if !defined (INCLUDED_PATCHMANIP_H)
#define INCLUDED_PATCHMANIP_H
#include "string/stringfwd.h"
void Patch_registerCommands();
typedef struct _GtkToolbar GtkToolbar;
typedef struct _GtkMenu GtkMenu;
void Patch_constructToolbar(GtkToolbar* toolbar);
void Patch_constructMenu(GtkMenu* menu);
namespace scene
{
class Graph;
}
void Scene_PatchSetShader_Selected(scene::Graph& graph, const char* name);
void Scene_PatchGetShader_Selected(scene::Graph& graph, CopiedString& name);
void Scene_PatchSelectByShader(scene::Graph& graph, const char* name);
void Scene_PatchFindReplaceShader(scene::Graph& graph, const char* find, const char* replace);
void Scene_PatchFindReplaceShader_Selected(scene::Graph& graph, const char* find, const char* replace);
void Scene_PatchCapTexture_Selected(scene::Graph& graph);
void Scene_PatchNaturalTexture_Selected(scene::Graph& graph);
void Scene_PatchTileTexture_Selected(scene::Graph& graph, float s, float t);
void PatchFilters_construct();
void PatchPreferences_construct();
void Patch_registerPreferencesPage();
class PatchCreator;
extern PatchCreator* g_patchCreator;
#endif

221
radiant/patchmodule.cpp Normal file
View File

@@ -0,0 +1,221 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#include "patchmodule.h"
#include "qerplugin.h"
#include "ipatch.h"
#include "patch.h"
#include "patchmanip.h"
namespace
{
std::size_t g_patchModuleCount = 0;
}
void Patch_Construct(EPatchType type)
{
if(++g_patchModuleCount != 1)
{
return;
}
PatchFilters_construct();
PatchPreferences_construct();
Patch_registerPreferencesPage();
Patch::constructStatic(type);
PatchInstance::constructStatic();
if(type == ePatchTypeDoom3)
{
MAX_PATCH_WIDTH = MAX_PATCH_HEIGHT = 99;
}
else
{
MAX_PATCH_WIDTH = MAX_PATCH_HEIGHT = 15;
}
}
void Patch_Destroy()
{
if(--g_patchModuleCount != 0)
{
return;
}
Patch::destroyStatic();
PatchInstance::destroyStatic();
}
class Quake3PatchCreator : public PatchCreator
{
public:
scene::Node& createPatch()
{
return (new PatchNodeQuake3())->node();
}
};
Quake3PatchCreator g_Quake3PatchCreator;
PatchCreator& GetQuake3PatchCreator()
{
return g_Quake3PatchCreator;
}
class Doom3PatchCreator : public PatchCreator
{
public:
scene::Node& createPatch()
{
return (new PatchNodeDoom3(true))->node();
}
};
Doom3PatchCreator g_Doom3PatchCreator;
PatchCreator& GetDoom3PatchCreator()
{
return g_Doom3PatchCreator;
}
class Doom3PatchDef2Creator : public PatchCreator
{
public:
scene::Node& createPatch()
{
return (new PatchNodeDoom3())->node();
}
};
Doom3PatchDef2Creator g_Doom3PatchDef2Creator;
PatchCreator& GetDoom3PatchDef2Creator()
{
return g_Doom3PatchDef2Creator;
}
#include "modulesystem/singletonmodule.h"
#include "modulesystem/moduleregistry.h"
class PatchDependencies :
public GlobalRadiantModuleRef,
public GlobalSceneGraphModuleRef,
public GlobalShaderCacheModuleRef,
public GlobalSelectionModuleRef,
public GlobalOpenGLModuleRef,
public GlobalUndoModuleRef,
public GlobalFilterModuleRef
{
};
class PatchQuake3API : public TypeSystemRef
{
PatchCreator* m_patchquake3;
public:
typedef PatchCreator Type;
STRING_CONSTANT(Name, "quake3");
PatchQuake3API()
{
Patch_Construct(ePatchTypeQuake3);
m_patchquake3 = &GetQuake3PatchCreator();
g_patchCreator = m_patchquake3;
}
~PatchQuake3API()
{
Patch_Destroy();
}
PatchCreator* getTable()
{
return m_patchquake3;
}
};
typedef SingletonModule<PatchQuake3API, PatchDependencies> PatchQuake3Module;
typedef Static<PatchQuake3Module> StaticPatchQuake3Module;
StaticRegisterModule staticRegisterPatchQuake3(StaticPatchQuake3Module::instance());
class PatchDoom3API : public TypeSystemRef
{
PatchCreator* m_patchdoom3;
public:
typedef PatchCreator Type;
STRING_CONSTANT(Name, "doom3");
PatchDoom3API()
{
Patch_Construct(ePatchTypeDoom3);
m_patchdoom3 = &GetDoom3PatchCreator();
}
~PatchDoom3API()
{
Patch_Destroy();
}
PatchCreator* getTable()
{
return m_patchdoom3;
}
};
typedef SingletonModule<PatchDoom3API, PatchDependencies> PatchDoom3Module;
typedef Static<PatchDoom3Module> StaticPatchDoom3Module;
StaticRegisterModule staticRegisterPatchDoom3(StaticPatchDoom3Module::instance());
class PatchDef2Doom3API : public TypeSystemRef
{
PatchCreator* m_patchdef2doom3;
public:
typedef PatchCreator Type;
STRING_CONSTANT(Name, "def2doom3");
PatchDef2Doom3API()
{
Patch_Construct(ePatchTypeDoom3);
m_patchdef2doom3 = &GetDoom3PatchDef2Creator();
g_patchCreator = m_patchdef2doom3;
}
~PatchDef2Doom3API()
{
Patch_Destroy();
}
PatchCreator* getTable()
{
return m_patchdef2doom3;
}
};
typedef SingletonModule<PatchDef2Doom3API, PatchDependencies> PatchDef2Doom3Module;
typedef Static<PatchDef2Doom3Module> StaticPatchDef2Doom3Module;
StaticRegisterModule staticRegisterPatchDef2Doom3(StaticPatchDef2Doom3Module::instance());

25
radiant/patchmodule.h Normal file
View File

@@ -0,0 +1,25 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#if !defined(INCLUDED_PATCHMODULE_H)
#define INCLUDED_PATCHMODULE_H
#endif

317
radiant/plugin.cpp Normal file
View File

@@ -0,0 +1,317 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#include "plugin.h"
#include "debugging/debugging.h"
#include "qerplugin.h"
#include "ifilesystem.h"
#include "ishaders.h"
#include "ientity.h"
#include "ieclass.h"
#include "irender.h"
#include "iscenegraph.h"
#include "iselection.h"
#include "ifilter.h"
#include "iscriplib.h"
#include "igl.h"
#include "iundo.h"
#include "itextures.h"
#include "ireference.h"
#include "ifiletypes.h"
#include "preferencesystem.h"
#include "ibrush.h"
#include "ipatch.h"
#include "iimage.h"
#include "itoolbar.h"
#include "iplugin.h"
#include "imap.h"
#include "namespace.h"
#include "gtkutil/messagebox.h"
#include "gtkutil/filechooser.h"
#include "maplib.h"
#include "error.h"
#include "map.h"
#include "qe3.h"
#include "entityinspector.h"
#include "entitylist.h"
#include "points.h"
#include "gtkmisc.h"
#include "texwindow.h"
#include "mainframe.h"
#include "build.h"
#include "mru.h"
#include "multimon.h"
#include "surfacedialog.h"
#include "groupdialog.h"
#include "patchdialog.h"
#include "camwindow.h"
#include "watchbsp.h"
#include "xywindow.h"
#include "entity.h"
#include "select.h"
#include "preferences.h"
#include "autosave.h"
#include "plugintoolbar.h"
#include "findtexturedialog.h"
#include "nullmodel.h"
#include "grid.h"
#include "modulesystem/modulesmap.h"
#include "modulesystem/singletonmodule.h"
#include "generic/callback.h"
const char* GameDescription_getKeyValue(const char* key)
{
return g_pGameDescription->getKeyValue(key);
}
const char* GameDescription_getRequiredKeyValue(const char* key)
{
return g_pGameDescription->getRequiredKeyValue(key);
}
class RadiantCoreAPI
{
_QERFuncTable_1 m_radiantcore;
public:
typedef _QERFuncTable_1 Type;
STRING_CONSTANT(Name, "*");
RadiantCoreAPI()
{
m_radiantcore.getEnginePath = &EnginePath_get;
m_radiantcore.getAppPath = &AppPath_get;
m_radiantcore.getGameToolsPath = &GameToolsPath_get;
m_radiantcore.getSettingsPath = &SettingsPath_get;
m_radiantcore.getGameName = &gamename_get;
m_radiantcore.getGameMode = &gamemode_get;
m_radiantcore.getGameDescriptionKeyValue = &GameDescription_getKeyValue;
m_radiantcore.getRequiredGameDescriptionKeyValue = &GameDescription_getRequiredKeyValue;
m_radiantcore.attachGameToolsPathObserver = Radiant_attachGameToolsPathObserver;
m_radiantcore.detachGameToolsPathObserver = Radiant_detachGameToolsPathObserver;
m_radiantcore.attachEnginePathObserver = Radiant_attachEnginePathObserver;
m_radiantcore.detachEnginePathObserver = Radiant_detachEnginePathObserver;
m_radiantcore.attachGameNameObserver = Radiant_attachGameNameObserver;
m_radiantcore.detachGameNameObserver = Radiant_detachGameNameObserver;
m_radiantcore.attachGameModeObserver = Radiant_attachGameModeObserver;
m_radiantcore.detachGameModeObserver = Radiant_detachGameModeObserver;
m_radiantcore.m_pfnMessageBox = &gtk_MessageBox;
m_radiantcore.m_pfnFileDialog = &file_dialog;
m_radiantcore.m_pfnColorDialog = &color_dialog;
m_radiantcore.m_pfnDirDialog = &dir_dialog;
m_radiantcore.m_pfnNewImage = &new_plugin_image;
}
_QERFuncTable_1* getTable()
{
return &m_radiantcore;
}
};
typedef SingletonModule<RadiantCoreAPI> RadiantCoreModule;
typedef Static<RadiantCoreModule> StaticRadiantCoreModule;
StaticRegisterModule staticRegisterRadiantCore(StaticRadiantCoreModule::instance());
class RadiantDependencies :
public GlobalRadiantModuleRef,
public GlobalFileSystemModuleRef,
public GlobalEntityModuleRef,
public GlobalShadersModuleRef,
public GlobalBrushModuleRef,
public GlobalSceneGraphModuleRef,
public GlobalShaderCacheModuleRef,
public GlobalFiletypesModuleRef,
public GlobalSelectionModuleRef,
public GlobalReferenceModuleRef,
public GlobalOpenGLModuleRef,
public GlobalEntityClassManagerModuleRef,
public GlobalUndoModuleRef,
public GlobalScripLibModuleRef,
public GlobalNamespaceModuleRef
{
ImageModulesRef m_image_modules;
MapModulesRef m_map_modules;
ToolbarModulesRef m_toolbar_modules;
PluginModulesRef m_plugin_modules;
public:
RadiantDependencies() :
GlobalEntityModuleRef(GlobalRadiant().getRequiredGameDescriptionKeyValue("entities")),
GlobalShadersModuleRef(GlobalRadiant().getRequiredGameDescriptionKeyValue("shaders")),
GlobalBrushModuleRef(GlobalRadiant().getRequiredGameDescriptionKeyValue("brushtypes")),
GlobalEntityClassManagerModuleRef(GlobalRadiant().getRequiredGameDescriptionKeyValue("entityclass")),
m_image_modules(GlobalRadiant().getRequiredGameDescriptionKeyValue("texturetypes")),
m_map_modules(GlobalRadiant().getRequiredGameDescriptionKeyValue("maptypes")),
m_toolbar_modules("*"),
m_plugin_modules("*")
{
}
ImageModules& getImageModules()
{
return m_image_modules.get();
}
MapModules& getMapModules()
{
return m_map_modules.get();
}
ToolbarModules& getToolbarModules()
{
return m_toolbar_modules.get();
}
PluginModules& getPluginModules()
{
return m_plugin_modules.get();
}
};
class Radiant : public TypeSystemRef
{
public:
Radiant()
{
Preferences_Init();
GlobalFiletypes().addType("sound", "wav", filetype_t("PCM sound files", "*.wav"));
Selection_construct();
HomePaths_Construct();
VFS_Construct();
Grid_construct();
MultiMon_Construct();
MRU_Construct();
Pointfile_Construct();
GLWindow_Construct();
BuildMenu_Construct();
Map_Construct();
EntityList_Construct();
MainFrame_Construct();
GroupDialog_Construct();
SurfaceInspector_Construct();
PatchInspector_Construct();
CamWnd_Construct();
XYWindow_Construct();
BuildMonitor_Construct();
TextureBrowser_Construct();
Entity_Construct();
Autosave_Construct();
EntityInspector_construct();
FindTextureDialog_Construct();
NullModel_construct();
MapRoot_construct();
EnginePath_verify();
EnginePath_Realise();
}
~Radiant()
{
EnginePath_Unrealise();
MapRoot_destroy();
NullModel_destroy();
FindTextureDialog_Destroy();
EntityInspector_destroy();
Autosave_Destroy();
Entity_Destroy();
TextureBrowser_Destroy();
BuildMonitor_Destroy();
XYWindow_Destroy();
CamWnd_Destroy();
PatchInspector_Destroy();
SurfaceInspector_Destroy();
GroupDialog_Destroy();
MainFrame_Destroy();
EntityList_Destroy();
Map_Destroy();
BuildMenu_Destroy();
GLWindow_Destroy();
Pointfile_Destroy();
MRU_Destroy();
MultiMon_Destroy();
Grid_destroy();
VFS_Destroy();
HomePaths_Destroy();
Selection_destroy();
}
};
namespace
{
bool g_RadiantInitialised = false;
RadiantDependencies* g_RadiantDependencies;
Radiant* g_Radiant;
}
bool Radiant_Construct(ModuleServer& server)
{
GlobalModuleServer::instance().set(server);
StaticModuleRegistryList().instance().registerModules();
g_RadiantDependencies = new RadiantDependencies();
g_RadiantInitialised = !server.getError();
if(g_RadiantInitialised)
{
g_Radiant = new Radiant;
}
return g_RadiantInitialised;
}
void Radiant_Destroy()
{
if(g_RadiantInitialised)
{
delete g_Radiant;
}
delete g_RadiantDependencies;
}
ImageModules& Radiant_getImageModules()
{
return g_RadiantDependencies->getImageModules();
}
MapModules& Radiant_getMapModules()
{
return g_RadiantDependencies->getMapModules();
}
ToolbarModules& Radiant_getToolbarModules()
{
return g_RadiantDependencies->getToolbarModules();
}
PluginModules& Radiant_getPluginModules()
{
return g_RadiantDependencies->getPluginModules();
}

47
radiant/plugin.h Normal file
View File

@@ -0,0 +1,47 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
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
*/
#if !defined(INCLUDED_PLUGIN_H)
#define INCLUDED_PLUGIN_H
class ModuleServer;
bool Radiant_Construct(ModuleServer& server);
void Radiant_Destroy();
template<typename Type>
class Modules;
struct _QERPlugImageTable;
typedef Modules<_QERPlugImageTable> ImageModules;
ImageModules& Radiant_getImageModules();
class MapFormat;
typedef Modules<MapFormat> MapModules;
MapModules& Radiant_getMapModules();
struct _QERPlugToolbarTable;
typedef Modules<_QERPlugToolbarTable> ToolbarModules;
ToolbarModules& Radiant_getToolbarModules();
struct _QERPluginTable;
typedef Modules<_QERPluginTable> PluginModules;
PluginModules& Radiant_getPluginModules();
#endif

92
radiant/pluginapi.cpp Normal file
View File

@@ -0,0 +1,92 @@
/*
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
*/
#include "pluginapi.h"
#include "modulesystem.h"
#include "qerplugin.h"
#include "generic/callback.h"
#include "math/vector.h"
#include "gtkmisc.h"
#include "camwindow.h"
#include "mainframe.h"
// camera API
void QERApp_GetCamera( Vector3& origin, Vector3& angles )
{
CamWnd& camwnd = *g_pParentWnd->GetCamWnd();
origin = Camera_getOrigin(camwnd);
angles = Camera_getAngles(camwnd);
}
void QERApp_SetCamera( const Vector3& origin, const Vector3& angles )
{
CamWnd& camwnd = *g_pParentWnd->GetCamWnd();
Camera_setOrigin(camwnd, origin);
Camera_setAngles(camwnd, angles);
}
void QERApp_GetCamWindowExtents( int *x, int *y, int *width, int *height )
{
#if 0
CamWnd* camwnd = g_pParentWnd->GetCamWnd();
gtk_window_get_position(GTK_WINDOW(camwnd->m_window), x, y);
*width = camwnd->Camera()->width;
*height = camwnd->Camera()->height;
#endif
}
#include "icamera.h"
class CameraAPI
{
_QERCameraTable m_camera;
public:
typedef _QERCameraTable Type;
STRING_CONSTANT(Name, "*");
CameraAPI()
{
m_camera.m_pfnGetCamera = &QERApp_GetCamera;
m_camera.m_pfnSetCamera = &QERApp_SetCamera;
m_camera.m_pfnGetCamWindowExtents = &QERApp_GetCamWindowExtents;
}
_QERCameraTable* getTable()
{
return &m_camera;
}
};
#include "modulesystem/singletonmodule.h"
#include "modulesystem/moduleregistry.h"
typedef SingletonModule<CameraAPI> CameraModule;
typedef Static<CameraModule> StaticCameraModule;
StaticRegisterModule staticRegisterCamera(StaticCameraModule::instance());

Some files were not shown because too many files have changed in this diff Show More