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

View File

@@ -0,0 +1,229 @@
/*
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 "archive.h"
#include "idatastream.h"
#include "cmdlib.h"
#include "bytestreamutils.h"
#include <algorithm>
#include "stream/filestream.h"
#include "iarchive.h"
#include "archivelib.h"
#include "plugin.h"
#include <map>
#include "string/string.h"
#include "fs_filesystem.h"
inline void buffer_findreplace(char* buffer, char find, char replace)
{
while(*buffer != '\0')
{
if(*buffer == find)
*buffer = replace;
++buffer;
}
}
#include "pak.h"
class PakArchive : public Archive
{
class PakRecord
{
public:
PakRecord(unsigned int position, unsigned int stream_size)
: m_position(position), m_stream_size(stream_size)
{
}
unsigned int m_position;
unsigned int m_stream_size;
};
typedef GenericFileSystem<PakRecord> PakFileSystem;
PakFileSystem m_filesystem;
FileInputStream m_pakfile;
CopiedString m_name;
public:
PakArchive(const char* name)
: m_pakfile(name), m_name(name)
{
if(!m_pakfile.failed())
{
pakheader_t header;
m_pakfile.read(reinterpret_cast<FileInputStream::byte_type*>(header.magic), 4);
header.diroffset = istream_read_uint32_le(m_pakfile);
header.dirsize = istream_read_uint32_le(m_pakfile);
if(strncmp (header.magic, "PACK", 4) == 0)
{
m_pakfile.seek(header.diroffset);
for(unsigned int i = 0; i < header.dirsize; i += sizeof(pakentry_t))
{
pakentry_t entry;
m_pakfile.read(reinterpret_cast<FileInputStream::byte_type*>(entry.filename), 0x38);
entry.offset = istream_read_uint32_le(m_pakfile);
entry.size = istream_read_uint32_le(m_pakfile);
buffer_findreplace(entry.filename, '\\', '/');
PakFileSystem::entry_type& file = m_filesystem[entry.filename];
if(!file.is_directory())
{
globalOutputStream() << "Warning: pak archive " << makeQuoted(m_name.c_str()) << " contains duplicated file: " << makeQuoted(entry.filename) << "\n";
}
else
{
file = new PakRecord(entry.offset, entry.size);
}
}
}
}
}
~PakArchive()
{
for(PakFileSystem::iterator i = m_filesystem.begin(); i != m_filesystem.end(); ++i)
delete i->second.file();
}
void release()
{
delete this;
}
ArchiveFile* openFile(const char* name)
{
PakFileSystem::iterator i = m_filesystem.find(name);
if(i != m_filesystem.end() && !i->second.is_directory())
{
PakRecord* file = i->second.file();
return StoredArchiveFile::create(name, m_name.c_str(), file->m_position, file->m_stream_size, file->m_stream_size);
}
return 0;
}
virtual ArchiveTextFile* openTextFile(const char* name)
{
PakFileSystem::iterator i = m_filesystem.find(name);
if(i != m_filesystem.end() && !i->second.is_directory())
{
PakRecord* file = i->second.file();
return StoredArchiveTextFile::create(name, m_name.c_str(), file->m_position, file->m_stream_size);
}
return 0;
}
bool containsFile(const char* name)
{
PakFileSystem::iterator i = m_filesystem.find(name);
return i != m_filesystem.end() && !i->second.is_directory();
}
void forEachFile(VisitorFunc visitor, const char* root)
{
m_filesystem.traverse(visitor, root);
}
};
Archive* OpenArchive(const char* name)
{
return new PakArchive(name);
}
#if 0
class TestArchive
{
public:
TestArchive()
{
Archive* archive = OpenArchive("c:/quake3/baseq3/pak0.pak");
ArchiveFile* file = archive->openFile("gfx/palette.lmp");
if(file != 0)
{
char buffer[1024];
file->getInputStream().read((InputStream::byte_type*)buffer, 1024);
file->release();
}
archive->release();
}
};
TestArchive g_test;
#endif
#if 0
class TestArchive
{
class TestVisitor : public Archive::IVisitor
{
public:
void visit(const char* name)
{
int bleh = 0;
}
};
public:
TestArchive()
{
{
Archive* archive = OpenArchive("");
archive->release();
}
{
Archive* archive = OpenArchive("NONEXISTANTFILE");
archive->release();
}
{
Archive* archive = OpenArchive("c:/quake/id1/pak0.pak");
ArchiveFile* file = archive->openFile("gfx/palette.lmp");
if(file != 0)
{
char buffer[1024];
file->getInputStream().read((InputStream::byte_type*)buffer, 1024);
file->release();
}
TestVisitor visitor;
archive->forEachFile(Archive::VisitorFunc(&visitor, Archive::eFilesAndDirectories, 0), "");
archive->forEachFile(Archive::VisitorFunc(&visitor, Archive::eFiles, 0), "progs/");
archive->forEachFile(Archive::VisitorFunc(&visitor, Archive::eFiles, 0), "maps/");
archive->forEachFile(Archive::VisitorFunc(&visitor, Archive::eFiles, 1), "sound/ambience/");
archive->forEachFile(Archive::VisitorFunc(&visitor, Archive::eFilesAndDirectories, 1), "sound/");
archive->forEachFile(Archive::VisitorFunc(&visitor, Archive::eDirectories, 1), "sound/");
archive->forEachFile(Archive::VisitorFunc(&visitor, Archive::eFilesAndDirectories, 2), "sound/");
archive->forEachFile(Archive::VisitorFunc(&visitor, Archive::eFilesAndDirectories, 2), "");
archive->release();
}
}
};
TestArchive g_test;
#endif

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
*/
class Archive;
Archive* OpenArchive(const char* name);

View File

@@ -0,0 +1,7 @@
; archivepak.def : Declares the module parameters for the DLL.
LIBRARY "ARCHIVEPAK"
EXPORTS
; Explicit exports can go here
Radiant_RegisterModules @1

View File

@@ -0,0 +1,150 @@
# Microsoft Developer Studio Project File - Name="archivepak" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
CFG=archivepak - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "archivepak.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "archivepak.mak" CFG="archivepak - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "archivepak - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "archivepak - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName "archivepak"
# PROP Scc_LocalPath "."
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "archivepak - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
F90=df.exe
# ADD BASE F90 /compile_only /include:"Release/" /libs:dll /nologo /warn:nofileopt /dll
# ADD F90 /compile_only /include:"Release/" /libs:dll /nologo /warn:nofileopt /dll
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "ARCHIVEPAK_EXPORTS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /O2 /I "..\..\include" /I "..\..\..\gtk2-win32\include\glib-2.0" /I "..\..\..\gtk2-win32\lib\glib-2.0\include" /I "..\common" /I "..\..\libs" /I "..\..\..\STLPort\stlport" /I "..\..\..\libxml2\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "ARCHIVEPAK_EXPORTS" /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
# ADD LINK32 cmdlib.lib glib-2.0.lib /nologo /dll /machine:I386 /def:".\archivepak.def" /libpath:"..\..\libs\cmdlib\release" /libpath:"..\..\..\gtk2-win32\lib"
# SUBTRACT LINK32 /pdb:none
# Begin Special Build Tool
SOURCE="$(InputPath)"
PostBuild_Desc=Copy to dir...
PostBuild_Cmds=copy Release\archivepak.dll "../../install/modules"
# End Special Build Tool
!ELSEIF "$(CFG)" == "archivepak - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
F90=df.exe
# ADD BASE F90 /check:bounds /compile_only /debug:full /include:"Debug/" /libs:dll /nologo /warn:argument_checking /warn:nofileopt /dll
# ADD F90 /check:bounds /compile_only /debug:full /include:"Debug/" /libs:dll /nologo /warn:argument_checking /warn:nofileopt /dll
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "ARCHIVEPAK_EXPORTS" /YX /FD /GZ /c
# ADD CPP /nologo /MDd /W3 /Gm /ZI /Od /I "..\..\include" /I "..\..\..\gtk2-win32\include\glib-2.0" /I "..\..\..\gtk2-win32\lib\glib-2.0\include" /I "..\common" /I "..\..\libs" /I "..\..\..\STLPort\stlport" /I "..\..\..\libxml2\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "ARCHIVEPAK_EXPORTS" /YX /FD /GZ /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
# ADD LINK32 cmdlib.lib glib-2.0.lib /nologo /dll /debug /machine:I386 /def:".\archivepak.def" /pdbtype:sept /libpath:"..\..\libs\cmdlib\debug" /libpath:"..\..\..\gtk2-win32\lib"
# SUBTRACT LINK32 /pdb:none
# Begin Special Build Tool
SOURCE="$(InputPath)"
PostBuild_Desc=Copy to dir...
PostBuild_Cmds=copy Debug\archivepak.dll "../../install/modules"
# End Special Build Tool
!ENDIF
# Begin Target
# Name "archivepak - Win32 Release"
# Name "archivepak - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;f90;for;f;fpp"
# Begin Source File
SOURCE=.\archive.cpp
# End Source File
# Begin Source File
SOURCE=.\archivepak.def
# PROP Exclude_From_Build 1
# End Source File
# Begin Source File
SOURCE=.\plugin.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
# Begin Source File
SOURCE=.\archive.h
# End Source File
# Begin Source File
SOURCE=.\pak.h
# End Source File
# Begin Source File
SOURCE=.\plugin.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# Begin Source File
SOURCE=.\Conscript
# End Source File
# End Target
# End Project

View File

@@ -0,0 +1,207 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="archivepak"
ProjectGUID="{75160E63-E642-4C71-9D4C-B733E152C418}"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../../include;../../libs;&quot;../../../STLPort-4.6/stlport&quot;"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;ARCHIVEPAK_EXPORTS"
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"
OutputFile="$(OutDir)/archivepak.dll"
LinkIncremental="1"
IgnoreDefaultLibraryNames="msvcprtd.lib"
ModuleDefinitionFile="$(ProjectName).def"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/archivepak.pdb"
SubSystem="2"
ImportLibrary="$(OutDir)/archivepak.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"
CommandLine="copy &quot;$(TargetPath)&quot; &quot;$(SolutionDir)install\modules&quot;
copy &quot;$(TargetDir)$(TargetName).pdb&quot; &quot;$(SolutionDir)install\modules&quot;"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<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="2"
CharacterSet="2"
WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
GlobalOptimizations="TRUE"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="TRUE"
FavorSizeOrSpeed="1"
OptimizeForWindowsApplication="FALSE"
AdditionalIncludeDirectories="../../include;../../libs;&quot;../../../STLPort-4.6/stlport&quot;"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;ARCHIVEPAK_EXPORTS"
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"
OutputFile="$(OutDir)/archivepak.dll"
LinkIncremental="1"
IgnoreDefaultLibraryNames="msvcprt.lib"
ModuleDefinitionFile="$(ProjectName).def"
GenerateDebugInformation="TRUE"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
ImportLibrary="$(OutDir)/archivepak.lib"
TargetMachine="1"
FixedBaseAddress="0"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"
CommandLine="copy &quot;$(TargetPath)&quot; &quot;$(SolutionDir)install\modules&quot;
copy &quot;$(TargetDir)$(TargetName).pdb&quot; &quot;$(SolutionDir)install\modules&quot;"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<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=".\archive.cpp">
</File>
<File
RelativePath=".\archive.h">
</File>
<File
RelativePath=".\pak.cpp">
</File>
<File
RelativePath=".\pak.h">
</File>
<File
RelativePath=".\plugin.cpp">
</File>
<File
RelativePath=".\plugin.h">
</File>
</Filter>
<File
RelativePath="..\..\debug.py">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCustomBuildTool"
CommandLine="python &quot;$(SolutionDir)debug.py&quot;"
AdditionalDependencies="&quot;$(SolutionDir)install\modules\$(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\modules\$(TargetName).pdb&quot;"
Outputs="&quot;$(TargetDir)$(TargetName).pdb&quot;"/>
</FileConfiguration>
</File>
<File
RelativePath=".\archivepak.def">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCustomBuildTool"
CommandLine="python &quot;$(SolutionDir)touch.py&quot; &quot;$(TargetPath)&quot;
"
AdditionalDependencies="&quot;$(SolutionDir)install\modules\$(TargetFileName)&quot;"
Outputs="&quot;$(TargetPath)&quot;"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCustomBuildTool"
CommandLine="python &quot;$(SolutionDir)touch.py&quot; &quot;$(TargetPath)&quot;
"
AdditionalDependencies="&quot;$(SolutionDir)install\modules\$(TargetFileName)&quot;"
Outputs="&quot;$(TargetPath)&quot;"/>
</FileConfiguration>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

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 "pak.h"

40
plugins/archivepak/pak.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_PAK_H)
#define INCLUDED_PAK_H
struct pakheader_t
{
char magic[4]; // Name of the new WAD format ("PACK")
unsigned int diroffset;// Position of WAD directory from start of file
unsigned int dirsize; // Number of entries * 0x40 (64 char)
};
struct pakentry_t
{
char filename[0x38]; // Name of the file, Unix style, with extension, 50 chars, padded with '\0'.
unsigned int offset; // Position of the entry in PACK file
unsigned int size; // Size of the entry in PACK file
};
#endif

View File

@@ -0,0 +1,61 @@
/*
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 "iarchive.h"
#include "debugging/debugging.h"
#include "modulesystem/singletonmodule.h"
#include "archive.h"
class ArchivePakAPI
{
_QERArchiveTable m_archivepak;
public:
typedef _QERArchiveTable Type;
STRING_CONSTANT(Name, "pak");
ArchivePakAPI()
{
m_archivepak.m_pfnOpenArchive = &OpenArchive;
}
_QERArchiveTable* getTable()
{
return &m_archivepak;
}
};
typedef SingletonModule<ArchivePakAPI> ArchivePakModule;
ArchivePakModule g_ArchivePakModule;
extern "C" void RADIANT_DLLEXPORT Radiant_RegisterModules(ModuleServer& server)
{
GlobalErrorStream::instance().setOutputStream(server.getErrorStream());
GlobalOutputStream::instance().setOutputStream(server.getOutputStream());
GlobalDebugMessageHandler::instance().setHandler(server.getDebugMessageHandler());
GlobalModuleServer::instance().set(server);
g_ArchivePakModule.selfRegister();
}

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_PLUGIN_H)
#define INCLUDED_PLUGIN_H
#endif

View File

@@ -0,0 +1,230 @@
/*
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 "archive.h"
#include "idatastream.h"
#include "cmdlib.h"
#include "bytestreamutils.h"
#include <algorithm>
#include "stream/filestream.h"
#include "iarchive.h"
#include "archivelib.h"
#include "plugin.h"
#include <map>
#include "string/string.h"
#include "wad.h"
class WadArchive : public Archive
{
class wad_record_t
{
public:
wad_record_t(unsigned int position, unsigned int stream_size, unsigned int file_size)
: m_position(position), m_stream_size(stream_size), m_file_size(file_size)
{}
unsigned int m_position;
unsigned int m_stream_size;
unsigned int m_file_size;
};
enum EWadVersion
{
eNotValid,
eWAD2,
eWAD3,
};
typedef std::map<CopiedString, wad_record_t, StringLessNoCase> files_t;
files_t m_files;
CopiedString m_name;
FileInputStream m_wadfile;
EWadVersion wad_version(const char* identification)
{
if(strncmp(identification, "WAD2", 4) == 0)
return eWAD2;
if(strncmp(identification, "WAD3", 4) == 0)
return eWAD3;
return eNotValid;
}
const char* type_for_version(EWadVersion version)
{
switch(version)
{
case eWAD2:
return ".mip";
case eWAD3:
return ".hlw";
default:
break;
}
return "";
}
int miptex_type_for_version(EWadVersion version)
{
switch(version)
{
case eWAD2:
return TYP_MIPTEX;
case eWAD3:
return 67;
default:
break;
}
return -1;
}
public:
WadArchive(const char* name)
: m_name(name), m_wadfile(name)
{
if(!m_wadfile.failed())
{
wadinfo_t wadinfo;
istream_read_wadinfo(m_wadfile, wadinfo);
EWadVersion version = wad_version(wadinfo.identification);
int miptexType = miptex_type_for_version(version);
if(version != eNotValid)
{
m_wadfile.seek(wadinfo.infotableofs);
for(int i = 0; i < wadinfo.numlumps; ++i)
{
char buffer[32];
lumpinfo_t lumpinfo;
istream_read_lumpinfo(m_wadfile, lumpinfo);
if(lumpinfo.type == miptexType)
{
strcpy(buffer, "textures/");
strcat(buffer, lumpinfo.name);
strcat(buffer, type_for_version(version));
m_files.insert(files_t::value_type(buffer, wad_record_t(lumpinfo.filepos, lumpinfo.disksize, lumpinfo.size)));
}
}
}
}
}
void release()
{
delete this;
}
ArchiveFile* openFile(const char* name)
{
files_t::iterator i = m_files.find(name);
if(i != m_files.end())
{
return StoredArchiveFile::create(name, m_name.c_str(), i->second.m_position, i->second.m_stream_size, i->second.m_file_size);
}
return 0;
}
virtual ArchiveTextFile* openTextFile(const char* name)
{
files_t::iterator i = m_files.find(name);
if(i != m_files.end())
{
return StoredArchiveTextFile::create(name, m_name.c_str(), i->second.m_position, i->second.m_stream_size);
}
return 0;
}
bool containsFile(const char* name)
{
return m_files.find(name) != m_files.end();
}
void forEachFile(VisitorFunc visitor, const char* root)
{
if(root[0] == '\0')
{
if(visitor.directory("textures/", 1))
return;
}
else if(strcmp(root, "textures/") != 0)
{
return;
}
for(files_t::iterator i = m_files.begin(); i != m_files.end(); ++i)
visitor.file(i->first.c_str());
}
};
Archive* OpenArchive(const char* name)
{
return new WadArchive(name);
}
#if 0
class TestArchive
{
class TestVisitor : public Archive::IVisitor
{
public:
void visit(const char* name)
{
int bleh = 0;
}
};
public:
TestArchive()
{
{
Archive* archive = OpenArchive("");
archive->release();
}
{
Archive* archive = OpenArchive("NONEXISTANTFILE");
archive->release();
}
{
Archive* archive = OpenArchive("c:/quake/id1/quake101.wad");
ArchiveFile* file = archive->openFile("textures/sky1.mip");
if(file != 0)
{
unsigned char* buffer = new unsigned char[file->size()];
file->getInputStream().read((InputStream::byte_type*)buffer, file->size());
delete[] buffer;
file->release();
}
TestVisitor visitor;
archive->forEachFile(Archive::VisitorFunc(&visitor, Archive::eFilesAndDirectories, 1), "");
archive->forEachFile(Archive::VisitorFunc(&visitor, Archive::eFilesAndDirectories, 0), "");
archive->forEachFile(Archive::VisitorFunc(&visitor, Archive::eFilesAndDirectories, 0), "textures/");
archive->forEachFile(Archive::VisitorFunc(&visitor, Archive::eFilesAndDirectories, 1), "textures/");
archive->release();
}
}
};
TestArchive g_test;
#endif

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
*/
class Archive;
Archive* OpenArchive(const char* name);

View File

@@ -0,0 +1,7 @@
; archivewad.def : Declares the module parameters for the DLL.
LIBRARY "ARCHIVEWAD"
EXPORTS
; Explicit exports can go here
Radiant_RegisterModules @1

View File

@@ -0,0 +1,150 @@
# Microsoft Developer Studio Project File - Name="archivewad" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
CFG=archivewad - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "archivewad.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "archivewad.mak" CFG="archivewad - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "archivewad - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "archivewad - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName "archivewad"
# PROP Scc_LocalPath "."
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "archivewad - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
F90=df.exe
# ADD BASE F90 /compile_only /include:"Release/" /libs:dll /nologo /warn:nofileopt /dll
# ADD F90 /compile_only /include:"Release/" /libs:dll /nologo /warn:nofileopt /dll
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "ARCHIVEWAD_EXPORTS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /O2 /I "..\..\include" /I "..\..\..\gtk2-win32\include\glib-2.0" /I "..\..\..\gtk2-win32\lib\glib-2.0\include" /I "..\common" /I "..\..\libs" /I "..\..\..\STLPort\stlport" /I "..\..\..\libxml2\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "ARCHIVEWAD_EXPORTS" /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
# ADD LINK32 cmdlib.lib glib-2.0.lib /nologo /dll /machine:I386 /def:".\archivewad.def" /libpath:"../../libs/cmdlib/release" /libpath:"..\..\..\gtk2-win32\lib"
# SUBTRACT LINK32 /pdb:none
# Begin Special Build Tool
SOURCE="$(InputPath)"
PostBuild_Desc=Copy to dir...
PostBuild_Cmds=copy Release\archivewad.dll "../../install/modules"
# End Special Build Tool
!ELSEIF "$(CFG)" == "archivewad - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
F90=df.exe
# ADD BASE F90 /check:bounds /compile_only /debug:full /include:"Debug/" /libs:dll /nologo /warn:argument_checking /warn:nofileopt /dll
# ADD F90 /check:bounds /compile_only /debug:full /include:"Debug/" /libs:dll /nologo /warn:argument_checking /warn:nofileopt /dll
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "ARCHIVEWAD_EXPORTS" /YX /FD /GZ /c
# ADD CPP /nologo /MDd /W3 /Gm /ZI /Od /I "..\..\include" /I "..\..\..\gtk2-win32\include\glib-2.0" /I "..\..\..\gtk2-win32\lib\glib-2.0\include" /I "..\common" /I "..\..\libs" /I "..\..\..\STLPort\stlport" /I "..\..\..\libxml2\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "ARCHIVEWAD_EXPORTS" /YX /FD /GZ /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
# ADD LINK32 cmdlib.lib glib-2.0.lib /nologo /dll /debug /machine:I386 /def:".\archivewad.def" /pdbtype:sept /libpath:"../../libs/cmdlib/debug" /libpath:"..\..\..\gtk2-win32\lib"
# SUBTRACT LINK32 /pdb:none
# Begin Special Build Tool
SOURCE="$(InputPath)"
PostBuild_Desc=Copy to dir...
PostBuild_Cmds=copy Debug\archivewad.dll "../../install/modules"
# End Special Build Tool
!ENDIF
# Begin Target
# Name "archivewad - Win32 Release"
# Name "archivewad - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;f90;for;f;fpp"
# Begin Source File
SOURCE=.\archive.cpp
# End Source File
# Begin Source File
SOURCE=.\archivewad.def
# PROP Exclude_From_Build 1
# End Source File
# Begin Source File
SOURCE=.\plugin.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
# Begin Source File
SOURCE=.\archive.h
# End Source File
# Begin Source File
SOURCE=.\plugin.h
# End Source File
# Begin Source File
SOURCE=.\wad.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# Begin Source File
SOURCE=.\Conscript
# End Source File
# End Target
# End Project

View File

@@ -0,0 +1,207 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="archivewad"
ProjectGUID="{9DC47AF9-ACFC-40A5-A4A6-FF3E7F8EFFBE}"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../../include;../../libs;&quot;../../../STLPort-4.6/stlport&quot;"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;ARCHIVEWAD_EXPORTS"
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"
OutputFile="$(OutDir)/archivewad.dll"
LinkIncremental="1"
IgnoreDefaultLibraryNames="msvcprtd.lib"
ModuleDefinitionFile="$(ProjectName).def"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/archivewad.pdb"
SubSystem="2"
ImportLibrary="$(OutDir)/archivewad.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"
CommandLine="copy &quot;$(TargetPath)&quot; &quot;$(SolutionDir)install\modules&quot;
copy &quot;$(TargetDir)$(TargetName).pdb&quot; &quot;$(SolutionDir)install\modules&quot;"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<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="2"
CharacterSet="2"
WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
GlobalOptimizations="TRUE"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="TRUE"
FavorSizeOrSpeed="1"
OptimizeForWindowsApplication="FALSE"
AdditionalIncludeDirectories="../../include;../../libs;&quot;../../../STLPort-4.6/stlport&quot;"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;ARCHIVEWAD_EXPORTS"
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"
OutputFile="$(OutDir)/archivewad.dll"
LinkIncremental="1"
IgnoreDefaultLibraryNames="msvcprt.lib"
ModuleDefinitionFile="$(ProjectName).def"
GenerateDebugInformation="TRUE"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
ImportLibrary="$(OutDir)/archivewad.lib"
TargetMachine="1"
FixedBaseAddress="0"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"
CommandLine="copy &quot;$(TargetPath)&quot; &quot;$(SolutionDir)install\modules&quot;
copy &quot;$(TargetDir)$(TargetName).pdb&quot; &quot;$(SolutionDir)install\modules&quot;"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<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=".\archive.cpp">
</File>
<File
RelativePath=".\archive.h">
</File>
<File
RelativePath=".\plugin.cpp">
</File>
<File
RelativePath=".\plugin.h">
</File>
<File
RelativePath=".\wad.cpp">
</File>
<File
RelativePath=".\wad.h">
</File>
</Filter>
<File
RelativePath="..\..\debug.py">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCustomBuildTool"
CommandLine="python &quot;$(SolutionDir)debug.py&quot;"
AdditionalDependencies="&quot;$(SolutionDir)install\modules\$(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\modules\$(TargetName).pdb&quot;"
Outputs="&quot;$(TargetDir)$(TargetName).pdb&quot;"/>
</FileConfiguration>
</File>
<File
RelativePath=".\archivewad.def">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCustomBuildTool"
CommandLine="python &quot;$(SolutionDir)touch.py&quot; &quot;$(TargetPath)&quot;
"
AdditionalDependencies="&quot;$(SolutionDir)install\modules\$(TargetFileName)&quot;"
Outputs="&quot;$(TargetPath)&quot;"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCustomBuildTool"
CommandLine="python &quot;$(SolutionDir)touch.py&quot; &quot;$(TargetPath)&quot;
"
AdditionalDependencies="&quot;$(SolutionDir)install\modules\$(TargetFileName)&quot;"
Outputs="&quot;$(TargetPath)&quot;"/>
</FileConfiguration>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@@ -0,0 +1,61 @@
/*
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 "iarchive.h"
#include "debugging/debugging.h"
#include "modulesystem/singletonmodule.h"
#include "archive.h"
class ArchiveWadAPI
{
_QERArchiveTable m_archivewad;
public:
typedef _QERArchiveTable Type;
STRING_CONSTANT(Name, "wad");
ArchiveWadAPI()
{
m_archivewad.m_pfnOpenArchive = &OpenArchive;
}
_QERArchiveTable* getTable()
{
return &m_archivewad;
}
};
typedef SingletonModule<ArchiveWadAPI> ArchiveWadModule;
ArchiveWadModule g_ArchiveWadModule;
extern "C" void RADIANT_DLLEXPORT Radiant_RegisterModules(ModuleServer& server)
{
GlobalErrorStream::instance().setOutputStream(server.getErrorStream());
GlobalOutputStream::instance().setOutputStream(server.getOutputStream());
GlobalDebugMessageHandler::instance().setHandler(server.getDebugMessageHandler());
GlobalModuleServer::instance().set(server);
g_ArchiveWadModule.selfRegister();
}

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_PLUGIN_H)
#define INCLUDED_PLUGIN_H
#endif

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 "wad.h"

78
plugins/archivewad/wad.h Normal file
View File

@@ -0,0 +1,78 @@
/*
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_WAD_H)
#define INCLUDED_WAD_H
#include "bytestreamutils.h"
#include "idatastream.h"
#define CMP_NONE 0
#define CMP_LZSS 1
#define TYP_NONE 0
#define TYP_LABEL 1
#define TYP_LUMPY 64 // 64 + grab command number
#define TYP_PALETTE 64
#define TYP_QTEX 65
#define TYP_QPIC 66
#define TYP_SOUND 67
#define TYP_MIPTEX 68
typedef struct
{
char identification[4]; // should be WAD2 or 2DAW
int numlumps;
int infotableofs;
} wadinfo_t;
typedef struct
{
int filepos;
int disksize;
int size; // uncompressed
char type;
char compression;
char pad1, pad2;
char name[16]; // must be null terminated
} lumpinfo_t;
inline void istream_read_wadinfo(InputStream& istream, wadinfo_t& wadinfo)
{
istream.read(reinterpret_cast<InputStream::byte_type*>(wadinfo.identification), 4);
wadinfo.numlumps = istream_read_int32_le(istream);
wadinfo.infotableofs = istream_read_int32_le(istream);
}
inline void istream_read_lumpinfo(InputStream& istream, lumpinfo_t& lumpinfo)
{
lumpinfo.filepos = istream_read_int32_le(istream);
lumpinfo.disksize = istream_read_int32_le(istream);
lumpinfo.size = istream_read_int32_le(istream);
lumpinfo.type = istream_read_byte(istream);
lumpinfo.compression = istream_read_byte(istream);
lumpinfo.pad1 = istream_read_byte(istream);
lumpinfo.pad2 = istream_read_byte(istream);
istream.read(reinterpret_cast<InputStream::byte_type*>(lumpinfo.name), 16);
}
#endif

View File

@@ -0,0 +1,353 @@
/*
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 "idatastream.h"
#include "cmdlib.h"
#include "bytestreamutils.h"
#include "modulesystem.h"
#include "iarchive.h"
#include <algorithm>
#include "stream/filestream.h"
#include "container/array.h"
#include "archivelib.h"
#include "zlibstream.h"
class DeflatedArchiveFile : public ArchiveFile
{
CopiedString m_name;
FileInputStream m_istream;
SubFileInputStream m_substream;
DeflatedInputStream m_zipstream;
FileInputStream::size_type m_size;
public:
typedef FileInputStream::size_type size_type;
typedef FileInputStream::position_type position_type;
DeflatedArchiveFile(const char* name, const char* archiveName, position_type position, size_type stream_size, size_type file_size)
: m_name(name), m_istream(archiveName), m_substream(m_istream, position, stream_size), m_zipstream(m_substream), m_size(file_size)
{
}
void release()
{
delete this;
}
size_type size() const
{
return m_size;
}
const char* getName() const
{
return m_name.c_str();
}
InputStream& getInputStream()
{
return m_zipstream;
}
};
class DeflatedArchiveTextFile : public ArchiveTextFile
{
CopiedString m_name;
FileInputStream m_istream;
SubFileInputStream m_substream;
DeflatedInputStream m_zipstream;
BinaryToTextInputStream<DeflatedInputStream> m_textStream;
public:
typedef FileInputStream::size_type size_type;
typedef FileInputStream::position_type position_type;
DeflatedArchiveTextFile(const char* name, const char* archiveName, position_type position, size_type stream_size)
: m_name(name), m_istream(archiveName), m_substream(m_istream, position, stream_size), m_zipstream(m_substream), m_textStream(m_zipstream)
{
}
void release()
{
delete this;
}
TextInputStream& getInputStream()
{
return m_textStream;
}
};
#include "pkzip.h"
#include <map>
#include "string/string.h"
#include "fs_filesystem.h"
class ZipArchive : public Archive
{
class ZipRecord
{
public:
enum ECompressionMode
{
eStored,
eDeflated,
};
ZipRecord(unsigned int position, unsigned int compressed_size, unsigned int uncompressed_size, ECompressionMode mode)
: m_position(position), m_stream_size(compressed_size), m_file_size(uncompressed_size), m_mode(mode)
{
}
unsigned int m_position;
unsigned int m_stream_size;
unsigned int m_file_size;
ECompressionMode m_mode;
};
typedef GenericFileSystem<ZipRecord> ZipFileSystem;
ZipFileSystem m_filesystem;
CopiedString m_name;
FileInputStream m_istream;
bool read_record()
{
zip_magic magic;
istream_read_zip_magic(m_istream, magic);
if(!(magic == zip_root_dirent_magic))
{
return false;
}
zip_version version_encoder;
istream_read_zip_version(m_istream, version_encoder);
zip_version version_extract;
istream_read_zip_version(m_istream, version_extract);
//unsigned short flags =
istream_read_int16_le(m_istream);
unsigned short compression_mode = istream_read_int16_le(m_istream);
if(compression_mode != Z_DEFLATED && compression_mode != 0)
{
return false;
}
zip_dostime dostime;
istream_read_zip_dostime(m_istream, dostime);
//unsigned int crc32 =
istream_read_int32_le(m_istream);
unsigned int compressed_size = istream_read_uint32_le(m_istream);
unsigned int uncompressed_size = istream_read_uint32_le(m_istream);
unsigned int namelength = istream_read_uint16_le(m_istream);
unsigned short extras = istream_read_uint16_le(m_istream);
unsigned short comment = istream_read_uint16_le(m_istream);
//unsigned short diskstart =
istream_read_int16_le(m_istream);
//unsigned short filetype =
istream_read_int16_le(m_istream);
//unsigned int filemode =
istream_read_int32_le(m_istream);
unsigned int position = istream_read_int32_le(m_istream);
Array<char> filename(namelength+1);
m_istream.read(reinterpret_cast<FileInputStream::byte_type*>(filename.data()), namelength);
filename[namelength] = '\0';
m_istream.seek(extras + comment, FileInputStream::cur);
if(path_is_directory(filename.data()))
{
m_filesystem[filename.data()] = 0;
}
else
{
ZipFileSystem::entry_type& file = m_filesystem[filename.data()];
if(!file.is_directory())
{
globalOutputStream() << "Warning: zip archive " << makeQuoted(m_name.c_str()) << " contains duplicated file: " << makeQuoted(filename.data()) << "\n";
}
else
{
file = new ZipRecord(position, compressed_size, uncompressed_size, (compression_mode == Z_DEFLATED) ? ZipRecord::eDeflated : ZipRecord::eStored);
}
}
return true;
}
bool read_pkzip()
{
SeekableStream::position_type pos = pkzip_find_disk_trailer(m_istream);
if(pos != 0)
{
zip_disk_trailer disk_trailer;
m_istream.seek(pos);
istream_read_zip_disk_trailer(m_istream, disk_trailer);
if(!(disk_trailer.z_magic == zip_disk_trailer_magic))
{
return false;
}
m_istream.seek(disk_trailer.z_rootseek);
for(unsigned int i = 0; i < disk_trailer.z_entries; ++i)
{
if(!read_record())
{
return false;
}
}
return true;
}
return false;
}
public:
ZipArchive(const char* name)
: m_name(name), m_istream(name)
{
if(!m_istream.failed())
{
if(!read_pkzip())
{
globalErrorStream() << "ERROR: invalid zip-file " << makeQuoted(name) << '\n';
}
}
}
~ZipArchive()
{
for(ZipFileSystem::iterator i = m_filesystem.begin(); i != m_filesystem.end(); ++i)
{
delete i->second.file();
}
}
bool failed()
{
return m_istream.failed();
}
void release()
{
delete this;
}
ArchiveFile* openFile(const char* name)
{
ZipFileSystem::iterator i = m_filesystem.find(name);
if(i != m_filesystem.end() && !i->second.is_directory())
{
ZipRecord* file = i->second.file();
m_istream.seek(file->m_position);
zip_file_header file_header;
istream_read_zip_file_header(m_istream, file_header);
if(file_header.z_magic != zip_file_header_magic)
{
globalErrorStream() << "error reading zip file " << makeQuoted(m_name.c_str());
return 0;
}
switch(file->m_mode)
{
case ZipRecord::eStored:
return StoredArchiveFile::create(name, m_name.c_str(), m_istream.tell(), file->m_stream_size, file->m_file_size);
case ZipRecord::eDeflated:
return new DeflatedArchiveFile(name, m_name.c_str(), m_istream.tell(), file->m_stream_size, file->m_file_size);
}
}
return 0;
}
ArchiveTextFile* openTextFile(const char* name)
{
ZipFileSystem::iterator i = m_filesystem.find(name);
if(i != m_filesystem.end() && !i->second.is_directory())
{
ZipRecord* file = i->second.file();
m_istream.seek(file->m_position);
zip_file_header file_header;
istream_read_zip_file_header(m_istream, file_header);
if(file_header.z_magic != zip_file_header_magic)
{
globalErrorStream() << "error reading zip file " << makeQuoted(m_name.c_str());
return 0;
}
switch(file->m_mode)
{
case ZipRecord::eStored:
return StoredArchiveTextFile::create(name, m_name.c_str(), m_istream.tell(), file->m_stream_size);
case ZipRecord::eDeflated:
return new DeflatedArchiveTextFile(name, m_name.c_str(), m_istream.tell(), file->m_stream_size);
}
}
return 0;
}
bool containsFile(const char* name)
{
ZipFileSystem::iterator i = m_filesystem.find(name);
return i != m_filesystem.end() && !i->second.is_directory();
}
void forEachFile(VisitorFunc visitor, const char* root)
{
m_filesystem.traverse(visitor, root);
}
};
Archive* OpenArchive(const char* name)
{
return new ZipArchive(name);
}
#if 0
class TestZip
{
class TestVisitor : public Archive::IVisitor
{
public:
void visit(const char* name)
{
int bleh = 0;
}
};
public:
TestZip()
{
testzip("c:/quake3/baseq3/mapmedia.pk3", "textures/radiant/notex.tga");
}
void testzip(const char* name, const char* filename)
{
Archive* archive = OpenArchive(name);
ArchiveFile* file = archive->openFile(filename);
if(file != 0)
{
unsigned char buffer[4096];
std::size_t count = file->getInputStream().read((InputStream::byte_type*)buffer, 4096);
file->release();
}
TestVisitor visitor;
archive->forEachFile(Archive::VisitorFunc(&visitor, Archive::eFilesAndDirectories, 0), "");
archive->forEachFile(Archive::VisitorFunc(&visitor, Archive::eFilesAndDirectories, 1), "");
archive->forEachFile(Archive::VisitorFunc(&visitor, Archive::eFiles, 1), "");
archive->forEachFile(Archive::VisitorFunc(&visitor, Archive::eDirectories, 1), "");
archive->forEachFile(Archive::VisitorFunc(&visitor, Archive::eFilesAndDirectories, 1), "textures");
archive->forEachFile(Archive::VisitorFunc(&visitor, Archive::eFilesAndDirectories, 1), "textures/");
archive->forEachFile(Archive::VisitorFunc(&visitor, Archive::eFilesAndDirectories, 2), "");
archive->release();
}
};
TestZip g_TestZip;
#endif

View File

@@ -0,0 +1,22 @@
/*
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
*/
Archive* OpenArchive(const char* name);

View File

@@ -0,0 +1,7 @@
; archivezip.def : Declares the module parameters for the DLL.
LIBRARY "ARCHIVEZIP"
EXPORTS
; Explicit exports can go here
Radiant_RegisterModules @1

View File

@@ -0,0 +1,154 @@
# Microsoft Developer Studio Project File - Name="archivezip" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
CFG=archivezip - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "archivezip.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "archivezip.mak" CFG="archivezip - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "archivezip - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "archivezip - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName "archivezip"
# PROP Scc_LocalPath "."
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "archivezip - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
F90=df.exe
# ADD BASE F90 /compile_only /include:"Release/" /libs:dll /nologo /warn:nofileopt /dll
# ADD F90 /compile_only /include:"Release/" /libs:dll /nologo /warn:nofileopt /dll
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "ARCHIVEZIP_EXPORTS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /O2 /I "..\..\include" /I "..\..\..\gtk2-win32\include\glib-2.0" /I "..\..\..\gtk2-win32\lib\glib-2.0\include" /I "..\common" /I "..\..\libs" /I "..\..\..\STLPort\stlport" /I "..\..\..\libxml2\include" /I "..\..\..\zlib" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "ARCHIVEZIP_EXPORTS" /D "ZLIB_DLL" /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
# ADD LINK32 cmdlib.lib glib-2.0.lib zlib.lib /nologo /dll /machine:I386 /def:".\archivezip.def" /libpath:"..\..\libs\cmdlib\release" /libpath:"..\..\..\gtk2-win32\lib" /libpath:"..\..\..\libpng\projects\msvc\zlib___Win32_Release"
# SUBTRACT LINK32 /pdb:none
# Begin Special Build Tool
SOURCE="$(InputPath)"
PostBuild_Desc=Copy to dir...
PostBuild_Cmds=copy Release\archivezip.dll "../../install/modules"
# End Special Build Tool
!ELSEIF "$(CFG)" == "archivezip - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
F90=df.exe
# ADD BASE F90 /check:bounds /compile_only /debug:full /include:"Debug/" /libs:dll /nologo /warn:argument_checking /warn:nofileopt /dll
# ADD F90 /check:bounds /compile_only /debug:full /include:"Debug/" /libs:dll /nologo /warn:argument_checking /warn:nofileopt /dll
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "ARCHIVEZIP_EXPORTS" /YX /FD /GZ /c
# ADD CPP /nologo /MDd /W3 /Gm /ZI /Od /I "..\..\include" /I "..\..\..\gtk2-win32\include\glib-2.0" /I "..\..\..\gtk2-win32\lib\glib-2.0\include" /I "..\common" /I "..\..\libs" /I "..\..\..\STLPort\stlport" /I "..\..\..\libxml2\include" /I "..\..\..\zlib" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "ARCHIVEZIP_EXPORTS" /D "ZLIB_DLL" /YX /FD /GZ /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
# ADD LINK32 cmdlib.lib glib-2.0.lib zlibd.lib /nologo /dll /debug /machine:I386 /def:".\archivezip.def" /pdbtype:sept /libpath:"..\..\libs\cmdlib\debug" /libpath:"..\..\..\gtk2-win32\lib" /libpath:"..\..\..\libpng\projects\msvc\zlib___Win32_Debug"
# SUBTRACT LINK32 /pdb:none
# Begin Special Build Tool
SOURCE="$(InputPath)"
PostBuild_Desc=Copy to dir...
PostBuild_Cmds=copy Debug\archivezip.dll "../../install/modules"
# End Special Build Tool
!ENDIF
# Begin Target
# Name "archivezip - Win32 Release"
# Name "archivezip - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;f90;for;f;fpp"
# Begin Source File
SOURCE=.\archive.cpp
# End Source File
# Begin Source File
SOURCE=.\archivezip.def
# PROP Exclude_From_Build 1
# End Source File
# Begin Source File
SOURCE=.\plugin.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
# Begin Source File
SOURCE=.\archive.h
# End Source File
# Begin Source File
SOURCE=.\pkzip.h
# End Source File
# Begin Source File
SOURCE=.\plugin.h
# End Source File
# Begin Source File
SOURCE=.\zlibstream.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# Begin Source File
SOURCE=.\Conscript
# End Source File
# End Target
# End Project

View File

@@ -0,0 +1,218 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="archivezip"
ProjectGUID="{A7E0FE03-E9BB-4478-9752-250BBD406C2D}"
RootNamespace="archivezip"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../../include;../../libs;&quot;../../../STLPort-4.6/stlport&quot;;../../../zlib1-1.2/include"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;ARCHIVEZIP_EXPORTS"
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="zdll.lib"
OutputFile="$(OutDir)/archivezip.dll"
LinkIncremental="1"
AdditionalLibraryDirectories="../../../zlib1-1.2/lib"
IgnoreDefaultLibraryNames="msvcprtd.lib"
ModuleDefinitionFile="$(ProjectName).def"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/archivezip.pdb"
SubSystem="2"
ImportLibrary="$(OutDir)/archivezip.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"
CommandLine="copy &quot;$(TargetPath)&quot; &quot;$(SolutionDir)install\modules&quot;
copy &quot;$(TargetDir)$(TargetName).pdb&quot; &quot;$(SolutionDir)install\modules&quot;"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<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="2"
CharacterSet="2"
WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
GlobalOptimizations="TRUE"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="TRUE"
FavorSizeOrSpeed="1"
OptimizeForWindowsApplication="FALSE"
AdditionalIncludeDirectories="../../include;../../libs;&quot;../../../STLPort-4.6/stlport&quot;;../../../zlib1-1.2/include"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;ARCHIVEZIP_EXPORTS"
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="zdll.lib"
OutputFile="$(OutDir)/archivezip.dll"
LinkIncremental="1"
AdditionalLibraryDirectories="../../../zlib1-1.2/lib"
IgnoreDefaultLibraryNames="msvcprt.lib"
ModuleDefinitionFile="$(ProjectName).def"
GenerateDebugInformation="TRUE"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
ImportLibrary="$(OutDir)/archivezip.lib"
TargetMachine="1"
FixedBaseAddress="0"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"
CommandLine="copy &quot;$(TargetPath)&quot; &quot;$(SolutionDir)install\modules&quot;
copy &quot;$(TargetDir)$(TargetName).pdb&quot; &quot;$(SolutionDir)install\modules&quot;"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<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=".\archive.cpp">
</File>
<File
RelativePath=".\archive.h">
</File>
<File
RelativePath=".\pkzip.cpp">
</File>
<File
RelativePath=".\pkzip.h">
</File>
<File
RelativePath=".\plugin.cpp">
</File>
<File
RelativePath=".\plugin.h">
</File>
<File
RelativePath=".\zlibstream.cpp">
</File>
<File
RelativePath=".\zlibstream.h">
</File>
</Filter>
<File
RelativePath="..\..\debug.py">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCustomBuildTool"
CommandLine="python &quot;$(SolutionDir)debug.py&quot;"
AdditionalDependencies="&quot;$(SolutionDir)install\modules\$(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\modules\$(TargetName).pdb&quot;"
Outputs="&quot;$(TargetDir)$(TargetName).pdb&quot;"/>
</FileConfiguration>
</File>
<File
RelativePath=".\archivezip.def">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCustomBuildTool"
CommandLine="python &quot;$(SolutionDir)touch.py&quot; &quot;$(TargetPath)&quot;
"
AdditionalDependencies="&quot;$(SolutionDir)install\modules\$(TargetFileName)&quot;"
Outputs="&quot;$(TargetPath)&quot;"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCustomBuildTool"
CommandLine="python &quot;$(SolutionDir)touch.py&quot; &quot;$(TargetPath)&quot;
"
AdditionalDependencies="&quot;$(SolutionDir)install\modules\$(TargetFileName)&quot;"
Outputs="&quot;$(TargetPath)&quot;"/>
</FileConfiguration>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

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 "pkzip.h"

266
plugins/archivezip/pkzip.h Normal file
View File

@@ -0,0 +1,266 @@
/*
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_PKZIP_H)
#define INCLUDED_PKZIP_H
#include "bytestreamutils.h"
#include "idatastream.h"
#include <algorithm>
class zip_magic
{
public:
bool operator==(const zip_magic& other) const
{
return m_value[0] == other.m_value[0]
&& m_value[1] == other.m_value[1]
&& m_value[2] == other.m_value[2]
&& m_value[3] == other.m_value[3];
}
bool operator!=(const zip_magic& other) const
{
return !(*this == other);
}
char m_value[4];
};
inline void istream_read_zip_magic(InputStream& istream, zip_magic& magic)
{
istream.read(reinterpret_cast<InputStream::byte_type*>(magic.m_value), 4);
}
struct zip_version
{
char version;
char ostype;
};
inline void istream_read_zip_version(InputStream& istream, zip_version& version)
{
version.version = istream_read_byte(istream);
version.ostype = istream_read_byte(istream);
}
struct zip_dostime
{
unsigned short time;
unsigned short date;
};
inline void istream_read_zip_dostime(InputStream& istream, zip_dostime& dostime)
{
dostime.time = istream_read_int16_le(istream);
dostime.date = istream_read_int16_le(istream);
}
const zip_magic zip_file_header_magic = { 'P', 'K', 0x03, 0x04, };
/* A. Local file header */
struct zip_file_header
{
zip_magic z_magic; /* local file header signature (0x04034b50) */
zip_version z_extract; /* version needed to extract */
unsigned short z_flags; /* general purpose bit flag */
unsigned short z_compr; /* compression method */
zip_dostime z_dostime; /* last mod file time (dos format) */
unsigned int z_crc32; /* crc-32 */
unsigned int z_csize; /* compressed size */
unsigned int z_usize; /* uncompressed size */
unsigned short z_namlen; /* filename length (null if stdin) */
unsigned short z_extras; /* extra field length */
/* followed by filename (of variable size) */
/* followed by extra field (of variable size) */
};
inline void istream_read_zip_file_header(SeekableInputStream& istream, zip_file_header& file_header)
{
istream_read_zip_magic(istream, file_header.z_magic);
istream_read_zip_version(istream, file_header.z_extract);
file_header.z_flags = istream_read_uint16_le(istream);
file_header.z_compr = istream_read_uint16_le(istream);
istream_read_zip_dostime(istream, file_header.z_dostime);
file_header.z_crc32 = istream_read_uint32_le(istream);
file_header.z_csize = istream_read_uint32_le(istream);
file_header.z_usize = istream_read_uint32_le(istream);
file_header.z_namlen = istream_read_uint16_le(istream);
file_header.z_extras = istream_read_uint16_le(istream);
istream.seek(file_header.z_namlen + file_header.z_extras, SeekableInputStream::cur);
};
/* B. data descriptor
* the data descriptor exists only if bit 3 of z_flags is set. It is byte aligned
* and immediately follows the last byte of compressed data. It is only used if
* the output media of the compressor was not seekable, eg. standard output.
*/
const zip_magic zip_file_trailer_magic = { 'P', 'K', 0x07, 0x08, };
struct zip_file_trailer
{
zip_magic z_magic;
unsigned int z_crc32; /* crc-32 */
unsigned int z_csize; /* compressed size */
unsigned int z_usize; /* uncompressed size */
};
inline void istream_read_zip_file_trailer(InputStream& istream, zip_file_trailer& file_trailer)
{
istream_read_zip_magic(istream, file_trailer.z_magic);
file_trailer.z_crc32 = istream_read_uint32_le(istream);
file_trailer.z_csize = istream_read_uint32_le(istream);
file_trailer.z_usize = istream_read_uint32_le(istream);
};
/* C. central directory structure:
[file header] . . . end of central dir record
*/
/* directory file header
* - a single entry including filename, extras and comment may not exceed 64k.
*/
const zip_magic zip_root_dirent_magic = { 'P', 'K', 0x01, 0x02, };
struct zip_root_dirent
{
zip_magic z_magic;
zip_version z_encoder; /* version made by */
zip_version z_extract; /* version need to extract */
unsigned short z_flags; /* general purpose bit flag */
unsigned short z_compr; /* compression method */
zip_dostime z_dostime; /* last mod file time&date (dos format) */
unsigned int z_crc32; /* crc-32 */
unsigned int z_csize; /* compressed size */
unsigned int z_usize; /* uncompressed size */
unsigned short z_namlen; /* filename length (null if stdin) */
unsigned short z_extras; /* extra field length */
unsigned short z_comment; /* file comment length */
unsigned short z_diskstart; /* disk number of start (if spanning zip over multiple disks) */
unsigned short z_filetype; /* internal file attributes, bit0 = ascii */
unsigned int z_filemode; /* extrnal file attributes, eg. msdos attrib byte */
unsigned int z_off; /* relative offset of local file header, seekval if singledisk */
/* followed by filename (of variable size) */
/* followed by extra field (of variable size) */
/* followed by file comment (of variable size) */
};
inline void istream_read_zip_root_dirent(SeekableInputStream& istream, zip_root_dirent& root_dirent)
{
istream_read_zip_magic(istream, root_dirent.z_magic);
istream_read_zip_version(istream, root_dirent.z_encoder);
istream_read_zip_version(istream, root_dirent.z_extract);
root_dirent.z_flags = istream_read_uint16_le(istream);
root_dirent.z_compr = istream_read_uint16_le(istream);
istream_read_zip_dostime(istream, root_dirent.z_dostime);
root_dirent.z_crc32 = istream_read_uint32_le(istream);
root_dirent.z_csize = istream_read_uint32_le(istream);
root_dirent.z_usize = istream_read_uint32_le(istream);
root_dirent.z_namlen = istream_read_uint16_le(istream);
root_dirent.z_extras = istream_read_uint16_le(istream);
root_dirent.z_comment = istream_read_uint16_le(istream);
root_dirent.z_diskstart = istream_read_uint16_le(istream);
root_dirent.z_filetype = istream_read_uint16_le(istream);
root_dirent.z_filemode = istream_read_uint32_le(istream);
root_dirent.z_off = istream_read_uint32_le(istream);
istream.seek(root_dirent.z_namlen + root_dirent.z_extras + root_dirent.z_comment, SeekableInputStream::cur);
}
/* end of central dir record */
const zip_magic zip_disk_trailer_magic = { 'P', 'K', 0x05, 0x06, };
const unsigned int disk_trailer_length = 22;
struct zip_disk_trailer
{
zip_magic z_magic;
unsigned short z_disk; /* number of this disk */
unsigned short z_finaldisk; /* number of the disk with the start of the central dir */
unsigned short z_entries; /* total number of entries in the central dir on this disk */
unsigned short z_finalentries; /* total number of entries in the central dir */
unsigned int z_rootsize; /* size of the central directory */
unsigned int z_rootseek; /* offset of start of central directory with respect to *
* the starting disk number */
unsigned short z_comment; /* zipfile comment length */
/* followed by zipfile comment (of variable size) */
};
inline void istream_read_zip_disk_trailer(SeekableInputStream& istream, zip_disk_trailer& disk_trailer)
{
istream_read_zip_magic(istream, disk_trailer.z_magic);
disk_trailer.z_disk = istream_read_uint16_le(istream);
disk_trailer.z_finaldisk = istream_read_uint16_le(istream);
disk_trailer.z_entries = istream_read_uint16_le(istream);
disk_trailer.z_finalentries = istream_read_uint16_le(istream);
disk_trailer.z_rootsize = istream_read_uint32_le(istream);
disk_trailer.z_rootseek = istream_read_uint32_le(istream);
disk_trailer.z_comment = istream_read_uint16_le(istream);
istream.seek(disk_trailer.z_comment, SeekableInputStream::cur);
}
inline SeekableStream::position_type pkzip_find_disk_trailer(SeekableInputStream& istream)
{
istream.seek(0, SeekableInputStream::end);
SeekableStream::position_type start_position = istream.tell();
if(start_position < disk_trailer_length)
return 0;
start_position -= disk_trailer_length;
zip_magic magic;
istream.seek(start_position);
istream_read_zip_magic(istream, magic);
if(magic == zip_disk_trailer_magic)
return start_position;
else
{
const SeekableStream::position_type max_comment = 0x10000;
const SeekableStream::position_type bufshift = 6;
const SeekableStream::position_type bufsize = max_comment >> bufshift;
unsigned char buffer[bufsize];
SeekableStream::position_type search_end = (max_comment < start_position) ? start_position - max_comment : 0;
SeekableStream::position_type position = start_position;
while(position != search_end)
{
StreamBase::size_type to_read = std::min(bufsize, position - search_end);
position -= to_read;
istream.seek(position);
StreamBase::size_type size = istream.read(buffer, to_read);
unsigned char* p = buffer + size;
while(p != buffer)
{
--p;
magic.m_value[3] = magic.m_value[2];
magic.m_value[2] = magic.m_value[1];
magic.m_value[1] = magic.m_value[0];
magic.m_value[0] = *p;
if(magic == zip_disk_trailer_magic)
{
return position + (p - buffer);
}
}
}
return 0;
}
}
#endif

View File

@@ -0,0 +1,85 @@
/*
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 "iarchive.h"
#include "debugging/debugging.h"
#include "modulesystem/singletonmodule.h"
#include "archive.h"
class ArchiveZipAPI
{
_QERArchiveTable m_archivezip;
public:
typedef _QERArchiveTable Type;
STRING_CONSTANT(Name, "pk3");
ArchiveZipAPI()
{
m_archivezip.m_pfnOpenArchive = &OpenArchive;
}
_QERArchiveTable* getTable()
{
return &m_archivezip;
}
};
typedef SingletonModule<ArchiveZipAPI> ArchiveZipModule;
ArchiveZipModule g_ArchiveZipModule;
class ArchivePK4API
{
_QERArchiveTable m_archivepk4;
public:
typedef _QERArchiveTable Type;
STRING_CONSTANT(Name, "pk4");
ArchivePK4API()
{
m_archivepk4.m_pfnOpenArchive = &OpenArchive;
}
_QERArchiveTable* getTable()
{
return &m_archivepk4;
}
};
typedef SingletonModule<ArchivePK4API> ArchivePK4Module;
ArchivePK4Module g_ArchivePK4Module;
extern "C" void RADIANT_DLLEXPORT Radiant_RegisterModules(ModuleServer& server)
{
GlobalErrorStream::instance().setOutputStream(server.getErrorStream());
GlobalOutputStream::instance().setOutputStream(server.getOutputStream());
GlobalDebugMessageHandler::instance().setHandler(server.getDebugMessageHandler());
GlobalModuleServer::instance().set(server);
g_ArchiveZipModule.selfRegister();
g_ArchivePK4Module.selfRegister();
}

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_PLUGIN_H)
#define INCLUDED_PLUGIN_H
#endif

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 "zlibstream.h"

View File

@@ -0,0 +1,75 @@
/*
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_ZLIBSTREAM_H)
#define INCLUDED_ZLIBSTREAM_H
#include "zlib.h"
#include "idatastream.h"
/// \brief A wrapper around an InputStream of data compressed with the zlib deflate algorithm.
///
/// - Uses z_stream to decompress the data stream on the fly.
/// - Uses a buffer to reduce the number of times the wrapped stream must be read.
class DeflatedInputStream : public InputStream
{
InputStream& m_istream;
z_stream m_zipstream;
static const int m_bufsize = 1024;
unsigned char m_buffer[m_bufsize];
public:
DeflatedInputStream(InputStream& istream)
: m_istream(istream)
{
m_zipstream.zalloc = 0;
m_zipstream.zfree = 0;
m_zipstream.opaque = 0;
m_zipstream.avail_in = 0;
inflateInit2(&m_zipstream, -MAX_WBITS);
}
~DeflatedInputStream()
{
inflateEnd(&m_zipstream);
}
size_type read(byte_type* buffer, size_type length)
{
m_zipstream.next_out = buffer;
m_zipstream.avail_out = static_cast<uInt>(length);
while(m_zipstream.avail_out != 0)
{
if(m_zipstream.avail_in == 0)
{
m_zipstream.next_in = m_buffer;
m_zipstream.avail_in = static_cast<uInt>(m_istream.read(m_buffer, m_bufsize));
}
if(inflate(&m_zipstream, Z_SYNC_FLUSH) != Z_OK)
{
break;
}
}
return length - m_zipstream.avail_out;
}
};
#endif

32
plugins/config.mk Normal file
View File

@@ -0,0 +1,32 @@
# Common configuration options for all plugins
CC=gcc
CXX=g++
CFLAGS+=`gtk-config --cflags` -Wall -g -I../../include
CPPFLAGS+=`gtk-config --cflags` -Wall -g -I../../include
LDFLAGS+=`gtk-config --libs` -shared
OUTDIR=$(RADIANT_DATA)plugins
OBJS := $(patsubst %.cpp,%.o,$(filter %.cpp,$(SRC)))
OBJS += $(patsubst %.c,%.o,$(filter %.c,$(SRC)))
all: $(OUTPUT)
$(OUTPUT): $(OBJS)
$(CXX) -o $(OUTPUT) $(OBJS) $(LDFLAGS)
@if [ -d $(OUTDIR) ]; then cp $(OUTPUT) $(OUTDIR); fi
## Other targets
.PHONY: clean
clean:
rm -f *.o *.d $(OUTPUT) core
## Dependencies
-include $(OBJS:.o=.d)
%.d: %.cpp
@echo -n "$(@) " > $@
@if { !(eval $(CXX) -MM $(CPPFLAGS) -w $<) >> $@; }; then \
rm -f $@; exit 1; \
fi
@[ -s $@ ] || rm -f $@

23
plugins/entity/angle.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 "angle.h"

101
plugins/entity/angle.h Normal file
View File

@@ -0,0 +1,101 @@
/*
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_ANGLE_H)
#define INCLUDED_ANGLE_H
#include "ientity.h"
#include "math/quaternion.h"
#include "generic/callback.h"
#include "stringio.h"
const float ANGLEKEY_IDENTITY = 0;
inline void default_angle(float& angle)
{
angle = ANGLEKEY_IDENTITY;
}
inline void normalise_angle(float& angle)
{
angle = static_cast<float>(float_mod(angle, 360.0));
}
inline void read_angle(float& angle, const char* value)
{
if(!string_parse_float(value, angle))
{
angle = 0;
}
else
{
normalise_angle(angle);
}
}
inline void write_angle(float angle, Entity* entity)
{
if(angle == 0)
{
entity->setKeyValue("angle", "");
}
else
{
char value[64];
sprintf(value, "%g", angle);
entity->setKeyValue("angle", value);
}
}
class AngleKey
{
Callback m_angleChanged;
public:
float m_angle;
AngleKey(const Callback& angleChanged)
: m_angleChanged(angleChanged), m_angle(ANGLEKEY_IDENTITY)
{
}
void angleChanged(const char* value)
{
read_angle(m_angle, value);
m_angleChanged();
}
typedef MemberCaller1<AngleKey, const char*, &AngleKey::angleChanged> AngleChangedCaller;
void write(Entity* entity) const
{
write_angle(m_angle, entity);
}
};
inline float angle_rotated(float angle, const Quaternion& rotation)
{
return matrix4_get_rotation_euler_xyz_degrees(
matrix4_multiplied_by_matrix4(
matrix4_rotation_for_z_degrees(angle),
matrix4_rotation_for_quaternion_quantised(rotation)
)
).z();
}
#endif

23
plugins/entity/angles.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 "angles.h"

140
plugins/entity/angles.h Normal file
View File

@@ -0,0 +1,140 @@
/*
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_ANGLES_H)
#define INCLUDED_ANGLES_H
#include "ientity.h"
#include "math/quaternion.h"
#include "generic/callback.h"
#include "stringio.h"
#include "angle.h"
const Vector3 ANGLESKEY_IDENTITY = Vector3(0, 0, 0);
inline void default_angles(Vector3& angles)
{
angles = ANGLESKEY_IDENTITY;
}
inline void normalise_angles(Vector3& angles)
{
angles[0] = static_cast<float>(float_mod(angles[0], 360));
angles[1] = static_cast<float>(float_mod(angles[1], 360));
angles[2] = static_cast<float>(float_mod(angles[2], 360));
}
inline void read_angle(Vector3& angles, const char* value)
{
if(!string_parse_float(value, angles[2]))
{
default_angles(angles);
}
else
{
angles[0] = 0;
angles[1] = 0;
normalise_angles(angles);
}
}
inline void read_angles(Vector3& angles, const char* value)
{
if(!string_parse_vector3(value, angles))
{
default_angles(angles);
}
else
{
angles = Vector3(angles[2], angles[0], angles[1]);
normalise_angles(angles);
}
}
inline void write_angles(const Vector3& angles, Entity* entity)
{
if(angles[0] == 0
&& angles[1] == 0
&& angles[2] == 0)
{
entity->setKeyValue("angle", "");
entity->setKeyValue("angles", "");
}
else
{
char value[64];
if(angles[0] == 0 && angles[1] == 0)
{
entity->setKeyValue("angles", "");
write_angle(angles[2], entity);
}
else
{
sprintf(value, "%g %g %g", angles[1], angles[2], angles[0]);
entity->setKeyValue("angle", "");
entity->setKeyValue("angles", value);
}
}
}
inline Vector3 angles_rotated(const Vector3& angles, const Quaternion& rotation)
{
return matrix4_get_rotation_euler_xyz_degrees(
matrix4_multiplied_by_matrix4(
matrix4_rotation_for_euler_xyz_degrees(angles),
matrix4_rotation_for_quaternion_quantised(rotation)
)
);
}
class AnglesKey
{
Callback m_anglesChanged;
public:
Vector3 m_angles;
AnglesKey(const Callback& anglesChanged)
: m_anglesChanged(anglesChanged), m_angles(ANGLESKEY_IDENTITY)
{
}
void angleChanged(const char* value)
{
read_angle(m_angles, value);
m_anglesChanged();
}
typedef MemberCaller1<AnglesKey, const char*, &AnglesKey::angleChanged> AngleChangedCaller;
void anglesChanged(const char* value)
{
read_angles(m_angles, value);
m_anglesChanged();
}
typedef MemberCaller1<AnglesKey, const char*, &AnglesKey::anglesChanged> AnglesChangedCaller;
void write(Entity* entity) const
{
write_angles(m_angles, entity);
}
};
#endif

23
plugins/entity/colour.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 "colour.h"

102
plugins/entity/colour.h Normal file
View File

@@ -0,0 +1,102 @@
/*
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_COLOUR_H)
#define INCLUDED_COLOUR_H
#include "ientity.h"
#include "irender.h"
#include "math/vector.h"
#include "eclasslib.h"
#include "generic/callback.h"
#include "stringio.h"
inline void default_colour(Vector3& colour)
{
colour = Vector3(1, 1, 1);
}
inline void read_colour(Vector3& colour, const char* value)
{
if(!string_parse_vector3(value, colour))
{
default_colour(colour);
}
}
inline void write_colour(const Vector3& colour, Entity* entity)
{
char value[64];
sprintf(value, "%f %f %f", colour[0], colour[1], colour[2]);
entity->setKeyValue("_color", value);
}
class Colour
{
Callback m_colourChanged;
Shader* m_state;
void capture_state()
{
m_state = colour_capture_state_fill(m_colour);
}
void release_state()
{
colour_release_state_fill(m_colour);
}
public:
Vector3 m_colour;
Colour(const Callback& colourChanged)
: m_colourChanged(colourChanged)
{
default_colour(m_colour);
capture_state();
}
~Colour()
{
release_state();
}
void colourChanged(const char* value)
{
release_state();
read_colour(m_colour, value);
capture_state();
m_colourChanged();
}
typedef MemberCaller1<Colour, const char*, &Colour::colourChanged> ColourChangedCaller;
void write(Entity* entity) const
{
write_colour(m_colour, entity);
}
Shader* state() const
{
return m_state;
}
};
#endif

23
plugins/entity/curve.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 "curve.h"

521
plugins/entity/curve.h Normal file
View File

@@ -0,0 +1,521 @@
/*
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_CURVE_H)
#define INCLUDED_CURVE_H
#include "ientity.h"
#include "selectable.h"
#include "renderable.h"
#include <set>
#include "math/curve.h"
#include "stream/stringstream.h"
#include "selectionlib.h"
#include "render.h"
#include "stringio.h"
class RenderableCurve : public OpenGLRenderable
{
public:
std::vector<PointVertex> m_vertices;
void render(RenderStateFlags state) const
{
pointvertex_gl_array(&m_vertices.front());
glDrawArrays(GL_LINE_STRIP, 0, GLsizei(m_vertices.size()));
}
};
inline void plotBasisFunction(std::size_t numSegments, int point, int degree)
{
Knots knots;
KnotVector_openUniform(knots, 4, degree);
globalOutputStream() << "plotBasisFunction point " << point << " of 4, knot vector:";
for(Knots::iterator i = knots.begin(); i != knots.end(); ++i)
{
globalOutputStream() << " " << *i;
}
globalOutputStream() << "\n";
globalOutputStream() << "t=0 basis=" << BSpline_basis(knots, point, degree, 0.0) << "\n";
for(std::size_t i = 1; i < numSegments; ++i)
{
double t = (1.0 / double(numSegments)) * double(i);
globalOutputStream() << "t=" << t << " basis=" << BSpline_basis(knots, point, degree, t) << "\n";
}
globalOutputStream() << "t=1 basis=" << BSpline_basis(knots, point, degree, 1.0) << "\n";
}
inline bool ControlPoints_parse(ControlPoints& controlPoints, const char* value)
{
StringTokeniser tokeniser(value, " ");
std::size_t size;
if(!string_parse_size(tokeniser.getToken(), size))
{
return false;
}
if(size < 3)
{
return false;
}
controlPoints.resize(size);
if(!string_equal(tokeniser.getToken(), "("))
{
return false;
}
for(ControlPoints::iterator i = controlPoints.begin(); i != controlPoints.end(); ++i)
{
if(!string_parse_float(tokeniser.getToken(), (*i).x())
|| !string_parse_float(tokeniser.getToken(), (*i).y())
|| !string_parse_float(tokeniser.getToken(), (*i).z()))
{
return false;
}
}
if(!string_equal(tokeniser.getToken(), ")"))
{
return false;
}
return true;
}
inline void ControlPoints_write(const ControlPoints& controlPoints, StringOutputStream& value)
{
value << Unsigned(controlPoints.size()) << " (";
for(ControlPoints::const_iterator i = controlPoints.begin(); i != controlPoints.end(); ++i)
{
value << " " << (*i).x() << " " << (*i).y() << " " << (*i).z() << " ";
}
value << ")";
}
inline void ControlPoint_testSelect(const Vector3& point, ObservedSelectable& selectable, Selector& selector, SelectionTest& test)
{
SelectionIntersection best;
test.TestPoint(point, best);
if(best.valid())
{
Selector_add(selector, selectable, best);
}
}
class ControlPointTransform
{
const Matrix4& m_matrix;
public:
ControlPointTransform(const Matrix4& matrix) : m_matrix(matrix)
{
}
void operator()(Vector3& point) const
{
matrix4_transform_point(m_matrix, point);
}
};
class ControlPointSnap
{
float m_snap;
public:
ControlPointSnap(float snap) : m_snap(snap)
{
}
void operator()(Vector3& point) const
{
vector3_snap(point, m_snap);
}
};
const Colour4b colour_vertex(0, 255, 0, 255);
const Colour4b colour_selected(0, 0, 255, 255);
class ControlPointAdd
{
RenderablePointVector& m_points;
public:
ControlPointAdd(RenderablePointVector& points) : m_points(points)
{
}
void operator()(const Vector3& point) const
{
m_points.push_back(PointVertex(vertex3f_for_vector3(point), colour_vertex));
}
};
class ControlPointAddSelected
{
RenderablePointVector& m_points;
public:
ControlPointAddSelected(RenderablePointVector& points) : m_points(points)
{
}
void operator()(const Vector3& point) const
{
m_points.push_back(PointVertex(vertex3f_for_vector3(point), colour_selected));
}
};
class CurveEditType
{
public:
Shader* m_controlsShader;
Shader* m_selectedShader;
};
inline void ControlPoints_write(ControlPoints& controlPoints, const char* key, Entity& entity)
{
StringOutputStream value(256);
if(!controlPoints.empty())
{
ControlPoints_write(controlPoints, value);
}
entity.setKeyValue(key, value.c_str());
}
class CurveEdit
{
SelectionChangeCallback m_selectionChanged;
ControlPoints& m_controlPoints;
typedef Array<ObservedSelectable> Selectables;
Selectables m_selectables;
RenderablePointVector m_controlsRender;
mutable RenderablePointVector m_selectedRender;
public:
typedef Static<CurveEditType> Type;
CurveEdit(ControlPoints& controlPoints, const SelectionChangeCallback& selectionChanged) :
m_selectionChanged(selectionChanged),
m_controlPoints(controlPoints),
m_controlsRender(GL_POINTS),
m_selectedRender(GL_POINTS)
{
}
template<typename Functor>
const Functor& forEachSelected(const Functor& functor)
{
ASSERT_MESSAGE(m_controlPoints.size() == m_selectables.size(), "curve instance mismatch");
ControlPoints::iterator p = m_controlPoints.begin();
for(Selectables::iterator i = m_selectables.begin(); i != m_selectables.end(); ++i, ++p)
{
if((*i).isSelected())
{
functor(*p);
}
}
return functor;
}
template<typename Functor>
const Functor& forEachSelected(const Functor& functor) const
{
ASSERT_MESSAGE(m_controlPoints.size() == m_selectables.size(), "curve instance mismatch");
ControlPoints::const_iterator p = m_controlPoints.begin();
for(Selectables::const_iterator i = m_selectables.begin(); i != m_selectables.end(); ++i, ++p)
{
if((*i).isSelected())
{
functor(*p);
}
}
return functor;
}
template<typename Functor>
const Functor& forEach(const Functor& functor) const
{
for(ControlPoints::const_iterator i = m_controlPoints.begin(); i != m_controlPoints.end(); ++i)
{
functor(*i);
}
return functor;
}
void testSelect(Selector& selector, SelectionTest& test)
{
ASSERT_MESSAGE(m_controlPoints.size() == m_selectables.size(), "curve instance mismatch");
ControlPoints::const_iterator p = m_controlPoints.begin();
for(Selectables::iterator i = m_selectables.begin(); i != m_selectables.end(); ++i, ++p)
{
ControlPoint_testSelect(*p, *i, selector, test);
}
}
bool isSelected() const
{
for(Selectables::const_iterator i = m_selectables.begin(); i != m_selectables.end(); ++i)
{
if((*i).isSelected())
{
return true;
}
}
return false;
}
void setSelected(bool selected)
{
for(Selectables::iterator i = m_selectables.begin(); i != m_selectables.end(); ++i)
{
(*i).setSelected(selected);
}
}
void write(const char* key, Entity& entity)
{
ControlPoints_write(m_controlPoints, key, entity);
}
void transform(const Matrix4& matrix)
{
forEachSelected(ControlPointTransform(matrix));
}
void snapto(float snap)
{
forEachSelected(ControlPointSnap(snap));
}
void updateSelected() const
{
m_selectedRender.clear();
forEachSelected(ControlPointAddSelected(m_selectedRender));
}
void renderComponents(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
{
renderer.SetState(Type::instance().m_controlsShader, Renderer::eWireframeOnly);
renderer.SetState(Type::instance().m_controlsShader, Renderer::eFullMaterials);
renderer.addRenderable(m_controlsRender, localToWorld);
}
void renderComponentsSelected(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
{
updateSelected();
if(!m_selectedRender.empty())
{
renderer.Highlight(Renderer::ePrimitive, false);
renderer.SetState(Type::instance().m_selectedShader, Renderer::eWireframeOnly);
renderer.SetState(Type::instance().m_selectedShader, Renderer::eFullMaterials);
renderer.addRenderable(m_selectedRender, localToWorld);
}
}
void curveChanged()
{
m_selectables.resize(m_controlPoints.size(), m_selectionChanged);
m_controlsRender.clear();
m_controlsRender.reserve(m_controlPoints.size());
forEach(ControlPointAdd(m_controlsRender));
m_selectedRender.reserve(m_controlPoints.size());
}
typedef MemberCaller<CurveEdit, &CurveEdit::curveChanged> CurveChangedCaller;
};
const int NURBS_degree = 3;
class NURBSCurve
{
typedef std::set<Callback> Callbacks;
Callbacks m_curveChanged;
Callback m_boundsChanged;
public:
ControlPoints m_controlPoints;
ControlPoints m_controlPointsTransformed;
NURBSWeights m_weights;
Knots m_knots;
RenderableCurve m_renderCurve;
AABB m_bounds;
NURBSCurve(const Callback& boundsChanged) : m_boundsChanged(boundsChanged)
{
}
void attach(const Callback& curveChanged)
{
m_curveChanged.insert(curveChanged);
curveChanged();
}
void detach(const Callback& curveChanged)
{
m_curveChanged.erase(curveChanged);
}
void notify()
{
std::for_each(m_curveChanged.begin(), m_curveChanged.end(), CallbackInvoke());
}
void tesselate()
{
if(!m_controlPointsTransformed.empty())
{
const std::size_t numSegments = (m_controlPointsTransformed.size() - 1) * 16;
m_renderCurve.m_vertices.resize(numSegments + 1);
m_renderCurve.m_vertices[0].vertex = vertex3f_for_vector3(m_controlPointsTransformed[0]);
for(std::size_t i = 1; i < numSegments; ++i)
{
m_renderCurve.m_vertices[i].vertex = vertex3f_for_vector3(NURBS_evaluate(m_controlPointsTransformed, m_weights, m_knots, NURBS_degree, (1.0 / double(numSegments)) * double(i)));
}
m_renderCurve.m_vertices[numSegments].vertex = vertex3f_for_vector3(m_controlPointsTransformed[m_controlPointsTransformed.size() - 1]);
}
else
{
m_renderCurve.m_vertices.clear();
}
}
void curveChanged()
{
tesselate();
m_bounds = AABB();
for(ControlPoints::iterator i = m_controlPointsTransformed.begin(); i != m_controlPointsTransformed.end(); ++i)
{
aabb_extend_by_point_safe(m_bounds, (*i));
}
m_boundsChanged();
notify();
}
bool parseCurve(const char* value)
{
if(!ControlPoints_parse(m_controlPoints, value))
{
return false;
}
m_weights.resize(m_controlPoints.size());
for(NURBSWeights::iterator i = m_weights.begin(); i != m_weights.end(); ++i)
{
(*i) = 1;
}
KnotVector_openUniform(m_knots, m_controlPoints.size(), NURBS_degree);
//plotBasisFunction(8, 0, NURBS_degree);
return true;
}
void curveChanged(const char* value)
{
if(string_empty(value) || !parseCurve(value))
{
m_controlPoints.resize(0);
m_knots.resize(0);
m_weights.resize(0);
}
m_controlPointsTransformed = m_controlPoints;
curveChanged();
}
typedef MemberCaller1<NURBSCurve, const char*, &NURBSCurve::curveChanged> CurveChangedCaller;
};
class CatmullRomSpline
{
typedef std::set<Callback> Callbacks;
Callbacks m_curveChanged;
Callback m_boundsChanged;
public:
ControlPoints m_controlPoints;
ControlPoints m_controlPointsTransformed;
RenderableCurve m_renderCurve;
AABB m_bounds;
CatmullRomSpline(const Callback& boundsChanged) : m_boundsChanged(boundsChanged)
{
}
void attach(const Callback& curveChanged)
{
m_curveChanged.insert(curveChanged);
curveChanged();
}
void detach(const Callback& curveChanged)
{
m_curveChanged.erase(curveChanged);
}
void notify()
{
std::for_each(m_curveChanged.begin(), m_curveChanged.end(), CallbackInvoke());
}
void tesselate()
{
if(!m_controlPointsTransformed.empty())
{
const std::size_t numSegments = (m_controlPointsTransformed.size() - 1) * 16;
m_renderCurve.m_vertices.resize(numSegments + 1);
m_renderCurve.m_vertices[0].vertex = vertex3f_for_vector3(m_controlPointsTransformed[0]);
for(std::size_t i = 1; i < numSegments; ++i)
{
m_renderCurve.m_vertices[i].vertex = vertex3f_for_vector3(CatmullRom_evaluate(m_controlPointsTransformed, (1.0 / double(numSegments)) * double(i)));
}
m_renderCurve.m_vertices[numSegments].vertex = vertex3f_for_vector3(m_controlPointsTransformed[m_controlPointsTransformed.size() - 1]);
}
else
{
m_renderCurve.m_vertices.clear();
}
}
bool parseCurve(const char* value)
{
return ControlPoints_parse(m_controlPoints, value);
}
void curveChanged()
{
tesselate();
m_bounds = AABB();
for(ControlPoints::iterator i = m_controlPointsTransformed.begin(); i != m_controlPointsTransformed.end(); ++i)
{
aabb_extend_by_point_safe(m_bounds, (*i));
}
m_boundsChanged();
notify();
}
void curveChanged(const char* value)
{
if(string_empty(value) || !parseCurve(value))
{
m_controlPoints.resize(0);
}
m_controlPointsTransformed = m_controlPoints;
curveChanged();
}
typedef MemberCaller1<CatmullRomSpline, const char*, &CatmullRomSpline::curveChanged> CurveChangedCaller;
};
const char* const curve_Nurbs = "curve_Nurbs";
const char* const curve_CatmullRomSpline = "curve_CatmullRomSpline";
#endif

View File

@@ -0,0 +1,809 @@
/*
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
*/
///\file
///\brief Represents any Doom3 entity which does not have a fixed size specified in its entity-definition (e.g. func_static).
///
/// This entity behaves as a group only when the "model" key is empty or is the same as the "name" key. Otherwise it behaves as a model.
/// When behaving as a group, the "origin" key is the translation to be applied to all brushes (not patches) grouped under this entity.
/// When behaving as a model, the "origin", "angle" and "rotation" keys directly control the entity's local-to-parent transform.
/// When either the "curve_Nurbs" or "curve_CatmullRomSpline" keys define a curve, the curve is rendered and can be edited.
#include "doom3group.h"
#include "cullable.h"
#include "renderable.h"
#include "editable.h"
#include "modelskin.h"
#include "selectionlib.h"
#include "instancelib.h"
#include "transformlib.h"
#include "traverselib.h"
#include "entitylib.h"
#include "render.h"
#include "eclasslib.h"
#include "stream/stringstream.h"
#include "pivot.h"
#include "targetable.h"
#include "origin.h"
#include "angle.h"
#include "rotation.h"
#include "model.h"
#include "filters.h"
#include "namedentity.h"
#include "keyobservers.h"
#include "namekeys.h"
#include "curve.h"
#include "modelskinkey.h"
#include "entity.h"
inline void PointVertexArray_testSelect(PointVertex* first, std::size_t count, SelectionTest& test, SelectionIntersection& best)
{
test.TestLineStrip(
VertexPointer(
reinterpret_cast<VertexPointer::pointer>(&first->vertex),
sizeof(PointVertex)
),
IndexPointer::index_type(count),
best
);
}
class Doom3Group :
public Bounded,
public Snappable
{
EntityKeyValues m_entity;
KeyObserverMap m_keyObservers;
TraversableNodeSet m_traverse;
MatrixTransform m_transform;
SingletonModel m_model;
OriginKey m_originKey;
Vector3 m_origin;
RotationKey m_rotationKey;
Float9 m_rotation;
ClassnameFilter m_filter;
NamedEntity m_named;
NameKeys m_nameKeys;
TraversableObserverPairRelay m_traverseObservers;
Doom3GroupOrigin m_funcStaticOrigin;
RenderablePivot m_renderOrigin;
RenderableNamedEntity m_renderName;
ModelSkinKey m_skin;
public:
NURBSCurve m_curveNURBS;
CatmullRomSpline m_curveCatmullRom;
private:
mutable AABB m_curveBounds;
Callback m_transformChanged;
Callback m_evaluateTransform;
CopiedString m_name;
CopiedString m_modelKey;
bool m_isModel;
scene::Traversable* m_traversable;
void construct()
{
default_rotation(m_rotation);
m_keyObservers.insert("classname", ClassnameFilter::ClassnameChangedCaller(m_filter));
m_keyObservers.insert(Static<KeyIsName>::instance().m_nameKey, NamedEntity::IdentifierChangedCaller(m_named));
m_keyObservers.insert("model", Doom3Group::ModelChangedCaller(*this));
m_keyObservers.insert("origin", OriginKey::OriginChangedCaller(m_originKey));
m_keyObservers.insert("angle", RotationKey::AngleChangedCaller(m_rotationKey));
m_keyObservers.insert("rotation", RotationKey::RotationChangedCaller(m_rotationKey));
m_keyObservers.insert("name", NameChangedCaller(*this));
m_keyObservers.insert(curve_Nurbs, NURBSCurve::CurveChangedCaller(m_curveNURBS));
m_keyObservers.insert(curve_CatmullRomSpline, CatmullRomSpline::CurveChangedCaller(m_curveCatmullRom));
m_keyObservers.insert("skin", ModelSkinKey::SkinChangedCaller(m_skin));
m_traverseObservers.attach(m_funcStaticOrigin);
m_isModel = false;
m_nameKeys.setKeyIsName(keyIsNameDoom3Doom3Group);
attachTraverse();
m_entity.attach(m_keyObservers);
}
void destroy()
{
m_entity.detach(m_keyObservers);
if(isModel())
{
detachModel();
}
else
{
detachTraverse();
}
m_traverseObservers.detach(m_funcStaticOrigin);
}
void attachModel()
{
m_traversable = &m_model.getTraversable();
m_model.attach(&m_traverseObservers);
}
void detachModel()
{
m_traversable = 0;
m_model.detach(&m_traverseObservers);
}
void attachTraverse()
{
m_traversable = &m_traverse;
m_traverse.attach(&m_traverseObservers);
}
void detachTraverse()
{
m_traversable = 0;
m_traverse.detach(&m_traverseObservers);
}
bool isModel() const
{
return m_isModel;
}
void setIsModel(bool newValue)
{
if(newValue && !m_isModel)
{
detachTraverse();
attachModel();
m_nameKeys.setKeyIsName(Static<KeyIsName>::instance().m_keyIsName);
m_model.modelChanged(m_modelKey.c_str());
}
else if(!newValue && m_isModel)
{
detachModel();
attachTraverse();
m_nameKeys.setKeyIsName(keyIsNameDoom3Doom3Group);
}
m_isModel = newValue;
updateTransform();
}
void updateIsModel()
{
setIsModel(!string_empty(m_modelKey.c_str()) && !string_equal(m_modelKey.c_str(), m_name.c_str()));
}
void nameChanged(const char* value)
{
m_name = value;
updateIsModel();
}
typedef MemberCaller1<Doom3Group, const char*, &Doom3Group::nameChanged> NameChangedCaller;
void modelChanged(const char* value)
{
m_modelKey = value;
updateIsModel();
if(isModel())
{
m_model.modelChanged(value);
}
else
{
m_model.modelChanged("");
}
}
typedef MemberCaller1<Doom3Group, const char*, &Doom3Group::modelChanged> ModelChangedCaller;
void updateTransform()
{
m_transform.localToParent() = g_matrix4_identity;
if(isModel())
{
matrix4_translate_by_vec3(m_transform.localToParent(), m_originKey.m_origin);
matrix4_multiply_by_matrix4(m_transform.localToParent(), rotation_toMatrix(m_rotationKey.m_rotation));
}
m_transformChanged();
if(!isModel())
{
m_funcStaticOrigin.originChanged();
}
}
typedef MemberCaller<Doom3Group, &Doom3Group::updateTransform> UpdateTransformCaller;
void originChanged()
{
m_origin = m_originKey.m_origin;
updateTransform();
}
typedef MemberCaller<Doom3Group, &Doom3Group::originChanged> OriginChangedCaller;
void rotationChanged()
{
rotation_assign(m_rotation, m_rotationKey.m_rotation);
updateTransform();
}
typedef MemberCaller<Doom3Group, &Doom3Group::rotationChanged> RotationChangedCaller;
void skinChanged()
{
if(isModel())
{
scene::Node* node = m_model.getNode();
if(node != 0)
{
Node_modelSkinChanged(*node);
}
}
}
typedef MemberCaller<Doom3Group, &Doom3Group::skinChanged> SkinChangedCaller;
public:
Doom3Group(EntityClass* eclass, scene::Node& node, const Callback& transformChanged, const Callback& boundsChanged, const Callback& evaluateTransform) :
m_entity(eclass),
m_originKey(OriginChangedCaller(*this)),
m_origin(ORIGINKEY_IDENTITY),
m_rotationKey(RotationChangedCaller(*this)),
m_filter(m_entity, node),
m_named(m_entity),
m_nameKeys(m_entity),
m_funcStaticOrigin(m_traverse, m_origin),
m_renderName(m_named, g_vector3_identity),
m_skin(SkinChangedCaller(*this)),
m_curveNURBS(boundsChanged),
m_curveCatmullRom(boundsChanged),
m_transformChanged(transformChanged),
m_evaluateTransform(evaluateTransform),
m_traversable(0)
{
construct();
}
Doom3Group(const Doom3Group& other, scene::Node& node, const Callback& transformChanged, const Callback& boundsChanged, const Callback& evaluateTransform) :
m_entity(other.m_entity),
m_originKey(OriginChangedCaller(*this)),
m_origin(ORIGINKEY_IDENTITY),
m_rotationKey(RotationChangedCaller(*this)),
m_filter(m_entity, node),
m_named(m_entity),
m_nameKeys(m_entity),
m_funcStaticOrigin(m_traverse, m_origin),
m_renderName(m_named, g_vector3_identity),
m_skin(SkinChangedCaller(*this)),
m_curveNURBS(boundsChanged),
m_curveCatmullRom(boundsChanged),
m_transformChanged(transformChanged),
m_evaluateTransform(evaluateTransform),
m_traversable(0)
{
construct();
}
~Doom3Group()
{
destroy();
}
InstanceCounter m_instanceCounter;
void instanceAttach(const scene::Path& path)
{
if(++m_instanceCounter.m_count == 1)
{
m_filter.instanceAttach();
m_entity.instanceAttach(path_find_mapfile(path.begin(), path.end()));
m_traverse.instanceAttach(path_find_mapfile(path.begin(), path.end()));
m_funcStaticOrigin.enable();
}
}
void instanceDetach(const scene::Path& path)
{
if(--m_instanceCounter.m_count == 0)
{
m_funcStaticOrigin.disable();
m_traverse.instanceDetach(path_find_mapfile(path.begin(), path.end()));
m_entity.instanceDetach(path_find_mapfile(path.begin(), path.end()));
m_filter.instanceDetach();
}
}
EntityKeyValues& getEntity()
{
return m_entity;
}
const EntityKeyValues& getEntity() const
{
return m_entity;
}
scene::Traversable& getTraversable()
{
return *m_traversable;
}
Namespaced& getNamespaced()
{
return m_nameKeys;
}
Nameable& getNameable()
{
return m_named;
}
TransformNode& getTransformNode()
{
return m_transform;
}
ModelSkin& getModelSkin()
{
return m_skin.get();
}
void attach(scene::Traversable::Observer* observer)
{
m_traverseObservers.attach(*observer);
}
void detach(scene::Traversable::Observer* observer)
{
m_traverseObservers.detach(*observer);
}
const AABB& localAABB() const
{
m_curveBounds = m_curveNURBS.m_bounds;
aabb_extend_by_aabb_safe(m_curveBounds, m_curveCatmullRom.m_bounds);
return m_curveBounds;
}
void renderSolid(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected) const
{
if(isModel() && selected)
{
m_renderOrigin.render(renderer, volume, localToWorld);
}
renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly);
renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eFullMaterials);
if(!m_curveNURBS.m_renderCurve.m_vertices.empty())
{
renderer.addRenderable(m_curveNURBS.m_renderCurve, localToWorld);
}
if(!m_curveCatmullRom.m_renderCurve.m_vertices.empty())
{
renderer.addRenderable(m_curveCatmullRom.m_renderCurve, localToWorld);
}
}
void renderWireframe(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected) const
{
renderSolid(renderer, volume, localToWorld, selected);
if(g_showNames && isModel())
{
renderer.addRenderable(m_renderName, localToWorld);
}
}
void testSelect(Selector& selector, SelectionTest& test, SelectionIntersection& best)
{
PointVertexArray_testSelect(&m_curveNURBS.m_renderCurve.m_vertices[0], m_curveNURBS.m_renderCurve.m_vertices.size(), test, best);
PointVertexArray_testSelect(&m_curveCatmullRom.m_renderCurve.m_vertices[0], m_curveCatmullRom.m_renderCurve.m_vertices.size(), test, best);
}
void translate(const Vector3& translation)
{
m_origin = origin_translated(m_origin, translation);
}
void rotate(const Quaternion& rotation)
{
rotation_rotate(m_rotation, rotation);
}
void snapto(float snap)
{
m_originKey.m_origin = origin_snapped(m_originKey.m_origin, snap);
m_originKey.write(&m_entity);
}
void revertTransform()
{
m_origin = m_originKey.m_origin;
rotation_assign(m_rotation, m_rotationKey.m_rotation);
m_curveNURBS.m_controlPointsTransformed = m_curveNURBS.m_controlPoints;
m_curveCatmullRom.m_controlPointsTransformed = m_curveCatmullRom.m_controlPoints;
}
void freezeTransform()
{
m_originKey.m_origin = m_origin;
m_originKey.write(&m_entity);
rotation_assign(m_rotationKey.m_rotation, m_rotation);
m_rotationKey.write(&m_entity);
m_curveNURBS.m_controlPoints = m_curveNURBS.m_controlPointsTransformed;
ControlPoints_write(m_curveNURBS.m_controlPoints, curve_Nurbs, m_entity);
m_curveCatmullRom.m_controlPoints = m_curveCatmullRom.m_controlPointsTransformed;
ControlPoints_write(m_curveCatmullRom.m_controlPoints, curve_CatmullRomSpline, m_entity);
}
void transformChanged()
{
revertTransform();
m_evaluateTransform();
updateTransform();
m_curveNURBS.curveChanged();
m_curveCatmullRom.curveChanged();
}
typedef MemberCaller<Doom3Group, &Doom3Group::transformChanged> TransformChangedCaller;
};
class ControlPointAddBounds
{
AABB& m_bounds;
public:
ControlPointAddBounds(AABB& bounds) : m_bounds(bounds)
{
}
void operator()(const Vector3& point) const
{
aabb_extend_by_point_safe(m_bounds, point);
}
};
class Doom3GroupInstance :
public TargetableInstance,
public TransformModifier,
public Renderable,
public SelectionTestable,
public ComponentSelectionTestable,
public ComponentEditable,
public ComponentSnappable
{
class TypeCasts
{
InstanceTypeCastTable m_casts;
public:
TypeCasts()
{
m_casts = TargetableInstance::StaticTypeCasts::instance().get();
InstanceContainedCast<Doom3GroupInstance, Bounded>::install(m_casts);
InstanceStaticCast<Doom3GroupInstance, Renderable>::install(m_casts);
InstanceStaticCast<Doom3GroupInstance, SelectionTestable>::install(m_casts);
InstanceStaticCast<Doom3GroupInstance, ComponentSelectionTestable>::install(m_casts);
InstanceStaticCast<Doom3GroupInstance, ComponentEditable>::install(m_casts);
InstanceStaticCast<Doom3GroupInstance, ComponentSnappable>::install(m_casts);
InstanceStaticCast<Doom3GroupInstance, Transformable>::install(m_casts);
InstanceIdentityCast<Doom3GroupInstance>::install(m_casts);
}
InstanceTypeCastTable& get()
{
return m_casts;
}
};
Doom3Group& m_contained;
CurveEdit m_curveNURBS;
CurveEdit m_curveCatmullRom;
mutable AABB m_aabb_component;
public:
typedef LazyStatic<TypeCasts> StaticTypeCasts;
Bounded& get(NullType<Bounded>)
{
return m_contained;
}
STRING_CONSTANT(Name, "Doom3GroupInstance");
Doom3GroupInstance(const scene::Path& path, scene::Instance* parent, Doom3Group& contained) :
TargetableInstance(path, parent, this, StaticTypeCasts::instance().get(), contained.getEntity(), *this),
TransformModifier(Doom3Group::TransformChangedCaller(contained), ApplyTransformCaller(*this)),
m_contained(contained),
m_curveNURBS(m_contained.m_curveNURBS.m_controlPointsTransformed, SelectionChangedComponentCaller(*this)),
m_curveCatmullRom(m_contained.m_curveCatmullRom.m_controlPointsTransformed, SelectionChangedComponentCaller(*this))
{
m_contained.instanceAttach(Instance::path());
m_contained.m_curveNURBS.attach(CurveEdit::CurveChangedCaller(m_curveNURBS));
m_contained.m_curveCatmullRom.attach(CurveEdit::CurveChangedCaller(m_curveCatmullRom));
StaticRenderableConnectionLines::instance().attach(*this);
}
~Doom3GroupInstance()
{
StaticRenderableConnectionLines::instance().detach(*this);
m_contained.m_curveCatmullRom.detach(CurveEdit::CurveChangedCaller(m_curveCatmullRom));
m_contained.m_curveNURBS.detach(CurveEdit::CurveChangedCaller(m_curveNURBS));
m_contained.instanceDetach(Instance::path());
}
void renderSolid(Renderer& renderer, const VolumeTest& volume) const
{
m_contained.renderSolid(renderer, volume, Instance::localToWorld(), getSelectable().isSelected());
m_curveNURBS.renderComponentsSelected(renderer, volume, localToWorld());
m_curveCatmullRom.renderComponentsSelected(renderer, volume, localToWorld());
}
void renderWireframe(Renderer& renderer, const VolumeTest& volume) const
{
m_contained.renderWireframe(renderer, volume, Instance::localToWorld(), getSelectable().isSelected());
m_curveNURBS.renderComponentsSelected(renderer, volume, localToWorld());
m_curveCatmullRom.renderComponentsSelected(renderer, volume, localToWorld());
}
void renderComponents(Renderer& renderer, const VolumeTest& volume) const
{
if(GlobalSelectionSystem().ComponentMode() == SelectionSystem::eVertex)
{
m_curveNURBS.renderComponents(renderer, volume, localToWorld());
m_curveCatmullRom.renderComponents(renderer, volume, localToWorld());
}
}
void testSelect(Selector& selector, SelectionTest& test)
{
test.BeginMesh(localToWorld());
SelectionIntersection best;
m_contained.testSelect(selector, test, best);
if(best.valid())
{
Selector_add(selector, getSelectable(), best);
}
}
bool isSelectedComponents() const
{
return m_curveNURBS.isSelected() || m_curveCatmullRom.isSelected();
}
void setSelectedComponents(bool selected, SelectionSystem::EComponentMode mode)
{
if(mode == SelectionSystem::eVertex)
{
m_curveNURBS.setSelected(selected);
m_curveCatmullRom.setSelected(selected);
}
}
void testSelectComponents(Selector& selector, SelectionTest& test, SelectionSystem::EComponentMode mode)
{
if(mode == SelectionSystem::eVertex)
{
test.BeginMesh(localToWorld());
m_curveNURBS.testSelect(selector, test);
m_curveCatmullRom.testSelect(selector, test);
}
}
void transformComponents(const Matrix4& matrix)
{
if(m_curveNURBS.isSelected())
{
m_curveNURBS.transform(matrix);
}
if(m_curveCatmullRom.isSelected())
{
m_curveCatmullRom.transform(matrix);
}
}
const AABB& getSelectedComponentsBounds() const
{
m_aabb_component = AABB();
m_curveNURBS.forEachSelected(ControlPointAddBounds(m_aabb_component));
m_curveCatmullRom.forEachSelected(ControlPointAddBounds(m_aabb_component));
return m_aabb_component;
}
void snapComponents(float snap)
{
if(m_curveNURBS.isSelected())
{
m_curveNURBS.snapto(snap);
m_curveNURBS.write(curve_Nurbs, m_contained.getEntity());
}
if(m_curveCatmullRom.isSelected())
{
m_curveCatmullRom.snapto(snap);
m_curveCatmullRom.write(curve_CatmullRomSpline, m_contained.getEntity());
}
}
void evaluateTransform()
{
if(getType() == TRANSFORM_PRIMITIVE)
{
m_contained.translate(getTranslation());
m_contained.rotate(getRotation());
}
else
{
transformComponents(calculateTransform());
}
}
void applyTransform()
{
m_contained.revertTransform();
evaluateTransform();
m_contained.freezeTransform();
}
typedef MemberCaller<Doom3GroupInstance, &Doom3GroupInstance::applyTransform> ApplyTransformCaller;
void selectionChangedComponent(const Selectable& selectable)
{
GlobalSelectionSystem().getObserver(SelectionSystem::eComponent)(selectable);
GlobalSelectionSystem().onComponentSelection(*this, selectable);
}
typedef MemberCaller1<Doom3GroupInstance, const Selectable&, &Doom3GroupInstance::selectionChangedComponent> SelectionChangedComponentCaller;
};
class Doom3GroupNode :
public scene::Node::Symbiot,
public scene::Instantiable,
public scene::Cloneable,
public scene::Traversable::Observer
{
class TypeCasts
{
NodeTypeCastTable m_casts;
public:
TypeCasts()
{
NodeStaticCast<Doom3GroupNode, scene::Instantiable>::install(m_casts);
NodeStaticCast<Doom3GroupNode, scene::Cloneable>::install(m_casts);
NodeContainedCast<Doom3GroupNode, scene::Traversable>::install(m_casts);
NodeContainedCast<Doom3GroupNode, Snappable>::install(m_casts);
NodeContainedCast<Doom3GroupNode, TransformNode>::install(m_casts);
NodeContainedCast<Doom3GroupNode, Entity>::install(m_casts);
NodeContainedCast<Doom3GroupNode, Nameable>::install(m_casts);
NodeContainedCast<Doom3GroupNode, Namespaced>::install(m_casts);
NodeContainedCast<Doom3GroupNode, ModelSkin>::install(m_casts);
}
NodeTypeCastTable& get()
{
return m_casts;
}
};
scene::Node m_node;
InstanceSet m_instances;
Doom3Group m_contained;
void construct()
{
m_contained.attach(this);
}
void destroy()
{
m_contained.detach(this);
}
public:
typedef LazyStatic<TypeCasts> StaticTypeCasts;
scene::Traversable& get(NullType<scene::Traversable>)
{
return m_contained.getTraversable();
}
Snappable& get(NullType<Snappable>)
{
return m_contained;
}
TransformNode& get(NullType<TransformNode>)
{
return m_contained.getTransformNode();
}
Entity& get(NullType<Entity>)
{
return m_contained.getEntity();
}
Nameable& get(NullType<Nameable>)
{
return m_contained.getNameable();
}
Namespaced& get(NullType<Namespaced>)
{
return m_contained.getNamespaced();
}
ModelSkin& get(NullType<ModelSkin>)
{
return m_contained.getModelSkin();
}
Doom3GroupNode(EntityClass* eclass) :
m_node(this, this, StaticTypeCasts::instance().get()),
m_contained(eclass, m_node, InstanceSet::TransformChangedCaller(m_instances), InstanceSet::BoundsChangedCaller(m_instances), InstanceSetEvaluateTransform<Doom3GroupInstance>::Caller(m_instances))
{
construct();
}
Doom3GroupNode(const Doom3GroupNode& other) :
scene::Node::Symbiot(other),
scene::Instantiable(other),
scene::Cloneable(other),
scene::Traversable::Observer(other),
m_node(this, this, StaticTypeCasts::instance().get()),
m_contained(other.m_contained, m_node, InstanceSet::TransformChangedCaller(m_instances), InstanceSet::BoundsChangedCaller(m_instances), InstanceSetEvaluateTransform<Doom3GroupInstance>::Caller(m_instances))
{
construct();
}
~Doom3GroupNode()
{
destroy();
}
void release()
{
delete this;
}
scene::Node& node()
{
return m_node;
}
scene::Node& clone() const
{
return (new Doom3GroupNode(*this))->node();
}
void insert(scene::Node& child)
{
m_instances.insert(child);
}
void erase(scene::Node& child)
{
m_instances.erase(child);
}
scene::Instance* create(const scene::Path& path, scene::Instance* parent)
{
return new Doom3GroupInstance(path, parent, m_contained);
}
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);
}
};
void Doom3Group_construct()
{
CurveEdit::Type::instance().m_controlsShader = GlobalShaderCache().capture("$POINT");
CurveEdit::Type::instance().m_selectedShader = GlobalShaderCache().capture("$SELPOINT");
}
void Doom3Group_destroy()
{
GlobalShaderCache().release("$SELPOINT");
GlobalShaderCache().release("$POINT");
}
scene::Node& New_Doom3Group(EntityClass* eclass)
{
return (new Doom3GroupNode(eclass))->node();
}

View File

@@ -0,0 +1,35 @@
/*
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_STATIC_H)
#define INCLUDED_STATIC_H
namespace scene
{
class Node;
}
class EntityClass;
void Doom3Group_construct();
void Doom3Group_destroy();
scene::Node& New_Doom3Group(EntityClass* eclass);
#endif

View File

@@ -0,0 +1,526 @@
/*
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
*/
///\file
///\brief Represents any entity which has a fixed size specified in its entity-definition and displays a model (e.g. ammo_bfg).
///
/// This entity displays the model specified in its entity-definition.
/// The "origin" and "angle" keys directly control the entity's local-to-parent transform.
/// The "rotation" key directly controls the entity's local-to-parent transform for Doom3 only.
#include "eclassmodel.h"
#include "cullable.h"
#include "renderable.h"
#include "editable.h"
#include "selectionlib.h"
#include "instancelib.h"
#include "transformlib.h"
#include "traverselib.h"
#include "entitylib.h"
#include "render.h"
#include "eclasslib.h"
#include "pivot.h"
#include "targetable.h"
#include "origin.h"
#include "angle.h"
#include "rotation.h"
#include "model.h"
#include "filters.h"
#include "namedentity.h"
#include "keyobservers.h"
#include "namekeys.h"
#include "modelskinkey.h"
#include "entity.h"
class EclassModel :
public Snappable
{
MatrixTransform m_transform;
EntityKeyValues m_entity;
KeyObserverMap m_keyObservers;
OriginKey m_originKey;
Vector3 m_origin;
AngleKey m_angleKey;
float m_angle;
RotationKey m_rotationKey;
Float9 m_rotation;
SingletonModel m_model;
ClassnameFilter m_filter;
NamedEntity m_named;
NameKeys m_nameKeys;
RenderablePivot m_renderOrigin;
RenderableNamedEntity m_renderName;
ModelSkinKey m_skin;
Callback m_transformChanged;
Callback m_evaluateTransform;
void construct()
{
default_rotation(m_rotation);
m_keyObservers.insert("classname", ClassnameFilter::ClassnameChangedCaller(m_filter));
m_keyObservers.insert(Static<KeyIsName>::instance().m_nameKey, NamedEntity::IdentifierChangedCaller(m_named));
if(g_gameType == eGameTypeDoom3)
{
m_keyObservers.insert("angle", RotationKey::AngleChangedCaller(m_rotationKey));
m_keyObservers.insert("rotation", RotationKey::RotationChangedCaller(m_rotationKey));
}
else
{
m_keyObservers.insert("angle", AngleKey::AngleChangedCaller(m_angleKey));
}
m_keyObservers.insert("origin", OriginKey::OriginChangedCaller(m_originKey));
}
void updateTransform()
{
m_transform.localToParent() = g_matrix4_identity;
matrix4_translate_by_vec3(m_transform.localToParent(), m_origin);
if(g_gameType == eGameTypeDoom3)
{
matrix4_multiply_by_matrix4(m_transform.localToParent(), rotation_toMatrix(m_rotation));
}
else
{
matrix4_multiply_by_matrix4(m_transform.localToParent(), matrix4_rotation_for_z_degrees(m_angle));
}
m_transformChanged();
}
typedef MemberCaller<EclassModel, &EclassModel::updateTransform> UpdateTransformCaller;
void originChanged()
{
m_origin = m_originKey.m_origin;
updateTransform();
}
typedef MemberCaller<EclassModel, &EclassModel::originChanged> OriginChangedCaller;
void angleChanged()
{
m_angle = m_angleKey.m_angle;
updateTransform();
}
typedef MemberCaller<EclassModel, &EclassModel::angleChanged> AngleChangedCaller;
void rotationChanged()
{
rotation_assign(m_rotation, m_rotationKey.m_rotation);
updateTransform();
}
typedef MemberCaller<EclassModel, &EclassModel::rotationChanged> RotationChangedCaller;
void skinChanged()
{
scene::Node* node = m_model.getNode();
if(node != 0)
{
Node_modelSkinChanged(*node);
}
}
typedef MemberCaller<EclassModel, &EclassModel::skinChanged> SkinChangedCaller;
public:
EclassModel(EntityClass* eclass, scene::Node& node, const Callback& transformChanged, const Callback& evaluateTransform) :
m_entity(eclass),
m_originKey(OriginChangedCaller(*this)),
m_origin(ORIGINKEY_IDENTITY),
m_angleKey(AngleChangedCaller(*this)),
m_angle(ANGLEKEY_IDENTITY),
m_rotationKey(RotationChangedCaller(*this)),
m_filter(m_entity, node),
m_named(m_entity),
m_nameKeys(m_entity),
m_renderName(m_named, g_vector3_identity),
m_skin(SkinChangedCaller(*this)),
m_transformChanged(transformChanged),
m_evaluateTransform(evaluateTransform)
{
construct();
}
EclassModel(const EclassModel& other, scene::Node& node, const Callback& transformChanged, const Callback& evaluateTransform) :
m_entity(other.m_entity),
m_originKey(OriginChangedCaller(*this)),
m_origin(ORIGINKEY_IDENTITY),
m_angleKey(AngleChangedCaller(*this)),
m_angle(ANGLEKEY_IDENTITY),
m_rotationKey(RotationChangedCaller(*this)),
m_filter(m_entity, node),
m_named(m_entity),
m_nameKeys(m_entity),
m_renderName(m_named, g_vector3_identity),
m_skin(SkinChangedCaller(*this)),
m_transformChanged(transformChanged),
m_evaluateTransform(evaluateTransform)
{
construct();
}
InstanceCounter m_instanceCounter;
void instanceAttach(const scene::Path& path)
{
if(++m_instanceCounter.m_count == 1)
{
m_filter.instanceAttach();
m_entity.instanceAttach(path_find_mapfile(path.begin(), path.end()));
m_entity.attach(m_keyObservers);
m_model.modelChanged(m_entity.getEntityClass().modelpath());
m_skin.skinChanged(m_entity.getEntityClass().skin());
}
}
void instanceDetach(const scene::Path& path)
{
if(--m_instanceCounter.m_count == 0)
{
m_skin.skinChanged("");
m_model.modelChanged("");
m_entity.detach(m_keyObservers);
m_entity.instanceDetach(path_find_mapfile(path.begin(), path.end()));
m_filter.instanceDetach();
}
}
EntityKeyValues& getEntity()
{
return m_entity;
}
const EntityKeyValues& getEntity() const
{
return m_entity;
}
scene::Traversable& getTraversable()
{
return m_model.getTraversable();
}
Namespaced& getNamespaced()
{
return m_nameKeys;
}
Nameable& getNameable()
{
return m_named;
}
TransformNode& getTransformNode()
{
return m_transform;
}
ModelSkin& getModelSkin()
{
return m_skin.get();
}
void attach(scene::Traversable::Observer* observer)
{
m_model.attach(observer);
}
void detach(scene::Traversable::Observer* observer)
{
m_model.detach(observer);
}
void renderSolid(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected) const
{
if(selected)
{
m_renderOrigin.render(renderer, volume, localToWorld);
}
renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly);
}
void renderWireframe(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected) const
{
renderSolid(renderer, volume, localToWorld, selected);
if(g_showNames)
{
renderer.addRenderable(m_renderName, localToWorld);
}
}
void translate(const Vector3& translation)
{
m_origin = origin_translated(m_origin, translation);
}
void rotate(const Quaternion& rotation)
{
if(g_gameType == eGameTypeDoom3)
{
rotation_rotate(m_rotation, rotation);
}
else
{
m_angle = angle_rotated(m_angle, rotation);
}
}
void snapto(float snap)
{
m_originKey.m_origin = origin_snapped(m_originKey.m_origin, snap);
m_originKey.write(&m_entity);
}
void revertTransform()
{
m_origin = m_originKey.m_origin;
if(g_gameType == eGameTypeDoom3)
{
rotation_assign(m_rotation, m_rotationKey.m_rotation);
}
else
{
m_angle = m_angleKey.m_angle;
}
}
void freezeTransform()
{
m_originKey.m_origin = m_origin;
m_originKey.write(&m_entity);
if(g_gameType == eGameTypeDoom3)
{
rotation_assign(m_rotationKey.m_rotation, m_rotation);
m_rotationKey.write(&m_entity);
}
else
{
m_angleKey.m_angle = m_angle;
m_angleKey.write(&m_entity);
}
}
void transformChanged()
{
revertTransform();
m_evaluateTransform();
updateTransform();
}
typedef MemberCaller<EclassModel, &EclassModel::transformChanged> TransformChangedCaller;
};
class EclassModelInstance : public TargetableInstance, public TransformModifier, public Renderable
{
class TypeCasts
{
InstanceTypeCastTable m_casts;
public:
TypeCasts()
{
m_casts = TargetableInstance::StaticTypeCasts::instance().get();
InstanceStaticCast<EclassModelInstance, Renderable>::install(m_casts);
InstanceStaticCast<EclassModelInstance, Transformable>::install(m_casts);
InstanceIdentityCast<EclassModelInstance>::install(m_casts);
}
InstanceTypeCastTable& get()
{
return m_casts;
}
};
EclassModel& m_contained;
public:
typedef LazyStatic<TypeCasts> StaticTypeCasts;
STRING_CONSTANT(Name, "EclassModelInstance");
EclassModelInstance(const scene::Path& path, scene::Instance* parent, EclassModel& contained) :
TargetableInstance(path, parent, this, StaticTypeCasts::instance().get(), contained.getEntity(), *this),
TransformModifier(EclassModel::TransformChangedCaller(contained), ApplyTransformCaller(*this)),
m_contained(contained)
{
m_contained.instanceAttach(Instance::path());
StaticRenderableConnectionLines::instance().attach(*this);
}
~EclassModelInstance()
{
StaticRenderableConnectionLines::instance().detach(*this);
m_contained.instanceDetach(Instance::path());
}
void renderSolid(Renderer& renderer, const VolumeTest& volume) const
{
m_contained.renderSolid(renderer, volume, Instance::localToWorld(), getSelectable().isSelected());
}
void renderWireframe(Renderer& renderer, const VolumeTest& volume) const
{
m_contained.renderWireframe(renderer, volume, Instance::localToWorld(), getSelectable().isSelected());
}
void evaluateTransform()
{
if(getType() == TRANSFORM_PRIMITIVE)
{
m_contained.translate(getTranslation());
m_contained.rotate(getRotation());
}
}
void applyTransform()
{
m_contained.revertTransform();
evaluateTransform();
m_contained.freezeTransform();
}
typedef MemberCaller<EclassModelInstance, &EclassModelInstance::applyTransform> ApplyTransformCaller;
};
class EclassModelNode :
public scene::Node::Symbiot,
public scene::Instantiable,
public scene::Cloneable,
public scene::Traversable::Observer
{
class TypeCasts
{
NodeTypeCastTable m_casts;
public:
TypeCasts()
{
NodeStaticCast<EclassModelNode, scene::Instantiable>::install(m_casts);
NodeStaticCast<EclassModelNode, scene::Cloneable>::install(m_casts);
NodeContainedCast<EclassModelNode, scene::Traversable>::install(m_casts);
NodeContainedCast<EclassModelNode, Snappable>::install(m_casts);
NodeContainedCast<EclassModelNode, TransformNode>::install(m_casts);
NodeContainedCast<EclassModelNode, Entity>::install(m_casts);
NodeContainedCast<EclassModelNode, Nameable>::install(m_casts);
NodeContainedCast<EclassModelNode, Namespaced>::install(m_casts);
NodeContainedCast<EclassModelNode, ModelSkin>::install(m_casts);
}
NodeTypeCastTable& get()
{
return m_casts;
}
};
scene::Node m_node;
InstanceSet m_instances;
EclassModel m_contained;
void construct()
{
m_contained.attach(this);
}
void destroy()
{
m_contained.detach(this);
}
public:
typedef LazyStatic<TypeCasts> StaticTypeCasts;
scene::Traversable& get(NullType<scene::Traversable>)
{
return m_contained.getTraversable();
}
Snappable& get(NullType<Snappable>)
{
return m_contained;
}
TransformNode& get(NullType<TransformNode>)
{
return m_contained.getTransformNode();
}
Entity& get(NullType<Entity>)
{
return m_contained.getEntity();
}
Nameable& get(NullType<Nameable>)
{
return m_contained.getNameable();
}
Namespaced& get(NullType<Namespaced>)
{
return m_contained.getNamespaced();
}
ModelSkin& get(NullType<ModelSkin>)
{
return m_contained.getModelSkin();
}
EclassModelNode(EntityClass* eclass) :
m_node(this, this, StaticTypeCasts::instance().get()),
m_contained(eclass, m_node, InstanceSet::TransformChangedCaller(m_instances), InstanceSetEvaluateTransform<EclassModelInstance>::Caller(m_instances))
{
construct();
}
EclassModelNode(const EclassModelNode& other) :
scene::Node::Symbiot(other),
scene::Instantiable(other),
scene::Cloneable(other),
scene::Traversable::Observer(other),
m_node(this, this, StaticTypeCasts::instance().get()),
m_contained(other.m_contained, m_node, InstanceSet::TransformChangedCaller(m_instances), InstanceSetEvaluateTransform<EclassModelInstance>::Caller(m_instances))
{
construct();
}
~EclassModelNode()
{
destroy();
}
void release()
{
delete this;
}
scene::Node& node()
{
return m_node;
}
void insert(scene::Node& child)
{
m_instances.insert(child);
}
void erase(scene::Node& child)
{
m_instances.erase(child);
}
scene::Node& clone() const
{
return (new EclassModelNode(*this))->node();
}
scene::Instance* create(const scene::Path& path, scene::Instance* parent)
{
return new EclassModelInstance(path, parent, m_contained);
}
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);
}
};
scene::Node& New_EclassModel(EntityClass* eclass)
{
return (new EclassModelNode(eclass))->node();
}

View File

@@ -0,0 +1,35 @@
/*
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_ECLASSMODEL_H)
#define INCLUDED_ECLASSMODEL_H
namespace scene
{
class Node;
};
class EntityClass;
scene::Node& New_EclassModel(EntityClass* eclass);
#include "entity.h"
#endif

383
plugins/entity/entity.cpp Normal file
View File

@@ -0,0 +1,383 @@
/*
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 "entity.h"
#include "ifilter.h"
#include "selectable.h"
#include "namespace.h"
#include "scenelib.h"
#include "entitylib.h"
#include "eclasslib.h"
#include "pivot.h"
#include "targetable.h"
#include "uniquenames.h"
#include "namekeys.h"
#include "stream/stringstream.h"
#include "filters.h"
#include "miscmodel.h"
#include "light.h"
#include "group.h"
#include "eclassmodel.h"
#include "generic.h"
#include "doom3group.h"
EGameType g_gameType;
inline scene::Node& entity_for_eclass(EntityClass* eclass)
{
if(classname_equal(eclass->name(), "misc_model")
|| classname_equal(eclass->name(), "misc_gamemodel")
|| classname_equal(eclass->name(), "model_static"))
{
return New_MiscModel(eclass);
}
else if(classname_equal(eclass->name(), "light")
|| classname_equal(eclass->name(), "lightJunior"))
{
return New_Light(eclass);
}
if(!eclass->fixedsize)
{
if(g_gameType == eGameTypeDoom3)
{
return New_Doom3Group(eclass);
}
else
{
return New_Group(eclass);
}
}
else if(!string_empty(eclass->modelpath()))
{
return New_EclassModel(eclass);
}
else
{
return New_GenericEntity(eclass);
}
}
void Entity_setName(Entity& entity, const char* name)
{
entity.setKeyValue("name", name);
}
typedef ReferenceCaller1<Entity, const char*, Entity_setName> EntitySetNameCaller;
inline Namespaced* Node_getNamespaced(scene::Node& node)
{
return NodeTypeCast<Namespaced>::cast(node);
}
inline scene::Node& node_for_eclass(EntityClass* eclass)
{
scene::Node& node = entity_for_eclass(eclass);
Node_getEntity(node)->setKeyValue("classname", eclass->name());
if(g_gameType == eGameTypeDoom3
&& string_not_empty(eclass->name())
&& !string_equal(eclass->name(), "worldspawn")
&& !string_equal(eclass->name(), "UNKNOWN_CLASS"))
{
char buffer[1024];
strcpy(buffer, eclass->name());
strcat(buffer, "_1");
GlobalNamespace().makeUnique(buffer, EntitySetNameCaller(*Node_getEntity(node)));
}
Namespaced* namespaced = Node_getNamespaced(node);
if(namespaced != 0)
{
namespaced->setNamespace(GlobalNamespace());
}
return node;
}
EntityCreator::KeyValueChangedFunc EntityKeyValues::m_entityKeyValueChanged = 0;
EntityCreator::KeyValueChangedFunc KeyValue::m_entityKeyValueChanged = 0;
Counter* EntityKeyValues::m_counter = 0;
bool g_showNames = true;
bool g_showAngles = true;
bool g_newLightDraw = true;
bool g_lightRadii = false;
class ConnectEntities
{
public:
Entity* m_e1;
Entity* m_e2;
ConnectEntities(Entity* e1, Entity* e2) : m_e1(e1), m_e2(e2)
{
}
void connect(const char* name)
{
m_e1->setKeyValue("target", name);
m_e2->setKeyValue("targetname", name);
}
typedef MemberCaller1<ConnectEntities, const char*, &ConnectEntities::connect> ConnectCaller;
};
inline Entity* ScenePath_getEntity(const scene::Path& path)
{
Entity* entity = Node_getEntity(path.top());
if(entity == 0)
{
entity = Node_getEntity(path.parent());
}
return entity;
}
class Quake3EntityCreator : public EntityCreator
{
public:
scene::Node& createEntity(EntityClass* eclass)
{
return node_for_eclass(eclass);
}
void setKeyValueChangedFunc(KeyValueChangedFunc func)
{
EntityKeyValues::setKeyValueChangedFunc(func);
}
void setCounter(Counter* counter)
{
EntityKeyValues::setCounter(counter);
}
void connectEntities(const scene::Path& path, const scene::Path& targetPath)
{
Entity* e1 = ScenePath_getEntity(path);
Entity* e2 = ScenePath_getEntity(targetPath);
if(e1 == 0 || e2 == 0)
{
globalErrorStream() << "entityConnectSelected: both of the selected instances must be an entity\n";
return;
}
if(e1 == e2)
{
globalErrorStream() << "entityConnectSelected: the selected instances must not both be from the same entity\n";
return;
}
UndoableCommand undo("entityConnectSelected");
if(g_gameType == eGameTypeDoom3)
{
StringOutputStream key(16);
for(unsigned int i = 0; ; ++i)
{
key << "target";
if(i != 0)
{
key << i;
}
const char* value = e1->getKeyValue(key.c_str());
if(string_empty(value))
{
e1->setKeyValue(key.c_str(), e2->getKeyValue("name"));
break;
}
key.clear();
}
}
else
{
ConnectEntities connector(e1, e2);
const char* value = e2->getKeyValue("targetname");
if(string_empty(value))
{
value = e1->getKeyValue("target");
}
if(!string_empty(value))
{
connector.connect(value);
}
else
{
const char* type = e2->getKeyValue("classname");
if(string_empty(type))
{
type = "t";
}
StringOutputStream key(64);
key << type << "1";
GlobalNamespace().makeUnique(key.c_str(), ConnectEntities::ConnectCaller(connector));
}
}
SceneChangeNotify();
}
void setLightRadii(bool lightRadii)
{
g_lightRadii = lightRadii;
}
bool getLightRadii()
{
return g_lightRadii;
}
void setShowNames(bool showNames)
{
g_showNames = showNames;
}
bool getShowNames()
{
return g_showNames;
}
void setShowAngles(bool showAngles)
{
g_showAngles = showAngles;
}
bool getShowAngles()
{
return g_showAngles;
}
};
Quake3EntityCreator g_Quake3EntityCreator;
EntityCreator& GetEntityCreator()
{
return g_Quake3EntityCreator;
}
class filter_entity_classname : public EntityFilter
{
const char* m_classname;
public:
filter_entity_classname(const char* classname) : m_classname(classname)
{
}
bool filter(const Entity& entity) const
{
return string_equal(entity.getKeyValue("classname"), m_classname);
}
};
class filter_entity_classgroup : public EntityFilter
{
const char* m_classgroup;
std::size_t m_length;
public:
filter_entity_classgroup(const char* classgroup) : m_classgroup(classgroup), m_length(string_length(m_classgroup))
{
}
bool filter(const Entity& entity) const
{
return string_equal_n(entity.getKeyValue("classname"), m_classgroup, m_length);
}
};
filter_entity_classname g_filter_entity_world("worldspawn");
filter_entity_classname g_filter_entity_func_group("func_group");
filter_entity_classname g_filter_entity_light("light");
filter_entity_classname g_filter_entity_misc_model("misc_model");
filter_entity_classgroup g_filter_entity_trigger("trigger_");
filter_entity_classgroup g_filter_entity_path("path_");
class filter_entity_doom3model : public EntityFilter
{
public:
bool filter(const Entity& entity) const
{
return string_equal(entity.getKeyValue("classname"), "func_static")
&& !string_equal(entity.getKeyValue("model"), entity.getKeyValue("name"));
}
};
filter_entity_doom3model g_filter_entity_doom3model;
void Entity_InitFilters()
{
add_entity_filter(g_filter_entity_world, EXCLUDE_WORLD);
add_entity_filter(g_filter_entity_func_group, EXCLUDE_WORLD);
add_entity_filter(g_filter_entity_world, EXCLUDE_ENT, true);
add_entity_filter(g_filter_entity_trigger, EXCLUDE_TRIGGERS);
add_entity_filter(g_filter_entity_misc_model, EXCLUDE_MODELS);
add_entity_filter(g_filter_entity_doom3model, EXCLUDE_MODELS);
add_entity_filter(g_filter_entity_light, EXCLUDE_LIGHTS);
add_entity_filter(g_filter_entity_path, EXCLUDE_PATHS);
}
#include "preferencesystem.h"
void Entity_Construct(EGameType gameType)
{
g_gameType = gameType;
if(g_gameType == eGameTypeDoom3)
{
g_targetable_nameKey = "name";
Static<KeyIsName>::instance().m_keyIsName = keyIsNameDoom3;
Static<KeyIsName>::instance().m_nameKey = "name";
}
else
{
Static<KeyIsName>::instance().m_keyIsName = keyIsNameQuake3;
Static<KeyIsName>::instance().m_nameKey = "targetname";
}
GlobalPreferenceSystem().registerPreference("SI_ShowNames", BoolImportStringCaller(g_showNames), BoolExportStringCaller(g_showNames));
GlobalPreferenceSystem().registerPreference("SI_ShowAngles", BoolImportStringCaller(g_showAngles), BoolExportStringCaller(g_showAngles));
GlobalPreferenceSystem().registerPreference("NewLightStyle", BoolImportStringCaller(g_newLightDraw), BoolExportStringCaller(g_newLightDraw));
GlobalPreferenceSystem().registerPreference("LightRadiuses", BoolImportStringCaller(g_lightRadii), BoolExportStringCaller(g_lightRadii));
Entity_InitFilters();
LightType lightType = LIGHTTYPE_DEFAULT;
if(g_gameType == eGameTypeRTCW)
{
lightType = LIGHTTYPE_RTCW;
}
else if(g_gameType == eGameTypeDoom3)
{
lightType = LIGHTTYPE_DOOM3;
}
Light_Construct(lightType);
MiscModel_construct();
Doom3Group_construct();
RenderablePivot::StaticShader::instance() = GlobalShaderCache().capture("$PIVOT");
GlobalShaderCache().attachRenderable(StaticRenderableConnectionLines::instance());
}
void Entity_Destroy()
{
GlobalShaderCache().detachRenderable(StaticRenderableConnectionLines::instance());
GlobalShaderCache().release("$PIVOT");
Doom3Group_destroy();
MiscModel_destroy();
Light_Destroy();
}

230
plugins/entity/entity.dsp Normal file
View File

@@ -0,0 +1,230 @@
# Microsoft Developer Studio Project File - Name="entity" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
CFG=entity - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "entity.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "entity.mak" CFG="entity - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "entity - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "entity - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName "entity"
# PROP Scc_LocalPath "..\.."
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "entity - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
F90=df.exe
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MAP_EXPORTS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /O2 /I "..\..\..\libxml2\include\\" /I "..\..\include" /I "..\..\..\gtk2-win32\include\glib-2.0" /I "..\..\..\gtk2-win32\lib\glib-2.0\include" /I "..\common" /I "..\..\libs" /I "..\..\libs\nvtristrip" /I "..\..\..\STLPort\stlport" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MAP_EXPORTS" /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x40c /d "NDEBUG"
# ADD RSC /l 0x40c /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
# ADD LINK32 mathlib.lib glib-2.0.lib /nologo /dll /machine:I386 /def:".\entity.def" /libpath:"..\..\libs\mathlib\release" /libpath:"..\..\..\gtk2-win32\lib\\"
# SUBTRACT LINK32 /pdb:none
# Begin Special Build Tool
SOURCE="$(InputPath)"
PostBuild_Desc=Copy to dir...
PostBuild_Cmds=copy Release\entity.dll "../../install/modules"
# End Special Build Tool
!ELSEIF "$(CFG)" == "entity - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
F90=df.exe
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MAP_EXPORTS" /YX /FD /GZ /c
# ADD CPP /nologo /MDd /W3 /Gm /ZI /Od /I "..\..\shared" /I "..\..\..\libxml2\include" /I "..\..\include" /I "..\..\..\gtk2-win32\include\glib-2.0" /I "..\..\..\gtk2-win32\lib\glib-2.0\include" /I "..\common" /I "..\..\libs" /I "..\..\libs\nvtristrip" /I "..\..\..\STLPort\stlport" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MAP_EXPORTS" /FR /YX /FD /GZ /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x40c /d "_DEBUG"
# ADD RSC /l 0x40c /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
# ADD LINK32 mathlib.lib glib-2.0.lib /nologo /dll /debug /machine:I386 /def:".\entity.def" /pdbtype:sept /libpath:"..\..\libs\mathlib\debug" /libpath:"..\..\..\gtk2-win32\lib\\"
# SUBTRACT LINK32 /pdb:none
# Begin Special Build Tool
SOURCE="$(InputPath)"
PostBuild_Desc=Copy to dir...
PostBuild_Cmds=copy Debug\entity.dll "../../install/modules"
# End Special Build Tool
!ENDIF
# Begin Target
# Name "entity - Win32 Release"
# Name "entity - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\eclassmodel.cpp
# End Source File
# Begin Source File
SOURCE=.\entity.cpp
# End Source File
# Begin Source File
SOURCE=.\entity.def
# PROP Exclude_From_Build 1
# End Source File
# Begin Source File
SOURCE=.\generic.cpp
# End Source File
# Begin Source File
SOURCE=.\group.cpp
# End Source File
# Begin Source File
SOURCE=.\light.cpp
# End Source File
# Begin Source File
SOURCE=.\miscmodel.cpp
# End Source File
# Begin Source File
SOURCE=.\plugin.cpp
# End Source File
# Begin Source File
SOURCE=.\targetable.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Group "API"
# PROP Default_Filter ""
# Begin Source File
SOURCE=..\..\include\ifilesystem.h
# End Source File
# Begin Source File
SOURCE=..\..\include\igl.h
# End Source File
# Begin Source File
SOURCE=..\..\include\imodel.h
# End Source File
# Begin Source File
SOURCE=..\..\include\ishaders.h
# End Source File
# Begin Source File
SOURCE=..\..\include\isurface.h
# End Source File
# Begin Source File
SOURCE=..\..\include\qerplugin.h
# End Source File
# Begin Source File
SOURCE=..\..\include\qertypes.h
# End Source File
# End Group
# Begin Source File
SOURCE=.\angle.h
# End Source File
# Begin Source File
SOURCE=.\angles.h
# End Source File
# Begin Source File
SOURCE=.\colour.h
# End Source File
# Begin Source File
SOURCE=.\entity.h
# End Source File
# Begin Source File
SOURCE=.\light.h
# End Source File
# Begin Source File
SOURCE=.\model.h
# End Source File
# Begin Source File
SOURCE=.\origin.h
# End Source File
# Begin Source File
SOURCE=.\plugin.h
# End Source File
# Begin Source File
SOURCE=.\scale.h
# End Source File
# Begin Source File
SOURCE=.\targetable.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# Begin Source File
SOURCE=.\Conscript
# End Source File
# End Target
# End Project

46
plugins/entity/entity.h Normal file
View File

@@ -0,0 +1,46 @@
/*
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_ENTITY_H)
#define INCLUDED_ENTITY_H
class EntityCreator;
EntityCreator& GetEntityCreator();
enum EGameType
{
eGameTypeQuake3,
eGameTypeRTCW,
eGameTypeDoom3,
};
extern EGameType g_gameType;
class FilterSystem;
void Entity_Construct(EGameType gameType = eGameTypeQuake3);
void Entity_Destroy();
extern bool g_showNames;
extern bool g_showAngles;
extern bool g_newLightDraw;
extern bool g_lightRadii;
#endif

View File

@@ -0,0 +1,7 @@
; entityq3.def : Declares the module parameters for the DLL.
LIBRARY "ENTITYQ3"
EXPORTS
; Explicit exports can go here
Radiant_RegisterModules @1

View File

@@ -0,0 +1,343 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="entityq3"
ProjectGUID="{49C5823A-5E50-4029-ACEE-1627EBB79E47}"
RootNamespace="entityq3"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../../include;../../libs;&quot;../../../STLPort-4.6/stlport&quot;"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;ENTITYQ3_EXPORTS"
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"
OutputFile="$(OutDir)/entityq3.dll"
LinkIncremental="1"
IgnoreDefaultLibraryNames="msvcprtd.lib"
ModuleDefinitionFile="$(ProjectName).def"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/entityq3.pdb"
SubSystem="2"
ImportLibrary="$(OutDir)/entityq3.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"
CommandLine="copy &quot;$(TargetPath)&quot; &quot;$(SolutionDir)install\modules&quot;
copy &quot;$(TargetDir)$(TargetName).pdb&quot; &quot;$(SolutionDir)install\modules&quot;
"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<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="2"
CharacterSet="2"
WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
GlobalOptimizations="TRUE"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="TRUE"
FavorSizeOrSpeed="1"
OptimizeForWindowsApplication="FALSE"
AdditionalIncludeDirectories="../../include;../../libs;&quot;../../../STLPort-4.6/stlport&quot;"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;ENTITYQ3_EXPORTS"
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"
OutputFile="$(OutDir)/entityq3.dll"
LinkIncremental="1"
IgnoreDefaultLibraryNames="msvcprt.lib"
ModuleDefinitionFile="$(ProjectName).def"
GenerateDebugInformation="TRUE"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
ImportLibrary="$(OutDir)/entityq3.lib"
TargetMachine="1"
FixedBaseAddress="0"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"
CommandLine="copy &quot;$(TargetPath)&quot; &quot;$(SolutionDir)install\modules&quot;
copy &quot;$(TargetDir)$(TargetName).pdb&quot; &quot;$(SolutionDir)install\modules&quot;
"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="src"
Filter="">
<File
RelativePath=".\plugin.cpp">
</File>
<File
RelativePath=".\plugin.h">
</File>
<Filter
Name="entities"
Filter="">
<File
RelativePath=".\doom3group.cpp">
</File>
<File
RelativePath=".\doom3group.h">
</File>
<File
RelativePath=".\eclassmodel.cpp">
</File>
<File
RelativePath=".\eclassmodel.h">
</File>
<File
RelativePath=".\generic.cpp">
</File>
<File
RelativePath=".\generic.h">
</File>
<File
RelativePath=".\group.cpp">
</File>
<File
RelativePath=".\group.h">
</File>
<File
RelativePath=".\light.cpp">
</File>
<File
RelativePath=".\light.h">
</File>
<File
RelativePath=".\miscmodel.cpp">
</File>
<File
RelativePath=".\miscmodel.h">
</File>
</Filter>
<Filter
Name="modules"
Filter="">
<File
RelativePath=".\entity.cpp">
</File>
<File
RelativePath=".\entity.h">
</File>
<File
RelativePath=".\skincache.cpp">
</File>
<File
RelativePath=".\skincache.h">
</File>
</Filter>
<Filter
Name="components"
Filter="">
<File
RelativePath=".\angle.cpp">
</File>
<File
RelativePath=".\angle.h">
</File>
<File
RelativePath=".\angles.cpp">
</File>
<File
RelativePath=".\angles.h">
</File>
<File
RelativePath=".\colour.cpp">
</File>
<File
RelativePath=".\colour.h">
</File>
<File
RelativePath=".\curve.cpp">
</File>
<File
RelativePath=".\curve.h">
</File>
<File
RelativePath=".\filters.cpp">
</File>
<File
RelativePath=".\filters.h">
</File>
<File
RelativePath=".\keyobservers.cpp">
</File>
<File
RelativePath=".\keyobservers.h">
</File>
<File
RelativePath=".\model.cpp">
</File>
<File
RelativePath=".\model.h">
</File>
<File
RelativePath=".\modelskinkey.cpp">
</File>
<File
RelativePath=".\modelskinkey.h">
</File>
<File
RelativePath=".\namedentity.cpp">
</File>
<File
RelativePath=".\namedentity.h">
</File>
<File
RelativePath=".\namekeys.cpp">
</File>
<File
RelativePath=".\namekeys.h">
</File>
<File
RelativePath=".\origin.cpp">
</File>
<File
RelativePath=".\origin.h">
</File>
<File
RelativePath=".\rotation.cpp">
</File>
<File
RelativePath=".\rotation.h">
</File>
<File
RelativePath=".\scale.cpp">
</File>
<File
RelativePath=".\scale.h">
</File>
<File
RelativePath=".\targetable.cpp">
</File>
<File
RelativePath=".\targetable.h">
</File>
</Filter>
</Filter>
<File
RelativePath="..\..\debug.py">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCustomBuildTool"
CommandLine="python &quot;$(SolutionDir)debug.py&quot;
"
AdditionalDependencies="&quot;$(SolutionDir)install\modules\$(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\modules\$(TargetName).pdb&quot;"
Outputs="&quot;$(TargetDir)$(TargetName).pdb&quot;"/>
</FileConfiguration>
</File>
<File
RelativePath=".\entityq3.def">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCustomBuildTool"
CommandLine="python &quot;$(SolutionDir)touch.py&quot; &quot;$(TargetPath)&quot;
"
AdditionalDependencies="&quot;$(SolutionDir)install\modules\$(TargetFileName)&quot;"
Outputs="&quot;$(TargetPath)&quot;"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCustomBuildTool"
CommandLine="python &quot;$(SolutionDir)touch.py&quot; &quot;$(TargetPath)&quot;
"
AdditionalDependencies="&quot;$(SolutionDir)install\modules\$(TargetFileName)&quot;"
Outputs="&quot;$(TargetPath)&quot;"/>
</FileConfiguration>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@@ -0,0 +1,72 @@
/*
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 "ifilter.h"
#include <list>
class EntityFilterWrapper : public Filter
{
bool m_active;
bool m_invert;
EntityFilter& m_filter;
public:
EntityFilterWrapper(EntityFilter& filter, bool invert) : m_invert(invert), m_filter(filter)
{
}
void setActive(bool active)
{
m_active = active;
}
bool active()
{
return m_active;
}
bool filter(const Entity& entity)
{
return m_invert ^ m_filter.filter(entity);
}
};
typedef std::list<EntityFilterWrapper> EntityFilters;
EntityFilters g_entityFilters;
void add_entity_filter(EntityFilter& filter, int mask, bool invert)
{
g_entityFilters.push_back(EntityFilterWrapper(filter, invert));
GlobalFilterSystem().addFilter(g_entityFilters.back(), mask);
}
bool entity_filtered(Entity& entity)
{
for(EntityFilters::iterator i = g_entityFilters.begin(); i != g_entityFilters.end(); ++i)
{
if((*i).active() && (*i).filter(entity))
{
return true;
}
}
return false;
}

82
plugins/entity/filters.h Normal file
View File

@@ -0,0 +1,82 @@
/*
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
#include "ifilter.h"
#include "generic/callback.h"
#include "scenelib.h"
class Entity;
class EntityFilter
{
public:
virtual bool filter(const Entity& entity) const = 0;
};
bool entity_filtered(Entity& entity);
void add_entity_filter(EntityFilter& filter, int mask, bool invert = false);
class ClassnameFilter : public Filterable
{
scene::Node& m_node;
public:
Entity& m_entity;
ClassnameFilter(Entity& entity, scene::Node& node) : m_node(node), m_entity(entity)
{
}
~ClassnameFilter()
{
}
void instanceAttach()
{
GlobalFilterSystem().registerFilterable(*this);
}
void instanceDetach()
{
GlobalFilterSystem().unregisterFilterable(*this);
}
void updateFiltered()
{
if(entity_filtered(m_entity))
{
m_node.enable(scene::Node::eFiltered);
}
else
{
m_node.disable(scene::Node::eFiltered);
}
}
void classnameChanged(const char* value)
{
updateFiltered();
}
typedef MemberCaller1<ClassnameFilter, const char*, &ClassnameFilter::classnameChanged> ClassnameChangedCaller;
};
#endif

494
plugins/entity/generic.cpp Normal file
View File

@@ -0,0 +1,494 @@
/*
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
*/
///\file
///\brief Represents any entity which has a fixed size specified in its entity-definition and does not display a model (e.g. info_player_start).
///
/// This entity displays an axis-aligned bounding box of the size and colour specified in its entity-definition.
/// The "origin" key directly controls the entity's local-to-parent transform.
/// An arrow is drawn to visualise the "angle" key.
#include "cullable.h"
#include "renderable.h"
#include "editable.h"
#include "math/frustum.h"
#include "selectionlib.h"
#include "instancelib.h"
#include "transformlib.h"
#include "entitylib.h"
#include "render.h"
#include "eclasslib.h"
#include "math/line.h"
#include "targetable.h"
#include "origin.h"
#include "angle.h"
#include "filters.h"
#include "namedentity.h"
#include "keyobservers.h"
#include "namekeys.h"
#include "rotation.h"
#include "entity.h"
class RenderableArrow : public OpenGLRenderable
{
const Ray& m_ray;
public:
RenderableArrow(const Ray& ray)
: m_ray(ray)
{
}
void render(RenderStateFlags state) const
{
arrow_draw(m_ray.origin, m_ray.direction);
}
};
inline void read_aabb(AABB& aabb, const EntityClass& eclass)
{
aabb = aabb_for_minmax(eclass.mins, eclass.maxs);
}
class GenericEntity :
public Cullable,
public Bounded,
public Snappable
{
EntityKeyValues m_entity;
KeyObserverMap m_keyObservers;
MatrixTransform m_transform;
OriginKey m_originKey;
Vector3 m_origin;
AngleKey m_angleKey;
float m_angle;
ClassnameFilter m_filter;
NamedEntity m_named;
NameKeys m_nameKeys;
AABB m_aabb_local;
Ray m_ray;
RenderableArrow m_arrow;
RenderableSolidAABB m_aabb_solid;
RenderableWireframeAABB m_aabb_wire;
RenderableNamedEntity m_renderName;
Callback m_transformChanged;
Callback m_evaluateTransform;
void construct()
{
read_aabb(m_aabb_local, m_entity.getEntityClass());
m_ray.origin = m_aabb_local.origin;
m_ray.direction[0] = 1;
m_ray.direction[1] = 0;
m_ray.direction[2] = 0;
m_keyObservers.insert("classname", ClassnameFilter::ClassnameChangedCaller(m_filter));
m_keyObservers.insert(Static<KeyIsName>::instance().m_nameKey, NamedEntity::IdentifierChangedCaller(m_named));
m_keyObservers.insert("angle", AngleKey::AngleChangedCaller(m_angleKey));
m_keyObservers.insert("origin", OriginKey::OriginChangedCaller(m_originKey));
}
void updateTransform()
{
m_transform.localToParent() = g_matrix4_identity;
matrix4_translate_by_vec3(m_transform.localToParent(), m_origin);
m_ray.direction = matrix4_transformed_direction(matrix4_rotation_for_z(degrees_to_radians(m_angle)), Vector3(1, 0, 0));
m_transformChanged();
}
typedef MemberCaller<GenericEntity, &GenericEntity::updateTransform> UpdateTransformCaller;
void originChanged()
{
m_origin = m_originKey.m_origin;
updateTransform();
}
typedef MemberCaller<GenericEntity, &GenericEntity::originChanged> OriginChangedCaller;
void angleChanged()
{
m_angle = m_angleKey.m_angle;
updateTransform();
}
typedef MemberCaller<GenericEntity, &GenericEntity::angleChanged> AngleChangedCaller;
public:
GenericEntity(EntityClass* eclass, scene::Node& node, const Callback& transformChanged, const Callback& evaluateTransform) :
m_entity(eclass),
m_originKey(OriginChangedCaller(*this)),
m_origin(ORIGINKEY_IDENTITY),
m_angleKey(AngleChangedCaller(*this)),
m_angle(ANGLEKEY_IDENTITY),
m_filter(m_entity, node),
m_named(m_entity),
m_nameKeys(m_entity),
m_arrow(m_ray),
m_aabb_solid(m_aabb_local),
m_aabb_wire(m_aabb_local),
m_renderName(m_named, g_vector3_identity),
m_transformChanged(transformChanged),
m_evaluateTransform(evaluateTransform)
{
construct();
}
GenericEntity(const GenericEntity& other, scene::Node& node, const Callback& transformChanged, const Callback& evaluateTransform) :
m_entity(other.m_entity),
m_originKey(OriginChangedCaller(*this)),
m_origin(ORIGINKEY_IDENTITY),
m_angleKey(AngleChangedCaller(*this)),
m_angle(ANGLEKEY_IDENTITY),
m_filter(m_entity, node),
m_named(m_entity),
m_nameKeys(m_entity),
m_arrow(m_ray),
m_aabb_solid(m_aabb_local),
m_aabb_wire(m_aabb_local),
m_renderName(m_named, g_vector3_identity),
m_transformChanged(transformChanged),
m_evaluateTransform(evaluateTransform)
{
construct();
}
InstanceCounter m_instanceCounter;
void instanceAttach(const scene::Path& path)
{
if(++m_instanceCounter.m_count == 1)
{
m_filter.instanceAttach();
m_entity.instanceAttach(path_find_mapfile(path.begin(), path.end()));
m_entity.attach(m_keyObservers);
}
}
void instanceDetach(const scene::Path& path)
{
if(--m_instanceCounter.m_count == 0)
{
m_entity.detach(m_keyObservers);
m_entity.instanceDetach(path_find_mapfile(path.begin(), path.end()));
m_filter.instanceDetach();
}
}
EntityKeyValues& getEntity()
{
return m_entity;
}
const EntityKeyValues& getEntity() const
{
return m_entity;
}
Namespaced& getNamespaced()
{
return m_nameKeys;
}
Nameable& getNameable()
{
return m_named;
}
TransformNode& getTransformNode()
{
return m_transform;
}
const AABB& localAABB() const
{
return m_aabb_local;
}
VolumeIntersectionValue intersectVolume(const VolumeTest& volume, const Matrix4& localToWorld) const
{
return volume.TestAABB(localAABB(), localToWorld);
}
void renderArrow(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
{
if(g_showAngles)
{
renderer.addRenderable(m_arrow, localToWorld);
}
}
void renderSolid(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
{
renderer.SetState(m_entity.getEntityClass().m_state_fill, Renderer::eFullMaterials);
renderer.addRenderable(m_aabb_solid, localToWorld);
renderArrow(renderer, volume, localToWorld);
}
void renderWireframe(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
{
renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly);
renderer.addRenderable(m_aabb_wire, localToWorld);
renderArrow(renderer, volume, localToWorld);
if(g_showNames)
{
renderer.addRenderable(m_renderName, 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);
}
}
void translate(const Vector3& translation)
{
m_origin = origin_translated(m_origin, translation);
}
void rotate(const Quaternion& rotation)
{
m_angle = angle_rotated(m_angle, rotation);
}
void snapto(float snap)
{
m_originKey.m_origin = origin_snapped(m_originKey.m_origin, snap);
m_originKey.write(&m_entity);
}
void revertTransform()
{
m_origin = m_originKey.m_origin;
m_angle = m_angleKey.m_angle;
}
void freezeTransform()
{
m_originKey.m_origin = m_origin;
m_originKey.write(&m_entity);
m_angleKey.m_angle = m_angle;
m_angleKey.write(&m_entity);
}
void transformChanged()
{
revertTransform();
m_evaluateTransform();
updateTransform();
}
typedef MemberCaller<GenericEntity, &GenericEntity::transformChanged> TransformChangedCaller;
};
class GenericEntityInstance :
public TargetableInstance,
public TransformModifier,
public Renderable,
public SelectionTestable
{
class TypeCasts
{
InstanceTypeCastTable m_casts;
public:
TypeCasts()
{
m_casts = TargetableInstance::StaticTypeCasts::instance().get();
InstanceContainedCast<GenericEntityInstance, Bounded>::install(m_casts);
InstanceContainedCast<GenericEntityInstance, Cullable>::install(m_casts);
InstanceStaticCast<GenericEntityInstance, Renderable>::install(m_casts);
InstanceStaticCast<GenericEntityInstance, SelectionTestable>::install(m_casts);
InstanceStaticCast<GenericEntityInstance, Transformable>::install(m_casts);
InstanceIdentityCast<GenericEntityInstance>::install(m_casts);
}
InstanceTypeCastTable& get()
{
return m_casts;
}
};
GenericEntity& m_contained;
mutable AABB m_bounds;
public:
typedef LazyStatic<TypeCasts> StaticTypeCasts;
Bounded& get(NullType<Bounded>)
{
return m_contained;
}
Cullable& get(NullType<Cullable>)
{
return m_contained;
}
STRING_CONSTANT(Name, "GenericEntityInstance");
GenericEntityInstance(const scene::Path& path, scene::Instance* parent, GenericEntity& contained) :
TargetableInstance(path, parent, this, StaticTypeCasts::instance().get(), contained.getEntity(), *this),
TransformModifier(GenericEntity::TransformChangedCaller(contained), ApplyTransformCaller(*this)),
m_contained(contained)
{
m_contained.instanceAttach(Instance::path());
StaticRenderableConnectionLines::instance().attach(*this);
}
~GenericEntityInstance()
{
StaticRenderableConnectionLines::instance().detach(*this);
m_contained.instanceDetach(Instance::path());
}
void renderSolid(Renderer& renderer, const VolumeTest& volume) const
{
m_contained.renderSolid(renderer, volume, Instance::localToWorld());
}
void renderWireframe(Renderer& renderer, const VolumeTest& volume) const
{
m_contained.renderWireframe(renderer, volume, Instance::localToWorld());
}
void testSelect(Selector& selector, SelectionTest& test)
{
m_contained.testSelect(selector, test, Instance::localToWorld());
}
void evaluateTransform()
{
if(getType() == TRANSFORM_PRIMITIVE)
{
m_contained.translate(getTranslation());
m_contained.rotate(getRotation());
}
}
void applyTransform()
{
m_contained.revertTransform();
evaluateTransform();
m_contained.freezeTransform();
}
typedef MemberCaller<GenericEntityInstance, &GenericEntityInstance::applyTransform> ApplyTransformCaller;
};
class GenericEntityNode :
public scene::Node::Symbiot,
public scene::Instantiable,
public scene::Cloneable
{
class TypeCasts
{
NodeTypeCastTable m_casts;
public:
TypeCasts()
{
NodeStaticCast<GenericEntityNode, scene::Instantiable>::install(m_casts);
NodeStaticCast<GenericEntityNode, scene::Cloneable>::install(m_casts);
NodeContainedCast<GenericEntityNode, Snappable>::install(m_casts);
NodeContainedCast<GenericEntityNode, TransformNode>::install(m_casts);
NodeContainedCast<GenericEntityNode, Entity>::install(m_casts);
NodeContainedCast<GenericEntityNode, Nameable>::install(m_casts);
NodeContainedCast<GenericEntityNode, Namespaced>::install(m_casts);
}
NodeTypeCastTable& get()
{
return m_casts;
}
};
InstanceSet m_instances;
scene::Node m_node;
GenericEntity m_contained;
public:
typedef LazyStatic<TypeCasts> StaticTypeCasts;
Snappable& get(NullType<Snappable>)
{
return m_contained;
}
TransformNode& get(NullType<TransformNode>)
{
return m_contained.getTransformNode();
}
Entity& get(NullType<Entity>)
{
return m_contained.getEntity();
}
Nameable& get(NullType<Nameable>)
{
return m_contained.getNameable();
}
Namespaced& get(NullType<Namespaced>)
{
return m_contained.getNamespaced();
}
GenericEntityNode(EntityClass* eclass) :
m_node(this, this, StaticTypeCasts::instance().get()),
m_contained(eclass, m_node, InstanceSet::TransformChangedCaller(m_instances), InstanceSetEvaluateTransform<GenericEntityInstance>::Caller(m_instances))
{
}
GenericEntityNode(const GenericEntityNode& other) :
scene::Node::Symbiot(other),
scene::Instantiable(other),
scene::Cloneable(other),
m_node(this, this, StaticTypeCasts::instance().get()),
m_contained(other.m_contained, m_node, InstanceSet::TransformChangedCaller(m_instances), InstanceSetEvaluateTransform<GenericEntityInstance>::Caller(m_instances))
{
}
void release()
{
delete this;
}
scene::Node& node()
{
return m_node;
}
scene::Node& clone() const
{
return (new GenericEntityNode(*this))->node();
}
scene::Instance* create(const scene::Path& path, scene::Instance* parent)
{
return new GenericEntityInstance(path, parent, m_contained);
}
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);
}
};
scene::Node& New_GenericEntity(EntityClass* eclass)
{
return (new GenericEntityNode(eclass))->node();
}

27
plugins/entity/generic.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_GENERIC_H)
#define INCLUDED_GENERIC_H
scene::Node& New_GenericEntity(EntityClass* eclass);
#endif

444
plugins/entity/group.cpp Normal file
View File

@@ -0,0 +1,444 @@
/*
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
*/
///\file
///\brief Represents any entity which does not have a fixed size specified in its entity-definition (except misc_model).
///
/// This entity behaves as a group, i.e. it contains brushes.
#include "cullable.h"
#include "renderable.h"
#include "editable.h"
#include "selectionlib.h"
#include "instancelib.h"
#include "transformlib.h"
#include "traverselib.h"
#include "entitylib.h"
#include "render.h"
#include "eclasslib.h"
#include "targetable.h"
#include "origin.h"
#include "angles.h"
#include "scale.h"
#include "filters.h"
#include "namedentity.h"
#include "keyobservers.h"
#include "namekeys.h"
#include "entity.h"
class Group
{
EntityKeyValues m_entity;
KeyObserverMap m_keyObservers;
MatrixTransform m_transform;
TraversableNodeSet m_traverse;
ClassnameFilter m_filter;
NamedEntity m_named;
NameKeys m_nameKeys;
RenderableNamedEntity m_renderName;
Callback m_transformChanged;
void construct()
{
m_keyObservers.insert("classname", ClassnameFilter::ClassnameChangedCaller(m_filter));
m_keyObservers.insert(Static<KeyIsName>::instance().m_nameKey, NamedEntity::IdentifierChangedCaller(m_named));
}
public:
Group(EntityClass* eclass, scene::Node& node, const Callback& transformChanged) :
m_entity(eclass),
m_filter(m_entity, node),
m_named(m_entity),
m_nameKeys(m_entity),
m_renderName(m_named, g_vector3_identity),
m_transformChanged(transformChanged)
{
construct();
}
Group(const Group& other, scene::Node& node, const Callback& transformChanged) :
m_entity(other.m_entity),
m_filter(m_entity, node),
m_named(m_entity),
m_nameKeys(m_entity),
m_renderName(m_named, g_vector3_identity),
m_transformChanged(transformChanged)
{
construct();
}
InstanceCounter m_instanceCounter;
void instanceAttach(const scene::Path& path)
{
if(++m_instanceCounter.m_count == 1)
{
m_filter.instanceAttach();
m_entity.instanceAttach(path_find_mapfile(path.begin(), path.end()));
m_traverse.instanceAttach(path_find_mapfile(path.begin(), path.end()));
m_entity.attach(m_keyObservers);
}
}
void instanceDetach(const scene::Path& path)
{
if(--m_instanceCounter.m_count == 0)
{
m_entity.detach(m_keyObservers);
m_traverse.instanceDetach(path_find_mapfile(path.begin(), path.end()));
m_entity.instanceDetach(path_find_mapfile(path.begin(), path.end()));
m_filter.instanceDetach();
}
}
EntityKeyValues& getEntity()
{
return m_entity;
}
const EntityKeyValues& getEntity() const
{
return m_entity;
}
scene::Traversable& getTraversable()
{
return m_traverse;
}
Namespaced& getNamespaced()
{
return m_nameKeys;
}
Nameable& getNameable()
{
return m_named;
}
TransformNode& getTransformNode()
{
return m_transform;
}
void attach(scene::Traversable::Observer* observer)
{
m_traverse.attach(observer);
}
void detach(scene::Traversable::Observer* observer)
{
m_traverse.detach(observer);
}
void renderSolid(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
{
renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly);
}
void renderWireframe(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
{
renderSolid(renderer, volume, localToWorld);
#if 0
if(g_showNames)
{
renderer.addRenderable(m_renderName, g_matrix4_identity);
}
#endif
}
};
#if 0
class TransformableSetTranslation
{
Translation m_value;
public:
TransformableSetTranslation(const Translation& value) : m_value(value)
{
}
void operator()(Transformable& transformable) const
{
transformable.setTranslation(m_value);
}
};
class TransformableSetRotation
{
Rotation m_value;
public:
TransformableSetRotation(const Rotation& value) : m_value(value)
{
}
void operator()(Transformable& transformable) const
{
transformable.setRotation(m_value);
}
};
class TransformableSetScale
{
Scale m_value;
public:
TransformableSetScale(const Scale& value) : m_value(value)
{
}
void operator()(Transformable& transformable) const
{
transformable.setScale(m_value);
}
};
class TransformableSetType
{
TransformModifierType m_value;
public:
TransformableSetType(const TransformModifierType& value) : m_value(value)
{
}
void operator()(Transformable& transformable) const
{
transformable.setType(m_value);
}
};
class TransformableFreezeTransform
{
TransformModifierType m_value;
public:
void operator()(Transformable& transformable) const
{
transformable.freezeTransform();
}
};
template<typename Functor>
inline void Scene_forEachChildTransformable(const Functor& functor, const scene::Path& path)
{
GlobalSceneGraph().traverse_subgraph(ChildInstanceWalker< InstanceApply<Transformable, Functor> >(functor), path);
}
#endif
class GroupInstance :
public TargetableInstance,
#if 0
public Transformable,
#endif
public Renderable
{
class TypeCasts
{
InstanceTypeCastTable m_casts;
public:
TypeCasts()
{
m_casts = TargetableInstance::StaticTypeCasts::instance().get();
InstanceStaticCast<GroupInstance, Renderable>::install(m_casts);
#if 0
InstanceStaticCast<GroupInstance, Transformable>::install(m_casts);
#endif
}
InstanceTypeCastTable& get()
{
return m_casts;
}
};
Group& m_contained;
public:
typedef LazyStatic<TypeCasts> StaticTypeCasts;
GroupInstance(const scene::Path& path, scene::Instance* parent, Group& group) :
TargetableInstance(path, parent, this, StaticTypeCasts::instance().get(), group.getEntity(), *this),
m_contained(group)
{
m_contained.instanceAttach(Instance::path());
StaticRenderableConnectionLines::instance().attach(*this);
}
~GroupInstance()
{
StaticRenderableConnectionLines::instance().detach(*this);
m_contained.instanceDetach(Instance::path());
}
void renderSolid(Renderer& renderer, const VolumeTest& volume) const
{
m_contained.renderSolid(renderer, volume, Instance::localToWorld());
}
void renderWireframe(Renderer& renderer, const VolumeTest& volume) const
{
m_contained.renderWireframe(renderer, volume, Instance::localToWorld());
}
#if 0
void setType(TransformModifierType type)
{
Scene_forEachChildTransformable(TransformableSetType(type), Instance::path());
}
void setTranslation(const Translation& value)
{
Scene_forEachChildTransformable(TransformableSetTranslation(value), Instance::path());
}
void setRotation(const Rotation& value)
{
Scene_forEachChildTransformable(TransformableSetRotation(value), Instance::path());
}
void setScale(const Scale& value)
{
Scene_forEachChildTransformable(TransformableSetScale(value), Instance::path());
}
void freezeTransform()
{
Scene_forEachChildTransformable(TransformableFreezeTransform(), Instance::path());
}
void evaluateTransform()
{
}
#endif
};
class GroupNode :
public scene::Node::Symbiot,
public scene::Instantiable,
public scene::Cloneable,
public scene::Traversable::Observer
{
class TypeCasts
{
NodeTypeCastTable m_casts;
public:
TypeCasts()
{
NodeStaticCast<GroupNode, scene::Instantiable>::install(m_casts);
NodeStaticCast<GroupNode, scene::Cloneable>::install(m_casts);
NodeContainedCast<GroupNode, scene::Traversable>::install(m_casts);
NodeContainedCast<GroupNode, TransformNode>::install(m_casts);
NodeContainedCast<GroupNode, Entity>::install(m_casts);
NodeContainedCast<GroupNode, Nameable>::install(m_casts);
NodeContainedCast<GroupNode, Namespaced>::install(m_casts);
}
NodeTypeCastTable& get()
{
return m_casts;
}
};
scene::Node m_node;
InstanceSet m_instances;
Group m_contained;
void construct()
{
m_contained.attach(this);
}
void destroy()
{
m_contained.detach(this);
}
public:
typedef LazyStatic<TypeCasts> StaticTypeCasts;
scene::Traversable& get(NullType<scene::Traversable>)
{
return m_contained.getTraversable();
}
TransformNode& get(NullType<TransformNode>)
{
return m_contained.getTransformNode();
}
Entity& get(NullType<Entity>)
{
return m_contained.getEntity();
}
Nameable& get(NullType<Nameable>)
{
return m_contained.getNameable();
}
Namespaced& get(NullType<Namespaced>)
{
return m_contained.getNamespaced();
}
GroupNode(EntityClass* eclass) :
m_node(this, this, StaticTypeCasts::instance().get()),
m_contained(eclass, m_node, InstanceSet::TransformChangedCaller(m_instances))
{
construct();
}
GroupNode(const GroupNode& other) :
scene::Node::Symbiot(other),
scene::Instantiable(other),
scene::Cloneable(other),
scene::Traversable::Observer(other),
m_node(this, this, StaticTypeCasts::instance().get()),
m_contained(other.m_contained, m_node, InstanceSet::TransformChangedCaller(m_instances))
{
construct();
}
~GroupNode()
{
destroy();
}
void release()
{
delete this;
}
scene::Node& node()
{
return m_node;
}
scene::Node& clone() const
{
return (new GroupNode(*this))->node();
}
void insert(scene::Node& child)
{
m_instances.insert(child);
}
void erase(scene::Node& child)
{
m_instances.erase(child);
}
scene::Instance* create(const scene::Path& path, scene::Instance* parent)
{
return new GroupInstance(path, parent, m_contained);
}
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);
}
};
scene::Node& New_Group(EntityClass* eclass)
{
return (new GroupNode(eclass))->node();
}

27
plugins/entity/group.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_GROUP_H)
#define INCLUDED_GROUP_H
scene::Node& New_Group(EntityClass* eclass);
#endif

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 "keyobservers.h"

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_KEYOBSERVERS_H)
#define INCLUDED_KEYOBSERVERS_H
#include "entitylib.h"
#include <map>
class KeyObserverMap : public EntityKeyValues::Observer
{
typedef std::multimap<const char*, KeyObserver, RawStringLess> KeyObservers;
KeyObservers m_keyObservers;
public:
void insert(const char* key, const KeyObserver& observer)
{
m_keyObservers.insert(KeyObservers::value_type(key, observer));
}
void insert(const char* key, EntityKeyValues::Value& value)
{
for(KeyObservers::const_iterator i = m_keyObservers.find(key); i != m_keyObservers.end() && string_equal((*i).first, key); ++i)
{
value.attach((*i).second);
}
}
void erase(const char* key, EntityKeyValues::Value& value)
{
for(KeyObservers::const_iterator i = m_keyObservers.find(key); i != m_keyObservers.end() && string_equal((*i).first, key); ++i)
{
value.detach((*i).second);
}
}
};
#endif

1839
plugins/entity/light.cpp Normal file

File diff suppressed because it is too large Load Diff

41
plugins/entity/light.h Normal file
View File

@@ -0,0 +1,41 @@
/*
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_LIGHT_H)
#define INCLUDED_LIGHT_H
namespace scene
{
class Node;
};
class EntityClass;
scene::Node& New_Light(EntityClass* eclass);
enum LightType
{
LIGHTTYPE_DEFAULT,
LIGHTTYPE_RTCW,
LIGHTTYPE_DOOM3
};
void Light_Construct(LightType lightType);
void Light_Destroy();
#endif

View File

@@ -0,0 +1,470 @@
/*
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
*/
///\file
///\brief Represents the Quake3 misc_model entity.
///
/// This entity displays the model specified in its "model" key.
/// The "origin", "angles" and "modelscale*" keys directly control the entity's local-to-parent transform.
#include "cullable.h"
#include "renderable.h"
#include "editable.h"
#include "selectionlib.h"
#include "instancelib.h"
#include "transformlib.h"
#include "traverselib.h"
#include "entitylib.h"
#include "eclasslib.h"
#include "render.h"
#include "pivot.h"
#include "targetable.h"
#include "origin.h"
#include "angles.h"
#include "scale.h"
#include "model.h"
#include "filters.h"
#include "namedentity.h"
#include "keyobservers.h"
#include "namekeys.h"
#include "entity.h"
class MiscModel :
public Snappable
{
EntityKeyValues m_entity;
KeyObserverMap m_keyObservers;
MatrixTransform m_transform;
OriginKey m_originKey;
Vector3 m_origin;
AnglesKey m_anglesKey;
Vector3 m_angles;
ScaleKey m_scaleKey;
Vector3 m_scale;
SingletonModel m_model;
ClassnameFilter m_filter;
NamedEntity m_named;
NameKeys m_nameKeys;
RenderablePivot m_renderOrigin;
RenderableNamedEntity m_renderName;
Callback m_transformChanged;
Callback m_evaluateTransform;
void construct()
{
m_keyObservers.insert("classname", ClassnameFilter::ClassnameChangedCaller(m_filter));
m_keyObservers.insert(Static<KeyIsName>::instance().m_nameKey, NamedEntity::IdentifierChangedCaller(m_named));
m_keyObservers.insert("model", SingletonModel::ModelChangedCaller(m_model));
m_keyObservers.insert("origin", OriginKey::OriginChangedCaller(m_originKey));
m_keyObservers.insert("angle", AnglesKey::AngleChangedCaller(m_anglesKey));
m_keyObservers.insert("angles", AnglesKey::AnglesChangedCaller(m_anglesKey));
m_keyObservers.insert("modelscale", ScaleKey::UniformScaleChangedCaller(m_scaleKey));
m_keyObservers.insert("modelscale_vec", ScaleKey::ScaleChangedCaller(m_scaleKey));
}
void updateTransform()
{
m_transform.localToParent() = g_matrix4_identity;
matrix4_transform_by_euler_xyz_degrees(m_transform.localToParent(), m_origin, m_angles, m_scale);
m_transformChanged();
}
void originChanged()
{
m_origin = m_originKey.m_origin;
updateTransform();
}
typedef MemberCaller<MiscModel, &MiscModel::originChanged> OriginChangedCaller;
void anglesChanged()
{
m_angles = m_anglesKey.m_angles;
updateTransform();
}
typedef MemberCaller<MiscModel, &MiscModel::anglesChanged> AnglesChangedCaller;
void scaleChanged()
{
m_scale = m_scaleKey.m_scale;
updateTransform();
}
typedef MemberCaller<MiscModel, &MiscModel::scaleChanged> ScaleChangedCaller;
public:
MiscModel(EntityClass* eclass, scene::Node& node, const Callback& transformChanged, const Callback& evaluateTransform) :
m_entity(eclass),
m_originKey(OriginChangedCaller(*this)),
m_origin(ORIGINKEY_IDENTITY),
m_anglesKey(AnglesChangedCaller(*this)),
m_angles(ANGLESKEY_IDENTITY),
m_scaleKey(ScaleChangedCaller(*this)),
m_scale(SCALEKEY_IDENTITY),
m_filter(m_entity, node),
m_named(m_entity),
m_nameKeys(m_entity),
m_renderName(m_named, g_vector3_identity),
m_transformChanged(transformChanged),
m_evaluateTransform(evaluateTransform)
{
construct();
}
MiscModel(const MiscModel& other, scene::Node& node, const Callback& transformChanged, const Callback& evaluateTransform) :
m_entity(other.m_entity),
m_originKey(OriginChangedCaller(*this)),
m_origin(ORIGINKEY_IDENTITY),
m_anglesKey(AnglesChangedCaller(*this)),
m_angles(ANGLESKEY_IDENTITY),
m_scaleKey(ScaleChangedCaller(*this)),
m_scale(SCALEKEY_IDENTITY),
m_filter(m_entity, node),
m_named(m_entity),
m_nameKeys(m_entity),
m_renderName(m_named, g_vector3_identity),
m_transformChanged(transformChanged),
m_evaluateTransform(evaluateTransform)
{
construct();
}
InstanceCounter m_instanceCounter;
void instanceAttach(const scene::Path& path)
{
if(++m_instanceCounter.m_count == 1)
{
m_filter.instanceAttach();
m_entity.instanceAttach(path_find_mapfile(path.begin(), path.end()));
m_entity.attach(m_keyObservers);
}
}
void instanceDetach(const scene::Path& path)
{
if(--m_instanceCounter.m_count == 0)
{
m_entity.detach(m_keyObservers);
m_entity.instanceDetach(path_find_mapfile(path.begin(), path.end()));
m_filter.instanceDetach();
}
}
EntityKeyValues& getEntity()
{
return m_entity;
}
const EntityKeyValues& getEntity() const
{
return m_entity;
}
scene::Traversable& getTraversable()
{
return m_model.getTraversable();
}
Namespaced& getNamespaced()
{
return m_nameKeys;
}
Nameable& getNameable()
{
return m_named;
}
TransformNode& getTransformNode()
{
return m_transform;
}
void attach(scene::Traversable::Observer* observer)
{
m_model.attach(observer);
}
void detach(scene::Traversable::Observer* observer)
{
m_model.detach(observer);
}
void renderSolid(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected) const
{
if(selected)
{
m_renderOrigin.render(renderer, volume, localToWorld);
}
renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly);
}
void renderWireframe(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected) const
{
renderSolid(renderer, volume, localToWorld, selected);
if(g_showNames)
{
renderer.addRenderable(m_renderName, localToWorld);
}
}
void translate(const Vector3& translation)
{
m_origin = origin_translated(m_origin, translation);
}
void rotate(const Quaternion& rotation)
{
m_angles = angles_rotated(m_angles, rotation);
}
void scale(const Vector3& scaling)
{
m_scale = scale_scaled(m_scale, scaling);
}
void snapto(float snap)
{
m_originKey.m_origin = origin_snapped(m_originKey.m_origin, snap);
m_originKey.write(&m_entity);
}
void revertTransform()
{
m_origin = m_originKey.m_origin;
m_angles = m_anglesKey.m_angles;
m_scale = m_scaleKey.m_scale;
}
void freezeTransform()
{
m_originKey.m_origin = m_origin;
m_originKey.write(&m_entity);
m_anglesKey.m_angles = m_angles;
m_anglesKey.write(&m_entity);
m_scaleKey.m_scale = m_scale;
m_scaleKey.write(&m_entity);
}
void transformChanged()
{
revertTransform();
m_evaluateTransform();
updateTransform();
}
typedef MemberCaller<MiscModel, &MiscModel::transformChanged> TransformChangedCaller;
};
class MiscModelInstance : public TargetableInstance, public TransformModifier, public Renderable
{
class TypeCasts
{
InstanceTypeCastTable m_casts;
public:
TypeCasts()
{
m_casts = TargetableInstance::StaticTypeCasts::instance().get();
InstanceStaticCast<MiscModelInstance, Renderable>::install(m_casts);
InstanceStaticCast<MiscModelInstance, Transformable>::install(m_casts);
InstanceIdentityCast<MiscModelInstance>::install(m_casts);
}
InstanceTypeCastTable& get()
{
return m_casts;
}
};
MiscModel& m_contained;
public:
typedef LazyStatic<TypeCasts> StaticTypeCasts;
STRING_CONSTANT(Name, "MiscModelInstance");
MiscModelInstance(const scene::Path& path, scene::Instance* parent, MiscModel& miscmodel) :
TargetableInstance(path, parent, this, StaticTypeCasts::instance().get(), miscmodel.getEntity(), *this),
TransformModifier(MiscModel::TransformChangedCaller(miscmodel), ApplyTransformCaller(*this)),
m_contained(miscmodel)
{
m_contained.instanceAttach(Instance::path());
StaticRenderableConnectionLines::instance().attach(*this);
}
~MiscModelInstance()
{
StaticRenderableConnectionLines::instance().detach(*this);
m_contained.instanceDetach(Instance::path());
}
void renderSolid(Renderer& renderer, const VolumeTest& volume) const
{
m_contained.renderSolid(renderer, volume, Instance::localToWorld(), getSelectable().isSelected());
}
void renderWireframe(Renderer& renderer, const VolumeTest& volume) const
{
m_contained.renderWireframe(renderer, volume, Instance::localToWorld(), getSelectable().isSelected());
}
void evaluateTransform()
{
if(getType() == TRANSFORM_PRIMITIVE)
{
m_contained.translate(getTranslation());
m_contained.rotate(getRotation());
m_contained.scale(getScale());
}
}
void applyTransform()
{
m_contained.revertTransform();
evaluateTransform();
m_contained.freezeTransform();
}
typedef MemberCaller<MiscModelInstance, &MiscModelInstance::applyTransform> ApplyTransformCaller;
};
class MiscModelNode :
public scene::Node::Symbiot,
public scene::Instantiable,
public scene::Cloneable,
public scene::Traversable::Observer
{
class TypeCasts
{
NodeTypeCastTable m_casts;
public:
TypeCasts()
{
NodeStaticCast<MiscModelNode, scene::Instantiable>::install(m_casts);
NodeStaticCast<MiscModelNode, scene::Cloneable>::install(m_casts);
NodeContainedCast<MiscModelNode, scene::Traversable>::install(m_casts);
NodeContainedCast<MiscModelNode, Snappable>::install(m_casts);
NodeContainedCast<MiscModelNode, TransformNode>::install(m_casts);
NodeContainedCast<MiscModelNode, Entity>::install(m_casts);
NodeContainedCast<MiscModelNode, Nameable>::install(m_casts);
NodeContainedCast<MiscModelNode, Namespaced>::install(m_casts);
}
NodeTypeCastTable& get()
{
return m_casts;
}
};
scene::Node m_node;
InstanceSet m_instances;
MiscModel m_contained;
void construct()
{
m_contained.attach(this);
}
void destroy()
{
m_contained.detach(this);
}
public:
typedef LazyStatic<TypeCasts> StaticTypeCasts;
scene::Traversable& get(NullType<scene::Traversable>)
{
return m_contained.getTraversable();
}
Snappable& get(NullType<Snappable>)
{
return m_contained;
}
TransformNode& get(NullType<TransformNode>)
{
return m_contained.getTransformNode();
}
Entity& get(NullType<Entity>)
{
return m_contained.getEntity();
}
Nameable& get(NullType<Nameable>)
{
return m_contained.getNameable();
}
Namespaced& get(NullType<Namespaced>)
{
return m_contained.getNamespaced();
}
MiscModelNode(EntityClass* eclass) :
m_node(this, this, StaticTypeCasts::instance().get()),
m_contained(eclass, m_node, InstanceSet::TransformChangedCaller(m_instances), InstanceSetEvaluateTransform<MiscModelInstance>::Caller(m_instances))
{
construct();
}
MiscModelNode(const MiscModelNode& other) :
scene::Node::Symbiot(other),
scene::Instantiable(other),
scene::Cloneable(other),
scene::Traversable::Observer(other),
m_node(this, this, StaticTypeCasts::instance().get()),
m_contained(other.m_contained, m_node, InstanceSet::TransformChangedCaller(m_instances), InstanceSetEvaluateTransform<MiscModelInstance>::Caller(m_instances))
{
construct();
}
~MiscModelNode()
{
destroy();
}
void release()
{
delete this;
}
scene::Node& node()
{
return m_node;
}
scene::Node& clone() const
{
return (new MiscModelNode(*this))->node();
}
void insert(scene::Node& child)
{
m_instances.insert(child);
}
void erase(scene::Node& child)
{
m_instances.erase(child);
}
scene::Instance* create(const scene::Path& path, scene::Instance* parent)
{
return new MiscModelInstance(path, parent, m_contained);
}
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);
}
};
scene::Node& New_MiscModel(EntityClass* eclass)
{
return (new MiscModelNode(eclass))->node();
}
void MiscModel_construct()
{
}
void MiscModel_destroy()
{
}

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_MISCMODEL_H)
#define INCLUDED_MISCMODEL_H
scene::Node& New_MiscModel(EntityClass* eclass);
void MiscModel_construct();
void MiscModel_destroy();
#endif

23
plugins/entity/model.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 "model.h"

124
plugins/entity/model.h Normal file
View File

@@ -0,0 +1,124 @@
/*
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_MODEL_H)
#define INCLUDED_MODEL_H
#include "entitylib.h"
#include "traverselib.h"
#include "generic/callback.h"
#include "stream/stringstream.h"
#include "os/path.h"
#include "moduleobserver.h"
class Model : public ModuleObserver
{
ResourceReference m_resource;
scene::Traversable& m_traverse;
scene::Node* m_node;
Callback m_modelChanged;
public:
Model(scene::Traversable& traversable, const Callback& modelChanged)
: m_resource(""), m_traverse(traversable), m_node(0), m_modelChanged(modelChanged)
{
m_resource.attach(*this);
}
~Model()
{
m_resource.detach(*this);
}
void realise()
{
m_resource.get()->load();
m_node = m_resource.get()->getNode();
if(m_node != 0)
{
m_traverse.insert(*m_node);
}
}
void unrealise()
{
if(m_node != 0)
{
m_traverse.erase(*m_node);
}
}
void modelChanged(const char* value)
{
StringOutputStream cleaned(string_length(value));
cleaned << PathCleaned(value);
m_resource.detach(*this);
m_resource.setName(cleaned.c_str());
m_resource.attach(*this);
m_modelChanged();
}
typedef MemberCaller1<Model, const char*, &Model::modelChanged> ModelChangedCaller;
const char* getName() const
{
return m_resource.getName();
}
scene::Node* getNode() const
{
return m_node;
}
};
class SingletonModel
{
TraversableNode m_traverse;
Model m_model;
public:
SingletonModel()
: m_model(m_traverse, Callback())
{
}
void attach(scene::Traversable::Observer* observer)
{
m_traverse.attach(observer);
}
void detach(scene::Traversable::Observer* observer)
{
m_traverse.detach(observer);
}
scene::Traversable& getTraversable()
{
return m_traverse;
}
void modelChanged(const char* value)
{
m_model.modelChanged(value);
}
typedef MemberCaller1<SingletonModel, const char*, &SingletonModel::modelChanged> ModelChangedCaller;
scene::Node* getNode() const
{
return m_model.getNode();
}
};
#endif

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 "modelskinkey.h"

View File

@@ -0,0 +1,111 @@
/*
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_MODELSKINKEY_H)
#define INCLUDED_MODELSKINKEY_H
#include "modelskin.h"
#include "os/path.h"
#include "stream/stringstream.h"
#include "moduleobserver.h"
#include "entitylib.h"
#include "traverselib.h"
inline void parseTextureName(CopiedString& name, const char* token)
{
StringOutputStream cleaned(256);
cleaned << PathCleaned(token);
name = CopiedString(cleaned.c_str(), path_get_filename_base_end(cleaned.c_str())); // remove extension
}
class ModelSkinKey : public ModuleObserver
{
CopiedString m_name;
ModelSkin* m_skin;
Callback m_skinChangedCallback;
ModelSkinKey(const ModelSkinKey&);
ModelSkinKey operator=(const ModelSkinKey&);
void construct()
{
m_skin = &GlobalModelSkinCache().capture(m_name.c_str());
m_skin->attach(*this);
}
void destroy()
{
m_skin->detach(*this);
GlobalModelSkinCache().release(m_name.c_str());
}
public:
ModelSkinKey(const Callback& skinChangedCallback) : m_skinChangedCallback(skinChangedCallback)
{
construct();
}
~ModelSkinKey()
{
destroy();
}
ModelSkin& get() const
{
return *m_skin;
}
void skinChanged(const char* value)
{
destroy();
parseTextureName(m_name, value);
construct();
}
typedef MemberCaller1<ModelSkinKey, const char*, &ModelSkinKey::skinChanged> SkinChangedCaller;
void realise()
{
m_skinChangedCallback();
}
void unrealise()
{
}
};
class InstanceSkinChanged : public scene::Instantiable::Visitor
{
public:
void visit(scene::Instance& instance) const
{
//\todo don't do this for instances that are not children of the entity setting the skin
SkinnedModel* skinned = InstanceTypeCast<SkinnedModel>::cast(instance);
if(skinned != 0)
{
skinned->skinChanged();
}
}
};
inline void Node_modelSkinChanged(scene::Node& node)
{
scene::Instantiable* instantiable = Node_getInstantiable(node);
ASSERT_NOTNULL(instantiable);
instantiable->forEachInstance(InstanceSkinChanged());
}
#endif

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 "namedentity.h"

View File

@@ -0,0 +1,113 @@
/*
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_NAMEDENTITY_H)
#define INCLUDED_NAMEDENTITY_H
#include "entitylib.h"
#include "eclasslib.h"
#include "generic/callback.h"
#include "nameable.h"
#include <set>
class NameCallbackSet
{
typedef std::set<NameCallback> NameCallbacks;
NameCallbacks m_callbacks;
public:
void insert(const NameCallback& callback)
{
m_callbacks.insert(callback);
}
void erase(const NameCallback& callback)
{
m_callbacks.erase(callback);
}
void changed(const char* name) const
{
for(NameCallbacks::const_iterator i = m_callbacks.begin(); i != m_callbacks.end(); ++i)
{
(*i)(name);
}
}
};
class NamedEntity : public Nameable
{
EntityKeyValues& m_entity;
NameCallbackSet m_changed;
CopiedString m_name;
public:
NamedEntity(EntityKeyValues& entity) : m_entity(entity)
{
}
const char* name() const
{
if(string_empty(m_name.c_str()))
{
return m_entity.getEntityClass().name();
}
return m_name.c_str();
}
void attach(const NameCallback& callback)
{
m_changed.insert(callback);
}
void detach(const NameCallback& callback)
{
m_changed.erase(callback);
}
void identifierChanged(const char* value)
{
if(string_empty(value))
{
m_changed.changed(m_entity.getEntityClass().name());
}
else
{
m_changed.changed(value);
}
m_name = value;
}
typedef MemberCaller1<NamedEntity, const char*, &NamedEntity::identifierChanged> IdentifierChangedCaller;
};
class RenderableNamedEntity : public OpenGLRenderable
{
const NamedEntity& m_named;
const Vector3& m_position;
public:
RenderableNamedEntity(const NamedEntity& named, const Vector3& position)
: m_named(named), m_position(position)
{
}
void render(RenderStateFlags state) const
{
glRasterPos3fv(vector3_to_array(m_position));
GlobalOpenGL().drawString(m_named.name());
}
};
#endif

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 "namekeys.h"

148
plugins/entity/namekeys.h Normal file
View File

@@ -0,0 +1,148 @@
/*
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_NAMEKEYS_H)
#define INCLUDED_NAMEKEYS_H
#include <stdio.h>
#include <map>
#include "generic/static.h"
#include "entitylib.h"
#include "namespace.h"
inline bool string_is_integer(const char* string)
{
strtol(string, const_cast<char**>(&string), 10);
return *string == '\0';
}
typedef bool (*KeyIsNameFunc)(const char* key);
class KeyIsName
{
public:
KeyIsNameFunc m_keyIsName;
const char* m_nameKey;
KeyIsName()
{
}
};
typedef MemberCaller1<KeyValue, const char*, &KeyValue::assign> KeyValueAssignCaller;
typedef MemberCaller1<KeyValue, const KeyObserver&, &KeyValue::attach> KeyValueAttachCaller;
typedef MemberCaller1<KeyValue, const KeyObserver&, &KeyValue::detach> KeyValueDetachCaller;
class NameKeys : public EntityKeyValues::Observer, public Namespaced
{
Namespace* m_namespace;
EntityKeyValues& m_entity;
KeyIsNameFunc m_keyIsName;
NameKeys(const NameKeys& other);
NameKeys& operator=(const NameKeys& other);
typedef std::map<CopiedString, EntityKeyValues::Value*> KeyValues;
KeyValues m_keyValues;
void insertName(const char* key, EntityKeyValues::Value& value)
{
if(m_namespace != 0 && m_keyIsName(key))
{
//globalOutputStream() << "insert " << key << "\n";
m_namespace->attach(KeyValueAssignCaller(value), KeyValueAttachCaller(value));
}
}
void eraseName(const char* key, EntityKeyValues::Value& value)
{
if(m_namespace != 0 && m_keyIsName(key))
{
//globalOutputStream() << "erase " << key << "\n";
m_namespace->detach(KeyValueAssignCaller(value), KeyValueDetachCaller(value));
}
}
void insertAll()
{
for(KeyValues::iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i)
{
insertName((*i).first.c_str(), *(*i).second);
}
}
void eraseAll()
{
for(KeyValues::iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i)
{
eraseName((*i).first.c_str(), *(*i).second);
}
}
public:
NameKeys(EntityKeyValues& entity) : m_namespace(0), m_entity(entity), m_keyIsName(Static<KeyIsName>::instance().m_keyIsName)
{
m_entity.attach(*this);
}
~NameKeys()
{
m_entity.detach(*this);
}
void setNamespace(Namespace& space)
{
eraseAll();
m_namespace = &space;
insertAll();
}
void setKeyIsName(KeyIsNameFunc keyIsName)
{
eraseAll();
m_keyIsName = keyIsName;
insertAll();
}
void insert(const char* key, EntityKeyValues::Value& value)
{
m_keyValues.insert(KeyValues::value_type(key, &value));
insertName(key, value);
}
void erase(const char* key, EntityKeyValues::Value& value)
{
eraseName(key, value);
m_keyValues.erase(key);
}
};
inline bool keyIsNameDoom3(const char* key)
{
return string_equal(key, "target")
|| (string_equal_n(key, "target", 6) && string_is_integer(key + 6))
|| string_equal(key, "name");
}
inline bool keyIsNameDoom3Doom3Group(const char* key)
{
return keyIsNameDoom3(key)
|| string_equal(key, "model");
}
inline bool keyIsNameQuake3(const char* key)
{
return string_equal(key, "target")
|| string_equal(key, "targetname");
}
#endif

23
plugins/entity/origin.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 "origin.h"

169
plugins/entity/origin.h Normal file
View File

@@ -0,0 +1,169 @@
/*
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_ORIGIN_H)
#define INCLUDED_ORIGIN_H
#include "ientity.h"
#include "math/matrix.h"
#include "generic/callback.h"
#include "stringio.h"
const Vector3 ORIGINKEY_IDENTITY = Vector3(0, 0, 0);
inline void default_origin(Vector3& origin)
{
origin = ORIGINKEY_IDENTITY;
}
inline void read_origin(Vector3& origin, const char* value)
{
if(!string_parse_vector3(value, origin))
{
default_origin(origin);
}
}
inline void write_origin(const Vector3& origin, Entity* entity, const char* key)
{
char value[64];
sprintf(value, "%g %g %g", origin[0], origin[1], origin[2]);
entity->setKeyValue(key, value);
}
inline Vector3 origin_translated(const Vector3& origin, const Vector3& translation)
{
return matrix4_get_translation_vec3(
matrix4_multiplied_by_matrix4(
matrix4_translation_for_vec3(origin),
matrix4_translation_for_vec3(translation)
)
);
}
inline Vector3 origin_snapped(const Vector3& origin, float snap)
{
return vector3_snapped(origin, snap);
}
class OriginKey
{
Callback m_originChanged;
public:
Vector3 m_origin;
OriginKey(const Callback& originChanged)
: m_originChanged(originChanged), m_origin(ORIGINKEY_IDENTITY)
{
}
void originChanged(const char* value)
{
read_origin(m_origin, value);
m_originChanged();
}
typedef MemberCaller1<OriginKey, const char*, &OriginKey::originChanged> OriginChangedCaller;
void write(Entity* entity) const
{
write_origin(m_origin, entity, "origin");
}
};
#include "scenelib.h"
inline BrushDoom3* Node_getBrushDoom3(scene::Node& node)
{
return NodeTypeCast<BrushDoom3>::cast(node);
}
inline void BrushDoom3_setDoom3GroupOrigin(scene::Node& node, const Vector3& origin)
{
BrushDoom3* brush = Node_getBrushDoom3(node);
if(brush != 0)
{
brush->setDoom3GroupOrigin(origin);
}
}
class SetDoom3GroupOriginWalker : public scene::Traversable::Walker
{
const Vector3& m_origin;
public:
SetDoom3GroupOriginWalker(const Vector3& origin) : m_origin(origin)
{
}
bool pre(scene::Node& node) const
{
BrushDoom3_setDoom3GroupOrigin(node, m_origin);
return true;
}
};
class Doom3GroupOrigin : public scene::Traversable::Observer
{
scene::Traversable& m_set;
const Vector3& m_origin;
bool m_enabled;
public:
Doom3GroupOrigin(scene::Traversable& set, const Vector3& origin) : m_set(set), m_origin(origin), m_enabled(false)
{
}
void enable()
{
m_enabled = true;
originChanged();
}
void disable()
{
m_enabled = false;
}
void originChanged()
{
if(m_enabled)
{
m_set.traverse(SetDoom3GroupOriginWalker(m_origin));
}
}
void insert(scene::Node& node)
{
if(m_enabled)
{
BrushDoom3_setDoom3GroupOrigin(node, m_origin);
}
}
void erase(scene::Node& node)
{
if(m_enabled)
{
BrushDoom3_setDoom3GroupOrigin(node, Vector3(0, 0, 0));
}
}
};
#endif

163
plugins/entity/plugin.cpp Normal file
View File

@@ -0,0 +1,163 @@
/*
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 "iscenegraph.h"
#include "irender.h"
#include "iselection.h"
#include "ientity.h"
#include "iundo.h"
#include "ieclass.h"
#include "igl.h"
#include "ireference.h"
#include "ifilter.h"
#include "preferencesystem.h"
#include "qerplugin.h"
#include "namespace.h"
#include "modelskin.h"
#include "typesystem.h"
#include "entity.h"
#include "skincache.h"
#include "modulesystem/singletonmodule.h"
class EntityDependencies :
public GlobalRadiantModuleRef,
public GlobalOpenGLModuleRef,
public GlobalUndoModuleRef,
public GlobalSceneGraphModuleRef,
public GlobalShaderCacheModuleRef,
public GlobalSelectionModuleRef,
public GlobalReferenceModuleRef,
public GlobalFilterModuleRef,
public GlobalPreferenceSystemModuleRef,
public GlobalNamespaceModuleRef,
public GlobalModelSkinCacheModuleRef
{
};
class EntityQ3API : public TypeSystemRef
{
EntityCreator* m_entityq3;
public:
typedef EntityCreator Type;
STRING_CONSTANT(Name, "quake3");
EntityQ3API()
{
Entity_Construct();
m_entityq3 = &GetEntityCreator();
GlobalReferenceCache().setEntityCreator(*m_entityq3);
}
~EntityQ3API()
{
Entity_Destroy();
}
EntityCreator* getTable()
{
return m_entityq3;
}
};
typedef SingletonModule<EntityQ3API, EntityDependencies> EntityQ3Module;
EntityQ3Module g_EntityQ3Module;
class EntityWolfAPI : public TypeSystemRef
{
EntityCreator* m_entitywolf;
public:
typedef EntityCreator Type;
STRING_CONSTANT(Name, "wolf");
EntityWolfAPI()
{
Entity_Construct(eGameTypeRTCW);
m_entitywolf = &GetEntityCreator();
GlobalReferenceCache().setEntityCreator(*m_entitywolf);
}
~EntityWolfAPI()
{
Entity_Destroy();
}
EntityCreator* getTable()
{
return m_entitywolf;
}
};
typedef SingletonModule<EntityWolfAPI, EntityDependencies> EntityWolfModule;
EntityWolfModule g_EntityWolfModule;
class EntityDoom3API : public TypeSystemRef
{
EntityCreator* m_entitydoom3;
public:
typedef EntityCreator Type;
STRING_CONSTANT(Name, "doom3");
EntityDoom3API()
{
Entity_Construct(eGameTypeDoom3);
m_entitydoom3 = &GetEntityCreator();
GlobalReferenceCache().setEntityCreator(*m_entitydoom3);
}
~EntityDoom3API()
{
Entity_Destroy();
}
EntityCreator* getTable()
{
return m_entitydoom3;
}
};
typedef SingletonModule<EntityDoom3API, EntityDependencies> EntityDoom3Module;
EntityDoom3Module g_EntityDoom3Module;
extern "C" void RADIANT_DLLEXPORT Radiant_RegisterModules(ModuleServer& server)
{
GlobalErrorStream::instance().setOutputStream(server.getErrorStream());
GlobalOutputStream::instance().setOutputStream(server.getOutputStream());
GlobalDebugMessageHandler::instance().setHandler(server.getDebugMessageHandler());
GlobalModuleServer::instance().set(server);
g_EntityQ3Module.selfRegister();
g_EntityWolfModule.selfRegister();
g_EntityDoom3Module.selfRegister();
Doom3ModelSkinCacheModule_selfRegister(server);
}

25
plugins/entity/plugin.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_PLUGIN_H)
#define INCLUDED_PLUGIN_H
#endif

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 "rotation.h"

199
plugins/entity/rotation.h Normal file
View File

@@ -0,0 +1,199 @@
/*
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_ROTATION_H)
#define INCLUDED_ROTATION_H
#include "ientity.h"
#include "stream/stringstream.h"
#include "math/quaternion.h"
#include "generic/callback.h"
#include "stringio.h"
#include "angle.h"
typedef float Float9[9];
inline void default_rotation(Float9 rotation)
{
rotation[0] = 1;
rotation[1] = 0;
rotation[2] = 0;
rotation[3] = 0;
rotation[4] = 1;
rotation[5] = 0;
rotation[6] = 0;
rotation[7] = 0;
rotation[8] = 1;
}
inline void write_rotation(const Float9 rotation, Entity* entity, const char* key = "rotation")
{
if(rotation[0] == 1
&& rotation[1] == 0
&& rotation[2] == 0
&& rotation[3] == 0
&& rotation[4] == 1
&& rotation[5] == 0
&& rotation[6] == 0
&& rotation[7] == 0
&& rotation[8] == 1)
{
entity->setKeyValue(key, "");
}
else
{
StringOutputStream value(256);
value << rotation[0] << ' '
<< rotation[1] << ' '
<< rotation[2] << ' '
<< rotation[3] << ' '
<< rotation[4] << ' '
<< rotation[5] << ' '
<< rotation[6] << ' '
<< rotation[7] << ' '
<< rotation[8];
entity->setKeyValue(key, value.c_str());
}
}
inline void read_rotation(Float9 rotation, const char* value)
{
if(!string_parse_vector(value, rotation, rotation + 9))
{
default_rotation(rotation);
}
}
inline Matrix4 rotation_toMatrix(const Float9 rotation)
{
return Matrix4(
rotation[0],
rotation[1],
rotation[2],
0,
rotation[3],
rotation[4],
rotation[5],
0,
rotation[6],
rotation[7],
rotation[8],
0,
0,
0,
0,
1
);
}
inline void rotation_fromMatrix(Float9 rotation, const Matrix4& matrix)
{
rotation[0] = matrix.xx();
rotation[1] = matrix.xy();
rotation[2] = matrix.xz();
rotation[3] = matrix.yx();
rotation[4] = matrix.yy();
rotation[5] = matrix.yz();
rotation[6] = matrix.zx();
rotation[7] = matrix.zy();
rotation[8] = matrix.zz();
}
inline void rotation_assign(Float9 rotation, const Float9 other)
{
rotation[0] = other[0];
rotation[1] = other[1];
rotation[2] = other[2];
rotation[3] = other[3];
rotation[4] = other[4];
rotation[5] = other[5];
rotation[6] = other[6];
rotation[7] = other[7];
rotation[8] = other[8];
}
inline void rotation_rotate(Float9 rotation, const Quaternion& rotate)
{
rotation_fromMatrix(rotation,
matrix4_multiplied_by_matrix4(
rotation_toMatrix(rotation),
matrix4_rotation_for_quaternion_quantised(rotate)
)
);
}
inline void read_angle(Float9 rotation, const char* value)
{
float angle;
if(!string_parse_float(value, angle))
{
default_rotation(rotation);
}
else
{
rotation_fromMatrix(rotation, matrix4_rotation_for_z_degrees(angle));
}
}
class RotationKey
{
Callback m_rotationChanged;
public:
Float9 m_rotation;
RotationKey(const Callback& rotationChanged)
: m_rotationChanged(rotationChanged)
{
default_rotation(m_rotation);
}
void angleChanged(const char* value)
{
read_angle(m_rotation, value);
m_rotationChanged();
}
typedef MemberCaller1<RotationKey, const char*, &RotationKey::angleChanged> AngleChangedCaller;
void rotationChanged(const char* value)
{
read_rotation(m_rotation, value);
m_rotationChanged();
}
typedef MemberCaller1<RotationKey, const char*, &RotationKey::rotationChanged> RotationChangedCaller;
void write(Entity* entity) const
{
Vector3 euler = matrix4_get_rotation_euler_xyz_degrees(rotation_toMatrix(m_rotation));
if(euler[0] == 0 && euler[1] == 0)
{
entity->setKeyValue("rotation", "");
write_angle(euler[2], entity);
}
else
{
entity->setKeyValue("angle", "");
write_rotation(m_rotation, entity);
}
}
};
#endif

23
plugins/entity/scale.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 "scale.h"

128
plugins/entity/scale.h Normal file
View File

@@ -0,0 +1,128 @@
/*
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_SCALE_H)
#define INCLUDED_SCALE_H
#include "ientity.h"
#include "math/matrix.h"
#include "generic/callback.h"
#include "stringio.h"
const Vector3 SCALEKEY_IDENTITY = Vector3(1, 1, 1);
inline void default_scale(Vector3& scale)
{
scale = SCALEKEY_IDENTITY;
}
inline void read_scale(Vector3& scalevec, const char* value)
{
float scale;
if(!string_parse_float(value, scale)
|| scale == 0)
{
default_scale(scalevec);
}
else
{
scalevec = Vector3(scale, scale, scale);
}
}
inline void read_scalevec(Vector3& scale, const char* value)
{
if(!string_parse_vector3(value, scale)
|| scale[0] == 0
|| scale[1] == 0
|| scale[2] == 0)
default_scale(scale);
}
inline void write_scale(const Vector3& scale, Entity* entity)
{
if(scale[0] == 1 && scale[1] == 1 && scale[2] == 1)
{
entity->setKeyValue("modelscale", "");
entity->setKeyValue("modelscale_vec", "");
}
else
{
char value[64];
if(scale[0] == scale[1] && scale[0] == scale[2])
{
sprintf(value, "%g", scale[0]);
entity->setKeyValue("modelscale_vec", "");
entity->setKeyValue("modelscale", value);
}
else
{
sprintf(value, "%g %g %g", scale[0], scale[1], scale[2]);
entity->setKeyValue("modelscale", "");
entity->setKeyValue("modelscale_vec", value);
}
}
}
inline Vector3 scale_scaled(const Vector3& scale, const Vector3& scaling)
{
return matrix4_get_scale_vec3(
matrix4_multiplied_by_matrix4(
matrix4_scale_for_vec3(scale),
matrix4_scale_for_vec3(scaling)
)
);
}
class ScaleKey
{
Callback m_scaleChanged;
public:
Vector3 m_scale;
ScaleKey(const Callback& scaleChanged)
: m_scaleChanged(scaleChanged), m_scale(SCALEKEY_IDENTITY)
{
}
void uniformScaleChanged(const char* value)
{
read_scale(m_scale, value);
m_scaleChanged();
}
typedef MemberCaller1<ScaleKey, const char*, &ScaleKey::uniformScaleChanged> UniformScaleChangedCaller;
void scaleChanged(const char* value)
{
read_scalevec(m_scale, value);
m_scaleChanged();
}
typedef MemberCaller1<ScaleKey, const char*, &ScaleKey::scaleChanged> ScaleChangedCaller;
void write(Entity* entity) const
{
write_scale(m_scale, entity);
}
};
#endif

View File

@@ -0,0 +1,348 @@
/*
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 "skincache.h"
#include "ifilesystem.h"
#include "iscriplib.h"
#include "iarchive.h"
#include "modelskin.h"
#include <map>
#include "stream/stringstream.h"
#include "generic/callback.h"
#include "container/cache.h"
#include "container/hashfunc.h"
#include "os/path.h"
#include "moduleobservers.h"
#include "modulesystem/singletonmodule.h"
#include "stringio.h"
void parseShaderName(CopiedString& name, const char* token)
{
StringOutputStream cleaned(256);
cleaned << PathCleaned(token);
name = cleaned.c_str();
}
class Doom3ModelSkin
{
typedef std::map<CopiedString, CopiedString> Remaps;
Remaps m_remaps;
public:
bool parseTokens(Tokeniser& tokeniser)
{
RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "{"));
tokeniser.nextLine();
for(;;)
{
const char* token = tokeniser.getToken();
if(token == 0)
{
return false;
}
if(string_equal(token, "}"))
{
tokeniser.nextLine();
return true;
}
else if(string_equal(token, "model"))
{
//const char* model =
tokeniser.getToken();
}
else
{
CopiedString from, to;
parseShaderName(from, token);
tokeniser.nextLine(); // hack to handle badly formed skins
parseShaderName(to, tokeniser.getToken());
if(!string_equal(from.c_str(), to.c_str()))
{
m_remaps.insert(Remaps::value_type(from, to));
}
}
tokeniser.nextLine();
}
}
const char* getRemap(const char* name) const
{
Remaps::const_iterator i = m_remaps.find(name);
if(i != m_remaps.end())
{
return (*i).second.c_str();
}
return "";
}
void forEachRemap(const SkinRemapCallback& callback) const
{
for(Remaps::const_iterator i = m_remaps.begin(); i != m_remaps.end(); ++i)
{
callback(SkinRemap((*i).first.c_str(), (*i).second.c_str()));
}
}
};
class GlobalSkins
{
public:
typedef std::map<CopiedString, Doom3ModelSkin> SkinMap;
SkinMap m_skins;
Doom3ModelSkin g_nullSkin;
Doom3ModelSkin& getSkin(const char* name)
{
SkinMap::iterator i = m_skins.find(name);
if(i != m_skins.end())
{
return (*i).second;
}
return g_nullSkin;
}
bool parseTokens(Tokeniser& tokeniser)
{
tokeniser.nextLine();
for(;;)
{
const char* token = tokeniser.getToken();
if(token == 0)
{
// end of token stream
return true;
}
if(!string_equal(token, "skin"))
{
Tokeniser_unexpectedError(tokeniser, token, "skin");
return false;
}
const char* other = tokeniser.getToken();
if(other == 0)
{
Tokeniser_unexpectedError(tokeniser, token, "#string");
return false;
}
CopiedString name;
parseShaderName(name, other);
Doom3ModelSkin& skin = m_skins[name];
RETURN_FALSE_IF_FAIL(skin.parseTokens(tokeniser));
}
}
void parseFile(const char* name)
{
StringOutputStream relativeName(64);
relativeName << "skins/" << name;
ArchiveTextFile* file = GlobalFileSystem().openTextFile(relativeName.c_str());
if(file != 0)
{
globalOutputStream() << "parsing skins from " << makeQuoted(name) << "\n";
{
Tokeniser& tokeniser = GlobalScriptLibrary().m_pfnNewSimpleTokeniser(file->getInputStream());
parseTokens(tokeniser);
tokeniser.release();
}
file->release();
}
else
{
globalErrorStream() << "failed to open " << makeQuoted(name) << "\n";
}
}
typedef MemberCaller1<GlobalSkins, const char*, &GlobalSkins::parseFile> ParseFileCaller;
void construct()
{
GlobalFileSystem().forEachFile("skins/", "skin", ParseFileCaller(*this));
}
void destroy()
{
m_skins.clear();
}
void realise()
{
construct();
}
void unrealise()
{
destroy();
}
};
GlobalSkins g_skins;
class Doom3ModelSkinCacheElement : public ModelSkin
{
ModuleObservers m_observers;
Doom3ModelSkin* m_skin;
public:
Doom3ModelSkinCacheElement() : m_skin(0)
{
}
void attach(ModuleObserver& observer)
{
m_observers.attach(observer);
if(realised())
{
observer.realise();
}
}
void detach(ModuleObserver& observer)
{
if(realised())
{
observer.unrealise();
}
m_observers.detach(observer);
}
bool realised() const
{
return m_skin != 0;
}
void realise(const char* name)
{
ASSERT_MESSAGE(!realised(), "Doom3ModelSkinCacheElement::realise: already realised");
m_skin = &g_skins.getSkin(name);
m_observers.realise();
}
void unrealise()
{
ASSERT_MESSAGE(realised(), "Doom3ModelSkinCacheElement::unrealise: not realised");
m_observers.unrealise();
m_skin = 0;
}
const char* getRemap(const char* name) const
{
ASSERT_MESSAGE(realised(), "Doom3ModelSkinCacheElement::getRemap: not realised");
return m_skin->getRemap(name);
}
void forEachRemap(const SkinRemapCallback& callback) const
{
ASSERT_MESSAGE(realised(), "Doom3ModelSkinCacheElement::forEachRemap: not realised");
m_skin->forEachRemap(callback);
}
};
class Doom3ModelSkinCache : public ModelSkinCache, public ModuleObserver
{
class CreateDoom3ModelSkin
{
Doom3ModelSkinCache& m_cache;
public:
explicit CreateDoom3ModelSkin(Doom3ModelSkinCache& cache)
: m_cache(cache)
{
}
Doom3ModelSkinCacheElement* construct(const CopiedString& name)
{
Doom3ModelSkinCacheElement* skin = new Doom3ModelSkinCacheElement;
if(m_cache.realised())
{
skin->realise(name.c_str());
}
return skin;
}
void destroy(Doom3ModelSkinCacheElement* skin)
{
if(m_cache.realised())
{
skin->unrealise();
}
delete skin;
}
};
typedef HashedCache<CopiedString, Doom3ModelSkinCacheElement, HashString, std::equal_to<CopiedString>, CreateDoom3ModelSkin> Cache;
Cache m_cache;
bool m_realised;
public:
typedef ModelSkinCache Type;
STRING_CONSTANT(Name, "*");
ModelSkinCache* getTable()
{
return this;
}
Doom3ModelSkinCache() : m_cache(CreateDoom3ModelSkin(*this)), m_realised(false)
{
GlobalFileSystem().attach(*this);
}
~Doom3ModelSkinCache()
{
GlobalFileSystem().detach(*this);
}
ModelSkin& capture(const char* name)
{
return *m_cache.capture(name);
}
void release(const char* name)
{
m_cache.release(name);
}
bool realised() const
{
return m_realised;
}
void realise()
{
g_skins.realise();
m_realised = true;
for(Cache::iterator i = m_cache.begin(); i != m_cache.end(); ++i)
{
(*i).value->realise((*i).key.c_str());
}
}
void unrealise()
{
m_realised = false;
for(Cache::iterator i = m_cache.begin(); i != m_cache.end(); ++i)
{
(*i).value->unrealise();
}
g_skins.unrealise();
}
};
class Doom3ModelSkinCacheDependencies : public GlobalFileSystemModuleRef, public GlobalScripLibModuleRef
{
};
typedef SingletonModule<Doom3ModelSkinCache, Doom3ModelSkinCacheDependencies> Doom3ModelSkinCacheModule;
Doom3ModelSkinCacheModule g_Doom3ModelSkinCacheModule;
void Doom3ModelSkinCacheModule_selfRegister(ModuleServer& server)
{
g_Doom3ModelSkinCacheModule.selfRegister();
}

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_SKINCACHE_H)
#define INCLUDED_SKINCACHE_H
class ModuleServer;
void Doom3ModelSkinCacheModule_selfRegister(ModuleServer& server);
#endif

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
*/
#include "targetable.h"
typedef std::map<CopiedString, targetables_t> targetnames_t;
const char* g_targetable_nameKey = "targetname";
targetnames_t g_targetnames;
targetables_t* getTargetables(const char* targetname)
{
if(targetname[0] == '\0')
return 0;
return &g_targetnames[targetname];
}
Shader* RenderableTargetingEntity::m_state;

452
plugins/entity/targetable.h Normal file
View File

@@ -0,0 +1,452 @@
/*
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_TARGETABLE_H)
#define INCLUDED_TARGETABLE_H
#include <set>
#include <map>
#include "cullable.h"
#include "renderable.h"
#include "math/line.h"
#include "render.h"
#include "generic/callback.h"
#include "selectionlib.h"
#include "entitylib.h"
#include "eclasslib.h"
#include "stringio.h"
class Targetable
{
public:
virtual const Vector3& world_position() const = 0;
};
typedef std::set<Targetable*> targetables_t;
extern const char* g_targetable_nameKey;
targetables_t* getTargetables(const char* targetname);
class EntityConnectionLine : public OpenGLRenderable
{
public:
Vector3 start;
Vector3 end;
void render(RenderStateFlags state) const
{
float s1[2], s2[2];
Vector3 dir(vector3_subtracted(end, start));
double len = vector3_length(dir);
vector3_scale(dir, 8.0 * (1.0 / len));
s1[0] = dir[0] - dir[1];
s1[1] = dir[0] + dir[1];
s2[0] = dir[0] + dir[1];
s2[1] = -dir[0] + dir[1];
glBegin(GL_LINES);
glVertex3fv(vector3_to_array(start));
glVertex3fv(vector3_to_array(end));
len*=0.0625; // half / 8
Vector3 arrow(start);
for (unsigned int i = 0, count = (len<32)? 1 : static_cast<unsigned int>(len*0.0625); i < count; i++)
{
vector3_add(arrow, vector3_scaled(dir, (len<32)?len:32));
glVertex3fv(vector3_to_array(arrow));
glVertex3f(arrow[0]+s1[0], arrow[1]+s1[1], arrow[2]+dir[2]);
glVertex3fv(vector3_to_array(arrow));
glVertex3f(arrow[0]+s2[0], arrow[1]+s2[1], arrow[2]+dir[2]);
}
glEnd();
}
};
class TargetedEntity
{
Targetable& m_targetable;
targetables_t* m_targets;
void construct()
{
if(m_targets != 0)
m_targets->insert(&m_targetable);
}
void destroy()
{
if(m_targets != 0)
m_targets->erase(&m_targetable);
}
public:
TargetedEntity(Targetable& targetable)
: m_targetable(targetable), m_targets(getTargetables(""))
{
construct();
}
~TargetedEntity()
{
destroy();
}
void targetnameChanged(const char* name)
{
destroy();
m_targets = getTargetables(name);
construct();
}
typedef MemberCaller1<TargetedEntity, const char*, &TargetedEntity::targetnameChanged> TargetnameChangedCaller;
};
class TargetingEntity
{
targetables_t* m_targets;
public:
TargetingEntity() :
m_targets(getTargetables(""))
{
}
void targetChanged(const char* target)
{
m_targets = getTargetables(target);
}
typedef MemberCaller1<TargetingEntity, const char*, &TargetingEntity::targetChanged> TargetChangedCaller;
typedef targetables_t::iterator iterator;
iterator begin() const
{
if(m_targets == 0)
{
return iterator();
}
return m_targets->begin();
}
iterator end() const
{
if(m_targets == 0)
{
return iterator();
}
return m_targets->end();
}
size_t size() const
{
if(m_targets == 0)
{
return 0;
}
return m_targets->size();
}
bool empty() const
{
return m_targets == 0 || m_targets->empty();
}
};
template<typename Functor>
void TargetingEntity_forEach(const TargetingEntity& targets, const Functor& functor)
{
for(TargetingEntity::iterator i = targets.begin(); i != targets.end(); ++i)
{
functor((*i)->world_position());
}
}
typedef std::map<std::size_t, TargetingEntity> TargetingEntities;
template<typename Functor>
void TargetingEntities_forEach(const TargetingEntities& targetingEntities, const Functor& functor)
{
for(TargetingEntities::const_iterator i = targetingEntities.begin(); i != targetingEntities.end(); ++i)
{
TargetingEntity_forEach((*i).second, functor);
}
}
class TargetLinesPushBack
{
RenderablePointVector& m_targetLines;
const Vector3& m_worldPosition;
const VolumeTest& m_volume;
public:
TargetLinesPushBack(RenderablePointVector& targetLines, const Vector3& worldPosition, const VolumeTest& volume) :
m_targetLines(targetLines), m_worldPosition(worldPosition), m_volume(volume)
{
}
void operator()(const Vector3& worldPosition) const
{
if(m_volume.TestLine(segment_for_startend(m_worldPosition, worldPosition)))
{
m_targetLines.push_back(PointVertex(reinterpret_cast<const Vertex3f&>(m_worldPosition)));
m_targetLines.push_back(PointVertex(reinterpret_cast<const Vertex3f&>(worldPosition)));
}
}
};
class TargetKeys : public EntityKeyValues::Observer
{
TargetingEntities m_targetingEntities;
Callback m_targetsChanged;
bool readTargetKey(const char* key, std::size_t& index)
{
if(string_equal_n(key, "target", 6))
{
index = 0;
if(string_empty(key + 6) || string_parse_size(key + 6, index))
{
return true;
}
}
return false;
}
public:
void setTargetsChanged(const Callback& targetsChanged)
{
m_targetsChanged = targetsChanged;
}
void targetsChanged()
{
m_targetsChanged();
}
void insert(const char* key, EntityKeyValues::Value& value)
{
std::size_t index;
if(readTargetKey(key, index))
{
TargetingEntities::iterator i = m_targetingEntities.insert(TargetingEntities::value_type(index, TargetingEntity())).first;
value.attach(TargetingEntity::TargetChangedCaller((*i).second));
targetsChanged();
}
}
void erase(const char* key, EntityKeyValues::Value& value)
{
std::size_t index;
if(readTargetKey(key, index))
{
TargetingEntities::iterator i = m_targetingEntities.find(index);
value.detach(TargetingEntity::TargetChangedCaller((*i).second));
m_targetingEntities.erase(i);
targetsChanged();
}
}
const TargetingEntities& get() const
{
return m_targetingEntities;
}
};
class RenderableTargetingEntity
{
TargetingEntity& m_targets;
mutable RenderablePointVector m_target_lines;
public:
static Shader* m_state;
RenderableTargetingEntity(TargetingEntity& targets)
: m_targets(targets), m_target_lines(GL_LINES)
{
}
void compile(const VolumeTest& volume, const Vector3& world_position) const
{
m_target_lines.clear();
m_target_lines.reserve(m_targets.size() * 2);
TargetingEntity_forEach(m_targets, TargetLinesPushBack(m_target_lines, world_position, volume));
}
void render(Renderer& renderer, const VolumeTest& volume, const Vector3& world_position) const
{
if(!m_targets.empty())
{
compile(volume, world_position);
if(!m_target_lines.empty())
{
renderer.addRenderable(m_target_lines, g_matrix4_identity);
}
}
}
};
class RenderableTargetingEntities
{
const TargetingEntities& m_targets;
mutable RenderablePointVector m_target_lines;
public:
static Shader* m_state;
RenderableTargetingEntities(const TargetingEntities& targets)
: m_targets(targets), m_target_lines(GL_LINES)
{
}
void compile(const VolumeTest& volume, const Vector3& world_position) const
{
m_target_lines.clear();
TargetingEntities_forEach(m_targets, TargetLinesPushBack(m_target_lines, world_position, volume));
}
void render(Renderer& renderer, const VolumeTest& volume, const Vector3& world_position) const
{
if(!m_targets.empty())
{
compile(volume, world_position);
if(!m_target_lines.empty())
{
renderer.addRenderable(m_target_lines, g_matrix4_identity);
}
}
}
};
class TargetableInstance :
public SelectableInstance,
public Targetable,
public EntityKeyValues::Observer
{
mutable Vertex3f m_position;
EntityKeyValues& m_entity;
TargetKeys m_targeting;
TargetedEntity m_targeted;
RenderableTargetingEntities m_renderable;
public:
TargetableInstance(
const scene::Path& path,
scene::Instance* parent,
void* instance,
InstanceTypeCastTable& casts,
EntityKeyValues& entity,
Targetable& targetable
) :
SelectableInstance(path, parent, instance, casts),
m_entity(entity),
m_targeted(targetable),
m_renderable(m_targeting.get())
{
m_entity.attach(*this);
m_entity.attach(m_targeting);
}
~TargetableInstance()
{
m_entity.detach(m_targeting);
m_entity.detach(*this);
}
void setTargetsChanged(const Callback& targetsChanged)
{
m_targeting.setTargetsChanged(targetsChanged);
}
void targetsChanged()
{
m_targeting.targetsChanged();
}
void insert(const char* key, EntityKeyValues::Value& value)
{
if(string_equal(key, g_targetable_nameKey))
{
value.attach(TargetedEntity::TargetnameChangedCaller(m_targeted));
}
}
void erase(const char* key, EntityKeyValues::Value& value)
{
if(string_equal(key, g_targetable_nameKey))
{
value.detach(TargetedEntity::TargetnameChangedCaller(m_targeted));
}
}
const Vector3& world_position() const
{
#if 1
const AABB& bounds = Instance::worldAABB();
if(aabb_valid(bounds))
{
return bounds.origin;
}
#else
const AABB& childBounds = Instance::childBounds();
if(aabb_valid(childBounds))
{
return childBounds.origin;
}
#endif
return localToWorld().t();
}
void render(Renderer& renderer, const VolumeTest& volume) const
{
renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly);
renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eFullMaterials);
m_renderable.render(renderer, volume, world_position());
}
const TargetingEntities& getTargeting() const
{
return m_targeting.get();
}
};
class RenderableConnectionLines : public Renderable
{
typedef std::set<TargetableInstance*> TargetableInstances;
TargetableInstances m_instances;
public:
void attach(TargetableInstance& instance)
{
ASSERT_MESSAGE(m_instances.find(&instance) == m_instances.end(), "cannot attach instance");
m_instances.insert(&instance);
}
void detach(TargetableInstance& instance)
{
ASSERT_MESSAGE(m_instances.find(&instance) != m_instances.end(), "cannot detach instance");
m_instances.erase(&instance);
}
void renderSolid(Renderer& renderer, const VolumeTest& volume) const
{
for(TargetableInstances::const_iterator i = m_instances.begin(); i != m_instances.end(); ++i)
{
if((*i)->path().top().get().visible())
{
(*i)->render(renderer, volume);
}
}
}
void renderWireframe(Renderer& renderer, const VolumeTest& volume) const
{
renderSolid(renderer, volume);
}
};
typedef Static<RenderableConnectionLines> StaticRenderableConnectionLines;
#endif

8
plugins/image/.cvsignore Normal file
View File

@@ -0,0 +1,8 @@
Debug
Release
*.d
*.plg
*.BAK
*.mak
*.ncb
*.opt

207
plugins/image/bmp.cpp Normal file
View File

@@ -0,0 +1,207 @@
/*
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 "bmp.h"
#include "ifilesystem.h"
typedef unsigned char byte;
#include "imagelib.h"
#include "bytestreamutils.h"
typedef unsigned char PaletteEntry[4];
typedef struct
{
char id[2];
unsigned long fileSize;
unsigned long reserved0;
unsigned long bitmapDataOffset;
unsigned long bitmapHeaderSize;
unsigned long width;
unsigned long height;
unsigned short planes;
unsigned short bitsPerPixel;
unsigned long compression;
unsigned long bitmapDataSize;
unsigned long hRes;
unsigned long vRes;
unsigned long colors;
unsigned long importantColors;
PaletteEntry palette[256];
} BMPHeader_t;
class ReadPixel8
{
PaletteEntry* m_palette;
public:
ReadPixel8(PaletteEntry* palette) : m_palette(palette)
{
}
void operator()(PointerInputStream& inputStream, byte*& pixbuf) const
{
byte palIndex;
inputStream.read(&palIndex, 1);
*pixbuf++ = m_palette[palIndex][2];
*pixbuf++ = m_palette[palIndex][1];
*pixbuf++ = m_palette[palIndex][0];
*pixbuf++ = 0xff;
}
};
class ReadPixel16
{
public:
void operator()(PointerInputStream& inputStream, byte*& pixbuf) const
{
unsigned short shortPixel;
inputStream.read(reinterpret_cast<byte*>(&shortPixel), sizeof(unsigned short)); //!\todo Is this endian safe?
*pixbuf++ = static_cast<byte>(shortPixel & (31 << 10)) >> 7;
*pixbuf++ = static_cast<byte>(shortPixel & (31 << 5)) >> 2;
*pixbuf++ = static_cast<byte>(shortPixel & (31)) << 3;
*pixbuf++ = 0xff;
}
};
class ReadPixel24
{
public:
void operator()(PointerInputStream& inputStream, byte*& pixbuf) const
{
byte bgr[3];
inputStream.read(bgr, 3);
*pixbuf++ = bgr[2];
*pixbuf++ = bgr[1];
*pixbuf++ = bgr[0];
*pixbuf++ = 255;
}
};
class ReadPixel32
{
public:
void operator()(PointerInputStream& inputStream, byte*& pixbuf) const
{
byte bgra[4];
inputStream.read(bgra, 4);
*pixbuf++ = bgra[2];
*pixbuf++ = bgra[1];
*pixbuf++ = bgra[0];
*pixbuf++ = bgra[3];
}
};
template<typename ReadPixel>
void ReadBMP(PointerInputStream& inputStream, byte* bmpRGBA, int rows, int columns, ReadPixel readPixel)
{
for (int row = rows - 1; row >= 0; row--)
{
byte* pixbuf = bmpRGBA + row * columns * 4;
for (int column = 0; column < columns; column++)
{
readPixel(inputStream, pixbuf);
}
}
}
Image* LoadBMPBuff(PointerInputStream& inputStream, std::size_t length)
{
BMPHeader_t bmpHeader;
inputStream.read(reinterpret_cast<byte*>(bmpHeader.id), 2);
bmpHeader.fileSize = istream_read_uint32_le(inputStream);
bmpHeader.reserved0 = istream_read_uint32_le(inputStream);
bmpHeader.bitmapDataOffset = istream_read_uint32_le(inputStream);
bmpHeader.bitmapHeaderSize = istream_read_uint32_le(inputStream);
bmpHeader.width = istream_read_uint32_le(inputStream);
bmpHeader.height = istream_read_uint32_le(inputStream);
bmpHeader.planes = istream_read_uint16_le(inputStream);
bmpHeader.bitsPerPixel = istream_read_uint16_le(inputStream);
bmpHeader.compression = istream_read_uint32_le(inputStream);
bmpHeader.bitmapDataSize = istream_read_uint32_le(inputStream);
bmpHeader.hRes = istream_read_uint32_le(inputStream);
bmpHeader.vRes = istream_read_uint32_le(inputStream);
bmpHeader.colors = istream_read_uint32_le(inputStream);
bmpHeader.importantColors = istream_read_uint32_le(inputStream);
if (bmpHeader.bitsPerPixel == 8)
{
int paletteSize = bmpHeader.colors * 4;
inputStream.read(reinterpret_cast<byte*>(bmpHeader.palette), paletteSize);
}
if (bmpHeader.id[0] != 'B' && bmpHeader.id[1] != 'M')
{
globalErrorStream() << "LoadBMP: only Windows-style BMP files supported\n";
return 0;
}
if (bmpHeader.fileSize != length)
{
globalErrorStream() << "LoadBMP: header size does not match file size (" << Unsigned(bmpHeader.fileSize) << " vs. " << Unsigned(length) << ")\n";
return 0;
}
if (bmpHeader.compression != 0)
{
globalErrorStream() << "LoadBMP: only uncompressed BMP files supported\n";
return 0;
}
if (bmpHeader.bitsPerPixel < 8)
{
globalErrorStream() << "LoadBMP: monochrome and 4-bit BMP files not supported\n";
return 0;
}
int columns = bmpHeader.width;
int rows = bmpHeader.height;
if (rows < 0)
rows = -rows;
RGBAImage* image = new RGBAImage(columns, rows);
switch(bmpHeader.bitsPerPixel)
{
case 8:
ReadBMP(inputStream, image->getRGBAPixels(), rows, columns, ReadPixel8(bmpHeader.palette));
break;
case 16:
ReadBMP(inputStream, image->getRGBAPixels(), rows, columns, ReadPixel16());
break;
case 24:
ReadBMP(inputStream, image->getRGBAPixels(), rows, columns, ReadPixel24());
break;
case 32:
ReadBMP(inputStream, image->getRGBAPixels(), rows, columns, ReadPixel32());
break;
default:
globalErrorStream() << "LoadBMP: illegal pixel_size '" << bmpHeader.bitsPerPixel << "'\n";
image->release();
return 0;
}
return image;
}
Image* LoadBMP(ArchiveFile& file)
{
ScopedArchiveBuffer buffer(file);
PointerInputStream inputStream(buffer.buffer);
return LoadBMPBuff(inputStream, buffer.length);
}

31
plugins/image/bmp.h Normal file
View File

@@ -0,0 +1,31 @@
/*
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_BMP_H)
#define INCLUDED_BMP_H
class Image;
class ArchiveFile;
Image* LoadBMP(ArchiveFile& file);
#endif

56
plugins/image/dds.cpp Normal file
View File

@@ -0,0 +1,56 @@
/*
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 "dds.h"
#include <stdlib.h>
#include "ifilesystem.h"
#include "iarchive.h"
#include "idatastream.h"
#include "ddslib.h"
#include "imagelib.h"
Image* LoadDDSBuff(const byte* buffer)
{
int width, height;
ddsPF_t pixelFormat;
if(DDSGetInfo(reinterpret_cast<ddsBuffer_t*>(const_cast<byte*>(buffer)), &width, &height, &pixelFormat) == -1)
{
return 0;
}
RGBAImage* image = new RGBAImage(width, height);
if(DDSDecompress(reinterpret_cast<ddsBuffer_t*>(const_cast<byte*>(buffer)), image->getRGBAPixels()) == -1)
{
image->release();
return 0;
}
return image;
}
Image* LoadDDS(ArchiveFile& file)
{
ScopedArchiveBuffer buffer(file);
return LoadDDSBuff(buffer.buffer);
}

30
plugins/image/dds.h Normal file
View File

@@ -0,0 +1,30 @@
/*
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_DDS_H)
#define INCLUDED_DDS_H
class Image;
class ArchiveFile;
Image* LoadDDS(ArchiveFile& file);
#endif

162
plugins/image/image.cpp Normal file
View File

@@ -0,0 +1,162 @@
/*
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 "ifilesystem.h"
#include "iimage.h"
#include "jpeg.h"
#include "tga.h"
#include "bmp.h"
#include "pcx.h"
#include "dds.h"
#include "modulesystem/singletonmodule.h"
class ImageDependencies : public GlobalFileSystemModuleRef
{
};
class ImageTGAAPI
{
_QERPlugImageTable m_imagetga;
public:
typedef _QERPlugImageTable Type;
STRING_CONSTANT(Name, "tga");
ImageTGAAPI()
{
m_imagetga.loadImage = LoadTGA;
}
_QERPlugImageTable* getTable()
{
return &m_imagetga;
}
};
typedef SingletonModule<ImageTGAAPI> ImageTGAModule;
ImageTGAModule g_ImageTGAModule;
class ImageJPGAPI
{
_QERPlugImageTable m_imagejpg;
public:
typedef _QERPlugImageTable Type;
STRING_CONSTANT(Name, "jpg");
ImageJPGAPI()
{
m_imagejpg.loadImage = LoadJPG;
}
_QERPlugImageTable* getTable()
{
return &m_imagejpg;
}
};
typedef SingletonModule<ImageJPGAPI, ImageDependencies> ImageJPGModule;
ImageJPGModule g_ImageJPGModule;
class ImageBMPAPI
{
_QERPlugImageTable m_imagebmp;
public:
typedef _QERPlugImageTable Type;
STRING_CONSTANT(Name, "bmp");
ImageBMPAPI()
{
m_imagebmp.loadImage = LoadBMP;
}
_QERPlugImageTable* getTable()
{
return &m_imagebmp;
}
};
typedef SingletonModule<ImageBMPAPI, ImageDependencies> ImageBMPModule;
ImageBMPModule g_ImageBMPModule;
class ImagePCXAPI
{
_QERPlugImageTable m_imagepcx;
public:
typedef _QERPlugImageTable Type;
STRING_CONSTANT(Name, "pcx");
ImagePCXAPI()
{
m_imagepcx.loadImage = LoadPCX32;
}
_QERPlugImageTable* getTable()
{
return &m_imagepcx;
}
};
typedef SingletonModule<ImagePCXAPI, ImageDependencies> ImagePCXModule;
ImagePCXModule g_ImagePCXModule;
class ImageDDSAPI
{
_QERPlugImageTable m_imagedds;
public:
typedef _QERPlugImageTable Type;
STRING_CONSTANT(Name, "dds");
ImageDDSAPI()
{
m_imagedds.loadImage = LoadDDS;
}
_QERPlugImageTable* getTable()
{
return &m_imagedds;
}
};
typedef SingletonModule<ImageDDSAPI, ImageDependencies> ImageDDSModule;
ImageDDSModule g_ImageDDSModule;
extern "C" void RADIANT_DLLEXPORT Radiant_RegisterModules(ModuleServer& server)
{
GlobalErrorStream::instance().setOutputStream(server.getErrorStream());
GlobalOutputStream::instance().setOutputStream(server.getOutputStream());
GlobalDebugMessageHandler::instance().setHandler(server.getDebugMessageHandler());
GlobalModuleServer::instance().set(server);
g_ImageTGAModule.selfRegister();
g_ImageJPGModule.selfRegister();
g_ImageBMPModule.selfRegister();
g_ImagePCXModule.selfRegister();
g_ImageDDSModule.selfRegister();
}

166
plugins/image/image.dsp Normal file
View File

@@ -0,0 +1,166 @@
# Microsoft Developer Studio Project File - Name="image" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
CFG=image - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "image.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "image.mak" CFG="image - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "image - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "image - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName "image"
# PROP Scc_LocalPath "..\.."
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "image - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
F90=df.exe
# ADD BASE F90 /compile_only /include:"Release/" /libs:dll /nologo /warn:nofileopt /dll
# ADD F90 /compile_only /include:"Release/" /libs:dll /nologo /warn:nofileopt /dll
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "IMAGE_EXPORTS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /O2 /I "..\..\include" /I "..\..\..\gtk2-win32\include\glib-2.0" /I "..\..\..\gtk2-win32\lib\glib-2.0\include" /I "..\common" /I "..\..\libs" /I "..\..\libs\jpeg6" /I "..\..\..\STLPort\stlport" /I "..\..\..\libxml2\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "IMAGE_EXPORTS" /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
# ADD LINK32 glib-2.0.lib jpeg6.lib /nologo /dll /machine:I386 /def:".\image.def" /libpath:"../../libs/jpeg6/release" /libpath:"..\..\..\gtk2-win32\lib\\"
# SUBTRACT LINK32 /pdb:none
# Begin Special Build Tool
SOURCE="$(InputPath)"
PostBuild_Desc=Copy to dir...
PostBuild_Cmds=copy Release\image.dll "../../install/modules"
# End Special Build Tool
!ELSEIF "$(CFG)" == "image - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
F90=df.exe
# ADD BASE F90 /check:bounds /compile_only /debug:full /include:"Debug/" /libs:dll /nologo /warn:argument_checking /warn:nofileopt /dll
# ADD F90 /check:bounds /compile_only /debug:full /include:"Debug/" /libs:dll /nologo /warn:argument_checking /warn:nofileopt /dll
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "IMAGE_EXPORTS" /YX /FD /GZ /c
# ADD CPP /nologo /MDd /W3 /Gm /ZI /Od /I "..\..\include" /I "..\..\..\gtk2-win32\include\glib-2.0" /I "..\..\..\gtk2-win32\lib\glib-2.0\include" /I "..\common" /I "..\..\libs" /I "..\..\libs\jpeg6" /I "..\..\..\STLPort\stlport" /I "..\..\..\libxml2\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "IMAGE_EXPORTS" /YX /FD /GZ /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
# ADD LINK32 glib-2.0.lib jpeg6.lib /nologo /dll /debug /machine:I386 /def:".\image.def" /pdbtype:sept /libpath:"../../libs/jpeg6/debug" /libpath:"..\..\..\gtk2-win32\lib\\"
# SUBTRACT LINK32 /pdb:none
# Begin Special Build Tool
SOURCE="$(InputPath)"
PostBuild_Desc=Copy to dir...
PostBuild_Cmds=copy Debug\image.dll "../../install/modules"
# End Special Build Tool
!ENDIF
# Begin Target
# Name "image - Win32 Release"
# Name "image - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;f90;for;f;fpp"
# Begin Source File
SOURCE=.\bmp.cpp
# End Source File
# Begin Source File
SOURCE=.\image.cpp
# End Source File
# Begin Source File
SOURCE=.\image.def
# PROP Exclude_From_Build 1
# End Source File
# Begin Source File
SOURCE=.\jpeg.cpp
# End Source File
# Begin Source File
SOURCE=.\pcx.cpp
# End Source File
# Begin Source File
SOURCE=.\tga.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
# Begin Source File
SOURCE=.\bmp.h
# End Source File
# Begin Source File
SOURCE=.\image.h
# End Source File
# Begin Source File
SOURCE=.\jpeg.h
# End Source File
# Begin Source File
SOURCE=.\pcx.h
# End Source File
# Begin Source File
SOURCE=.\tga.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# End Target
# End Project

25
plugins/image/image.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_IMAGE_H)
#define INCLUDED_IMAGE_H
#endif

View File

@@ -0,0 +1,7 @@
; imageq3.def : Declares the module parameters for the DLL.
LIBRARY "ImageQ3"
EXPORTS
; Explicit exports can go here
Radiant_RegisterModules @1

View File

@@ -0,0 +1,231 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="imageq3"
ProjectGUID="{0A0D3519-2ADD-4B47-A890-746170B2CCD8}"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../../include;../../libs;&quot;../../../STLPort-4.6/stlport&quot;;&quot;../../../gtk2-2.4/include/glib-2.0&quot;;&quot;../../../gtk2-2.4/lib/glib-2.0/include&quot;"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;IMAGEQ3_EXPORTS"
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"
OutputFile="$(OutDir)/imageq3.dll"
LinkIncremental="1"
AdditionalLibraryDirectories=""
IgnoreDefaultLibraryNames="msvcprtd.lib"
ModuleDefinitionFile="$(ProjectName).def"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/imageq3.pdb"
SubSystem="2"
ImportLibrary="$(OutDir)/imageq3.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"
CommandLine="copy &quot;$(TargetPath)&quot; &quot;$(SolutionDir)install\modules&quot;
copy &quot;$(TargetDir)$(TargetName).pdb&quot; &quot;$(SolutionDir)install\modules&quot;"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<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="2"
CharacterSet="2"
WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
GlobalOptimizations="TRUE"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="TRUE"
FavorSizeOrSpeed="1"
OptimizeForWindowsApplication="FALSE"
AdditionalIncludeDirectories="../../include;../../libs;&quot;../../../STLPort-4.6/stlport&quot;;&quot;../../../gtk2-2.4/include/glib-2.0&quot;;&quot;../../../gtk2-2.4/lib/glib-2.0/include&quot;"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;IMAGEQ3_EXPORTS"
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"
OutputFile="$(OutDir)/imageq3.dll"
LinkIncremental="1"
AdditionalLibraryDirectories=""
IgnoreDefaultLibraryNames="msvcprt.lib"
ModuleDefinitionFile="$(ProjectName).def"
GenerateDebugInformation="TRUE"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
ImportLibrary="$(OutDir)/imageq3.lib"
TargetMachine="1"
FixedBaseAddress="0"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"
CommandLine="copy &quot;$(TargetPath)&quot; &quot;$(SolutionDir)install\modules&quot;
copy &quot;$(TargetDir)$(TargetName).pdb&quot; &quot;$(SolutionDir)install\modules&quot;"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="src"
Filter="">
<File
RelativePath=".\image.cpp">
</File>
<File
RelativePath=".\image.h">
</File>
<Filter
Name="modules"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
<File
RelativePath=".\bmp.cpp">
</File>
<File
RelativePath=".\bmp.h">
</File>
<File
RelativePath=".\dds.cpp">
</File>
<File
RelativePath=".\dds.h">
</File>
<File
RelativePath=".\jpeg.cpp">
</File>
<File
RelativePath=".\jpeg.h">
</File>
<File
RelativePath=".\pcx.cpp">
</File>
<File
RelativePath=".\pcx.h">
</File>
<File
RelativePath=".\tga.cpp">
</File>
<File
RelativePath=".\tga.h">
</File>
</Filter>
</Filter>
<File
RelativePath="..\..\debug.py">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCustomBuildTool"
CommandLine="python &quot;$(SolutionDir)debug.py&quot;"
AdditionalDependencies="&quot;$(SolutionDir)install\modules\$(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\modules\$(TargetName).pdb&quot;"
Outputs="&quot;$(TargetDir)$(TargetName).pdb&quot;"/>
</FileConfiguration>
</File>
<File
RelativePath=".\imageq3.def">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCustomBuildTool"
CommandLine="python &quot;$(SolutionDir)touch.py&quot; &quot;$(TargetPath)&quot;
"
AdditionalDependencies="&quot;$(SolutionDir)install\modules\$(TargetFileName)&quot;"
Outputs="&quot;$(TargetPath)&quot;"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCustomBuildTool"
CommandLine="python &quot;$(SolutionDir)touch.py&quot; &quot;$(TargetPath)&quot;
"
AdditionalDependencies="&quot;$(SolutionDir)install\modules\$(TargetFileName)&quot;"
Outputs="&quot;$(TargetPath)&quot;"/>
</FileConfiguration>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

406
plugins/image/jpeg.cpp Normal file
View File

@@ -0,0 +1,406 @@
/*
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.
*/
//
// Functions to load JPEG files from a buffer, based on jdatasrc.c
//
// Leonardo Zide (leo@lokigames.com)
//
#include "jpeg.h"
#include <setjmp.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
extern "C" {
#include "radiant_jpeglib.h"
#include "jpeg6/jerror.h"
}
#include "ifilesystem.h"
#include "imagelib.h"
typedef unsigned char byte;
/* Expanded data source object for stdio input */
typedef struct {
struct jpeg_source_mgr pub; /* public fields */
int src_size;
JOCTET * src_buffer;
JOCTET * buffer; /* start of buffer */
boolean start_of_file; /* have we gotten any data yet? */
} my_source_mgr;
typedef my_source_mgr * my_src_ptr;
#define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */
/*
* Initialize source --- called by jpeg_read_header
* before any data is actually read.
*/
static void my_init_source (j_decompress_ptr cinfo)
{
my_src_ptr src = (my_src_ptr) cinfo->src;
/* We reset the empty-input-file flag for each image,
* but we don't clear the input buffer.
* This is correct behavior for reading a series of images from one source.
*/
src->start_of_file = TRUE;
}
/*
* Fill the input buffer --- called whenever buffer is emptied.
*
* In typical applications, this should read fresh data into the buffer
* (ignoring the current state of next_input_byte & bytes_in_buffer),
* reset the pointer & count to the start of the buffer, and return TRUE
* indicating that the buffer has been reloaded. It is not necessary to
* fill the buffer entirely, only to obtain at least one more byte.
*
* There is no such thing as an EOF return. If the end of the file has been
* reached, the routine has a choice of ERREXIT() or inserting fake data into
* the buffer. In most cases, generating a warning message and inserting a
* fake EOI marker is the best course of action --- this will allow the
* decompressor to output however much of the image is there. However,
* the resulting error message is misleading if the real problem is an empty
* input file, so we handle that case specially.
*
* In applications that need to be able to suspend compression due to input
* not being available yet, a FALSE return indicates that no more data can be
* obtained right now, but more may be forthcoming later. In this situation,
* the decompressor will return to its caller (with an indication of the
* number of scanlines it has read, if any). The application should resume
* decompression after it has loaded more data into the input buffer. Note
* that there are substantial restrictions on the use of suspension --- see
* the documentation.
*
* When suspending, the decompressor will back up to a convenient restart point
* (typically the start of the current MCU). next_input_byte & bytes_in_buffer
* indicate where the restart point will be if the current call returns FALSE.
* Data beyond this point must be rescanned after resumption, so move it to
* the front of the buffer rather than discarding it.
*/
static boolean my_fill_input_buffer (j_decompress_ptr cinfo)
{
my_src_ptr src = (my_src_ptr) cinfo->src;
size_t nbytes;
if (src->src_size > INPUT_BUF_SIZE)
nbytes = INPUT_BUF_SIZE;
else
nbytes = src->src_size;
memcpy (src->buffer, src->src_buffer, nbytes);
src->src_buffer += nbytes;
src->src_size -= nbytes;
if (nbytes <= 0) {
if (src->start_of_file) /* Treat empty input file as fatal error */
ERREXIT(cinfo, JERR_INPUT_EMPTY);
WARNMS(cinfo, JWRN_JPEG_EOF);
/* Insert a fake EOI marker */
src->buffer[0] = (JOCTET) 0xFF;
src->buffer[1] = (JOCTET) JPEG_EOI;
nbytes = 2;
}
src->pub.next_input_byte = src->buffer;
src->pub.bytes_in_buffer = nbytes;
src->start_of_file = FALSE;
return TRUE;
}
/*
* Skip data --- used to skip over a potentially large amount of
* uninteresting data (such as an APPn marker).
*
* Writers of suspendable-input applications must note that skip_input_data
* is not granted the right to give a suspension return. If the skip extends
* beyond the data currently in the buffer, the buffer can be marked empty so
* that the next read will cause a fill_input_buffer call that can suspend.
* Arranging for additional bytes to be discarded before reloading the input
* buffer is the application writer's problem.
*/
static void my_skip_input_data (j_decompress_ptr cinfo, long num_bytes)
{
my_src_ptr src = (my_src_ptr) cinfo->src;
/* Just a dumb implementation for now. Could use fseek() except
* it doesn't work on pipes. Not clear that being smart is worth
* any trouble anyway --- large skips are infrequent.
*/
if (num_bytes > 0) {
while (num_bytes > (long) src->pub.bytes_in_buffer) {
num_bytes -= (long) src->pub.bytes_in_buffer;
(void) my_fill_input_buffer(cinfo);
/* note we assume that fill_input_buffer will never return FALSE,
* so suspension need not be handled.
*/
}
src->pub.next_input_byte += (size_t) num_bytes;
src->pub.bytes_in_buffer -= (size_t) num_bytes;
}
}
/*
* An additional method that can be provided by data source modules is the
* resync_to_restart method for error recovery in the presence of RST markers.
* For the moment, this source module just uses the default resync method
* provided by the JPEG library. That method assumes that no backtracking
* is possible.
*/
/*
* Terminate source --- called by jpeg_finish_decompress
* after all data has been read. Often a no-op.
*
* NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
* application must deal with any cleanup that should happen even
* for error exit.
*/
static void my_term_source (j_decompress_ptr cinfo)
{
/* no work necessary here */
}
/*
* Prepare for input from a stdio stream.
* The caller must have already opened the stream, and is responsible
* for closing it after finishing decompression.
*/
static void jpeg_buffer_src (j_decompress_ptr cinfo, void* buffer, int bufsize)
{
my_src_ptr src;
/* The source object and input buffer are made permanent so that a series
* of JPEG images can be read from the same file by calling jpeg_stdio_src
* only before the first one. (If we discarded the buffer at the end of
* one image, we'd likely lose the start of the next one.)
* This makes it unsafe to use this manager and a different source
* manager serially with the same JPEG object. Caveat programmer.
*/
if (cinfo->src == NULL) { /* first time for this JPEG object? */
cinfo->src = (struct jpeg_source_mgr *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
sizeof (my_source_mgr));
src = (my_src_ptr) cinfo->src;
src->buffer = (JOCTET *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
INPUT_BUF_SIZE * sizeof (JOCTET));
}
src = (my_src_ptr) cinfo->src;
src->pub.init_source = my_init_source;
src->pub.fill_input_buffer = my_fill_input_buffer;
src->pub.skip_input_data = my_skip_input_data;
src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
src->pub.term_source = my_term_source;
src->src_buffer = (JOCTET *)buffer;
src->src_size = bufsize;
src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
src->pub.next_input_byte = NULL; /* until buffer loaded */
}
// =============================================================================
static char errormsg[JMSG_LENGTH_MAX];
typedef struct my_jpeg_error_mgr
{
struct jpeg_error_mgr pub; // "public" fields
jmp_buf setjmp_buffer; // for return to caller
} bt_jpeg_error_mgr;
static void my_jpeg_error_exit (j_common_ptr cinfo)
{
my_jpeg_error_mgr* myerr = (bt_jpeg_error_mgr*) cinfo->err;
(*cinfo->err->format_message) (cinfo, errormsg);
longjmp (myerr->setjmp_buffer, 1);
}
// stash a scanline
static void j_putRGBScanline (unsigned char* jpegline, int widthPix, unsigned char* outBuf, int row)
{
int offset = row * widthPix * 4;
int count;
for (count = 0; count < widthPix; count++)
{
unsigned char iRed, iBlu, iGrn;
unsigned char *oRed, *oBlu, *oGrn, *oAlp;
iRed = *(jpegline + count * 3 + 0);
iGrn = *(jpegline + count * 3 + 1);
iBlu = *(jpegline + count * 3 + 2);
oRed = outBuf + offset + count * 4 + 0;
oGrn = outBuf + offset + count * 4 + 1;
oBlu = outBuf + offset + count * 4 + 2;
oAlp = outBuf + offset + count * 4 + 3;
*oRed = iRed;
*oGrn = iGrn;
*oBlu = iBlu;
*oAlp = 255;
}
}
// stash a scanline
static void j_putRGBAScanline (unsigned char* jpegline, int widthPix, unsigned char* outBuf, int row)
{
int offset = row * widthPix * 4;
int count;
for (count = 0; count < widthPix; count++)
{
unsigned char iRed, iBlu, iGrn, iAlp;
unsigned char *oRed, *oBlu, *oGrn, *oAlp;
iRed = *(jpegline + count * 4 + 0);
iGrn = *(jpegline + count * 4 + 1);
iBlu = *(jpegline + count * 4 + 2);
iAlp = *(jpegline + count * 4 + 3);
oRed = outBuf + offset + count * 4 + 0;
oGrn = outBuf + offset + count * 4 + 1;
oBlu = outBuf + offset + count * 4 + 2;
oAlp = outBuf + offset + count * 4 + 3;
*oRed = iRed;
*oGrn = iGrn;
*oBlu = iBlu;
//!\todo fix jpeglib, it leaves alpha channel uninitialised
#if 1
*oAlp = 255;
#else
*oAlp = iAlp;
#endif
}
}
// stash a gray scanline
static void j_putGrayScanlineToRGB (unsigned char* jpegline, int widthPix, unsigned char* outBuf, int row)
{
int offset = row * widthPix * 4;
int count;
for (count = 0; count < widthPix; count++)
{
unsigned char iGray;
unsigned char *oRed, *oBlu, *oGrn, *oAlp;
// get our grayscale value
iGray = *(jpegline + count);
oRed = outBuf + offset + count * 4;
oGrn = outBuf + offset + count * 4 + 1;
oBlu = outBuf + offset + count * 4 + 2;
oAlp = outBuf + offset + count * 4 + 3;
*oRed = iGray;
*oGrn = iGray;
*oBlu = iGray;
*oAlp = 255;
}
}
static Image* LoadJPGBuff_(const void *src_buffer, int src_size)
{
struct jpeg_decompress_struct cinfo;
struct my_jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error (&jerr.pub);
jerr.pub.error_exit = my_jpeg_error_exit;
if (setjmp (jerr.setjmp_buffer)) //< TODO: use c++ exceptions instead of setjmp/longjmp to handle errors
{
globalErrorStream() << "WARNING: JPEG library error: " << errormsg << "\n";
jpeg_destroy_decompress (&cinfo);
return 0;
}
jpeg_create_decompress (&cinfo);
jpeg_buffer_src (&cinfo, const_cast<void*>(src_buffer), src_size);
jpeg_read_header (&cinfo, TRUE);
jpeg_start_decompress (&cinfo);
int row_stride = cinfo.output_width * cinfo.output_components;
RGBAImage* image = new RGBAImage(cinfo.output_width, cinfo.output_height);
JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
while (cinfo.output_scanline < cinfo.output_height)
{
jpeg_read_scanlines (&cinfo, buffer, 1);
if (cinfo.out_color_components == 4)
j_putRGBAScanline (buffer[0], cinfo.output_width, image->getRGBAPixels(), cinfo.output_scanline-1);
else if (cinfo.out_color_components == 3)
j_putRGBScanline (buffer[0], cinfo.output_width, image->getRGBAPixels(), cinfo.output_scanline-1);
else if (cinfo.out_color_components == 1)
j_putGrayScanlineToRGB (buffer[0], cinfo.output_width, image->getRGBAPixels(), cinfo.output_scanline-1);
}
jpeg_finish_decompress (&cinfo);
jpeg_destroy_decompress (&cinfo);
return image;
}
Image* LoadJPG(ArchiveFile& file)
{
ScopedArchiveBuffer buffer(file);
return LoadJPGBuff_(buffer.buffer, static_cast<int>(buffer.length));
}

40
plugins/image/jpeg.h Normal file
View File

@@ -0,0 +1,40 @@
/*
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_JPEG_H)
#define INCLUDED_JPEG_H
class Image;
class ArchiveFile;
Image* LoadJPG(ArchiveFile& file);
#endif

222
plugins/image/pcx.cpp Normal file
View File

@@ -0,0 +1,222 @@
/*
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 "pcx.h"
#include "ifilesystem.h"
typedef unsigned char byte;
#include <stdlib.h>
#include "imagelib.h"
#include "bytestreamutils.h"
/*
=================================================================
PCX LOADING
=================================================================
*/
typedef struct
{
unsigned char manufacturer;
unsigned char version;
unsigned char encoding;
unsigned char bits_per_pixel;
unsigned short xmin, ymin, xmax, ymax;
unsigned short hres, vres;
unsigned char palette[48];
unsigned char reserved;
unsigned char color_planes;
unsigned short bytes_per_line;
unsigned short palette_type;
unsigned char filler[58];
unsigned char data; // unbounded
} pcx_t;
/*
==============
LoadPCX
==============
*/
struct PCXRLEPacket
{
byte data;
int length;
};
inline void ByteStream_readPCXRLEPacket(PointerInputStream& inputStream, PCXRLEPacket& packet)
{
byte d;
inputStream.read(&d, 1);
if((d & 0xC0) == 0xC0)
{
packet.length = d & 0x3F;
inputStream.read(&packet.data, 1);
}
else
{
packet.length = 1;
packet.data = d;
}
}
void LoadPCXBuff(byte* buffer, std::size_t len, byte **pic, byte **palette, int *width, int *height )
{
*pic = 0;
pcx_t pcx;
int x, y, lsize;
byte *out, *pix;
/* parse the PCX file */
PointerInputStream inputStream(buffer);
pcx.manufacturer = istream_read_byte(inputStream);
pcx.version = istream_read_byte(inputStream);
pcx.encoding = istream_read_byte(inputStream);
pcx.bits_per_pixel = istream_read_byte(inputStream);
pcx.xmin = istream_read_int16_le(inputStream);
pcx.ymin = istream_read_int16_le(inputStream);
pcx.xmax = istream_read_int16_le(inputStream);
pcx.ymax = istream_read_int16_le(inputStream);
pcx.hres = istream_read_int16_le(inputStream);
pcx.vres = istream_read_int16_le(inputStream);
inputStream.read(pcx.palette, 48);
pcx.reserved = istream_read_byte(inputStream);
pcx.color_planes = istream_read_byte(inputStream);
pcx.bytes_per_line = istream_read_int16_le(inputStream);
pcx.palette_type = istream_read_int16_le(inputStream);
inputStream.read(pcx.filler, 58);
if (pcx.manufacturer != 0x0a
|| pcx.version != 5
|| pcx.encoding != 1
|| pcx.bits_per_pixel != 8)
return;
if (width)
*width = pcx.xmax+1;
if (height)
*height = pcx.ymax+1;
if (!pic)
return;
out = (byte *)malloc ( (pcx.ymax+1) * (pcx.xmax+1) );
*pic = out;
pix = out;
/* RR2DO2: pcx fix */
lsize = pcx.color_planes * pcx.bytes_per_line;
/* go scanline by scanline */
for( y = 0; y <= pcx.ymax; y++, pix += pcx.xmax + 1 )
{
/* do a scanline */
for( x=0; x <= pcx.xmax; )
{
/* RR2DO2 */
PCXRLEPacket packet;
ByteStream_readPCXRLEPacket(inputStream, packet);
while(packet.length-- > 0)
{
pix[ x++ ] = packet.data;
}
}
/* RR2DO2: discard any other data */
PCXRLEPacket packet;
while( x < lsize )
{
ByteStream_readPCXRLEPacket(inputStream, packet);
x++;
}
while( packet.length-- > 0 )
{
x++;
}
}
/* validity check */
if( std::size_t(inputStream.get() - buffer) > len)
{
*pic = 0;
}
if (palette)
{
*palette = (byte *)malloc(768);
memcpy (*palette, buffer + len - 768, 768);
}
}
/*
==============
LoadPCX32
==============
*/
Image* LoadPCX32Buff(byte* buffer, std::size_t length)
{
byte *palette;
byte *pic8;
int i, c, p, width, height;
byte *pic32;
LoadPCXBuff(buffer, length, &pic8, &palette, &width, &height);
if (!pic8)
{
return 0;
}
RGBAImage* image = new RGBAImage(width, height);
c = (width) * (height);
pic32 = image->getRGBAPixels();
for (i = 0; i < c; i++)
{
p = pic8[i];
pic32[0] = palette[p * 3];
pic32[1] = palette[p * 3 + 1];
pic32[2] = palette[p * 3 + 2];
pic32[3] = 255;
pic32 += 4;
}
free (pic8);
free (palette);
return image;
}
Image* LoadPCX32(ArchiveFile& file)
{
ScopedArchiveBuffer buffer(file);
return LoadPCX32Buff(buffer.buffer, buffer.length);
}

30
plugins/image/pcx.h Normal file
View File

@@ -0,0 +1,30 @@
/*
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_PCX_H)
#define INCLUDED_PCX_H
class Image;
class ArchiveFile;
Image* LoadPCX32(ArchiveFile& file);
#endif

420
plugins/image/tga.cpp Normal file
View File

@@ -0,0 +1,420 @@
/*
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 "tga.h"
#include "ifilesystem.h"
#include "iarchive.h"
#include "idatastream.h"
typedef unsigned char byte;
#include <stdlib.h>
#include "generic/bitfield.h"
#include "imagelib.h"
#include "bytestreamutils.h"
// represents x,y origin of tga image being decoded
class Flip00 {}; // no flip
class Flip01 {}; // vertical flip only
class Flip10 {}; // horizontal flip only
class Flip11 {}; // both
template<typename PixelDecoder>
void image_decode(PointerInputStream& istream, PixelDecoder& decode, RGBAImage& image, const Flip00&)
{
RGBAPixel* end = image.pixels + (image.height * image.width);
for(RGBAPixel* row = end; row != image.pixels; row -= image.width)
{
for(RGBAPixel* pixel = row - image.width; pixel != row; ++pixel)
{
decode(istream, *pixel);
}
}
}
template<typename PixelDecoder>
void image_decode(PointerInputStream& istream, PixelDecoder& decode, RGBAImage& image, const Flip01&)
{
RGBAPixel* end = image.pixels + (image.height * image.width);
for(RGBAPixel* row = image.pixels; row != end; row += image.width)
{
for(RGBAPixel* pixel = row; pixel != row + image.width; ++pixel)
{
decode(istream, *pixel);
}
}
}
template<typename PixelDecoder>
void image_decode(PointerInputStream& istream, PixelDecoder& decode, RGBAImage& image, const Flip10&)
{
RGBAPixel* end = image.pixels + (image.height * image.width);
for(RGBAPixel* row = end; row != image.pixels; row -= image.width)
{
for(RGBAPixel* pixel = row; pixel != row - image.width;)
{
decode(istream, *--pixel);
}
}
}
template<typename PixelDecoder>
void image_decode(PointerInputStream& istream, PixelDecoder& decode, RGBAImage& image, const Flip11&)
{
RGBAPixel* end = image.pixels + (image.height * image.width);
for(RGBAPixel* row = image.pixels; row != end; row += image.width)
{
for(RGBAPixel* pixel = row + image.width; pixel != row;)
{
decode(istream, *--pixel);
}
}
}
inline void istream_read_gray(PointerInputStream& istream, RGBAPixel& pixel)
{
istream.read(&pixel.blue, 1);
pixel.red = pixel.green = pixel.blue;
pixel.alpha = 0xff;
}
inline void istream_read_rgb(PointerInputStream& istream, RGBAPixel& pixel)
{
istream.read(&pixel.blue, 1);
istream.read(&pixel.green, 1);
istream.read(&pixel.red, 1);
pixel.alpha = 0xff;
}
inline void istream_read_rgba(PointerInputStream& istream, RGBAPixel& pixel)
{
istream.read(&pixel.blue, 1);
istream.read(&pixel.green, 1);
istream.read(&pixel.red, 1);
istream.read(&pixel.alpha, 1);
}
class TargaDecodeGrayPixel
{
public:
void operator()(PointerInputStream& istream, RGBAPixel& pixel)
{
istream_read_gray(istream, pixel);
}
};
template<typename Flip>
void targa_decode_grayscale(PointerInputStream& istream, RGBAImage& image, const Flip& flip)
{
TargaDecodeGrayPixel decode;
image_decode(istream, decode, image, flip);
}
class TargaDecodeRGBPixel
{
public:
void operator()(PointerInputStream& istream, RGBAPixel& pixel)
{
istream_read_rgb(istream, pixel);
}
};
template<typename Flip>
void targa_decode_rgb(PointerInputStream& istream, RGBAImage& image, const Flip& flip)
{
TargaDecodeRGBPixel decode;
image_decode(istream, decode, image, flip);
}
class TargaDecodeRGBAPixel
{
public:
void operator()(PointerInputStream& istream, RGBAPixel& pixel)
{
istream_read_rgba(istream, pixel);
}
};
template<typename Flip>
void targa_decode_rgba(PointerInputStream& istream, RGBAImage& image, const Flip& flip)
{
TargaDecodeRGBAPixel decode;
image_decode(istream, decode, image, flip);
}
typedef byte TargaPacket;
typedef byte TargaPacketSize;
inline void targa_packet_read_istream(TargaPacket& packet, PointerInputStream& istream)
{
istream.read(&packet, 1);
}
inline bool targa_packet_is_rle(const TargaPacket& packet)
{
return (packet & 0x80) != 0;
}
inline TargaPacketSize targa_packet_size(const TargaPacket& packet)
{
return 1 + (packet & 0x7f);
}
class TargaDecodeRGBPixelRLE
{
TargaPacketSize m_packetSize;
RGBAPixel m_pixel;
TargaPacket m_packet;
public:
TargaDecodeRGBPixelRLE() : m_packetSize(0)
{
}
void operator()(PointerInputStream& istream, RGBAPixel& pixel)
{
if(m_packetSize == 0)
{
targa_packet_read_istream(m_packet, istream);
m_packetSize = targa_packet_size(m_packet);
if(targa_packet_is_rle(m_packet))
{
istream_read_rgb(istream, m_pixel);
}
}
if(targa_packet_is_rle(m_packet))
{
pixel = m_pixel;
}
else
{
istream_read_rgb(istream, pixel);
}
--m_packetSize;
}
};
template<typename Flip>
void targa_decode_rle_rgb(PointerInputStream& istream, RGBAImage& image, const Flip& flip)
{
TargaDecodeRGBPixelRLE decode;
image_decode(istream, decode, image, flip);
}
class TargaDecodeRGBAPixelRLE
{
TargaPacketSize m_packetSize;
RGBAPixel m_pixel;
TargaPacket m_packet;
public:
TargaDecodeRGBAPixelRLE() : m_packetSize(0)
{
}
void operator()(PointerInputStream& istream, RGBAPixel& pixel)
{
if(m_packetSize == 0)
{
targa_packet_read_istream(m_packet, istream);
m_packetSize = targa_packet_size(m_packet);
if(targa_packet_is_rle(m_packet))
{
istream_read_rgba(istream, m_pixel);
}
}
if(targa_packet_is_rle(m_packet))
{
pixel = m_pixel;
}
else
{
istream_read_rgba(istream, pixel);
}
--m_packetSize;
}
};
template<typename Flip>
void targa_decode_rle_rgba(PointerInputStream& istream, RGBAImage& image, const Flip& flip)
{
TargaDecodeRGBAPixelRLE decode;
image_decode(istream, decode, image, flip);
}
struct TargaHeader
{
unsigned char id_length, colormap_type, image_type;
unsigned short colormap_index, colormap_length;
unsigned char colormap_size;
unsigned short x_origin, y_origin, width, height;
unsigned char pixel_size, attributes;
};
inline void targa_header_read_istream(TargaHeader& targa_header, PointerInputStream& istream)
{
targa_header.id_length = istream_read_byte(istream);
targa_header.colormap_type = istream_read_byte(istream);
targa_header.image_type = istream_read_byte(istream);
targa_header.colormap_index = istream_read_int16_le(istream);
targa_header.colormap_length = istream_read_int16_le(istream);
targa_header.colormap_size = istream_read_byte(istream);
targa_header.x_origin = istream_read_int16_le(istream);
targa_header.y_origin = istream_read_int16_le(istream);
targa_header.width = istream_read_int16_le(istream);
targa_header.height = istream_read_int16_le(istream);
targa_header.pixel_size = istream_read_byte(istream);
targa_header.attributes = istream_read_byte(istream);
if (targa_header.id_length != 0)
istream.seek(targa_header.id_length); // skip TARGA image comment
}
template<typename Type>
class ScopeDelete
{
Type* m_value;
ScopeDelete(const ScopeDelete&);
ScopeDelete& operator=(const ScopeDelete&);
public:
ScopeDelete(Type* value) : m_value(value)
{
}
~ScopeDelete()
{
delete m_value;
}
Type* get_pointer() const
{
return m_value;
}
};
template<typename Flip>
Image* Targa_decodeImageData(const TargaHeader& targa_header, PointerInputStream& istream, const Flip& flip)
{
RGBAImage* image = new RGBAImage(targa_header.width, targa_header.height);
if (targa_header.image_type == 2 || targa_header.image_type == 3)
{
switch (targa_header.pixel_size)
{
case 8:
targa_decode_grayscale(istream, *image, flip);
break;
case 24:
targa_decode_rgb(istream, *image, flip);
break;
case 32:
targa_decode_rgba(istream, *image, flip);
break;
default:
globalErrorStream() << "LoadTGA: illegal pixel_size '" << targa_header.pixel_size << "'\n";
image->release();
return 0;
}
}
else if (targa_header.image_type == 10)
{
switch (targa_header.pixel_size)
{
case 24:
targa_decode_rle_rgb(istream, *image, flip);
break;
case 32:
targa_decode_rle_rgba(istream, *image, flip);
break;
default:
globalErrorStream() << "LoadTGA: illegal pixel_size '" << targa_header.pixel_size << "'\n";
image->release();
return 0;
}
}
return image;
}
const unsigned int TGA_FLIP_HORIZONTAL = 0x10;
const unsigned int TGA_FLIP_VERTICAL = 0x20;
Image* LoadTGABuff(const byte* buffer)
{
PointerInputStream istream(buffer);
TargaHeader targa_header;
targa_header_read_istream(targa_header, istream);
if (targa_header.image_type != 2 && targa_header.image_type != 10 && targa_header.image_type != 3)
{
globalErrorStream() << "LoadTGA: TGA type " << targa_header.image_type << " not supported\n";
globalErrorStream() << "LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n";
return 0;
}
if (targa_header.colormap_type != 0)
{
globalErrorStream() << "LoadTGA: colormaps not supported\n";
return 0;
}
if ((targa_header.pixel_size != 32 && targa_header.pixel_size != 24)
&& targa_header.image_type != 3)
{
globalErrorStream() << "LoadTGA: Only 32 or 24 bit images supported\n";
return 0;
}
if(!bitfield_enabled(targa_header.attributes, TGA_FLIP_HORIZONTAL)
&& !bitfield_enabled(targa_header.attributes, TGA_FLIP_VERTICAL))
{
return Targa_decodeImageData(targa_header, istream, Flip00());
}
if(!bitfield_enabled(targa_header.attributes, TGA_FLIP_HORIZONTAL)
&& bitfield_enabled(targa_header.attributes, TGA_FLIP_VERTICAL))
{
return Targa_decodeImageData(targa_header, istream, Flip01());
}
if(bitfield_enabled(targa_header.attributes, TGA_FLIP_HORIZONTAL)
&& !bitfield_enabled(targa_header.attributes, TGA_FLIP_VERTICAL))
{
return Targa_decodeImageData(targa_header, istream, Flip10());
}
if(bitfield_enabled(targa_header.attributes, TGA_FLIP_HORIZONTAL)
&& bitfield_enabled(targa_header.attributes, TGA_FLIP_VERTICAL))
{
return Targa_decodeImageData(targa_header, istream, Flip11());
}
// unreachable
return 0;
}
Image* LoadTGA(ArchiveFile& file)
{
ScopedArchiveBuffer buffer(file);
return LoadTGABuff(buffer.buffer);
}

31
plugins/image/tga.h Normal file
View File

@@ -0,0 +1,31 @@
/*
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_TGA_H)
#define INCLUDED_TGA_H
class Image;
class ArchiveFile;
Image* LoadTGA(ArchiveFile& file);
#endif

157
plugins/imagehl/hlw.cpp Normal file
View File

@@ -0,0 +1,157 @@
/*
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
*/
// by Hydra - hydra@hydras-world.com
//
// HLW = Half-Life-WAD, I don't know if the actual in data in the WAD files
// has it's own name, so I'm just calling the individal textures .HLW files :)
//
// Thanks to the guys that made Wally for releasing an example WAD loader.
// without it this would not have been possible.
#include "hlw.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
typedef unsigned char byte;
#include "ifilesystem.h"
#include "imagelib.h"
/*
============================================================================
HLW IMAGE
HalfLife WAD files contain files that look like this:
Mip section
First mip
Mip header
First mip (width * height)
Second mip (width * height / 4)
Third mip (width * height / 16)
Fourth mip (width * height / 64)
Palette size (WORD)
Palette (Palette size * 3)
Padding (WORD)
============================================================================
*/
#define GET_MIP_DATA_SIZE(WIDTH, HEIGHT) (sizeof(WAD3_MIP) + (WIDTH * HEIGHT) + (WIDTH * HEIGHT / 4) + (WIDTH * HEIGHT / 16) + (WIDTH * HEIGHT / 64))
typedef struct
{
char name[16];
unsigned int width, height;
unsigned int offsets[4]; // four mip maps stored
} WAD3_MIP, *LPWAD3_MIP;
/*
=========================================================
HLW LOADING
Hydra: this code isn't bullet proof and probably won't
like corrupt WAD files, but it works for now.
TODO: make it more robust.
=========================================================
*/
/*
=============
LoadHLW
=============
*/
Image* LoadHLWBuff(byte* buffer)
{
byte *buf_p;
unsigned long mipdatasize;
int columns, rows, numPixels;
byte *pixbuf;
int row, column;
byte *palette;
LPWAD3_MIP lpMip;
unsigned char red, green, blue, alphabyte;
lpMip = (LPWAD3_MIP)buffer; //!\todo Make endian-safe.
mipdatasize = GET_MIP_DATA_SIZE(lpMip->width,lpMip->height);
palette = buffer+mipdatasize+2;
buf_p = buffer+lpMip->offsets[0];
columns = lpMip->width;
rows = lpMip->height;
numPixels = columns * rows;
RGBAImage* image = new RGBAImage(columns, rows);
for (row = 0; row < rows; row++)
{
pixbuf = image->getRGBAPixels() + row * columns * 4;
for (column = 0; column < columns; column++)
{
int palIndex;
palIndex = *buf_p++;
red = *(palette+(palIndex*3));
green = *(palette+(palIndex*3)+1);
blue = *(palette+(palIndex*3)+2);
// HalfLife engine makes pixels that are BLUE transparent.
// So show them that way in the editor.
if (blue == 0xff && red == 0x00 && green == 0x00)
{
alphabyte = 0x00;
blue = 0x00; // don't set the resulting pixel to blue
}
else
{
alphabyte = 0xff;
}
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = alphabyte;
}
}
return image;
}
Image* LoadHLW(ArchiveFile& file)
{
ScopedArchiveBuffer buffer(file);
return LoadHLWBuff(buffer.buffer );
}

31
plugins/imagehl/hlw.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_HLW_H)
#define INCLUDED_HLW_H
class Image;
class ArchiveFile;
Image* LoadHLW(ArchiveFile& file);
#endif

116
plugins/imagehl/imagehl.cpp Normal file
View File

@@ -0,0 +1,116 @@
/*
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 "imagehl.h"
#include "debugging/debugging.h"
#include "ifilesystem.h"
#include "iimage.h"
#include "hlw.h"
#include "mip.h"
#include "sprite.h"
#include "modulesystem/singletonmodule.h"
class ImageDependencies : public GlobalFileSystemModuleRef
{
};
class ImageHLWAPI
{
_QERPlugImageTable m_imagehlw;
public:
typedef _QERPlugImageTable Type;
STRING_CONSTANT(Name, "hlw");
ImageHLWAPI()
{
m_imagehlw.loadImage = LoadHLW;
}
_QERPlugImageTable* getTable()
{
return &m_imagehlw;
}
};
typedef SingletonModule<ImageHLWAPI, ImageDependencies> ImageHLWModule;
ImageHLWModule g_ImageHLWModule;
class ImageMipAPI
{
_QERPlugImageTable m_imagemip;
public:
typedef _QERPlugImageTable Type;
STRING_CONSTANT(Name, "mip");
ImageMipAPI()
{
m_imagemip.loadImage = LoadMIP;
}
_QERPlugImageTable* getTable()
{
return &m_imagemip;
}
};
typedef SingletonModule<ImageMipAPI, ImageDependencies> ImageMipModule;
ImageMipModule g_ImageMipModule;
class ImageSpriteAPI
{
_QERPlugImageTable m_imagesprite;
public:
typedef _QERPlugImageTable Type;
STRING_CONSTANT(Name, "spr");
ImageSpriteAPI()
{
m_imagesprite.loadImage = LoadIDSP;
}
_QERPlugImageTable* getTable()
{
return &m_imagesprite;
}
};
typedef SingletonModule<ImageSpriteAPI, ImageDependencies> ImageSpriteModule;
ImageSpriteModule g_ImageSpriteModule;
extern "C" void RADIANT_DLLEXPORT Radiant_RegisterModules(ModuleServer& server)
{
GlobalErrorStream::instance().setOutputStream(server.getErrorStream());
GlobalOutputStream::instance().setOutputStream(server.getOutputStream());
GlobalDebugMessageHandler::instance().setHandler(server.getDebugMessageHandler());
GlobalModuleServer::instance().set(server);
g_ImageHLWModule.selfRegister();
g_ImageMipModule.selfRegister();
g_ImageSpriteModule.selfRegister();
}

View File

@@ -0,0 +1,7 @@
; imagehl.def : Declares the module parameters for the DLL.
LIBRARY "ImageHL"
EXPORTS
; Explicit exports can go here
Radiant_RegisterModules @1

174
plugins/imagehl/imagehl.dsp Normal file
View File

@@ -0,0 +1,174 @@
# Microsoft Developer Studio Project File - Name="imagehl" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
CFG=imagehl - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "imagehl.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "imagehl.mak" CFG="imagehl - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "imagehl - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "imagehl - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName "imagehl"
# PROP Scc_LocalPath "..\.."
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "imagehl - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
F90=df.exe
# ADD BASE F90 /compile_only /include:"Release/" /libs:dll /nologo /warn:nofileopt /dll
# ADD F90 /compile_only /include:"Release/" /libs:dll /nologo /warn:nofileopt /dll
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "IMAGE_EXPORTS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /O2 /I "..\..\include" /I "..\..\..\gtk2-win32\include\glib-2.0" /I "..\..\..\gtk2-win32\lib\glib-2.0\include" /I "..\common" /I "..\..\libs" /I "..\..\..\STLPort\stlport" /I "..\..\..\libxml2\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "IMAGE_EXPORTS" /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
# ADD LINK32 glib-2.0.lib /nologo /dll /machine:I386 /def:".\imagehl.def" /libpath:"..\..\..\gtk2-win32\lib\\"
# SUBTRACT LINK32 /pdb:none
# Begin Special Build Tool
SOURCE="$(InputPath)"
PostBuild_Desc=Copy to dir...
PostBuild_Cmds=copy Release\imagehl.dll "../../install/modules"
# End Special Build Tool
!ELSEIF "$(CFG)" == "imagehl - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
F90=df.exe
# ADD BASE F90 /check:bounds /compile_only /debug:full /include:"Debug/" /libs:dll /nologo /warn:argument_checking /warn:nofileopt /dll
# ADD F90 /check:bounds /compile_only /debug:full /include:"Debug/" /libs:dll /nologo /warn:argument_checking /warn:nofileopt /dll
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "IMAGE_EXPORTS" /YX /FD /GZ /c
# ADD CPP /nologo /MDd /W3 /Gm /ZI /Od /I "..\..\include" /I "..\..\..\gtk2-win32\include\glib-2.0" /I "..\..\..\gtk2-win32\lib\glib-2.0\include" /I "..\common" /I "..\..\libs" /I "..\..\..\STLPort\stlport" /I "..\..\..\libxml2\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "IMAGE_EXPORTS" /YX /FD /GZ /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
# ADD LINK32 glib-2.0.lib /nologo /dll /debug /machine:I386 /def:".\imagehl.def" /pdbtype:sept /libpath:"..\..\..\gtk2-win32\lib\\"
# SUBTRACT LINK32 /pdb:none
# Begin Special Build Tool
SOURCE="$(InputPath)"
PostBuild_Desc=Copy to dir...
PostBuild_Cmds=copy Debug\imagehl.dll "../../install/modules"
# End Special Build Tool
!ENDIF
# Begin Target
# Name "imagehl - Win32 Release"
# Name "imagehl - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;f90;for;f;fpp"
# Begin Source File
SOURCE=.\hlw.cpp
# End Source File
# Begin Source File
SOURCE=.\imagehl.cpp
# End Source File
# Begin Source File
SOURCE=.\imagehl.def
# PROP Exclude_From_Build 1
# End Source File
# Begin Source File
SOURCE=.\mip.cpp
# End Source File
# Begin Source File
SOURCE=.\sprite.cpp
# End Source File
# Begin Source File
SOURCE=.\wal.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
# Begin Source File
SOURCE=.\hlw.h
# End Source File
# Begin Source File
SOURCE=.\imagehl.h
# End Source File
# Begin Source File
SOURCE=.\mip.h
# End Source File
# Begin Source File
SOURCE=.\sprite.h
# End Source File
# Begin Source File
SOURCE=.\wal.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;txt"
# Begin Source File
SOURCE=.\imagehl.txt
# End Source File
# End Group
# Begin Source File
SOURCE=.\Conscript
# End Source File
# End Target
# End Project

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