mirror of
https://github.com/TTimo/GtkRadiant.git
synced 2025-02-10 10:21:15 +00:00
Merge remote branch 'upstream/master'
This commit is contained in:
commit
a9142e69d2
148 changed files with 57561 additions and 5857 deletions
|
@ -33,7 +33,7 @@ class Config:
|
|||
# platforms for which to assemble a setup
|
||||
self.setup_platforms = [ 'local', 'x86', 'x64', 'win32' ]
|
||||
# paks to assemble in the setup
|
||||
self.setup_packs = [ 'Q3Pack', 'UrTPack', 'UFOAIPack', 'Q2WPack', 'ReactionPack' ]
|
||||
self.setup_packs = [ 'Q3Pack', 'UrTPack', 'ETPack', ] # 'UFOAIPack', 'Q2WPack', 'ReactionPack' ]
|
||||
|
||||
def __repr__( self ):
|
||||
return 'config: target=%s config=%s' % ( self.target_selected, self.config_selected )
|
||||
|
@ -261,9 +261,8 @@ class Config:
|
|||
|
||||
def FetchGamePaks( self, path ):
|
||||
for pak in self.setup_packs:
|
||||
if ( pak == 'Q3Pack' or pak == 'UrTPack' or pak == 'UFOAIPack' or pak == 'Q2WPack' or pak == 'ReactionPack' ):
|
||||
svnurl = 'svn://svn.icculus.org/gtkradiant-gamepacks/%s/trunk' % pak
|
||||
self.CheckoutOrUpdate( svnurl, os.path.join( path, 'installs', pak ) )
|
||||
svnurl = 'svn://svn.icculus.org/gtkradiant-gamepacks/%s/trunk' % pak
|
||||
self.CheckoutOrUpdate( svnurl, os.path.join( path, 'installs', pak ) )
|
||||
|
||||
def CopyTree( self, src, dst):
|
||||
for root, dirs, files in os.walk( src ):
|
||||
|
|
|
@ -209,7 +209,7 @@ DIR * findHandle;
|
|||
#endif
|
||||
};
|
||||
|
||||
bool CopyTree( const char* source, const char* dest );
|
||||
bool radCopyTree( const char* source, const char* dest, bool fatal_on_error = true );
|
||||
|
||||
typedef enum {
|
||||
PATH_FAIL, // stat call failed (does not exist is likely)
|
||||
|
@ -220,7 +220,7 @@ typedef enum {
|
|||
// check a path for existence, return directory / file
|
||||
EPathCheck CheckFile( const char *path );
|
||||
|
||||
bool radCreateDirectory( const char *directory );
|
||||
bool radCopyFile( const char *lpExistingFileName, const char *lpNewFileName );
|
||||
bool radCreateDirectory( const char *directory, bool fatal_on_error = true );
|
||||
bool radCopyFile( const char *lpExistingFileName, const char *lpNewFileName, bool fatal_on_error = true );
|
||||
|
||||
#endif // _MISSING_H_
|
||||
|
|
|
@ -48,12 +48,18 @@ void CPicoSurface::Draw( int state, IShader *pShader, int rflags ){
|
|||
|
||||
if ( !( rflags & ( DRAW_RF_SEL_OUTLINE | DRAW_RF_SEL_FILL | DRAW_RF_XY ) ) ) {
|
||||
if ( state & DRAW_GL_TEXTURE_2D ) {
|
||||
bool bTrans = ( pShader->getFlags() & QER_TRANS ) == QER_TRANS;
|
||||
bool bDrawBlend = ( state & DRAW_GL_BLEND ) == DRAW_GL_BLEND;
|
||||
//only draw transparent stuff when in transparent stuff pass and vice versa
|
||||
if(bTrans != bDrawBlend) {
|
||||
return;
|
||||
}
|
||||
g_QglTable.m_pfn_qglBindTexture( GL_TEXTURE_2D, pShader->getTexture()->texture_number );
|
||||
if ( ( rflags & DRAW_RF_CAM ) && ( pShader->getFlags() & QER_ALPHAFUNC ) ) {
|
||||
int nFunc = 0;
|
||||
float fRef = 0.f;
|
||||
|
||||
g_QglTable.m_pfn_qglColor4f( 1.f, 1.f, 1.f, 1.f ); // identity
|
||||
g_QglTable.m_pfn_qglColor4f( 1.f, 1.f, 1.f, pShader->getTrans() ); // transparency
|
||||
|
||||
g_QglTable.m_pfn_qglEnable( GL_ALPHA_TEST );
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -894,7 +894,11 @@ int main( int argc, char* argv[] ) {
|
|||
|
||||
g_pParentWnd = new MainFrame();
|
||||
|
||||
if ( g_PrefsDlg.m_bLoadLastMap && g_PrefsDlg.m_strLastMap.GetLength() > 0 ) {
|
||||
// If the first parameter is a .map, load that.
|
||||
if( g_argc > 1 && IsMap( g_argv[1] ) ){
|
||||
Map_LoadFile( g_argv[1] );
|
||||
}
|
||||
else if ( g_PrefsDlg.m_bLoadLastMap && g_PrefsDlg.m_strLastMap.GetLength() > 0 ) {
|
||||
Map_LoadFile( g_PrefsDlg.m_strLastMap.GetBuffer() );
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -2021,8 +2021,10 @@ static void mainframe_unmap( GtkWidget *widget ){
|
|||
|
||||
static GtkWidget* create_floating( MainFrame* mainframe ){
|
||||
GtkWidget *wnd = gtk_window_new( GTK_WINDOW_TOPLEVEL );
|
||||
//if (mainframe->CurrentStyle() != MainFrame::eFloating)
|
||||
gtk_window_set_transient_for( GTK_WINDOW( wnd ), GTK_WINDOW( mainframe->m_pWidget ) );
|
||||
//workaround for a bug with set_transient_for in GTK - resulting behaviour is not perfect but better than the bug.
|
||||
//(see https://bugzilla.gnome.org/show_bug.cgi?id=658975 regarding the bug)
|
||||
if (mainframe->CurrentStyle() != MainFrame::eFloating)
|
||||
gtk_window_set_transient_for( GTK_WINDOW( wnd ), GTK_WINDOW( mainframe->m_pWidget ) );
|
||||
gtk_widget_set_events( wnd, GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK );
|
||||
gtk_signal_connect( GTK_OBJECT( wnd ), "delete_event", GTK_SIGNAL_FUNC( widget_delete_hide ), NULL );
|
||||
gtk_signal_connect( GTK_OBJECT( wnd ), "destroy", GTK_SIGNAL_FUNC( gtk_widget_destroy ), NULL );
|
||||
|
@ -3619,9 +3621,14 @@ void MainFrame::ShowMenuItemKeyBindings( GtkWidget* window ){
|
|||
}
|
||||
}
|
||||
|
||||
// Checks whether a given filename ends in .map
|
||||
const bool IsMap(const char* filename){
|
||||
return strlen(filename) >= 4 && strcmp(filename + strlen(filename) - 4, ".map") == 0;
|
||||
}
|
||||
|
||||
void MainFrame::CreateQEChildren(){
|
||||
// load the project file
|
||||
if ( g_argc > 1 ) {
|
||||
// load the project file, if it is a project file. (Or at least no .map)
|
||||
if ( g_argc > 1 && !IsMap( g_argv[1] ) ) {
|
||||
Sys_Printf( "loading project file from the command line: %s\n", g_argv[1] );
|
||||
if ( !QE_LoadProject( g_argv[1] ) ) {
|
||||
Error( "Unable to load project file %s\n", g_argv[1] );
|
||||
|
|
|
@ -908,4 +908,7 @@ int gdk_offset_y;
|
|||
// some C API to the mainframe functions
|
||||
void WINAPI QERApp_Sleep();
|
||||
|
||||
// Checks whether a given filename ends in .map
|
||||
const bool IsMap(const char* filename);
|
||||
|
||||
#endif // _MAINFRAME_H_
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
|
||||
#include "missing.h"
|
||||
#include "qsysprintf.h"
|
||||
#include "qe3.h"
|
||||
|
||||
#if defined ( __linux__ ) || defined ( __APPLE__ )
|
||||
|
||||
|
@ -47,7 +48,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <dirent.h>
|
||||
|
||||
bool radCopyFile( const char *lpExistingFileName, const char *lpNewFileName ){
|
||||
bool radCopyFile( const char *lpExistingFileName, const char *lpNewFileName, bool fatal_on_error ){
|
||||
FILE *src, *dst;
|
||||
void* buf;
|
||||
int l;
|
||||
|
@ -59,12 +60,20 @@ bool radCopyFile( const char *lpExistingFileName, const char *lpNewFileName ){
|
|||
|
||||
src = fopen( realsrc, "rb" );
|
||||
if ( !src ) {
|
||||
return false;
|
||||
if ( fatal_on_error ) {
|
||||
Error( "Failed to open source for copy: %s\n", realsrc );
|
||||
}
|
||||
Sys_Printf( "Failed to open source for copy: %s\n", realsrc );
|
||||
return false;
|
||||
}
|
||||
dst = fopen( realdest, "wb" );
|
||||
if ( !dst ) {
|
||||
fclose( src );
|
||||
return false;
|
||||
if ( fatal_on_error ) {
|
||||
Error( "Failed to open destination for copy: %s\n", realdest );
|
||||
}
|
||||
Sys_Printf( "Failed to open destination for copy: %s\n", realdest );
|
||||
fclose( src );
|
||||
return false;
|
||||
}
|
||||
|
||||
fseek( src, 0, SEEK_END );
|
||||
|
@ -79,6 +88,12 @@ bool radCopyFile( const char *lpExistingFileName, const char *lpNewFileName ){
|
|||
}
|
||||
}
|
||||
}
|
||||
if ( !ret ) {
|
||||
if ( fatal_on_error ) {
|
||||
Error( "short read or short write while copying %s to %s\n", realsrc, realdest );
|
||||
}
|
||||
Sys_Printf( "short read or short write while copying %s to %s\n", realsrc, realdest );
|
||||
}
|
||||
|
||||
g_free( buf );
|
||||
fclose( src );
|
||||
|
@ -87,12 +102,15 @@ bool radCopyFile( const char *lpExistingFileName, const char *lpNewFileName ){
|
|||
return ret;
|
||||
}
|
||||
|
||||
bool radCreateDirectory( const char *directory ) {
|
||||
if ( mkdir( directory, 0777 ) == -1 ) {
|
||||
Sys_Printf( "mkdir %s failed\n", directory );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
bool radCreateDirectory( const char *directory, bool fatal_on_error ) {
|
||||
if ( mkdir( directory, 0777 ) >= 0 ) {
|
||||
return true;
|
||||
}
|
||||
if ( fatal_on_error ) {
|
||||
Error( "mkdir %s failed - check your permissions", directory );
|
||||
}
|
||||
Sys_Printf( "mkdir %s failed - check your permissions\n", directory );
|
||||
return false;
|
||||
}
|
||||
|
||||
int GetFullPathName( const char *lpFileName, int nBufferLength, char *lpBuffer, char **lpFilePart ){
|
||||
|
@ -219,17 +237,31 @@ EPathCheck CheckFile( const char *path ) {
|
|||
return PATH_FILE;
|
||||
}
|
||||
|
||||
bool radCreateDirectory( const char *directory ) {
|
||||
return ( CreateDirectory( directory, NULL ) != false );
|
||||
bool radCreateDirectory( const char *directory, bool fatal_on_error ) {
|
||||
if ( CreateDirectory( directory, NULL ) ) {
|
||||
return true;
|
||||
}
|
||||
if ( fatal_on_error ) {
|
||||
Error( "mkdir %s failed - check your permissions", directory );
|
||||
}
|
||||
Sys_Printf( "mkdir %s failed - check your permissions\n", directory );
|
||||
return false;
|
||||
}
|
||||
|
||||
bool radCopyFile( const char *lpExistingFileName, const char *lpNewFileName ) {
|
||||
return ( CopyFile( lpExistingFileName, lpNewFileName, FALSE ) != false );
|
||||
bool radCopyFile( const char *lpExistingFileName, const char *lpNewFileName, bool fatal_on_error ) {
|
||||
if ( CopyFile( lpExistingFileName, lpNewFileName, FALSE ) ) {
|
||||
return true;
|
||||
}
|
||||
if ( fatal_on_error ) {
|
||||
Error( "copy %s %s failed - check your permissions", lpExistingFileName, lpNewFileName );
|
||||
}
|
||||
Sys_Printf( "copy %s %s failed - check your permissions\n", lpExistingFileName, lpNewFileName );
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool CopyTree( const char *source, const char *dest ) {
|
||||
bool radCopyTree( const char *source, const char *dest, bool fatal_on_error ) {
|
||||
Str srcEntry;
|
||||
Str dstEntry;
|
||||
const char *dirname;
|
||||
|
@ -249,23 +281,28 @@ bool CopyTree( const char *source, const char *dest ) {
|
|||
dstEntry += "/";
|
||||
dstEntry += dirname;
|
||||
switch ( CheckFile( srcEntry.GetBuffer() ) ) {
|
||||
case PATH_FAIL: {
|
||||
if ( fatal_on_error ) {
|
||||
Error( "%s does not exist. check your permissions", srcEntry.GetBuffer() );
|
||||
}
|
||||
}
|
||||
case PATH_DIRECTORY: {
|
||||
if ( CheckFile( dstEntry.GetBuffer() ) == PATH_FAIL ) {
|
||||
if ( !radCreateDirectory( dstEntry.GetBuffer() ) ) {
|
||||
Sys_Printf( "create directory %s failed\n", dstEntry.GetBuffer() );
|
||||
Sys_Printf( "Create directory %s\n", dstEntry.GetBuffer() );
|
||||
if ( !radCreateDirectory( dstEntry.GetBuffer(), fatal_on_error ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool ret;
|
||||
ret = CopyTree( srcEntry.GetBuffer(), dstEntry.GetBuffer() );
|
||||
ret = radCopyTree( srcEntry.GetBuffer(), dstEntry.GetBuffer(), fatal_on_error );
|
||||
if ( !ret ) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PATH_FILE: {
|
||||
Sys_Printf( "copy %s -> %s\n", srcEntry.GetBuffer(), dstEntry.GetBuffer() );
|
||||
bool ret = radCopyFile( srcEntry.GetBuffer(), dstEntry.GetBuffer() );
|
||||
Sys_Printf( "Copy %s -> %s\n", srcEntry.GetBuffer(), dstEntry.GetBuffer() );
|
||||
bool ret = radCopyFile( srcEntry.GetBuffer(), dstEntry.GetBuffer(), fatal_on_error );
|
||||
if ( !ret ) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -2029,6 +2029,7 @@ bool CSynapseClientRadiant::RequestAPI( APIDescriptor_t *pAPI ){
|
|||
pTable->m_pfnDeletePatch = &QERApp_DeletePatch;
|
||||
pTable->m_pfnCreatePatchHandle = &QERApp_CreatePatchHandle;
|
||||
pTable->m_pfnCommitPatchHandleToMap = &QERApp_CommitPatchHandleToMap;
|
||||
pTable->m_pfnCommitPatchHandleToEntity = &QERApp_CommitPatchHandleToEntity;
|
||||
pTable->m_pfnLoadImage = &QERApp_LoadImage;
|
||||
pTable->m_pfnMessageBox = >k_MessageBox;
|
||||
pTable->m_pfnFileDialog = &file_dialog;
|
||||
|
|
|
@ -2701,7 +2701,7 @@ void PrefsDlg::BuildDialog(){
|
|||
|
||||
// end new prefs dialog
|
||||
|
||||
void PrefsDlg::LoadTexdefPref( texdef_t* pTexdef, char* pName ){
|
||||
void PrefsDlg::LoadTexdefPref( texdef_t* pTexdef, const char* pName ){
|
||||
char buffer[256];
|
||||
|
||||
memset( pTexdef, 0, sizeof( texdef_t ) );
|
||||
|
@ -3335,6 +3335,9 @@ void CGameInstall::BuildDialog() {
|
|||
case GAME_REACTION:
|
||||
gtk_combo_box_append_text( GTK_COMBO_BOX( combo ), _( "Reaction Quake 3" ) );
|
||||
break;
|
||||
case GAME_ET:
|
||||
gtk_combo_box_append_text( GTK_COMBO_BOX( combo ), _( "Wolfenstein: Enemy Territory" ) );
|
||||
break;
|
||||
}
|
||||
iGame++;
|
||||
}
|
||||
|
@ -3408,11 +3411,46 @@ void CGameInstall::Run() {
|
|||
// write out the game file
|
||||
Str gameFilePath = g_strAppPath.GetBuffer();
|
||||
gameFilePath += "games/";
|
||||
if(CheckFile(gameFilePath) != PATH_DIRECTORY) {
|
||||
radCreateDirectory(gameFilePath);
|
||||
if ( CheckFile( gameFilePath ) != PATH_DIRECTORY ) {
|
||||
radCreateDirectory( gameFilePath );
|
||||
}
|
||||
gameFilePath += m_strName.GetBuffer();
|
||||
gameFilePath += ".game";
|
||||
|
||||
switch ( m_availGames[ m_nComboSelect ] ) {
|
||||
case GAME_Q2:
|
||||
gameFilePath += "q2.game";
|
||||
break;
|
||||
case GAME_Q3:
|
||||
gameFilePath += "q3.game";
|
||||
break;
|
||||
case GAME_URT:
|
||||
gameFilePath += "urt.game";
|
||||
break;
|
||||
case GAME_UFOAI:
|
||||
gameFilePath += "ufoai.game";
|
||||
break;
|
||||
case GAME_Q2W:
|
||||
gameFilePath += "q2w.game";
|
||||
break;
|
||||
case GAME_WARSOW:
|
||||
gameFilePath += "warsow.game";
|
||||
break;
|
||||
case GAME_NEXUIZ:
|
||||
gameFilePath += "nexuiz.game";
|
||||
break;
|
||||
case GAME_TREMULOUS:
|
||||
gameFilePath += "tremulous.game";
|
||||
break;
|
||||
case GAME_JA:
|
||||
gameFilePath += "ja.game";
|
||||
break;
|
||||
case GAME_REACTION:
|
||||
gameFilePath += "reaction.game";
|
||||
break;
|
||||
case GAME_ET:
|
||||
gameFilePath += "et.game";
|
||||
break;
|
||||
}
|
||||
|
||||
Sys_Printf( "game file: %s\n", gameFilePath.GetBuffer() );
|
||||
|
||||
FILE * fg = fopen( gameFilePath.GetBuffer(), "w" );
|
||||
|
@ -3431,7 +3469,7 @@ void CGameInstall::Run() {
|
|||
source += Q2_PACK;
|
||||
source += "/install/";
|
||||
Str dest = m_strEngine.GetBuffer();
|
||||
CopyTree( source.GetBuffer(), dest.GetBuffer() );
|
||||
radCopyTree( source.GetBuffer(), dest.GetBuffer() );
|
||||
fprintf( fg, " basegame=\"baseq2\"\n" );
|
||||
break;
|
||||
}
|
||||
|
@ -3443,7 +3481,7 @@ void CGameInstall::Run() {
|
|||
source += Q3_PACK;
|
||||
source += "/install/";
|
||||
Str dest = m_strEngine.GetBuffer();
|
||||
CopyTree( source.GetBuffer(), dest.GetBuffer() );
|
||||
radCopyTree( source.GetBuffer(), dest.GetBuffer() );
|
||||
// Hardcoded fix for "missing" shaderlist in gamepack
|
||||
dest += "/baseq3/scripts/shaderlist.txt";
|
||||
if(CheckFile(dest.GetBuffer()) != PATH_FILE) {
|
||||
|
@ -3461,7 +3499,7 @@ void CGameInstall::Run() {
|
|||
source += URT_PACK;
|
||||
source += "/install/";
|
||||
Str dest = m_strEngine.GetBuffer();
|
||||
CopyTree( source.GetBuffer(), dest.GetBuffer() );
|
||||
radCopyTree( source.GetBuffer(), dest.GetBuffer() );
|
||||
fprintf( fg, " basegame=\"q3ut4\"\n" );
|
||||
break;
|
||||
}
|
||||
|
@ -3473,7 +3511,7 @@ void CGameInstall::Run() {
|
|||
source += UFOAI_PACK;
|
||||
source += "/install/";
|
||||
Str dest = m_strEngine.GetBuffer();
|
||||
CopyTree( source.GetBuffer(), dest.GetBuffer() );
|
||||
radCopyTree( source.GetBuffer(), dest.GetBuffer() );
|
||||
fprintf( fg, " basegame=\"base\"\n" );
|
||||
break;
|
||||
}
|
||||
|
@ -3485,7 +3523,7 @@ void CGameInstall::Run() {
|
|||
source += Q2W_PACK;
|
||||
source += "/install/";
|
||||
Str dest = m_strEngine.GetBuffer();
|
||||
CopyTree( source.GetBuffer(), dest.GetBuffer() );
|
||||
radCopyTree( source.GetBuffer(), dest.GetBuffer() );
|
||||
fprintf( fg, " basegame=\"default\"\n" );
|
||||
break;
|
||||
}
|
||||
|
@ -3497,7 +3535,7 @@ void CGameInstall::Run() {
|
|||
source += WARSOW_PACK;
|
||||
source += "/install/";
|
||||
Str dest = m_strEngine.GetBuffer();
|
||||
CopyTree( source.GetBuffer(), dest.GetBuffer() );
|
||||
radCopyTree( source.GetBuffer(), dest.GetBuffer() );
|
||||
fprintf( fg, " basegame=\"basewsw\"\n" );
|
||||
break;
|
||||
}
|
||||
|
@ -3509,7 +3547,7 @@ void CGameInstall::Run() {
|
|||
source += NEXUIZ_PACK;
|
||||
source += "/install/";
|
||||
Str dest = m_strEngine.GetBuffer();
|
||||
CopyTree( source.GetBuffer(), dest.GetBuffer() );
|
||||
radCopyTree( source.GetBuffer(), dest.GetBuffer() );
|
||||
fprintf( fg, " basegame=\"data\"\n" );
|
||||
break;
|
||||
}
|
||||
|
@ -3521,7 +3559,7 @@ void CGameInstall::Run() {
|
|||
source += TREMULOUS_PACK;
|
||||
source += "/install/";
|
||||
Str dest = m_strEngine.GetBuffer();
|
||||
CopyTree( source.GetBuffer(), dest.GetBuffer() );
|
||||
radCopyTree( source.GetBuffer(), dest.GetBuffer() );
|
||||
fprintf( fg, " basegame=\"base\"\n" );
|
||||
break;
|
||||
}
|
||||
|
@ -3533,7 +3571,7 @@ void CGameInstall::Run() {
|
|||
source += JA_PACK;
|
||||
source += "/install/";
|
||||
Str dest = m_strEngine.GetBuffer();
|
||||
CopyTree( source.GetBuffer(), dest.GetBuffer() );
|
||||
radCopyTree( source.GetBuffer(), dest.GetBuffer() );
|
||||
fprintf( fg, " basegame=\"base\"\n" );
|
||||
break;
|
||||
}
|
||||
|
@ -3545,13 +3583,36 @@ void CGameInstall::Run() {
|
|||
source += REACTION_PACK;
|
||||
source += "/install/";
|
||||
Str dest = m_strEngine.GetBuffer();
|
||||
CopyTree( source.GetBuffer(), dest.GetBuffer() );
|
||||
radCopyTree( source.GetBuffer(), dest.GetBuffer() );
|
||||
fprintf( fg, " basegame=\"Boomstick\"\n" );
|
||||
fprintf( fg, " default_scale=\"0.5\"\n" ); // Superfluous because the default is already 0.5,
|
||||
// but demonstrates how to set the default texture scale
|
||||
// for a specific game.
|
||||
break;
|
||||
}
|
||||
case GAME_ET: {
|
||||
#ifdef _WIN32
|
||||
fprintf( fg, " "ENGINE_ATTRIBUTE "=\"ET.exe\"\n");
|
||||
#elif __linux__
|
||||
fprintf( fg, " "ENGINE_ATTRIBUTE "=\"et\"\n" );
|
||||
#endif
|
||||
fprintf( fg, " "TOOLS_ATTRIBUTE "=\"%sinstalls/"ET_PACK "/game\"\n", g_strAppPath.GetBuffer() );
|
||||
fprintf( fg, " prefix=\".etwolf\"\n" );
|
||||
Str source = g_strAppPath.GetBuffer();
|
||||
source += "installs/";
|
||||
source += ET_PACK;
|
||||
source += "/install/";
|
||||
Str dest = m_strEngine.GetBuffer();
|
||||
radCopyTree( source.GetBuffer(), dest.GetBuffer() );
|
||||
// Hardcoded fix for "missing" shaderlist in gamepack
|
||||
dest += "/etmain/scripts/shaderlist.txt";
|
||||
if(CheckFile(dest.GetBuffer()) != PATH_FILE) {
|
||||
source += "etmain/scripts/default_shaderlist.txt";
|
||||
radCopyFile(source.GetBuffer(),dest.GetBuffer());
|
||||
}
|
||||
fprintf( fg, " basegame=\"etmain\"\n" );
|
||||
break;
|
||||
}
|
||||
}
|
||||
fprintf( fg, "/>\n" );
|
||||
fclose( fg );
|
||||
|
@ -3601,6 +3662,9 @@ void CGameInstall::ScanGames() {
|
|||
if ( stricmp( dirname, REACTION_PACK ) == 0 ) {
|
||||
m_availGames[ iGame++ ] = GAME_REACTION;
|
||||
}
|
||||
if ( stricmp( dirname, ET_PACK ) == 0 ) {
|
||||
m_availGames[ iGame++ ] = GAME_ET;
|
||||
}
|
||||
}
|
||||
Sys_Printf( "No installable games found in: %s\n",
|
||||
pakPaths.GetBuffer() );
|
||||
|
|
|
@ -213,6 +213,7 @@ void Dump();
|
|||
#define TREMULOUS_PACK "TremulousPack"
|
||||
#define JA_PACK "JAPack"
|
||||
#define REACTION_PACK "ReactionPack"
|
||||
#define ET_PACK "ETPack"
|
||||
|
||||
class CGameInstall : public Dialog {
|
||||
public:
|
||||
|
@ -236,6 +237,7 @@ enum gameType_e {
|
|||
GAME_TREMULOUS,
|
||||
GAME_JA,
|
||||
GAME_REACTION,
|
||||
GAME_ET,
|
||||
GAME_COUNT
|
||||
};
|
||||
|
||||
|
@ -494,7 +496,7 @@ void UpdateNvidiaAeroHack();
|
|||
|
||||
void LoadPrefs();
|
||||
void SavePrefs();
|
||||
void LoadTexdefPref( texdef_t* pTexdef, char* pName );
|
||||
void LoadTexdefPref( texdef_t* pTexdef, const char* pName );
|
||||
|
||||
PrefsDlg ();
|
||||
virtual ~PrefsDlg (){
|
||||
|
|
281
tools/quake2/extra/COPYING.txt
Normal file
281
tools/quake2/extra/COPYING.txt
Normal file
|
@ -0,0 +1,281 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
72
tools/quake2/extra/Unpack/Unpack.dsp
Normal file
72
tools/quake2/extra/Unpack/Unpack.dsp
Normal file
|
@ -0,0 +1,72 @@
|
|||
# Microsoft Developer Studio Project File - Name="Unpack" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 5.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Java Virtual Machine Java Project" 0x0809
|
||||
|
||||
CFG=Unpack - Java Virtual Machine 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 "Unpack.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 "Unpack.mak" CFG="Unpack - Java Virtual Machine Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "Unpack - Java Virtual Machine Release" (based on\
|
||||
"Java Virtual Machine Java Project")
|
||||
!MESSAGE "Unpack - Java Virtual Machine Debug" (based on\
|
||||
"Java Virtual Machine Java Project")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
JAVA=jvc.exe
|
||||
|
||||
!IF "$(CFG)" == "Unpack - Java Virtual Machine Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir ""
|
||||
# PROP BASE Intermediate_Dir ""
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir ""
|
||||
# PROP Intermediate_Dir ""
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE JAVA /O
|
||||
# ADD JAVA /O
|
||||
|
||||
!ELSEIF "$(CFG)" == "Unpack - Java Virtual Machine Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir ""
|
||||
# PROP BASE Intermediate_Dir ""
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir ""
|
||||
# PROP Intermediate_Dir ""
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE JAVA /g
|
||||
# ADD JAVA /g
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "Unpack - Java Virtual Machine Release"
|
||||
# Name "Unpack - Java Virtual Machine Debug"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Unpack.java
|
||||
# End Source File
|
||||
# End Target
|
||||
# End Project
|
29
tools/quake2/extra/Unpack/Unpack.dsw
Normal file
29
tools/quake2/extra/Unpack/Unpack.dsw
Normal file
|
@ -0,0 +1,29 @@
|
|||
Microsoft Developer Studio Workspace File, Format Version 5.00
|
||||
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
|
||||
|
||||
###############################################################################
|
||||
|
||||
Project: "Unpack"=.\Unpack.dsp - Package Owner=<4>
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<4>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Global:
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<3>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
198
tools/quake2/extra/Unpack/Unpack.java
Normal file
198
tools/quake2/extra/Unpack/Unpack.java
Normal file
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
* Unpack -- a completely non-object oriented utility...
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
|
||||
class Unpack {
|
||||
static final int IDPAKHEADER = (('K'<<24)+('C'<<16)+('A'<<8)+'P');
|
||||
|
||||
static int intSwap(int i) {
|
||||
int a, b, c, d;
|
||||
|
||||
a = i & 255;
|
||||
b = (i >> 8) & 255;
|
||||
c = (i >> 16) & 255;
|
||||
d = (i >> 24) & 255;
|
||||
|
||||
return (a << 24) + (b << 16) + (c << 8) + d;
|
||||
}
|
||||
|
||||
static boolean patternMatch (String pattern, String s) {
|
||||
int index;
|
||||
int remaining;
|
||||
|
||||
if (pattern.equals(s)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// fairly lame single wildcard matching
|
||||
index = pattern.indexOf('*');
|
||||
if (index == -1) {
|
||||
return false;
|
||||
}
|
||||
if (!pattern.regionMatches(0, s, 0, index)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
index += 1; // skip the *
|
||||
remaining = pattern.length() - index;
|
||||
if (s.length() < remaining) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!pattern.regionMatches(index, s, s.length()-remaining, remaining)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void usage() {
|
||||
System.out.println ("Usage: unpack <packfile> <match> <basedir>");
|
||||
System.out.println (" or: unpack -list <packfile>");
|
||||
System.out.println ("<match> may contain a single * wildcard");
|
||||
System.exit (1);
|
||||
}
|
||||
|
||||
public static void main (String[] args) {
|
||||
int ident;
|
||||
int dirofs;
|
||||
int dirlen;
|
||||
int i;
|
||||
int numLumps;
|
||||
byte[] name = new byte[56];
|
||||
String nameString;
|
||||
int filepos;
|
||||
int filelen;
|
||||
RandomAccessFile readLump;
|
||||
DataInputStream directory;
|
||||
String pakName;
|
||||
String pattern;
|
||||
|
||||
if (args.length == 2) {
|
||||
if (!args[0].equals("-list")) {
|
||||
usage();
|
||||
}
|
||||
pakName = args[1];
|
||||
pattern = null;
|
||||
} else if (args.length == 3) {
|
||||
pakName = args[0];
|
||||
pattern = args[1];
|
||||
} else {
|
||||
pakName = null;
|
||||
pattern = null;
|
||||
usage ();
|
||||
}
|
||||
|
||||
try {
|
||||
// one stream to read the directory
|
||||
directory = new DataInputStream(new FileInputStream(pakName));
|
||||
|
||||
// another to read lumps
|
||||
readLump = new RandomAccessFile(pakName, "r");
|
||||
|
||||
// read the header
|
||||
ident = intSwap(directory.readInt());
|
||||
dirofs = intSwap(directory.readInt());
|
||||
dirlen = intSwap(directory.readInt());
|
||||
|
||||
if (ident != IDPAKHEADER) {
|
||||
System.out.println ( pakName + " is not a pakfile.");
|
||||
System.exit (1);
|
||||
}
|
||||
|
||||
// read the directory
|
||||
directory.skipBytes (dirofs - 12);
|
||||
numLumps = dirlen / 64;
|
||||
|
||||
System.out.println (numLumps + " lumps in " + pakName);
|
||||
|
||||
for (i = 0 ; i < numLumps ; i++) {
|
||||
directory.readFully(name);
|
||||
filepos = intSwap(directory.readInt());
|
||||
filelen = intSwap(directory.readInt());
|
||||
|
||||
nameString = new String (name, 0);
|
||||
// chop to the first 0 byte
|
||||
nameString = nameString.substring (0, nameString.indexOf(0));
|
||||
|
||||
if (pattern == null) {
|
||||
// listing mode
|
||||
System.out.println (nameString + " : " + filelen + "bytes");
|
||||
} else if (patternMatch (pattern, nameString) ) {
|
||||
File writeFile;
|
||||
DataOutputStream writeLump;
|
||||
byte[] buffer = new byte[filelen];
|
||||
StringBuffer fixedString;
|
||||
String finalName;
|
||||
int index;
|
||||
|
||||
System.out.println ("Unpaking " + nameString + " " + filelen
|
||||
+ " bytes");
|
||||
|
||||
// load the lump
|
||||
readLump.seek(filepos);
|
||||
readLump.readFully(buffer);
|
||||
|
||||
// quake uses forward slashes, but java requires
|
||||
// they only by the host's seperator, which
|
||||
// varies from win to unix
|
||||
fixedString = new StringBuffer (args[2] + File.separator + nameString);
|
||||
for (index = 0 ; index < fixedString.length() ; index++) {
|
||||
if (fixedString.charAt(index) == '/') {
|
||||
fixedString.setCharAt(index, File.separatorChar);
|
||||
}
|
||||
}
|
||||
finalName = fixedString.toString ();
|
||||
|
||||
index = finalName.lastIndexOf(File.separatorChar);
|
||||
if (index != -1) {
|
||||
String finalPath;
|
||||
File writePath;
|
||||
|
||||
finalPath = finalName.substring(0, index);
|
||||
writePath = new File (finalPath);
|
||||
writePath.mkdirs();
|
||||
}
|
||||
|
||||
writeFile = new File (finalName);
|
||||
writeLump = new DataOutputStream ( new FileOutputStream(writeFile) );
|
||||
writeLump.write(buffer);
|
||||
writeLump.close();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
readLump.close();
|
||||
directory.close();
|
||||
|
||||
} catch (IOException e) {
|
||||
System.out.println ( e.toString() );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
1776
tools/quake2/extra/bsp/bsp.mak
Normal file
1776
tools/quake2/extra/bsp/bsp.mak
Normal file
File diff suppressed because it is too large
Load diff
56
tools/quake2/extra/bsp/bspinfo3/bspinfo3.c
Normal file
56
tools/quake2/extra/bsp/bspinfo3/bspinfo3.c
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "cmdlib.h"
|
||||
#include "mathlib.h"
|
||||
#include "bspfile.h"
|
||||
|
||||
void main (int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
char source[1024];
|
||||
int size;
|
||||
FILE *f;
|
||||
|
||||
if (argc == 1)
|
||||
Error ("usage: bspinfo bspfile [bspfiles]");
|
||||
|
||||
for (i=1 ; i<argc ; i++)
|
||||
{
|
||||
printf ("---------------------\n");
|
||||
strcpy (source, argv[i]);
|
||||
DefaultExtension (source, ".bsp");
|
||||
f = fopen (source, "rb");
|
||||
if (f)
|
||||
{
|
||||
size = Q_filelength (f);
|
||||
fclose (f);
|
||||
}
|
||||
else
|
||||
size = 0;
|
||||
printf ("%s: %i\n", source, size);
|
||||
|
||||
LoadBSPFile (source);
|
||||
PrintBSPFileSizes ();
|
||||
printf ("---------------------\n");
|
||||
}
|
||||
}
|
53
tools/quake2/extra/bsp/bspinfo3/makefile
Normal file
53
tools/quake2/extra/bsp/bspinfo3/makefile
Normal file
|
@ -0,0 +1,53 @@
|
|||
|
||||
CFLAGS = -c
|
||||
LDFLAGS =
|
||||
ODIR = baddir
|
||||
|
||||
EXEBASE = bspinfo3
|
||||
EXE = $(ODIR)/bspinfo3
|
||||
all: $(EXE)
|
||||
|
||||
_next:
|
||||
make "CFLAGS = -c -g -I../../common -DDOUBLEVEC_T" "ODIR = next"
|
||||
|
||||
_irix:
|
||||
make "CFLAGS = -c -Ofast=ip32_10k -I../../common -Xcpluscomm -DDOUBLEVEC_T" "LDFLAGS = -Ofast=ip32_10k" "ODIR = irix"
|
||||
|
||||
_irixdebug:
|
||||
make "CFLAGS = -c -O2 -g -I../../common -Xcpluscomm -DDOUBLEVEC_T" "LDFLAGS = -g" "ODIR = irix"
|
||||
|
||||
_irixinst:
|
||||
make "CFLAGS = -c -Ofast=ip32_10k -I../../common -Xcpluscomm -DDOUBLEVEC_T" "LDFLAGS = -Ofast=ip32_10k" "ODIR = irix"
|
||||
cp irix/$(EXEBASE) /limbo/quake2/bin_irix
|
||||
|
||||
_irixclean:
|
||||
rm -f irix/*.o irix/$(EXEBASE)
|
||||
|
||||
_osf:
|
||||
make "CFLAGS = -c -O4 -I../../common -threads -DDOUBLEVEC_T" "LDFLAGS = -threads" "ODIR = osf"
|
||||
|
||||
clean:
|
||||
rm -f irix/*.o irix/$(EXEBASE)
|
||||
|
||||
install:
|
||||
cp irix/$(EXEBASE) /limbo/quake2/bin_irix
|
||||
|
||||
|
||||
FILES = $(ODIR)/bspinfo3.o $(ODIR)/bspfile.o $(ODIR)/cmdlib.o $(ODIR)/scriplib.o
|
||||
|
||||
$(EXE) : $(FILES)
|
||||
cc -o $(EXE) $(LDFLAGS) $(FILES)
|
||||
|
||||
$(ODIR)/bspinfo3.o : bspinfo3.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/cmdlib.o : ../../common/cmdlib.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/scriplib.o : ../../common/scriplib.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/bspfile.o : ../../common/bspfile.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
1330
tools/quake2/extra/bsp/qbsp3/brushbsp.c
Normal file
1330
tools/quake2/extra/bsp/qbsp3/brushbsp.c
Normal file
File diff suppressed because it is too large
Load diff
635
tools/quake2/extra/bsp/qbsp3/csg.c
Normal file
635
tools/quake2/extra/bsp/qbsp3/csg.c
Normal file
|
@ -0,0 +1,635 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "qbsp.h"
|
||||
|
||||
/*
|
||||
|
||||
tag all brushes with original contents
|
||||
brushes may contain multiple contents
|
||||
there will be no brush overlap after csg phase
|
||||
|
||||
|
||||
|
||||
|
||||
each side has a count of the other sides it splits
|
||||
|
||||
the best split will be the one that minimizes the total split counts
|
||||
of all remaining sides
|
||||
|
||||
precalc side on plane table
|
||||
|
||||
evaluate split side
|
||||
{
|
||||
cost = 0
|
||||
for all sides
|
||||
for all sides
|
||||
get
|
||||
if side splits side and splitside is on same child
|
||||
cost++;
|
||||
}
|
||||
|
||||
|
||||
*/
|
||||
|
||||
void SplitBrush2 (bspbrush_t *brush, int planenum,
|
||||
bspbrush_t **front, bspbrush_t **back)
|
||||
{
|
||||
SplitBrush (brush, planenum, front, back);
|
||||
#if 0
|
||||
if (*front && (*front)->sides[(*front)->numsides-1].texinfo == -1)
|
||||
(*front)->sides[(*front)->numsides-1].texinfo = (*front)->sides[0].texinfo; // not -1
|
||||
if (*back && (*back)->sides[(*back)->numsides-1].texinfo == -1)
|
||||
(*back)->sides[(*back)->numsides-1].texinfo = (*back)->sides[0].texinfo; // not -1
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SubtractBrush
|
||||
|
||||
Returns a list of brushes that remain after B is subtracted from A.
|
||||
May by empty if A is contained inside B.
|
||||
|
||||
The originals are undisturbed.
|
||||
===============
|
||||
*/
|
||||
bspbrush_t *SubtractBrush (bspbrush_t *a, bspbrush_t *b)
|
||||
{ // a - b = out (list)
|
||||
int i;
|
||||
bspbrush_t *front, *back;
|
||||
bspbrush_t *out, *in;
|
||||
|
||||
in = a;
|
||||
out = NULL;
|
||||
for (i=0 ; i<b->numsides && in ; i++)
|
||||
{
|
||||
SplitBrush2 (in, b->sides[i].planenum, &front, &back);
|
||||
if (in != a)
|
||||
FreeBrush (in);
|
||||
if (front)
|
||||
{ // add to list
|
||||
front->next = out;
|
||||
out = front;
|
||||
}
|
||||
in = back;
|
||||
}
|
||||
if (in)
|
||||
FreeBrush (in);
|
||||
else
|
||||
{ // didn't really intersect
|
||||
FreeBrushList (out);
|
||||
return a;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
IntersectBrush
|
||||
|
||||
Returns a single brush made up by the intersection of the
|
||||
two provided brushes, or NULL if they are disjoint.
|
||||
|
||||
The originals are undisturbed.
|
||||
===============
|
||||
*/
|
||||
bspbrush_t *IntersectBrush (bspbrush_t *a, bspbrush_t *b)
|
||||
{
|
||||
int i;
|
||||
bspbrush_t *front, *back;
|
||||
bspbrush_t *in;
|
||||
|
||||
in = a;
|
||||
for (i=0 ; i<b->numsides && in ; i++)
|
||||
{
|
||||
SplitBrush2 (in, b->sides[i].planenum, &front, &back);
|
||||
if (in != a)
|
||||
FreeBrush (in);
|
||||
if (front)
|
||||
FreeBrush (front);
|
||||
in = back;
|
||||
}
|
||||
|
||||
if (in == a)
|
||||
return NULL;
|
||||
|
||||
in->next = NULL;
|
||||
return in;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
BrushesDisjoint
|
||||
|
||||
Returns true if the two brushes definately do not intersect.
|
||||
There will be false negatives for some non-axial combinations.
|
||||
===============
|
||||
*/
|
||||
qboolean BrushesDisjoint (bspbrush_t *a, bspbrush_t *b)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
// check bounding boxes
|
||||
for (i=0 ; i<3 ; i++)
|
||||
if (a->mins[i] >= b->maxs[i]
|
||||
|| a->maxs[i] <= b->mins[i])
|
||||
return true; // bounding boxes don't overlap
|
||||
|
||||
// check for opposing planes
|
||||
for (i=0 ; i<a->numsides ; i++)
|
||||
{
|
||||
for (j=0 ; j<b->numsides ; j++)
|
||||
{
|
||||
if (a->sides[i].planenum ==
|
||||
(b->sides[j].planenum^1) )
|
||||
return true; // opposite planes, so not touching
|
||||
}
|
||||
}
|
||||
|
||||
return false; // might intersect
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
IntersectionContents
|
||||
|
||||
Returns a content word for the intersection of two brushes.
|
||||
Some combinations will generate a combination (water + clip),
|
||||
but most will be the stronger of the two contents.
|
||||
===============
|
||||
*/
|
||||
int IntersectionContents (int c1, int c2)
|
||||
{
|
||||
int out;
|
||||
|
||||
out = c1 | c2;
|
||||
|
||||
if (out & CONTENTS_SOLID)
|
||||
out = CONTENTS_SOLID;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
int minplanenums[3];
|
||||
int maxplanenums[3];
|
||||
|
||||
/*
|
||||
===============
|
||||
ClipBrushToBox
|
||||
|
||||
Any planes shared with the box edge will be set to no texinfo
|
||||
===============
|
||||
*/
|
||||
bspbrush_t *ClipBrushToBox (bspbrush_t *brush, vec3_t clipmins, vec3_t clipmaxs)
|
||||
{
|
||||
int i, j;
|
||||
bspbrush_t *front, *back;
|
||||
int p;
|
||||
|
||||
for (j=0 ; j<2 ; j++)
|
||||
{
|
||||
if (brush->maxs[j] > clipmaxs[j])
|
||||
{
|
||||
SplitBrush (brush, maxplanenums[j], &front, &back);
|
||||
if (front)
|
||||
FreeBrush (front);
|
||||
brush = back;
|
||||
if (!brush)
|
||||
return NULL;
|
||||
}
|
||||
if (brush->mins[j] < clipmins[j])
|
||||
{
|
||||
SplitBrush (brush, minplanenums[j], &front, &back);
|
||||
if (back)
|
||||
FreeBrush (back);
|
||||
brush = front;
|
||||
if (!brush)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// remove any colinear faces
|
||||
|
||||
for (i=0 ; i<brush->numsides ; i++)
|
||||
{
|
||||
p = brush->sides[i].planenum & ~1;
|
||||
if (p == maxplanenums[0] || p == maxplanenums[1]
|
||||
|| p == minplanenums[0] || p == minplanenums[1])
|
||||
{
|
||||
brush->sides[i].texinfo = TEXINFO_NODE;
|
||||
brush->sides[i].visible = false;
|
||||
}
|
||||
}
|
||||
return brush;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
MakeBspBrushList
|
||||
===============
|
||||
*/
|
||||
bspbrush_t *MakeBspBrushList (int startbrush, int endbrush,
|
||||
vec3_t clipmins, vec3_t clipmaxs)
|
||||
{
|
||||
mapbrush_t *mb;
|
||||
bspbrush_t *brushlist, *newbrush;
|
||||
int i, j;
|
||||
int c_faces;
|
||||
int c_brushes;
|
||||
int numsides;
|
||||
int vis;
|
||||
vec3_t normal;
|
||||
float dist;
|
||||
|
||||
for (i=0 ; i<2 ; i++)
|
||||
{
|
||||
VectorClear (normal);
|
||||
normal[i] = 1;
|
||||
dist = clipmaxs[i];
|
||||
maxplanenums[i] = FindFloatPlane (normal, dist);
|
||||
dist = clipmins[i];
|
||||
minplanenums[i] = FindFloatPlane (normal, dist);
|
||||
}
|
||||
|
||||
brushlist = NULL;
|
||||
c_faces = 0;
|
||||
c_brushes = 0;
|
||||
|
||||
for (i=startbrush ; i<endbrush ; i++)
|
||||
{
|
||||
mb = &mapbrushes[i];
|
||||
|
||||
numsides = mb->numsides;
|
||||
if (!numsides)
|
||||
continue;
|
||||
// make sure the brush has at least one face showing
|
||||
vis = 0;
|
||||
for (j=0 ; j<numsides ; j++)
|
||||
if (mb->original_sides[j].visible && mb->original_sides[j].winding)
|
||||
vis++;
|
||||
#if 0
|
||||
if (!vis)
|
||||
continue; // no faces at all
|
||||
#endif
|
||||
// if the brush is outside the clip area, skip it
|
||||
for (j=0 ; j<3 ; j++)
|
||||
if (mb->mins[j] >= clipmaxs[j]
|
||||
|| mb->maxs[j] <= clipmins[j])
|
||||
break;
|
||||
if (j != 3)
|
||||
continue;
|
||||
|
||||
//
|
||||
// make a copy of the brush
|
||||
//
|
||||
newbrush = AllocBrush (mb->numsides);
|
||||
newbrush->original = mb;
|
||||
newbrush->numsides = mb->numsides;
|
||||
memcpy (newbrush->sides, mb->original_sides, numsides*sizeof(side_t));
|
||||
for (j=0 ; j<numsides ; j++)
|
||||
{
|
||||
if (newbrush->sides[j].winding)
|
||||
newbrush->sides[j].winding = CopyWinding (newbrush->sides[j].winding);
|
||||
if (newbrush->sides[j].surf & SURF_HINT)
|
||||
newbrush->sides[j].visible = true; // hints are always visible
|
||||
}
|
||||
VectorCopy (mb->mins, newbrush->mins);
|
||||
VectorCopy (mb->maxs, newbrush->maxs);
|
||||
|
||||
//
|
||||
// carve off anything outside the clip box
|
||||
//
|
||||
newbrush = ClipBrushToBox (newbrush, clipmins, clipmaxs);
|
||||
if (!newbrush)
|
||||
continue;
|
||||
|
||||
c_faces += vis;
|
||||
c_brushes++;
|
||||
|
||||
newbrush->next = brushlist;
|
||||
brushlist = newbrush;
|
||||
}
|
||||
|
||||
return brushlist;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
AddBspBrushListToTail
|
||||
===============
|
||||
*/
|
||||
bspbrush_t *AddBrushListToTail (bspbrush_t *list, bspbrush_t *tail)
|
||||
{
|
||||
bspbrush_t *walk, *next;
|
||||
|
||||
for (walk=list ; walk ; walk=next)
|
||||
{ // add to end of list
|
||||
next = walk->next;
|
||||
walk->next = NULL;
|
||||
tail->next = walk;
|
||||
tail = walk;
|
||||
}
|
||||
|
||||
return tail;
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
CullList
|
||||
|
||||
Builds a new list that doesn't hold the given brush
|
||||
===========
|
||||
*/
|
||||
bspbrush_t *CullList (bspbrush_t *list, bspbrush_t *skip1)
|
||||
{
|
||||
bspbrush_t *newlist;
|
||||
bspbrush_t *next;
|
||||
|
||||
newlist = NULL;
|
||||
|
||||
for ( ; list ; list = next)
|
||||
{
|
||||
next = list->next;
|
||||
if (list == skip1)
|
||||
{
|
||||
FreeBrush (list);
|
||||
continue;
|
||||
}
|
||||
list->next = newlist;
|
||||
newlist = list;
|
||||
}
|
||||
return newlist;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
WriteBrushMap
|
||||
==================
|
||||
*/
|
||||
void WriteBrushMap (char *name, bspbrush_t *list)
|
||||
{
|
||||
FILE *f;
|
||||
side_t *s;
|
||||
int i;
|
||||
winding_t *w;
|
||||
|
||||
printf ("writing %s\n", name);
|
||||
f = fopen (name, "wb");
|
||||
if (!f)
|
||||
Error ("Can't write %s\b", name);
|
||||
|
||||
fprintf (f, "{\n\"classname\" \"worldspawn\"\n");
|
||||
|
||||
for ( ; list ; list=list->next )
|
||||
{
|
||||
fprintf (f, "{\n");
|
||||
for (i=0,s=list->sides ; i<list->numsides ; i++,s++)
|
||||
{
|
||||
w = BaseWindingForPlane (mapplanes[s->planenum].normal, mapplanes[s->planenum].dist);
|
||||
|
||||
fprintf (f,"( %i %i %i ) ", (int)w->p[0][0], (int)w->p[0][1], (int)w->p[0][2]);
|
||||
fprintf (f,"( %i %i %i ) ", (int)w->p[1][0], (int)w->p[1][1], (int)w->p[1][2]);
|
||||
fprintf (f,"( %i %i %i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]);
|
||||
|
||||
fprintf (f, "%s 0 0 0 1 1\n", texinfo[s->texinfo].texture);
|
||||
FreeWinding (w);
|
||||
}
|
||||
fprintf (f, "}\n");
|
||||
}
|
||||
fprintf (f, "}\n");
|
||||
|
||||
fclose (f);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
BrushGE
|
||||
|
||||
Returns true if b1 is allowed to bite b2
|
||||
==================
|
||||
*/
|
||||
qboolean BrushGE (bspbrush_t *b1, bspbrush_t *b2)
|
||||
{
|
||||
// detail brushes never bite structural brushes
|
||||
if ( (b1->original->contents & CONTENTS_DETAIL)
|
||||
&& !(b2->original->contents & CONTENTS_DETAIL) )
|
||||
return false;
|
||||
if (b1->original->contents & CONTENTS_SOLID)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
ChopBrushes
|
||||
|
||||
Carves any intersecting solid brushes into the minimum number
|
||||
of non-intersecting brushes.
|
||||
=================
|
||||
*/
|
||||
bspbrush_t *ChopBrushes (bspbrush_t *head)
|
||||
{
|
||||
bspbrush_t *b1, *b2, *next;
|
||||
bspbrush_t *tail;
|
||||
bspbrush_t *keep;
|
||||
bspbrush_t *sub, *sub2;
|
||||
int c1, c2;
|
||||
|
||||
qprintf ("---- ChopBrushes ----\n");
|
||||
qprintf ("original brushes: %i\n", CountBrushList (head));
|
||||
|
||||
#if 0
|
||||
if (startbrush == 0)
|
||||
WriteBrushList ("before.gl", head, false);
|
||||
#endif
|
||||
keep = NULL;
|
||||
|
||||
newlist:
|
||||
// find tail
|
||||
if (!head)
|
||||
return NULL;
|
||||
for (tail=head ; tail->next ; tail=tail->next)
|
||||
;
|
||||
|
||||
for (b1=head ; b1 ; b1=next)
|
||||
{
|
||||
next = b1->next;
|
||||
for (b2=b1->next ; b2 ; b2 = b2->next)
|
||||
{
|
||||
if (BrushesDisjoint (b1, b2))
|
||||
continue;
|
||||
|
||||
sub = NULL;
|
||||
sub2 = NULL;
|
||||
c1 = 999999;
|
||||
c2 = 999999;
|
||||
|
||||
if ( BrushGE (b2, b1) )
|
||||
{
|
||||
sub = SubtractBrush (b1, b2);
|
||||
if (sub == b1)
|
||||
continue; // didn't really intersect
|
||||
if (!sub)
|
||||
{ // b1 is swallowed by b2
|
||||
head = CullList (b1, b1);
|
||||
goto newlist;
|
||||
}
|
||||
c1 = CountBrushList (sub);
|
||||
}
|
||||
|
||||
if ( BrushGE (b1, b2) )
|
||||
{
|
||||
sub2 = SubtractBrush (b2, b1);
|
||||
if (sub2 == b2)
|
||||
continue; // didn't really intersect
|
||||
if (!sub2)
|
||||
{ // b2 is swallowed by b1
|
||||
FreeBrushList (sub);
|
||||
head = CullList (b1, b2);
|
||||
goto newlist;
|
||||
}
|
||||
c2 = CountBrushList (sub2);
|
||||
}
|
||||
|
||||
if (!sub && !sub2)
|
||||
continue; // neither one can bite
|
||||
|
||||
// only accept if it didn't fragment
|
||||
// (commening this out allows full fragmentation)
|
||||
if (c1 > 1 && c2 > 1)
|
||||
{
|
||||
if (sub2)
|
||||
FreeBrushList (sub2);
|
||||
if (sub)
|
||||
FreeBrushList (sub);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c1 < c2)
|
||||
{
|
||||
if (sub2)
|
||||
FreeBrushList (sub2);
|
||||
tail = AddBrushListToTail (sub, tail);
|
||||
head = CullList (b1, b1);
|
||||
goto newlist;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sub)
|
||||
FreeBrushList (sub);
|
||||
tail = AddBrushListToTail (sub2, tail);
|
||||
head = CullList (b1, b2);
|
||||
goto newlist;
|
||||
}
|
||||
}
|
||||
|
||||
if (!b2)
|
||||
{ // b1 is no longer intersecting anything, so keep it
|
||||
b1->next = keep;
|
||||
keep = b1;
|
||||
}
|
||||
}
|
||||
|
||||
qprintf ("output brushes: %i\n", CountBrushList (keep));
|
||||
#if 0
|
||||
{
|
||||
WriteBrushList ("after.gl", keep, false);
|
||||
WriteBrushMap ("after.map", keep);
|
||||
}
|
||||
#endif
|
||||
return keep;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
InitialBrushList
|
||||
=================
|
||||
*/
|
||||
bspbrush_t *InitialBrushList (bspbrush_t *list)
|
||||
{
|
||||
bspbrush_t *b;
|
||||
bspbrush_t *out, *newb;
|
||||
int i;
|
||||
|
||||
// only return brushes that have visible faces
|
||||
out = NULL;
|
||||
for (b=list ; b ; b=b->next)
|
||||
{
|
||||
#if 0
|
||||
for (i=0 ; i<b->numsides ; i++)
|
||||
if (b->sides[i].visible)
|
||||
break;
|
||||
if (i == b->numsides)
|
||||
continue;
|
||||
#endif
|
||||
newb = CopyBrush (b);
|
||||
newb->next = out;
|
||||
out = newb;
|
||||
|
||||
// clear visible, so it must be set by MarkVisibleFaces_r
|
||||
// to be used in the optimized list
|
||||
for (i=0 ; i<b->numsides ; i++)
|
||||
{
|
||||
newb->sides[i].original = &b->sides[i];
|
||||
// newb->sides[i].visible = true;
|
||||
b->sides[i].visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
OptimizedBrushList
|
||||
=================
|
||||
*/
|
||||
bspbrush_t *OptimizedBrushList (bspbrush_t *list)
|
||||
{
|
||||
bspbrush_t *b;
|
||||
bspbrush_t *out, *newb;
|
||||
int i;
|
||||
|
||||
// only return brushes that have visible faces
|
||||
out = NULL;
|
||||
for (b=list ; b ; b=b->next)
|
||||
{
|
||||
for (i=0 ; i<b->numsides ; i++)
|
||||
if (b->sides[i].visible)
|
||||
break;
|
||||
if (i == b->numsides)
|
||||
continue;
|
||||
newb = CopyBrush (b);
|
||||
newb->next = out;
|
||||
out = newb;
|
||||
}
|
||||
|
||||
// WriteBrushList ("vis.gl", out, true);
|
||||
|
||||
return out;
|
||||
}
|
1076
tools/quake2/extra/bsp/qbsp3/faces.c
Normal file
1076
tools/quake2/extra/bsp/qbsp3/faces.c
Normal file
File diff suppressed because it is too large
Load diff
232
tools/quake2/extra/bsp/qbsp3/gldraw.c
Normal file
232
tools/quake2/extra/bsp/qbsp3/gldraw.c
Normal file
|
@ -0,0 +1,232 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glu.h>
|
||||
#include <GL/glaux.h>
|
||||
|
||||
#include "qbsp.h"
|
||||
|
||||
// can't use the glvertex3fv functions, because the vec3_t fields
|
||||
// could be either floats or doubles, depending on DOUBLEVEC_T
|
||||
|
||||
qboolean drawflag;
|
||||
vec3_t draw_mins, draw_maxs;
|
||||
|
||||
|
||||
#define WIN_SIZE 512
|
||||
|
||||
void InitWindow (void)
|
||||
{
|
||||
auxInitDisplayMode (AUX_SINGLE | AUX_RGB);
|
||||
auxInitPosition (0, 0, WIN_SIZE, WIN_SIZE);
|
||||
auxInitWindow ("qcsg");
|
||||
}
|
||||
|
||||
void Draw_ClearWindow (void)
|
||||
{
|
||||
static int init;
|
||||
int w, h, g;
|
||||
vec_t mx, my;
|
||||
|
||||
if (!drawflag)
|
||||
return;
|
||||
|
||||
if (!init)
|
||||
{
|
||||
init = true;
|
||||
InitWindow ();
|
||||
}
|
||||
|
||||
glClearColor (1,0.8,0.8,0);
|
||||
glClear (GL_COLOR_BUFFER_BIT);
|
||||
|
||||
w = (draw_maxs[0] - draw_mins[0]);
|
||||
h = (draw_maxs[1] - draw_mins[1]);
|
||||
|
||||
mx = draw_mins[0] + w/2;
|
||||
my = draw_mins[1] + h/2;
|
||||
|
||||
g = w > h ? w : h;
|
||||
|
||||
glLoadIdentity ();
|
||||
gluPerspective (90, 1, 2, 16384);
|
||||
gluLookAt (mx, my, draw_maxs[2] + g/2, mx , my, draw_maxs[2], 0, 1, 0);
|
||||
|
||||
glColor3f (0,0,0);
|
||||
// glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
|
||||
glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
|
||||
glDisable (GL_DEPTH_TEST);
|
||||
glEnable (GL_BLEND);
|
||||
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
#if 0
|
||||
glColor4f (1,0,0,0.5);
|
||||
glBegin (GL_POLYGON);
|
||||
|
||||
glVertex3f (0, 500, 0);
|
||||
glVertex3f (0, 900, 0);
|
||||
glVertex3f (0, 900, 100);
|
||||
glVertex3f (0, 500, 100);
|
||||
|
||||
glEnd ();
|
||||
#endif
|
||||
|
||||
glFlush ();
|
||||
|
||||
}
|
||||
|
||||
void Draw_SetRed (void)
|
||||
{
|
||||
if (!drawflag)
|
||||
return;
|
||||
|
||||
glColor3f (1,0,0);
|
||||
}
|
||||
|
||||
void Draw_SetGrey (void)
|
||||
{
|
||||
if (!drawflag)
|
||||
return;
|
||||
|
||||
glColor3f (0.5,0.5,0.5);
|
||||
}
|
||||
|
||||
void Draw_SetBlack (void)
|
||||
{
|
||||
if (!drawflag)
|
||||
return;
|
||||
|
||||
glColor3f (0,0,0);
|
||||
}
|
||||
|
||||
void DrawWinding (winding_t *w)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!drawflag)
|
||||
return;
|
||||
|
||||
glColor4f (0,0,0,0.5);
|
||||
glBegin (GL_LINE_LOOP);
|
||||
for (i=0 ; i<w->numpoints ; i++)
|
||||
glVertex3f (w->p[i][0],w->p[i][1],w->p[i][2] );
|
||||
glEnd ();
|
||||
|
||||
glColor4f (0,1,0,0.3);
|
||||
glBegin (GL_POLYGON);
|
||||
for (i=0 ; i<w->numpoints ; i++)
|
||||
glVertex3f (w->p[i][0],w->p[i][1],w->p[i][2] );
|
||||
glEnd ();
|
||||
|
||||
glFlush ();
|
||||
}
|
||||
|
||||
void DrawAuxWinding (winding_t *w)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!drawflag)
|
||||
return;
|
||||
|
||||
glColor4f (0,0,0,0.5);
|
||||
glBegin (GL_LINE_LOOP);
|
||||
for (i=0 ; i<w->numpoints ; i++)
|
||||
glVertex3f (w->p[i][0],w->p[i][1],w->p[i][2] );
|
||||
glEnd ();
|
||||
|
||||
glColor4f (1,0,0,0.3);
|
||||
glBegin (GL_POLYGON);
|
||||
for (i=0 ; i<w->numpoints ; i++)
|
||||
glVertex3f (w->p[i][0],w->p[i][1],w->p[i][2] );
|
||||
glEnd ();
|
||||
|
||||
glFlush ();
|
||||
}
|
||||
|
||||
//============================================================
|
||||
|
||||
#define GLSERV_PORT 25001
|
||||
|
||||
qboolean wins_init;
|
||||
int draw_socket;
|
||||
|
||||
void GLS_BeginScene (void)
|
||||
{
|
||||
WSADATA winsockdata;
|
||||
WORD wVersionRequested;
|
||||
struct sockaddr_in address;
|
||||
int r;
|
||||
|
||||
if (!wins_init)
|
||||
{
|
||||
wins_init = true;
|
||||
|
||||
wVersionRequested = MAKEWORD(1, 1);
|
||||
|
||||
r = WSAStartup (MAKEWORD(1, 1), &winsockdata);
|
||||
|
||||
if (r)
|
||||
Error ("Winsock initialization failed.");
|
||||
|
||||
}
|
||||
|
||||
// connect a socket to the server
|
||||
|
||||
draw_socket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (draw_socket == -1)
|
||||
Error ("draw_socket failed");
|
||||
|
||||
address.sin_family = AF_INET;
|
||||
address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
address.sin_port = GLSERV_PORT;
|
||||
r = connect (draw_socket, (struct sockaddr *)&address, sizeof(address));
|
||||
if (r == -1)
|
||||
{
|
||||
closesocket (draw_socket);
|
||||
draw_socket = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void GLS_Winding (winding_t *w, int code)
|
||||
{
|
||||
byte buf[1024];
|
||||
int i, j;
|
||||
|
||||
if (!draw_socket)
|
||||
return;
|
||||
|
||||
((int *)buf)[0] = w->numpoints;
|
||||
((int *)buf)[1] = code;
|
||||
for (i=0 ; i<w->numpoints ; i++)
|
||||
for (j=0 ; j<3 ; j++)
|
||||
((float *)buf)[2+i*3+j] = w->p[i][j];
|
||||
|
||||
send (draw_socket, buf, w->numpoints*12+8, 0);
|
||||
}
|
||||
|
||||
void GLS_EndScene (void)
|
||||
{
|
||||
closesocket (draw_socket);
|
||||
draw_socket = 0;
|
||||
}
|
149
tools/quake2/extra/bsp/qbsp3/glfile.c
Normal file
149
tools/quake2/extra/bsp/qbsp3/glfile.c
Normal file
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "qbsp.h"
|
||||
|
||||
int c_glfaces;
|
||||
|
||||
int PortalVisibleSides (portal_t *p)
|
||||
{
|
||||
int fcon, bcon;
|
||||
|
||||
if (!p->onnode)
|
||||
return 0; // outside
|
||||
|
||||
fcon = p->nodes[0]->contents;
|
||||
bcon = p->nodes[1]->contents;
|
||||
|
||||
// same contents never create a face
|
||||
if (fcon == bcon)
|
||||
return 0;
|
||||
|
||||
// FIXME: is this correct now?
|
||||
if (!fcon)
|
||||
return 1;
|
||||
if (!bcon)
|
||||
return 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void OutputWinding (winding_t *w, FILE *glview)
|
||||
{
|
||||
static int level = 128;
|
||||
vec_t light;
|
||||
int i;
|
||||
|
||||
fprintf (glview, "%i\n", w->numpoints);
|
||||
level+=28;
|
||||
light = (level&255)/255.0;
|
||||
for (i=0 ; i<w->numpoints ; i++)
|
||||
{
|
||||
fprintf (glview, "%6.3f %6.3f %6.3f %6.3f %6.3f %6.3f\n",
|
||||
w->p[i][0],
|
||||
w->p[i][1],
|
||||
w->p[i][2],
|
||||
light,
|
||||
light,
|
||||
light);
|
||||
}
|
||||
fprintf (glview, "\n");
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
OutputPortal
|
||||
=============
|
||||
*/
|
||||
void OutputPortal (portal_t *p, FILE *glview)
|
||||
{
|
||||
winding_t *w;
|
||||
int sides;
|
||||
|
||||
sides = PortalVisibleSides (p);
|
||||
if (!sides)
|
||||
return;
|
||||
|
||||
c_glfaces++;
|
||||
|
||||
w = p->winding;
|
||||
|
||||
if (sides == 2) // back side
|
||||
w = ReverseWinding (w);
|
||||
|
||||
OutputWinding (w, glview);
|
||||
|
||||
if (sides == 2)
|
||||
FreeWinding(w);
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
WriteGLView_r
|
||||
=============
|
||||
*/
|
||||
void WriteGLView_r (node_t *node, FILE *glview)
|
||||
{
|
||||
portal_t *p, *nextp;
|
||||
|
||||
if (node->planenum != PLANENUM_LEAF)
|
||||
{
|
||||
WriteGLView_r (node->children[0], glview);
|
||||
WriteGLView_r (node->children[1], glview);
|
||||
return;
|
||||
}
|
||||
|
||||
// write all the portals
|
||||
for (p=node->portals ; p ; p=nextp)
|
||||
{
|
||||
if (p->nodes[0] == node)
|
||||
{
|
||||
OutputPortal (p, glview);
|
||||
nextp = p->next[0];
|
||||
}
|
||||
else
|
||||
nextp = p->next[1];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
WriteGLView
|
||||
=============
|
||||
*/
|
||||
void WriteGLView (tree_t *tree, char *source)
|
||||
{
|
||||
char name[1024];
|
||||
FILE *glview;
|
||||
|
||||
c_glfaces = 0;
|
||||
sprintf (name, "%s%s.gl",outbase, source);
|
||||
printf ("Writing %s\n", name);
|
||||
|
||||
glview = fopen (name, "w");
|
||||
if (!glview)
|
||||
Error ("Couldn't open %s", name);
|
||||
WriteGLView_r (tree->headnode, glview);
|
||||
fclose (glview);
|
||||
|
||||
printf ("%5i c_glfaces\n", c_glfaces);
|
||||
}
|
||||
|
100
tools/quake2/extra/bsp/qbsp3/leakfile.c
Normal file
100
tools/quake2/extra/bsp/qbsp3/leakfile.c
Normal file
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "qbsp.h"
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
LEAF FILE GENERATION
|
||||
|
||||
Save out name.line for qe3 to read
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
LeakFile
|
||||
|
||||
Finds the shortest possible chain of portals
|
||||
that leads from the outside leaf to a specifically
|
||||
occupied leaf
|
||||
=============
|
||||
*/
|
||||
void LeakFile (tree_t *tree)
|
||||
{
|
||||
vec3_t mid;
|
||||
FILE *linefile;
|
||||
char filename[1024];
|
||||
node_t *node;
|
||||
int count;
|
||||
|
||||
if (!tree->outside_node.occupied)
|
||||
return;
|
||||
|
||||
qprintf ("--- LeakFile ---\n");
|
||||
|
||||
//
|
||||
// write the points to the file
|
||||
//
|
||||
sprintf (filename, "%s.lin", source);
|
||||
linefile = fopen (filename, "w");
|
||||
if (!linefile)
|
||||
Error ("Couldn't open %s\n", filename);
|
||||
|
||||
count = 0;
|
||||
node = &tree->outside_node;
|
||||
while (node->occupied > 1)
|
||||
{
|
||||
int next;
|
||||
portal_t *p, *nextportal;
|
||||
node_t *nextnode;
|
||||
int s;
|
||||
|
||||
// find the best portal exit
|
||||
next = node->occupied;
|
||||
for (p=node->portals ; p ; p = p->next[!s])
|
||||
{
|
||||
s = (p->nodes[0] == node);
|
||||
if (p->nodes[s]->occupied
|
||||
&& p->nodes[s]->occupied < next)
|
||||
{
|
||||
nextportal = p;
|
||||
nextnode = p->nodes[s];
|
||||
next = nextnode->occupied;
|
||||
}
|
||||
}
|
||||
node = nextnode;
|
||||
WindingCenter (nextportal->winding, mid);
|
||||
fprintf (linefile, "%f %f %f\n", mid[0], mid[1], mid[2]);
|
||||
count++;
|
||||
}
|
||||
// add the occupant center
|
||||
GetVectorForKey (node->occupant, "origin", mid);
|
||||
|
||||
fprintf (linefile, "%f %f %f\n", mid[0], mid[1], mid[2]);
|
||||
qprintf ("%5i point linefile\n", count+1);
|
||||
|
||||
fclose (linefile);
|
||||
}
|
||||
|
98
tools/quake2/extra/bsp/qbsp3/makefile
Normal file
98
tools/quake2/extra/bsp/qbsp3/makefile
Normal file
|
@ -0,0 +1,98 @@
|
|||
|
||||
CFLAGS = -c
|
||||
LDFLAGS =
|
||||
ODIR = baddir
|
||||
|
||||
EXEBASE = qbsp3
|
||||
EXE = $(ODIR)/qbsp3
|
||||
all: $(EXE)
|
||||
|
||||
_next:
|
||||
make "CFLAGS = -c -g -I../../common -DDOUBLEVEC_T" "ODIR = next"
|
||||
|
||||
_irix:
|
||||
make "CFLAGS = -c -Ofast=ip27 -OPT:IEEE_arithmetic=3 -I../../common -Xcpluscomm -DDOUBLEVEC_T" "LDFLAGS = -Ofast=ip27 -OPT:IEEE_arithmetic=3" "ODIR = irix"
|
||||
|
||||
_irixdebug:
|
||||
make "CFLAGS = -c -O2 -g -I../../common -Xcpluscomm -DDOUBLEVEC_T" "LDFLAGS = -g" "ODIR = irix"
|
||||
|
||||
_irixinst:
|
||||
make "CFLAGS = -c -Ofast=ip27 -OPT:IEEE_arithmetic=3 -I../../common -Xcpluscomm -DDOUBLEVEC_T" "LDFLAGS = -Ofast=ip27 -OPT:IEEE_arithmetic=3" "ODIR = irix"
|
||||
cp irix/$(EXEBASE) /limbo/quake2/bin_irix
|
||||
|
||||
_irixclean:
|
||||
rm -f irix/*.o irix/$(EXEBASE)
|
||||
|
||||
_osf:
|
||||
make "CFLAGS = -c -O4 -I../../common -threads -DDOUBLEVEC_T" "LDFLAGS = -threads" "ODIR = osf"
|
||||
|
||||
clean:
|
||||
rm -f irix/*.o irix/$(EXEBASE)
|
||||
|
||||
install:
|
||||
cp irix/$(EXEBASE) /limbo/quake2/bin_irix
|
||||
|
||||
|
||||
FILES = $(ODIR)/brushbsp.o $(ODIR)/bspfile.o $(ODIR)/cmdlib.o $(ODIR)/faces.o $(ODIR)/nodraw.o $(ODIR)/glfile.o $(ODIR)/leakfile.o $(ODIR)/map.o $(ODIR)/mathlib.o $(ODIR)/polylib.o $(ODIR)/portals.o $(ODIR)/prtfile.o $(ODIR)/qbsp3.o $(ODIR)/scriplib.o $(ODIR)/textures.o $(ODIR)/threads.o $(ODIR)/tree.o $(ODIR)/writebsp.o $(ODIR)/csg.o
|
||||
|
||||
$(EXE) : $(FILES)
|
||||
cc -o $(EXE) $(LDFLAGS) $(FILES) -lm
|
||||
|
||||
$(ODIR)/brushbsp.o : brushbsp.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/faces.o : faces.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/nodraw.o : nodraw.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/glfile.o : glfile.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/leakfile.o : leakfile.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/map.o : map.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/portals.o : portals.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/prtfile.o : prtfile.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/qbsp3.o : qbsp3.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/tree.o : tree.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/textures.o : textures.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/writebsp.o : writebsp.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/csg.o : csg.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/cmdlib.o : ../../common/cmdlib.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/mathlib.o : ../../common/mathlib.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/polylib.o : ../../common/polylib.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/scriplib.o : ../../common/scriplib.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/threads.o : ../../common/threads.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/bspfile.o : ../../common/bspfile.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
1017
tools/quake2/extra/bsp/qbsp3/map.c
Normal file
1017
tools/quake2/extra/bsp/qbsp3/map.c
Normal file
File diff suppressed because it is too large
Load diff
47
tools/quake2/extra/bsp/qbsp3/nodraw.c
Normal file
47
tools/quake2/extra/bsp/qbsp3/nodraw.c
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "qbsp.h"
|
||||
|
||||
vec3_t draw_mins, draw_maxs;
|
||||
qboolean drawflag;
|
||||
|
||||
void Draw_ClearWindow (void)
|
||||
{
|
||||
}
|
||||
|
||||
//============================================================
|
||||
|
||||
#define GLSERV_PORT 25001
|
||||
|
||||
|
||||
void GLS_BeginScene (void)
|
||||
{
|
||||
}
|
||||
|
||||
void GLS_Winding (winding_t *w, int code)
|
||||
{
|
||||
}
|
||||
|
||||
void GLS_EndScene (void)
|
||||
{
|
||||
}
|
1111
tools/quake2/extra/bsp/qbsp3/portals.c
Normal file
1111
tools/quake2/extra/bsp/qbsp3/portals.c
Normal file
File diff suppressed because it is too large
Load diff
287
tools/quake2/extra/bsp/qbsp3/prtfile.c
Normal file
287
tools/quake2/extra/bsp/qbsp3/prtfile.c
Normal file
|
@ -0,0 +1,287 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "qbsp.h"
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
PORTAL FILE GENERATION
|
||||
|
||||
Save out name.prt for qvis to read
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
|
||||
#define PORTALFILE "PRT1"
|
||||
|
||||
FILE *pf;
|
||||
int num_visclusters; // clusters the player can be in
|
||||
int num_visportals;
|
||||
|
||||
void WriteFloat (FILE *f, vec_t v)
|
||||
{
|
||||
if ( fabs(v - Q_rint(v)) < 0.001 )
|
||||
fprintf (f,"%i ",(int)Q_rint(v));
|
||||
else
|
||||
fprintf (f,"%f ",v);
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
WritePortalFile_r
|
||||
=================
|
||||
*/
|
||||
void WritePortalFile_r (node_t *node)
|
||||
{
|
||||
int i, s;
|
||||
portal_t *p;
|
||||
winding_t *w;
|
||||
vec3_t normal;
|
||||
vec_t dist;
|
||||
|
||||
// decision node
|
||||
if (node->planenum != PLANENUM_LEAF && !node->detail_seperator)
|
||||
{
|
||||
WritePortalFile_r (node->children[0]);
|
||||
WritePortalFile_r (node->children[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (node->contents & CONTENTS_SOLID)
|
||||
return;
|
||||
|
||||
for (p = node->portals ; p ; p=p->next[s])
|
||||
{
|
||||
w = p->winding;
|
||||
s = (p->nodes[1] == node);
|
||||
if (w && p->nodes[0] == node)
|
||||
{
|
||||
if (!Portal_VisFlood (p))
|
||||
continue;
|
||||
// write out to the file
|
||||
|
||||
// sometimes planes get turned around when they are very near
|
||||
// the changeover point between different axis. interpret the
|
||||
// plane the same way vis will, and flip the side orders if needed
|
||||
// FIXME: is this still relevent?
|
||||
WindingPlane (w, normal, &dist);
|
||||
if ( DotProduct (p->plane.normal, normal) < 0.99 )
|
||||
{ // backwards...
|
||||
fprintf (pf,"%i %i %i ",w->numpoints, p->nodes[1]->cluster, p->nodes[0]->cluster);
|
||||
}
|
||||
else
|
||||
fprintf (pf,"%i %i %i ",w->numpoints, p->nodes[0]->cluster, p->nodes[1]->cluster);
|
||||
for (i=0 ; i<w->numpoints ; i++)
|
||||
{
|
||||
fprintf (pf,"(");
|
||||
WriteFloat (pf, w->p[i][0]);
|
||||
WriteFloat (pf, w->p[i][1]);
|
||||
WriteFloat (pf, w->p[i][2]);
|
||||
fprintf (pf,") ");
|
||||
}
|
||||
fprintf (pf,"\n");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
FillLeafNumbers_r
|
||||
|
||||
All of the leafs under node will have the same cluster
|
||||
================
|
||||
*/
|
||||
void FillLeafNumbers_r (node_t *node, int num)
|
||||
{
|
||||
if (node->planenum == PLANENUM_LEAF)
|
||||
{
|
||||
if (node->contents & CONTENTS_SOLID)
|
||||
node->cluster = -1;
|
||||
else
|
||||
node->cluster = num;
|
||||
return;
|
||||
}
|
||||
node->cluster = num;
|
||||
FillLeafNumbers_r (node->children[0], num);
|
||||
FillLeafNumbers_r (node->children[1], num);
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
NumberLeafs_r
|
||||
================
|
||||
*/
|
||||
void NumberLeafs_r (node_t *node)
|
||||
{
|
||||
portal_t *p;
|
||||
|
||||
if (node->planenum != PLANENUM_LEAF && !node->detail_seperator)
|
||||
{ // decision node
|
||||
node->cluster = -99;
|
||||
NumberLeafs_r (node->children[0]);
|
||||
NumberLeafs_r (node->children[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
// either a leaf or a detail cluster
|
||||
|
||||
if ( node->contents & CONTENTS_SOLID )
|
||||
{ // solid block, viewpoint never inside
|
||||
node->cluster = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
FillLeafNumbers_r (node, num_visclusters);
|
||||
num_visclusters++;
|
||||
|
||||
// count the portals
|
||||
for (p = node->portals ; p ; )
|
||||
{
|
||||
if (p->nodes[0] == node) // only write out from first leaf
|
||||
{
|
||||
if (Portal_VisFlood (p))
|
||||
num_visportals++;
|
||||
p = p->next[0];
|
||||
}
|
||||
else
|
||||
p = p->next[1];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
CreateVisPortals_r
|
||||
================
|
||||
*/
|
||||
void CreateVisPortals_r (node_t *node)
|
||||
{
|
||||
// stop as soon as we get to a detail_seperator, which
|
||||
// means that everything below is in a single cluster
|
||||
if (node->planenum == PLANENUM_LEAF || node->detail_seperator )
|
||||
return;
|
||||
|
||||
MakeNodePortal (node);
|
||||
SplitNodePortals (node);
|
||||
|
||||
CreateVisPortals_r (node->children[0]);
|
||||
CreateVisPortals_r (node->children[1]);
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
FinishVisPortals_r
|
||||
================
|
||||
*/
|
||||
void FinishVisPortals2_r (node_t *node)
|
||||
{
|
||||
if (node->planenum == PLANENUM_LEAF)
|
||||
return;
|
||||
|
||||
MakeNodePortal (node);
|
||||
SplitNodePortals (node);
|
||||
|
||||
FinishVisPortals2_r (node->children[0]);
|
||||
FinishVisPortals2_r (node->children[1]);
|
||||
}
|
||||
|
||||
void FinishVisPortals_r (node_t *node)
|
||||
{
|
||||
if (node->planenum == PLANENUM_LEAF)
|
||||
return;
|
||||
|
||||
if (node->detail_seperator)
|
||||
{
|
||||
FinishVisPortals2_r (node);
|
||||
return;
|
||||
}
|
||||
|
||||
FinishVisPortals_r (node->children[0]);
|
||||
FinishVisPortals_r (node->children[1]);
|
||||
}
|
||||
|
||||
|
||||
int clusterleaf;
|
||||
void SaveClusters_r (node_t *node)
|
||||
{
|
||||
if (node->planenum == PLANENUM_LEAF)
|
||||
{
|
||||
dleafs[clusterleaf++].cluster = node->cluster;
|
||||
return;
|
||||
}
|
||||
SaveClusters_r (node->children[0]);
|
||||
SaveClusters_r (node->children[1]);
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
WritePortalFile
|
||||
================
|
||||
*/
|
||||
void WritePortalFile (tree_t *tree)
|
||||
{
|
||||
char filename[1024];
|
||||
node_t *headnode;
|
||||
|
||||
qprintf ("--- WritePortalFile ---\n");
|
||||
|
||||
headnode = tree->headnode;
|
||||
num_visclusters = 0;
|
||||
num_visportals = 0;
|
||||
|
||||
FreeTreePortals_r (headnode);
|
||||
|
||||
MakeHeadnodePortals (tree);
|
||||
|
||||
CreateVisPortals_r (headnode);
|
||||
|
||||
// set the cluster field in every leaf and count the total number of portals
|
||||
|
||||
NumberLeafs_r (headnode);
|
||||
|
||||
// write the file
|
||||
sprintf (filename, "%s.prt", source);
|
||||
printf ("writing %s\n", filename);
|
||||
pf = fopen (filename, "w");
|
||||
if (!pf)
|
||||
Error ("Error opening %s", filename);
|
||||
|
||||
fprintf (pf, "%s\n", PORTALFILE);
|
||||
fprintf (pf, "%i\n", num_visclusters);
|
||||
fprintf (pf, "%i\n", num_visportals);
|
||||
|
||||
qprintf ("%5i visclusters\n", num_visclusters);
|
||||
qprintf ("%5i visportals\n", num_visportals);
|
||||
|
||||
WritePortalFile_r (headnode);
|
||||
|
||||
fclose (pf);
|
||||
|
||||
// we need to store the clusters out now because ordering
|
||||
// issues made us do this after writebsp...
|
||||
clusterleaf = 1;
|
||||
SaveClusters_r (headnode);
|
||||
}
|
||||
|
355
tools/quake2/extra/bsp/qbsp3/qbsp.h
Normal file
355
tools/quake2/extra/bsp/qbsp3/qbsp.h
Normal file
|
@ -0,0 +1,355 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "cmdlib.h"
|
||||
#include "mathlib.h"
|
||||
#include "scriplib.h"
|
||||
#include "polylib.h"
|
||||
#include "threads.h"
|
||||
#include "bspfile.h"
|
||||
|
||||
#define MAX_BRUSH_SIDES 128
|
||||
#define CLIP_EPSILON 0.1
|
||||
|
||||
#define BOGUS_RANGE 8192
|
||||
|
||||
#define TEXINFO_NODE -1 // side is allready on a node
|
||||
|
||||
typedef struct plane_s
|
||||
{
|
||||
vec3_t normal;
|
||||
vec_t dist;
|
||||
int type;
|
||||
struct plane_s *hash_chain;
|
||||
} plane_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
vec_t shift[2];
|
||||
vec_t rotate;
|
||||
vec_t scale[2];
|
||||
char name[32];
|
||||
int flags;
|
||||
int value;
|
||||
} brush_texture_t;
|
||||
|
||||
typedef struct side_s
|
||||
{
|
||||
int planenum;
|
||||
int texinfo;
|
||||
winding_t *winding;
|
||||
struct side_s *original; // bspbrush_t sides will reference the mapbrush_t sides
|
||||
int contents; // from miptex
|
||||
int surf; // from miptex
|
||||
qboolean visible; // choose visble planes first
|
||||
qboolean tested; // this plane allready checked as a split
|
||||
qboolean bevel; // don't ever use for bsp splitting
|
||||
} side_t;
|
||||
|
||||
typedef struct brush_s
|
||||
{
|
||||
int entitynum;
|
||||
int brushnum;
|
||||
|
||||
int contents;
|
||||
|
||||
vec3_t mins, maxs;
|
||||
|
||||
int numsides;
|
||||
side_t *original_sides;
|
||||
} mapbrush_t;
|
||||
|
||||
#define PLANENUM_LEAF -1
|
||||
|
||||
#define MAXEDGES 20
|
||||
|
||||
typedef struct face_s
|
||||
{
|
||||
struct face_s *next; // on node
|
||||
|
||||
// the chain of faces off of a node can be merged or split,
|
||||
// but each face_t along the way will remain in the chain
|
||||
// until the entire tree is freed
|
||||
struct face_s *merged; // if set, this face isn't valid anymore
|
||||
struct face_s *split[2]; // if set, this face isn't valid anymore
|
||||
|
||||
struct portal_s *portal;
|
||||
int texinfo;
|
||||
int planenum;
|
||||
int contents; // faces in different contents can't merge
|
||||
int outputnumber;
|
||||
winding_t *w;
|
||||
int numpoints;
|
||||
qboolean badstartvert; // tjunctions cannot be fixed without a midpoint vertex
|
||||
int vertexnums[MAXEDGES];
|
||||
} face_t;
|
||||
|
||||
|
||||
|
||||
typedef struct bspbrush_s
|
||||
{
|
||||
struct bspbrush_s *next;
|
||||
vec3_t mins, maxs;
|
||||
int side, testside; // side of node during construction
|
||||
mapbrush_t *original;
|
||||
int numsides;
|
||||
side_t sides[6]; // variably sized
|
||||
} bspbrush_t;
|
||||
|
||||
|
||||
|
||||
#define MAX_NODE_BRUSHES 8
|
||||
typedef struct node_s
|
||||
{
|
||||
// both leafs and nodes
|
||||
int planenum; // -1 = leaf node
|
||||
struct node_s *parent;
|
||||
vec3_t mins, maxs; // valid after portalization
|
||||
bspbrush_t *volume; // one for each leaf/node
|
||||
|
||||
// nodes only
|
||||
qboolean detail_seperator; // a detail brush caused the split
|
||||
side_t *side; // the side that created the node
|
||||
struct node_s *children[2];
|
||||
face_t *faces;
|
||||
|
||||
// leafs only
|
||||
bspbrush_t *brushlist; // fragments of all brushes in this leaf
|
||||
int contents; // OR of all brush contents
|
||||
int occupied; // 1 or greater can reach entity
|
||||
entity_t *occupant; // for leak file testing
|
||||
int cluster; // for portalfile writing
|
||||
int area; // for areaportals
|
||||
struct portal_s *portals; // also on nodes during construction
|
||||
} node_t;
|
||||
|
||||
typedef struct portal_s
|
||||
{
|
||||
plane_t plane;
|
||||
node_t *onnode; // NULL = outside box
|
||||
node_t *nodes[2]; // [0] = front side of plane
|
||||
struct portal_s *next[2];
|
||||
winding_t *winding;
|
||||
|
||||
qboolean sidefound; // false if ->side hasn't been checked
|
||||
side_t *side; // NULL = non-visible
|
||||
face_t *face[2]; // output face in bsp file
|
||||
} portal_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
node_t *headnode;
|
||||
node_t outside_node;
|
||||
vec3_t mins, maxs;
|
||||
} tree_t;
|
||||
|
||||
extern int entity_num;
|
||||
|
||||
extern plane_t mapplanes[MAX_MAP_PLANES];
|
||||
extern int nummapplanes;
|
||||
|
||||
extern int nummapbrushes;
|
||||
extern mapbrush_t mapbrushes[MAX_MAP_BRUSHES];
|
||||
|
||||
extern vec3_t map_mins, map_maxs;
|
||||
|
||||
#define MAX_MAP_SIDES (MAX_MAP_BRUSHES*6)
|
||||
|
||||
extern int nummapbrushsides;
|
||||
extern side_t brushsides[MAX_MAP_SIDES];
|
||||
|
||||
extern qboolean noprune;
|
||||
extern qboolean nodetail;
|
||||
extern qboolean fulldetail;
|
||||
extern qboolean nomerge;
|
||||
extern qboolean nosubdiv;
|
||||
extern qboolean nowater;
|
||||
extern qboolean noweld;
|
||||
extern qboolean noshare;
|
||||
extern qboolean notjunc;
|
||||
|
||||
extern vec_t microvolume;
|
||||
|
||||
extern char outbase[32];
|
||||
|
||||
extern char source[1024];
|
||||
|
||||
void LoadMapFile (char *filename);
|
||||
int FindFloatPlane (vec3_t normal, vec_t dist);
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// textures.c
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char name[64];
|
||||
int flags;
|
||||
int value;
|
||||
int contents;
|
||||
char animname[64];
|
||||
} textureref_t;
|
||||
|
||||
#define MAX_MAP_TEXTURES 1024
|
||||
|
||||
extern textureref_t textureref[MAX_MAP_TEXTURES];
|
||||
|
||||
int FindMiptex (char *name);
|
||||
|
||||
int TexinfoForBrushTexture (plane_t *plane, brush_texture_t *bt, vec3_t origin);
|
||||
|
||||
//=============================================================================
|
||||
|
||||
void FindGCD (int *v);
|
||||
|
||||
mapbrush_t *Brush_LoadEntity (entity_t *ent);
|
||||
int PlaneTypeForNormal (vec3_t normal);
|
||||
qboolean MakeBrushPlanes (mapbrush_t *b);
|
||||
int FindIntPlane (int *inormal, int *iorigin);
|
||||
void CreateBrush (int brushnum);
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// draw.c
|
||||
|
||||
extern vec3_t draw_mins, draw_maxs;
|
||||
extern qboolean drawflag;
|
||||
|
||||
void Draw_ClearWindow (void);
|
||||
void DrawWinding (winding_t *w);
|
||||
|
||||
void GLS_BeginScene (void);
|
||||
void GLS_Winding (winding_t *w, int code);
|
||||
void GLS_EndScene (void);
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// csg
|
||||
|
||||
bspbrush_t *MakeBspBrushList (int startbrush, int endbrush,
|
||||
vec3_t clipmins, vec3_t clipmaxs);
|
||||
bspbrush_t *ChopBrushes (bspbrush_t *head);
|
||||
bspbrush_t *InitialBrushList (bspbrush_t *list);
|
||||
bspbrush_t *OptimizedBrushList (bspbrush_t *list);
|
||||
|
||||
void WriteBrushMap (char *name, bspbrush_t *list);
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// brushbsp
|
||||
|
||||
void WriteBrushList (char *name, bspbrush_t *brush, qboolean onlyvis);
|
||||
|
||||
bspbrush_t *CopyBrush (bspbrush_t *brush);
|
||||
|
||||
void SplitBrush (bspbrush_t *brush, int planenum,
|
||||
bspbrush_t **front, bspbrush_t **back);
|
||||
|
||||
tree_t *AllocTree (void);
|
||||
node_t *AllocNode (void);
|
||||
bspbrush_t *AllocBrush (int numsides);
|
||||
int CountBrushList (bspbrush_t *brushes);
|
||||
void FreeBrush (bspbrush_t *brushes);
|
||||
vec_t BrushVolume (bspbrush_t *brush);
|
||||
|
||||
void BoundBrush (bspbrush_t *brush);
|
||||
void FreeBrushList (bspbrush_t *brushes);
|
||||
|
||||
tree_t *BrushBSP (bspbrush_t *brushlist, vec3_t mins, vec3_t maxs);
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// portals.c
|
||||
|
||||
int VisibleContents (int contents);
|
||||
|
||||
void MakeHeadnodePortals (tree_t *tree);
|
||||
void MakeNodePortal (node_t *node);
|
||||
void SplitNodePortals (node_t *node);
|
||||
|
||||
qboolean Portal_VisFlood (portal_t *p);
|
||||
|
||||
qboolean FloodEntities (tree_t *tree);
|
||||
void FillOutside (node_t *headnode);
|
||||
void FloodAreas (tree_t *tree);
|
||||
void MarkVisibleSides (tree_t *tree, int start, int end);
|
||||
void FreePortal (portal_t *p);
|
||||
void EmitAreaPortals (node_t *headnode);
|
||||
|
||||
void MakeTreePortals (tree_t *tree);
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// glfile.c
|
||||
|
||||
void OutputWinding (winding_t *w, FILE *glview);
|
||||
void WriteGLView (tree_t *tree, char *source);
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// leakfile.c
|
||||
|
||||
void LeakFile (tree_t *tree);
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// prtfile.c
|
||||
|
||||
void WritePortalFile (tree_t *tree);
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// writebsp.c
|
||||
|
||||
void SetModelNumbers (void);
|
||||
void SetLightStyles (void);
|
||||
|
||||
void BeginBSPFile (void);
|
||||
void WriteBSP (node_t *headnode);
|
||||
void EndBSPFile (void);
|
||||
void BeginModel (void);
|
||||
void EndModel (void);
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// faces.c
|
||||
|
||||
void MakeFaces (node_t *headnode);
|
||||
void FixTjuncs (node_t *headnode);
|
||||
int GetEdge2 (int v1, int v2, face_t *f);
|
||||
|
||||
face_t *AllocFace (void);
|
||||
void FreeFace (face_t *f);
|
||||
|
||||
void MergeNodeFaces (node_t *node);
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// tree.c
|
||||
|
||||
void FreeTree (tree_t *tree);
|
||||
void FreeTree_r (node_t *node);
|
||||
void PrintTree_r (node_t *node, int depth);
|
||||
void FreeTreePortals_r (node_t *node);
|
||||
void PruneNodes_r (node_t *node);
|
||||
void PruneNodes (node_t *node);
|
537
tools/quake2/extra/bsp/qbsp3/qbsp3.c
Normal file
537
tools/quake2/extra/bsp/qbsp3/qbsp3.c
Normal file
|
@ -0,0 +1,537 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "qbsp.h"
|
||||
|
||||
extern float subdivide_size;
|
||||
|
||||
char source[1024];
|
||||
char name[1024];
|
||||
|
||||
vec_t microvolume = 1.0;
|
||||
qboolean noprune;
|
||||
qboolean glview;
|
||||
qboolean nodetail;
|
||||
qboolean fulldetail;
|
||||
qboolean onlyents;
|
||||
qboolean nomerge;
|
||||
qboolean nowater;
|
||||
qboolean nofill;
|
||||
qboolean nocsg;
|
||||
qboolean noweld;
|
||||
qboolean noshare;
|
||||
qboolean nosubdiv;
|
||||
qboolean notjunc;
|
||||
qboolean noopt;
|
||||
qboolean leaktest;
|
||||
qboolean verboseentities;
|
||||
|
||||
char outbase[32];
|
||||
|
||||
int block_xl = -8, block_xh = 7, block_yl = -8, block_yh = 7;
|
||||
|
||||
int entity_num;
|
||||
|
||||
|
||||
node_t *block_nodes[10][10];
|
||||
|
||||
/*
|
||||
============
|
||||
BlockTree
|
||||
|
||||
============
|
||||
*/
|
||||
node_t *BlockTree (int xl, int yl, int xh, int yh)
|
||||
{
|
||||
node_t *node;
|
||||
vec3_t normal;
|
||||
float dist;
|
||||
int mid;
|
||||
|
||||
if (xl == xh && yl == yh)
|
||||
{
|
||||
node = block_nodes[xl+5][yl+5];
|
||||
if (!node)
|
||||
{ // return an empty leaf
|
||||
node = AllocNode ();
|
||||
node->planenum = PLANENUM_LEAF;
|
||||
node->contents = 0; //CONTENTS_SOLID;
|
||||
return node;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
// create a seperator along the largest axis
|
||||
node = AllocNode ();
|
||||
|
||||
if (xh - xl > yh - yl)
|
||||
{ // split x axis
|
||||
mid = xl + (xh-xl)/2 + 1;
|
||||
normal[0] = 1;
|
||||
normal[1] = 0;
|
||||
normal[2] = 0;
|
||||
dist = mid*1024;
|
||||
node->planenum = FindFloatPlane (normal, dist);
|
||||
node->children[0] = BlockTree ( mid, yl, xh, yh);
|
||||
node->children[1] = BlockTree ( xl, yl, mid-1, yh);
|
||||
}
|
||||
else
|
||||
{
|
||||
mid = yl + (yh-yl)/2 + 1;
|
||||
normal[0] = 0;
|
||||
normal[1] = 1;
|
||||
normal[2] = 0;
|
||||
dist = mid*1024;
|
||||
node->planenum = FindFloatPlane (normal, dist);
|
||||
node->children[0] = BlockTree ( xl, mid, xh, yh);
|
||||
node->children[1] = BlockTree ( xl, yl, xh, mid-1);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
ProcessBlock_Thread
|
||||
|
||||
============
|
||||
*/
|
||||
int brush_start, brush_end;
|
||||
void ProcessBlock_Thread (int blocknum)
|
||||
{
|
||||
int xblock, yblock;
|
||||
vec3_t mins, maxs;
|
||||
bspbrush_t *brushes;
|
||||
tree_t *tree;
|
||||
node_t *node;
|
||||
|
||||
yblock = block_yl + blocknum / (block_xh-block_xl+1);
|
||||
xblock = block_xl + blocknum % (block_xh-block_xl+1);
|
||||
|
||||
qprintf ("############### block %2i,%2i ###############\n", xblock, yblock);
|
||||
|
||||
mins[0] = xblock*1024;
|
||||
mins[1] = yblock*1024;
|
||||
mins[2] = -4096;
|
||||
maxs[0] = (xblock+1)*1024;
|
||||
maxs[1] = (yblock+1)*1024;
|
||||
maxs[2] = 4096;
|
||||
|
||||
// the makelist and chopbrushes could be cached between the passes...
|
||||
brushes = MakeBspBrushList (brush_start, brush_end, mins, maxs);
|
||||
if (!brushes)
|
||||
{
|
||||
node = AllocNode ();
|
||||
node->planenum = PLANENUM_LEAF;
|
||||
node->contents = CONTENTS_SOLID;
|
||||
block_nodes[xblock+5][yblock+5] = node;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!nocsg)
|
||||
brushes = ChopBrushes (brushes);
|
||||
|
||||
tree = BrushBSP (brushes, mins, maxs);
|
||||
|
||||
block_nodes[xblock+5][yblock+5] = tree->headnode;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
ProcessWorldModel
|
||||
|
||||
============
|
||||
*/
|
||||
void ProcessWorldModel (void)
|
||||
{
|
||||
entity_t *e;
|
||||
tree_t *tree;
|
||||
qboolean leaked;
|
||||
qboolean optimize;
|
||||
|
||||
e = &entities[entity_num];
|
||||
|
||||
brush_start = e->firstbrush;
|
||||
brush_end = brush_start + e->numbrushes;
|
||||
leaked = false;
|
||||
|
||||
//
|
||||
// perform per-block operations
|
||||
//
|
||||
if (block_xh * 1024 > map_maxs[0])
|
||||
block_xh = floor(map_maxs[0]/1024.0);
|
||||
if ( (block_xl+1) * 1024 < map_mins[0])
|
||||
block_xl = floor(map_mins[0]/1024.0);
|
||||
if (block_yh * 1024 > map_maxs[1])
|
||||
block_yh = floor(map_maxs[1]/1024.0);
|
||||
if ( (block_yl+1) * 1024 < map_mins[1])
|
||||
block_yl = floor(map_mins[1]/1024.0);
|
||||
|
||||
if (block_xl <-4)
|
||||
block_xl = -4;
|
||||
if (block_yl <-4)
|
||||
block_yl = -4;
|
||||
if (block_xh > 3)
|
||||
block_xh = 3;
|
||||
if (block_yh > 3)
|
||||
block_yh = 3;
|
||||
|
||||
for (optimize = false ; optimize <= true ; optimize++)
|
||||
{
|
||||
qprintf ("--------------------------------------------\n");
|
||||
|
||||
RunThreadsOnIndividual ((block_xh-block_xl+1)*(block_yh-block_yl+1),
|
||||
!verbose, ProcessBlock_Thread);
|
||||
|
||||
//
|
||||
// build the division tree
|
||||
// oversizing the blocks guarantees that all the boundaries
|
||||
// will also get nodes.
|
||||
//
|
||||
|
||||
qprintf ("--------------------------------------------\n");
|
||||
|
||||
tree = AllocTree ();
|
||||
tree->headnode = BlockTree (block_xl-1, block_yl-1, block_xh+1, block_yh+1);
|
||||
|
||||
tree->mins[0] = (block_xl)*1024;
|
||||
tree->mins[1] = (block_yl)*1024;
|
||||
tree->mins[2] = map_mins[2] - 8;
|
||||
|
||||
tree->maxs[0] = (block_xh+1)*1024;
|
||||
tree->maxs[1] = (block_yh+1)*1024;
|
||||
tree->maxs[2] = map_maxs[2] + 8;
|
||||
|
||||
//
|
||||
// perform the global operations
|
||||
//
|
||||
MakeTreePortals (tree);
|
||||
|
||||
if (FloodEntities (tree))
|
||||
FillOutside (tree->headnode);
|
||||
else
|
||||
{
|
||||
printf ("**** leaked ****\n");
|
||||
leaked = true;
|
||||
LeakFile (tree);
|
||||
if (leaktest)
|
||||
{
|
||||
printf ("--- MAP LEAKED ---\n");
|
||||
exit (0);
|
||||
}
|
||||
}
|
||||
|
||||
MarkVisibleSides (tree, brush_start, brush_end);
|
||||
if (noopt || leaked)
|
||||
break;
|
||||
if (!optimize)
|
||||
{
|
||||
FreeTree (tree);
|
||||
}
|
||||
}
|
||||
|
||||
FloodAreas (tree);
|
||||
if (glview)
|
||||
WriteGLView (tree, source);
|
||||
MakeFaces (tree->headnode);
|
||||
FixTjuncs (tree->headnode);
|
||||
|
||||
if (!noprune)
|
||||
PruneNodes (tree->headnode);
|
||||
|
||||
WriteBSP (tree->headnode);
|
||||
|
||||
if (!leaked)
|
||||
WritePortalFile (tree);
|
||||
|
||||
FreeTree (tree);
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
ProcessSubModel
|
||||
|
||||
============
|
||||
*/
|
||||
void ProcessSubModel (void)
|
||||
{
|
||||
entity_t *e;
|
||||
int start, end;
|
||||
tree_t *tree;
|
||||
bspbrush_t *list;
|
||||
vec3_t mins, maxs;
|
||||
|
||||
e = &entities[entity_num];
|
||||
|
||||
start = e->firstbrush;
|
||||
end = start + e->numbrushes;
|
||||
|
||||
mins[0] = mins[1] = mins[2] = -4096;
|
||||
maxs[0] = maxs[1] = maxs[2] = 4096;
|
||||
list = MakeBspBrushList (start, end, mins, maxs);
|
||||
if (!nocsg)
|
||||
list = ChopBrushes (list);
|
||||
tree = BrushBSP (list, mins, maxs);
|
||||
MakeTreePortals (tree);
|
||||
MarkVisibleSides (tree, start, end);
|
||||
MakeFaces (tree->headnode);
|
||||
FixTjuncs (tree->headnode);
|
||||
WriteBSP (tree->headnode);
|
||||
FreeTree (tree);
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
ProcessModels
|
||||
============
|
||||
*/
|
||||
void ProcessModels (void)
|
||||
{
|
||||
BeginBSPFile ();
|
||||
|
||||
for (entity_num=0 ; entity_num< num_entities ; entity_num++)
|
||||
{
|
||||
if (!entities[entity_num].numbrushes)
|
||||
continue;
|
||||
|
||||
qprintf ("############### model %i ###############\n", nummodels);
|
||||
BeginModel ();
|
||||
if (entity_num == 0)
|
||||
ProcessWorldModel ();
|
||||
else
|
||||
ProcessSubModel ();
|
||||
EndModel ();
|
||||
|
||||
if (!verboseentities)
|
||||
verbose = false; // don't bother printing submodels
|
||||
}
|
||||
|
||||
EndBSPFile ();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
main
|
||||
============
|
||||
*/
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
double start, end;
|
||||
char path[1024];
|
||||
|
||||
printf ("---- qbsp3 ----\n");
|
||||
|
||||
for (i=1 ; i<argc ; i++)
|
||||
{
|
||||
if (!strcmp(argv[i],"-threads"))
|
||||
{
|
||||
numthreads = atoi (argv[i+1]);
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(argv[i],"-glview"))
|
||||
{
|
||||
glview = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-v"))
|
||||
{
|
||||
printf ("verbose = true\n");
|
||||
verbose = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-draw"))
|
||||
{
|
||||
printf ("drawflag = true\n");
|
||||
drawflag = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-noweld"))
|
||||
{
|
||||
printf ("noweld = true\n");
|
||||
noweld = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-nocsg"))
|
||||
{
|
||||
printf ("nocsg = true\n");
|
||||
nocsg = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-noshare"))
|
||||
{
|
||||
printf ("noshare = true\n");
|
||||
noshare = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-notjunc"))
|
||||
{
|
||||
printf ("notjunc = true\n");
|
||||
notjunc = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-nowater"))
|
||||
{
|
||||
printf ("nowater = true\n");
|
||||
nowater = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-noopt"))
|
||||
{
|
||||
printf ("noopt = true\n");
|
||||
noopt = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-noprune"))
|
||||
{
|
||||
printf ("noprune = true\n");
|
||||
noprune = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-nofill"))
|
||||
{
|
||||
printf ("nofill = true\n");
|
||||
nofill = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-nomerge"))
|
||||
{
|
||||
printf ("nomerge = true\n");
|
||||
nomerge = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-nosubdiv"))
|
||||
{
|
||||
printf ("nosubdiv = true\n");
|
||||
nosubdiv = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-nodetail"))
|
||||
{
|
||||
printf ("nodetail = true\n");
|
||||
nodetail = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-fulldetail"))
|
||||
{
|
||||
printf ("fulldetail = true\n");
|
||||
fulldetail = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-onlyents"))
|
||||
{
|
||||
printf ("onlyents = true\n");
|
||||
onlyents = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-micro"))
|
||||
{
|
||||
microvolume = atof(argv[i+1]);
|
||||
printf ("microvolume = %f\n", microvolume);
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-leaktest"))
|
||||
{
|
||||
printf ("leaktest = true\n");
|
||||
leaktest = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-verboseentities"))
|
||||
{
|
||||
printf ("verboseentities = true\n");
|
||||
verboseentities = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-chop"))
|
||||
{
|
||||
subdivide_size = atof(argv[i+1]);
|
||||
printf ("subdivide_size = %f\n", subdivide_size);
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-block"))
|
||||
{
|
||||
block_xl = block_xh = atoi(argv[i+1]);
|
||||
block_yl = block_yh = atoi(argv[i+2]);
|
||||
printf ("block: %i,%i\n", block_xl, block_yl);
|
||||
i+=2;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-blocks"))
|
||||
{
|
||||
block_xl = atoi(argv[i+1]);
|
||||
block_yl = atoi(argv[i+2]);
|
||||
block_xh = atoi(argv[i+3]);
|
||||
block_yh = atoi(argv[i+4]);
|
||||
printf ("blocks: %i,%i to %i,%i\n",
|
||||
block_xl, block_yl, block_xh, block_yh);
|
||||
i+=4;
|
||||
}
|
||||
else if (!strcmp (argv[i],"-tmpout"))
|
||||
{
|
||||
strcpy (outbase, "/tmp");
|
||||
}
|
||||
else if (argv[i][0] == '-')
|
||||
Error ("Unknown option \"%s\"", argv[i]);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (i != argc - 1)
|
||||
Error ("usage: qbsp3 [options] mapfile");
|
||||
|
||||
start = I_FloatTime ();
|
||||
|
||||
ThreadSetDefault ();
|
||||
numthreads = 1; // multiple threads aren't helping...
|
||||
SetQdirFromPath (argv[i]);
|
||||
|
||||
strcpy (source, ExpandArg (argv[i]));
|
||||
StripExtension (source);
|
||||
|
||||
// delete portal and line files
|
||||
sprintf (path, "%s.prt", source);
|
||||
remove (path);
|
||||
sprintf (path, "%s.lin", source);
|
||||
remove (path);
|
||||
|
||||
strcpy (name, ExpandArg (argv[i]));
|
||||
DefaultExtension (name, ".map"); // might be .reg
|
||||
|
||||
//
|
||||
// if onlyents, just grab the entites and resave
|
||||
//
|
||||
if (onlyents)
|
||||
{
|
||||
char out[1024];
|
||||
|
||||
sprintf (out, "%s.bsp", source);
|
||||
LoadBSPFile (out);
|
||||
num_entities = 0;
|
||||
|
||||
LoadMapFile (name);
|
||||
SetModelNumbers ();
|
||||
SetLightStyles ();
|
||||
|
||||
UnparseEntities ();
|
||||
|
||||
WriteBSPFile (out);
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// start from scratch
|
||||
//
|
||||
LoadMapFile (name);
|
||||
SetModelNumbers ();
|
||||
SetLightStyles ();
|
||||
|
||||
ProcessModels ();
|
||||
}
|
||||
|
||||
end = I_FloatTime ();
|
||||
printf ("%5.0f seconds elapsed\n", end-start);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
221
tools/quake2/extra/bsp/qbsp3/textures.c
Normal file
221
tools/quake2/extra/bsp/qbsp3/textures.c
Normal file
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "qbsp.h"
|
||||
|
||||
int nummiptex;
|
||||
textureref_t textureref[MAX_MAP_TEXTURES];
|
||||
|
||||
//==========================================================================
|
||||
|
||||
|
||||
int FindMiptex (char *name)
|
||||
{
|
||||
int i;
|
||||
char path[1024];
|
||||
miptex_t *mt;
|
||||
|
||||
for (i=0 ; i<nummiptex ; i++)
|
||||
if (!strcmp (name, textureref[i].name))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
if (nummiptex == MAX_MAP_TEXTURES)
|
||||
Error ("MAX_MAP_TEXTURES");
|
||||
strcpy (textureref[i].name, name);
|
||||
|
||||
// load the miptex to get the flags and values
|
||||
sprintf (path, "%stextures/%s.wal", gamedir, name);
|
||||
if (TryLoadFile (path, (void **)&mt) != -1)
|
||||
{
|
||||
textureref[i].value = LittleLong (mt->value);
|
||||
textureref[i].flags = LittleLong (mt->flags);
|
||||
textureref[i].contents = LittleLong (mt->contents);
|
||||
strcpy (textureref[i].animname, mt->animname);
|
||||
free (mt);
|
||||
}
|
||||
nummiptex++;
|
||||
|
||||
if (textureref[i].animname[0])
|
||||
FindMiptex (textureref[i].animname);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
textureAxisFromPlane
|
||||
==================
|
||||
*/
|
||||
vec3_t baseaxis[18] =
|
||||
{
|
||||
{0,0,1}, {1,0,0}, {0,-1,0}, // floor
|
||||
{0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling
|
||||
{1,0,0}, {0,1,0}, {0,0,-1}, // west wall
|
||||
{-1,0,0}, {0,1,0}, {0,0,-1}, // east wall
|
||||
{0,1,0}, {1,0,0}, {0,0,-1}, // south wall
|
||||
{0,-1,0}, {1,0,0}, {0,0,-1} // north wall
|
||||
};
|
||||
|
||||
void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv)
|
||||
{
|
||||
int bestaxis;
|
||||
vec_t dot,best;
|
||||
int i;
|
||||
|
||||
best = 0;
|
||||
bestaxis = 0;
|
||||
|
||||
for (i=0 ; i<6 ; i++)
|
||||
{
|
||||
dot = DotProduct (pln->normal, baseaxis[i*3]);
|
||||
if (dot > best)
|
||||
{
|
||||
best = dot;
|
||||
bestaxis = i;
|
||||
}
|
||||
}
|
||||
|
||||
VectorCopy (baseaxis[bestaxis*3+1], xv);
|
||||
VectorCopy (baseaxis[bestaxis*3+2], yv);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int TexinfoForBrushTexture (plane_t *plane, brush_texture_t *bt, vec3_t origin)
|
||||
{
|
||||
vec3_t vecs[2];
|
||||
int sv, tv;
|
||||
vec_t ang, sinv, cosv;
|
||||
vec_t ns, nt;
|
||||
texinfo_t tx, *tc;
|
||||
int i, j, k;
|
||||
float shift[2];
|
||||
brush_texture_t anim;
|
||||
int mt;
|
||||
|
||||
if (!bt->name[0])
|
||||
return 0;
|
||||
|
||||
memset (&tx, 0, sizeof(tx));
|
||||
strcpy (tx.texture, bt->name);
|
||||
|
||||
TextureAxisFromPlane(plane, vecs[0], vecs[1]);
|
||||
|
||||
shift[0] = DotProduct (origin, vecs[0]);
|
||||
shift[1] = DotProduct (origin, vecs[1]);
|
||||
|
||||
if (!bt->scale[0])
|
||||
bt->scale[0] = 1;
|
||||
if (!bt->scale[1])
|
||||
bt->scale[1] = 1;
|
||||
|
||||
|
||||
// rotate axis
|
||||
if (bt->rotate == 0)
|
||||
{ sinv = 0 ; cosv = 1; }
|
||||
else if (bt->rotate == 90)
|
||||
{ sinv = 1 ; cosv = 0; }
|
||||
else if (bt->rotate == 180)
|
||||
{ sinv = 0 ; cosv = -1; }
|
||||
else if (bt->rotate == 270)
|
||||
{ sinv = -1 ; cosv = 0; }
|
||||
else
|
||||
{
|
||||
ang = bt->rotate / 180 * Q_PI;
|
||||
sinv = sin(ang);
|
||||
cosv = cos(ang);
|
||||
}
|
||||
|
||||
if (vecs[0][0])
|
||||
sv = 0;
|
||||
else if (vecs[0][1])
|
||||
sv = 1;
|
||||
else
|
||||
sv = 2;
|
||||
|
||||
if (vecs[1][0])
|
||||
tv = 0;
|
||||
else if (vecs[1][1])
|
||||
tv = 1;
|
||||
else
|
||||
tv = 2;
|
||||
|
||||
for (i=0 ; i<2 ; i++)
|
||||
{
|
||||
ns = cosv * vecs[i][sv] - sinv * vecs[i][tv];
|
||||
nt = sinv * vecs[i][sv] + cosv * vecs[i][tv];
|
||||
vecs[i][sv] = ns;
|
||||
vecs[i][tv] = nt;
|
||||
}
|
||||
|
||||
for (i=0 ; i<2 ; i++)
|
||||
for (j=0 ; j<3 ; j++)
|
||||
tx.vecs[i][j] = vecs[i][j] / bt->scale[i];
|
||||
|
||||
tx.vecs[0][3] = bt->shift[0] + shift[0];
|
||||
tx.vecs[1][3] = bt->shift[1] + shift[1];
|
||||
tx.flags = bt->flags;
|
||||
tx.value = bt->value;
|
||||
|
||||
//
|
||||
// find the texinfo
|
||||
//
|
||||
tc = texinfo;
|
||||
for (i=0 ; i<numtexinfo ; i++, tc++)
|
||||
{
|
||||
if (tc->flags != tx.flags)
|
||||
continue;
|
||||
if (tc->value != tx.value)
|
||||
continue;
|
||||
for (j=0 ; j<2 ; j++)
|
||||
{
|
||||
if (strcmp (tc->texture, tx.texture))
|
||||
goto skip;
|
||||
for (k=0 ; k<4 ; k++)
|
||||
{
|
||||
if (tc->vecs[j][k] != tx.vecs[j][k])
|
||||
goto skip;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
skip:;
|
||||
}
|
||||
*tc = tx;
|
||||
numtexinfo++;
|
||||
|
||||
// load the next animation
|
||||
mt = FindMiptex (bt->name);
|
||||
if (textureref[mt].animname[0])
|
||||
{
|
||||
anim = *bt;
|
||||
strcpy (anim.name, textureref[mt].animname);
|
||||
tc->nexttexinfo = TexinfoForBrushTexture (plane, &anim, origin);
|
||||
}
|
||||
else
|
||||
tc->nexttexinfo = -1;
|
||||
|
||||
|
||||
return i;
|
||||
}
|
219
tools/quake2/extra/bsp/qbsp3/tree.c
Normal file
219
tools/quake2/extra/bsp/qbsp3/tree.c
Normal file
|
@ -0,0 +1,219 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
#include "qbsp.h"
|
||||
|
||||
extern int c_nodes;
|
||||
|
||||
void RemovePortalFromNode (portal_t *portal, node_t *l);
|
||||
|
||||
node_t *NodeForPoint (node_t *node, vec3_t origin)
|
||||
{
|
||||
plane_t *plane;
|
||||
vec_t d;
|
||||
|
||||
while (node->planenum != PLANENUM_LEAF)
|
||||
{
|
||||
plane = &mapplanes[node->planenum];
|
||||
d = DotProduct (origin, plane->normal) - plane->dist;
|
||||
if (d >= 0)
|
||||
node = node->children[0];
|
||||
else
|
||||
node = node->children[1];
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
FreeTreePortals_r
|
||||
=============
|
||||
*/
|
||||
void FreeTreePortals_r (node_t *node)
|
||||
{
|
||||
portal_t *p, *nextp;
|
||||
int s;
|
||||
|
||||
// free children
|
||||
if (node->planenum != PLANENUM_LEAF)
|
||||
{
|
||||
FreeTreePortals_r (node->children[0]);
|
||||
FreeTreePortals_r (node->children[1]);
|
||||
}
|
||||
|
||||
// free portals
|
||||
for (p=node->portals ; p ; p=nextp)
|
||||
{
|
||||
s = (p->nodes[1] == node);
|
||||
nextp = p->next[s];
|
||||
|
||||
RemovePortalFromNode (p, p->nodes[!s]);
|
||||
FreePortal (p);
|
||||
}
|
||||
node->portals = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
FreeTree_r
|
||||
=============
|
||||
*/
|
||||
void FreeTree_r (node_t *node)
|
||||
{
|
||||
face_t *f, *nextf;
|
||||
|
||||
// free children
|
||||
if (node->planenum != PLANENUM_LEAF)
|
||||
{
|
||||
FreeTree_r (node->children[0]);
|
||||
FreeTree_r (node->children[1]);
|
||||
}
|
||||
|
||||
// free bspbrushes
|
||||
FreeBrushList (node->brushlist);
|
||||
|
||||
// free faces
|
||||
for (f=node->faces ; f ; f=nextf)
|
||||
{
|
||||
nextf = f->next;
|
||||
FreeFace (f);
|
||||
}
|
||||
|
||||
// free the node
|
||||
if (node->volume)
|
||||
FreeBrush (node->volume);
|
||||
|
||||
if (numthreads == 1)
|
||||
c_nodes--;
|
||||
free (node);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
FreeTree
|
||||
=============
|
||||
*/
|
||||
void FreeTree (tree_t *tree)
|
||||
{
|
||||
FreeTreePortals_r (tree->headnode);
|
||||
FreeTree_r (tree->headnode);
|
||||
free (tree);
|
||||
}
|
||||
|
||||
//===============================================================
|
||||
|
||||
void PrintTree_r (node_t *node, int depth)
|
||||
{
|
||||
int i;
|
||||
plane_t *plane;
|
||||
bspbrush_t *bb;
|
||||
|
||||
for (i=0 ; i<depth ; i++)
|
||||
printf (" ");
|
||||
if (node->planenum == PLANENUM_LEAF)
|
||||
{
|
||||
if (!node->brushlist)
|
||||
printf ("NULL\n");
|
||||
else
|
||||
{
|
||||
for (bb=node->brushlist ; bb ; bb=bb->next)
|
||||
printf ("%i ", bb->original->brushnum);
|
||||
printf ("\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
plane = &mapplanes[node->planenum];
|
||||
printf ("#%i (%5.2f %5.2f %5.2f):%5.2f\n", node->planenum,
|
||||
plane->normal[0], plane->normal[1], plane->normal[2],
|
||||
plane->dist);
|
||||
PrintTree_r (node->children[0], depth+1);
|
||||
PrintTree_r (node->children[1], depth+1);
|
||||
}
|
||||
|
||||
/*
|
||||
=========================================================
|
||||
|
||||
NODES THAT DON'T SEPERATE DIFFERENT CONTENTS CAN BE PRUNED
|
||||
|
||||
=========================================================
|
||||
*/
|
||||
|
||||
int c_pruned;
|
||||
|
||||
/*
|
||||
============
|
||||
PruneNodes_r
|
||||
============
|
||||
*/
|
||||
void PruneNodes_r (node_t *node)
|
||||
{
|
||||
bspbrush_t *b, *next;
|
||||
|
||||
if (node->planenum == PLANENUM_LEAF)
|
||||
return;
|
||||
PruneNodes_r (node->children[0]);
|
||||
PruneNodes_r (node->children[1]);
|
||||
|
||||
if ( (node->children[0]->contents & CONTENTS_SOLID)
|
||||
&& (node->children[1]->contents & CONTENTS_SOLID) )
|
||||
{
|
||||
if (node->faces)
|
||||
Error ("node->faces seperating CONTENTS_SOLID");
|
||||
if (node->children[0]->faces || node->children[1]->faces)
|
||||
Error ("!node->faces with children");
|
||||
|
||||
// FIXME: free stuff
|
||||
node->planenum = PLANENUM_LEAF;
|
||||
node->contents = CONTENTS_SOLID;
|
||||
node->detail_seperator = false;
|
||||
|
||||
if (node->brushlist)
|
||||
Error ("PruneNodes: node->brushlist");
|
||||
|
||||
// combine brush lists
|
||||
node->brushlist = node->children[1]->brushlist;
|
||||
|
||||
for (b=node->children[0]->brushlist ; b ; b=next)
|
||||
{
|
||||
next = b->next;
|
||||
b->next = node->brushlist;
|
||||
node->brushlist = b;
|
||||
}
|
||||
|
||||
c_pruned++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PruneNodes (node_t *node)
|
||||
{
|
||||
qprintf ("--- PruneNodes ---\n");
|
||||
c_pruned = 0;
|
||||
PruneNodes_r (node);
|
||||
qprintf ("%5i pruned nodes\n", c_pruned);
|
||||
}
|
||||
|
||||
//===========================================================
|
590
tools/quake2/extra/bsp/qbsp3/writebsp.c
Normal file
590
tools/quake2/extra/bsp/qbsp3/writebsp.c
Normal file
|
@ -0,0 +1,590 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
#include "qbsp.h"
|
||||
|
||||
int c_nofaces;
|
||||
int c_facenodes;
|
||||
|
||||
|
||||
/*
|
||||
=========================================================
|
||||
|
||||
ONLY SAVE OUT PLANES THAT ARE ACTUALLY USED AS NODES
|
||||
|
||||
=========================================================
|
||||
*/
|
||||
|
||||
int planeused[MAX_MAP_PLANES];
|
||||
|
||||
/*
|
||||
============
|
||||
EmitPlanes
|
||||
|
||||
There is no oportunity to discard planes, because all of the original
|
||||
brushes will be saved in the map.
|
||||
============
|
||||
*/
|
||||
void EmitPlanes (void)
|
||||
{
|
||||
int i;
|
||||
dplane_t *dp;
|
||||
plane_t *mp;
|
||||
int planetranslate[MAX_MAP_PLANES];
|
||||
|
||||
mp = mapplanes;
|
||||
for (i=0 ; i<nummapplanes ; i++, mp++)
|
||||
{
|
||||
dp = &dplanes[numplanes];
|
||||
planetranslate[i] = numplanes;
|
||||
VectorCopy ( mp->normal, dp->normal);
|
||||
dp->dist = mp->dist;
|
||||
dp->type = mp->type;
|
||||
numplanes++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//========================================================
|
||||
|
||||
void EmitMarkFace (dleaf_t *leaf_p, face_t *f)
|
||||
{
|
||||
int i;
|
||||
int facenum;
|
||||
|
||||
while (f->merged)
|
||||
f = f->merged;
|
||||
|
||||
if (f->split[0])
|
||||
{
|
||||
EmitMarkFace (leaf_p, f->split[0]);
|
||||
EmitMarkFace (leaf_p, f->split[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
facenum = f->outputnumber;
|
||||
if (facenum == -1)
|
||||
return; // degenerate face
|
||||
|
||||
if (facenum < 0 || facenum >= numfaces)
|
||||
Error ("Bad leafface");
|
||||
for (i=leaf_p->firstleafface ; i<numleaffaces ; i++)
|
||||
if (dleaffaces[i] == facenum)
|
||||
break; // merged out face
|
||||
if (i == numleaffaces)
|
||||
{
|
||||
if (numleaffaces >= MAX_MAP_LEAFFACES)
|
||||
Error ("MAX_MAP_LEAFFACES");
|
||||
|
||||
dleaffaces[numleaffaces] = facenum;
|
||||
numleaffaces++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
EmitLeaf
|
||||
==================
|
||||
*/
|
||||
void EmitLeaf (node_t *node)
|
||||
{
|
||||
dleaf_t *leaf_p;
|
||||
portal_t *p;
|
||||
int s;
|
||||
face_t *f;
|
||||
bspbrush_t *b;
|
||||
int i;
|
||||
int brushnum;
|
||||
|
||||
// emit a leaf
|
||||
if (numleafs >= MAX_MAP_LEAFS)
|
||||
Error ("MAX_MAP_LEAFS");
|
||||
|
||||
leaf_p = &dleafs[numleafs];
|
||||
numleafs++;
|
||||
|
||||
leaf_p->contents = node->contents;
|
||||
leaf_p->cluster = node->cluster;
|
||||
leaf_p->area = node->area;
|
||||
|
||||
//
|
||||
// write bounding box info
|
||||
//
|
||||
VectorCopy (node->mins, leaf_p->mins);
|
||||
VectorCopy (node->maxs, leaf_p->maxs);
|
||||
|
||||
//
|
||||
// write the leafbrushes
|
||||
//
|
||||
leaf_p->firstleafbrush = numleafbrushes;
|
||||
for (b=node->brushlist ; b ; b=b->next)
|
||||
{
|
||||
if (numleafbrushes >= MAX_MAP_LEAFBRUSHES)
|
||||
Error ("MAX_MAP_LEAFBRUSHES");
|
||||
|
||||
brushnum = b->original - mapbrushes;
|
||||
for (i=leaf_p->firstleafbrush ; i<numleafbrushes ; i++)
|
||||
if (dleafbrushes[i] == brushnum)
|
||||
break;
|
||||
if (i == numleafbrushes)
|
||||
{
|
||||
dleafbrushes[numleafbrushes] = brushnum;
|
||||
numleafbrushes++;
|
||||
}
|
||||
}
|
||||
leaf_p->numleafbrushes = numleafbrushes - leaf_p->firstleafbrush;
|
||||
|
||||
//
|
||||
// write the leaffaces
|
||||
//
|
||||
if (leaf_p->contents & CONTENTS_SOLID)
|
||||
return; // no leaffaces in solids
|
||||
|
||||
leaf_p->firstleafface = numleaffaces;
|
||||
|
||||
for (p = node->portals ; p ; p = p->next[s])
|
||||
{
|
||||
s = (p->nodes[1] == node);
|
||||
f = p->face[s];
|
||||
if (!f)
|
||||
continue; // not a visible portal
|
||||
|
||||
EmitMarkFace (leaf_p, f);
|
||||
}
|
||||
|
||||
leaf_p->numleaffaces = numleaffaces - leaf_p->firstleafface;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
EmitFace
|
||||
==================
|
||||
*/
|
||||
void EmitFace (face_t *f)
|
||||
{
|
||||
dface_t *df;
|
||||
int i;
|
||||
int e;
|
||||
|
||||
f->outputnumber = -1;
|
||||
|
||||
if (f->numpoints < 3)
|
||||
{
|
||||
return; // degenerated
|
||||
}
|
||||
if (f->merged || f->split[0] || f->split[1])
|
||||
{
|
||||
return; // not a final face
|
||||
}
|
||||
|
||||
// save output number so leaffaces can use
|
||||
f->outputnumber = numfaces;
|
||||
|
||||
if (numfaces >= MAX_MAP_FACES)
|
||||
Error ("numfaces == MAX_MAP_FACES");
|
||||
df = &dfaces[numfaces];
|
||||
numfaces++;
|
||||
|
||||
// planenum is used by qlight, but not quake
|
||||
df->planenum = f->planenum & (~1);
|
||||
df->side = f->planenum & 1;
|
||||
|
||||
df->firstedge = numsurfedges;
|
||||
df->numedges = f->numpoints;
|
||||
df->texinfo = f->texinfo;
|
||||
for (i=0 ; i<f->numpoints ; i++)
|
||||
{
|
||||
// e = GetEdge (f->pts[i], f->pts[(i+1)%f->numpoints], f);
|
||||
e = GetEdge2 (f->vertexnums[i], f->vertexnums[(i+1)%f->numpoints], f);
|
||||
if (numsurfedges >= MAX_MAP_SURFEDGES)
|
||||
Error ("numsurfedges == MAX_MAP_SURFEDGES");
|
||||
dsurfedges[numsurfedges] = e;
|
||||
numsurfedges++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
EmitDrawingNode_r
|
||||
============
|
||||
*/
|
||||
int EmitDrawNode_r (node_t *node)
|
||||
{
|
||||
dnode_t *n;
|
||||
face_t *f;
|
||||
int i;
|
||||
|
||||
if (node->planenum == PLANENUM_LEAF)
|
||||
{
|
||||
EmitLeaf (node);
|
||||
return -numleafs;
|
||||
}
|
||||
|
||||
// emit a node
|
||||
if (numnodes == MAX_MAP_NODES)
|
||||
Error ("MAX_MAP_NODES");
|
||||
n = &dnodes[numnodes];
|
||||
numnodes++;
|
||||
|
||||
VectorCopy (node->mins, n->mins);
|
||||
VectorCopy (node->maxs, n->maxs);
|
||||
|
||||
planeused[node->planenum]++;
|
||||
planeused[node->planenum^1]++;
|
||||
|
||||
if (node->planenum & 1)
|
||||
Error ("WriteDrawNodes_r: odd planenum");
|
||||
n->planenum = node->planenum;
|
||||
n->firstface = numfaces;
|
||||
|
||||
if (!node->faces)
|
||||
c_nofaces++;
|
||||
else
|
||||
c_facenodes++;
|
||||
|
||||
for (f=node->faces ; f ; f=f->next)
|
||||
EmitFace (f);
|
||||
|
||||
n->numfaces = numfaces - n->firstface;
|
||||
|
||||
|
||||
//
|
||||
// recursively output the other nodes
|
||||
//
|
||||
for (i=0 ; i<2 ; i++)
|
||||
{
|
||||
if (node->children[i]->planenum == PLANENUM_LEAF)
|
||||
{
|
||||
n->children[i] = -(numleafs + 1);
|
||||
EmitLeaf (node->children[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
n->children[i] = numnodes;
|
||||
EmitDrawNode_r (node->children[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return n - dnodes;
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
WriteBSP
|
||||
============
|
||||
*/
|
||||
void WriteBSP (node_t *headnode)
|
||||
{
|
||||
int oldfaces;
|
||||
|
||||
c_nofaces = 0;
|
||||
c_facenodes = 0;
|
||||
|
||||
qprintf ("--- WriteBSP ---\n");
|
||||
|
||||
oldfaces = numfaces;
|
||||
dmodels[nummodels].headnode = EmitDrawNode_r (headnode);
|
||||
EmitAreaPortals (headnode);
|
||||
|
||||
qprintf ("%5i nodes with faces\n", c_facenodes);
|
||||
qprintf ("%5i nodes without faces\n", c_nofaces);
|
||||
qprintf ("%5i faces\n", numfaces-oldfaces);
|
||||
}
|
||||
|
||||
//===========================================================
|
||||
|
||||
/*
|
||||
============
|
||||
SetModelNumbers
|
||||
============
|
||||
*/
|
||||
void SetModelNumbers (void)
|
||||
{
|
||||
int i;
|
||||
int models;
|
||||
char value[10];
|
||||
|
||||
models = 1;
|
||||
for (i=1 ; i<num_entities ; i++)
|
||||
{
|
||||
if (entities[i].numbrushes)
|
||||
{
|
||||
sprintf (value, "*%i", models);
|
||||
models++;
|
||||
SetKeyValue (&entities[i], "model", value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
SetLightStyles
|
||||
============
|
||||
*/
|
||||
#define MAX_SWITCHED_LIGHTS 32
|
||||
void SetLightStyles (void)
|
||||
{
|
||||
int stylenum;
|
||||
char *t;
|
||||
entity_t *e;
|
||||
int i, j;
|
||||
char value[10];
|
||||
char lighttargets[MAX_SWITCHED_LIGHTS][64];
|
||||
|
||||
|
||||
// any light that is controlled (has a targetname)
|
||||
// must have a unique style number generated for it
|
||||
|
||||
stylenum = 0;
|
||||
for (i=1 ; i<num_entities ; i++)
|
||||
{
|
||||
e = &entities[i];
|
||||
|
||||
t = ValueForKey (e, "classname");
|
||||
if (Q_strncasecmp (t, "light", 5))
|
||||
continue;
|
||||
t = ValueForKey (e, "targetname");
|
||||
if (!t[0])
|
||||
continue;
|
||||
|
||||
// find this targetname
|
||||
for (j=0 ; j<stylenum ; j++)
|
||||
if (!strcmp (lighttargets[j], t))
|
||||
break;
|
||||
if (j == stylenum)
|
||||
{
|
||||
if (stylenum == MAX_SWITCHED_LIGHTS)
|
||||
Error ("stylenum == MAX_SWITCHED_LIGHTS");
|
||||
strcpy (lighttargets[j], t);
|
||||
stylenum++;
|
||||
}
|
||||
sprintf (value, "%i", 32 + j);
|
||||
SetKeyValue (e, "style", value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//===========================================================
|
||||
|
||||
/*
|
||||
============
|
||||
EmitBrushes
|
||||
============
|
||||
*/
|
||||
void EmitBrushes (void)
|
||||
{
|
||||
int i, j, bnum, s, x;
|
||||
dbrush_t *db;
|
||||
mapbrush_t *b;
|
||||
dbrushside_t *cp;
|
||||
vec3_t normal;
|
||||
vec_t dist;
|
||||
int planenum;
|
||||
|
||||
numbrushsides = 0;
|
||||
numbrushes = nummapbrushes;
|
||||
|
||||
for (bnum=0 ; bnum<nummapbrushes ; bnum++)
|
||||
{
|
||||
b = &mapbrushes[bnum];
|
||||
db = &dbrushes[bnum];
|
||||
|
||||
db->contents = b->contents;
|
||||
db->firstside = numbrushsides;
|
||||
db->numsides = b->numsides;
|
||||
for (j=0 ; j<b->numsides ; j++)
|
||||
{
|
||||
if (numbrushsides == MAX_MAP_BRUSHSIDES)
|
||||
Error ("MAX_MAP_BRUSHSIDES");
|
||||
cp = &dbrushsides[numbrushsides];
|
||||
numbrushsides++;
|
||||
cp->planenum = b->original_sides[j].planenum;
|
||||
cp->texinfo = b->original_sides[j].texinfo;
|
||||
}
|
||||
|
||||
// add any axis planes not contained in the brush to bevel off corners
|
||||
for (x=0 ; x<3 ; x++)
|
||||
for (s=-1 ; s<=1 ; s+=2)
|
||||
{
|
||||
// add the plane
|
||||
VectorCopy (vec3_origin, normal);
|
||||
normal[x] = s;
|
||||
if (s == -1)
|
||||
dist = -b->mins[x];
|
||||
else
|
||||
dist = b->maxs[x];
|
||||
planenum = FindFloatPlane (normal, dist);
|
||||
for (i=0 ; i<b->numsides ; i++)
|
||||
if (b->original_sides[i].planenum == planenum)
|
||||
break;
|
||||
if (i == b->numsides)
|
||||
{
|
||||
if (numbrushsides >= MAX_MAP_BRUSHSIDES)
|
||||
Error ("MAX_MAP_BRUSHSIDES");
|
||||
|
||||
dbrushsides[numbrushsides].planenum = planenum;
|
||||
dbrushsides[numbrushsides].texinfo =
|
||||
dbrushsides[numbrushsides-1].texinfo;
|
||||
numbrushsides++;
|
||||
db->numsides++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//===========================================================
|
||||
|
||||
/*
|
||||
==================
|
||||
BeginBSPFile
|
||||
==================
|
||||
*/
|
||||
void BeginBSPFile (void)
|
||||
{
|
||||
// these values may actually be initialized
|
||||
// if the file existed when loaded, so clear them explicitly
|
||||
nummodels = 0;
|
||||
numfaces = 0;
|
||||
numnodes = 0;
|
||||
numbrushsides = 0;
|
||||
numvertexes = 0;
|
||||
numleaffaces = 0;
|
||||
numleafbrushes = 0;
|
||||
numsurfedges = 0;
|
||||
|
||||
// edge 0 is not used, because 0 can't be negated
|
||||
numedges = 1;
|
||||
|
||||
// leave vertex 0 as an error
|
||||
numvertexes = 1;
|
||||
|
||||
// leave leaf 0 as an error
|
||||
numleafs = 1;
|
||||
dleafs[0].contents = CONTENTS_SOLID;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
EndBSPFile
|
||||
============
|
||||
*/
|
||||
void EndBSPFile (void)
|
||||
{
|
||||
char path[1024];
|
||||
int len;
|
||||
byte *buf;
|
||||
|
||||
|
||||
EmitBrushes ();
|
||||
EmitPlanes ();
|
||||
UnparseEntities ();
|
||||
|
||||
// load the pop
|
||||
#if 0
|
||||
sprintf (path, "%s/pics/pop.lmp", gamedir);
|
||||
len = LoadFile (path, &buf);
|
||||
memcpy (dpop, buf, sizeof(dpop));
|
||||
free (buf);
|
||||
#endif
|
||||
|
||||
// write the map
|
||||
sprintf (path, "%s.bsp", source);
|
||||
printf ("Writing %s\n", path);
|
||||
WriteBSPFile (path);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
BeginModel
|
||||
==================
|
||||
*/
|
||||
int firstmodleaf;
|
||||
extern int firstmodeledge;
|
||||
extern int firstmodelface;
|
||||
void BeginModel (void)
|
||||
{
|
||||
dmodel_t *mod;
|
||||
int start, end;
|
||||
mapbrush_t *b;
|
||||
int j;
|
||||
entity_t *e;
|
||||
vec3_t mins, maxs;
|
||||
|
||||
if (nummodels == MAX_MAP_MODELS)
|
||||
Error ("MAX_MAP_MODELS");
|
||||
mod = &dmodels[nummodels];
|
||||
|
||||
mod->firstface = numfaces;
|
||||
|
||||
firstmodleaf = numleafs;
|
||||
firstmodeledge = numedges;
|
||||
firstmodelface = numfaces;
|
||||
|
||||
//
|
||||
// bound the brushes
|
||||
//
|
||||
e = &entities[entity_num];
|
||||
|
||||
start = e->firstbrush;
|
||||
end = start + e->numbrushes;
|
||||
ClearBounds (mins, maxs);
|
||||
|
||||
for (j=start ; j<end ; j++)
|
||||
{
|
||||
b = &mapbrushes[j];
|
||||
if (!b->numsides)
|
||||
continue; // not a real brush (origin brush)
|
||||
AddPointToBounds (b->mins, mins, maxs);
|
||||
AddPointToBounds (b->maxs, mins, maxs);
|
||||
}
|
||||
|
||||
VectorCopy (mins, mod->mins);
|
||||
VectorCopy (maxs, mod->maxs);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
EndModel
|
||||
==================
|
||||
*/
|
||||
void EndModel (void)
|
||||
{
|
||||
dmodel_t *mod;
|
||||
|
||||
mod = &dmodels[nummodels];
|
||||
|
||||
mod->numfaces = numfaces - mod->firstface;
|
||||
|
||||
nummodels++;
|
||||
}
|
||||
|
1316
tools/quake2/extra/bsp/qrad3/lightmap.c
Normal file
1316
tools/quake2/extra/bsp/qrad3/lightmap.c
Normal file
File diff suppressed because it is too large
Load diff
77
tools/quake2/extra/bsp/qrad3/makefile
Normal file
77
tools/quake2/extra/bsp/qrad3/makefile
Normal file
|
@ -0,0 +1,77 @@
|
|||
|
||||
CFLAGS = -c
|
||||
LDFLAGS =
|
||||
ODIR = baddir
|
||||
|
||||
EXEBASE = qrad3
|
||||
EXE = $(ODIR)/qrad3
|
||||
all: $(EXE)
|
||||
|
||||
_next:
|
||||
make "CFLAGS = -c -g -I../../common" "ODIR = next"
|
||||
|
||||
_irix:
|
||||
make "CFLAGS = -c -Ofast=ip32_10k -I../../common -Xcpluscomm" "LDFLAGS = -Ofast=ip32_10k" "ODIR = irix"
|
||||
|
||||
_irixdebug:
|
||||
make "CFLAGS = -c -g -I../../common -Xcpluscomm" "LDFLAGS = " "ODIR = irix"
|
||||
|
||||
_irixinst:
|
||||
make "CFLAGS = -c -Ofast=ip32_10k -I../../common -Xcpluscomm" "LDFLAGS = -Ofast=ip32_10k" "ODIR = irix"
|
||||
cp irix/$(EXEBASE) /limbo/quake2/bin_irix
|
||||
|
||||
_irixclean:
|
||||
rm -f irix/*.o irix/$(EXEBASE)
|
||||
|
||||
_osf:
|
||||
make "CFLAGS = -c -O4 -I../../common -threads" "LDFLAGS = -threads" "ODIR = osf"
|
||||
|
||||
clean:
|
||||
rm -f irix/*.o irix/$(EXEBASE)
|
||||
|
||||
install:
|
||||
cp irix/$(EXEBASE) /limbo/quake2/bin_irix
|
||||
|
||||
|
||||
FILES = $(ODIR)/bspfile.o $(ODIR)/cmdlib.o $(ODIR)/lbmlib.o $(ODIR)/mathlib.o $(ODIR)/scriplib.o $(ODIR)/polylib.o $(ODIR)/qrad3.o $(ODIR)/threads.o $(ODIR)/trace.o $(ODIR)/lightmap.o $(ODIR)/patches.o
|
||||
|
||||
$(EXE) : $(FILES)
|
||||
cc -o $(EXE) $(LDFLAGS) $(FILES) -lm
|
||||
|
||||
$(ODIR)/qrad3.o : qrad3.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/patches.o : patches.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/trace.o : trace.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/vismat.o : vismat.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/lightmap.o : lightmap.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/cmdlib.o : ../../common/cmdlib.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/lbmlib.o : ../../common/lbmlib.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/mathlib.o : ../../common/mathlib.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/polylib.o : ../../common/polylib.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/scriplib.o : ../../common/scriplib.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/threads.o : ../../common/threads.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/bspfile.o : ../../common/bspfile.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
515
tools/quake2/extra/bsp/qrad3/patches.c
Normal file
515
tools/quake2/extra/bsp/qrad3/patches.c
Normal file
|
@ -0,0 +1,515 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "qrad.h"
|
||||
|
||||
vec3_t texture_reflectivity[MAX_MAP_TEXINFO];
|
||||
|
||||
/*
|
||||
===================================================================
|
||||
|
||||
TEXTURE LIGHT VALUES
|
||||
|
||||
===================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
======================
|
||||
CalcTextureReflectivity
|
||||
======================
|
||||
*/
|
||||
void CalcTextureReflectivity (void)
|
||||
{
|
||||
int i;
|
||||
int j, k, texels;
|
||||
int color[3];
|
||||
int texel;
|
||||
byte *palette;
|
||||
char path[1024];
|
||||
float r, scale;
|
||||
miptex_t *mt;
|
||||
|
||||
sprintf (path, "%spics/colormap.pcx", gamedir);
|
||||
|
||||
// get the game palette
|
||||
Load256Image (path, NULL, &palette, NULL, NULL);
|
||||
|
||||
// allways set index 0 even if no textures
|
||||
texture_reflectivity[0][0] = 0.5;
|
||||
texture_reflectivity[0][1] = 0.5;
|
||||
texture_reflectivity[0][2] = 0.5;
|
||||
|
||||
for (i=0 ; i<numtexinfo ; i++)
|
||||
{
|
||||
// see if an earlier texinfo allready got the value
|
||||
for (j=0 ; j<i ; j++)
|
||||
{
|
||||
if (!strcmp (texinfo[i].texture, texinfo[j].texture))
|
||||
{
|
||||
VectorCopy (texture_reflectivity[j], texture_reflectivity[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j != i)
|
||||
continue;
|
||||
|
||||
// load the wal file
|
||||
sprintf (path, "%stextures/%s.wal", gamedir, texinfo[i].texture);
|
||||
if (TryLoadFile (path, (void **)&mt) == -1)
|
||||
{
|
||||
printf ("Couldn't load %s\n", path);
|
||||
texture_reflectivity[i][0] = 0.5;
|
||||
texture_reflectivity[i][1] = 0.5;
|
||||
texture_reflectivity[i][2] = 0.5;
|
||||
continue;
|
||||
}
|
||||
texels = LittleLong(mt->width)*LittleLong(mt->height);
|
||||
color[0] = color[1] = color[2] = 0;
|
||||
|
||||
for (j=0 ; j<texels ; j++)
|
||||
{
|
||||
texel = ((byte *)mt)[LittleLong(mt->offsets[0]) + j];
|
||||
for (k=0 ; k<3 ; k++)
|
||||
color[k] += palette[texel*3+k];
|
||||
}
|
||||
|
||||
for (j=0 ; j<3 ; j++)
|
||||
{
|
||||
r = color[j]/texels/255.0;
|
||||
texture_reflectivity[i][j] = r;
|
||||
}
|
||||
// scale the reflectivity up, because the textures are
|
||||
// so dim
|
||||
scale = ColorNormalize (texture_reflectivity[i],
|
||||
texture_reflectivity[i]);
|
||||
if (scale < 0.5)
|
||||
{
|
||||
scale *= 2;
|
||||
VectorScale (texture_reflectivity[i], scale, texture_reflectivity[i]);
|
||||
}
|
||||
#if 0
|
||||
texture_reflectivity[i][0] = 0.5;
|
||||
texture_reflectivity[i][1] = 0.5;
|
||||
texture_reflectivity[i][2] = 0.5;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=======================================================================
|
||||
|
||||
MAKE FACES
|
||||
|
||||
=======================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
=============
|
||||
WindingFromFace
|
||||
=============
|
||||
*/
|
||||
winding_t *WindingFromFace (dface_t *f)
|
||||
{
|
||||
int i;
|
||||
int se;
|
||||
dvertex_t *dv;
|
||||
int v;
|
||||
winding_t *w;
|
||||
|
||||
w = AllocWinding (f->numedges);
|
||||
w->numpoints = f->numedges;
|
||||
|
||||
for (i=0 ; i<f->numedges ; i++)
|
||||
{
|
||||
se = dsurfedges[f->firstedge + i];
|
||||
if (se < 0)
|
||||
v = dedges[-se].v[1];
|
||||
else
|
||||
v = dedges[se].v[0];
|
||||
|
||||
dv = &dvertexes[v];
|
||||
VectorCopy (dv->point, w->p[i]);
|
||||
}
|
||||
|
||||
RemoveColinearPoints (w);
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
BaseLightForFace
|
||||
=============
|
||||
*/
|
||||
void BaseLightForFace (dface_t *f, vec3_t color)
|
||||
{
|
||||
texinfo_t *tx;
|
||||
|
||||
//
|
||||
// check for light emited by texture
|
||||
//
|
||||
tx = &texinfo[f->texinfo];
|
||||
if (!(tx->flags & SURF_LIGHT) || tx->value == 0)
|
||||
{
|
||||
VectorClear (color);
|
||||
return;
|
||||
}
|
||||
|
||||
VectorScale (texture_reflectivity[f->texinfo], tx->value, color);
|
||||
}
|
||||
|
||||
qboolean IsSky (dface_t *f)
|
||||
{
|
||||
texinfo_t *tx;
|
||||
|
||||
tx = &texinfo[f->texinfo];
|
||||
if (tx->flags & SURF_SKY)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
MakePatchForFace
|
||||
=============
|
||||
*/
|
||||
float totalarea;
|
||||
void MakePatchForFace (int fn, winding_t *w)
|
||||
{
|
||||
dface_t *f;
|
||||
float area;
|
||||
patch_t *patch;
|
||||
dplane_t *pl;
|
||||
int i;
|
||||
vec3_t color;
|
||||
dleaf_t *leaf;
|
||||
|
||||
f = &dfaces[fn];
|
||||
|
||||
area = WindingArea (w);
|
||||
totalarea += area;
|
||||
|
||||
patch = &patches[num_patches];
|
||||
if (num_patches == MAX_PATCHES)
|
||||
Error ("num_patches == MAX_PATCHES");
|
||||
patch->next = face_patches[fn];
|
||||
face_patches[fn] = patch;
|
||||
|
||||
patch->winding = w;
|
||||
|
||||
if (f->side)
|
||||
patch->plane = &backplanes[f->planenum];
|
||||
else
|
||||
patch->plane = &dplanes[f->planenum];
|
||||
if (face_offset[fn][0] || face_offset[fn][1] || face_offset[fn][2] )
|
||||
{ // origin offset faces must create new planes
|
||||
if (numplanes + fakeplanes >= MAX_MAP_PLANES)
|
||||
Error ("numplanes + fakeplanes >= MAX_MAP_PLANES");
|
||||
pl = &dplanes[numplanes + fakeplanes];
|
||||
fakeplanes++;
|
||||
|
||||
*pl = *(patch->plane);
|
||||
pl->dist += DotProduct (face_offset[fn], pl->normal);
|
||||
patch->plane = pl;
|
||||
}
|
||||
|
||||
WindingCenter (w, patch->origin);
|
||||
VectorAdd (patch->origin, patch->plane->normal, patch->origin);
|
||||
leaf = PointInLeaf(patch->origin);
|
||||
patch->cluster = leaf->cluster;
|
||||
if (patch->cluster == -1)
|
||||
qprintf ("patch->cluster == -1\n");
|
||||
|
||||
patch->area = area;
|
||||
if (patch->area <= 1)
|
||||
patch->area = 1;
|
||||
patch->sky = IsSky (f);
|
||||
|
||||
VectorCopy (texture_reflectivity[f->texinfo], patch->reflectivity);
|
||||
|
||||
// non-bmodel patches can emit light
|
||||
if (fn < dmodels[0].numfaces)
|
||||
{
|
||||
BaseLightForFace (f, patch->baselight);
|
||||
|
||||
ColorNormalize (patch->reflectivity, color);
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
patch->baselight[i] *= color[i];
|
||||
|
||||
VectorCopy (patch->baselight, patch->totallight);
|
||||
}
|
||||
num_patches++;
|
||||
}
|
||||
|
||||
|
||||
entity_t *EntityForModel (int modnum)
|
||||
{
|
||||
int i;
|
||||
char *s;
|
||||
char name[16];
|
||||
|
||||
sprintf (name, "*%i", modnum);
|
||||
// search the entities for one using modnum
|
||||
for (i=0 ; i<num_entities ; i++)
|
||||
{
|
||||
s = ValueForKey (&entities[i], "model");
|
||||
if (!strcmp (s, name))
|
||||
return &entities[i];
|
||||
}
|
||||
|
||||
return &entities[0];
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
MakePatches
|
||||
=============
|
||||
*/
|
||||
void MakePatches (void)
|
||||
{
|
||||
int i, j, k;
|
||||
dface_t *f;
|
||||
int fn;
|
||||
winding_t *w;
|
||||
dmodel_t *mod;
|
||||
vec3_t origin;
|
||||
entity_t *ent;
|
||||
|
||||
qprintf ("%i faces\n", numfaces);
|
||||
|
||||
for (i=0 ; i<nummodels ; i++)
|
||||
{
|
||||
mod = &dmodels[i];
|
||||
ent = EntityForModel (i);
|
||||
// bmodels with origin brushes need to be offset into their
|
||||
// in-use position
|
||||
GetVectorForKey (ent, "origin", origin);
|
||||
//VectorCopy (vec3_origin, origin);
|
||||
|
||||
for (j=0 ; j<mod->numfaces ; j++)
|
||||
{
|
||||
fn = mod->firstface + j;
|
||||
face_entity[fn] = ent;
|
||||
VectorCopy (origin, face_offset[fn]);
|
||||
f = &dfaces[fn];
|
||||
w = WindingFromFace (f);
|
||||
for (k=0 ; k<w->numpoints ; k++)
|
||||
{
|
||||
VectorAdd (w->p[k], origin, w->p[k]);
|
||||
}
|
||||
MakePatchForFace (fn, w);
|
||||
}
|
||||
}
|
||||
|
||||
qprintf ("%i sqaure feet\n", (int)(totalarea/64));
|
||||
}
|
||||
|
||||
/*
|
||||
=======================================================================
|
||||
|
||||
SUBDIVIDE
|
||||
|
||||
=======================================================================
|
||||
*/
|
||||
|
||||
void FinishSplit (patch_t *patch, patch_t *newp)
|
||||
{
|
||||
dleaf_t *leaf;
|
||||
|
||||
VectorCopy (patch->baselight, newp->baselight);
|
||||
VectorCopy (patch->totallight, newp->totallight);
|
||||
VectorCopy (patch->reflectivity, newp->reflectivity);
|
||||
newp->plane = patch->plane;
|
||||
newp->sky = patch->sky;
|
||||
|
||||
patch->area = WindingArea (patch->winding);
|
||||
newp->area = WindingArea (newp->winding);
|
||||
|
||||
if (patch->area <= 1)
|
||||
patch->area = 1;
|
||||
if (newp->area <= 1)
|
||||
newp->area = 1;
|
||||
|
||||
WindingCenter (patch->winding, patch->origin);
|
||||
VectorAdd (patch->origin, patch->plane->normal, patch->origin);
|
||||
leaf = PointInLeaf(patch->origin);
|
||||
patch->cluster = leaf->cluster;
|
||||
if (patch->cluster == -1)
|
||||
qprintf ("patch->cluster == -1\n");
|
||||
|
||||
WindingCenter (newp->winding, newp->origin);
|
||||
VectorAdd (newp->origin, newp->plane->normal, newp->origin);
|
||||
leaf = PointInLeaf(newp->origin);
|
||||
newp->cluster = leaf->cluster;
|
||||
if (newp->cluster == -1)
|
||||
qprintf ("patch->cluster == -1\n");
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
SubdividePatch
|
||||
|
||||
Chops the patch only if its local bounds exceed the max size
|
||||
=============
|
||||
*/
|
||||
void SubdividePatch (patch_t *patch)
|
||||
{
|
||||
winding_t *w, *o1, *o2;
|
||||
vec3_t mins, maxs, total;
|
||||
vec3_t split;
|
||||
vec_t dist;
|
||||
int i, j;
|
||||
vec_t v;
|
||||
patch_t *newp;
|
||||
|
||||
w = patch->winding;
|
||||
mins[0] = mins[1] = mins[2] = 99999;
|
||||
maxs[0] = maxs[1] = maxs[2] = -99999;
|
||||
for (i=0 ; i<w->numpoints ; i++)
|
||||
{
|
||||
for (j=0 ; j<3 ; j++)
|
||||
{
|
||||
v = w->p[i][j];
|
||||
if (v < mins[j])
|
||||
mins[j] = v;
|
||||
if (v > maxs[j])
|
||||
maxs[j] = v;
|
||||
}
|
||||
}
|
||||
VectorSubtract (maxs, mins, total);
|
||||
for (i=0 ; i<3 ; i++)
|
||||
if (total[i] > (subdiv+1) )
|
||||
break;
|
||||
if (i == 3)
|
||||
{
|
||||
// no splitting needed
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// split the winding
|
||||
//
|
||||
VectorCopy (vec3_origin, split);
|
||||
split[i] = 1;
|
||||
dist = (mins[i] + maxs[i])*0.5;
|
||||
ClipWindingEpsilon (w, split, dist, ON_EPSILON, &o1, &o2);
|
||||
|
||||
//
|
||||
// create a new patch
|
||||
//
|
||||
if (num_patches == MAX_PATCHES)
|
||||
Error ("MAX_PATCHES");
|
||||
newp = &patches[num_patches];
|
||||
num_patches++;
|
||||
|
||||
newp->next = patch->next;
|
||||
patch->next = newp;
|
||||
|
||||
patch->winding = o1;
|
||||
newp->winding = o2;
|
||||
|
||||
FinishSplit (patch, newp);
|
||||
|
||||
SubdividePatch (patch);
|
||||
SubdividePatch (newp);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
DicePatch
|
||||
|
||||
Chops the patch by a global grid
|
||||
=============
|
||||
*/
|
||||
void DicePatch (patch_t *patch)
|
||||
{
|
||||
winding_t *w, *o1, *o2;
|
||||
vec3_t mins, maxs;
|
||||
vec3_t split;
|
||||
vec_t dist;
|
||||
int i;
|
||||
patch_t *newp;
|
||||
|
||||
w = patch->winding;
|
||||
WindingBounds (w, mins, maxs);
|
||||
for (i=0 ; i<3 ; i++)
|
||||
if (floor((mins[i]+1)/subdiv) < floor((maxs[i]-1)/subdiv))
|
||||
break;
|
||||
if (i == 3)
|
||||
{
|
||||
// no splitting needed
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// split the winding
|
||||
//
|
||||
VectorCopy (vec3_origin, split);
|
||||
split[i] = 1;
|
||||
dist = subdiv*(1+floor((mins[i]+1)/subdiv));
|
||||
ClipWindingEpsilon (w, split, dist, ON_EPSILON, &o1, &o2);
|
||||
|
||||
//
|
||||
// create a new patch
|
||||
//
|
||||
if (num_patches == MAX_PATCHES)
|
||||
Error ("MAX_PATCHES");
|
||||
newp = &patches[num_patches];
|
||||
num_patches++;
|
||||
|
||||
newp->next = patch->next;
|
||||
patch->next = newp;
|
||||
|
||||
patch->winding = o1;
|
||||
newp->winding = o2;
|
||||
|
||||
FinishSplit (patch, newp);
|
||||
|
||||
DicePatch (patch);
|
||||
DicePatch (newp);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
SubdividePatches
|
||||
=============
|
||||
*/
|
||||
void SubdividePatches (void)
|
||||
{
|
||||
int i, num;
|
||||
|
||||
if (subdiv < 1)
|
||||
return;
|
||||
|
||||
num = num_patches; // because the list will grow
|
||||
for (i=0 ; i<num ; i++)
|
||||
{
|
||||
// SubdividePatch (&patches[i]);
|
||||
DicePatch (&patches[i]);
|
||||
}
|
||||
qprintf ("%i patches after subdivision\n", num_patches);
|
||||
}
|
||||
|
||||
//=====================================================================
|
158
tools/quake2/extra/bsp/qrad3/qrad.h
Normal file
158
tools/quake2/extra/bsp/qrad3/qrad.h
Normal file
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "cmdlib.h"
|
||||
#include "mathlib.h"
|
||||
#include "bspfile.h"
|
||||
#include "polylib.h"
|
||||
#include "threads.h"
|
||||
#include "lbmlib.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
emit_surface,
|
||||
emit_point,
|
||||
emit_spotlight
|
||||
} emittype_t;
|
||||
|
||||
|
||||
|
||||
typedef struct directlight_s
|
||||
{
|
||||
struct directlight_s *next;
|
||||
emittype_t type;
|
||||
|
||||
float intensity;
|
||||
int style;
|
||||
vec3_t origin;
|
||||
vec3_t color;
|
||||
vec3_t normal; // for surfaces and spotlights
|
||||
float stopdot; // for spotlights
|
||||
} directlight_t;
|
||||
|
||||
|
||||
// the sum of all tranfer->transfer values for a given patch
|
||||
// should equal exactly 0x10000, showing that all radiance
|
||||
// reaches other patches
|
||||
typedef struct
|
||||
{
|
||||
unsigned short patch;
|
||||
unsigned short transfer;
|
||||
} transfer_t;
|
||||
|
||||
|
||||
#define MAX_PATCHES 65000 // larger will cause 32 bit overflows
|
||||
|
||||
typedef struct patch_s
|
||||
{
|
||||
winding_t *winding;
|
||||
struct patch_s *next; // next in face
|
||||
int numtransfers;
|
||||
transfer_t *transfers;
|
||||
|
||||
int cluster; // for pvs checking
|
||||
vec3_t origin;
|
||||
dplane_t *plane;
|
||||
|
||||
qboolean sky;
|
||||
|
||||
vec3_t totallight; // accumulated by radiosity
|
||||
// does NOT include light
|
||||
// accounted for by direct lighting
|
||||
float area;
|
||||
|
||||
// illuminance * reflectivity = radiosity
|
||||
vec3_t reflectivity;
|
||||
vec3_t baselight; // emissivity only
|
||||
|
||||
// each style 0 lightmap sample in the patch will be
|
||||
// added up to get the average illuminance of the entire patch
|
||||
vec3_t samplelight;
|
||||
int samples; // for averaging direct light
|
||||
} patch_t;
|
||||
|
||||
extern patch_t *face_patches[MAX_MAP_FACES];
|
||||
extern entity_t *face_entity[MAX_MAP_FACES];
|
||||
extern vec3_t face_offset[MAX_MAP_FACES]; // for rotating bmodels
|
||||
extern patch_t patches[MAX_PATCHES];
|
||||
extern unsigned num_patches;
|
||||
|
||||
extern int leafparents[MAX_MAP_LEAFS];
|
||||
extern int nodeparents[MAX_MAP_NODES];
|
||||
|
||||
extern float lightscale;
|
||||
|
||||
|
||||
void MakeShadowSplits (void);
|
||||
|
||||
//==============================================
|
||||
|
||||
|
||||
void BuildVisMatrix (void);
|
||||
qboolean CheckVisBit (unsigned p1, unsigned p2);
|
||||
|
||||
//==============================================
|
||||
|
||||
extern float ambient, maxlight;
|
||||
|
||||
void LinkPlaneFaces (void);
|
||||
|
||||
extern qboolean extrasamples;
|
||||
extern int numbounce;
|
||||
|
||||
extern directlight_t *directlights[MAX_MAP_LEAFS];
|
||||
|
||||
extern byte nodehit[MAX_MAP_NODES];
|
||||
|
||||
void BuildLightmaps (void);
|
||||
|
||||
void BuildFacelights (int facenum);
|
||||
|
||||
void FinalLightFace (int facenum);
|
||||
|
||||
qboolean PvsForOrigin (vec3_t org, byte *pvs);
|
||||
|
||||
int TestLine_r (int node, vec3_t start, vec3_t stop);
|
||||
|
||||
void CreateDirectLights (void);
|
||||
|
||||
dleaf_t *PointInLeaf (vec3_t point);
|
||||
|
||||
|
||||
extern dplane_t backplanes[MAX_MAP_PLANES];
|
||||
extern int fakeplanes; // created planes for origin offset
|
||||
|
||||
extern float subdiv;
|
||||
|
||||
extern float direct_scale;
|
||||
extern float entity_scale;
|
||||
|
||||
int PointInLeafnum (vec3_t point);
|
||||
void MakeTnodes (dmodel_t *bm);
|
||||
void MakePatches (void);
|
||||
void SubdividePatches (void);
|
||||
void PairEdges (void);
|
||||
void CalcTextureReflectivity (void);
|
717
tools/quake2/extra/bsp/qrad3/qrad3.c
Normal file
717
tools/quake2/extra/bsp/qrad3/qrad3.c
Normal file
|
@ -0,0 +1,717 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "qrad.h"
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
NOTES
|
||||
-----
|
||||
|
||||
every surface must be divided into at least two patches each axis
|
||||
|
||||
*/
|
||||
|
||||
patch_t *face_patches[MAX_MAP_FACES];
|
||||
entity_t *face_entity[MAX_MAP_FACES];
|
||||
patch_t patches[MAX_PATCHES];
|
||||
unsigned num_patches;
|
||||
|
||||
vec3_t radiosity[MAX_PATCHES]; // light leaving a patch
|
||||
vec3_t illumination[MAX_PATCHES]; // light arriving at a patch
|
||||
|
||||
vec3_t face_offset[MAX_MAP_FACES]; // for rotating bmodels
|
||||
dplane_t backplanes[MAX_MAP_PLANES];
|
||||
|
||||
char inbase[32], outbase[32];
|
||||
|
||||
int fakeplanes; // created planes for origin offset
|
||||
|
||||
int numbounce = 8;
|
||||
qboolean extrasamples;
|
||||
|
||||
float subdiv = 64;
|
||||
qboolean dumppatches;
|
||||
|
||||
void BuildLightmaps (void);
|
||||
int TestLine (vec3_t start, vec3_t stop);
|
||||
|
||||
int junk;
|
||||
|
||||
float ambient = 0;
|
||||
float maxlight = 196;
|
||||
|
||||
float lightscale = 1.0;
|
||||
|
||||
qboolean glview;
|
||||
|
||||
qboolean nopvs;
|
||||
|
||||
char source[1024];
|
||||
|
||||
float direct_scale = 0.4;
|
||||
float entity_scale = 1.0;
|
||||
|
||||
/*
|
||||
===================================================================
|
||||
|
||||
MISC
|
||||
|
||||
===================================================================
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
MakeBackplanes
|
||||
=============
|
||||
*/
|
||||
void MakeBackplanes (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0 ; i<numplanes ; i++)
|
||||
{
|
||||
backplanes[i].dist = -dplanes[i].dist;
|
||||
VectorSubtract (vec3_origin, dplanes[i].normal, backplanes[i].normal);
|
||||
}
|
||||
}
|
||||
|
||||
int leafparents[MAX_MAP_LEAFS];
|
||||
int nodeparents[MAX_MAP_NODES];
|
||||
|
||||
/*
|
||||
=============
|
||||
MakeParents
|
||||
=============
|
||||
*/
|
||||
void MakeParents (int nodenum, int parent)
|
||||
{
|
||||
int i, j;
|
||||
dnode_t *node;
|
||||
|
||||
nodeparents[nodenum] = parent;
|
||||
node = &dnodes[nodenum];
|
||||
|
||||
for (i=0 ; i<2 ; i++)
|
||||
{
|
||||
j = node->children[i];
|
||||
if (j < 0)
|
||||
leafparents[-j - 1] = nodenum;
|
||||
else
|
||||
MakeParents (j, nodenum);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===================================================================
|
||||
|
||||
TRANSFER SCALES
|
||||
|
||||
===================================================================
|
||||
*/
|
||||
|
||||
int PointInLeafnum (vec3_t point)
|
||||
{
|
||||
int nodenum;
|
||||
vec_t dist;
|
||||
dnode_t *node;
|
||||
dplane_t *plane;
|
||||
|
||||
nodenum = 0;
|
||||
while (nodenum >= 0)
|
||||
{
|
||||
node = &dnodes[nodenum];
|
||||
plane = &dplanes[node->planenum];
|
||||
dist = DotProduct (point, plane->normal) - plane->dist;
|
||||
if (dist > 0)
|
||||
nodenum = node->children[0];
|
||||
else
|
||||
nodenum = node->children[1];
|
||||
}
|
||||
|
||||
return -nodenum - 1;
|
||||
}
|
||||
|
||||
|
||||
dleaf_t *PointInLeaf (vec3_t point)
|
||||
{
|
||||
int num;
|
||||
|
||||
num = PointInLeafnum (point);
|
||||
return &dleafs[num];
|
||||
}
|
||||
|
||||
|
||||
qboolean PvsForOrigin (vec3_t org, byte *pvs)
|
||||
{
|
||||
dleaf_t *leaf;
|
||||
|
||||
if (!visdatasize)
|
||||
{
|
||||
memset (pvs, 255, (numleafs+7)/8 );
|
||||
return true;
|
||||
}
|
||||
|
||||
leaf = PointInLeaf (org);
|
||||
if (leaf->cluster == -1)
|
||||
return false; // in solid leaf
|
||||
|
||||
DecompressVis (dvisdata + dvis->bitofs[leaf->cluster][DVIS_PVS], pvs);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
MakeTransfers
|
||||
|
||||
=============
|
||||
*/
|
||||
int total_transfer;
|
||||
|
||||
void MakeTransfers (int i)
|
||||
{
|
||||
int j;
|
||||
vec3_t delta;
|
||||
vec_t dist, scale;
|
||||
float trans;
|
||||
int itrans;
|
||||
patch_t *patch, *patch2;
|
||||
float total;
|
||||
dplane_t plane;
|
||||
vec3_t origin;
|
||||
float transfers[MAX_PATCHES], *all_transfers;
|
||||
int s;
|
||||
int itotal;
|
||||
byte pvs[(MAX_MAP_LEAFS+7)/8];
|
||||
int cluster;
|
||||
|
||||
patch = patches + i;
|
||||
total = 0;
|
||||
|
||||
VectorCopy (patch->origin, origin);
|
||||
plane = *patch->plane;
|
||||
|
||||
if (!PvsForOrigin (patch->origin, pvs))
|
||||
return;
|
||||
|
||||
// find out which patch2s will collect light
|
||||
// from patch
|
||||
|
||||
all_transfers = transfers;
|
||||
patch->numtransfers = 0;
|
||||
for (j=0, patch2 = patches ; j<num_patches ; j++, patch2++)
|
||||
{
|
||||
transfers[j] = 0;
|
||||
|
||||
if (j == i)
|
||||
continue;
|
||||
|
||||
// check pvs bit
|
||||
if (!nopvs)
|
||||
{
|
||||
cluster = patch2->cluster;
|
||||
if (cluster == -1)
|
||||
continue;
|
||||
if ( ! ( pvs[cluster>>3] & (1<<(cluster&7)) ) )
|
||||
continue; // not in pvs
|
||||
}
|
||||
|
||||
// calculate vector
|
||||
VectorSubtract (patch2->origin, origin, delta);
|
||||
dist = VectorNormalize (delta, delta);
|
||||
if (!dist)
|
||||
continue; // should never happen
|
||||
|
||||
// reletive angles
|
||||
scale = DotProduct (delta, plane.normal);
|
||||
scale *= -DotProduct (delta, patch2->plane->normal);
|
||||
if (scale <= 0)
|
||||
continue;
|
||||
|
||||
// check exact tramsfer
|
||||
if (TestLine_r (0, patch->origin, patch2->origin) )
|
||||
continue;
|
||||
|
||||
trans = scale * patch2->area / (dist*dist);
|
||||
|
||||
if (trans < 0)
|
||||
trans = 0; // rounding errors...
|
||||
|
||||
transfers[j] = trans;
|
||||
if (trans > 0)
|
||||
{
|
||||
total += trans;
|
||||
patch->numtransfers++;
|
||||
}
|
||||
}
|
||||
|
||||
// copy the transfers out and normalize
|
||||
// total should be somewhere near PI if everything went right
|
||||
// because partial occlusion isn't accounted for, and nearby
|
||||
// patches have underestimated form factors, it will usually
|
||||
// be higher than PI
|
||||
if (patch->numtransfers)
|
||||
{
|
||||
transfer_t *t;
|
||||
|
||||
if (patch->numtransfers < 0 || patch->numtransfers > MAX_PATCHES)
|
||||
Error ("Weird numtransfers");
|
||||
s = patch->numtransfers * sizeof(transfer_t);
|
||||
patch->transfers = malloc (s);
|
||||
if (!patch->transfers)
|
||||
Error ("Memory allocation failure");
|
||||
|
||||
//
|
||||
// normalize all transfers so all of the light
|
||||
// is transfered to the surroundings
|
||||
//
|
||||
t = patch->transfers;
|
||||
itotal = 0;
|
||||
for (j=0 ; j<num_patches ; j++)
|
||||
{
|
||||
if (transfers[j] <= 0)
|
||||
continue;
|
||||
itrans = transfers[j]*0x10000 / total;
|
||||
itotal += itrans;
|
||||
t->transfer = itrans;
|
||||
t->patch = j;
|
||||
t++;
|
||||
}
|
||||
}
|
||||
|
||||
// don't bother locking around this. not that important.
|
||||
total_transfer += patch->numtransfers;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
FreeTransfers
|
||||
=============
|
||||
*/
|
||||
void FreeTransfers (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0 ; i<num_patches ; i++)
|
||||
{
|
||||
free (patches[i].transfers);
|
||||
patches[i].transfers = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//===================================================================
|
||||
|
||||
/*
|
||||
=============
|
||||
WriteWorld
|
||||
=============
|
||||
*/
|
||||
void WriteWorld (char *name)
|
||||
{
|
||||
int i, j;
|
||||
FILE *out;
|
||||
patch_t *patch;
|
||||
winding_t *w;
|
||||
|
||||
out = fopen (name, "w");
|
||||
if (!out)
|
||||
Error ("Couldn't open %s", name);
|
||||
|
||||
for (j=0, patch=patches ; j<num_patches ; j++, patch++)
|
||||
{
|
||||
w = patch->winding;
|
||||
fprintf (out, "%i\n", w->numpoints);
|
||||
for (i=0 ; i<w->numpoints ; i++)
|
||||
{
|
||||
fprintf (out, "%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n",
|
||||
w->p[i][0],
|
||||
w->p[i][1],
|
||||
w->p[i][2],
|
||||
patch->totallight[0],
|
||||
patch->totallight[1],
|
||||
patch->totallight[2]);
|
||||
}
|
||||
fprintf (out, "\n");
|
||||
}
|
||||
|
||||
fclose (out);
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
WriteGlView
|
||||
=============
|
||||
*/
|
||||
void WriteGlView (void)
|
||||
{
|
||||
char name[1024];
|
||||
FILE *f;
|
||||
int i, j;
|
||||
patch_t *p;
|
||||
winding_t *w;
|
||||
|
||||
strcpy (name, source);
|
||||
StripExtension (name);
|
||||
strcat (name, ".glr");
|
||||
|
||||
f = fopen (name, "w");
|
||||
if (!f)
|
||||
Error ("Couldn't open %s", f);
|
||||
|
||||
for (j=0 ; j<num_patches ; j++)
|
||||
{
|
||||
p = &patches[j];
|
||||
w = p->winding;
|
||||
fprintf (f, "%i\n", w->numpoints);
|
||||
for (i=0 ; i<w->numpoints ; i++)
|
||||
{
|
||||
fprintf (f, "%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n",
|
||||
w->p[i][0],
|
||||
w->p[i][1],
|
||||
w->p[i][2],
|
||||
p->totallight[0]/128,
|
||||
p->totallight[1]/128,
|
||||
p->totallight[2]/128);
|
||||
}
|
||||
fprintf (f, "\n");
|
||||
}
|
||||
|
||||
fclose (f);
|
||||
}
|
||||
|
||||
|
||||
//==============================================================
|
||||
|
||||
/*
|
||||
=============
|
||||
CollectLight
|
||||
=============
|
||||
*/
|
||||
float CollectLight (void)
|
||||
{
|
||||
int i, j;
|
||||
patch_t *patch;
|
||||
vec_t total;
|
||||
|
||||
total = 0;
|
||||
|
||||
for (i=0, patch=patches ; i<num_patches ; i++, patch++)
|
||||
{
|
||||
// skys never collect light, it is just dropped
|
||||
if (patch->sky)
|
||||
{
|
||||
VectorClear (radiosity[i]);
|
||||
VectorClear (illumination[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (j=0 ; j<3 ; j++)
|
||||
{
|
||||
patch->totallight[j] += illumination[i][j] / patch->area;
|
||||
radiosity[i][j] = illumination[i][j] * patch->reflectivity[j];
|
||||
}
|
||||
|
||||
total += radiosity[i][0] + radiosity[i][1] + radiosity[i][2];
|
||||
VectorClear (illumination[i]);
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
ShootLight
|
||||
|
||||
Send light out to other patches
|
||||
Run multi-threaded
|
||||
=============
|
||||
*/
|
||||
void ShootLight (int patchnum)
|
||||
{
|
||||
int k, l;
|
||||
transfer_t *trans;
|
||||
int num;
|
||||
patch_t *patch;
|
||||
vec3_t send;
|
||||
|
||||
// this is the amount of light we are distributing
|
||||
// prescale it so that multiplying by the 16 bit
|
||||
// transfer values gives a proper output value
|
||||
for (k=0 ; k<3 ; k++)
|
||||
send[k] = radiosity[patchnum][k] / 0x10000;
|
||||
patch = &patches[patchnum];
|
||||
|
||||
trans = patch->transfers;
|
||||
num = patch->numtransfers;
|
||||
|
||||
for (k=0 ; k<num ; k++, trans++)
|
||||
{
|
||||
for (l=0 ; l<3 ; l++)
|
||||
illumination[trans->patch][l] += send[l]*trans->transfer;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
BounceLight
|
||||
=============
|
||||
*/
|
||||
void BounceLight (void)
|
||||
{
|
||||
int i, j;
|
||||
float added;
|
||||
char name[64];
|
||||
patch_t *p;
|
||||
|
||||
for (i=0 ; i<num_patches ; i++)
|
||||
{
|
||||
p = &patches[i];
|
||||
for (j=0 ; j<3 ; j++)
|
||||
{
|
||||
// p->totallight[j] = p->samplelight[j];
|
||||
radiosity[i][j] = p->samplelight[j] * p->reflectivity[j] * p->area;
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0 ; i<numbounce ; i++)
|
||||
{
|
||||
RunThreadsOnIndividual (num_patches, false, ShootLight);
|
||||
added = CollectLight ();
|
||||
|
||||
qprintf ("bounce:%i added:%f\n", i, added);
|
||||
if ( dumppatches && (i==0 || i == numbounce-1) )
|
||||
{
|
||||
sprintf (name, "bounce%i.txt", i);
|
||||
WriteWorld (name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==============================================================
|
||||
|
||||
void CheckPatches (void)
|
||||
{
|
||||
int i;
|
||||
patch_t *patch;
|
||||
|
||||
for (i=0 ; i<num_patches ; i++)
|
||||
{
|
||||
patch = &patches[i];
|
||||
if (patch->totallight[0] < 0 || patch->totallight[1] < 0 || patch->totallight[2] < 0)
|
||||
Error ("negative patch totallight\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
RadWorld
|
||||
=============
|
||||
*/
|
||||
void RadWorld (void)
|
||||
{
|
||||
if (numnodes == 0 || numfaces == 0)
|
||||
Error ("Empty map");
|
||||
MakeBackplanes ();
|
||||
MakeParents (0, -1);
|
||||
MakeTnodes (&dmodels[0]);
|
||||
|
||||
// turn each face into a single patch
|
||||
MakePatches ();
|
||||
|
||||
// subdivide patches to a maximum dimension
|
||||
SubdividePatches ();
|
||||
|
||||
// create directlights out of patches and lights
|
||||
CreateDirectLights ();
|
||||
|
||||
// build initial facelights
|
||||
RunThreadsOnIndividual (numfaces, true, BuildFacelights);
|
||||
|
||||
if (numbounce > 0)
|
||||
{
|
||||
// build transfer lists
|
||||
RunThreadsOnIndividual (num_patches, true, MakeTransfers);
|
||||
qprintf ("transfer lists: %5.1f megs\n"
|
||||
, (float)total_transfer * sizeof(transfer_t) / (1024*1024));
|
||||
|
||||
// spread light around
|
||||
BounceLight ();
|
||||
|
||||
FreeTransfers ();
|
||||
|
||||
CheckPatches ();
|
||||
}
|
||||
|
||||
if (glview)
|
||||
WriteGlView ();
|
||||
|
||||
// blend bounced light into direct light and save
|
||||
PairEdges ();
|
||||
LinkPlaneFaces ();
|
||||
|
||||
lightdatasize = 0;
|
||||
RunThreadsOnIndividual (numfaces, true, FinalLightFace);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
========
|
||||
main
|
||||
|
||||
light modelfile
|
||||
========
|
||||
*/
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
double start, end;
|
||||
char name[1024];
|
||||
|
||||
printf ("----- Radiosity ----\n");
|
||||
|
||||
verbose = false;
|
||||
|
||||
for (i=1 ; i<argc ; i++)
|
||||
{
|
||||
if (!strcmp(argv[i],"-dump"))
|
||||
dumppatches = true;
|
||||
else if (!strcmp(argv[i],"-bounce"))
|
||||
{
|
||||
numbounce = atoi (argv[i+1]);
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(argv[i],"-v"))
|
||||
{
|
||||
verbose = true;
|
||||
}
|
||||
else if (!strcmp(argv[i],"-extra"))
|
||||
{
|
||||
extrasamples = true;
|
||||
printf ("extrasamples = true\n");
|
||||
}
|
||||
else if (!strcmp(argv[i],"-threads"))
|
||||
{
|
||||
numthreads = atoi (argv[i+1]);
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(argv[i],"-chop"))
|
||||
{
|
||||
subdiv = atoi (argv[i+1]);
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(argv[i],"-scale"))
|
||||
{
|
||||
lightscale = atof (argv[i+1]);
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(argv[i],"-direct"))
|
||||
{
|
||||
direct_scale *= atof(argv[i+1]);
|
||||
printf ("direct light scaling at %f\n", direct_scale);
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(argv[i],"-entity"))
|
||||
{
|
||||
entity_scale *= atof(argv[i+1]);
|
||||
printf ("entity light scaling at %f\n", entity_scale);
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(argv[i],"-glview"))
|
||||
{
|
||||
glview = true;
|
||||
printf ("glview = true\n");
|
||||
}
|
||||
else if (!strcmp(argv[i],"-nopvs"))
|
||||
{
|
||||
nopvs = true;
|
||||
printf ("nopvs = true\n");
|
||||
}
|
||||
else if (!strcmp(argv[i],"-ambient"))
|
||||
{
|
||||
ambient = atof (argv[i+1]) * 128;
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(argv[i],"-maxlight"))
|
||||
{
|
||||
maxlight = atof (argv[i+1]) * 128;
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp (argv[i],"-tmpin"))
|
||||
strcpy (inbase, "/tmp");
|
||||
else if (!strcmp (argv[i],"-tmpout"))
|
||||
strcpy (outbase, "/tmp");
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
ThreadSetDefault ();
|
||||
|
||||
if (maxlight > 255)
|
||||
maxlight = 255;
|
||||
|
||||
if (i != argc - 1)
|
||||
Error ("usage: qrad [-v] [-chop num] [-scale num] [-ambient num] [-maxlight num] [-threads num] bspfile");
|
||||
|
||||
start = I_FloatTime ();
|
||||
|
||||
SetQdirFromPath (argv[i]);
|
||||
strcpy (source, ExpandArg(argv[i]));
|
||||
StripExtension (source);
|
||||
DefaultExtension (source, ".bsp");
|
||||
|
||||
// ReadLightFile ();
|
||||
|
||||
sprintf (name, "%s%s", inbase, source);
|
||||
printf ("reading %s\n", name);
|
||||
LoadBSPFile (name);
|
||||
ParseEntities ();
|
||||
CalcTextureReflectivity ();
|
||||
|
||||
if (!visdatasize)
|
||||
{
|
||||
printf ("No vis information, direct lighting only.\n");
|
||||
numbounce = 0;
|
||||
ambient = 0.1;
|
||||
}
|
||||
|
||||
RadWorld ();
|
||||
|
||||
sprintf (name, "%s%s", outbase, source);
|
||||
printf ("writing %s\n", name);
|
||||
WriteBSPFile (name);
|
||||
|
||||
end = I_FloatTime ();
|
||||
printf ("%5.0f seconds elapsed\n", end-start);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
295
tools/quake2/extra/bsp/qrad3/trace.c
Normal file
295
tools/quake2/extra/bsp/qrad3/trace.c
Normal file
|
@ -0,0 +1,295 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "cmdlib.h"
|
||||
#include "mathlib.h"
|
||||
#include "bspfile.h"
|
||||
|
||||
#define ON_EPSILON 0.1
|
||||
|
||||
typedef struct tnode_s
|
||||
{
|
||||
int type;
|
||||
vec3_t normal;
|
||||
float dist;
|
||||
int children[2];
|
||||
int pad;
|
||||
} tnode_t;
|
||||
|
||||
tnode_t *tnodes, *tnode_p;
|
||||
|
||||
/*
|
||||
==============
|
||||
MakeTnode
|
||||
|
||||
Converts the disk node structure into the efficient tracing structure
|
||||
==============
|
||||
*/
|
||||
void MakeTnode (int nodenum)
|
||||
{
|
||||
tnode_t *t;
|
||||
dplane_t *plane;
|
||||
int i;
|
||||
dnode_t *node;
|
||||
|
||||
t = tnode_p++;
|
||||
|
||||
node = dnodes + nodenum;
|
||||
plane = dplanes + node->planenum;
|
||||
|
||||
t->type = plane->type;
|
||||
VectorCopy (plane->normal, t->normal);
|
||||
t->dist = plane->dist;
|
||||
|
||||
for (i=0 ; i<2 ; i++)
|
||||
{
|
||||
if (node->children[i] < 0)
|
||||
t->children[i] = (dleafs[-node->children[i] - 1].contents & CONTENTS_SOLID) | (1<<31);
|
||||
else
|
||||
{
|
||||
t->children[i] = tnode_p - tnodes;
|
||||
MakeTnode (node->children[i]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
MakeTnodes
|
||||
|
||||
Loads the node structure out of a .bsp file to be used for light occlusion
|
||||
=============
|
||||
*/
|
||||
void MakeTnodes (dmodel_t *bm)
|
||||
{
|
||||
// 32 byte align the structs
|
||||
tnodes = malloc( (numnodes+1) * sizeof(tnode_t));
|
||||
tnodes = (tnode_t *)(((int)tnodes + 31)&~31);
|
||||
tnode_p = tnodes;
|
||||
|
||||
MakeTnode (0);
|
||||
}
|
||||
|
||||
|
||||
//==========================================================
|
||||
|
||||
|
||||
int TestLine_r (int node, vec3_t start, vec3_t stop)
|
||||
{
|
||||
tnode_t *tnode;
|
||||
float front, back;
|
||||
vec3_t mid;
|
||||
float frac;
|
||||
int side;
|
||||
int r;
|
||||
|
||||
if (node & (1<<31))
|
||||
return node & ~(1<<31); // leaf node
|
||||
|
||||
tnode = &tnodes[node];
|
||||
switch (tnode->type)
|
||||
{
|
||||
case PLANE_X:
|
||||
front = start[0] - tnode->dist;
|
||||
back = stop[0] - tnode->dist;
|
||||
break;
|
||||
case PLANE_Y:
|
||||
front = start[1] - tnode->dist;
|
||||
back = stop[1] - tnode->dist;
|
||||
break;
|
||||
case PLANE_Z:
|
||||
front = start[2] - tnode->dist;
|
||||
back = stop[2] - tnode->dist;
|
||||
break;
|
||||
default:
|
||||
front = (start[0]*tnode->normal[0] + start[1]*tnode->normal[1] + start[2]*tnode->normal[2]) - tnode->dist;
|
||||
back = (stop[0]*tnode->normal[0] + stop[1]*tnode->normal[1] + stop[2]*tnode->normal[2]) - tnode->dist;
|
||||
break;
|
||||
}
|
||||
|
||||
if (front >= -ON_EPSILON && back >= -ON_EPSILON)
|
||||
return TestLine_r (tnode->children[0], start, stop);
|
||||
|
||||
if (front < ON_EPSILON && back < ON_EPSILON)
|
||||
return TestLine_r (tnode->children[1], start, stop);
|
||||
|
||||
side = front < 0;
|
||||
|
||||
frac = front / (front-back);
|
||||
|
||||
mid[0] = start[0] + (stop[0] - start[0])*frac;
|
||||
mid[1] = start[1] + (stop[1] - start[1])*frac;
|
||||
mid[2] = start[2] + (stop[2] - start[2])*frac;
|
||||
|
||||
r = TestLine_r (tnode->children[side], start, mid);
|
||||
if (r)
|
||||
return r;
|
||||
return TestLine_r (tnode->children[!side], mid, stop);
|
||||
}
|
||||
|
||||
int TestLine (vec3_t start, vec3_t stop)
|
||||
{
|
||||
return TestLine_r (0, start, stop);
|
||||
}
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
LINE TRACING
|
||||
|
||||
The major lighting operation is a point to point visibility test, performed
|
||||
by recursive subdivision of the line by the BSP tree.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
vec3_t backpt;
|
||||
int side;
|
||||
int node;
|
||||
} tracestack_t;
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
TestLine
|
||||
==============
|
||||
*/
|
||||
qboolean _TestLine (vec3_t start, vec3_t stop)
|
||||
{
|
||||
int node;
|
||||
float front, back;
|
||||
tracestack_t *tstack_p;
|
||||
int side;
|
||||
float frontx,fronty, frontz, backx, backy, backz;
|
||||
tracestack_t tracestack[64];
|
||||
tnode_t *tnode;
|
||||
|
||||
frontx = start[0];
|
||||
fronty = start[1];
|
||||
frontz = start[2];
|
||||
backx = stop[0];
|
||||
backy = stop[1];
|
||||
backz = stop[2];
|
||||
|
||||
tstack_p = tracestack;
|
||||
node = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (node == CONTENTS_SOLID)
|
||||
{
|
||||
#if 0
|
||||
float d1, d2, d3;
|
||||
|
||||
d1 = backx - frontx;
|
||||
d2 = backy - fronty;
|
||||
d3 = backz - frontz;
|
||||
|
||||
if (d1*d1 + d2*d2 + d3*d3 > 1)
|
||||
#endif
|
||||
return false; // DONE!
|
||||
}
|
||||
|
||||
while (node < 0)
|
||||
{
|
||||
// pop up the stack for a back side
|
||||
tstack_p--;
|
||||
if (tstack_p < tracestack)
|
||||
return true;
|
||||
node = tstack_p->node;
|
||||
|
||||
// set the hit point for this plane
|
||||
|
||||
frontx = backx;
|
||||
fronty = backy;
|
||||
frontz = backz;
|
||||
|
||||
// go down the back side
|
||||
|
||||
backx = tstack_p->backpt[0];
|
||||
backy = tstack_p->backpt[1];
|
||||
backz = tstack_p->backpt[2];
|
||||
|
||||
node = tnodes[tstack_p->node].children[!tstack_p->side];
|
||||
}
|
||||
|
||||
tnode = &tnodes[node];
|
||||
|
||||
switch (tnode->type)
|
||||
{
|
||||
case PLANE_X:
|
||||
front = frontx - tnode->dist;
|
||||
back = backx - tnode->dist;
|
||||
break;
|
||||
case PLANE_Y:
|
||||
front = fronty - tnode->dist;
|
||||
back = backy - tnode->dist;
|
||||
break;
|
||||
case PLANE_Z:
|
||||
front = frontz - tnode->dist;
|
||||
back = backz - tnode->dist;
|
||||
break;
|
||||
default:
|
||||
front = (frontx*tnode->normal[0] + fronty*tnode->normal[1] + frontz*tnode->normal[2]) - tnode->dist;
|
||||
back = (backx*tnode->normal[0] + backy*tnode->normal[1] + backz*tnode->normal[2]) - tnode->dist;
|
||||
break;
|
||||
}
|
||||
|
||||
if (front > -ON_EPSILON && back > -ON_EPSILON)
|
||||
// if (front > 0 && back > 0)
|
||||
{
|
||||
node = tnode->children[0];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (front < ON_EPSILON && back < ON_EPSILON)
|
||||
// if (front <= 0 && back <= 0)
|
||||
{
|
||||
node = tnode->children[1];
|
||||
continue;
|
||||
}
|
||||
|
||||
side = front < 0;
|
||||
|
||||
front = front / (front-back);
|
||||
|
||||
tstack_p->node = node;
|
||||
tstack_p->side = side;
|
||||
tstack_p->backpt[0] = backx;
|
||||
tstack_p->backpt[1] = backy;
|
||||
tstack_p->backpt[2] = backz;
|
||||
|
||||
tstack_p++;
|
||||
|
||||
backx = frontx + front*(backx-frontx);
|
||||
backy = fronty + front*(backy-fronty);
|
||||
backz = frontz + front*(backz-frontz);
|
||||
|
||||
node = tnode->children[side];
|
||||
}
|
||||
}
|
||||
|
||||
|
788
tools/quake2/extra/bsp/qvis3/flow.c
Normal file
788
tools/quake2/extra/bsp/qvis3/flow.c
Normal file
|
@ -0,0 +1,788 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
#include "vis.h"
|
||||
|
||||
/*
|
||||
|
||||
each portal will have a list of all possible to see from first portal
|
||||
|
||||
if (!thread->portalmightsee[portalnum])
|
||||
|
||||
portal mightsee
|
||||
|
||||
for p2 = all other portals in leaf
|
||||
get sperating planes
|
||||
for all portals that might be seen by p2
|
||||
mark as unseen if not present in seperating plane
|
||||
flood fill a new mightsee
|
||||
save as passagemightsee
|
||||
|
||||
|
||||
void CalcMightSee (leaf_t *leaf,
|
||||
*/
|
||||
|
||||
int CountBits (byte *bits, int numbits)
|
||||
{
|
||||
int i;
|
||||
int c;
|
||||
|
||||
c = 0;
|
||||
for (i=0 ; i<numbits ; i++)
|
||||
if (bits[i>>3] & (1<<(i&7)) )
|
||||
c++;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
int c_fullskip;
|
||||
int c_portalskip, c_leafskip;
|
||||
int c_vistest, c_mighttest;
|
||||
|
||||
int c_chop, c_nochop;
|
||||
|
||||
int active;
|
||||
|
||||
void CheckStack (leaf_t *leaf, threaddata_t *thread)
|
||||
{
|
||||
pstack_t *p, *p2;
|
||||
|
||||
for (p=thread->pstack_head.next ; p ; p=p->next)
|
||||
{
|
||||
// printf ("=");
|
||||
if (p->leaf == leaf)
|
||||
Error ("CheckStack: leaf recursion");
|
||||
for (p2=thread->pstack_head.next ; p2 != p ; p2=p2->next)
|
||||
if (p2->leaf == p->leaf)
|
||||
Error ("CheckStack: late leaf recursion");
|
||||
}
|
||||
// printf ("\n");
|
||||
}
|
||||
|
||||
|
||||
winding_t *AllocStackWinding (pstack_t *stack)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
if (stack->freewindings[i])
|
||||
{
|
||||
stack->freewindings[i] = 0;
|
||||
return &stack->windings[i];
|
||||
}
|
||||
}
|
||||
|
||||
Error ("AllocStackWinding: failed");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void FreeStackWinding (winding_t *w, pstack_t *stack)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = w - stack->windings;
|
||||
|
||||
if (i<0 || i>2)
|
||||
return; // not from local
|
||||
|
||||
if (stack->freewindings[i])
|
||||
Error ("FreeStackWinding: allready free");
|
||||
stack->freewindings[i] = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
ChopWinding
|
||||
|
||||
==============
|
||||
*/
|
||||
winding_t *ChopWinding (winding_t *in, pstack_t *stack, plane_t *split)
|
||||
{
|
||||
vec_t dists[128];
|
||||
int sides[128];
|
||||
int counts[3];
|
||||
vec_t dot;
|
||||
int i, j;
|
||||
vec_t *p1, *p2;
|
||||
vec3_t mid;
|
||||
winding_t *neww;
|
||||
|
||||
counts[0] = counts[1] = counts[2] = 0;
|
||||
|
||||
// determine sides for each point
|
||||
for (i=0 ; i<in->numpoints ; i++)
|
||||
{
|
||||
dot = DotProduct (in->points[i], split->normal);
|
||||
dot -= split->dist;
|
||||
dists[i] = dot;
|
||||
if (dot > ON_EPSILON)
|
||||
sides[i] = SIDE_FRONT;
|
||||
else if (dot < -ON_EPSILON)
|
||||
sides[i] = SIDE_BACK;
|
||||
else
|
||||
{
|
||||
sides[i] = SIDE_ON;
|
||||
}
|
||||
counts[sides[i]]++;
|
||||
}
|
||||
|
||||
if (!counts[1])
|
||||
return in; // completely on front side
|
||||
|
||||
if (!counts[0])
|
||||
{
|
||||
FreeStackWinding (in, stack);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sides[i] = sides[0];
|
||||
dists[i] = dists[0];
|
||||
|
||||
neww = AllocStackWinding (stack);
|
||||
|
||||
neww->numpoints = 0;
|
||||
|
||||
for (i=0 ; i<in->numpoints ; i++)
|
||||
{
|
||||
p1 = in->points[i];
|
||||
|
||||
if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING)
|
||||
{
|
||||
FreeStackWinding (neww, stack);
|
||||
return in; // can't chop -- fall back to original
|
||||
}
|
||||
|
||||
if (sides[i] == SIDE_ON)
|
||||
{
|
||||
VectorCopy (p1, neww->points[neww->numpoints]);
|
||||
neww->numpoints++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sides[i] == SIDE_FRONT)
|
||||
{
|
||||
VectorCopy (p1, neww->points[neww->numpoints]);
|
||||
neww->numpoints++;
|
||||
}
|
||||
|
||||
if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
|
||||
continue;
|
||||
|
||||
if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING)
|
||||
{
|
||||
FreeStackWinding (neww, stack);
|
||||
return in; // can't chop -- fall back to original
|
||||
}
|
||||
|
||||
// generate a split point
|
||||
p2 = in->points[(i+1)%in->numpoints];
|
||||
|
||||
dot = dists[i] / (dists[i]-dists[i+1]);
|
||||
for (j=0 ; j<3 ; j++)
|
||||
{ // avoid round off error when possible
|
||||
if (split->normal[j] == 1)
|
||||
mid[j] = split->dist;
|
||||
else if (split->normal[j] == -1)
|
||||
mid[j] = -split->dist;
|
||||
else
|
||||
mid[j] = p1[j] + dot*(p2[j]-p1[j]);
|
||||
}
|
||||
|
||||
VectorCopy (mid, neww->points[neww->numpoints]);
|
||||
neww->numpoints++;
|
||||
}
|
||||
|
||||
// free the original winding
|
||||
FreeStackWinding (in, stack);
|
||||
|
||||
return neww;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
ClipToSeperators
|
||||
|
||||
Source, pass, and target are an ordering of portals.
|
||||
|
||||
Generates seperating planes canidates by taking two points from source and one
|
||||
point from pass, and clips target by them.
|
||||
|
||||
If target is totally clipped away, that portal can not be seen through.
|
||||
|
||||
Normal clip keeps target on the same side as pass, which is correct if the
|
||||
order goes source, pass, target. If the order goes pass, source, target then
|
||||
flipclip should be set.
|
||||
==============
|
||||
*/
|
||||
winding_t *ClipToSeperators (winding_t *source, winding_t *pass, winding_t *target, qboolean flipclip, pstack_t *stack)
|
||||
{
|
||||
int i, j, k, l;
|
||||
plane_t plane;
|
||||
vec3_t v1, v2;
|
||||
float d;
|
||||
vec_t length;
|
||||
int counts[3];
|
||||
qboolean fliptest;
|
||||
|
||||
// check all combinations
|
||||
for (i=0 ; i<source->numpoints ; i++)
|
||||
{
|
||||
l = (i+1)%source->numpoints;
|
||||
VectorSubtract (source->points[l] , source->points[i], v1);
|
||||
|
||||
// fing a vertex of pass that makes a plane that puts all of the
|
||||
// vertexes of pass on the front side and all of the vertexes of
|
||||
// source on the back side
|
||||
for (j=0 ; j<pass->numpoints ; j++)
|
||||
{
|
||||
VectorSubtract (pass->points[j], source->points[i], v2);
|
||||
|
||||
plane.normal[0] = v1[1]*v2[2] - v1[2]*v2[1];
|
||||
plane.normal[1] = v1[2]*v2[0] - v1[0]*v2[2];
|
||||
plane.normal[2] = v1[0]*v2[1] - v1[1]*v2[0];
|
||||
|
||||
// if points don't make a valid plane, skip it
|
||||
|
||||
length = plane.normal[0] * plane.normal[0]
|
||||
+ plane.normal[1] * plane.normal[1]
|
||||
+ plane.normal[2] * plane.normal[2];
|
||||
|
||||
if (length < ON_EPSILON)
|
||||
continue;
|
||||
|
||||
length = 1/sqrt(length);
|
||||
|
||||
plane.normal[0] *= length;
|
||||
plane.normal[1] *= length;
|
||||
plane.normal[2] *= length;
|
||||
|
||||
plane.dist = DotProduct (pass->points[j], plane.normal);
|
||||
|
||||
//
|
||||
// find out which side of the generated seperating plane has the
|
||||
// source portal
|
||||
//
|
||||
#if 1
|
||||
fliptest = false;
|
||||
for (k=0 ; k<source->numpoints ; k++)
|
||||
{
|
||||
if (k == i || k == l)
|
||||
continue;
|
||||
d = DotProduct (source->points[k], plane.normal) - plane.dist;
|
||||
if (d < -ON_EPSILON)
|
||||
{ // source is on the negative side, so we want all
|
||||
// pass and target on the positive side
|
||||
fliptest = false;
|
||||
break;
|
||||
}
|
||||
else if (d > ON_EPSILON)
|
||||
{ // source is on the positive side, so we want all
|
||||
// pass and target on the negative side
|
||||
fliptest = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (k == source->numpoints)
|
||||
continue; // planar with source portal
|
||||
#else
|
||||
fliptest = flipclip;
|
||||
#endif
|
||||
//
|
||||
// flip the normal if the source portal is backwards
|
||||
//
|
||||
if (fliptest)
|
||||
{
|
||||
VectorSubtract (vec3_origin, plane.normal, plane.normal);
|
||||
plane.dist = -plane.dist;
|
||||
}
|
||||
#if 1
|
||||
//
|
||||
// if all of the pass portal points are now on the positive side,
|
||||
// this is the seperating plane
|
||||
//
|
||||
counts[0] = counts[1] = counts[2] = 0;
|
||||
for (k=0 ; k<pass->numpoints ; k++)
|
||||
{
|
||||
if (k==j)
|
||||
continue;
|
||||
d = DotProduct (pass->points[k], plane.normal) - plane.dist;
|
||||
if (d < -ON_EPSILON)
|
||||
break;
|
||||
else if (d > ON_EPSILON)
|
||||
counts[0]++;
|
||||
else
|
||||
counts[2]++;
|
||||
}
|
||||
if (k != pass->numpoints)
|
||||
continue; // points on negative side, not a seperating plane
|
||||
|
||||
if (!counts[0])
|
||||
continue; // planar with seperating plane
|
||||
#else
|
||||
k = (j+1)%pass->numpoints;
|
||||
d = DotProduct (pass->points[k], plane.normal) - plane.dist;
|
||||
if (d < -ON_EPSILON)
|
||||
continue;
|
||||
k = (j+pass->numpoints-1)%pass->numpoints;
|
||||
d = DotProduct (pass->points[k], plane.normal) - plane.dist;
|
||||
if (d < -ON_EPSILON)
|
||||
continue;
|
||||
#endif
|
||||
//
|
||||
// flip the normal if we want the back side
|
||||
//
|
||||
if (flipclip)
|
||||
{
|
||||
VectorSubtract (vec3_origin, plane.normal, plane.normal);
|
||||
plane.dist = -plane.dist;
|
||||
}
|
||||
|
||||
//
|
||||
// clip target by the seperating plane
|
||||
//
|
||||
target = ChopWinding (target, stack, &plane);
|
||||
if (!target)
|
||||
return NULL; // target is not visible
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
RecursiveLeafFlow
|
||||
|
||||
Flood fill through the leafs
|
||||
If src_portal is NULL, this is the originating leaf
|
||||
==================
|
||||
*/
|
||||
void RecursiveLeafFlow (int leafnum, threaddata_t *thread, pstack_t *prevstack)
|
||||
{
|
||||
pstack_t stack;
|
||||
portal_t *p;
|
||||
plane_t backplane;
|
||||
leaf_t *leaf;
|
||||
int i, j;
|
||||
long *test, *might, *vis, more;
|
||||
int pnum;
|
||||
|
||||
thread->c_chains++;
|
||||
|
||||
leaf = &leafs[leafnum];
|
||||
// CheckStack (leaf, thread);
|
||||
|
||||
prevstack->next = &stack;
|
||||
|
||||
stack.next = NULL;
|
||||
stack.leaf = leaf;
|
||||
stack.portal = NULL;
|
||||
|
||||
might = (long *)stack.mightsee;
|
||||
vis = (long *)thread->base->portalvis;
|
||||
|
||||
// check all portals for flowing into other leafs
|
||||
for (i=0 ; i<leaf->numportals ; i++)
|
||||
{
|
||||
p = leaf->portals[i];
|
||||
pnum = p - portals;
|
||||
|
||||
if ( ! (prevstack->mightsee[pnum >> 3] & (1<<(pnum&7)) ) )
|
||||
{
|
||||
continue; // can't possibly see it
|
||||
}
|
||||
|
||||
// if the portal can't see anything we haven't allready seen, skip it
|
||||
if (p->status == stat_done)
|
||||
{
|
||||
test = (long *)p->portalvis;
|
||||
}
|
||||
else
|
||||
{
|
||||
test = (long *)p->portalflood;
|
||||
}
|
||||
|
||||
more = 0;
|
||||
for (j=0 ; j<portallongs ; j++)
|
||||
{
|
||||
might[j] = ((long *)prevstack->mightsee)[j] & test[j];
|
||||
more |= (might[j] & ~vis[j]);
|
||||
}
|
||||
|
||||
if (!more &&
|
||||
(thread->base->portalvis[pnum>>3] & (1<<(pnum&7))) )
|
||||
{ // can't see anything new
|
||||
continue;
|
||||
}
|
||||
|
||||
// get plane of portal, point normal into the neighbor leaf
|
||||
stack.portalplane = p->plane;
|
||||
VectorSubtract (vec3_origin, p->plane.normal, backplane.normal);
|
||||
backplane.dist = -p->plane.dist;
|
||||
|
||||
// c_portalcheck++;
|
||||
|
||||
stack.portal = p;
|
||||
stack.next = NULL;
|
||||
stack.freewindings[0] = 1;
|
||||
stack.freewindings[1] = 1;
|
||||
stack.freewindings[2] = 1;
|
||||
|
||||
#if 1
|
||||
{
|
||||
float d;
|
||||
|
||||
d = DotProduct (p->origin, thread->pstack_head.portalplane.normal);
|
||||
d -= thread->pstack_head.portalplane.dist;
|
||||
if (d < -p->radius)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (d > p->radius)
|
||||
{
|
||||
stack.pass = p->winding;
|
||||
}
|
||||
else
|
||||
{
|
||||
stack.pass = ChopWinding (p->winding, &stack, &thread->pstack_head.portalplane);
|
||||
if (!stack.pass)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#else
|
||||
stack.pass = ChopWinding (p->winding, &stack, &thread->pstack_head.portalplane);
|
||||
if (!stack.pass)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
|
||||
#if 1
|
||||
{
|
||||
float d;
|
||||
|
||||
d = DotProduct (thread->base->origin, p->plane.normal);
|
||||
d -= p->plane.dist;
|
||||
if (d > p->radius)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (d < -p->radius)
|
||||
{
|
||||
stack.source = prevstack->source;
|
||||
}
|
||||
else
|
||||
{
|
||||
stack.source = ChopWinding (prevstack->source, &stack, &backplane);
|
||||
if (!stack.source)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#else
|
||||
stack.source = ChopWinding (prevstack->source, &stack, &backplane);
|
||||
if (!stack.source)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
if (!prevstack->pass)
|
||||
{ // the second leaf can only be blocked if coplanar
|
||||
|
||||
// mark the portal as visible
|
||||
thread->base->portalvis[pnum>>3] |= (1<<(pnum&7));
|
||||
|
||||
RecursiveLeafFlow (p->leaf, thread, &stack);
|
||||
continue;
|
||||
}
|
||||
|
||||
stack.pass = ClipToSeperators (stack.source, prevstack->pass, stack.pass, false, &stack);
|
||||
if (!stack.pass)
|
||||
continue;
|
||||
|
||||
stack.pass = ClipToSeperators (prevstack->pass, stack.source, stack.pass, true, &stack);
|
||||
if (!stack.pass)
|
||||
continue;
|
||||
|
||||
// mark the portal as visible
|
||||
thread->base->portalvis[pnum>>3] |= (1<<(pnum&7));
|
||||
|
||||
// flow through it for real
|
||||
RecursiveLeafFlow (p->leaf, thread, &stack);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
PortalFlow
|
||||
|
||||
generates the portalvis bit vector
|
||||
===============
|
||||
*/
|
||||
void PortalFlow (int portalnum)
|
||||
{
|
||||
threaddata_t data;
|
||||
int i;
|
||||
portal_t *p;
|
||||
int c_might, c_can;
|
||||
|
||||
p = sorted_portals[portalnum];
|
||||
p->status = stat_working;
|
||||
|
||||
c_might = CountBits (p->portalflood, numportals*2);
|
||||
|
||||
memset (&data, 0, sizeof(data));
|
||||
data.base = p;
|
||||
|
||||
data.pstack_head.portal = p;
|
||||
data.pstack_head.source = p->winding;
|
||||
data.pstack_head.portalplane = p->plane;
|
||||
for (i=0 ; i<portallongs ; i++)
|
||||
((long *)data.pstack_head.mightsee)[i] = ((long *)p->portalflood)[i];
|
||||
RecursiveLeafFlow (p->leaf, &data, &data.pstack_head);
|
||||
|
||||
p->status = stat_done;
|
||||
|
||||
c_can = CountBits (p->portalvis, numportals*2);
|
||||
|
||||
qprintf ("portal:%4i mightsee:%4i cansee:%4i (%i chains)\n",
|
||||
(int)(p - portals), c_might, c_can, data.c_chains);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
This is a rough first-order aproximation that is used to trivially reject some
|
||||
of the final calculations.
|
||||
|
||||
|
||||
Calculates portalfront and portalflood bit vectors
|
||||
|
||||
thinking about:
|
||||
|
||||
typedef struct passage_s
|
||||
{
|
||||
struct passage_s *next;
|
||||
struct portal_s *to;
|
||||
stryct sep_s *seperators;
|
||||
byte *mightsee;
|
||||
} passage_t;
|
||||
|
||||
typedef struct portal_s
|
||||
{
|
||||
struct passage_s *passages;
|
||||
int leaf; // leaf portal faces into
|
||||
} portal_s;
|
||||
|
||||
leaf = portal->leaf
|
||||
clear
|
||||
for all portals
|
||||
|
||||
|
||||
calc portal visibility
|
||||
clear bit vector
|
||||
for all passages
|
||||
passage visibility
|
||||
|
||||
|
||||
for a portal to be visible to a passage, it must be on the front of
|
||||
all seperating planes, and both portals must be behind the mew portal
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
int c_flood, c_vis;
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
SimpleFlood
|
||||
|
||||
==================
|
||||
*/
|
||||
void SimpleFlood (portal_t *srcportal, int leafnum)
|
||||
{
|
||||
int i;
|
||||
leaf_t *leaf;
|
||||
portal_t *p;
|
||||
int pnum;
|
||||
|
||||
leaf = &leafs[leafnum];
|
||||
|
||||
for (i=0 ; i<leaf->numportals ; i++)
|
||||
{
|
||||
p = leaf->portals[i];
|
||||
pnum = p - portals;
|
||||
if ( ! (srcportal->portalfront[pnum>>3] & (1<<(pnum&7)) ) )
|
||||
continue;
|
||||
|
||||
if (srcportal->portalflood[pnum>>3] & (1<<(pnum&7)) )
|
||||
continue;
|
||||
|
||||
srcportal->portalflood[pnum>>3] |= (1<<(pnum&7));
|
||||
|
||||
SimpleFlood (srcportal, p->leaf);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
BasePortalVis
|
||||
==============
|
||||
*/
|
||||
void BasePortalVis (int portalnum)
|
||||
{
|
||||
int j, k;
|
||||
portal_t *tp, *p;
|
||||
float d;
|
||||
winding_t *w;
|
||||
|
||||
p = portals+portalnum;
|
||||
|
||||
p->portalfront = malloc (portalbytes);
|
||||
memset (p->portalfront, 0, portalbytes);
|
||||
|
||||
p->portalflood = malloc (portalbytes);
|
||||
memset (p->portalflood, 0, portalbytes);
|
||||
|
||||
p->portalvis = malloc (portalbytes);
|
||||
memset (p->portalvis, 0, portalbytes);
|
||||
|
||||
for (j=0, tp = portals ; j<numportals*2 ; j++, tp++)
|
||||
{
|
||||
if (j == portalnum)
|
||||
continue;
|
||||
w = tp->winding;
|
||||
for (k=0 ; k<w->numpoints ; k++)
|
||||
{
|
||||
d = DotProduct (w->points[k], p->plane.normal)
|
||||
- p->plane.dist;
|
||||
if (d > ON_EPSILON)
|
||||
break;
|
||||
}
|
||||
if (k == w->numpoints)
|
||||
continue; // no points on front
|
||||
|
||||
w = p->winding;
|
||||
for (k=0 ; k<w->numpoints ; k++)
|
||||
{
|
||||
d = DotProduct (w->points[k], tp->plane.normal)
|
||||
- tp->plane.dist;
|
||||
if (d < -ON_EPSILON)
|
||||
break;
|
||||
}
|
||||
if (k == w->numpoints)
|
||||
continue; // no points on front
|
||||
|
||||
p->portalfront[j>>3] |= (1<<(j&7));
|
||||
}
|
||||
|
||||
SimpleFlood (p, p->leaf);
|
||||
|
||||
p->nummightsee = CountBits (p->portalflood, numportals*2);
|
||||
// printf ("portal %i: %i mightsee\n", portalnum, p->nummightsee);
|
||||
c_flood += p->nummightsee;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
This is a second order aproximation
|
||||
|
||||
Calculates portalvis bit vector
|
||||
|
||||
WAAAAAAY too slow.
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
==================
|
||||
RecursiveLeafBitFlow
|
||||
|
||||
==================
|
||||
*/
|
||||
void RecursiveLeafBitFlow (int leafnum, byte *mightsee, byte *cansee)
|
||||
{
|
||||
portal_t *p;
|
||||
leaf_t *leaf;
|
||||
int i, j;
|
||||
long more;
|
||||
int pnum;
|
||||
byte newmight[MAX_PORTALS/8];
|
||||
|
||||
leaf = &leafs[leafnum];
|
||||
|
||||
// check all portals for flowing into other leafs
|
||||
for (i=0 ; i<leaf->numportals ; i++)
|
||||
{
|
||||
p = leaf->portals[i];
|
||||
pnum = p - portals;
|
||||
|
||||
// if some previous portal can't see it, skip
|
||||
if (! (mightsee[pnum>>3] & (1<<(pnum&7)) ) )
|
||||
continue;
|
||||
|
||||
// if this portal can see some portals we mightsee, recurse
|
||||
more = 0;
|
||||
for (j=0 ; j<portallongs ; j++)
|
||||
{
|
||||
((long *)newmight)[j] = ((long *)mightsee)[j]
|
||||
& ((long *)p->portalflood)[j];
|
||||
more |= ((long *)newmight)[j] & ~((long *)cansee)[j];
|
||||
}
|
||||
|
||||
if (!more)
|
||||
continue; // can't see anything new
|
||||
|
||||
cansee[pnum>>3] |= (1<<(pnum&7));
|
||||
|
||||
RecursiveLeafBitFlow (p->leaf, newmight, cansee);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
BetterPortalVis
|
||||
==============
|
||||
*/
|
||||
void BetterPortalVis (int portalnum)
|
||||
{
|
||||
portal_t *p;
|
||||
|
||||
p = portals+portalnum;
|
||||
|
||||
RecursiveLeafBitFlow (p->leaf, p->portalflood, p->portalvis);
|
||||
|
||||
// build leaf vis information
|
||||
p->nummightsee = CountBits (p->portalvis, numportals*2);
|
||||
c_vis += p->nummightsee;
|
||||
}
|
||||
|
||||
|
62
tools/quake2/extra/bsp/qvis3/makefile
Normal file
62
tools/quake2/extra/bsp/qvis3/makefile
Normal file
|
@ -0,0 +1,62 @@
|
|||
|
||||
CFLAGS = -c
|
||||
LDFLAGS =
|
||||
ODIR = baddir
|
||||
|
||||
EXEBASE = qvis3
|
||||
EXE = $(ODIR)/qvis3
|
||||
all: $(EXE)
|
||||
|
||||
_next:
|
||||
make "CFLAGS = -c -g -I../../common" "ODIR = next"
|
||||
|
||||
_irix:
|
||||
make "CFLAGS = -c -Ofast=ip32_10k -I../../common -Xcpluscomm" "LDFLAGS = -Ofast=ip32_10k" "ODIR = irix"
|
||||
|
||||
_irixinst:
|
||||
make "CFLAGS = -c -Ofast=ip32_10k -I../../common -Xcpluscomm" "LDFLAGS = -Ofast=ip32_10k" "ODIR = irix"
|
||||
cp irix/$(EXEBASE) /limbo/quake2/bin_irix
|
||||
|
||||
_irixclean:
|
||||
rm -f irix/*.o irix/$(EXEBASE)
|
||||
|
||||
_osf:
|
||||
make "CFLAGS = -c -O4 -I../../common -threads" "LDFLAGS = -threads -lm" "ODIR = osf"
|
||||
|
||||
clean:
|
||||
rm -f irix/*.o irix/$(EXEBASE)
|
||||
|
||||
install:
|
||||
cp irix/$(EXEBASE) /limbo/quake2/bin_irix
|
||||
|
||||
|
||||
FILES = $(ODIR)/bspfile.o $(ODIR)/cmdlib.o $(ODIR)/mathlib.o $(ODIR)/scriplib.o $(ODIR)/threads.o $(ODIR)/qvis3.o $(ODIR)/flow.o
|
||||
|
||||
$(EXE) : $(FILES)
|
||||
cc -o $(EXE) $(LDFLAGS) $(FILES)
|
||||
|
||||
$(ODIR)/qvis3.o : qvis3.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/flow.o : flow.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/cmdlib.o : ../../common/cmdlib.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/mathlib.o : ../../common/mathlib.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/polylib.o : ../../common/polylib.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/scriplib.o : ../../common/scriplib.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/threads.o : ../../common/threads.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/bspfile.o : ../../common/bspfile.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
615
tools/quake2/extra/bsp/qvis3/qvis3.c
Normal file
615
tools/quake2/extra/bsp/qvis3/qvis3.c
Normal file
|
@ -0,0 +1,615 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "vis.h"
|
||||
#include "threads.h"
|
||||
#include "stdlib.h"
|
||||
|
||||
int numportals;
|
||||
int portalclusters;
|
||||
|
||||
char inbase[32];
|
||||
char outbase[32];
|
||||
|
||||
portal_t *portals;
|
||||
leaf_t *leafs;
|
||||
|
||||
int c_portaltest, c_portalpass, c_portalcheck;
|
||||
|
||||
byte *uncompressedvis;
|
||||
|
||||
byte *vismap, *vismap_p, *vismap_end; // past visfile
|
||||
int originalvismapsize;
|
||||
|
||||
int leafbytes; // (portalclusters+63)>>3
|
||||
int leaflongs;
|
||||
|
||||
int portalbytes, portallongs;
|
||||
|
||||
qboolean fastvis;
|
||||
qboolean nosort;
|
||||
|
||||
int testlevel = 2;
|
||||
|
||||
int totalvis;
|
||||
|
||||
portal_t *sorted_portals[MAX_MAP_PORTALS*2];
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
void PlaneFromWinding (winding_t *w, plane_t *plane)
|
||||
{
|
||||
vec3_t v1, v2;
|
||||
|
||||
// calc plane
|
||||
VectorSubtract (w->points[2], w->points[1], v1);
|
||||
VectorSubtract (w->points[0], w->points[1], v2);
|
||||
CrossProduct (v2, v1, plane->normal);
|
||||
VectorNormalize (plane->normal, plane->normal);
|
||||
plane->dist = DotProduct (w->points[0], plane->normal);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
NewWinding
|
||||
==================
|
||||
*/
|
||||
winding_t *NewWinding (int points)
|
||||
{
|
||||
winding_t *w;
|
||||
int size;
|
||||
|
||||
if (points > MAX_POINTS_ON_WINDING)
|
||||
Error ("NewWinding: %i points", points);
|
||||
|
||||
size = (int)((winding_t *)0)->points[points];
|
||||
w = malloc (size);
|
||||
memset (w, 0, size);
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void pw(winding_t *w)
|
||||
{
|
||||
int i;
|
||||
for (i=0 ; i<w->numpoints ; i++)
|
||||
printf ("(%5.1f, %5.1f, %5.1f)\n",w->points[i][0], w->points[i][1],w->points[i][2]);
|
||||
}
|
||||
|
||||
void prl(leaf_t *l)
|
||||
{
|
||||
int i;
|
||||
portal_t *p;
|
||||
plane_t pl;
|
||||
|
||||
for (i=0 ; i<l->numportals ; i++)
|
||||
{
|
||||
p = l->portals[i];
|
||||
pl = p->plane;
|
||||
printf ("portal %4i to leaf %4i : %7.1f : (%4.1f, %4.1f, %4.1f)\n",(int)(p-portals),p->leaf,pl.dist, pl.normal[0], pl.normal[1], pl.normal[2]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
/*
|
||||
=============
|
||||
SortPortals
|
||||
|
||||
Sorts the portals from the least complex, so the later ones can reuse
|
||||
the earlier information.
|
||||
=============
|
||||
*/
|
||||
int PComp (const void *a, const void *b)
|
||||
{
|
||||
if ( (*(portal_t **)a)->nummightsee == (*(portal_t **)b)->nummightsee)
|
||||
return 0;
|
||||
if ( (*(portal_t **)a)->nummightsee < (*(portal_t **)b)->nummightsee)
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
void SortPortals (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0 ; i<numportals*2 ; i++)
|
||||
sorted_portals[i] = &portals[i];
|
||||
|
||||
if (nosort)
|
||||
return;
|
||||
qsort (sorted_portals, numportals*2, sizeof(sorted_portals[0]), PComp);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
LeafVectorFromPortalVector
|
||||
==============
|
||||
*/
|
||||
int LeafVectorFromPortalVector (byte *portalbits, byte *leafbits)
|
||||
{
|
||||
int i;
|
||||
portal_t *p;
|
||||
int c_leafs;
|
||||
|
||||
|
||||
memset (leafbits, 0, leafbytes);
|
||||
|
||||
for (i=0 ; i<numportals*2 ; i++)
|
||||
{
|
||||
if (portalbits[i>>3] & (1<<(i&7)) )
|
||||
{
|
||||
p = portals+i;
|
||||
leafbits[p->leaf>>3] |= (1<<(p->leaf&7));
|
||||
}
|
||||
}
|
||||
|
||||
c_leafs = CountBits (leafbits, portalclusters);
|
||||
|
||||
return c_leafs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
ClusterMerge
|
||||
|
||||
Merges the portal visibility for a leaf
|
||||
===============
|
||||
*/
|
||||
void ClusterMerge (int leafnum)
|
||||
{
|
||||
leaf_t *leaf;
|
||||
byte portalvector[MAX_PORTALS/8];
|
||||
byte uncompressed[MAX_MAP_LEAFS/8];
|
||||
byte compressed[MAX_MAP_LEAFS/8];
|
||||
int i, j;
|
||||
int numvis;
|
||||
byte *dest;
|
||||
portal_t *p;
|
||||
int pnum;
|
||||
|
||||
// OR together all the portalvis bits
|
||||
|
||||
memset (portalvector, 0, portalbytes);
|
||||
leaf = &leafs[leafnum];
|
||||
for (i=0 ; i<leaf->numportals ; i++)
|
||||
{
|
||||
p = leaf->portals[i];
|
||||
if (p->status != stat_done)
|
||||
Error ("portal not done");
|
||||
for (j=0 ; j<portallongs ; j++)
|
||||
((long *)portalvector)[j] |= ((long *)p->portalvis)[j];
|
||||
pnum = p - portals;
|
||||
portalvector[pnum>>3] |= 1<<(pnum&7);
|
||||
}
|
||||
|
||||
// convert portal bits to leaf bits
|
||||
numvis = LeafVectorFromPortalVector (portalvector, uncompressed);
|
||||
|
||||
if (uncompressed[leafnum>>3] & (1<<(leafnum&7)))
|
||||
printf ("WARNING: Leaf portals saw into leaf\n");
|
||||
|
||||
uncompressed[leafnum>>3] |= (1<<(leafnum&7));
|
||||
numvis++; // count the leaf itself
|
||||
|
||||
// save uncompressed for PHS calculation
|
||||
memcpy (uncompressedvis + leafnum*leafbytes, uncompressed, leafbytes);
|
||||
|
||||
//
|
||||
// compress the bit string
|
||||
//
|
||||
qprintf ("cluster %4i : %4i visible\n", leafnum, numvis);
|
||||
totalvis += numvis;
|
||||
|
||||
i = CompressVis (uncompressed, compressed);
|
||||
|
||||
dest = vismap_p;
|
||||
vismap_p += i;
|
||||
|
||||
if (vismap_p > vismap_end)
|
||||
Error ("Vismap expansion overflow");
|
||||
|
||||
dvis->bitofs[leafnum][DVIS_PVS] = dest-vismap;
|
||||
|
||||
memcpy (dest, compressed, i);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
CalcPortalVis
|
||||
==================
|
||||
*/
|
||||
void CalcPortalVis (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
// fastvis just uses mightsee for a very loose bound
|
||||
if (fastvis)
|
||||
{
|
||||
for (i=0 ; i<numportals*2 ; i++)
|
||||
{
|
||||
portals[i].portalvis = portals[i].portalflood;
|
||||
portals[i].status = stat_done;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
RunThreadsOnIndividual (numportals*2, true, PortalFlow);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
CalcVis
|
||||
==================
|
||||
*/
|
||||
void CalcVis (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
RunThreadsOnIndividual (numportals*2, true, BasePortalVis);
|
||||
|
||||
// RunThreadsOnIndividual (numportals*2, true, BetterPortalVis);
|
||||
|
||||
SortPortals ();
|
||||
|
||||
CalcPortalVis ();
|
||||
|
||||
//
|
||||
// assemble the leaf vis lists by oring and compressing the portal lists
|
||||
//
|
||||
for (i=0 ; i<portalclusters ; i++)
|
||||
ClusterMerge (i);
|
||||
|
||||
printf ("Average clusters visible: %i\n", totalvis / portalclusters);
|
||||
}
|
||||
|
||||
|
||||
void SetPortalSphere (portal_t *p)
|
||||
{
|
||||
int i;
|
||||
vec3_t total, dist;
|
||||
winding_t *w;
|
||||
float r, bestr;
|
||||
|
||||
w = p->winding;
|
||||
VectorCopy (vec3_origin, total);
|
||||
for (i=0 ; i<w->numpoints ; i++)
|
||||
{
|
||||
VectorAdd (total, w->points[i], total);
|
||||
}
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
total[i] /= w->numpoints;
|
||||
|
||||
bestr = 0;
|
||||
for (i=0 ; i<w->numpoints ; i++)
|
||||
{
|
||||
VectorSubtract (w->points[i], total, dist);
|
||||
r = VectorLength (dist);
|
||||
if (r > bestr)
|
||||
bestr = r;
|
||||
}
|
||||
VectorCopy (total, p->origin);
|
||||
p->radius = bestr;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
LoadPortals
|
||||
============
|
||||
*/
|
||||
void LoadPortals (char *name)
|
||||
{
|
||||
int i, j;
|
||||
portal_t *p;
|
||||
leaf_t *l;
|
||||
char magic[80];
|
||||
FILE *f;
|
||||
int numpoints;
|
||||
winding_t *w;
|
||||
int leafnums[2];
|
||||
plane_t plane;
|
||||
|
||||
if (!strcmp(name,"-"))
|
||||
f = stdin;
|
||||
else
|
||||
{
|
||||
f = fopen(name, "r");
|
||||
if (!f)
|
||||
Error ("LoadPortals: couldn't read %s\n",name);
|
||||
}
|
||||
|
||||
if (fscanf (f,"%79s\n%i\n%i\n",magic, &portalclusters, &numportals) != 3)
|
||||
Error ("LoadPortals: failed to read header");
|
||||
if (strcmp(magic,PORTALFILE))
|
||||
Error ("LoadPortals: not a portal file");
|
||||
|
||||
printf ("%4i portalclusters\n", portalclusters);
|
||||
printf ("%4i numportals\n", numportals);
|
||||
|
||||
// these counts should take advantage of 64 bit systems automatically
|
||||
leafbytes = ((portalclusters+63)&~63)>>3;
|
||||
leaflongs = leafbytes/sizeof(long);
|
||||
|
||||
portalbytes = ((numportals*2+63)&~63)>>3;
|
||||
portallongs = portalbytes/sizeof(long);
|
||||
|
||||
// each file portal is split into two memory portals
|
||||
portals = malloc(2*numportals*sizeof(portal_t));
|
||||
memset (portals, 0, 2*numportals*sizeof(portal_t));
|
||||
|
||||
leafs = malloc(portalclusters*sizeof(leaf_t));
|
||||
memset (leafs, 0, portalclusters*sizeof(leaf_t));
|
||||
|
||||
originalvismapsize = portalclusters*leafbytes;
|
||||
uncompressedvis = malloc(originalvismapsize);
|
||||
|
||||
vismap = vismap_p = dvisdata;
|
||||
dvis->numclusters = portalclusters;
|
||||
vismap_p = (byte *)&dvis->bitofs[portalclusters];
|
||||
|
||||
vismap_end = vismap + MAX_MAP_VISIBILITY;
|
||||
|
||||
for (i=0, p=portals ; i<numportals ; i++)
|
||||
{
|
||||
if (fscanf (f, "%i %i %i ", &numpoints, &leafnums[0], &leafnums[1])
|
||||
!= 3)
|
||||
Error ("LoadPortals: reading portal %i", i);
|
||||
if (numpoints > MAX_POINTS_ON_WINDING)
|
||||
Error ("LoadPortals: portal %i has too many points", i);
|
||||
if ( (unsigned)leafnums[0] > portalclusters
|
||||
|| (unsigned)leafnums[1] > portalclusters)
|
||||
Error ("LoadPortals: reading portal %i", i);
|
||||
|
||||
w = p->winding = NewWinding (numpoints);
|
||||
w->original = true;
|
||||
w->numpoints = numpoints;
|
||||
|
||||
for (j=0 ; j<numpoints ; j++)
|
||||
{
|
||||
double v[3];
|
||||
int k;
|
||||
|
||||
// scanf into double, then assign to vec_t
|
||||
// so we don't care what size vec_t is
|
||||
if (fscanf (f, "(%lf %lf %lf ) "
|
||||
, &v[0], &v[1], &v[2]) != 3)
|
||||
Error ("LoadPortals: reading portal %i", i);
|
||||
for (k=0 ; k<3 ; k++)
|
||||
w->points[j][k] = v[k];
|
||||
}
|
||||
fscanf (f, "\n");
|
||||
|
||||
// calc plane
|
||||
PlaneFromWinding (w, &plane);
|
||||
|
||||
// create forward portal
|
||||
l = &leafs[leafnums[0]];
|
||||
if (l->numportals == MAX_PORTALS_ON_LEAF)
|
||||
Error ("Leaf with too many portals");
|
||||
l->portals[l->numportals] = p;
|
||||
l->numportals++;
|
||||
|
||||
p->winding = w;
|
||||
VectorSubtract (vec3_origin, plane.normal, p->plane.normal);
|
||||
p->plane.dist = -plane.dist;
|
||||
p->leaf = leafnums[1];
|
||||
SetPortalSphere (p);
|
||||
p++;
|
||||
|
||||
// create backwards portal
|
||||
l = &leafs[leafnums[1]];
|
||||
if (l->numportals == MAX_PORTALS_ON_LEAF)
|
||||
Error ("Leaf with too many portals");
|
||||
l->portals[l->numportals] = p;
|
||||
l->numportals++;
|
||||
|
||||
p->winding = NewWinding(w->numpoints);
|
||||
p->winding->numpoints = w->numpoints;
|
||||
for (j=0 ; j<w->numpoints ; j++)
|
||||
{
|
||||
VectorCopy (w->points[w->numpoints-1-j], p->winding->points[j]);
|
||||
}
|
||||
|
||||
p->plane = plane;
|
||||
p->leaf = leafnums[0];
|
||||
SetPortalSphere (p);
|
||||
p++;
|
||||
|
||||
}
|
||||
|
||||
fclose (f);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
CalcPHS
|
||||
|
||||
Calculate the PHS (Potentially Hearable Set)
|
||||
by ORing together all the PVS visible from a leaf
|
||||
================
|
||||
*/
|
||||
void CalcPHS (void)
|
||||
{
|
||||
int i, j, k, l, index;
|
||||
int bitbyte;
|
||||
long *dest, *src;
|
||||
byte *scan;
|
||||
int count;
|
||||
byte uncompressed[MAX_MAP_LEAFS/8];
|
||||
byte compressed[MAX_MAP_LEAFS/8];
|
||||
|
||||
printf ("Building PHS...\n");
|
||||
|
||||
count = 0;
|
||||
for (i=0 ; i<portalclusters ; i++)
|
||||
{
|
||||
scan = uncompressedvis + i*leafbytes;
|
||||
memcpy (uncompressed, scan, leafbytes);
|
||||
for (j=0 ; j<leafbytes ; j++)
|
||||
{
|
||||
bitbyte = scan[j];
|
||||
if (!bitbyte)
|
||||
continue;
|
||||
for (k=0 ; k<8 ; k++)
|
||||
{
|
||||
if (! (bitbyte & (1<<k)) )
|
||||
continue;
|
||||
// OR this pvs row into the phs
|
||||
index = ((j<<3)+k);
|
||||
if (index >= portalclusters)
|
||||
Error ("Bad bit in PVS"); // pad bits should be 0
|
||||
src = (long *)(uncompressedvis + index*leafbytes);
|
||||
dest = (long *)uncompressed;
|
||||
for (l=0 ; l<leaflongs ; l++)
|
||||
((long *)uncompressed)[l] |= src[l];
|
||||
}
|
||||
}
|
||||
for (j=0 ; j<portalclusters ; j++)
|
||||
if (uncompressed[j>>3] & (1<<(j&7)) )
|
||||
count++;
|
||||
|
||||
//
|
||||
// compress the bit string
|
||||
//
|
||||
j = CompressVis (uncompressed, compressed);
|
||||
|
||||
dest = (long *)vismap_p;
|
||||
vismap_p += j;
|
||||
|
||||
if (vismap_p > vismap_end)
|
||||
Error ("Vismap expansion overflow");
|
||||
|
||||
dvis->bitofs[i][DVIS_PHS] = (byte *)dest-vismap;
|
||||
|
||||
memcpy (dest, compressed, j);
|
||||
}
|
||||
|
||||
printf ("Average clusters hearable: %i\n", count/portalclusters);
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
main
|
||||
===========
|
||||
*/
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
char portalfile[1024];
|
||||
char source[1024];
|
||||
char name[1024];
|
||||
int i;
|
||||
double start, end;
|
||||
|
||||
printf ("---- vis ----\n");
|
||||
|
||||
verbose = false;
|
||||
for (i=1 ; i<argc ; i++)
|
||||
{
|
||||
if (!strcmp(argv[i],"-threads"))
|
||||
{
|
||||
numthreads = atoi (argv[i+1]);
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-fast"))
|
||||
{
|
||||
printf ("fastvis = true\n");
|
||||
fastvis = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-level"))
|
||||
{
|
||||
testlevel = atoi(argv[i+1]);
|
||||
printf ("testlevel = %i\n", testlevel);
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-v"))
|
||||
{
|
||||
printf ("verbose = true\n");
|
||||
verbose = true;
|
||||
}
|
||||
else if (!strcmp (argv[i],"-nosort"))
|
||||
{
|
||||
printf ("nosort = true\n");
|
||||
nosort = true;
|
||||
}
|
||||
else if (!strcmp (argv[i],"-tmpin"))
|
||||
strcpy (inbase, "/tmp");
|
||||
else if (!strcmp (argv[i],"-tmpout"))
|
||||
strcpy (outbase, "/tmp");
|
||||
else if (argv[i][0] == '-')
|
||||
Error ("Unknown option \"%s\"", argv[i]);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (i != argc - 1)
|
||||
Error ("usage: vis [-threads #] [-level 0-4] [-fast] [-v] bspfile");
|
||||
|
||||
start = I_FloatTime ();
|
||||
|
||||
ThreadSetDefault ();
|
||||
|
||||
SetQdirFromPath (argv[i]);
|
||||
strcpy (source, ExpandArg(argv[i]));
|
||||
StripExtension (source);
|
||||
DefaultExtension (source, ".bsp");
|
||||
|
||||
sprintf (name, "%s%s", inbase, source);
|
||||
printf ("reading %s\n", name);
|
||||
LoadBSPFile (name);
|
||||
if (numnodes == 0 || numfaces == 0)
|
||||
Error ("Empty map");
|
||||
|
||||
sprintf (portalfile, "%s%s", inbase, ExpandArg(argv[i]));
|
||||
StripExtension (portalfile);
|
||||
strcat (portalfile, ".prt");
|
||||
|
||||
printf ("reading %s\n", portalfile);
|
||||
LoadPortals (portalfile);
|
||||
|
||||
CalcVis ();
|
||||
|
||||
CalcPHS ();
|
||||
|
||||
visdatasize = vismap_p - dvisdata;
|
||||
printf ("visdatasize:%i compressed from %i\n", visdatasize, originalvismapsize*2);
|
||||
|
||||
sprintf (name, "%s%s", outbase, source);
|
||||
printf ("writing %s\n", name);
|
||||
WriteBSPFile (name);
|
||||
|
||||
end = I_FloatTime ();
|
||||
printf ("%5.1f seconds elapsed\n", end-start);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
149
tools/quake2/extra/bsp/qvis3/vis.h
Normal file
149
tools/quake2/extra/bsp/qvis3/vis.h
Normal file
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "cmdlib.h"
|
||||
#include "mathlib.h"
|
||||
#include "bspfile.h"
|
||||
|
||||
#define MAX_PORTALS 32768
|
||||
|
||||
#define PORTALFILE "PRT1"
|
||||
|
||||
#define ON_EPSILON 0.1
|
||||
|
||||
typedef struct
|
||||
{
|
||||
vec3_t normal;
|
||||
float dist;
|
||||
} plane_t;
|
||||
|
||||
#define MAX_POINTS_ON_WINDING 64
|
||||
#define MAX_POINTS_ON_FIXED_WINDING 12
|
||||
|
||||
typedef struct
|
||||
{
|
||||
qboolean original; // don't free, it's part of the portal
|
||||
int numpoints;
|
||||
vec3_t points[MAX_POINTS_ON_FIXED_WINDING]; // variable sized
|
||||
} winding_t;
|
||||
|
||||
winding_t *NewWinding (int points);
|
||||
void FreeWinding (winding_t *w);
|
||||
winding_t *CopyWinding (winding_t *w);
|
||||
|
||||
|
||||
typedef enum {stat_none, stat_working, stat_done} vstatus_t;
|
||||
typedef struct
|
||||
{
|
||||
plane_t plane; // normal pointing into neighbor
|
||||
int leaf; // neighbor
|
||||
|
||||
vec3_t origin; // for fast clip testing
|
||||
float radius;
|
||||
|
||||
winding_t *winding;
|
||||
vstatus_t status;
|
||||
byte *portalfront; // [portals], preliminary
|
||||
byte *portalflood; // [portals], intermediate
|
||||
byte *portalvis; // [portals], final
|
||||
|
||||
int nummightsee; // bit count on portalflood for sort
|
||||
} portal_t;
|
||||
|
||||
typedef struct seperating_plane_s
|
||||
{
|
||||
struct seperating_plane_s *next;
|
||||
plane_t plane; // from portal is on positive side
|
||||
} sep_t;
|
||||
|
||||
|
||||
typedef struct passage_s
|
||||
{
|
||||
struct passage_s *next;
|
||||
int from, to; // leaf numbers
|
||||
sep_t *planes;
|
||||
} passage_t;
|
||||
|
||||
#define MAX_PORTALS_ON_LEAF 128
|
||||
typedef struct leaf_s
|
||||
{
|
||||
int numportals;
|
||||
passage_t *passages;
|
||||
portal_t *portals[MAX_PORTALS_ON_LEAF];
|
||||
} leaf_t;
|
||||
|
||||
|
||||
typedef struct pstack_s
|
||||
{
|
||||
byte mightsee[MAX_PORTALS/8]; // bit string
|
||||
struct pstack_s *next;
|
||||
leaf_t *leaf;
|
||||
portal_t *portal; // portal exiting
|
||||
winding_t *source;
|
||||
winding_t *pass;
|
||||
|
||||
winding_t windings[3]; // source, pass, temp in any order
|
||||
int freewindings[3];
|
||||
|
||||
plane_t portalplane;
|
||||
} pstack_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
portal_t *base;
|
||||
int c_chains;
|
||||
pstack_t pstack_head;
|
||||
} threaddata_t;
|
||||
|
||||
|
||||
|
||||
extern int numportals;
|
||||
extern int portalclusters;
|
||||
|
||||
extern portal_t *portals;
|
||||
extern leaf_t *leafs;
|
||||
|
||||
extern int c_portaltest, c_portalpass, c_portalcheck;
|
||||
extern int c_portalskip, c_leafskip;
|
||||
extern int c_vistest, c_mighttest;
|
||||
extern int c_chains;
|
||||
|
||||
extern byte *vismap, *vismap_p, *vismap_end; // past visfile
|
||||
|
||||
extern int testlevel;
|
||||
|
||||
extern byte *uncompressed;
|
||||
|
||||
extern int leafbytes, leaflongs;
|
||||
extern int portalbytes, portallongs;
|
||||
|
||||
|
||||
void LeafFlow (int leafnum);
|
||||
|
||||
|
||||
void BasePortalVis (int portalnum);
|
||||
void BetterPortalVis (int portalnum);
|
||||
void PortalFlow (int portalnum);
|
||||
|
||||
extern portal_t *sorted_portals[MAX_MAP_PORTALS*2];
|
||||
|
||||
int CountBits (byte *bits, int numbits);
|
789
tools/quake2/extra/common/bspfile.c
Normal file
789
tools/quake2/extra/common/bspfile.c
Normal file
|
@ -0,0 +1,789 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "cmdlib.h"
|
||||
#include "mathlib.h"
|
||||
#include "bspfile.h"
|
||||
#include "scriplib.h"
|
||||
|
||||
void GetLeafNums (void);
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int nummodels;
|
||||
dmodel_t dmodels[MAX_MAP_MODELS];
|
||||
|
||||
int visdatasize;
|
||||
byte dvisdata[MAX_MAP_VISIBILITY];
|
||||
dvis_t *dvis = (dvis_t *)dvisdata;
|
||||
|
||||
int lightdatasize;
|
||||
byte dlightdata[MAX_MAP_LIGHTING];
|
||||
|
||||
int entdatasize;
|
||||
char dentdata[MAX_MAP_ENTSTRING];
|
||||
|
||||
int numleafs;
|
||||
dleaf_t dleafs[MAX_MAP_LEAFS];
|
||||
|
||||
int numplanes;
|
||||
dplane_t dplanes[MAX_MAP_PLANES];
|
||||
|
||||
int numvertexes;
|
||||
dvertex_t dvertexes[MAX_MAP_VERTS];
|
||||
|
||||
int numnodes;
|
||||
dnode_t dnodes[MAX_MAP_NODES];
|
||||
|
||||
int numtexinfo;
|
||||
texinfo_t texinfo[MAX_MAP_TEXINFO];
|
||||
|
||||
int numfaces;
|
||||
dface_t dfaces[MAX_MAP_FACES];
|
||||
|
||||
int numedges;
|
||||
dedge_t dedges[MAX_MAP_EDGES];
|
||||
|
||||
int numleaffaces;
|
||||
unsigned short dleaffaces[MAX_MAP_LEAFFACES];
|
||||
|
||||
int numleafbrushes;
|
||||
unsigned short dleafbrushes[MAX_MAP_LEAFBRUSHES];
|
||||
|
||||
int numsurfedges;
|
||||
int dsurfedges[MAX_MAP_SURFEDGES];
|
||||
|
||||
int numbrushes;
|
||||
dbrush_t dbrushes[MAX_MAP_BRUSHES];
|
||||
|
||||
int numbrushsides;
|
||||
dbrushside_t dbrushsides[MAX_MAP_BRUSHSIDES];
|
||||
|
||||
int numareas;
|
||||
darea_t dareas[MAX_MAP_AREAS];
|
||||
|
||||
int numareaportals;
|
||||
dareaportal_t dareaportals[MAX_MAP_AREAPORTALS];
|
||||
|
||||
byte dpop[256];
|
||||
|
||||
/*
|
||||
===============
|
||||
CompressVis
|
||||
|
||||
===============
|
||||
*/
|
||||
int CompressVis (byte *vis, byte *dest)
|
||||
{
|
||||
int j;
|
||||
int rep;
|
||||
int visrow;
|
||||
byte *dest_p;
|
||||
|
||||
dest_p = dest;
|
||||
// visrow = (r_numvisleafs + 7)>>3;
|
||||
visrow = (dvis->numclusters + 7)>>3;
|
||||
|
||||
for (j=0 ; j<visrow ; j++)
|
||||
{
|
||||
*dest_p++ = vis[j];
|
||||
if (vis[j])
|
||||
continue;
|
||||
|
||||
rep = 1;
|
||||
for ( j++; j<visrow ; j++)
|
||||
if (vis[j] || rep == 255)
|
||||
break;
|
||||
else
|
||||
rep++;
|
||||
*dest_p++ = rep;
|
||||
j--;
|
||||
}
|
||||
|
||||
return dest_p - dest;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===================
|
||||
DecompressVis
|
||||
===================
|
||||
*/
|
||||
void DecompressVis (byte *in, byte *decompressed)
|
||||
{
|
||||
int c;
|
||||
byte *out;
|
||||
int row;
|
||||
|
||||
// row = (r_numvisleafs+7)>>3;
|
||||
row = (dvis->numclusters+7)>>3;
|
||||
out = decompressed;
|
||||
|
||||
do
|
||||
{
|
||||
if (*in)
|
||||
{
|
||||
*out++ = *in++;
|
||||
continue;
|
||||
}
|
||||
|
||||
c = in[1];
|
||||
if (!c)
|
||||
Error ("DecompressVis: 0 repeat");
|
||||
in += 2;
|
||||
while (c)
|
||||
{
|
||||
*out++ = 0;
|
||||
c--;
|
||||
}
|
||||
} while (out - decompressed < row);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
/*
|
||||
=============
|
||||
SwapBSPFile
|
||||
|
||||
Byte swaps all data in a bsp file.
|
||||
=============
|
||||
*/
|
||||
void SwapBSPFile (qboolean todisk)
|
||||
{
|
||||
int i, j;
|
||||
dmodel_t *d;
|
||||
|
||||
|
||||
// models
|
||||
for (i=0 ; i<nummodels ; i++)
|
||||
{
|
||||
d = &dmodels[i];
|
||||
|
||||
d->firstface = LittleLong (d->firstface);
|
||||
d->numfaces = LittleLong (d->numfaces);
|
||||
d->headnode = LittleLong (d->headnode);
|
||||
|
||||
for (j=0 ; j<3 ; j++)
|
||||
{
|
||||
d->mins[j] = LittleFloat(d->mins[j]);
|
||||
d->maxs[j] = LittleFloat(d->maxs[j]);
|
||||
d->origin[j] = LittleFloat(d->origin[j]);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// vertexes
|
||||
//
|
||||
for (i=0 ; i<numvertexes ; i++)
|
||||
{
|
||||
for (j=0 ; j<3 ; j++)
|
||||
dvertexes[i].point[j] = LittleFloat (dvertexes[i].point[j]);
|
||||
}
|
||||
|
||||
//
|
||||
// planes
|
||||
//
|
||||
for (i=0 ; i<numplanes ; i++)
|
||||
{
|
||||
for (j=0 ; j<3 ; j++)
|
||||
dplanes[i].normal[j] = LittleFloat (dplanes[i].normal[j]);
|
||||
dplanes[i].dist = LittleFloat (dplanes[i].dist);
|
||||
dplanes[i].type = LittleLong (dplanes[i].type);
|
||||
}
|
||||
|
||||
//
|
||||
// texinfos
|
||||
//
|
||||
for (i=0 ; i<numtexinfo ; i++)
|
||||
{
|
||||
for (j=0 ; j<8 ; j++)
|
||||
texinfo[i].vecs[0][j] = LittleFloat (texinfo[i].vecs[0][j]);
|
||||
texinfo[i].flags = LittleLong (texinfo[i].flags);
|
||||
texinfo[i].value = LittleLong (texinfo[i].value);
|
||||
texinfo[i].nexttexinfo = LittleLong (texinfo[i].nexttexinfo);
|
||||
}
|
||||
|
||||
//
|
||||
// faces
|
||||
//
|
||||
for (i=0 ; i<numfaces ; i++)
|
||||
{
|
||||
dfaces[i].texinfo = LittleShort (dfaces[i].texinfo);
|
||||
dfaces[i].planenum = LittleShort (dfaces[i].planenum);
|
||||
dfaces[i].side = LittleShort (dfaces[i].side);
|
||||
dfaces[i].lightofs = LittleLong (dfaces[i].lightofs);
|
||||
dfaces[i].firstedge = LittleLong (dfaces[i].firstedge);
|
||||
dfaces[i].numedges = LittleShort (dfaces[i].numedges);
|
||||
}
|
||||
|
||||
//
|
||||
// nodes
|
||||
//
|
||||
for (i=0 ; i<numnodes ; i++)
|
||||
{
|
||||
dnodes[i].planenum = LittleLong (dnodes[i].planenum);
|
||||
for (j=0 ; j<3 ; j++)
|
||||
{
|
||||
dnodes[i].mins[j] = LittleShort (dnodes[i].mins[j]);
|
||||
dnodes[i].maxs[j] = LittleShort (dnodes[i].maxs[j]);
|
||||
}
|
||||
dnodes[i].children[0] = LittleLong (dnodes[i].children[0]);
|
||||
dnodes[i].children[1] = LittleLong (dnodes[i].children[1]);
|
||||
dnodes[i].firstface = LittleShort (dnodes[i].firstface);
|
||||
dnodes[i].numfaces = LittleShort (dnodes[i].numfaces);
|
||||
}
|
||||
|
||||
//
|
||||
// leafs
|
||||
//
|
||||
for (i=0 ; i<numleafs ; i++)
|
||||
{
|
||||
dleafs[i].contents = LittleLong (dleafs[i].contents);
|
||||
dleafs[i].cluster = LittleShort (dleafs[i].cluster);
|
||||
dleafs[i].area = LittleShort (dleafs[i].area);
|
||||
for (j=0 ; j<3 ; j++)
|
||||
{
|
||||
dleafs[i].mins[j] = LittleShort (dleafs[i].mins[j]);
|
||||
dleafs[i].maxs[j] = LittleShort (dleafs[i].maxs[j]);
|
||||
}
|
||||
|
||||
dleafs[i].firstleafface = LittleShort (dleafs[i].firstleafface);
|
||||
dleafs[i].numleaffaces = LittleShort (dleafs[i].numleaffaces);
|
||||
dleafs[i].firstleafbrush = LittleShort (dleafs[i].firstleafbrush);
|
||||
dleafs[i].numleafbrushes = LittleShort (dleafs[i].numleafbrushes);
|
||||
}
|
||||
|
||||
//
|
||||
// leaffaces
|
||||
//
|
||||
for (i=0 ; i<numleaffaces ; i++)
|
||||
dleaffaces[i] = LittleShort (dleaffaces[i]);
|
||||
|
||||
//
|
||||
// leafbrushes
|
||||
//
|
||||
for (i=0 ; i<numleafbrushes ; i++)
|
||||
dleafbrushes[i] = LittleShort (dleafbrushes[i]);
|
||||
|
||||
//
|
||||
// surfedges
|
||||
//
|
||||
for (i=0 ; i<numsurfedges ; i++)
|
||||
dsurfedges[i] = LittleLong (dsurfedges[i]);
|
||||
|
||||
//
|
||||
// edges
|
||||
//
|
||||
for (i=0 ; i<numedges ; i++)
|
||||
{
|
||||
dedges[i].v[0] = LittleShort (dedges[i].v[0]);
|
||||
dedges[i].v[1] = LittleShort (dedges[i].v[1]);
|
||||
}
|
||||
|
||||
//
|
||||
// brushes
|
||||
//
|
||||
for (i=0 ; i<numbrushes ; i++)
|
||||
{
|
||||
dbrushes[i].firstside = LittleLong (dbrushes[i].firstside);
|
||||
dbrushes[i].numsides = LittleLong (dbrushes[i].numsides);
|
||||
dbrushes[i].contents = LittleLong (dbrushes[i].contents);
|
||||
}
|
||||
|
||||
//
|
||||
// areas
|
||||
//
|
||||
for (i=0 ; i<numareas ; i++)
|
||||
{
|
||||
dareas[i].numareaportals = LittleLong (dareas[i].numareaportals);
|
||||
dareas[i].firstareaportal = LittleLong (dareas[i].firstareaportal);
|
||||
}
|
||||
|
||||
//
|
||||
// areasportals
|
||||
//
|
||||
for (i=0 ; i<numareaportals ; i++)
|
||||
{
|
||||
dareaportals[i].portalnum = LittleLong (dareaportals[i].portalnum);
|
||||
dareaportals[i].otherarea = LittleLong (dareaportals[i].otherarea);
|
||||
}
|
||||
|
||||
//
|
||||
// brushsides
|
||||
//
|
||||
for (i=0 ; i<numbrushsides ; i++)
|
||||
{
|
||||
dbrushsides[i].planenum = LittleShort (dbrushsides[i].planenum);
|
||||
dbrushsides[i].texinfo = LittleShort (dbrushsides[i].texinfo);
|
||||
}
|
||||
|
||||
//
|
||||
// visibility
|
||||
//
|
||||
if (todisk)
|
||||
j = dvis->numclusters;
|
||||
else
|
||||
j = LittleLong(dvis->numclusters);
|
||||
dvis->numclusters = LittleLong (dvis->numclusters);
|
||||
for (i=0 ; i<j ; i++)
|
||||
{
|
||||
dvis->bitofs[i][0] = LittleLong (dvis->bitofs[i][0]);
|
||||
dvis->bitofs[i][1] = LittleLong (dvis->bitofs[i][1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
dheader_t *header;
|
||||
|
||||
int CopyLump (int lump, void *dest, int size)
|
||||
{
|
||||
int length, ofs;
|
||||
|
||||
length = header->lumps[lump].filelen;
|
||||
ofs = header->lumps[lump].fileofs;
|
||||
|
||||
if (length % size)
|
||||
Error ("LoadBSPFile: odd lump size");
|
||||
|
||||
memcpy (dest, (byte *)header + ofs, length);
|
||||
|
||||
return length / size;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
LoadBSPFile
|
||||
=============
|
||||
*/
|
||||
void LoadBSPFile (char *filename)
|
||||
{
|
||||
int i;
|
||||
|
||||
//
|
||||
// load the file header
|
||||
//
|
||||
LoadFile (filename, (void **)&header);
|
||||
|
||||
// swap the header
|
||||
for (i=0 ; i< sizeof(dheader_t)/4 ; i++)
|
||||
((int *)header)[i] = LittleLong ( ((int *)header)[i]);
|
||||
|
||||
if (header->ident != IDBSPHEADER)
|
||||
Error ("%s is not a IBSP file", filename);
|
||||
if (header->version != BSPVERSION)
|
||||
Error ("%s is version %i, not %i", filename, header->version, BSPVERSION);
|
||||
|
||||
nummodels = CopyLump (LUMP_MODELS, dmodels, sizeof(dmodel_t));
|
||||
numvertexes = CopyLump (LUMP_VERTEXES, dvertexes, sizeof(dvertex_t));
|
||||
numplanes = CopyLump (LUMP_PLANES, dplanes, sizeof(dplane_t));
|
||||
numleafs = CopyLump (LUMP_LEAFS, dleafs, sizeof(dleaf_t));
|
||||
numnodes = CopyLump (LUMP_NODES, dnodes, sizeof(dnode_t));
|
||||
numtexinfo = CopyLump (LUMP_TEXINFO, texinfo, sizeof(texinfo_t));
|
||||
numfaces = CopyLump (LUMP_FACES, dfaces, sizeof(dface_t));
|
||||
numleaffaces = CopyLump (LUMP_LEAFFACES, dleaffaces, sizeof(dleaffaces[0]));
|
||||
numleafbrushes = CopyLump (LUMP_LEAFBRUSHES, dleafbrushes, sizeof(dleafbrushes[0]));
|
||||
numsurfedges = CopyLump (LUMP_SURFEDGES, dsurfedges, sizeof(dsurfedges[0]));
|
||||
numedges = CopyLump (LUMP_EDGES, dedges, sizeof(dedge_t));
|
||||
numbrushes = CopyLump (LUMP_BRUSHES, dbrushes, sizeof(dbrush_t));
|
||||
numbrushsides = CopyLump (LUMP_BRUSHSIDES, dbrushsides, sizeof(dbrushside_t));
|
||||
numareas = CopyLump (LUMP_AREAS, dareas, sizeof(darea_t));
|
||||
numareaportals = CopyLump (LUMP_AREAPORTALS, dareaportals, sizeof(dareaportal_t));
|
||||
|
||||
visdatasize = CopyLump (LUMP_VISIBILITY, dvisdata, 1);
|
||||
lightdatasize = CopyLump (LUMP_LIGHTING, dlightdata, 1);
|
||||
entdatasize = CopyLump (LUMP_ENTITIES, dentdata, 1);
|
||||
|
||||
CopyLump (LUMP_POP, dpop, 1);
|
||||
|
||||
free (header); // everything has been copied out
|
||||
|
||||
//
|
||||
// swap everything
|
||||
//
|
||||
SwapBSPFile (false);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
LoadBSPFileTexinfo
|
||||
|
||||
Only loads the texinfo lump, so qdata can scan for textures
|
||||
=============
|
||||
*/
|
||||
void LoadBSPFileTexinfo (char *filename)
|
||||
{
|
||||
int i;
|
||||
FILE *f;
|
||||
int length, ofs;
|
||||
|
||||
header = malloc(sizeof(dheader_t));
|
||||
|
||||
f = fopen (filename, "rb");
|
||||
fread (header, sizeof(dheader_t), 1, f);
|
||||
|
||||
// swap the header
|
||||
for (i=0 ; i< sizeof(dheader_t)/4 ; i++)
|
||||
((int *)header)[i] = LittleLong ( ((int *)header)[i]);
|
||||
|
||||
if (header->ident != IDBSPHEADER)
|
||||
Error ("%s is not a IBSP file", filename);
|
||||
if (header->version != BSPVERSION)
|
||||
Error ("%s is version %i, not %i", filename, header->version, BSPVERSION);
|
||||
|
||||
|
||||
length = header->lumps[LUMP_TEXINFO].filelen;
|
||||
ofs = header->lumps[LUMP_TEXINFO].fileofs;
|
||||
|
||||
fseek (f, ofs, SEEK_SET);
|
||||
fread (texinfo, length, 1, f);
|
||||
fclose (f);
|
||||
|
||||
numtexinfo = length / sizeof(texinfo_t);
|
||||
|
||||
free (header); // everything has been copied out
|
||||
|
||||
SwapBSPFile (false);
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
|
||||
FILE *wadfile;
|
||||
dheader_t outheader;
|
||||
|
||||
void AddLump (int lumpnum, void *data, int len)
|
||||
{
|
||||
lump_t *lump;
|
||||
|
||||
lump = &header->lumps[lumpnum];
|
||||
|
||||
lump->fileofs = LittleLong( ftell(wadfile) );
|
||||
lump->filelen = LittleLong(len);
|
||||
SafeWrite (wadfile, data, (len+3)&~3);
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
WriteBSPFile
|
||||
|
||||
Swaps the bsp file in place, so it should not be referenced again
|
||||
=============
|
||||
*/
|
||||
void WriteBSPFile (char *filename)
|
||||
{
|
||||
header = &outheader;
|
||||
memset (header, 0, sizeof(dheader_t));
|
||||
|
||||
SwapBSPFile (true);
|
||||
|
||||
header->ident = LittleLong (IDBSPHEADER);
|
||||
header->version = LittleLong (BSPVERSION);
|
||||
|
||||
wadfile = SafeOpenWrite (filename);
|
||||
SafeWrite (wadfile, header, sizeof(dheader_t)); // overwritten later
|
||||
|
||||
AddLump (LUMP_PLANES, dplanes, numplanes*sizeof(dplane_t));
|
||||
AddLump (LUMP_LEAFS, dleafs, numleafs*sizeof(dleaf_t));
|
||||
AddLump (LUMP_VERTEXES, dvertexes, numvertexes*sizeof(dvertex_t));
|
||||
AddLump (LUMP_NODES, dnodes, numnodes*sizeof(dnode_t));
|
||||
AddLump (LUMP_TEXINFO, texinfo, numtexinfo*sizeof(texinfo_t));
|
||||
AddLump (LUMP_FACES, dfaces, numfaces*sizeof(dface_t));
|
||||
AddLump (LUMP_BRUSHES, dbrushes, numbrushes*sizeof(dbrush_t));
|
||||
AddLump (LUMP_BRUSHSIDES, dbrushsides, numbrushsides*sizeof(dbrushside_t));
|
||||
AddLump (LUMP_LEAFFACES, dleaffaces, numleaffaces*sizeof(dleaffaces[0]));
|
||||
AddLump (LUMP_LEAFBRUSHES, dleafbrushes, numleafbrushes*sizeof(dleafbrushes[0]));
|
||||
AddLump (LUMP_SURFEDGES, dsurfedges, numsurfedges*sizeof(dsurfedges[0]));
|
||||
AddLump (LUMP_EDGES, dedges, numedges*sizeof(dedge_t));
|
||||
AddLump (LUMP_MODELS, dmodels, nummodels*sizeof(dmodel_t));
|
||||
AddLump (LUMP_AREAS, dareas, numareas*sizeof(darea_t));
|
||||
AddLump (LUMP_AREAPORTALS, dareaportals, numareaportals*sizeof(dareaportal_t));
|
||||
|
||||
AddLump (LUMP_LIGHTING, dlightdata, lightdatasize);
|
||||
AddLump (LUMP_VISIBILITY, dvisdata, visdatasize);
|
||||
AddLump (LUMP_ENTITIES, dentdata, entdatasize);
|
||||
AddLump (LUMP_POP, dpop, sizeof(dpop));
|
||||
|
||||
fseek (wadfile, 0, SEEK_SET);
|
||||
SafeWrite (wadfile, header, sizeof(dheader_t));
|
||||
fclose (wadfile);
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
||||
/*
|
||||
=============
|
||||
PrintBSPFileSizes
|
||||
|
||||
Dumps info about current file
|
||||
=============
|
||||
*/
|
||||
void PrintBSPFileSizes (void)
|
||||
{
|
||||
if (!num_entities)
|
||||
ParseEntities ();
|
||||
|
||||
printf ("%5i models %7i\n"
|
||||
,nummodels, (int)(nummodels*sizeof(dmodel_t)));
|
||||
printf ("%5i brushes %7i\n"
|
||||
,numbrushes, (int)(numbrushes*sizeof(dbrush_t)));
|
||||
printf ("%5i brushsides %7i\n"
|
||||
,numbrushsides, (int)(numbrushsides*sizeof(dbrushside_t)));
|
||||
printf ("%5i planes %7i\n"
|
||||
,numplanes, (int)(numplanes*sizeof(dplane_t)));
|
||||
printf ("%5i texinfo %7i\n"
|
||||
,numtexinfo, (int)(numtexinfo*sizeof(texinfo_t)));
|
||||
printf ("%5i entdata %7i\n", num_entities, entdatasize);
|
||||
|
||||
printf ("\n");
|
||||
|
||||
printf ("%5i vertexes %7i\n"
|
||||
,numvertexes, (int)(numvertexes*sizeof(dvertex_t)));
|
||||
printf ("%5i nodes %7i\n"
|
||||
,numnodes, (int)(numnodes*sizeof(dnode_t)));
|
||||
printf ("%5i faces %7i\n"
|
||||
,numfaces, (int)(numfaces*sizeof(dface_t)));
|
||||
printf ("%5i leafs %7i\n"
|
||||
,numleafs, (int)(numleafs*sizeof(dleaf_t)));
|
||||
printf ("%5i leaffaces %7i\n"
|
||||
,numleaffaces, (int)(numleaffaces*sizeof(dleaffaces[0])));
|
||||
printf ("%5i leafbrushes %7i\n"
|
||||
,numleafbrushes, (int)(numleafbrushes*sizeof(dleafbrushes[0])));
|
||||
printf ("%5i surfedges %7i\n"
|
||||
,numsurfedges, (int)(numsurfedges*sizeof(dsurfedges[0])));
|
||||
printf ("%5i edges %7i\n"
|
||||
,numedges, (int)(numedges*sizeof(dedge_t)));
|
||||
printf (" lightdata %7i\n", lightdatasize);
|
||||
printf (" visdata %7i\n", visdatasize);
|
||||
}
|
||||
|
||||
|
||||
//============================================
|
||||
|
||||
int num_entities;
|
||||
entity_t entities[MAX_MAP_ENTITIES];
|
||||
|
||||
void StripTrailing (char *e)
|
||||
{
|
||||
char *s;
|
||||
|
||||
s = e + strlen(e)-1;
|
||||
while (s >= e && *s <= 32)
|
||||
{
|
||||
*s = 0;
|
||||
s--;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
ParseEpair
|
||||
=================
|
||||
*/
|
||||
epair_t *ParseEpair (void)
|
||||
{
|
||||
epair_t *e;
|
||||
|
||||
e = malloc (sizeof(epair_t));
|
||||
memset (e, 0, sizeof(epair_t));
|
||||
|
||||
if (strlen(token) >= MAX_KEY-1)
|
||||
Error ("ParseEpar: token too long");
|
||||
e->key = copystring(token);
|
||||
GetToken (false);
|
||||
if (strlen(token) >= MAX_VALUE-1)
|
||||
Error ("ParseEpar: token too long");
|
||||
e->value = copystring(token);
|
||||
|
||||
// strip trailing spaces
|
||||
StripTrailing (e->key);
|
||||
StripTrailing (e->value);
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
ParseEntity
|
||||
================
|
||||
*/
|
||||
qboolean ParseEntity (void)
|
||||
{
|
||||
epair_t *e;
|
||||
entity_t *mapent;
|
||||
|
||||
if (!GetToken (true))
|
||||
return false;
|
||||
|
||||
if (strcmp (token, "{") )
|
||||
Error ("ParseEntity: { not found");
|
||||
|
||||
if (num_entities == MAX_MAP_ENTITIES)
|
||||
Error ("num_entities == MAX_MAP_ENTITIES");
|
||||
|
||||
mapent = &entities[num_entities];
|
||||
num_entities++;
|
||||
|
||||
do
|
||||
{
|
||||
if (!GetToken (true))
|
||||
Error ("ParseEntity: EOF without closing brace");
|
||||
if (!strcmp (token, "}") )
|
||||
break;
|
||||
e = ParseEpair ();
|
||||
e->next = mapent->epairs;
|
||||
mapent->epairs = e;
|
||||
} while (1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
ParseEntities
|
||||
|
||||
Parses the dentdata string into entities
|
||||
================
|
||||
*/
|
||||
void ParseEntities (void)
|
||||
{
|
||||
num_entities = 0;
|
||||
ParseFromMemory (dentdata, entdatasize);
|
||||
|
||||
while (ParseEntity ())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
UnparseEntities
|
||||
|
||||
Generates the dentdata string from all the entities
|
||||
================
|
||||
*/
|
||||
void UnparseEntities (void)
|
||||
{
|
||||
char *buf, *end;
|
||||
epair_t *ep;
|
||||
char line[2048];
|
||||
int i;
|
||||
char key[1024], value[1024];
|
||||
|
||||
buf = dentdata;
|
||||
end = buf;
|
||||
*end = 0;
|
||||
|
||||
for (i=0 ; i<num_entities ; i++)
|
||||
{
|
||||
ep = entities[i].epairs;
|
||||
if (!ep)
|
||||
continue; // ent got removed
|
||||
|
||||
strcat (end,"{\n");
|
||||
end += 2;
|
||||
|
||||
for (ep = entities[i].epairs ; ep ; ep=ep->next)
|
||||
{
|
||||
strcpy (key, ep->key);
|
||||
StripTrailing (key);
|
||||
strcpy (value, ep->value);
|
||||
StripTrailing (value);
|
||||
|
||||
sprintf (line, "\"%s\" \"%s\"\n", key, value);
|
||||
strcat (end, line);
|
||||
end += strlen(line);
|
||||
}
|
||||
strcat (end,"}\n");
|
||||
end += 2;
|
||||
|
||||
if (end > buf + MAX_MAP_ENTSTRING)
|
||||
Error ("Entity text too long");
|
||||
}
|
||||
entdatasize = end - buf + 1;
|
||||
}
|
||||
|
||||
void PrintEntity (entity_t *ent)
|
||||
{
|
||||
epair_t *ep;
|
||||
|
||||
printf ("------- entity %p -------\n", ent);
|
||||
for (ep=ent->epairs ; ep ; ep=ep->next)
|
||||
{
|
||||
printf ("%s = %s\n", ep->key, ep->value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SetKeyValue (entity_t *ent, char *key, char *value)
|
||||
{
|
||||
epair_t *ep;
|
||||
|
||||
for (ep=ent->epairs ; ep ; ep=ep->next)
|
||||
if (!strcmp (ep->key, key) )
|
||||
{
|
||||
free (ep->value);
|
||||
ep->value = copystring(value);
|
||||
return;
|
||||
}
|
||||
ep = malloc (sizeof(*ep));
|
||||
ep->next = ent->epairs;
|
||||
ent->epairs = ep;
|
||||
ep->key = copystring(key);
|
||||
ep->value = copystring(value);
|
||||
}
|
||||
|
||||
char *ValueForKey (entity_t *ent, char *key)
|
||||
{
|
||||
epair_t *ep;
|
||||
|
||||
for (ep=ent->epairs ; ep ; ep=ep->next)
|
||||
if (!strcmp (ep->key, key) )
|
||||
return ep->value;
|
||||
return "";
|
||||
}
|
||||
|
||||
vec_t FloatForKey (entity_t *ent, char *key)
|
||||
{
|
||||
char *k;
|
||||
|
||||
k = ValueForKey (ent, key);
|
||||
return atof(k);
|
||||
}
|
||||
|
||||
void GetVectorForKey (entity_t *ent, char *key, vec3_t vec)
|
||||
{
|
||||
char *k;
|
||||
double v1, v2, v3;
|
||||
|
||||
k = ValueForKey (ent, key);
|
||||
// scanf into doubles, then assign, so it is vec_t size independent
|
||||
v1 = v2 = v3 = 0;
|
||||
sscanf (k, "%lf %lf %lf", &v1, &v2, &v3);
|
||||
vec[0] = v1;
|
||||
vec[1] = v2;
|
||||
vec[2] = v3;
|
||||
}
|
||||
|
||||
|
129
tools/quake2/extra/common/bspfile.h
Normal file
129
tools/quake2/extra/common/bspfile.h
Normal file
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "qfiles.h"
|
||||
|
||||
|
||||
extern int nummodels;
|
||||
extern dmodel_t dmodels[MAX_MAP_MODELS];
|
||||
|
||||
extern int visdatasize;
|
||||
extern byte dvisdata[MAX_MAP_VISIBILITY];
|
||||
extern dvis_t *dvis;
|
||||
|
||||
extern int lightdatasize;
|
||||
extern byte dlightdata[MAX_MAP_LIGHTING];
|
||||
|
||||
extern int entdatasize;
|
||||
extern char dentdata[MAX_MAP_ENTSTRING];
|
||||
|
||||
extern int numleafs;
|
||||
extern dleaf_t dleafs[MAX_MAP_LEAFS];
|
||||
|
||||
extern int numplanes;
|
||||
extern dplane_t dplanes[MAX_MAP_PLANES];
|
||||
|
||||
extern int numvertexes;
|
||||
extern dvertex_t dvertexes[MAX_MAP_VERTS];
|
||||
|
||||
extern int numnodes;
|
||||
extern dnode_t dnodes[MAX_MAP_NODES];
|
||||
|
||||
extern int numtexinfo;
|
||||
extern texinfo_t texinfo[MAX_MAP_TEXINFO];
|
||||
|
||||
extern int numfaces;
|
||||
extern dface_t dfaces[MAX_MAP_FACES];
|
||||
|
||||
extern int numedges;
|
||||
extern dedge_t dedges[MAX_MAP_EDGES];
|
||||
|
||||
extern int numleaffaces;
|
||||
extern unsigned short dleaffaces[MAX_MAP_LEAFFACES];
|
||||
|
||||
extern int numleafbrushes;
|
||||
extern unsigned short dleafbrushes[MAX_MAP_LEAFBRUSHES];
|
||||
|
||||
extern int numsurfedges;
|
||||
extern int dsurfedges[MAX_MAP_SURFEDGES];
|
||||
|
||||
extern int numareas;
|
||||
extern darea_t dareas[MAX_MAP_AREAS];
|
||||
|
||||
extern int numareaportals;
|
||||
extern dareaportal_t dareaportals[MAX_MAP_AREAPORTALS];
|
||||
|
||||
extern int numbrushes;
|
||||
extern dbrush_t dbrushes[MAX_MAP_BRUSHES];
|
||||
|
||||
extern int numbrushsides;
|
||||
extern dbrushside_t dbrushsides[MAX_MAP_BRUSHSIDES];
|
||||
|
||||
extern byte dpop[256];
|
||||
|
||||
void DecompressVis (byte *in, byte *decompressed);
|
||||
int CompressVis (byte *vis, byte *dest);
|
||||
|
||||
void LoadBSPFile (char *filename);
|
||||
void LoadBSPFileTexinfo (char *filename); // just for qdata
|
||||
void WriteBSPFile (char *filename);
|
||||
void PrintBSPFileSizes (void);
|
||||
|
||||
//===============
|
||||
|
||||
|
||||
typedef struct epair_s
|
||||
{
|
||||
struct epair_s *next;
|
||||
char *key;
|
||||
char *value;
|
||||
} epair_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
vec3_t origin;
|
||||
int firstbrush;
|
||||
int numbrushes;
|
||||
epair_t *epairs;
|
||||
|
||||
// only valid for func_areaportals
|
||||
int areaportalnum;
|
||||
int portalareas[2];
|
||||
} entity_t;
|
||||
|
||||
extern int num_entities;
|
||||
extern entity_t entities[MAX_MAP_ENTITIES];
|
||||
|
||||
void ParseEntities (void);
|
||||
void UnparseEntities (void);
|
||||
|
||||
void SetKeyValue (entity_t *ent, char *key, char *value);
|
||||
char *ValueForKey (entity_t *ent, char *key);
|
||||
// will return "" if not present
|
||||
|
||||
vec_t FloatForKey (entity_t *ent, char *key);
|
||||
void GetVectorForKey (entity_t *ent, char *key, vec3_t vec);
|
||||
|
||||
epair_t *ParseEpair (void);
|
||||
|
||||
void PrintEntity (entity_t *ent);
|
||||
|
1055
tools/quake2/extra/common/cmdlib.c
Normal file
1055
tools/quake2/extra/common/cmdlib.c
Normal file
File diff suppressed because it is too large
Load diff
145
tools/quake2/extra/common/cmdlib.h
Normal file
145
tools/quake2/extra/common/cmdlib.h
Normal file
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// cmdlib.h
|
||||
|
||||
#ifndef __CMDLIB__
|
||||
#define __CMDLIB__
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(disable : 4244) // MIPS
|
||||
#pragma warning(disable : 4136) // X86
|
||||
#pragma warning(disable : 4051) // ALPHA
|
||||
|
||||
#pragma warning(disable : 4018) // signed/unsigned mismatch
|
||||
#pragma warning(disable : 4305) // truncate from double to float
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifndef __BYTEBOOL__
|
||||
#define __BYTEBOOL__
|
||||
typedef enum {false, true} qboolean;
|
||||
typedef unsigned char byte;
|
||||
#endif
|
||||
|
||||
// the dec offsetof macro doesnt work very well...
|
||||
#define myoffsetof(type,identifier) ((size_t)&((type *)0)->identifier)
|
||||
|
||||
|
||||
// set these before calling CheckParm
|
||||
extern int myargc;
|
||||
extern char **myargv;
|
||||
|
||||
char *strupr (char *in);
|
||||
char *strlower (char *in);
|
||||
int Q_strncasecmp (char *s1, char *s2, int n);
|
||||
int Q_strcasecmp (char *s1, char *s2);
|
||||
void Q_getwd (char *out);
|
||||
|
||||
int Q_filelength (FILE *f);
|
||||
int FileTime (char *path);
|
||||
|
||||
void Q_mkdir (char *path);
|
||||
|
||||
extern char qdir[1024];
|
||||
extern char gamedir[1024];
|
||||
void SetQdirFromPath (char *path);
|
||||
char *ExpandArg (char *path); // from cmd line
|
||||
char *ExpandPath (char *path); // from scripts
|
||||
char *ExpandPathAndArchive (char *path);
|
||||
|
||||
|
||||
double I_FloatTime (void);
|
||||
|
||||
void Error (char *error, ...);
|
||||
int CheckParm (char *check);
|
||||
|
||||
FILE *SafeOpenWrite (char *filename);
|
||||
FILE *SafeOpenRead (char *filename);
|
||||
void SafeRead (FILE *f, void *buffer, int count);
|
||||
void SafeWrite (FILE *f, void *buffer, int count);
|
||||
|
||||
int LoadFile (char *filename, void **bufferptr);
|
||||
int TryLoadFile (char *filename, void **bufferptr);
|
||||
void SaveFile (char *filename, void *buffer, int count);
|
||||
qboolean FileExists (char *filename);
|
||||
|
||||
void DefaultExtension (char *path, char *extension);
|
||||
void DefaultPath (char *path, char *basepath);
|
||||
void StripFilename (char *path);
|
||||
void StripExtension (char *path);
|
||||
|
||||
void ExtractFilePath (char *path, char *dest);
|
||||
void ExtractFileBase (char *path, char *dest);
|
||||
void ExtractFileExtension (char *path, char *dest);
|
||||
|
||||
int ParseNum (char *str);
|
||||
|
||||
short BigShort (short l);
|
||||
short LittleShort (short l);
|
||||
int BigLong (int l);
|
||||
int LittleLong (int l);
|
||||
float BigFloat (float l);
|
||||
float LittleFloat (float l);
|
||||
|
||||
|
||||
char *COM_Parse (char *data);
|
||||
|
||||
extern char com_token[1024];
|
||||
extern qboolean com_eof;
|
||||
|
||||
char *copystring(char *s);
|
||||
|
||||
|
||||
void CRC_Init(unsigned short *crcvalue);
|
||||
void CRC_ProcessByte(unsigned short *crcvalue, byte data);
|
||||
unsigned short CRC_Value(unsigned short crcvalue);
|
||||
|
||||
void CreatePath (char *path);
|
||||
void QCopyFile (char *from, char *to);
|
||||
|
||||
extern qboolean archive;
|
||||
extern char archivedir[1024];
|
||||
|
||||
|
||||
extern qboolean verbose;
|
||||
void qprintf (char *format, ...);
|
||||
|
||||
void ExpandWildcards (int *argc, char ***argv);
|
||||
|
||||
|
||||
// for compression routines
|
||||
typedef struct
|
||||
{
|
||||
byte *data;
|
||||
int count;
|
||||
} cblock_t;
|
||||
|
||||
|
||||
#endif
|
301
tools/quake2/extra/common/l3dslib.c
Normal file
301
tools/quake2/extra/common/l3dslib.c
Normal file
|
@ -0,0 +1,301 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
//
|
||||
// l3dslib.c: library for loading triangles from an Alias triangle file
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
#include "cmdlib.h"
|
||||
#include "mathlib.h"
|
||||
#include "trilib.h"
|
||||
#include "l3dslib.h"
|
||||
|
||||
#define MAIN3DS 0x4D4D
|
||||
#define EDIT3DS 0x3D3D // this is the start of the editor config
|
||||
#define EDIT_OBJECT 0x4000
|
||||
#define OBJ_TRIMESH 0x4100
|
||||
#define TRI_VERTEXL 0x4110
|
||||
#define TRI_FACEL1 0x4120
|
||||
|
||||
#define MAXVERTS 2000
|
||||
|
||||
typedef struct {
|
||||
int v[4];
|
||||
} tri;
|
||||
|
||||
float fverts[MAXVERTS][3];
|
||||
tri tris[MAXTRIANGLES];
|
||||
|
||||
int bytesread, level, numtris, totaltris;
|
||||
int vertsfound, trisfound;
|
||||
|
||||
triangle_t *ptri;
|
||||
|
||||
|
||||
// Alias stores triangles as 3 explicit vertices in .tri files, so even though we
|
||||
// start out with a vertex pool and vertex indices for triangles, we have to convert
|
||||
// to raw, explicit triangles
|
||||
void StoreAliasTriangles (void)
|
||||
{
|
||||
int i, j, k;
|
||||
|
||||
if ((totaltris + numtris) > MAXTRIANGLES)
|
||||
Error ("Error: Too many triangles");
|
||||
|
||||
for (i=0; i<numtris ; i++)
|
||||
{
|
||||
for (j=0 ; j<3 ; j++)
|
||||
{
|
||||
for (k=0 ; k<3 ; k++)
|
||||
{
|
||||
ptri[i+totaltris].verts[j][k] = fverts[tris[i].v[j]][k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
totaltris += numtris;
|
||||
numtris = 0;
|
||||
vertsfound = 0;
|
||||
trisfound = 0;
|
||||
}
|
||||
|
||||
|
||||
int ParseVertexL (FILE *input)
|
||||
{
|
||||
int i, j, startbytesread, numverts;
|
||||
unsigned short tshort;
|
||||
|
||||
if (vertsfound)
|
||||
Error ("Error: Multiple vertex chunks");
|
||||
|
||||
vertsfound = 1;
|
||||
startbytesread = bytesread;
|
||||
|
||||
if (feof(input))
|
||||
Error ("Error: unexpected end of file");
|
||||
|
||||
fread(&tshort, sizeof(tshort), 1, input);
|
||||
bytesread += sizeof(tshort);
|
||||
numverts = (int)tshort;
|
||||
|
||||
if (numverts > MAXVERTS)
|
||||
Error ("Error: Too many vertices");
|
||||
|
||||
for (i=0 ; i<numverts ; i++)
|
||||
{
|
||||
for (j=0 ; j<3 ; j++)
|
||||
{
|
||||
if (feof(input))
|
||||
Error ("Error: unexpected end of file");
|
||||
|
||||
fread(&fverts[i][j], sizeof(float), 1, input);
|
||||
bytesread += sizeof(float);
|
||||
}
|
||||
}
|
||||
|
||||
if (vertsfound && trisfound)
|
||||
StoreAliasTriangles ();
|
||||
|
||||
return bytesread - startbytesread;
|
||||
}
|
||||
|
||||
|
||||
int ParseFaceL1 (FILE *input)
|
||||
{
|
||||
|
||||
int i, j, startbytesread;
|
||||
unsigned short tshort;
|
||||
|
||||
if (trisfound)
|
||||
Error ("Error: Multiple face chunks");
|
||||
|
||||
trisfound = 1;
|
||||
startbytesread = bytesread;
|
||||
|
||||
if (feof(input))
|
||||
Error ("Error: unexpected end of file");
|
||||
|
||||
fread(&tshort, sizeof(tshort), 1, input);
|
||||
bytesread += sizeof(tshort);
|
||||
numtris = (int)tshort;
|
||||
|
||||
if (numtris > MAXTRIANGLES)
|
||||
Error ("Error: Too many triangles");
|
||||
|
||||
for (i=0 ; i<numtris ; i++)
|
||||
{
|
||||
for (j=0 ; j<4 ; j++)
|
||||
{
|
||||
if (feof(input))
|
||||
Error ("Error: unexpected end of file");
|
||||
|
||||
fread(&tshort, sizeof(tshort), 1, input);
|
||||
bytesread += sizeof(tshort);
|
||||
tris[i].v[j] = (int)tshort;
|
||||
}
|
||||
}
|
||||
|
||||
if (vertsfound && trisfound)
|
||||
StoreAliasTriangles ();
|
||||
|
||||
return bytesread - startbytesread;
|
||||
}
|
||||
|
||||
|
||||
int ParseChunk (FILE *input)
|
||||
{
|
||||
#define BLOCK_SIZE 4096
|
||||
char temp[BLOCK_SIZE];
|
||||
unsigned short type;
|
||||
int i, length, w, t, retval;
|
||||
|
||||
level++;
|
||||
retval = 0;
|
||||
|
||||
// chunk type
|
||||
if (feof(input))
|
||||
Error ("Error: unexpected end of file");
|
||||
|
||||
fread(&type, sizeof(type), 1, input);
|
||||
bytesread += sizeof(type);
|
||||
|
||||
// chunk length
|
||||
if (feof(input))
|
||||
Error ("Error: unexpected end of file");
|
||||
|
||||
fread (&length, sizeof(length), 1, input);
|
||||
bytesread += sizeof(length);
|
||||
w = length - 6;
|
||||
|
||||
// process chunk if we care about it, otherwise skip it
|
||||
switch (type)
|
||||
{
|
||||
case TRI_VERTEXL:
|
||||
w -= ParseVertexL (input);
|
||||
goto ParseSubchunk;
|
||||
|
||||
case TRI_FACEL1:
|
||||
w -= ParseFaceL1 (input);
|
||||
goto ParseSubchunk;
|
||||
|
||||
case EDIT_OBJECT:
|
||||
// read the name
|
||||
i = 0;
|
||||
|
||||
do
|
||||
{
|
||||
if (feof(input))
|
||||
Error ("Error: unexpected end of file");
|
||||
|
||||
fread (&temp[i], 1, 1, input);
|
||||
i++;
|
||||
w--;
|
||||
bytesread++;
|
||||
} while (temp[i-1]);
|
||||
|
||||
case MAIN3DS:
|
||||
case OBJ_TRIMESH:
|
||||
case EDIT3DS:
|
||||
// parse through subchunks
|
||||
ParseSubchunk:
|
||||
while (w > 0)
|
||||
{
|
||||
w -= ParseChunk (input);
|
||||
}
|
||||
|
||||
retval = length;
|
||||
goto Done;
|
||||
|
||||
default:
|
||||
// skip other chunks
|
||||
while (w > 0)
|
||||
{
|
||||
t = w;
|
||||
|
||||
if (t > BLOCK_SIZE)
|
||||
t = BLOCK_SIZE;
|
||||
|
||||
if (feof(input))
|
||||
Error ("Error: unexpected end of file");
|
||||
|
||||
fread (&temp, t, 1, input);
|
||||
bytesread += t;
|
||||
|
||||
w -= t;
|
||||
}
|
||||
|
||||
retval = length;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
Done:
|
||||
level--;
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
void Load3DSTriangleList (char *filename, triangle_t **pptri, int *numtriangles)
|
||||
{
|
||||
FILE *input;
|
||||
short int tshort;
|
||||
|
||||
bytesread = 0;
|
||||
level = 0;
|
||||
numtris = 0;
|
||||
totaltris = 0;
|
||||
vertsfound = 0;
|
||||
trisfound = 0;
|
||||
|
||||
if ((input = fopen(filename, "rb")) == 0) {
|
||||
fprintf(stderr,"reader: could not open file '%s'\n", filename);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
fread(&tshort, sizeof(tshort), 1, input);
|
||||
|
||||
// should only be MAIN3DS, but some files seem to start with EDIT3DS, with
|
||||
// no MAIN3DS
|
||||
if ((tshort != MAIN3DS) && (tshort != EDIT3DS)) {
|
||||
fprintf(stderr,"File is not a 3DS file.\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// back to top of file so we can parse the first chunk descriptor
|
||||
fseek(input, 0, SEEK_SET);
|
||||
|
||||
ptri = malloc (MAXTRIANGLES * sizeof(triangle_t));
|
||||
|
||||
*pptri = ptri;
|
||||
|
||||
// parse through looking for the relevant chunk tree (MAIN3DS | EDIT3DS | EDIT_OBJECT |
|
||||
// OBJ_TRIMESH | {TRI_VERTEXL, TRI_FACEL1}) and skipping other chunks
|
||||
ParseChunk (input);
|
||||
|
||||
if (vertsfound || trisfound)
|
||||
Error ("Incomplete triangle set");
|
||||
|
||||
*numtriangles = totaltris;
|
||||
|
||||
fclose (input);
|
||||
}
|
||||
|
27
tools/quake2/extra/common/l3dslib.h
Normal file
27
tools/quake2/extra/common/l3dslib.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
//
|
||||
// l3dslib.h: header file for loading triangles from a 3DS triangle file
|
||||
//
|
||||
void Load3DSTriangleList (char *filename, triangle_t **pptri, int *numtriangles);
|
||||
|
824
tools/quake2/extra/common/lbmlib.c
Normal file
824
tools/quake2/extra/common/lbmlib.c
Normal file
|
@ -0,0 +1,824 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// lbmlib.c
|
||||
|
||||
#include "cmdlib.h"
|
||||
#include "lbmlib.h"
|
||||
|
||||
|
||||
|
||||
/*
|
||||
============================================================================
|
||||
|
||||
LBM STUFF
|
||||
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
|
||||
typedef unsigned char UBYTE;
|
||||
//conflicts with windows typedef short WORD;
|
||||
typedef unsigned short UWORD;
|
||||
typedef long LONG;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ms_none,
|
||||
ms_mask,
|
||||
ms_transcolor,
|
||||
ms_lasso
|
||||
} mask_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
cm_none,
|
||||
cm_rle1
|
||||
} compress_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UWORD w,h;
|
||||
short x,y;
|
||||
UBYTE nPlanes;
|
||||
UBYTE masking;
|
||||
UBYTE compression;
|
||||
UBYTE pad1;
|
||||
UWORD transparentColor;
|
||||
UBYTE xAspect,yAspect;
|
||||
short pageWidth,pageHeight;
|
||||
} bmhd_t;
|
||||
|
||||
extern bmhd_t bmhd; // will be in native byte order
|
||||
|
||||
|
||||
|
||||
#define FORMID ('F'+('O'<<8)+((int)'R'<<16)+((int)'M'<<24))
|
||||
#define ILBMID ('I'+('L'<<8)+((int)'B'<<16)+((int)'M'<<24))
|
||||
#define PBMID ('P'+('B'<<8)+((int)'M'<<16)+((int)' '<<24))
|
||||
#define BMHDID ('B'+('M'<<8)+((int)'H'<<16)+((int)'D'<<24))
|
||||
#define BODYID ('B'+('O'<<8)+((int)'D'<<16)+((int)'Y'<<24))
|
||||
#define CMAPID ('C'+('M'<<8)+((int)'A'<<16)+((int)'P'<<24))
|
||||
|
||||
|
||||
bmhd_t bmhd;
|
||||
|
||||
int Align (int l)
|
||||
{
|
||||
if (l&1)
|
||||
return l+1;
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
LBMRLEdecompress
|
||||
|
||||
Source must be evenly aligned!
|
||||
================
|
||||
*/
|
||||
byte *LBMRLEDecompress (byte *source,byte *unpacked, int bpwidth)
|
||||
{
|
||||
int count;
|
||||
byte b,rept;
|
||||
|
||||
count = 0;
|
||||
|
||||
do
|
||||
{
|
||||
rept = *source++;
|
||||
|
||||
if (rept > 0x80)
|
||||
{
|
||||
rept = (rept^0xff)+2;
|
||||
b = *source++;
|
||||
memset(unpacked,b,rept);
|
||||
unpacked += rept;
|
||||
}
|
||||
else if (rept < 0x80)
|
||||
{
|
||||
rept++;
|
||||
memcpy(unpacked,source,rept);
|
||||
unpacked += rept;
|
||||
source += rept;
|
||||
}
|
||||
else
|
||||
rept = 0; // rept of 0x80 is NOP
|
||||
|
||||
count += rept;
|
||||
|
||||
} while (count<bpwidth);
|
||||
|
||||
if (count>bpwidth)
|
||||
Error ("Decompression exceeded width!\n");
|
||||
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
LoadLBM
|
||||
=================
|
||||
*/
|
||||
void LoadLBM (char *filename, byte **picture, byte **palette)
|
||||
{
|
||||
byte *LBMbuffer, *picbuffer, *cmapbuffer;
|
||||
int y;
|
||||
byte *LBM_P, *LBMEND_P;
|
||||
byte *pic_p;
|
||||
byte *body_p;
|
||||
|
||||
int formtype,formlength;
|
||||
int chunktype,chunklength;
|
||||
|
||||
// qiet compiler warnings
|
||||
picbuffer = NULL;
|
||||
cmapbuffer = NULL;
|
||||
|
||||
//
|
||||
// load the LBM
|
||||
//
|
||||
LoadFile (filename, (void **)&LBMbuffer);
|
||||
|
||||
//
|
||||
// parse the LBM header
|
||||
//
|
||||
LBM_P = LBMbuffer;
|
||||
if ( *(int *)LBMbuffer != LittleLong(FORMID) )
|
||||
Error ("No FORM ID at start of file!\n");
|
||||
|
||||
LBM_P += 4;
|
||||
formlength = BigLong( *(int *)LBM_P );
|
||||
LBM_P += 4;
|
||||
LBMEND_P = LBM_P + Align(formlength);
|
||||
|
||||
formtype = LittleLong(*(int *)LBM_P);
|
||||
|
||||
if (formtype != ILBMID && formtype != PBMID)
|
||||
Error ("Unrecognized form type: %c%c%c%c\n", formtype&0xff
|
||||
,(formtype>>8)&0xff,(formtype>>16)&0xff,(formtype>>24)&0xff);
|
||||
|
||||
LBM_P += 4;
|
||||
|
||||
//
|
||||
// parse chunks
|
||||
//
|
||||
|
||||
while (LBM_P < LBMEND_P)
|
||||
{
|
||||
chunktype = LBM_P[0] + (LBM_P[1]<<8) + (LBM_P[2]<<16) + (LBM_P[3]<<24);
|
||||
LBM_P += 4;
|
||||
chunklength = LBM_P[3] + (LBM_P[2]<<8) + (LBM_P[1]<<16) + (LBM_P[0]<<24);
|
||||
LBM_P += 4;
|
||||
|
||||
switch ( chunktype )
|
||||
{
|
||||
case BMHDID:
|
||||
memcpy (&bmhd,LBM_P,sizeof(bmhd));
|
||||
bmhd.w = BigShort(bmhd.w);
|
||||
bmhd.h = BigShort(bmhd.h);
|
||||
bmhd.x = BigShort(bmhd.x);
|
||||
bmhd.y = BigShort(bmhd.y);
|
||||
bmhd.pageWidth = BigShort(bmhd.pageWidth);
|
||||
bmhd.pageHeight = BigShort(bmhd.pageHeight);
|
||||
break;
|
||||
|
||||
case CMAPID:
|
||||
cmapbuffer = malloc (768);
|
||||
memset (cmapbuffer, 0, 768);
|
||||
memcpy (cmapbuffer, LBM_P, chunklength);
|
||||
break;
|
||||
|
||||
case BODYID:
|
||||
body_p = LBM_P;
|
||||
|
||||
pic_p = picbuffer = malloc (bmhd.w*bmhd.h);
|
||||
if (formtype == PBMID)
|
||||
{
|
||||
//
|
||||
// unpack PBM
|
||||
//
|
||||
for (y=0 ; y<bmhd.h ; y++, pic_p += bmhd.w)
|
||||
{
|
||||
if (bmhd.compression == cm_rle1)
|
||||
body_p = LBMRLEDecompress ((byte *)body_p
|
||||
, pic_p , bmhd.w);
|
||||
else if (bmhd.compression == cm_none)
|
||||
{
|
||||
memcpy (pic_p,body_p,bmhd.w);
|
||||
body_p += Align(bmhd.w);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// unpack ILBM
|
||||
//
|
||||
Error ("%s is an interlaced LBM, not packed", filename);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
LBM_P += Align(chunklength);
|
||||
}
|
||||
|
||||
free (LBMbuffer);
|
||||
|
||||
*picture = picbuffer;
|
||||
|
||||
if (palette)
|
||||
*palette = cmapbuffer;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============================================================================
|
||||
|
||||
WRITE LBM
|
||||
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
==============
|
||||
WriteLBMfile
|
||||
==============
|
||||
*/
|
||||
void WriteLBMfile (char *filename, byte *data,
|
||||
int width, int height, byte *palette)
|
||||
{
|
||||
byte *lbm, *lbmptr;
|
||||
int *formlength, *bmhdlength, *cmaplength, *bodylength;
|
||||
int length;
|
||||
bmhd_t basebmhd;
|
||||
|
||||
lbm = lbmptr = malloc (width*height+1000);
|
||||
|
||||
//
|
||||
// start FORM
|
||||
//
|
||||
*lbmptr++ = 'F';
|
||||
*lbmptr++ = 'O';
|
||||
*lbmptr++ = 'R';
|
||||
*lbmptr++ = 'M';
|
||||
|
||||
formlength = (int*)lbmptr;
|
||||
lbmptr+=4; // leave space for length
|
||||
|
||||
*lbmptr++ = 'P';
|
||||
*lbmptr++ = 'B';
|
||||
*lbmptr++ = 'M';
|
||||
*lbmptr++ = ' ';
|
||||
|
||||
//
|
||||
// write BMHD
|
||||
//
|
||||
*lbmptr++ = 'B';
|
||||
*lbmptr++ = 'M';
|
||||
*lbmptr++ = 'H';
|
||||
*lbmptr++ = 'D';
|
||||
|
||||
bmhdlength = (int *)lbmptr;
|
||||
lbmptr+=4; // leave space for length
|
||||
|
||||
memset (&basebmhd,0,sizeof(basebmhd));
|
||||
basebmhd.w = BigShort((short)width);
|
||||
basebmhd.h = BigShort((short)height);
|
||||
basebmhd.nPlanes = BigShort(8);
|
||||
basebmhd.xAspect = BigShort(5);
|
||||
basebmhd.yAspect = BigShort(6);
|
||||
basebmhd.pageWidth = BigShort((short)width);
|
||||
basebmhd.pageHeight = BigShort((short)height);
|
||||
|
||||
memcpy (lbmptr,&basebmhd,sizeof(basebmhd));
|
||||
lbmptr += sizeof(basebmhd);
|
||||
|
||||
length = lbmptr-(byte *)bmhdlength-4;
|
||||
*bmhdlength = BigLong(length);
|
||||
if (length&1)
|
||||
*lbmptr++ = 0; // pad chunk to even offset
|
||||
|
||||
//
|
||||
// write CMAP
|
||||
//
|
||||
*lbmptr++ = 'C';
|
||||
*lbmptr++ = 'M';
|
||||
*lbmptr++ = 'A';
|
||||
*lbmptr++ = 'P';
|
||||
|
||||
cmaplength = (int *)lbmptr;
|
||||
lbmptr+=4; // leave space for length
|
||||
|
||||
memcpy (lbmptr,palette,768);
|
||||
lbmptr += 768;
|
||||
|
||||
length = lbmptr-(byte *)cmaplength-4;
|
||||
*cmaplength = BigLong(length);
|
||||
if (length&1)
|
||||
*lbmptr++ = 0; // pad chunk to even offset
|
||||
|
||||
//
|
||||
// write BODY
|
||||
//
|
||||
*lbmptr++ = 'B';
|
||||
*lbmptr++ = 'O';
|
||||
*lbmptr++ = 'D';
|
||||
*lbmptr++ = 'Y';
|
||||
|
||||
bodylength = (int *)lbmptr;
|
||||
lbmptr+=4; // leave space for length
|
||||
|
||||
memcpy (lbmptr,data,width*height);
|
||||
lbmptr += width*height;
|
||||
|
||||
length = lbmptr-(byte *)bodylength-4;
|
||||
*bodylength = BigLong(length);
|
||||
if (length&1)
|
||||
*lbmptr++ = 0; // pad chunk to even offset
|
||||
|
||||
//
|
||||
// done
|
||||
//
|
||||
length = lbmptr-(byte *)formlength-4;
|
||||
*formlength = BigLong(length);
|
||||
if (length&1)
|
||||
*lbmptr++ = 0; // pad chunk to even offset
|
||||
|
||||
//
|
||||
// write output file
|
||||
//
|
||||
SaveFile (filename, lbm, lbmptr-lbm);
|
||||
free (lbm);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============================================================================
|
||||
|
||||
LOAD PCX
|
||||
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char manufacturer;
|
||||
char version;
|
||||
char encoding;
|
||||
char bits_per_pixel;
|
||||
unsigned short xmin,ymin,xmax,ymax;
|
||||
unsigned short hres,vres;
|
||||
unsigned char palette[48];
|
||||
char reserved;
|
||||
char color_planes;
|
||||
unsigned short bytes_per_line;
|
||||
unsigned short palette_type;
|
||||
char filler[58];
|
||||
unsigned char data; // unbounded
|
||||
} pcx_t;
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
LoadPCX
|
||||
==============
|
||||
*/
|
||||
void LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height)
|
||||
{
|
||||
byte *raw;
|
||||
pcx_t *pcx;
|
||||
int x, y;
|
||||
int len;
|
||||
int dataByte, runLength;
|
||||
byte *out, *pix;
|
||||
|
||||
//
|
||||
// load the file
|
||||
//
|
||||
len = LoadFile (filename, (void **)&raw);
|
||||
|
||||
//
|
||||
// parse the PCX file
|
||||
//
|
||||
pcx = (pcx_t *)raw;
|
||||
raw = &pcx->data;
|
||||
|
||||
pcx->xmin = LittleShort(pcx->xmin);
|
||||
pcx->ymin = LittleShort(pcx->ymin);
|
||||
pcx->xmax = LittleShort(pcx->xmax);
|
||||
pcx->ymax = LittleShort(pcx->ymax);
|
||||
pcx->hres = LittleShort(pcx->hres);
|
||||
pcx->vres = LittleShort(pcx->vres);
|
||||
pcx->bytes_per_line = LittleShort(pcx->bytes_per_line);
|
||||
pcx->palette_type = LittleShort(pcx->palette_type);
|
||||
|
||||
if (pcx->manufacturer != 0x0a
|
||||
|| pcx->version != 5
|
||||
|| pcx->encoding != 1
|
||||
|| pcx->bits_per_pixel != 8
|
||||
|| pcx->xmax >= 640
|
||||
|| pcx->ymax >= 480)
|
||||
Error ("Bad pcx file %s", filename);
|
||||
|
||||
if (palette)
|
||||
{
|
||||
*palette = malloc(768);
|
||||
memcpy (*palette, (byte *)pcx + len - 768, 768);
|
||||
}
|
||||
|
||||
if (width)
|
||||
*width = pcx->xmax+1;
|
||||
if (height)
|
||||
*height = pcx->ymax+1;
|
||||
|
||||
if (!pic)
|
||||
return;
|
||||
|
||||
out = malloc ( (pcx->ymax+1) * (pcx->xmax+1) );
|
||||
if (!out)
|
||||
Error ("Skin_Cache: couldn't allocate");
|
||||
|
||||
*pic = out;
|
||||
|
||||
pix = out;
|
||||
|
||||
for (y=0 ; y<=pcx->ymax ; y++, pix += pcx->xmax+1)
|
||||
{
|
||||
for (x=0 ; x<=pcx->xmax ; )
|
||||
{
|
||||
dataByte = *raw++;
|
||||
|
||||
if((dataByte & 0xC0) == 0xC0)
|
||||
{
|
||||
runLength = dataByte & 0x3F;
|
||||
dataByte = *raw++;
|
||||
}
|
||||
else
|
||||
runLength = 1;
|
||||
|
||||
while(runLength-- > 0)
|
||||
pix[x++] = dataByte;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( raw - (byte *)pcx > len)
|
||||
Error ("PCX file %s was malformed", filename);
|
||||
|
||||
free (pcx);
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
WritePCXfile
|
||||
==============
|
||||
*/
|
||||
void WritePCXfile (char *filename, byte *data,
|
||||
int width, int height, byte *palette)
|
||||
{
|
||||
int i, j, length;
|
||||
pcx_t *pcx;
|
||||
byte *pack;
|
||||
|
||||
pcx = malloc (width*height*2+1000);
|
||||
memset (pcx, 0, sizeof(*pcx));
|
||||
|
||||
pcx->manufacturer = 0x0a; // PCX id
|
||||
pcx->version = 5; // 256 color
|
||||
pcx->encoding = 1; // uncompressed
|
||||
pcx->bits_per_pixel = 8; // 256 color
|
||||
pcx->xmin = 0;
|
||||
pcx->ymin = 0;
|
||||
pcx->xmax = LittleShort((short)(width-1));
|
||||
pcx->ymax = LittleShort((short)(height-1));
|
||||
pcx->hres = LittleShort((short)width);
|
||||
pcx->vres = LittleShort((short)height);
|
||||
pcx->color_planes = 1; // chunky image
|
||||
pcx->bytes_per_line = LittleShort((short)width);
|
||||
pcx->palette_type = LittleShort(2); // not a grey scale
|
||||
|
||||
// pack the image
|
||||
pack = &pcx->data;
|
||||
|
||||
for (i=0 ; i<height ; i++)
|
||||
{
|
||||
for (j=0 ; j<width ; j++)
|
||||
{
|
||||
if ( (*data & 0xc0) != 0xc0)
|
||||
*pack++ = *data++;
|
||||
else
|
||||
{
|
||||
*pack++ = 0xc1;
|
||||
*pack++ = *data++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// write the palette
|
||||
*pack++ = 0x0c; // palette ID byte
|
||||
for (i=0 ; i<768 ; i++)
|
||||
*pack++ = *palette++;
|
||||
|
||||
// write output file
|
||||
length = pack - (byte *)pcx;
|
||||
SaveFile (filename, pcx, length);
|
||||
|
||||
free (pcx);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============================================================================
|
||||
|
||||
LOAD IMAGE
|
||||
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
==============
|
||||
Load256Image
|
||||
|
||||
Will load either an lbm or pcx, depending on extension.
|
||||
Any of the return pointers can be NULL if you don't want them.
|
||||
==============
|
||||
*/
|
||||
void Load256Image (char *name, byte **pixels, byte **palette,
|
||||
int *width, int *height)
|
||||
{
|
||||
char ext[128];
|
||||
|
||||
ExtractFileExtension (name, ext);
|
||||
if (!Q_strcasecmp (ext, "lbm"))
|
||||
{
|
||||
LoadLBM (name, pixels, palette);
|
||||
if (width)
|
||||
*width = bmhd.w;
|
||||
if (height)
|
||||
*height = bmhd.h;
|
||||
}
|
||||
else if (!Q_strcasecmp (ext, "pcx"))
|
||||
{
|
||||
LoadPCX (name, pixels, palette, width, height);
|
||||
}
|
||||
else
|
||||
Error ("%s doesn't have a known image extension", name);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
Save256Image
|
||||
|
||||
Will save either an lbm or pcx, depending on extension.
|
||||
==============
|
||||
*/
|
||||
void Save256Image (char *name, byte *pixels, byte *palette,
|
||||
int width, int height)
|
||||
{
|
||||
char ext[128];
|
||||
|
||||
ExtractFileExtension (name, ext);
|
||||
if (!Q_strcasecmp (ext, "lbm"))
|
||||
{
|
||||
WriteLBMfile (name, pixels, width, height, palette);
|
||||
}
|
||||
else if (!Q_strcasecmp (ext, "pcx"))
|
||||
{
|
||||
WritePCXfile (name, pixels, width, height, palette);
|
||||
}
|
||||
else
|
||||
Error ("%s doesn't have a known image extension", name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
============================================================================
|
||||
|
||||
TARGA IMAGE
|
||||
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
typedef 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;
|
||||
} TargaHeader;
|
||||
|
||||
int fgetLittleShort (FILE *f)
|
||||
{
|
||||
byte b1, b2;
|
||||
|
||||
b1 = fgetc(f);
|
||||
b2 = fgetc(f);
|
||||
|
||||
return (short)(b1 + b2*256);
|
||||
}
|
||||
|
||||
int fgetLittleLong (FILE *f)
|
||||
{
|
||||
byte b1, b2, b3, b4;
|
||||
|
||||
b1 = fgetc(f);
|
||||
b2 = fgetc(f);
|
||||
b3 = fgetc(f);
|
||||
b4 = fgetc(f);
|
||||
|
||||
return b1 + (b2<<8) + (b3<<16) + (b4<<24);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
LoadTGA
|
||||
=============
|
||||
*/
|
||||
void LoadTGA (char *name, byte **pixels, int *width, int *height)
|
||||
{
|
||||
int columns, rows, numPixels;
|
||||
byte *pixbuf;
|
||||
int row, column;
|
||||
FILE *fin;
|
||||
byte *targa_rgba;
|
||||
TargaHeader targa_header;
|
||||
|
||||
fin = fopen (name, "rb");
|
||||
if (!fin)
|
||||
Error ("Couldn't read %s", name);
|
||||
|
||||
targa_header.id_length = fgetc(fin);
|
||||
targa_header.colormap_type = fgetc(fin);
|
||||
targa_header.image_type = fgetc(fin);
|
||||
|
||||
targa_header.colormap_index = fgetLittleShort(fin);
|
||||
targa_header.colormap_length = fgetLittleShort(fin);
|
||||
targa_header.colormap_size = fgetc(fin);
|
||||
targa_header.x_origin = fgetLittleShort(fin);
|
||||
targa_header.y_origin = fgetLittleShort(fin);
|
||||
targa_header.width = fgetLittleShort(fin);
|
||||
targa_header.height = fgetLittleShort(fin);
|
||||
targa_header.pixel_size = fgetc(fin);
|
||||
targa_header.attributes = fgetc(fin);
|
||||
|
||||
if (targa_header.image_type!=2
|
||||
&& targa_header.image_type!=10)
|
||||
Error ("LoadTGA: Only type 2 and 10 targa RGB images supported\n");
|
||||
|
||||
if (targa_header.colormap_type !=0
|
||||
|| (targa_header.pixel_size!=32 && targa_header.pixel_size!=24))
|
||||
Error ("Texture_LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");
|
||||
|
||||
columns = targa_header.width;
|
||||
rows = targa_header.height;
|
||||
numPixels = columns * rows;
|
||||
|
||||
if (width)
|
||||
*width = columns;
|
||||
if (height)
|
||||
*height = rows;
|
||||
targa_rgba = malloc(numPixels*4);
|
||||
*pixels = targa_rgba;
|
||||
|
||||
if (targa_header.id_length != 0)
|
||||
fseek(fin, targa_header.id_length, SEEK_CUR); // skip TARGA image comment
|
||||
|
||||
if (targa_header.image_type==2) { // Uncompressed, RGB images
|
||||
for(row=rows-1; row>=0; row--) {
|
||||
pixbuf = targa_rgba + row*columns*4;
|
||||
for(column=0; column<columns; column++) {
|
||||
unsigned char red,green,blue,alphabyte;
|
||||
switch (targa_header.pixel_size) {
|
||||
case 24:
|
||||
|
||||
blue = getc(fin);
|
||||
green = getc(fin);
|
||||
red = getc(fin);
|
||||
*pixbuf++ = red;
|
||||
*pixbuf++ = green;
|
||||
*pixbuf++ = blue;
|
||||
*pixbuf++ = 255;
|
||||
break;
|
||||
case 32:
|
||||
blue = getc(fin);
|
||||
green = getc(fin);
|
||||
red = getc(fin);
|
||||
alphabyte = getc(fin);
|
||||
*pixbuf++ = red;
|
||||
*pixbuf++ = green;
|
||||
*pixbuf++ = blue;
|
||||
*pixbuf++ = alphabyte;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (targa_header.image_type==10) { // Runlength encoded RGB images
|
||||
unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j;
|
||||
for(row=rows-1; row>=0; row--) {
|
||||
pixbuf = targa_rgba + row*columns*4;
|
||||
for(column=0; column<columns; ) {
|
||||
packetHeader=getc(fin);
|
||||
packetSize = 1 + (packetHeader & 0x7f);
|
||||
if (packetHeader & 0x80) { // run-length packet
|
||||
switch (targa_header.pixel_size) {
|
||||
case 24:
|
||||
blue = getc(fin);
|
||||
green = getc(fin);
|
||||
red = getc(fin);
|
||||
alphabyte = 255;
|
||||
break;
|
||||
case 32:
|
||||
blue = getc(fin);
|
||||
green = getc(fin);
|
||||
red = getc(fin);
|
||||
alphabyte = getc(fin);
|
||||
break;
|
||||
}
|
||||
|
||||
for(j=0;j<packetSize;j++) {
|
||||
*pixbuf++=red;
|
||||
*pixbuf++=green;
|
||||
*pixbuf++=blue;
|
||||
*pixbuf++=alphabyte;
|
||||
column++;
|
||||
if (column==columns) { // run spans across rows
|
||||
column=0;
|
||||
if (row>0)
|
||||
row--;
|
||||
else
|
||||
goto breakOut;
|
||||
pixbuf = targa_rgba + row*columns*4;
|
||||
}
|
||||
}
|
||||
}
|
||||
else { // non run-length packet
|
||||
for(j=0;j<packetSize;j++) {
|
||||
switch (targa_header.pixel_size) {
|
||||
case 24:
|
||||
blue = getc(fin);
|
||||
green = getc(fin);
|
||||
red = getc(fin);
|
||||
*pixbuf++ = red;
|
||||
*pixbuf++ = green;
|
||||
*pixbuf++ = blue;
|
||||
*pixbuf++ = 255;
|
||||
break;
|
||||
case 32:
|
||||
blue = getc(fin);
|
||||
green = getc(fin);
|
||||
red = getc(fin);
|
||||
alphabyte = getc(fin);
|
||||
*pixbuf++ = red;
|
||||
*pixbuf++ = green;
|
||||
*pixbuf++ = blue;
|
||||
*pixbuf++ = alphabyte;
|
||||
break;
|
||||
}
|
||||
column++;
|
||||
if (column==columns) { // pixel packet run spans across rows
|
||||
column=0;
|
||||
if (row>0)
|
||||
row--;
|
||||
else
|
||||
goto breakOut;
|
||||
pixbuf = targa_rgba + row*columns*4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
breakOut:;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fin);
|
||||
}
|
40
tools/quake2/extra/common/lbmlib.h
Normal file
40
tools/quake2/extra/common/lbmlib.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// piclib.h
|
||||
|
||||
|
||||
void LoadLBM (char *filename, byte **picture, byte **palette);
|
||||
void WriteLBMfile (char *filename, byte *data, int width, int height
|
||||
, byte *palette);
|
||||
void LoadPCX (char *filename, byte **picture, byte **palette, int *width, int *height);
|
||||
void WritePCXfile (char *filename, byte *data, int width, int height
|
||||
, byte *palette);
|
||||
|
||||
// loads / saves either lbm or pcx, depending on extension
|
||||
void Load256Image (char *name, byte **pixels, byte **palette,
|
||||
int *width, int *height);
|
||||
void Save256Image (char *name, byte *pixels, byte *palette,
|
||||
int width, int height);
|
||||
|
||||
|
||||
void LoadTGA (char *filename, byte **pixels, int *width, int *height);
|
174
tools/quake2/extra/common/mathlib.c
Normal file
174
tools/quake2/extra/common/mathlib.c
Normal file
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// mathlib.c -- math primitives
|
||||
|
||||
#include "cmdlib.h"
|
||||
#include "mathlib.h"
|
||||
|
||||
vec3_t vec3_origin = {0,0,0};
|
||||
|
||||
|
||||
double VectorLength(vec3_t v)
|
||||
{
|
||||
int i;
|
||||
double length;
|
||||
|
||||
length = 0;
|
||||
for (i=0 ; i< 3 ; i++)
|
||||
length += v[i]*v[i];
|
||||
length = sqrt (length); // FIXME
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
qboolean VectorCompare (vec3_t v1, vec3_t v2)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
if (fabs(v1[i]-v2[i]) > EQUAL_EPSILON)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
vec_t Q_rint (vec_t in)
|
||||
{
|
||||
return floor (in + 0.5);
|
||||
}
|
||||
|
||||
void VectorMA (vec3_t va, double scale, vec3_t vb, vec3_t vc)
|
||||
{
|
||||
vc[0] = va[0] + scale*vb[0];
|
||||
vc[1] = va[1] + scale*vb[1];
|
||||
vc[2] = va[2] + scale*vb[2];
|
||||
}
|
||||
|
||||
void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross)
|
||||
{
|
||||
cross[0] = v1[1]*v2[2] - v1[2]*v2[1];
|
||||
cross[1] = v1[2]*v2[0] - v1[0]*v2[2];
|
||||
cross[2] = v1[0]*v2[1] - v1[1]*v2[0];
|
||||
}
|
||||
|
||||
vec_t _DotProduct (vec3_t v1, vec3_t v2)
|
||||
{
|
||||
return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
|
||||
}
|
||||
|
||||
void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out)
|
||||
{
|
||||
out[0] = va[0]-vb[0];
|
||||
out[1] = va[1]-vb[1];
|
||||
out[2] = va[2]-vb[2];
|
||||
}
|
||||
|
||||
void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out)
|
||||
{
|
||||
out[0] = va[0]+vb[0];
|
||||
out[1] = va[1]+vb[1];
|
||||
out[2] = va[2]+vb[2];
|
||||
}
|
||||
|
||||
void _VectorCopy (vec3_t in, vec3_t out)
|
||||
{
|
||||
out[0] = in[0];
|
||||
out[1] = in[1];
|
||||
out[2] = in[2];
|
||||
}
|
||||
|
||||
void _VectorScale (vec3_t v, vec_t scale, vec3_t out)
|
||||
{
|
||||
out[0] = v[0] * scale;
|
||||
out[1] = v[1] * scale;
|
||||
out[2] = v[2] * scale;
|
||||
}
|
||||
|
||||
vec_t VectorNormalize (vec3_t in, vec3_t out)
|
||||
{
|
||||
vec_t length, ilength;
|
||||
|
||||
length = sqrt (in[0]*in[0] + in[1]*in[1] + in[2]*in[2]);
|
||||
if (length == 0)
|
||||
{
|
||||
VectorClear (out);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ilength = 1.0/length;
|
||||
out[0] = in[0]*ilength;
|
||||
out[1] = in[1]*ilength;
|
||||
out[2] = in[2]*ilength;
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
vec_t ColorNormalize (vec3_t in, vec3_t out)
|
||||
{
|
||||
float max, scale;
|
||||
|
||||
max = in[0];
|
||||
if (in[1] > max)
|
||||
max = in[1];
|
||||
if (in[2] > max)
|
||||
max = in[2];
|
||||
|
||||
if (max == 0)
|
||||
return 0;
|
||||
|
||||
scale = 1.0 / max;
|
||||
|
||||
VectorScale (in, scale, out);
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void VectorInverse (vec3_t v)
|
||||
{
|
||||
v[0] = -v[0];
|
||||
v[1] = -v[1];
|
||||
v[2] = -v[2];
|
||||
}
|
||||
|
||||
void ClearBounds (vec3_t mins, vec3_t maxs)
|
||||
{
|
||||
mins[0] = mins[1] = mins[2] = 99999;
|
||||
maxs[0] = maxs[1] = maxs[2] = -99999;
|
||||
}
|
||||
|
||||
void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs)
|
||||
{
|
||||
int i;
|
||||
vec_t val;
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
val = v[i];
|
||||
if (val < mins[i])
|
||||
mins[i] = val;
|
||||
if (val > maxs[i])
|
||||
maxs[i] = val;
|
||||
}
|
||||
}
|
77
tools/quake2/extra/common/mathlib.h
Normal file
77
tools/quake2/extra/common/mathlib.h
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __MATHLIB__
|
||||
#define __MATHLIB__
|
||||
|
||||
// mathlib.h
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#ifdef DOUBLEVEC_T
|
||||
typedef double vec_t;
|
||||
#else
|
||||
typedef float vec_t;
|
||||
#endif
|
||||
typedef vec_t vec3_t[3];
|
||||
|
||||
#define SIDE_FRONT 0
|
||||
#define SIDE_ON 2
|
||||
#define SIDE_BACK 1
|
||||
#define SIDE_CROSS -2
|
||||
|
||||
#define Q_PI 3.14159265358979323846
|
||||
|
||||
extern vec3_t vec3_origin;
|
||||
|
||||
#define EQUAL_EPSILON 0.001
|
||||
|
||||
qboolean VectorCompare (vec3_t v1, vec3_t v2);
|
||||
|
||||
#define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2])
|
||||
#define VectorSubtract(a,b,c) {c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];}
|
||||
#define VectorAdd(a,b,c) {c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2];}
|
||||
#define VectorCopy(a,b) {b[0]=a[0];b[1]=a[1];b[2]=a[2];}
|
||||
#define VectorScale(a,b,c) {c[0]=b*a[0];c[1]=b*a[1];c[2]=b*a[2];}
|
||||
#define VectorClear(x) {x[0] = x[1] = x[2] = 0;}
|
||||
#define VectorNegate(x) {x[0]=-x[0];x[1]=-x[1];x[2]=-x[2];}
|
||||
|
||||
vec_t Q_rint (vec_t in);
|
||||
vec_t _DotProduct (vec3_t v1, vec3_t v2);
|
||||
void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out);
|
||||
void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out);
|
||||
void _VectorCopy (vec3_t in, vec3_t out);
|
||||
void _VectorScale (vec3_t v, vec_t scale, vec3_t out);
|
||||
|
||||
double VectorLength(vec3_t v);
|
||||
|
||||
void VectorMA (vec3_t va, double scale, vec3_t vb, vec3_t vc);
|
||||
|
||||
void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross);
|
||||
vec_t VectorNormalize (vec3_t in, vec3_t out);
|
||||
vec_t ColorNormalize (vec3_t in, vec3_t out);
|
||||
void VectorInverse (vec3_t v);
|
||||
|
||||
void ClearBounds (vec3_t mins, vec3_t maxs);
|
||||
void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs);
|
||||
|
||||
#endif
|
224
tools/quake2/extra/common/mdfour.c
Normal file
224
tools/quake2/extra/common/mdfour.c
Normal file
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
mdfour.c
|
||||
|
||||
An implementation of MD4 designed for use in the samba SMB
|
||||
authentication protocol
|
||||
|
||||
Copyright (C) 1997-1998 Andrew Tridgell
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program; if not, write to:
|
||||
|
||||
Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA
|
||||
|
||||
$Id: mdfour.c,v 1.1 2002/08/23 22:03:27 abster Exp $
|
||||
*/
|
||||
|
||||
#include <string.h> /* XoXus: needed for memset call */
|
||||
#include "mdfour.h"
|
||||
|
||||
/* NOTE: This code makes no attempt to be fast!
|
||||
|
||||
It assumes that a int is at least 32 bits long
|
||||
*/
|
||||
|
||||
static struct mdfour *m;
|
||||
|
||||
#define F(X,Y,Z) (((X)&(Y)) | ((~(X))&(Z)))
|
||||
#define G(X,Y,Z) (((X)&(Y)) | ((X)&(Z)) | ((Y)&(Z)))
|
||||
#define H(X,Y,Z) ((X)^(Y)^(Z))
|
||||
#ifdef LARGE_INT32
|
||||
#define lshift(x,s) ((((x)<<(s))&0xFFFFFFFF) | (((x)>>(32-(s)))&0xFFFFFFFF))
|
||||
#else
|
||||
#define lshift(x,s) (((x)<<(s)) | ((x)>>(32-(s))))
|
||||
#endif
|
||||
|
||||
#define ROUND1(a,b,c,d,k,s) a = lshift(a + F(b,c,d) + X[k], s)
|
||||
#define ROUND2(a,b,c,d,k,s) a = lshift(a + G(b,c,d) + X[k] + 0x5A827999,s)
|
||||
#define ROUND3(a,b,c,d,k,s) a = lshift(a + H(b,c,d) + X[k] + 0x6ED9EBA1,s)
|
||||
|
||||
/* this applies md4 to 64 byte chunks */
|
||||
static void mdfour64(uint32 *M)
|
||||
{
|
||||
int j;
|
||||
uint32 AA, BB, CC, DD;
|
||||
uint32 X[16];
|
||||
uint32 A,B,C,D;
|
||||
|
||||
for (j=0;j<16;j++)
|
||||
X[j] = M[j];
|
||||
|
||||
A = m->A; B = m->B; C = m->C; D = m->D;
|
||||
AA = A; BB = B; CC = C; DD = D;
|
||||
|
||||
ROUND1(A,B,C,D, 0, 3); ROUND1(D,A,B,C, 1, 7);
|
||||
ROUND1(C,D,A,B, 2, 11); ROUND1(B,C,D,A, 3, 19);
|
||||
ROUND1(A,B,C,D, 4, 3); ROUND1(D,A,B,C, 5, 7);
|
||||
ROUND1(C,D,A,B, 6, 11); ROUND1(B,C,D,A, 7, 19);
|
||||
ROUND1(A,B,C,D, 8, 3); ROUND1(D,A,B,C, 9, 7);
|
||||
ROUND1(C,D,A,B, 10, 11); ROUND1(B,C,D,A, 11, 19);
|
||||
ROUND1(A,B,C,D, 12, 3); ROUND1(D,A,B,C, 13, 7);
|
||||
ROUND1(C,D,A,B, 14, 11); ROUND1(B,C,D,A, 15, 19);
|
||||
|
||||
ROUND2(A,B,C,D, 0, 3); ROUND2(D,A,B,C, 4, 5);
|
||||
ROUND2(C,D,A,B, 8, 9); ROUND2(B,C,D,A, 12, 13);
|
||||
ROUND2(A,B,C,D, 1, 3); ROUND2(D,A,B,C, 5, 5);
|
||||
ROUND2(C,D,A,B, 9, 9); ROUND2(B,C,D,A, 13, 13);
|
||||
ROUND2(A,B,C,D, 2, 3); ROUND2(D,A,B,C, 6, 5);
|
||||
ROUND2(C,D,A,B, 10, 9); ROUND2(B,C,D,A, 14, 13);
|
||||
ROUND2(A,B,C,D, 3, 3); ROUND2(D,A,B,C, 7, 5);
|
||||
ROUND2(C,D,A,B, 11, 9); ROUND2(B,C,D,A, 15, 13);
|
||||
|
||||
ROUND3(A,B,C,D, 0, 3); ROUND3(D,A,B,C, 8, 9);
|
||||
ROUND3(C,D,A,B, 4, 11); ROUND3(B,C,D,A, 12, 15);
|
||||
ROUND3(A,B,C,D, 2, 3); ROUND3(D,A,B,C, 10, 9);
|
||||
ROUND3(C,D,A,B, 6, 11); ROUND3(B,C,D,A, 14, 15);
|
||||
ROUND3(A,B,C,D, 1, 3); ROUND3(D,A,B,C, 9, 9);
|
||||
ROUND3(C,D,A,B, 5, 11); ROUND3(B,C,D,A, 13, 15);
|
||||
ROUND3(A,B,C,D, 3, 3); ROUND3(D,A,B,C, 11, 9);
|
||||
ROUND3(C,D,A,B, 7, 11); ROUND3(B,C,D,A, 15, 15);
|
||||
|
||||
A += AA; B += BB; C += CC; D += DD;
|
||||
|
||||
#ifdef LARGE_INT32
|
||||
A &= 0xFFFFFFFF; B &= 0xFFFFFFFF;
|
||||
C &= 0xFFFFFFFF; D &= 0xFFFFFFFF;
|
||||
#endif
|
||||
|
||||
for (j=0;j<16;j++)
|
||||
X[j] = 0;
|
||||
|
||||
m->A = A; m->B = B; m->C = C; m->D = D;
|
||||
}
|
||||
|
||||
static void copy64(uint32 *M, unsigned char *in)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0;i<16;i++)
|
||||
M[i] = (in[i*4+3]<<24) | (in[i*4+2]<<16) |
|
||||
(in[i*4+1]<<8) | (in[i*4+0]<<0);
|
||||
}
|
||||
|
||||
static void copy4(unsigned char *out,uint32 x)
|
||||
{
|
||||
out[0] = x&0xFF;
|
||||
out[1] = (x>>8)&0xFF;
|
||||
out[2] = (x>>16)&0xFF;
|
||||
out[3] = (x>>24)&0xFF;
|
||||
}
|
||||
|
||||
void mdfour_begin(struct mdfour *md)
|
||||
{
|
||||
md->A = 0x67452301;
|
||||
md->B = 0xefcdab89;
|
||||
md->C = 0x98badcfe;
|
||||
md->D = 0x10325476;
|
||||
md->totalN = 0;
|
||||
}
|
||||
|
||||
|
||||
static void mdfour_tail(unsigned char *in, int n)
|
||||
{
|
||||
unsigned char buf[128];
|
||||
uint32 M[16];
|
||||
uint32 b;
|
||||
|
||||
m->totalN += n;
|
||||
|
||||
b = m->totalN * 8;
|
||||
|
||||
memset(buf, 0, 128);
|
||||
if (n) memcpy(buf, in, n);
|
||||
buf[n] = 0x80;
|
||||
|
||||
if (n <= 55) {
|
||||
copy4(buf+56, b);
|
||||
copy64(M, buf);
|
||||
mdfour64(M);
|
||||
} else {
|
||||
copy4(buf+120, b);
|
||||
copy64(M, buf);
|
||||
mdfour64(M);
|
||||
copy64(M, buf+64);
|
||||
mdfour64(M);
|
||||
}
|
||||
}
|
||||
|
||||
void mdfour_update(struct mdfour *md, unsigned char *in, int n)
|
||||
{
|
||||
uint32 M[16];
|
||||
|
||||
if (n == 0) mdfour_tail(in, n);
|
||||
|
||||
m = md;
|
||||
|
||||
while (n >= 64) {
|
||||
copy64(M, in);
|
||||
mdfour64(M);
|
||||
in += 64;
|
||||
n -= 64;
|
||||
m->totalN += 64;
|
||||
}
|
||||
|
||||
mdfour_tail(in, n);
|
||||
}
|
||||
|
||||
|
||||
void mdfour_result(struct mdfour *md, unsigned char *out)
|
||||
{
|
||||
m = md;
|
||||
|
||||
copy4(out, m->A);
|
||||
copy4(out+4, m->B);
|
||||
copy4(out+8, m->C);
|
||||
copy4(out+12, m->D);
|
||||
}
|
||||
|
||||
|
||||
void mdfour(unsigned char *out, unsigned char *in, int n)
|
||||
{
|
||||
struct mdfour md;
|
||||
mdfour_begin(&md);
|
||||
mdfour_update(&md, in, n);
|
||||
mdfour_result(&md, out);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// MD4-based checksum utility functions
|
||||
//
|
||||
// Copyright (C) 2000 Jeff Teunissen <d2deek@pmail.net>
|
||||
//
|
||||
// Author: Jeff Teunissen <d2deek@pmail.net>
|
||||
// Date: 01 Jan 2000
|
||||
|
||||
unsigned Com_BlockChecksum (void *buffer, int length)
|
||||
{
|
||||
int digest[4];
|
||||
unsigned val;
|
||||
|
||||
mdfour ( (unsigned char *) digest, (unsigned char *) buffer, length );
|
||||
|
||||
val = digest[0] ^ digest[1] ^ digest[2] ^ digest[3];
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void Com_BlockFullChecksum (void *buffer, int len, unsigned char *outbuf)
|
||||
{
|
||||
mdfour ( outbuf, (unsigned char *) buffer, len );
|
||||
}
|
||||
|
54
tools/quake2/extra/common/mdfour.h
Normal file
54
tools/quake2/extra/common/mdfour.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
mdfour.h
|
||||
|
||||
an implementation of MD4 designed for use in the SMB authentication
|
||||
protocol
|
||||
|
||||
Copyright (C) Andrew Tridgell 1997-1998
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program; if not, write to:
|
||||
|
||||
Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef _MDFOUR_H
|
||||
#define _MDFOUR_H
|
||||
|
||||
#ifndef int32
|
||||
#define int32 int
|
||||
#endif
|
||||
|
||||
#if SIZEOF_INT > 4
|
||||
#define LARGE_INT32
|
||||
#endif
|
||||
|
||||
#ifndef uint32
|
||||
#define uint32 unsigned int32
|
||||
#endif
|
||||
|
||||
struct mdfour {
|
||||
uint32 A, B, C, D;
|
||||
uint32 totalN;
|
||||
};
|
||||
|
||||
void mdfour_begin(struct mdfour *md); // old: MD4Init
|
||||
void mdfour_update(struct mdfour *md, unsigned char *in, int n); //old: MD4Update
|
||||
void mdfour_result(struct mdfour *md, unsigned char *out); // old: MD4Final
|
||||
void mdfour(unsigned char *out, unsigned char *in, int n);
|
||||
|
||||
#endif // _MDFOUR_H
|
||||
|
642
tools/quake2/extra/common/polylib.c
Normal file
642
tools/quake2/extra/common/polylib.c
Normal file
|
@ -0,0 +1,642 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "cmdlib.h"
|
||||
#include "mathlib.h"
|
||||
#include "polylib.h"
|
||||
|
||||
|
||||
extern int numthreads;
|
||||
|
||||
// counters are only bumped when running single threaded,
|
||||
// because they are an awefull coherence problem
|
||||
int c_active_windings;
|
||||
int c_peak_windings;
|
||||
int c_winding_allocs;
|
||||
int c_winding_points;
|
||||
|
||||
#define BOGUS_RANGE 8192
|
||||
|
||||
void pw(winding_t *w)
|
||||
{
|
||||
int i;
|
||||
for (i=0 ; i<w->numpoints ; i++)
|
||||
printf ("(%5.1f, %5.1f, %5.1f)\n",w->p[i][0], w->p[i][1],w->p[i][2]);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
AllocWinding
|
||||
=============
|
||||
*/
|
||||
winding_t *AllocWinding (int points)
|
||||
{
|
||||
winding_t *w;
|
||||
int s;
|
||||
|
||||
if (numthreads == 1)
|
||||
{
|
||||
c_winding_allocs++;
|
||||
c_winding_points += points;
|
||||
c_active_windings++;
|
||||
if (c_active_windings > c_peak_windings)
|
||||
c_peak_windings = c_active_windings;
|
||||
}
|
||||
s = sizeof(vec_t)*3*points + sizeof(int);
|
||||
w = malloc (s);
|
||||
memset (w, 0, s);
|
||||
return w;
|
||||
}
|
||||
|
||||
void FreeWinding (winding_t *w)
|
||||
{
|
||||
if (*(unsigned *)w == 0xdeaddead)
|
||||
Error ("FreeWinding: freed a freed winding");
|
||||
*(unsigned *)w = 0xdeaddead;
|
||||
|
||||
if (numthreads == 1)
|
||||
c_active_windings--;
|
||||
free (w);
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
RemoveColinearPoints
|
||||
============
|
||||
*/
|
||||
int c_removed;
|
||||
|
||||
void RemoveColinearPoints (winding_t *w)
|
||||
{
|
||||
int i, j, k;
|
||||
vec3_t v1, v2;
|
||||
int nump;
|
||||
vec3_t p[MAX_POINTS_ON_WINDING];
|
||||
|
||||
nump = 0;
|
||||
for (i=0 ; i<w->numpoints ; i++)
|
||||
{
|
||||
j = (i+1)%w->numpoints;
|
||||
k = (i+w->numpoints-1)%w->numpoints;
|
||||
VectorSubtract (w->p[j], w->p[i], v1);
|
||||
VectorSubtract (w->p[i], w->p[k], v2);
|
||||
VectorNormalize(v1,v1);
|
||||
VectorNormalize(v2,v2);
|
||||
if (DotProduct(v1, v2) < 0.999)
|
||||
{
|
||||
VectorCopy (w->p[i], p[nump]);
|
||||
nump++;
|
||||
}
|
||||
}
|
||||
|
||||
if (nump == w->numpoints)
|
||||
return;
|
||||
|
||||
if (numthreads == 1)
|
||||
c_removed += w->numpoints - nump;
|
||||
w->numpoints = nump;
|
||||
memcpy (w->p, p, nump*sizeof(p[0]));
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
WindingPlane
|
||||
============
|
||||
*/
|
||||
void WindingPlane (winding_t *w, vec3_t normal, vec_t *dist)
|
||||
{
|
||||
vec3_t v1, v2;
|
||||
|
||||
VectorSubtract (w->p[1], w->p[0], v1);
|
||||
VectorSubtract (w->p[2], w->p[0], v2);
|
||||
CrossProduct (v2, v1, normal);
|
||||
VectorNormalize (normal, normal);
|
||||
*dist = DotProduct (w->p[0], normal);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
WindingArea
|
||||
=============
|
||||
*/
|
||||
vec_t WindingArea (winding_t *w)
|
||||
{
|
||||
int i;
|
||||
vec3_t d1, d2, cross;
|
||||
vec_t total;
|
||||
|
||||
total = 0;
|
||||
for (i=2 ; i<w->numpoints ; i++)
|
||||
{
|
||||
VectorSubtract (w->p[i-1], w->p[0], d1);
|
||||
VectorSubtract (w->p[i], w->p[0], d2);
|
||||
CrossProduct (d1, d2, cross);
|
||||
total += 0.5 * VectorLength ( cross );
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
void WindingBounds (winding_t *w, vec3_t mins, vec3_t maxs)
|
||||
{
|
||||
vec_t v;
|
||||
int i,j;
|
||||
|
||||
mins[0] = mins[1] = mins[2] = 99999;
|
||||
maxs[0] = maxs[1] = maxs[2] = -99999;
|
||||
|
||||
for (i=0 ; i<w->numpoints ; i++)
|
||||
{
|
||||
for (j=0 ; j<3 ; j++)
|
||||
{
|
||||
v = w->p[i][j];
|
||||
if (v < mins[j])
|
||||
mins[j] = v;
|
||||
if (v > maxs[j])
|
||||
maxs[j] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
WindingCenter
|
||||
=============
|
||||
*/
|
||||
void WindingCenter (winding_t *w, vec3_t center)
|
||||
{
|
||||
int i;
|
||||
float scale;
|
||||
|
||||
VectorCopy (vec3_origin, center);
|
||||
for (i=0 ; i<w->numpoints ; i++)
|
||||
VectorAdd (w->p[i], center, center);
|
||||
|
||||
scale = 1.0/w->numpoints;
|
||||
VectorScale (center, scale, center);
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
BaseWindingForPlane
|
||||
=================
|
||||
*/
|
||||
winding_t *BaseWindingForPlane (vec3_t normal, vec_t dist)
|
||||
{
|
||||
int i, x;
|
||||
vec_t max, v;
|
||||
vec3_t org, vright, vup;
|
||||
winding_t *w;
|
||||
|
||||
// find the major axis
|
||||
|
||||
max = -BOGUS_RANGE;
|
||||
x = -1;
|
||||
for (i=0 ; i<3; i++)
|
||||
{
|
||||
v = fabs(normal[i]);
|
||||
if (v > max)
|
||||
{
|
||||
x = i;
|
||||
max = v;
|
||||
}
|
||||
}
|
||||
if (x==-1)
|
||||
Error ("BaseWindingForPlane: no axis found");
|
||||
|
||||
VectorCopy (vec3_origin, vup);
|
||||
switch (x)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
vup[2] = 1;
|
||||
break;
|
||||
case 2:
|
||||
vup[0] = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
v = DotProduct (vup, normal);
|
||||
VectorMA (vup, -v, normal, vup);
|
||||
VectorNormalize (vup, vup);
|
||||
|
||||
VectorScale (normal, dist, org);
|
||||
|
||||
CrossProduct (vup, normal, vright);
|
||||
|
||||
VectorScale (vup, 8192, vup);
|
||||
VectorScale (vright, 8192, vright);
|
||||
|
||||
// project a really big axis aligned box onto the plane
|
||||
w = AllocWinding (4);
|
||||
|
||||
VectorSubtract (org, vright, w->p[0]);
|
||||
VectorAdd (w->p[0], vup, w->p[0]);
|
||||
|
||||
VectorAdd (org, vright, w->p[1]);
|
||||
VectorAdd (w->p[1], vup, w->p[1]);
|
||||
|
||||
VectorAdd (org, vright, w->p[2]);
|
||||
VectorSubtract (w->p[2], vup, w->p[2]);
|
||||
|
||||
VectorSubtract (org, vright, w->p[3]);
|
||||
VectorSubtract (w->p[3], vup, w->p[3]);
|
||||
|
||||
w->numpoints = 4;
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
CopyWinding
|
||||
==================
|
||||
*/
|
||||
winding_t *CopyWinding (winding_t *w)
|
||||
{
|
||||
int size;
|
||||
winding_t *c;
|
||||
|
||||
c = AllocWinding (w->numpoints);
|
||||
size = (int)((winding_t *)0)->p[w->numpoints];
|
||||
memcpy (c, w, size);
|
||||
return c;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
ReverseWinding
|
||||
==================
|
||||
*/
|
||||
winding_t *ReverseWinding (winding_t *w)
|
||||
{
|
||||
int i;
|
||||
winding_t *c;
|
||||
|
||||
c = AllocWinding (w->numpoints);
|
||||
for (i=0 ; i<w->numpoints ; i++)
|
||||
{
|
||||
VectorCopy (w->p[w->numpoints-1-i], c->p[i]);
|
||||
}
|
||||
c->numpoints = w->numpoints;
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
ClipWindingEpsilon
|
||||
=============
|
||||
*/
|
||||
void ClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist,
|
||||
vec_t epsilon, winding_t **front, winding_t **back)
|
||||
{
|
||||
vec_t dists[MAX_POINTS_ON_WINDING+4];
|
||||
int sides[MAX_POINTS_ON_WINDING+4];
|
||||
int counts[3];
|
||||
static vec_t dot; // VC 4.2 optimizer bug if not static
|
||||
int i, j;
|
||||
vec_t *p1, *p2;
|
||||
vec3_t mid;
|
||||
winding_t *f, *b;
|
||||
int maxpts;
|
||||
|
||||
counts[0] = counts[1] = counts[2] = 0;
|
||||
|
||||
// determine sides for each point
|
||||
for (i=0 ; i<in->numpoints ; i++)
|
||||
{
|
||||
dot = DotProduct (in->p[i], normal);
|
||||
dot -= dist;
|
||||
dists[i] = dot;
|
||||
if (dot > epsilon)
|
||||
sides[i] = SIDE_FRONT;
|
||||
else if (dot < -epsilon)
|
||||
sides[i] = SIDE_BACK;
|
||||
else
|
||||
{
|
||||
sides[i] = SIDE_ON;
|
||||
}
|
||||
counts[sides[i]]++;
|
||||
}
|
||||
sides[i] = sides[0];
|
||||
dists[i] = dists[0];
|
||||
|
||||
*front = *back = NULL;
|
||||
|
||||
if (!counts[0])
|
||||
{
|
||||
*back = CopyWinding (in);
|
||||
return;
|
||||
}
|
||||
if (!counts[1])
|
||||
{
|
||||
*front = CopyWinding (in);
|
||||
return;
|
||||
}
|
||||
|
||||
maxpts = in->numpoints+4; // cant use counts[0]+2 because
|
||||
// of fp grouping errors
|
||||
|
||||
*front = f = AllocWinding (maxpts);
|
||||
*back = b = AllocWinding (maxpts);
|
||||
|
||||
for (i=0 ; i<in->numpoints ; i++)
|
||||
{
|
||||
p1 = in->p[i];
|
||||
|
||||
if (sides[i] == SIDE_ON)
|
||||
{
|
||||
VectorCopy (p1, f->p[f->numpoints]);
|
||||
f->numpoints++;
|
||||
VectorCopy (p1, b->p[b->numpoints]);
|
||||
b->numpoints++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sides[i] == SIDE_FRONT)
|
||||
{
|
||||
VectorCopy (p1, f->p[f->numpoints]);
|
||||
f->numpoints++;
|
||||
}
|
||||
if (sides[i] == SIDE_BACK)
|
||||
{
|
||||
VectorCopy (p1, b->p[b->numpoints]);
|
||||
b->numpoints++;
|
||||
}
|
||||
|
||||
if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
|
||||
continue;
|
||||
|
||||
// generate a split point
|
||||
p2 = in->p[(i+1)%in->numpoints];
|
||||
|
||||
dot = dists[i] / (dists[i]-dists[i+1]);
|
||||
for (j=0 ; j<3 ; j++)
|
||||
{ // avoid round off error when possible
|
||||
if (normal[j] == 1)
|
||||
mid[j] = dist;
|
||||
else if (normal[j] == -1)
|
||||
mid[j] = -dist;
|
||||
else
|
||||
mid[j] = p1[j] + dot*(p2[j]-p1[j]);
|
||||
}
|
||||
|
||||
VectorCopy (mid, f->p[f->numpoints]);
|
||||
f->numpoints++;
|
||||
VectorCopy (mid, b->p[b->numpoints]);
|
||||
b->numpoints++;
|
||||
}
|
||||
|
||||
if (f->numpoints > maxpts || b->numpoints > maxpts)
|
||||
Error ("ClipWinding: points exceeded estimate");
|
||||
if (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING)
|
||||
Error ("ClipWinding: MAX_POINTS_ON_WINDING");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
ChopWindingInPlace
|
||||
=============
|
||||
*/
|
||||
void ChopWindingInPlace (winding_t **inout, vec3_t normal, vec_t dist, vec_t epsilon)
|
||||
{
|
||||
winding_t *in;
|
||||
vec_t dists[MAX_POINTS_ON_WINDING+4];
|
||||
int sides[MAX_POINTS_ON_WINDING+4];
|
||||
int counts[3];
|
||||
static vec_t dot; // VC 4.2 optimizer bug if not static
|
||||
int i, j;
|
||||
vec_t *p1, *p2;
|
||||
vec3_t mid;
|
||||
winding_t *f;
|
||||
int maxpts;
|
||||
|
||||
in = *inout;
|
||||
counts[0] = counts[1] = counts[2] = 0;
|
||||
|
||||
// determine sides for each point
|
||||
for (i=0 ; i<in->numpoints ; i++)
|
||||
{
|
||||
dot = DotProduct (in->p[i], normal);
|
||||
dot -= dist;
|
||||
dists[i] = dot;
|
||||
if (dot > epsilon)
|
||||
sides[i] = SIDE_FRONT;
|
||||
else if (dot < -epsilon)
|
||||
sides[i] = SIDE_BACK;
|
||||
else
|
||||
{
|
||||
sides[i] = SIDE_ON;
|
||||
}
|
||||
counts[sides[i]]++;
|
||||
}
|
||||
sides[i] = sides[0];
|
||||
dists[i] = dists[0];
|
||||
|
||||
if (!counts[0])
|
||||
{
|
||||
FreeWinding (in);
|
||||
*inout = NULL;
|
||||
return;
|
||||
}
|
||||
if (!counts[1])
|
||||
return; // inout stays the same
|
||||
|
||||
maxpts = in->numpoints+4; // cant use counts[0]+2 because
|
||||
// of fp grouping errors
|
||||
|
||||
f = AllocWinding (maxpts);
|
||||
|
||||
for (i=0 ; i<in->numpoints ; i++)
|
||||
{
|
||||
p1 = in->p[i];
|
||||
|
||||
if (sides[i] == SIDE_ON)
|
||||
{
|
||||
VectorCopy (p1, f->p[f->numpoints]);
|
||||
f->numpoints++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sides[i] == SIDE_FRONT)
|
||||
{
|
||||
VectorCopy (p1, f->p[f->numpoints]);
|
||||
f->numpoints++;
|
||||
}
|
||||
|
||||
if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
|
||||
continue;
|
||||
|
||||
// generate a split point
|
||||
p2 = in->p[(i+1)%in->numpoints];
|
||||
|
||||
dot = dists[i] / (dists[i]-dists[i+1]);
|
||||
for (j=0 ; j<3 ; j++)
|
||||
{ // avoid round off error when possible
|
||||
if (normal[j] == 1)
|
||||
mid[j] = dist;
|
||||
else if (normal[j] == -1)
|
||||
mid[j] = -dist;
|
||||
else
|
||||
mid[j] = p1[j] + dot*(p2[j]-p1[j]);
|
||||
}
|
||||
|
||||
VectorCopy (mid, f->p[f->numpoints]);
|
||||
f->numpoints++;
|
||||
}
|
||||
|
||||
if (f->numpoints > maxpts)
|
||||
Error ("ClipWinding: points exceeded estimate");
|
||||
if (f->numpoints > MAX_POINTS_ON_WINDING)
|
||||
Error ("ClipWinding: MAX_POINTS_ON_WINDING");
|
||||
|
||||
FreeWinding (in);
|
||||
*inout = f;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
ChopWinding
|
||||
|
||||
Returns the fragment of in that is on the front side
|
||||
of the cliping plane. The original is freed.
|
||||
=================
|
||||
*/
|
||||
winding_t *ChopWinding (winding_t *in, vec3_t normal, vec_t dist)
|
||||
{
|
||||
winding_t *f, *b;
|
||||
|
||||
ClipWindingEpsilon (in, normal, dist, ON_EPSILON, &f, &b);
|
||||
FreeWinding (in);
|
||||
if (b)
|
||||
FreeWinding (b);
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
CheckWinding
|
||||
|
||||
=================
|
||||
*/
|
||||
void CheckWinding (winding_t *w)
|
||||
{
|
||||
int i, j;
|
||||
vec_t *p1, *p2;
|
||||
vec_t d, edgedist;
|
||||
vec3_t dir, edgenormal, facenormal;
|
||||
vec_t area;
|
||||
vec_t facedist;
|
||||
|
||||
if (w->numpoints < 3)
|
||||
Error ("CheckWinding: %i points",w->numpoints);
|
||||
|
||||
area = WindingArea(w);
|
||||
if (area < 1)
|
||||
Error ("CheckWinding: %f area", area);
|
||||
|
||||
WindingPlane (w, facenormal, &facedist);
|
||||
|
||||
for (i=0 ; i<w->numpoints ; i++)
|
||||
{
|
||||
p1 = w->p[i];
|
||||
|
||||
for (j=0 ; j<3 ; j++)
|
||||
if (p1[j] > BOGUS_RANGE || p1[j] < -BOGUS_RANGE)
|
||||
Error ("CheckFace: BUGUS_RANGE: %f",p1[j]);
|
||||
|
||||
j = i+1 == w->numpoints ? 0 : i+1;
|
||||
|
||||
// check the point is on the face plane
|
||||
d = DotProduct (p1, facenormal) - facedist;
|
||||
if (d < -ON_EPSILON || d > ON_EPSILON)
|
||||
Error ("CheckWinding: point off plane");
|
||||
|
||||
// check the edge isnt degenerate
|
||||
p2 = w->p[j];
|
||||
VectorSubtract (p2, p1, dir);
|
||||
|
||||
if (VectorLength (dir) < ON_EPSILON)
|
||||
Error ("CheckWinding: degenerate edge");
|
||||
|
||||
CrossProduct (facenormal, dir, edgenormal);
|
||||
VectorNormalize (edgenormal, edgenormal);
|
||||
edgedist = DotProduct (p1, edgenormal);
|
||||
edgedist += ON_EPSILON;
|
||||
|
||||
// all other points must be on front side
|
||||
for (j=0 ; j<w->numpoints ; j++)
|
||||
{
|
||||
if (j == i)
|
||||
continue;
|
||||
d = DotProduct (w->p[j], edgenormal);
|
||||
if (d > edgedist)
|
||||
Error ("CheckWinding: non-convex");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
WindingOnPlaneSide
|
||||
============
|
||||
*/
|
||||
int WindingOnPlaneSide (winding_t *w, vec3_t normal, vec_t dist)
|
||||
{
|
||||
qboolean front, back;
|
||||
int i;
|
||||
vec_t d;
|
||||
|
||||
front = false;
|
||||
back = false;
|
||||
for (i=0 ; i<w->numpoints ; i++)
|
||||
{
|
||||
d = DotProduct (w->p[i], normal) - dist;
|
||||
if (d < -ON_EPSILON)
|
||||
{
|
||||
if (front)
|
||||
return SIDE_CROSS;
|
||||
back = true;
|
||||
continue;
|
||||
}
|
||||
if (d > ON_EPSILON)
|
||||
{
|
||||
if (back)
|
||||
return SIDE_CROSS;
|
||||
front = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (back)
|
||||
return SIDE_BACK;
|
||||
if (front)
|
||||
return SIDE_FRONT;
|
||||
return SIDE_ON;
|
||||
}
|
||||
|
55
tools/quake2/extra/common/polylib.h
Normal file
55
tools/quake2/extra/common/polylib.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int numpoints;
|
||||
vec3_t p[4]; // variable sized
|
||||
} winding_t;
|
||||
|
||||
#define MAX_POINTS_ON_WINDING 64
|
||||
|
||||
// you can define on_epsilon in the makefile as tighter
|
||||
#ifndef ON_EPSILON
|
||||
#define ON_EPSILON 0.1
|
||||
#endif
|
||||
|
||||
winding_t *AllocWinding (int points);
|
||||
vec_t WindingArea (winding_t *w);
|
||||
void WindingCenter (winding_t *w, vec3_t center);
|
||||
void ClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist,
|
||||
vec_t epsilon, winding_t **front, winding_t **back);
|
||||
winding_t *ChopWinding (winding_t *in, vec3_t normal, vec_t dist);
|
||||
winding_t *CopyWinding (winding_t *w);
|
||||
winding_t *ReverseWinding (winding_t *w);
|
||||
winding_t *BaseWindingForPlane (vec3_t normal, vec_t dist);
|
||||
void CheckWinding (winding_t *w);
|
||||
void WindingPlane (winding_t *w, vec3_t normal, vec_t *dist);
|
||||
void RemoveColinearPoints (winding_t *w);
|
||||
int WindingOnPlaneSide (winding_t *w, vec3_t normal, vec_t dist);
|
||||
void FreeWinding (winding_t *w);
|
||||
void WindingBounds (winding_t *w, vec3_t mins, vec3_t maxs);
|
||||
|
||||
void ChopWindingInPlace (winding_t **w, vec3_t normal, vec_t dist, vec_t epsilon);
|
||||
// frees the original if clipped
|
||||
|
||||
void pw(winding_t *w);
|
486
tools/quake2/extra/common/qfiles.h
Normal file
486
tools/quake2/extra/common/qfiles.h
Normal file
|
@ -0,0 +1,486 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
//
|
||||
// qfiles.h: quake file formats
|
||||
// This file must be identical in the quake and utils directories
|
||||
//
|
||||
|
||||
/*
|
||||
========================================================================
|
||||
|
||||
The .pak files are just a linear collapse of a directory tree
|
||||
|
||||
========================================================================
|
||||
*/
|
||||
|
||||
#define IDPAKHEADER (('K'<<24)+('C'<<16)+('A'<<8)+'P')
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char name[56];
|
||||
int filepos, filelen;
|
||||
} dpackfile_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int ident; // == IDPAKHEADER
|
||||
int dirofs;
|
||||
int dirlen;
|
||||
} dpackheader_t;
|
||||
|
||||
#define MAX_FILES_IN_PACK 4096
|
||||
|
||||
|
||||
/*
|
||||
========================================================================
|
||||
|
||||
PCX files are used for as many images as possible
|
||||
|
||||
========================================================================
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char manufacturer;
|
||||
char version;
|
||||
char encoding;
|
||||
char bits_per_pixel;
|
||||
unsigned short xmin,ymin,xmax,ymax;
|
||||
unsigned short hres,vres;
|
||||
unsigned char palette[48];
|
||||
char reserved;
|
||||
char color_planes;
|
||||
unsigned short bytes_per_line;
|
||||
unsigned short palette_type;
|
||||
char filler[58];
|
||||
unsigned char data; // unbounded
|
||||
} pcx_t;
|
||||
|
||||
|
||||
/*
|
||||
========================================================================
|
||||
|
||||
.MD2 triangle model file format
|
||||
|
||||
========================================================================
|
||||
*/
|
||||
|
||||
#define IDALIASHEADER (('2'<<24)+('P'<<16)+('D'<<8)+'I')
|
||||
#define ALIAS_VERSION 8
|
||||
|
||||
#define MAX_TRIANGLES 4096
|
||||
#define MAX_VERTS 2048
|
||||
#define MAX_FRAMES 512
|
||||
#define MAX_MD2SKINS 32
|
||||
#define MAX_SKINNAME 64
|
||||
|
||||
typedef struct
|
||||
{
|
||||
short s;
|
||||
short t;
|
||||
} dstvert_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
short index_xyz[3];
|
||||
short index_st[3];
|
||||
} dtriangle_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
byte v[3]; // scaled byte to fit in frame mins/maxs
|
||||
byte lightnormalindex;
|
||||
} dtrivertx_t;
|
||||
|
||||
#define DTRIVERTX_V0 0
|
||||
#define DTRIVERTX_V1 1
|
||||
#define DTRIVERTX_V2 2
|
||||
#define DTRIVERTX_LNI 3
|
||||
#define DTRIVERTX_SIZE 4
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float scale[3]; // multiply byte verts by this
|
||||
float translate[3]; // then add this
|
||||
char name[16]; // frame name from grabbing
|
||||
dtrivertx_t verts[1]; // variable sized
|
||||
} daliasframe_t;
|
||||
|
||||
|
||||
// the glcmd format:
|
||||
// a positive integer starts a tristrip command, followed by that many
|
||||
// vertex structures.
|
||||
// a negative integer starts a trifan command, followed by -x vertexes
|
||||
// a zero indicates the end of the command list.
|
||||
// a vertex consists of a floating point s, a floating point t,
|
||||
// and an integer vertex index.
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int ident;
|
||||
int version;
|
||||
|
||||
int skinwidth;
|
||||
int skinheight;
|
||||
int framesize; // byte size of each frame
|
||||
|
||||
int num_skins;
|
||||
int num_xyz;
|
||||
int num_st; // greater than num_xyz for seams
|
||||
int num_tris;
|
||||
int num_glcmds; // dwords in strip/fan command list
|
||||
int num_frames;
|
||||
|
||||
int ofs_skins; // each skin is a MAX_SKINNAME string
|
||||
int ofs_st; // byte offset from start for stverts
|
||||
int ofs_tris; // offset for dtriangles
|
||||
int ofs_frames; // offset for first frame
|
||||
int ofs_glcmds;
|
||||
int ofs_end; // end of file
|
||||
|
||||
} dmdl_t;
|
||||
|
||||
/*
|
||||
========================================================================
|
||||
|
||||
.SP2 sprite file format
|
||||
|
||||
========================================================================
|
||||
*/
|
||||
|
||||
#define IDSPRITEHEADER (('2'<<24)+('S'<<16)+('D'<<8)+'I')
|
||||
// little-endian "IDS2"
|
||||
#define SPRITE_VERSION 2
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int width, height;
|
||||
int origin_x, origin_y; // raster coordinates inside pic
|
||||
char name[MAX_SKINNAME]; // name of pcx file
|
||||
} dsprframe_t;
|
||||
|
||||
typedef struct {
|
||||
int ident;
|
||||
int version;
|
||||
int numframes;
|
||||
dsprframe_t frames[1]; // variable sized
|
||||
} dsprite_t;
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
.WAL texture file format
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
|
||||
#define MIPLEVELS 4
|
||||
typedef struct miptex_s
|
||||
{
|
||||
char name[32];
|
||||
unsigned width, height;
|
||||
unsigned offsets[MIPLEVELS]; // four mip maps stored
|
||||
char animname[32]; // next frame in animation chain
|
||||
int flags;
|
||||
int contents;
|
||||
int value;
|
||||
} miptex_t;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
.BSP file format
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#define IDBSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'I')
|
||||
// little-endian "IBSP"
|
||||
|
||||
#define BSPVERSION 38
|
||||
|
||||
|
||||
// upper design bounds
|
||||
// leaffaces, leafbrushes, planes, and verts are still bounded by
|
||||
// 16 bit short limits
|
||||
#define MAX_MAP_MODELS 1024
|
||||
#define MAX_MAP_BRUSHES 8192
|
||||
#define MAX_MAP_ENTITIES 2048
|
||||
#define MAX_MAP_ENTSTRING 0x40000
|
||||
#define MAX_MAP_TEXINFO 8192
|
||||
|
||||
#define MAX_MAP_AREAS 256
|
||||
#define MAX_MAP_AREAPORTALS 1024
|
||||
#define MAX_MAP_PLANES 65536
|
||||
#define MAX_MAP_NODES 65536
|
||||
#define MAX_MAP_BRUSHSIDES 65536
|
||||
#define MAX_MAP_LEAFS 65536
|
||||
#define MAX_MAP_VERTS 65536
|
||||
#define MAX_MAP_FACES 65536
|
||||
#define MAX_MAP_LEAFFACES 65536
|
||||
#define MAX_MAP_LEAFBRUSHES 65536
|
||||
#define MAX_MAP_PORTALS 65536
|
||||
#define MAX_MAP_EDGES 128000
|
||||
#define MAX_MAP_SURFEDGES 256000
|
||||
#define MAX_MAP_LIGHTING 0x200000
|
||||
#define MAX_MAP_VISIBILITY 0x100000
|
||||
|
||||
// key / value pair sizes
|
||||
|
||||
#define MAX_KEY 32
|
||||
#define MAX_VALUE 1024
|
||||
|
||||
//=============================================================================
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int fileofs, filelen;
|
||||
} lump_t;
|
||||
|
||||
#define LUMP_ENTITIES 0
|
||||
#define LUMP_PLANES 1
|
||||
#define LUMP_VERTEXES 2
|
||||
#define LUMP_VISIBILITY 3
|
||||
#define LUMP_NODES 4
|
||||
#define LUMP_TEXINFO 5
|
||||
#define LUMP_FACES 6
|
||||
#define LUMP_LIGHTING 7
|
||||
#define LUMP_LEAFS 8
|
||||
#define LUMP_LEAFFACES 9
|
||||
#define LUMP_LEAFBRUSHES 10
|
||||
#define LUMP_EDGES 11
|
||||
#define LUMP_SURFEDGES 12
|
||||
#define LUMP_MODELS 13
|
||||
#define LUMP_BRUSHES 14
|
||||
#define LUMP_BRUSHSIDES 15
|
||||
#define LUMP_POP 16
|
||||
#define LUMP_AREAS 17
|
||||
#define LUMP_AREAPORTALS 18
|
||||
#define HEADER_LUMPS 19
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int ident;
|
||||
int version;
|
||||
lump_t lumps[HEADER_LUMPS];
|
||||
} dheader_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float mins[3], maxs[3];
|
||||
float origin[3]; // for sounds or lights
|
||||
int headnode;
|
||||
int firstface, numfaces; // submodels just draw faces
|
||||
// without walking the bsp tree
|
||||
} dmodel_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float point[3];
|
||||
} dvertex_t;
|
||||
|
||||
|
||||
// 0-2 are axial planes
|
||||
#define PLANE_X 0
|
||||
#define PLANE_Y 1
|
||||
#define PLANE_Z 2
|
||||
|
||||
// 3-5 are non-axial planes snapped to the nearest
|
||||
#define PLANE_ANYX 3
|
||||
#define PLANE_ANYY 4
|
||||
#define PLANE_ANYZ 5
|
||||
|
||||
// planes (x&~1) and (x&~1)+1 are allways opposites
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float normal[3];
|
||||
float dist;
|
||||
int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate
|
||||
} dplane_t;
|
||||
|
||||
|
||||
// contents flags are seperate bits
|
||||
// a given brush can contribute multiple content bits
|
||||
// multiple brushes can be in a single leaf
|
||||
|
||||
// these definitions also need to be in q_shared.h!
|
||||
|
||||
// lower bits are stronger, and will eat weaker brushes completely
|
||||
#define CONTENTS_SOLID 1 // an eye is never valid in a solid
|
||||
#define CONTENTS_WINDOW 2 // translucent, but not watery
|
||||
#define CONTENTS_AUX 4
|
||||
#define CONTENTS_LAVA 8
|
||||
#define CONTENTS_SLIME 16
|
||||
#define CONTENTS_WATER 32
|
||||
#define CONTENTS_MIST 64
|
||||
#define LAST_VISIBLE_CONTENTS 64
|
||||
|
||||
// remaining contents are non-visible, and don't eat brushes
|
||||
|
||||
#define CONTENTS_AREAPORTAL 0x8000
|
||||
|
||||
#define CONTENTS_PLAYERCLIP 0x10000
|
||||
#define CONTENTS_MONSTERCLIP 0x20000
|
||||
|
||||
// currents can be added to any other contents, and may be mixed
|
||||
#define CONTENTS_CURRENT_0 0x40000
|
||||
#define CONTENTS_CURRENT_90 0x80000
|
||||
#define CONTENTS_CURRENT_180 0x100000
|
||||
#define CONTENTS_CURRENT_270 0x200000
|
||||
#define CONTENTS_CURRENT_UP 0x400000
|
||||
#define CONTENTS_CURRENT_DOWN 0x800000
|
||||
|
||||
#define CONTENTS_ORIGIN 0x1000000 // removed before bsping an entity
|
||||
|
||||
#define CONTENTS_MONSTER 0x2000000 // should never be on a brush, only in game
|
||||
#define CONTENTS_DEADMONSTER 0x4000000
|
||||
#define CONTENTS_DETAIL 0x8000000 // brushes to be added after vis leafs
|
||||
#define CONTENTS_TRANSLUCENT 0x10000000 // auto set if any surface has trans
|
||||
#define CONTENTS_LADDER 0x20000000
|
||||
|
||||
|
||||
|
||||
#define SURF_LIGHT 0x1 // value will hold the light strength
|
||||
|
||||
#define SURF_SLICK 0x2 // effects game physics
|
||||
|
||||
#define SURF_SKY 0x4 // don't draw, but add to skybox
|
||||
#define SURF_WARP 0x8 // turbulent water warp
|
||||
#define SURF_TRANS33 0x10
|
||||
#define SURF_TRANS66 0x20
|
||||
#define SURF_FLOWING 0x40 // scroll towards angle
|
||||
#define SURF_NODRAW 0x80 // don't bother referencing the texture
|
||||
|
||||
#define SURF_HINT 0x100 // make a primary bsp splitter
|
||||
#define SURF_SKIP 0x200 // completely ignore, allowing non-closed brushes
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int planenum;
|
||||
int children[2]; // negative numbers are -(leafs+1), not nodes
|
||||
short mins[3]; // for frustom culling
|
||||
short maxs[3];
|
||||
unsigned short firstface;
|
||||
unsigned short numfaces; // counting both sides
|
||||
} dnode_t;
|
||||
|
||||
|
||||
typedef struct texinfo_s
|
||||
{
|
||||
float vecs[2][4]; // [s/t][xyz offset]
|
||||
int flags; // miptex flags + overrides
|
||||
int value; // light emission, etc
|
||||
char texture[32]; // texture name (textures/*.wal)
|
||||
int nexttexinfo; // for animations, -1 = end of chain
|
||||
} texinfo_t;
|
||||
|
||||
|
||||
// note that edge 0 is never used, because negative edge nums are used for
|
||||
// counterclockwise use of the edge in a face
|
||||
typedef struct
|
||||
{
|
||||
unsigned short v[2]; // vertex numbers
|
||||
} dedge_t;
|
||||
|
||||
#define MAXLIGHTMAPS 4
|
||||
typedef struct
|
||||
{
|
||||
unsigned short planenum;
|
||||
short side;
|
||||
|
||||
int firstedge; // we must support > 64k edges
|
||||
short numedges;
|
||||
short texinfo;
|
||||
|
||||
// lighting info
|
||||
byte styles[MAXLIGHTMAPS];
|
||||
int lightofs; // start of [numstyles*surfsize] samples
|
||||
} dface_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int contents; // OR of all brushes (not needed?)
|
||||
|
||||
short cluster;
|
||||
short area;
|
||||
|
||||
short mins[3]; // for frustum culling
|
||||
short maxs[3];
|
||||
|
||||
unsigned short firstleafface;
|
||||
unsigned short numleaffaces;
|
||||
|
||||
unsigned short firstleafbrush;
|
||||
unsigned short numleafbrushes;
|
||||
} dleaf_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned short planenum; // facing out of the leaf
|
||||
short texinfo;
|
||||
} dbrushside_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int firstside;
|
||||
int numsides;
|
||||
int contents;
|
||||
} dbrush_t;
|
||||
|
||||
#define ANGLE_UP -1
|
||||
#define ANGLE_DOWN -2
|
||||
|
||||
|
||||
// the visibility lump consists of a header with a count, then
|
||||
// byte offsets for the PVS and PHS of each cluster, then the raw
|
||||
// compressed bit vectors
|
||||
#define DVIS_PVS 0
|
||||
#define DVIS_PHS 1
|
||||
typedef struct
|
||||
{
|
||||
int numclusters;
|
||||
int bitofs[8][2]; // bitofs[numclusters][2]
|
||||
} dvis_t;
|
||||
|
||||
// each area has a list of portals that lead into other areas
|
||||
// when portals are closed, other areas may not be visible or
|
||||
// hearable even if the vis info says that it should be
|
||||
typedef struct
|
||||
{
|
||||
int portalnum;
|
||||
int otherarea;
|
||||
} dareaportal_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int numareaportals;
|
||||
int firstareaportal;
|
||||
} darea_t;
|
297
tools/quake2/extra/common/scriplib.c
Normal file
297
tools/quake2/extra/common/scriplib.c
Normal file
|
@ -0,0 +1,297 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// scriplib.c
|
||||
|
||||
#include "cmdlib.h"
|
||||
#include "scriplib.h"
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
PARSING STUFF
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char filename[1024];
|
||||
char *buffer,*script_p,*end_p;
|
||||
int line;
|
||||
} script_t;
|
||||
|
||||
#define MAX_INCLUDES 8
|
||||
script_t scriptstack[MAX_INCLUDES];
|
||||
script_t *script;
|
||||
int scriptline;
|
||||
|
||||
char token[MAXTOKEN];
|
||||
qboolean endofscript;
|
||||
qboolean tokenready; // only true if UnGetToken was just called
|
||||
|
||||
/*
|
||||
==============
|
||||
AddScriptToStack
|
||||
==============
|
||||
*/
|
||||
void AddScriptToStack (char *filename)
|
||||
{
|
||||
int size;
|
||||
|
||||
script++;
|
||||
if (script == &scriptstack[MAX_INCLUDES])
|
||||
Error ("script file exceeded MAX_INCLUDES");
|
||||
strcpy (script->filename, ExpandPath (filename) );
|
||||
|
||||
size = LoadFile (script->filename, (void **)&script->buffer);
|
||||
|
||||
printf ("entering %s\n", script->filename);
|
||||
|
||||
script->line = 1;
|
||||
|
||||
script->script_p = script->buffer;
|
||||
script->end_p = script->buffer + size;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
LoadScriptFile
|
||||
==============
|
||||
*/
|
||||
void LoadScriptFile (char *filename)
|
||||
{
|
||||
script = scriptstack;
|
||||
AddScriptToStack (filename);
|
||||
|
||||
endofscript = false;
|
||||
tokenready = false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
ParseFromMemory
|
||||
==============
|
||||
*/
|
||||
void ParseFromMemory (char *buffer, int size)
|
||||
{
|
||||
script = scriptstack;
|
||||
script++;
|
||||
if (script == &scriptstack[MAX_INCLUDES])
|
||||
Error ("script file exceeded MAX_INCLUDES");
|
||||
strcpy (script->filename, "memory buffer" );
|
||||
|
||||
script->buffer = buffer;
|
||||
script->line = 1;
|
||||
script->script_p = script->buffer;
|
||||
script->end_p = script->buffer + size;
|
||||
|
||||
endofscript = false;
|
||||
tokenready = false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
UnGetToken
|
||||
|
||||
Signals that the current token was not used, and should be reported
|
||||
for the next GetToken. Note that
|
||||
|
||||
GetToken (true);
|
||||
UnGetToken ();
|
||||
GetToken (false);
|
||||
|
||||
could cross a line boundary.
|
||||
==============
|
||||
*/
|
||||
void UnGetToken (void)
|
||||
{
|
||||
tokenready = true;
|
||||
}
|
||||
|
||||
|
||||
qboolean EndOfScript (qboolean crossline)
|
||||
{
|
||||
if (!crossline)
|
||||
Error ("Line %i is incomplete\n",scriptline);
|
||||
|
||||
if (!strcmp (script->filename, "memory buffer"))
|
||||
{
|
||||
endofscript = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
free (script->buffer);
|
||||
if (script == scriptstack+1)
|
||||
{
|
||||
endofscript = true;
|
||||
return false;
|
||||
}
|
||||
script--;
|
||||
scriptline = script->line;
|
||||
printf ("returning to %s\n", script->filename);
|
||||
return GetToken (crossline);
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
GetToken
|
||||
==============
|
||||
*/
|
||||
qboolean GetToken (qboolean crossline)
|
||||
{
|
||||
char *token_p;
|
||||
|
||||
if (tokenready) // is a token allready waiting?
|
||||
{
|
||||
tokenready = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (script->script_p >= script->end_p)
|
||||
return EndOfScript (crossline);
|
||||
|
||||
//
|
||||
// skip space
|
||||
//
|
||||
skipspace:
|
||||
while (*script->script_p <= 32)
|
||||
{
|
||||
if (script->script_p >= script->end_p)
|
||||
return EndOfScript (crossline);
|
||||
if (*script->script_p++ == '\n')
|
||||
{
|
||||
if (!crossline)
|
||||
Error ("Line %i is incomplete\n",scriptline);
|
||||
scriptline = script->line++;
|
||||
}
|
||||
}
|
||||
|
||||
if (script->script_p >= script->end_p)
|
||||
return EndOfScript (crossline);
|
||||
|
||||
// ; # // comments
|
||||
if (*script->script_p == ';' || *script->script_p == '#'
|
||||
|| ( script->script_p[0] == '/' && script->script_p[1] == '/') )
|
||||
{
|
||||
if (!crossline)
|
||||
Error ("Line %i is incomplete\n",scriptline);
|
||||
while (*script->script_p++ != '\n')
|
||||
if (script->script_p >= script->end_p)
|
||||
return EndOfScript (crossline);
|
||||
goto skipspace;
|
||||
}
|
||||
|
||||
// /* */ comments
|
||||
if (script->script_p[0] == '/' && script->script_p[1] == '*')
|
||||
{
|
||||
if (!crossline)
|
||||
Error ("Line %i is incomplete\n",scriptline);
|
||||
script->script_p+=2;
|
||||
while (script->script_p[0] != '*' && script->script_p[1] != '/')
|
||||
{
|
||||
script->script_p++;
|
||||
if (script->script_p >= script->end_p)
|
||||
return EndOfScript (crossline);
|
||||
}
|
||||
script->script_p += 2;
|
||||
goto skipspace;
|
||||
}
|
||||
|
||||
//
|
||||
// copy token
|
||||
//
|
||||
token_p = token;
|
||||
|
||||
if (*script->script_p == '"')
|
||||
{
|
||||
// quoted token
|
||||
script->script_p++;
|
||||
while (*script->script_p != '"')
|
||||
{
|
||||
*token_p++ = *script->script_p++;
|
||||
if (script->script_p == script->end_p)
|
||||
break;
|
||||
if (token_p == &token[MAXTOKEN])
|
||||
Error ("Token too large on line %i\n",scriptline);
|
||||
}
|
||||
script->script_p++;
|
||||
}
|
||||
else // regular token
|
||||
while ( *script->script_p > 32 && *script->script_p != ';')
|
||||
{
|
||||
*token_p++ = *script->script_p++;
|
||||
if (script->script_p == script->end_p)
|
||||
break;
|
||||
if (token_p == &token[MAXTOKEN])
|
||||
Error ("Token too large on line %i\n",scriptline);
|
||||
}
|
||||
|
||||
*token_p = 0;
|
||||
|
||||
if (!strcmp (token, "$include"))
|
||||
{
|
||||
GetToken (false);
|
||||
AddScriptToStack (token);
|
||||
return GetToken (crossline);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
TokenAvailable
|
||||
|
||||
Returns true if there is another token on the line
|
||||
==============
|
||||
*/
|
||||
qboolean TokenAvailable (void)
|
||||
{
|
||||
char *search_p;
|
||||
|
||||
search_p = script->script_p;
|
||||
|
||||
if (search_p >= script->end_p)
|
||||
return false;
|
||||
|
||||
while ( *search_p <= 32)
|
||||
{
|
||||
if (*search_p == '\n')
|
||||
return false;
|
||||
search_p++;
|
||||
if (search_p == script->end_p)
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
if (*search_p == ';')
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
45
tools/quake2/extra/common/scriplib.h
Normal file
45
tools/quake2/extra/common/scriplib.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// scriplib.h
|
||||
|
||||
#ifndef __CMDLIB__
|
||||
#include "cmdlib.h"
|
||||
#endif
|
||||
|
||||
#define MAXTOKEN 1024
|
||||
|
||||
extern char token[MAXTOKEN];
|
||||
extern char *scriptbuffer,*script_p,*scriptend_p;
|
||||
extern int grabbed;
|
||||
extern int scriptline;
|
||||
extern qboolean endofscript;
|
||||
|
||||
|
||||
void LoadScriptFile (char *filename);
|
||||
void ParseFromMemory (char *buffer, int size);
|
||||
|
||||
qboolean GetToken (qboolean crossline);
|
||||
void UnGetToken (void);
|
||||
qboolean TokenAvailable (void);
|
||||
|
||||
|
448
tools/quake2/extra/common/threads.c
Normal file
448
tools/quake2/extra/common/threads.c
Normal file
|
@ -0,0 +1,448 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "cmdlib.h"
|
||||
#include "threads.h"
|
||||
|
||||
#define MAX_THREADS 64
|
||||
|
||||
int dispatch;
|
||||
int workcount;
|
||||
int oldf;
|
||||
qboolean pacifier;
|
||||
|
||||
qboolean threaded;
|
||||
|
||||
/*
|
||||
=============
|
||||
GetThreadWork
|
||||
|
||||
=============
|
||||
*/
|
||||
int GetThreadWork (void)
|
||||
{
|
||||
int r;
|
||||
int f;
|
||||
|
||||
ThreadLock ();
|
||||
|
||||
if (dispatch == workcount)
|
||||
{
|
||||
ThreadUnlock ();
|
||||
return -1;
|
||||
}
|
||||
|
||||
f = 10*dispatch / workcount;
|
||||
if (f != oldf)
|
||||
{
|
||||
oldf = f;
|
||||
if (pacifier)
|
||||
printf ("%i...", f);
|
||||
}
|
||||
|
||||
r = dispatch;
|
||||
dispatch++;
|
||||
ThreadUnlock ();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
void (*workfunction) (int);
|
||||
|
||||
void ThreadWorkerFunction (int threadnum)
|
||||
{
|
||||
int work;
|
||||
|
||||
while (1)
|
||||
{
|
||||
work = GetThreadWork ();
|
||||
if (work == -1)
|
||||
break;
|
||||
//printf ("thread %i, work %i\n", threadnum, work);
|
||||
workfunction(work);
|
||||
}
|
||||
}
|
||||
|
||||
void RunThreadsOnIndividual (int workcnt, qboolean showpacifier, void(*func)(int))
|
||||
{
|
||||
if (numthreads == -1)
|
||||
ThreadSetDefault ();
|
||||
workfunction = func;
|
||||
RunThreadsOn (workcnt, showpacifier, ThreadWorkerFunction);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===================================================================
|
||||
|
||||
WIN32
|
||||
|
||||
===================================================================
|
||||
*/
|
||||
#ifdef WIN32
|
||||
|
||||
#define USED
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
int numthreads = -1;
|
||||
CRITICAL_SECTION crit;
|
||||
static int enter;
|
||||
|
||||
void ThreadSetDefault (void)
|
||||
{
|
||||
SYSTEM_INFO info;
|
||||
|
||||
if (numthreads == -1) // not set manually
|
||||
{
|
||||
GetSystemInfo (&info);
|
||||
numthreads = info.dwNumberOfProcessors;
|
||||
if (numthreads < 1 || numthreads > 32)
|
||||
numthreads = 1;
|
||||
}
|
||||
|
||||
qprintf ("%i threads\n", numthreads);
|
||||
}
|
||||
|
||||
|
||||
void ThreadLock (void)
|
||||
{
|
||||
if (!threaded)
|
||||
return;
|
||||
EnterCriticalSection (&crit);
|
||||
if (enter)
|
||||
Error ("Recursive ThreadLock\n");
|
||||
enter = 1;
|
||||
}
|
||||
|
||||
void ThreadUnlock (void)
|
||||
{
|
||||
if (!threaded)
|
||||
return;
|
||||
if (!enter)
|
||||
Error ("ThreadUnlock without lock\n");
|
||||
enter = 0;
|
||||
LeaveCriticalSection (&crit);
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
RunThreadsOn
|
||||
=============
|
||||
*/
|
||||
void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))
|
||||
{
|
||||
int threadid[MAX_THREADS];
|
||||
HANDLE threadhandle[MAX_THREADS];
|
||||
int i;
|
||||
int start, end;
|
||||
|
||||
start = I_FloatTime ();
|
||||
dispatch = 0;
|
||||
workcount = workcnt;
|
||||
oldf = -1;
|
||||
pacifier = showpacifier;
|
||||
threaded = true;
|
||||
|
||||
//
|
||||
// run threads in parallel
|
||||
//
|
||||
InitializeCriticalSection (&crit);
|
||||
|
||||
if (numthreads == 1)
|
||||
{ // use same thread
|
||||
func (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i=0 ; i<numthreads ; i++)
|
||||
{
|
||||
threadhandle[i] = CreateThread(
|
||||
NULL, // LPSECURITY_ATTRIBUTES lpsa,
|
||||
0, // DWORD cbStack,
|
||||
(LPTHREAD_START_ROUTINE)func, // LPTHREAD_START_ROUTINE lpStartAddr,
|
||||
(LPVOID)i, // LPVOID lpvThreadParm,
|
||||
0, // DWORD fdwCreate,
|
||||
&threadid[i]);
|
||||
}
|
||||
|
||||
for (i=0 ; i<numthreads ; i++)
|
||||
WaitForSingleObject (threadhandle[i], INFINITE);
|
||||
}
|
||||
DeleteCriticalSection (&crit);
|
||||
|
||||
threaded = false;
|
||||
end = I_FloatTime ();
|
||||
if (pacifier)
|
||||
printf (" (%i)\n", end-start);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
===================================================================
|
||||
|
||||
OSF1
|
||||
|
||||
===================================================================
|
||||
*/
|
||||
|
||||
#ifdef __osf__
|
||||
#define USED
|
||||
|
||||
int numthreads = 4;
|
||||
|
||||
void ThreadSetDefault (void)
|
||||
{
|
||||
if (numthreads == -1) // not set manually
|
||||
{
|
||||
numthreads = 4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
pthread_mutex_t *my_mutex;
|
||||
|
||||
void ThreadLock (void)
|
||||
{
|
||||
if (my_mutex)
|
||||
pthread_mutex_lock (my_mutex);
|
||||
}
|
||||
|
||||
void ThreadUnlock (void)
|
||||
{
|
||||
if (my_mutex)
|
||||
pthread_mutex_unlock (my_mutex);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
RunThreadsOn
|
||||
=============
|
||||
*/
|
||||
void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))
|
||||
{
|
||||
int i;
|
||||
pthread_t work_threads[MAX_THREADS];
|
||||
pthread_addr_t status;
|
||||
pthread_attr_t attrib;
|
||||
pthread_mutexattr_t mattrib;
|
||||
int start, end;
|
||||
|
||||
start = I_FloatTime ();
|
||||
dispatch = 0;
|
||||
workcount = workcnt;
|
||||
oldf = -1;
|
||||
pacifier = showpacifier;
|
||||
threaded = true;
|
||||
|
||||
if (pacifier)
|
||||
setbuf (stdout, NULL);
|
||||
|
||||
if (!my_mutex)
|
||||
{
|
||||
my_mutex = malloc (sizeof(*my_mutex));
|
||||
if (pthread_mutexattr_create (&mattrib) == -1)
|
||||
Error ("pthread_mutex_attr_create failed");
|
||||
if (pthread_mutexattr_setkind_np (&mattrib, MUTEX_FAST_NP) == -1)
|
||||
Error ("pthread_mutexattr_setkind_np failed");
|
||||
if (pthread_mutex_init (my_mutex, mattrib) == -1)
|
||||
Error ("pthread_mutex_init failed");
|
||||
}
|
||||
|
||||
if (pthread_attr_create (&attrib) == -1)
|
||||
Error ("pthread_attr_create failed");
|
||||
if (pthread_attr_setstacksize (&attrib, 0x100000) == -1)
|
||||
Error ("pthread_attr_setstacksize failed");
|
||||
|
||||
for (i=0 ; i<numthreads ; i++)
|
||||
{
|
||||
if (pthread_create(&work_threads[i], attrib
|
||||
, (pthread_startroutine_t)func, (pthread_addr_t)i) == -1)
|
||||
Error ("pthread_create failed");
|
||||
}
|
||||
|
||||
for (i=0 ; i<numthreads ; i++)
|
||||
{
|
||||
if (pthread_join (work_threads[i], &status) == -1)
|
||||
Error ("pthread_join failed");
|
||||
}
|
||||
|
||||
threaded = false;
|
||||
|
||||
end = I_FloatTime ();
|
||||
if (pacifier)
|
||||
printf (" (%i)\n", end-start);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
===================================================================
|
||||
|
||||
IRIX
|
||||
|
||||
===================================================================
|
||||
*/
|
||||
|
||||
#ifdef _MIPS_ISA
|
||||
#define USED
|
||||
|
||||
#include <task.h>
|
||||
#include <abi_mutex.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/prctl.h>
|
||||
|
||||
|
||||
int numthreads = -1;
|
||||
abilock_t lck;
|
||||
|
||||
void ThreadSetDefault (void)
|
||||
{
|
||||
if (numthreads == -1)
|
||||
numthreads = prctl(PR_MAXPPROCS);
|
||||
printf ("%i threads\n", numthreads);
|
||||
//@@
|
||||
usconfig (CONF_INITUSERS, numthreads);
|
||||
}
|
||||
|
||||
|
||||
void ThreadLock (void)
|
||||
{
|
||||
spin_lock (&lck);
|
||||
}
|
||||
|
||||
void ThreadUnlock (void)
|
||||
{
|
||||
release_lock (&lck);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
RunThreadsOn
|
||||
=============
|
||||
*/
|
||||
void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))
|
||||
{
|
||||
int i;
|
||||
int pid[MAX_THREADS];
|
||||
int start, end;
|
||||
|
||||
start = I_FloatTime ();
|
||||
dispatch = 0;
|
||||
workcount = workcnt;
|
||||
oldf = -1;
|
||||
pacifier = showpacifier;
|
||||
threaded = true;
|
||||
|
||||
if (pacifier)
|
||||
setbuf (stdout, NULL);
|
||||
|
||||
init_lock (&lck);
|
||||
|
||||
for (i=0 ; i<numthreads-1 ; i++)
|
||||
{
|
||||
pid[i] = sprocsp ( (void (*)(void *, size_t))func, PR_SALL, (void *)i
|
||||
, NULL, 0x100000);
|
||||
// pid[i] = sprocsp ( (void (*)(void *, size_t))func, PR_SALL, (void *)i
|
||||
// , NULL, 0x80000);
|
||||
if (pid[i] == -1)
|
||||
{
|
||||
perror ("sproc");
|
||||
Error ("sproc failed");
|
||||
}
|
||||
}
|
||||
|
||||
func(i);
|
||||
|
||||
for (i=0 ; i<numthreads-1 ; i++)
|
||||
wait (NULL);
|
||||
|
||||
threaded = false;
|
||||
|
||||
end = I_FloatTime ();
|
||||
if (pacifier)
|
||||
printf (" (%i)\n", end-start);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
=======================================================================
|
||||
|
||||
SINGLE THREAD
|
||||
|
||||
=======================================================================
|
||||
*/
|
||||
|
||||
#ifndef USED
|
||||
|
||||
int numthreads = 1;
|
||||
|
||||
void ThreadSetDefault (void)
|
||||
{
|
||||
numthreads = 1;
|
||||
}
|
||||
|
||||
void ThreadLock (void)
|
||||
{
|
||||
}
|
||||
|
||||
void ThreadUnlock (void)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
RunThreadsOn
|
||||
=============
|
||||
*/
|
||||
void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))
|
||||
{
|
||||
int i;
|
||||
int start, end;
|
||||
|
||||
dispatch = 0;
|
||||
workcount = workcnt;
|
||||
oldf = -1;
|
||||
pacifier = showpacifier;
|
||||
start = I_FloatTime ();
|
||||
#ifdef NeXT
|
||||
if (pacifier)
|
||||
setbuf (stdout, NULL);
|
||||
#endif
|
||||
func(0);
|
||||
|
||||
end = I_FloatTime ();
|
||||
if (pacifier)
|
||||
printf (" (%i)\n", end-start);
|
||||
}
|
||||
|
||||
#endif
|
31
tools/quake2/extra/common/threads.h
Normal file
31
tools/quake2/extra/common/threads.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
extern int numthreads;
|
||||
|
||||
void ThreadSetDefault (void);
|
||||
int GetThreadWork (void);
|
||||
void RunThreadsOnIndividual (int workcnt, qboolean showpacifier, void(*func)(int));
|
||||
void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int));
|
||||
void ThreadLock (void);
|
||||
void ThreadUnlock (void);
|
||||
|
187
tools/quake2/extra/common/trilib.c
Normal file
187
tools/quake2/extra/common/trilib.c
Normal file
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
//
|
||||
// trilib.c: library for loading triangles from an Alias triangle file
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
#include "cmdlib.h"
|
||||
#include "mathlib.h"
|
||||
#include "trilib.h"
|
||||
|
||||
// on disk representation of a face
|
||||
|
||||
|
||||
#define FLOAT_START 99999.0
|
||||
#define FLOAT_END -FLOAT_START
|
||||
#define MAGIC 123322
|
||||
|
||||
//#define NOISY 1
|
||||
|
||||
typedef struct {
|
||||
float v[3];
|
||||
} vector;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
vector n; /* normal */
|
||||
vector p; /* point */
|
||||
vector c; /* color */
|
||||
float u; /* u */
|
||||
float v; /* v */
|
||||
} aliaspoint_t;
|
||||
|
||||
typedef struct {
|
||||
aliaspoint_t pt[3];
|
||||
} tf_triangle;
|
||||
|
||||
|
||||
void ByteSwapTri (tf_triangle *tri)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0 ; i<sizeof(tf_triangle)/4 ; i++)
|
||||
{
|
||||
((int *)tri)[i] = BigLong (((int *)tri)[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void LoadTriangleList (char *filename, triangle_t **pptri, int *numtriangles)
|
||||
{
|
||||
FILE *input;
|
||||
float start;
|
||||
char name[256], tex[256];
|
||||
int i, count, magic;
|
||||
tf_triangle tri;
|
||||
triangle_t *ptri;
|
||||
int iLevel;
|
||||
int exitpattern;
|
||||
float t;
|
||||
|
||||
t = -FLOAT_START;
|
||||
*((unsigned char *)&exitpattern + 0) = *((unsigned char *)&t + 3);
|
||||
*((unsigned char *)&exitpattern + 1) = *((unsigned char *)&t + 2);
|
||||
*((unsigned char *)&exitpattern + 2) = *((unsigned char *)&t + 1);
|
||||
*((unsigned char *)&exitpattern + 3) = *((unsigned char *)&t + 0);
|
||||
|
||||
if ((input = fopen(filename, "rb")) == 0)
|
||||
Error ("reader: could not open file '%s'", filename);
|
||||
|
||||
iLevel = 0;
|
||||
|
||||
fread(&magic, sizeof(int), 1, input);
|
||||
if (BigLong(magic) != MAGIC)
|
||||
Error ("%s is not a Alias object separated triangle file, magic number is wrong.", filename);
|
||||
|
||||
ptri = malloc (MAXTRIANGLES * sizeof(triangle_t));
|
||||
|
||||
*pptri = ptri;
|
||||
|
||||
while (feof(input) == 0) {
|
||||
if (fread(&start, sizeof(float), 1, input) < 1)
|
||||
break;
|
||||
*(int *)&start = BigLong(*(int *)&start);
|
||||
if (*(int *)&start != exitpattern)
|
||||
{
|
||||
if (start == FLOAT_START) {
|
||||
/* Start of an object or group of objects. */
|
||||
i = -1;
|
||||
do {
|
||||
/* There are probably better ways to read a string from */
|
||||
/* a file, but this does allow you to do error checking */
|
||||
/* (which I'm not doing) on a per character basis. */
|
||||
++i;
|
||||
fread( &(name[i]), sizeof( char ), 1, input);
|
||||
} while( name[i] != '\0' );
|
||||
|
||||
// indent();
|
||||
// fprintf(stdout,"OBJECT START: %s\n",name);
|
||||
fread( &count, sizeof(int), 1, input);
|
||||
count = BigLong(count);
|
||||
++iLevel;
|
||||
if (count != 0) {
|
||||
// indent();
|
||||
// fprintf(stdout,"NUMBER OF TRIANGLES: %d\n",count);
|
||||
|
||||
i = -1;
|
||||
do {
|
||||
++i;
|
||||
fread( &(tex[i]), sizeof( char ), 1, input);
|
||||
} while( tex[i] != '\0' );
|
||||
|
||||
// indent();
|
||||
// fprintf(stdout," Object texture name: '%s'\n",tex);
|
||||
}
|
||||
|
||||
/* Else (count == 0) this is the start of a group, and */
|
||||
/* no texture name is present. */
|
||||
}
|
||||
else if (start == FLOAT_END) {
|
||||
/* End of an object or group. Yes, the name should be */
|
||||
/* obvious from context, but it is in here just to be */
|
||||
/* safe and to provide a little extra information for */
|
||||
/* those who do not wish to write a recursive reader. */
|
||||
/* Mia culpa. */
|
||||
--iLevel;
|
||||
i = -1;
|
||||
do {
|
||||
++i;
|
||||
fread( &(name[i]), sizeof( char ), 1, input);
|
||||
} while( name[i] != '\0' );
|
||||
|
||||
// indent();
|
||||
// fprintf(stdout,"OBJECT END: %s\n",name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// read the triangles
|
||||
//
|
||||
for (i = 0; i < count; ++i) {
|
||||
int j;
|
||||
|
||||
fread( &tri, sizeof(tf_triangle), 1, input );
|
||||
ByteSwapTri (&tri);
|
||||
for (j=0 ; j<3 ; j++)
|
||||
{
|
||||
int k;
|
||||
|
||||
for (k=0 ; k<3 ; k++)
|
||||
{
|
||||
ptri->verts[j][k] = tri.pt[j].p.v[k];
|
||||
}
|
||||
}
|
||||
|
||||
ptri++;
|
||||
|
||||
if ((ptri - *pptri) >= MAXTRIANGLES)
|
||||
Error ("Error: too many triangles; increase MAXTRIANGLES\n");
|
||||
}
|
||||
}
|
||||
|
||||
*numtriangles = ptri - *pptri;
|
||||
|
||||
fclose (input);
|
||||
}
|
||||
|
33
tools/quake2/extra/common/trilib.h
Normal file
33
tools/quake2/extra/common/trilib.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
//
|
||||
// trilib.h: header file for loading triangles from an Alias triangle file
|
||||
//
|
||||
#define MAXTRIANGLES 2048
|
||||
|
||||
typedef struct {
|
||||
vec3_t verts[3];
|
||||
} triangle_t;
|
||||
|
||||
void LoadTriangleList (char *filename, triangle_t **pptri, int *numtriangles);
|
||||
|
184
tools/quake2/extra/qdata/anorms.h
Normal file
184
tools/quake2/extra/qdata/anorms.h
Normal file
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
{-0.525731, 0.000000, 0.850651},
|
||||
{-0.442863, 0.238856, 0.864188},
|
||||
{-0.295242, 0.000000, 0.955423},
|
||||
{-0.309017, 0.500000, 0.809017},
|
||||
{-0.162460, 0.262866, 0.951056},
|
||||
{0.000000, 0.000000, 1.000000},
|
||||
{0.000000, 0.850651, 0.525731},
|
||||
{-0.147621, 0.716567, 0.681718},
|
||||
{0.147621, 0.716567, 0.681718},
|
||||
{0.000000, 0.525731, 0.850651},
|
||||
{0.309017, 0.500000, 0.809017},
|
||||
{0.525731, 0.000000, 0.850651},
|
||||
{0.295242, 0.000000, 0.955423},
|
||||
{0.442863, 0.238856, 0.864188},
|
||||
{0.162460, 0.262866, 0.951056},
|
||||
{-0.681718, 0.147621, 0.716567},
|
||||
{-0.809017, 0.309017, 0.500000},
|
||||
{-0.587785, 0.425325, 0.688191},
|
||||
{-0.850651, 0.525731, 0.000000},
|
||||
{-0.864188, 0.442863, 0.238856},
|
||||
{-0.716567, 0.681718, 0.147621},
|
||||
{-0.688191, 0.587785, 0.425325},
|
||||
{-0.500000, 0.809017, 0.309017},
|
||||
{-0.238856, 0.864188, 0.442863},
|
||||
{-0.425325, 0.688191, 0.587785},
|
||||
{-0.716567, 0.681718, -0.147621},
|
||||
{-0.500000, 0.809017, -0.309017},
|
||||
{-0.525731, 0.850651, 0.000000},
|
||||
{0.000000, 0.850651, -0.525731},
|
||||
{-0.238856, 0.864188, -0.442863},
|
||||
{0.000000, 0.955423, -0.295242},
|
||||
{-0.262866, 0.951056, -0.162460},
|
||||
{0.000000, 1.000000, 0.000000},
|
||||
{0.000000, 0.955423, 0.295242},
|
||||
{-0.262866, 0.951056, 0.162460},
|
||||
{0.238856, 0.864188, 0.442863},
|
||||
{0.262866, 0.951056, 0.162460},
|
||||
{0.500000, 0.809017, 0.309017},
|
||||
{0.238856, 0.864188, -0.442863},
|
||||
{0.262866, 0.951056, -0.162460},
|
||||
{0.500000, 0.809017, -0.309017},
|
||||
{0.850651, 0.525731, 0.000000},
|
||||
{0.716567, 0.681718, 0.147621},
|
||||
{0.716567, 0.681718, -0.147621},
|
||||
{0.525731, 0.850651, 0.000000},
|
||||
{0.425325, 0.688191, 0.587785},
|
||||
{0.864188, 0.442863, 0.238856},
|
||||
{0.688191, 0.587785, 0.425325},
|
||||
{0.809017, 0.309017, 0.500000},
|
||||
{0.681718, 0.147621, 0.716567},
|
||||
{0.587785, 0.425325, 0.688191},
|
||||
{0.955423, 0.295242, 0.000000},
|
||||
{1.000000, 0.000000, 0.000000},
|
||||
{0.951056, 0.162460, 0.262866},
|
||||
{0.850651, -0.525731, 0.000000},
|
||||
{0.955423, -0.295242, 0.000000},
|
||||
{0.864188, -0.442863, 0.238856},
|
||||
{0.951056, -0.162460, 0.262866},
|
||||
{0.809017, -0.309017, 0.500000},
|
||||
{0.681718, -0.147621, 0.716567},
|
||||
{0.850651, 0.000000, 0.525731},
|
||||
{0.864188, 0.442863, -0.238856},
|
||||
{0.809017, 0.309017, -0.500000},
|
||||
{0.951056, 0.162460, -0.262866},
|
||||
{0.525731, 0.000000, -0.850651},
|
||||
{0.681718, 0.147621, -0.716567},
|
||||
{0.681718, -0.147621, -0.716567},
|
||||
{0.850651, 0.000000, -0.525731},
|
||||
{0.809017, -0.309017, -0.500000},
|
||||
{0.864188, -0.442863, -0.238856},
|
||||
{0.951056, -0.162460, -0.262866},
|
||||
{0.147621, 0.716567, -0.681718},
|
||||
{0.309017, 0.500000, -0.809017},
|
||||
{0.425325, 0.688191, -0.587785},
|
||||
{0.442863, 0.238856, -0.864188},
|
||||
{0.587785, 0.425325, -0.688191},
|
||||
{0.688191, 0.587785, -0.425325},
|
||||
{-0.147621, 0.716567, -0.681718},
|
||||
{-0.309017, 0.500000, -0.809017},
|
||||
{0.000000, 0.525731, -0.850651},
|
||||
{-0.525731, 0.000000, -0.850651},
|
||||
{-0.442863, 0.238856, -0.864188},
|
||||
{-0.295242, 0.000000, -0.955423},
|
||||
{-0.162460, 0.262866, -0.951056},
|
||||
{0.000000, 0.000000, -1.000000},
|
||||
{0.295242, 0.000000, -0.955423},
|
||||
{0.162460, 0.262866, -0.951056},
|
||||
{-0.442863, -0.238856, -0.864188},
|
||||
{-0.309017, -0.500000, -0.809017},
|
||||
{-0.162460, -0.262866, -0.951056},
|
||||
{0.000000, -0.850651, -0.525731},
|
||||
{-0.147621, -0.716567, -0.681718},
|
||||
{0.147621, -0.716567, -0.681718},
|
||||
{0.000000, -0.525731, -0.850651},
|
||||
{0.309017, -0.500000, -0.809017},
|
||||
{0.442863, -0.238856, -0.864188},
|
||||
{0.162460, -0.262866, -0.951056},
|
||||
{0.238856, -0.864188, -0.442863},
|
||||
{0.500000, -0.809017, -0.309017},
|
||||
{0.425325, -0.688191, -0.587785},
|
||||
{0.716567, -0.681718, -0.147621},
|
||||
{0.688191, -0.587785, -0.425325},
|
||||
{0.587785, -0.425325, -0.688191},
|
||||
{0.000000, -0.955423, -0.295242},
|
||||
{0.000000, -1.000000, 0.000000},
|
||||
{0.262866, -0.951056, -0.162460},
|
||||
{0.000000, -0.850651, 0.525731},
|
||||
{0.000000, -0.955423, 0.295242},
|
||||
{0.238856, -0.864188, 0.442863},
|
||||
{0.262866, -0.951056, 0.162460},
|
||||
{0.500000, -0.809017, 0.309017},
|
||||
{0.716567, -0.681718, 0.147621},
|
||||
{0.525731, -0.850651, 0.000000},
|
||||
{-0.238856, -0.864188, -0.442863},
|
||||
{-0.500000, -0.809017, -0.309017},
|
||||
{-0.262866, -0.951056, -0.162460},
|
||||
{-0.850651, -0.525731, 0.000000},
|
||||
{-0.716567, -0.681718, -0.147621},
|
||||
{-0.716567, -0.681718, 0.147621},
|
||||
{-0.525731, -0.850651, 0.000000},
|
||||
{-0.500000, -0.809017, 0.309017},
|
||||
{-0.238856, -0.864188, 0.442863},
|
||||
{-0.262866, -0.951056, 0.162460},
|
||||
{-0.864188, -0.442863, 0.238856},
|
||||
{-0.809017, -0.309017, 0.500000},
|
||||
{-0.688191, -0.587785, 0.425325},
|
||||
{-0.681718, -0.147621, 0.716567},
|
||||
{-0.442863, -0.238856, 0.864188},
|
||||
{-0.587785, -0.425325, 0.688191},
|
||||
{-0.309017, -0.500000, 0.809017},
|
||||
{-0.147621, -0.716567, 0.681718},
|
||||
{-0.425325, -0.688191, 0.587785},
|
||||
{-0.162460, -0.262866, 0.951056},
|
||||
{0.442863, -0.238856, 0.864188},
|
||||
{0.162460, -0.262866, 0.951056},
|
||||
{0.309017, -0.500000, 0.809017},
|
||||
{0.147621, -0.716567, 0.681718},
|
||||
{0.000000, -0.525731, 0.850651},
|
||||
{0.425325, -0.688191, 0.587785},
|
||||
{0.587785, -0.425325, 0.688191},
|
||||
{0.688191, -0.587785, 0.425325},
|
||||
{-0.955423, 0.295242, 0.000000},
|
||||
{-0.951056, 0.162460, 0.262866},
|
||||
{-1.000000, 0.000000, 0.000000},
|
||||
{-0.850651, 0.000000, 0.525731},
|
||||
{-0.955423, -0.295242, 0.000000},
|
||||
{-0.951056, -0.162460, 0.262866},
|
||||
{-0.864188, 0.442863, -0.238856},
|
||||
{-0.951056, 0.162460, -0.262866},
|
||||
{-0.809017, 0.309017, -0.500000},
|
||||
{-0.864188, -0.442863, -0.238856},
|
||||
{-0.951056, -0.162460, -0.262866},
|
||||
{-0.809017, -0.309017, -0.500000},
|
||||
{-0.681718, 0.147621, -0.716567},
|
||||
{-0.681718, -0.147621, -0.716567},
|
||||
{-0.850651, 0.000000, -0.525731},
|
||||
{-0.688191, 0.587785, -0.425325},
|
||||
{-0.587785, 0.425325, -0.688191},
|
||||
{-0.425325, 0.688191, -0.587785},
|
||||
{-0.425325, -0.688191, -0.587785},
|
||||
{-0.587785, -0.425325, -0.688191},
|
||||
{-0.688191, -0.587785, -0.425325},
|
763
tools/quake2/extra/qdata/images.c
Normal file
763
tools/quake2/extra/qdata/images.c
Normal file
|
@ -0,0 +1,763 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "qdata.h"
|
||||
|
||||
char mip_prefix[1024]; // directory to dump the textures in
|
||||
|
||||
qboolean colormap_issued;
|
||||
byte colormap_palette[768];
|
||||
|
||||
/*
|
||||
==============
|
||||
RemapZero
|
||||
|
||||
Replaces all 0 bytes in an image with the closest palette entry.
|
||||
This is because NT won't let us change index 0, so any palette
|
||||
animation leaves those pixels untouched.
|
||||
==============
|
||||
*/
|
||||
void RemapZero (byte *pixels, byte *palette, int width, int height)
|
||||
{
|
||||
int i, c;
|
||||
int alt_zero;
|
||||
int value, best;
|
||||
|
||||
alt_zero = 0;
|
||||
best = 9999999;
|
||||
for (i=1 ; i<255 ; i++)
|
||||
{
|
||||
value = palette[i*3+0]+palette[i*3+1]+palette[i*3+2];
|
||||
if (value < best)
|
||||
{
|
||||
best = value;
|
||||
alt_zero = i;
|
||||
}
|
||||
}
|
||||
|
||||
c = width*height;
|
||||
for (i=0 ; i<c ; i++)
|
||||
if (pixels[i] == 0)
|
||||
pixels[i] = alt_zero;
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
Cmd_Grab
|
||||
|
||||
$grab filename x y width height
|
||||
==============
|
||||
*/
|
||||
void Cmd_Grab (void)
|
||||
{
|
||||
int xl,yl,w,h,y;
|
||||
byte *cropped;
|
||||
char savename[1024];
|
||||
char dest[1024];
|
||||
|
||||
GetToken (false);
|
||||
|
||||
if (token[0] == '/' || token[0] == '\\')
|
||||
sprintf (savename, "%s%s.pcx", gamedir, token+1);
|
||||
else
|
||||
sprintf (savename, "%spics/%s.pcx", gamedir, token);
|
||||
|
||||
if (g_release)
|
||||
{
|
||||
if (token[0] == '/' || token[0] == '\\')
|
||||
sprintf (dest, "%s.pcx", token+1);
|
||||
else
|
||||
sprintf (dest, "pics/%s.pcx", token);
|
||||
|
||||
ReleaseFile (dest);
|
||||
return;
|
||||
}
|
||||
|
||||
GetToken (false);
|
||||
xl = atoi (token);
|
||||
GetToken (false);
|
||||
yl = atoi (token);
|
||||
GetToken (false);
|
||||
w = atoi (token);
|
||||
GetToken (false);
|
||||
h = atoi (token);
|
||||
|
||||
if (xl<0 || yl<0 || w<0 || h<0 || xl+w>byteimagewidth || yl+h>byteimageheight)
|
||||
Error ("GrabPic: Bad size: %i, %i, %i, %i",xl,yl,w,h);
|
||||
|
||||
// crop it to the proper size
|
||||
cropped = malloc (w*h);
|
||||
for (y=0 ; y<h ; y++)
|
||||
{
|
||||
memcpy (cropped+y*w, byteimage+(y+yl)*byteimagewidth+xl, w);
|
||||
}
|
||||
|
||||
// save off the new image
|
||||
printf ("saving %s\n", savename);
|
||||
CreatePath (savename);
|
||||
WritePCXfile (savename, cropped, w, h, lbmpalette);
|
||||
|
||||
free (cropped);
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
Cmd_Raw
|
||||
|
||||
$grab filename x y width height
|
||||
==============
|
||||
*/
|
||||
void Cmd_Raw (void)
|
||||
{
|
||||
int xl,yl,w,h,y;
|
||||
byte *cropped;
|
||||
char savename[1024];
|
||||
char dest[1024];
|
||||
|
||||
GetToken (false);
|
||||
|
||||
sprintf (savename, "%s%s.lmp", gamedir, token);
|
||||
|
||||
if (g_release)
|
||||
{
|
||||
sprintf (dest, "%s.lmp", token);
|
||||
ReleaseFile (dest);
|
||||
return;
|
||||
}
|
||||
|
||||
GetToken (false);
|
||||
xl = atoi (token);
|
||||
GetToken (false);
|
||||
yl = atoi (token);
|
||||
GetToken (false);
|
||||
w = atoi (token);
|
||||
GetToken (false);
|
||||
h = atoi (token);
|
||||
|
||||
if (xl<0 || yl<0 || w<0 || h<0 || xl+w>byteimagewidth || yl+h>byteimageheight)
|
||||
Error ("GrabPic: Bad size: %i, %i, %i, %i",xl,yl,w,h);
|
||||
|
||||
// crop it to the proper size
|
||||
cropped = malloc (w*h);
|
||||
for (y=0 ; y<h ; y++)
|
||||
{
|
||||
memcpy (cropped+y*w, byteimage+(y+yl)*byteimagewidth+xl, w);
|
||||
}
|
||||
|
||||
// save off the new image
|
||||
printf ("saving %s\n", savename);
|
||||
CreatePath (savename);
|
||||
|
||||
SaveFile (savename, cropped, w*h);
|
||||
|
||||
free (cropped);
|
||||
}
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
COLORMAP GRABBING
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
===============
|
||||
BestColor
|
||||
===============
|
||||
*/
|
||||
byte BestColor (int r, int g, int b, int start, int stop)
|
||||
{
|
||||
int i;
|
||||
int dr, dg, db;
|
||||
int bestdistortion, distortion;
|
||||
int bestcolor;
|
||||
byte *pal;
|
||||
|
||||
//
|
||||
// let any color go to 0 as a last resort
|
||||
//
|
||||
bestdistortion = 256*256*4;
|
||||
bestcolor = 0;
|
||||
|
||||
pal = colormap_palette + start*3;
|
||||
for (i=start ; i<= stop ; i++)
|
||||
{
|
||||
dr = r - (int)pal[0];
|
||||
dg = g - (int)pal[1];
|
||||
db = b - (int)pal[2];
|
||||
pal += 3;
|
||||
distortion = dr*dr + dg*dg + db*db;
|
||||
if (distortion < bestdistortion)
|
||||
{
|
||||
if (!distortion)
|
||||
return i; // perfect match
|
||||
|
||||
bestdistortion = distortion;
|
||||
bestcolor = i;
|
||||
}
|
||||
}
|
||||
|
||||
return bestcolor;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
Cmd_Colormap
|
||||
|
||||
$colormap filename
|
||||
|
||||
the brightes colormap is first in the table (FIXME: reverse this now?)
|
||||
|
||||
64 rows of 256 : lightmaps
|
||||
256 rows of 256 : translucency table
|
||||
==============
|
||||
*/
|
||||
void Cmd_Colormap (void)
|
||||
{
|
||||
int levels, brights;
|
||||
int l, c;
|
||||
float frac, red, green, blue;
|
||||
float range;
|
||||
byte *cropped, *lump_p;
|
||||
char savename[1024];
|
||||
char dest[1024];
|
||||
|
||||
colormap_issued = true;
|
||||
if (!g_release)
|
||||
memcpy (colormap_palette, lbmpalette, 768);
|
||||
|
||||
if (!TokenAvailable ())
|
||||
{ // just setting colormap_issued
|
||||
return;
|
||||
}
|
||||
|
||||
GetToken (false);
|
||||
sprintf (savename, "%spics/%s.pcx", gamedir, token);
|
||||
|
||||
if (g_release)
|
||||
{
|
||||
sprintf (dest, "pics/%s.pcx", token);
|
||||
ReleaseFile (dest);
|
||||
return;
|
||||
}
|
||||
|
||||
range = 2;
|
||||
levels = 64;
|
||||
brights = 1; // ignore 255 (transparent)
|
||||
|
||||
cropped = malloc((levels+256)*256);
|
||||
lump_p = cropped;
|
||||
|
||||
// shaded levels
|
||||
for (l=0;l<levels;l++)
|
||||
{
|
||||
frac = range - range*(float)l/(levels-1);
|
||||
for (c=0 ; c<256-brights ; c++)
|
||||
{
|
||||
red = lbmpalette[c*3];
|
||||
green = lbmpalette[c*3+1];
|
||||
blue = lbmpalette[c*3+2];
|
||||
|
||||
red = (int)(red*frac+0.5);
|
||||
green = (int)(green*frac+0.5);
|
||||
blue = (int)(blue*frac+0.5);
|
||||
|
||||
//
|
||||
// note: 254 instead of 255 because 255 is the transparent color, and we
|
||||
// don't want anything remapping to that
|
||||
// don't use color 0, because NT can't remap that (or 255)
|
||||
//
|
||||
*lump_p++ = BestColor(red,green,blue, 1, 254);
|
||||
}
|
||||
|
||||
// fullbrights allways stay the same
|
||||
for ( ; c<256 ; c++)
|
||||
*lump_p++ = c;
|
||||
}
|
||||
|
||||
// 66% transparancy table
|
||||
for (l=0;l<255;l++)
|
||||
{
|
||||
for (c=0 ; c<255 ; c++)
|
||||
{
|
||||
red = lbmpalette[c*3]*0.33 + lbmpalette[l*3]*0.66;
|
||||
green = lbmpalette[c*3+1]*0.33 + lbmpalette[l*3+1]*0.66;
|
||||
blue = lbmpalette[c*3+2]*0.33 + lbmpalette[l*3+2]*0.66;
|
||||
|
||||
*lump_p++ = BestColor(red,green,blue, 1, 254);
|
||||
}
|
||||
*lump_p++ = 255;
|
||||
}
|
||||
for (c=0 ; c<256 ; c++)
|
||||
*lump_p++ = 255;
|
||||
|
||||
// save off the new image
|
||||
printf ("saving %s\n", savename);
|
||||
CreatePath (savename);
|
||||
WritePCXfile (savename, cropped, 256, levels+256, lbmpalette);
|
||||
|
||||
free (cropped);
|
||||
}
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
MIPTEX GRABBING
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
byte pixdata[256];
|
||||
|
||||
int d_red, d_green, d_blue;
|
||||
|
||||
byte palmap[32][32][32];
|
||||
qboolean palmap_built;
|
||||
|
||||
/*
|
||||
=============
|
||||
FindColor
|
||||
=============
|
||||
*/
|
||||
int FindColor (int r, int g, int b)
|
||||
{
|
||||
int bestcolor;
|
||||
|
||||
if (r > 255)
|
||||
r = 255;
|
||||
if (r < 0)
|
||||
r = 0;
|
||||
if (g > 255)
|
||||
g = 255;
|
||||
if (g < 0)
|
||||
g = 0;
|
||||
if (b > 255)
|
||||
b = 255;
|
||||
if (b < 0)
|
||||
b = 0;
|
||||
#ifndef TABLECOLORS
|
||||
bestcolor = BestColor (r, g, b, 0, 254);
|
||||
#else
|
||||
bestcolor = palmap[r>>3][g>>3][b>>3];
|
||||
#endif
|
||||
|
||||
return bestcolor;
|
||||
}
|
||||
|
||||
|
||||
void BuildPalmap (void)
|
||||
{
|
||||
#ifdef TABLECOLORS
|
||||
int r, g, b;
|
||||
int bestcolor;
|
||||
|
||||
if (palmap_built)
|
||||
return;
|
||||
palmap_built = true;
|
||||
|
||||
for (r=4 ; r<256 ; r+=8)
|
||||
{
|
||||
for (g=4 ; g<256 ; g+=8)
|
||||
{
|
||||
for (b=4 ; b<256 ; b+=8)
|
||||
{
|
||||
bestcolor = BestColor (r, g, b, 1, 254);
|
||||
palmap[r>>3][g>>3][b>>3] = bestcolor;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!colormap_issued)
|
||||
Error ("You must issue a $colormap command first");
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
AveragePixels
|
||||
=============
|
||||
*/
|
||||
byte AveragePixels (int count)
|
||||
{
|
||||
int r,g,b;
|
||||
int i;
|
||||
int vis;
|
||||
int pix;
|
||||
int bestcolor;
|
||||
byte *pal;
|
||||
int fullbright;
|
||||
|
||||
vis = 0;
|
||||
r = g = b = 0;
|
||||
fullbright = 0;
|
||||
for (i=0 ; i<count ; i++)
|
||||
{
|
||||
pix = pixdata[i];
|
||||
|
||||
r += lbmpalette[pix*3];
|
||||
g += lbmpalette[pix*3+1];
|
||||
b += lbmpalette[pix*3+2];
|
||||
vis++;
|
||||
}
|
||||
|
||||
r /= vis;
|
||||
g /= vis;
|
||||
b /= vis;
|
||||
|
||||
// error diffusion
|
||||
r += d_red;
|
||||
g += d_green;
|
||||
b += d_blue;
|
||||
|
||||
//
|
||||
// find the best color
|
||||
//
|
||||
bestcolor = FindColor (r, g, b);
|
||||
|
||||
// error diffusion
|
||||
pal = colormap_palette + bestcolor*3;
|
||||
d_red = r - (int)pal[0];
|
||||
d_green = g - (int)pal[1];
|
||||
d_blue = b - (int)pal[2];
|
||||
|
||||
return bestcolor;
|
||||
}
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
pt_contents,
|
||||
pt_flags,
|
||||
pt_animvalue,
|
||||
pt_flagvalue
|
||||
} parmtype_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *name;
|
||||
int flags;
|
||||
parmtype_t type;
|
||||
} mipparm_t;
|
||||
|
||||
mipparm_t mipparms[] =
|
||||
{
|
||||
// utility content attributes
|
||||
{"water", CONTENTS_WATER, pt_contents},
|
||||
{"slime", CONTENTS_SLIME, pt_contents}, // mildly damaging
|
||||
{"lava", CONTENTS_LAVA, pt_contents}, // very damaging
|
||||
{"window", CONTENTS_WINDOW, pt_contents}, // solid, but doesn't eat internal textures
|
||||
{"mist", CONTENTS_MIST, pt_contents}, // non-solid window
|
||||
{"origin", CONTENTS_ORIGIN, pt_contents}, // center of rotating brushes
|
||||
{"playerclip", CONTENTS_PLAYERCLIP, pt_contents},
|
||||
{"monsterclip", CONTENTS_MONSTERCLIP, pt_contents},
|
||||
|
||||
// utility surface attributes
|
||||
{"hint", SURF_HINT, pt_flags},
|
||||
{"skip", SURF_SKIP, pt_flags},
|
||||
{"light", SURF_LIGHT, pt_flagvalue}, // value is the light quantity
|
||||
|
||||
// texture chaining
|
||||
{"anim", 0, pt_animvalue}, // value is the next animation
|
||||
|
||||
// server attributes
|
||||
{"slick", SURF_SLICK, pt_flags},
|
||||
|
||||
// drawing attributes
|
||||
{"sky", SURF_SKY, pt_flags},
|
||||
{"warping", SURF_WARP, pt_flags}, // only valid with 64x64 textures
|
||||
{"trans33", SURF_TRANS33, pt_flags}, // translucent should allso set fullbright
|
||||
{"trans66", SURF_TRANS66, pt_flags},
|
||||
{"flowing", SURF_FLOWING, pt_flags}, // flow direction towards angle 0
|
||||
{"nodraw", SURF_NODRAW, pt_flags}, // for clip textures and trigger textures
|
||||
|
||||
{NULL, 0, pt_contents}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
Cmd_Mip
|
||||
|
||||
$mip filename x y width height <OPTIONS>
|
||||
must be multiples of sixteen
|
||||
SURF_WINDOW
|
||||
==============
|
||||
*/
|
||||
void Cmd_Mip (void)
|
||||
{
|
||||
int x,y,xl,yl,xh,yh,w,h;
|
||||
byte *screen_p, *source;
|
||||
int linedelta;
|
||||
miptex_t *qtex;
|
||||
int miplevel, mipstep;
|
||||
int xx, yy, pix;
|
||||
int count;
|
||||
int flags, value, contents;
|
||||
mipparm_t *mp;
|
||||
char lumpname[64];
|
||||
byte *lump_p;
|
||||
char filename[1024];
|
||||
char animname[64];
|
||||
|
||||
GetToken (false);
|
||||
strcpy (lumpname, token);
|
||||
|
||||
GetToken (false);
|
||||
xl = atoi (token);
|
||||
GetToken (false);
|
||||
yl = atoi (token);
|
||||
GetToken (false);
|
||||
w = atoi (token);
|
||||
GetToken (false);
|
||||
h = atoi (token);
|
||||
|
||||
if ( (w & 15) || (h & 15) )
|
||||
Error ("line %i: miptex sizes must be multiples of 16", scriptline);
|
||||
|
||||
flags = 0;
|
||||
contents = 0;
|
||||
value = 0;
|
||||
|
||||
animname[0] = 0;
|
||||
|
||||
// get optional flags and values
|
||||
while (TokenAvailable ())
|
||||
{
|
||||
GetToken (false);
|
||||
|
||||
for (mp=mipparms ; mp->name ; mp++)
|
||||
{
|
||||
if (!strcmp(mp->name, token))
|
||||
{
|
||||
switch (mp->type)
|
||||
{
|
||||
case pt_animvalue:
|
||||
GetToken (false); // specify the next animation frame
|
||||
strcpy (animname, token);
|
||||
break;
|
||||
case pt_flags:
|
||||
flags |= mp->flags;
|
||||
break;
|
||||
case pt_contents:
|
||||
contents |= mp->flags;
|
||||
break;
|
||||
case pt_flagvalue:
|
||||
flags |= mp->flags;
|
||||
GetToken (false); // specify the light value
|
||||
value = atoi(token);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!mp->name)
|
||||
Error ("line %i: unknown parm %s", scriptline, token);
|
||||
}
|
||||
|
||||
sprintf (filename, "%stextures/%s/%s.wal", gamedir, mip_prefix, lumpname);
|
||||
if (g_release)
|
||||
return; // textures are only released by $maps
|
||||
|
||||
xh = xl+w;
|
||||
yh = yl+h;
|
||||
|
||||
qtex = malloc (sizeof(miptex_t) + w*h*2);
|
||||
memset (qtex, 0, sizeof(miptex_t));
|
||||
|
||||
qtex->width = LittleLong(w);
|
||||
qtex->height = LittleLong(h);
|
||||
qtex->flags = LittleLong(flags);
|
||||
qtex->contents = LittleLong(contents);
|
||||
qtex->value = LittleLong(value);
|
||||
sprintf (qtex->name, "%s/%s", mip_prefix, lumpname);
|
||||
if (animname[0])
|
||||
sprintf (qtex->animname, "%s/%s", mip_prefix, animname);
|
||||
|
||||
lump_p = (byte *)(&qtex->value+1);
|
||||
|
||||
screen_p = byteimage + yl*byteimagewidth + xl;
|
||||
linedelta = byteimagewidth - w;
|
||||
|
||||
source = lump_p;
|
||||
qtex->offsets[0] = LittleLong(lump_p - (byte *)qtex);
|
||||
|
||||
for (y=yl ; y<yh ; y++)
|
||||
{
|
||||
for (x=xl ; x<xh ; x++)
|
||||
{
|
||||
pix = *screen_p++;
|
||||
if (pix == 255)
|
||||
pix = 1; // should never happen
|
||||
*lump_p++ = pix;
|
||||
}
|
||||
screen_p += linedelta;
|
||||
}
|
||||
|
||||
//
|
||||
// subsample for greater mip levels
|
||||
//
|
||||
d_red = d_green = d_blue = 0; // no distortion yet
|
||||
|
||||
for (miplevel = 1 ; miplevel<4 ; miplevel++)
|
||||
{
|
||||
qtex->offsets[miplevel] = LittleLong(lump_p - (byte *)qtex);
|
||||
|
||||
mipstep = 1<<miplevel;
|
||||
for (y=0 ; y<h ; y+=mipstep)
|
||||
{
|
||||
|
||||
for (x = 0 ; x<w ; x+= mipstep)
|
||||
{
|
||||
count = 0;
|
||||
for (yy=0 ; yy<mipstep ; yy++)
|
||||
for (xx=0 ; xx<mipstep ; xx++)
|
||||
{
|
||||
pixdata[count] = source[ (y+yy)*w + x + xx ];
|
||||
count++;
|
||||
}
|
||||
*lump_p++ = AveragePixels (count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// dword align the size
|
||||
//
|
||||
while ((int)lump_p&3)
|
||||
*lump_p++ = 0;
|
||||
|
||||
//
|
||||
// write it out
|
||||
//
|
||||
printf ("writing %s\n", filename);
|
||||
SaveFile (filename, (byte *)qtex, lump_p - (byte *)qtex);
|
||||
|
||||
free (qtex);
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
Cmd_Mippal
|
||||
===============
|
||||
*/
|
||||
void Cmd_Mippal (void)
|
||||
{
|
||||
colormap_issued = true;
|
||||
if (g_release)
|
||||
return;
|
||||
|
||||
memcpy (colormap_palette, lbmpalette, 768);
|
||||
|
||||
BuildPalmap();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
Cmd_Mipdir
|
||||
===============
|
||||
*/
|
||||
void Cmd_Mipdir (void)
|
||||
{
|
||||
char filename[1024];
|
||||
|
||||
GetToken (false);
|
||||
strcpy (mip_prefix, token);
|
||||
// create the directory if needed
|
||||
sprintf (filename, "%stextures", gamedir, mip_prefix);
|
||||
Q_mkdir (filename);
|
||||
sprintf (filename, "%stextures/%s", gamedir, mip_prefix);
|
||||
Q_mkdir (filename);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
ENVIRONMENT MAP GRABBING
|
||||
|
||||
Creates six pcx files from tga files without any palette edge seams
|
||||
also copies the tga files for GL rendering.
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
// 3dstudio environment map suffixes
|
||||
char *suf[6] = {"rt", "ft", "lf", "bk", "up", "dn"};
|
||||
|
||||
/*
|
||||
=================
|
||||
Cmd_Environment
|
||||
=================
|
||||
*/
|
||||
void Cmd_Environment (void)
|
||||
{
|
||||
char name[1024];
|
||||
int i, x, y;
|
||||
byte image[256*256];
|
||||
byte *tga;
|
||||
|
||||
GetToken (false);
|
||||
|
||||
if (g_release)
|
||||
{
|
||||
for (i=0 ; i<6 ; i++)
|
||||
{
|
||||
sprintf (name, "env/%s%s.pcx", token, suf[i]);
|
||||
ReleaseFile (name);
|
||||
sprintf (name, "env/%s%s.tga", token, suf[i]);
|
||||
ReleaseFile (name);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// get the palette
|
||||
BuildPalmap ();
|
||||
|
||||
sprintf (name, "%senv/", gamedir);
|
||||
CreatePath (name);
|
||||
|
||||
// convert the images
|
||||
for (i=0 ; i<6 ; i++)
|
||||
{
|
||||
sprintf (name, "%senv/%s%s.tga", gamedir, token, suf[i]);
|
||||
printf ("loading %s...\n", name);
|
||||
LoadTGA (name, &tga, NULL, NULL);
|
||||
|
||||
for (y=0 ; y<256 ; y++)
|
||||
{
|
||||
for (x=0 ; x<256 ; x++)
|
||||
{
|
||||
image[y*256+x] = FindColor (tga[(y*256+x)*4+0],tga[(y*256+x)*4+1],tga[(y*256+x)*4+2]);
|
||||
}
|
||||
}
|
||||
free (tga);
|
||||
sprintf (name, "%senv/%s%s.pcx", gamedir, token, suf[i]);
|
||||
if (FileTime (name) != -1)
|
||||
printf ("%s already exists, not overwriting.\n", name);
|
||||
else
|
||||
WritePCXfile (name, image, 256, 256, colormap_palette);
|
||||
}
|
||||
}
|
||||
|
81
tools/quake2/extra/qdata/makefile
Normal file
81
tools/quake2/extra/qdata/makefile
Normal file
|
@ -0,0 +1,81 @@
|
|||
|
||||
CFLAGS = -c
|
||||
LDFLAGS =
|
||||
ODIR = baddir
|
||||
|
||||
EXEBASE = qdata
|
||||
EXE = $(ODIR)/qdata
|
||||
all: $(EXE)
|
||||
|
||||
_next:
|
||||
make "CFLAGS = -c -g -I../common" "ODIR = next"
|
||||
|
||||
_irix:
|
||||
make "CFLAGS = -c -Ofast=ip32_10k -I../common -Xcpluscomm" "LDFLAGS = -Ofast=ip32_10k" "ODIR = irix"
|
||||
|
||||
_irixdebug:
|
||||
make "CFLAGS = -c -O2 -g -I../common -Xcpluscomm" "LDFLAGS = -g" "ODIR = irix"
|
||||
|
||||
_irixinst:
|
||||
make "CFLAGS = -c -Ofast=ip32_10k -I../common -Xcpluscomm" "LDFLAGS = -Ofast=ip32_10k" "ODIR = irix"
|
||||
cp irix/$(EXEBASE) /limbo/quake/bin_irix
|
||||
|
||||
_irixclean:
|
||||
rm -f irix/*.o irix/$(EXEBASE)
|
||||
|
||||
_osf:
|
||||
make "CFLAGS = -c -O4 -I../common -threads" "LDFLAGS = -threads" "ODIR = osf"
|
||||
|
||||
clean:
|
||||
rm -f next/*.o next/$(EXEBASE)
|
||||
rm -f osf/*.o osf/$(EXEBASE)
|
||||
rm -f irix/*.o irix/$(EXEBASE)
|
||||
|
||||
install:
|
||||
cp next/$(EXEBASE) /limbo/quake2/bin_next
|
||||
cp osf/$(EXEBASE) /limbo/quake2/bin_osf
|
||||
cp irix/$(EXEBASE) /limbo/quake2/bin_irix
|
||||
|
||||
|
||||
FILES = $(ODIR)/qdata.o $(ODIR)/models.o $(ODIR)/sprites.o $(ODIR)/images.o $(ODIR)/cmdlib.o $(ODIR)/scriplib.o $(ODIR)/lbmlib.o $(ODIR)/mathlib.o $(ODIR)/l3dslib.o $(ODIR)/trilib.o $(ODIR)/threads.o $(ODIR)/tables.o
|
||||
|
||||
$(EXE) : $(FILES)
|
||||
cc -o $(EXE) $(LDFLAGS) $(FILES) -lm
|
||||
|
||||
$(ODIR)/qdata.o : qdata.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/models.o : models.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/sprites.o : sprites.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/images.o : images.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/tables.o : tables.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/cmdlib.o : ../common/cmdlib.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/scriplib.o : ../common/scriplib.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/lbmlib.o : ../common/lbmlib.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/mathlib.o : ../common/mathlib.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/trilib.o : ../common/trilib.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/l3dslib.o : ../common/l3dslib.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/threads.o : ../common/threads.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
1152
tools/quake2/extra/qdata/models.c
Normal file
1152
tools/quake2/extra/qdata/models.c
Normal file
File diff suppressed because it is too large
Load diff
551
tools/quake2/extra/qdata/qdata.c
Normal file
551
tools/quake2/extra/qdata/qdata.c
Normal file
|
@ -0,0 +1,551 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "qdata.h"
|
||||
|
||||
qboolean g_compress_pak;
|
||||
qboolean g_release; // don't grab, copy output data to new tree
|
||||
qboolean g_pak; // if true, copy to pak instead of release
|
||||
char g_releasedir[1024]; // c:\quake2\baseq2, etc
|
||||
qboolean g_archive; // don't grab, copy source data to new tree
|
||||
qboolean do3ds;
|
||||
char g_only[256]; // if set, only grab this cd
|
||||
qboolean g_skipmodel; // set true when a cd is not g_only
|
||||
|
||||
char *ext_3ds = "3ds";
|
||||
char *ext_tri= "tri";
|
||||
char *trifileext;
|
||||
|
||||
/*
|
||||
=======================================================
|
||||
|
||||
PAK FILES
|
||||
|
||||
=======================================================
|
||||
*/
|
||||
|
||||
unsigned Com_BlockChecksum (void *buffer, int length);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char name[56];
|
||||
int filepos, filelen;
|
||||
} packfile_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char id[4];
|
||||
int dirofs;
|
||||
int dirlen;
|
||||
} packheader_t;
|
||||
|
||||
packfile_t pfiles[16384];
|
||||
FILE *pakfile;
|
||||
packfile_t *pf;
|
||||
packheader_t pakheader;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
BeginPak
|
||||
==============
|
||||
*/
|
||||
void BeginPak (char *outname)
|
||||
{
|
||||
if (!g_pak)
|
||||
return;
|
||||
|
||||
pakfile = SafeOpenWrite (outname);
|
||||
|
||||
// leave space for header
|
||||
SafeWrite (pakfile, &pakheader, sizeof(pakheader));
|
||||
|
||||
pf = pfiles;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
ReleaseFile
|
||||
|
||||
Filename should be gamedir reletive.
|
||||
Either copies the file to the release dir, or adds it to
|
||||
the pak file.
|
||||
==============
|
||||
*/
|
||||
void ReleaseFile (char *filename)
|
||||
{
|
||||
int len;
|
||||
byte *buf;
|
||||
char source[1024];
|
||||
char dest[1024];
|
||||
|
||||
if (!g_release)
|
||||
return;
|
||||
|
||||
sprintf (source, "%s%s", gamedir, filename);
|
||||
|
||||
if (!g_pak)
|
||||
{ // copy it
|
||||
sprintf (dest, "%s/%s", g_releasedir, filename);
|
||||
printf ("copying to %s\n", dest);
|
||||
QCopyFile (source, dest);
|
||||
return;
|
||||
}
|
||||
|
||||
// pak it
|
||||
printf ("paking %s\n", filename);
|
||||
if (strlen(filename) >= sizeof(pf->name))
|
||||
Error ("Filename too long for pak: %s", filename);
|
||||
|
||||
len = LoadFile (source, (void **)&buf);
|
||||
|
||||
if (g_compress_pak && len < 4096*1024 )
|
||||
{
|
||||
cblock_t in, out;
|
||||
cblock_t Huffman (cblock_t in);
|
||||
|
||||
in.count = len;
|
||||
in.data = buf;
|
||||
|
||||
out = Huffman (in);
|
||||
|
||||
if (out.count < in.count)
|
||||
{
|
||||
printf (" compressed from %i to %i\n", in.count, out.count);
|
||||
free (in.data);
|
||||
buf = out.data;
|
||||
len = out.count;
|
||||
}
|
||||
else
|
||||
free (out.data);
|
||||
}
|
||||
|
||||
strcpy (pf->name, filename);
|
||||
pf->filepos = LittleLong(ftell(pakfile));
|
||||
pf->filelen = LittleLong(len);
|
||||
pf++;
|
||||
|
||||
SafeWrite (pakfile, buf, len);
|
||||
|
||||
free (buf);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
FinishPak
|
||||
==============
|
||||
*/
|
||||
void FinishPak (void)
|
||||
{
|
||||
int dirlen;
|
||||
int d;
|
||||
int i;
|
||||
unsigned checksum;
|
||||
|
||||
if (!g_pak)
|
||||
return;
|
||||
|
||||
pakheader.id[0] = 'P';
|
||||
pakheader.id[1] = 'A';
|
||||
pakheader.id[2] = 'C';
|
||||
pakheader.id[3] = 'K';
|
||||
dirlen = (byte *)pf - (byte *)pfiles;
|
||||
pakheader.dirofs = LittleLong(ftell(pakfile));
|
||||
pakheader.dirlen = LittleLong(dirlen);
|
||||
|
||||
checksum = Com_BlockChecksum ( (void *)pfiles, dirlen );
|
||||
|
||||
SafeWrite (pakfile, pfiles, dirlen);
|
||||
|
||||
i = ftell (pakfile);
|
||||
|
||||
fseek (pakfile, 0, SEEK_SET);
|
||||
SafeWrite (pakfile, &pakheader, sizeof(pakheader));
|
||||
fclose (pakfile);
|
||||
|
||||
d = pf - pfiles;
|
||||
printf ("%i files packed in %i bytes\n",d, i);
|
||||
printf ("checksum: 0x%x\n", checksum);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
Cmd_File
|
||||
|
||||
This is only used to cause a file to be copied during a release
|
||||
build (default.cfg, maps, etc)
|
||||
===============
|
||||
*/
|
||||
void Cmd_File (void)
|
||||
{
|
||||
GetToken (false);
|
||||
ReleaseFile (token);
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
PackDirectory_r
|
||||
|
||||
===============
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
#include "io.h"
|
||||
void PackDirectory_r (char *dir)
|
||||
{
|
||||
struct _finddata_t fileinfo;
|
||||
int handle;
|
||||
char dirstring[1024];
|
||||
char filename[1024];
|
||||
|
||||
sprintf (dirstring, "%s%s/*.*", gamedir, dir);
|
||||
|
||||
handle = _findfirst (dirstring, &fileinfo);
|
||||
if (handle == -1)
|
||||
return;
|
||||
|
||||
do
|
||||
{
|
||||
sprintf (filename, "%s/%s", dir, fileinfo.name);
|
||||
if (fileinfo.attrib & _A_SUBDIR)
|
||||
{ // directory
|
||||
if (fileinfo.name[0] != '.') // don't pak . and ..
|
||||
PackDirectory_r (filename);
|
||||
continue;
|
||||
}
|
||||
// copy or pack the file
|
||||
ReleaseFile (filename);
|
||||
} while (_findnext( handle, &fileinfo ) != -1);
|
||||
|
||||
_findclose (handle);
|
||||
}
|
||||
#else
|
||||
|
||||
#include <sys/types.h>
|
||||
#ifdef NeXT
|
||||
#include <sys/dir.h>
|
||||
#else
|
||||
#include <sys/dirent.h>
|
||||
#endif
|
||||
|
||||
void PackDirectory_r (char *dir)
|
||||
{
|
||||
#ifdef NeXT
|
||||
struct direct **namelist, *ent;
|
||||
#else
|
||||
struct dirent **namelist, *ent;
|
||||
#endif
|
||||
int count;
|
||||
struct stat st;
|
||||
int i;
|
||||
int len;
|
||||
char fullname[1024];
|
||||
char dirstring[1024];
|
||||
char *name;
|
||||
|
||||
sprintf (dirstring, "%s%s", gamedir, dir);
|
||||
count = scandir(dirstring, &namelist, NULL, NULL);
|
||||
|
||||
for (i=0 ; i<count ; i++)
|
||||
{
|
||||
ent = namelist[i];
|
||||
name = ent->d_name;
|
||||
|
||||
if (name[0] == '.')
|
||||
continue;
|
||||
|
||||
sprintf (fullname, "%s/%s", dir, name);
|
||||
sprintf (dirstring, "%s%s/%s", gamedir, dir, name);
|
||||
|
||||
if (stat (dirstring, &st) == -1)
|
||||
Error ("fstating %s", pf->name);
|
||||
if (st.st_mode & S_IFDIR)
|
||||
{ // directory
|
||||
PackDirectory_r (fullname);
|
||||
continue;
|
||||
}
|
||||
|
||||
// copy or pack the file
|
||||
ReleaseFile (fullname);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
Cmd_Dir
|
||||
|
||||
This is only used to cause a directory to be copied during a
|
||||
release build (sounds, etc)
|
||||
===============
|
||||
*/
|
||||
void Cmd_Dir (void)
|
||||
{
|
||||
GetToken (false);
|
||||
PackDirectory_r (token);
|
||||
}
|
||||
|
||||
//========================================================================
|
||||
|
||||
#define MAX_RTEX 16384
|
||||
int numrtex;
|
||||
char rtex[MAX_RTEX][64];
|
||||
|
||||
void ReleaseTexture (char *name)
|
||||
{
|
||||
int i;
|
||||
char path[1024];
|
||||
|
||||
for (i=0 ; i<numrtex ; i++)
|
||||
if (!Q_strcasecmp(name, rtex[i]))
|
||||
return;
|
||||
|
||||
if (numrtex == MAX_RTEX)
|
||||
Error ("numrtex == MAX_RTEX");
|
||||
|
||||
strcpy (rtex[i], name);
|
||||
numrtex++;
|
||||
|
||||
sprintf (path, "textures/%s.wal", name);
|
||||
ReleaseFile (path);
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
Cmd_Maps
|
||||
|
||||
Only relevent for release and pak files.
|
||||
Releases the .bsp files for the maps, and scans all of the files to
|
||||
build a list of all textures used, which are then released.
|
||||
===============
|
||||
*/
|
||||
void Cmd_Maps (void)
|
||||
{
|
||||
char map[1024];
|
||||
int i;
|
||||
|
||||
while (TokenAvailable ())
|
||||
{
|
||||
GetToken (false);
|
||||
sprintf (map, "maps/%s.bsp", token);
|
||||
ReleaseFile (map);
|
||||
|
||||
if (!g_release)
|
||||
continue;
|
||||
|
||||
// get all the texture references
|
||||
sprintf (map, "%smaps/%s.bsp", gamedir, token);
|
||||
LoadBSPFileTexinfo (map);
|
||||
for (i=0 ; i<numtexinfo ; i++)
|
||||
ReleaseTexture (texinfo[i].texture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==============================================================
|
||||
|
||||
/*
|
||||
===============
|
||||
ParseScript
|
||||
===============
|
||||
*/
|
||||
void ParseScript (void)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
do
|
||||
{ // look for a line starting with a $ command
|
||||
GetToken (true);
|
||||
if (endofscript)
|
||||
return;
|
||||
if (token[0] == '$')
|
||||
break;
|
||||
while (TokenAvailable())
|
||||
GetToken (false);
|
||||
} while (1);
|
||||
|
||||
//
|
||||
// model commands
|
||||
//
|
||||
if (!strcmp (token, "$modelname"))
|
||||
Cmd_Modelname ();
|
||||
else if (!strcmp (token, "$base"))
|
||||
Cmd_Base ();
|
||||
else if (!strcmp (token, "$cd"))
|
||||
Cmd_Cd ();
|
||||
else if (!strcmp (token, "$origin"))
|
||||
Cmd_Origin ();
|
||||
else if (!strcmp (token, "$scale"))
|
||||
Cmd_ScaleUp ();
|
||||
else if (!strcmp (token, "$frame"))
|
||||
Cmd_Frame ();
|
||||
else if (!strcmp (token, "$skin"))
|
||||
Cmd_Skin ();
|
||||
else if (!strcmp (token, "$skinsize"))
|
||||
Cmd_Skinsize ();
|
||||
//
|
||||
// sprite commands
|
||||
//
|
||||
else if (!strcmp (token, "$spritename"))
|
||||
Cmd_SpriteName ();
|
||||
else if (!strcmp (token, "$load"))
|
||||
Cmd_Load ();
|
||||
else if (!strcmp (token, "$spriteframe"))
|
||||
Cmd_SpriteFrame ();
|
||||
//
|
||||
// image commands
|
||||
//
|
||||
else if (!strcmp (token, "$grab"))
|
||||
Cmd_Grab ();
|
||||
else if (!strcmp (token, "$raw"))
|
||||
Cmd_Raw ();
|
||||
else if (!strcmp (token, "$colormap"))
|
||||
Cmd_Colormap ();
|
||||
else if (!strcmp (token, "$mippal"))
|
||||
Cmd_Mippal ();
|
||||
else if (!strcmp (token, "$mipdir"))
|
||||
Cmd_Mipdir ();
|
||||
else if (!strcmp (token, "$mip"))
|
||||
Cmd_Mip ();
|
||||
else if (!strcmp (token, "$environment"))
|
||||
Cmd_Environment ();
|
||||
//
|
||||
// video
|
||||
//
|
||||
else if (!strcmp (token, "$video"))
|
||||
Cmd_Video ();
|
||||
//
|
||||
// misc
|
||||
//
|
||||
else if (!strcmp (token, "$file"))
|
||||
Cmd_File ();
|
||||
else if (!strcmp (token, "$dir"))
|
||||
Cmd_Dir ();
|
||||
else if (!strcmp (token, "$maps"))
|
||||
Cmd_Maps ();
|
||||
else if (!strcmp (token, "$alphalight"))
|
||||
Cmd_Alphalight ();
|
||||
else if (!strcmp (token, "$inverse16table" ))
|
||||
Cmd_Inverse16Table();
|
||||
else
|
||||
Error ("bad command %s\n", token);
|
||||
}
|
||||
}
|
||||
|
||||
//=======================================================
|
||||
|
||||
/*
|
||||
==============
|
||||
main
|
||||
==============
|
||||
*/
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
static int i; // VC4.2 compiler bug if auto...
|
||||
char path[1024];
|
||||
|
||||
ExpandWildcards (&argc, &argv);
|
||||
|
||||
for (i=1 ; i<argc ; i++)
|
||||
{
|
||||
if (!strcmp(argv[i], "-archive"))
|
||||
{
|
||||
// -archive f:/quake2/release/dump_11_30
|
||||
archive = true;
|
||||
strcpy (archivedir, argv[i+1]);
|
||||
printf ("Archiving source to: %s\n", archivedir);
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-release"))
|
||||
{
|
||||
g_release = true;
|
||||
strcpy (g_releasedir, argv[i+1]);
|
||||
printf ("Copy output to: %s\n", g_releasedir);
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-compress"))
|
||||
{
|
||||
g_compress_pak = true;
|
||||
printf ("Compressing pakfile\n");
|
||||
}
|
||||
else if (!strcmp(argv[i], "-pak"))
|
||||
{
|
||||
g_release = true;
|
||||
g_pak = true;
|
||||
printf ("Building pakfile: %s\n", argv[i+1]);
|
||||
BeginPak (argv[i+1]);
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-only"))
|
||||
{
|
||||
strcpy (g_only, argv[i+1]);
|
||||
printf ("Only grabbing %s\n", g_only);
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-3ds"))
|
||||
{
|
||||
do3ds = true;
|
||||
printf ("loading .3ds files\n");
|
||||
}
|
||||
else if (argv[i][0] == '-')
|
||||
Error ("Unknown option \"%s\"", argv[i]);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= argc)
|
||||
Error ("usage: qgrab [-archive <directory>] [-release <directory>] [-only <model>] [-3ds] file.qgr");
|
||||
|
||||
if (do3ds)
|
||||
trifileext = ext_3ds;
|
||||
else
|
||||
trifileext = ext_tri;
|
||||
|
||||
for ( ; i<argc ; i++)
|
||||
{
|
||||
printf ("--------------- %s ---------------\n", argv[i]);
|
||||
// load the script
|
||||
strcpy (path, argv[i]);
|
||||
DefaultExtension (path, ".qdt");
|
||||
SetQdirFromPath (path);
|
||||
LoadScriptFile (ExpandArg(path));
|
||||
|
||||
//
|
||||
// parse it
|
||||
//
|
||||
ParseScript ();
|
||||
|
||||
// write out the last model
|
||||
FinishModel ();
|
||||
FinishSprite ();
|
||||
}
|
||||
|
||||
if (g_pak)
|
||||
FinishPak ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
204
tools/quake2/extra/qdata/qdata.dsp
Normal file
204
tools/quake2/extra/qdata/qdata.dsp
Normal file
|
@ -0,0 +1,204 @@
|
|||
# Microsoft Developer Studio Project File - Name="qdata" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 5.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Console Application" 0x0103
|
||||
|
||||
CFG=qdata - Win32 Release
|
||||
!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 "qdata.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 "qdata.mak" CFG="qdata - Win32 Release"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "qdata - Win32 Release" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE "qdata - Win32 Debug" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "qdata - 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 Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
|
||||
# ADD CPP /nologo /W3 /GX /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /FD /c
|
||||
# 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 /subsystem:console /machine:I386
|
||||
# ADD 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 /subsystem:console /machine:I386
|
||||
|
||||
!ELSEIF "$(CFG)" == "qdata - 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 ""
|
||||
# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
|
||||
# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /FD /c
|
||||
# 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 /subsystem:console /debug /machine:I386
|
||||
# ADD 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 /subsystem:console /debug /machine:I386
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "qdata - Win32 Release"
|
||||
# Name "qdata - Win32 Debug"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\bspfile.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\cmdlib.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\images.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\l3dslib.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\lbmlib.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\mathlib.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\mdfour.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\models.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\qdata.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\scriplib.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\sprites.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\tables.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\threads.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\trilib.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\video.c
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\anorms.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\bspfile.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\cmdlib.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\l3dslib.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\lbmlib.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\mathlib.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\modelgen.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\qdata.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\qfiles.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\scriplib.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\threads.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\trilib.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Resource Files"
|
||||
|
||||
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
|
||||
# End Group
|
||||
# End Target
|
||||
# End Project
|
29
tools/quake2/extra/qdata/qdata.dsw
Normal file
29
tools/quake2/extra/qdata/qdata.dsw
Normal file
|
@ -0,0 +1,29 @@
|
|||
Microsoft Developer Studio Workspace File, Format Version 5.00
|
||||
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
|
||||
|
||||
###############################################################################
|
||||
|
||||
Project: "qdata"=.\qdata.dsp - Package Owner=<4>
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<4>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Global:
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<3>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
89
tools/quake2/extra/qdata/qdata.h
Normal file
89
tools/quake2/extra/qdata/qdata.h
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// qdata.h
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "cmdlib.h"
|
||||
#include "scriplib.h"
|
||||
#include "mathlib.h"
|
||||
#include "trilib.h"
|
||||
#include "lbmlib.h"
|
||||
#include "threads.h"
|
||||
#include "l3dslib.h"
|
||||
#include "bspfile.h"
|
||||
|
||||
void Cmd_Modelname (void);
|
||||
void Cmd_Base (void);
|
||||
void Cmd_Cd (void);
|
||||
void Cmd_Origin (void);
|
||||
void Cmd_ScaleUp (void);
|
||||
void Cmd_Frame (void);
|
||||
void Cmd_Modelname (void);
|
||||
void Cmd_Skin (void);
|
||||
void Cmd_Skinsize (void);
|
||||
void FinishModel (void);
|
||||
|
||||
void Cmd_Inverse16Table( void );
|
||||
|
||||
void Cmd_SpriteName (void);
|
||||
void Cmd_Load (void);
|
||||
void Cmd_SpriteFrame (void);
|
||||
void FinishSprite (void);
|
||||
|
||||
void Cmd_Grab (void);
|
||||
void Cmd_Raw (void);
|
||||
void Cmd_Mip (void);
|
||||
void Cmd_Environment (void);
|
||||
void Cmd_Colormap (void);
|
||||
|
||||
void Cmd_File (void);
|
||||
void Cmd_Dir (void);
|
||||
void Cmd_StartWad (void);
|
||||
void Cmd_EndWad (void);
|
||||
void Cmd_Mippal (void);
|
||||
void Cmd_Mipdir (void);
|
||||
void Cmd_Alphalight (void);
|
||||
|
||||
void Cmd_Video (void);
|
||||
|
||||
void RemapZero (byte *pixels, byte *palette, int width, int height);
|
||||
|
||||
void ReleaseFile (char *filename);
|
||||
|
||||
extern byte *byteimage, *lbmpalette;
|
||||
extern int byteimagewidth, byteimageheight;
|
||||
|
||||
extern qboolean g_release; // don't grab, copy output data to new tree
|
||||
extern char g_releasedir[1024]; // c:\quake2\baseq2, etc
|
||||
extern qboolean g_archive; // don't grab, copy source data to new tree
|
||||
extern qboolean do3ds;
|
||||
extern char g_only[256]; // if set, only grab this cd
|
||||
extern qboolean g_skipmodel; // set true when a cd is not g_only
|
||||
|
||||
extern char *trifileext;
|
549
tools/quake2/extra/qdata/qdata.mak
Normal file
549
tools/quake2/extra/qdata/qdata.mak
Normal file
|
@ -0,0 +1,549 @@
|
|||
# Microsoft Developer Studio Generated NMAKE File, Format Version 4.20
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Console Application" 0x0103
|
||||
|
||||
!IF "$(CFG)" == ""
|
||||
CFG=qdata - Win32 Debug
|
||||
!MESSAGE No configuration specified. Defaulting to qdata - Win32 Debug.
|
||||
!ENDIF
|
||||
|
||||
!IF "$(CFG)" != "qdata - Win32 Release" && "$(CFG)" != "qdata - Win32 Debug"
|
||||
!MESSAGE Invalid configuration "$(CFG)" specified.
|
||||
!MESSAGE You can specify a configuration when running NMAKE on this makefile
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "qdata.mak" CFG="qdata - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "qdata - Win32 Release" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE "qdata - Win32 Debug" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE
|
||||
!ERROR An invalid configuration is specified.
|
||||
!ENDIF
|
||||
|
||||
!IF "$(OS)" == "Windows_NT"
|
||||
NULL=
|
||||
!ELSE
|
||||
NULL=nul
|
||||
!ENDIF
|
||||
################################################################################
|
||||
# Begin Project
|
||||
# PROP Target_Last_Scanned "qdata - Win32 Debug"
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "qdata - 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 Target_Dir ""
|
||||
OUTDIR=.\Release
|
||||
INTDIR=.\Release
|
||||
|
||||
ALL : "$(OUTDIR)\qdata.exe"
|
||||
|
||||
CLEAN :
|
||||
-@erase "$(INTDIR)\bspfile.obj"
|
||||
-@erase "$(INTDIR)\cmdlib.obj"
|
||||
-@erase "$(INTDIR)\images.obj"
|
||||
-@erase "$(INTDIR)\l3dslib.obj"
|
||||
-@erase "$(INTDIR)\lbmlib.obj"
|
||||
-@erase "$(INTDIR)\mathlib.obj"
|
||||
-@erase "$(INTDIR)\models.obj"
|
||||
-@erase "$(INTDIR)\qdata.obj"
|
||||
-@erase "$(INTDIR)\scriplib.obj"
|
||||
-@erase "$(INTDIR)\sprites.obj"
|
||||
-@erase "$(INTDIR)\tables.obj"
|
||||
-@erase "$(INTDIR)\threads.obj"
|
||||
-@erase "$(INTDIR)\trilib.obj"
|
||||
-@erase "$(OUTDIR)\qdata.exe"
|
||||
|
||||
"$(OUTDIR)" :
|
||||
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
|
||||
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
|
||||
# ADD CPP /nologo /W3 /GX /O2 /I "../common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
|
||||
CPP_PROJ=/nologo /ML /W3 /GX /O2 /I "../common" /D "WIN32" /D "NDEBUG" /D\
|
||||
"_CONSOLE" /Fp"$(INTDIR)/qdata.pch" /YX /Fo"$(INTDIR)/" /c
|
||||
CPP_OBJS=.\Release/
|
||||
CPP_SBRS=.\.
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
BSC32_FLAGS=/nologo /o"$(OUTDIR)/qdata.bsc"
|
||||
BSC32_SBRS= \
|
||||
|
||||
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 /subsystem:console /machine:I386
|
||||
# ADD 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 /subsystem:console /machine:I386
|
||||
LINK32_FLAGS=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 /subsystem:console /incremental:no\
|
||||
/pdb:"$(OUTDIR)/qdata.pdb" /machine:I386 /out:"$(OUTDIR)/qdata.exe"
|
||||
LINK32_OBJS= \
|
||||
"$(INTDIR)\bspfile.obj" \
|
||||
"$(INTDIR)\cmdlib.obj" \
|
||||
"$(INTDIR)\images.obj" \
|
||||
"$(INTDIR)\l3dslib.obj" \
|
||||
"$(INTDIR)\lbmlib.obj" \
|
||||
"$(INTDIR)\mathlib.obj" \
|
||||
"$(INTDIR)\models.obj" \
|
||||
"$(INTDIR)\qdata.obj" \
|
||||
"$(INTDIR)\scriplib.obj" \
|
||||
"$(INTDIR)\sprites.obj" \
|
||||
"$(INTDIR)\tables.obj" \
|
||||
"$(INTDIR)\threads.obj" \
|
||||
"$(INTDIR)\trilib.obj"
|
||||
|
||||
"$(OUTDIR)\qdata.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
|
||||
$(LINK32) @<<
|
||||
$(LINK32_FLAGS) $(LINK32_OBJS)
|
||||
<<
|
||||
|
||||
!ELSEIF "$(CFG)" == "qdata - 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 Target_Dir ""
|
||||
OUTDIR=.\Debug
|
||||
INTDIR=.\Debug
|
||||
|
||||
ALL : "$(OUTDIR)\qdata.exe"
|
||||
|
||||
CLEAN :
|
||||
-@erase "$(INTDIR)\bspfile.obj"
|
||||
-@erase "$(INTDIR)\cmdlib.obj"
|
||||
-@erase "$(INTDIR)\images.obj"
|
||||
-@erase "$(INTDIR)\l3dslib.obj"
|
||||
-@erase "$(INTDIR)\lbmlib.obj"
|
||||
-@erase "$(INTDIR)\mathlib.obj"
|
||||
-@erase "$(INTDIR)\models.obj"
|
||||
-@erase "$(INTDIR)\qdata.obj"
|
||||
-@erase "$(INTDIR)\scriplib.obj"
|
||||
-@erase "$(INTDIR)\sprites.obj"
|
||||
-@erase "$(INTDIR)\tables.obj"
|
||||
-@erase "$(INTDIR)\threads.obj"
|
||||
-@erase "$(INTDIR)\trilib.obj"
|
||||
-@erase "$(INTDIR)\vc40.idb"
|
||||
-@erase "$(INTDIR)\vc40.pdb"
|
||||
-@erase "$(OUTDIR)\qdata.exe"
|
||||
-@erase "$(OUTDIR)\qdata.ilk"
|
||||
-@erase "$(OUTDIR)\qdata.pdb"
|
||||
|
||||
"$(OUTDIR)" :
|
||||
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
|
||||
|
||||
# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
|
||||
# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "../common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
|
||||
CPP_PROJ=/nologo /MLd /W3 /Gm /GX /Zi /Od /I "../common" /D "WIN32" /D "_DEBUG"\
|
||||
/D "_CONSOLE" /Fp"$(INTDIR)/qdata.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
|
||||
CPP_OBJS=.\Debug/
|
||||
CPP_SBRS=.\.
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
BSC32_FLAGS=/nologo /o"$(OUTDIR)/qdata.bsc"
|
||||
BSC32_SBRS= \
|
||||
|
||||
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 /subsystem:console /debug /machine:I386
|
||||
# ADD 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 /subsystem:console /debug /machine:I386
|
||||
LINK32_FLAGS=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 /subsystem:console /incremental:yes\
|
||||
/pdb:"$(OUTDIR)/qdata.pdb" /debug /machine:I386 /out:"$(OUTDIR)/qdata.exe"
|
||||
LINK32_OBJS= \
|
||||
"$(INTDIR)\bspfile.obj" \
|
||||
"$(INTDIR)\cmdlib.obj" \
|
||||
"$(INTDIR)\images.obj" \
|
||||
"$(INTDIR)\l3dslib.obj" \
|
||||
"$(INTDIR)\lbmlib.obj" \
|
||||
"$(INTDIR)\mathlib.obj" \
|
||||
"$(INTDIR)\models.obj" \
|
||||
"$(INTDIR)\qdata.obj" \
|
||||
"$(INTDIR)\scriplib.obj" \
|
||||
"$(INTDIR)\sprites.obj" \
|
||||
"$(INTDIR)\tables.obj" \
|
||||
"$(INTDIR)\threads.obj" \
|
||||
"$(INTDIR)\trilib.obj"
|
||||
|
||||
"$(OUTDIR)\qdata.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
|
||||
$(LINK32) @<<
|
||||
$(LINK32_FLAGS) $(LINK32_OBJS)
|
||||
<<
|
||||
|
||||
!ENDIF
|
||||
|
||||
.c{$(CPP_OBJS)}.obj:
|
||||
$(CPP) $(CPP_PROJ) $<
|
||||
|
||||
.cpp{$(CPP_OBJS)}.obj:
|
||||
$(CPP) $(CPP_PROJ) $<
|
||||
|
||||
.cxx{$(CPP_OBJS)}.obj:
|
||||
$(CPP) $(CPP_PROJ) $<
|
||||
|
||||
.c{$(CPP_SBRS)}.sbr:
|
||||
$(CPP) $(CPP_PROJ) $<
|
||||
|
||||
.cpp{$(CPP_SBRS)}.sbr:
|
||||
$(CPP) $(CPP_PROJ) $<
|
||||
|
||||
.cxx{$(CPP_SBRS)}.sbr:
|
||||
$(CPP) $(CPP_PROJ) $<
|
||||
|
||||
################################################################################
|
||||
# Begin Target
|
||||
|
||||
# Name "qdata - Win32 Release"
|
||||
# Name "qdata - Win32 Debug"
|
||||
|
||||
!IF "$(CFG)" == "qdata - Win32 Release"
|
||||
|
||||
!ELSEIF "$(CFG)" == "qdata - Win32 Debug"
|
||||
|
||||
!ENDIF
|
||||
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\images.c
|
||||
DEP_CPP_IMAGE=\
|
||||
"..\common\qfiles.h"\
|
||||
".\../common\bspfile.h"\
|
||||
".\../common\cmdlib.h"\
|
||||
".\../common\l3dslib.h"\
|
||||
".\../common\lbmlib.h"\
|
||||
".\../common\mathlib.h"\
|
||||
".\../common\scriplib.h"\
|
||||
".\../common\threads.h"\
|
||||
".\../common\trilib.h"\
|
||||
".\qdata.h"\
|
||||
{$(INCLUDE)}"\sys\STAT.H"\
|
||||
{$(INCLUDE)}"\sys\TYPES.H"\
|
||||
|
||||
|
||||
"$(INTDIR)\images.obj" : $(SOURCE) $(DEP_CPP_IMAGE) "$(INTDIR)"
|
||||
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\modelgen.h
|
||||
|
||||
!IF "$(CFG)" == "qdata - Win32 Release"
|
||||
|
||||
!ELSEIF "$(CFG)" == "qdata - Win32 Debug"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\qdata.h
|
||||
|
||||
!IF "$(CFG)" == "qdata - Win32 Release"
|
||||
|
||||
!ELSEIF "$(CFG)" == "qdata - Win32 Debug"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\sprites.c
|
||||
DEP_CPP_SPRIT=\
|
||||
"..\common\qfiles.h"\
|
||||
".\../common\bspfile.h"\
|
||||
".\../common\cmdlib.h"\
|
||||
".\../common\l3dslib.h"\
|
||||
".\../common\lbmlib.h"\
|
||||
".\../common\mathlib.h"\
|
||||
".\../common\scriplib.h"\
|
||||
".\../common\threads.h"\
|
||||
".\../common\trilib.h"\
|
||||
".\qdata.h"\
|
||||
{$(INCLUDE)}"\sys\STAT.H"\
|
||||
{$(INCLUDE)}"\sys\TYPES.H"\
|
||||
|
||||
|
||||
"$(INTDIR)\sprites.obj" : $(SOURCE) $(DEP_CPP_SPRIT) "$(INTDIR)"
|
||||
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\l3dslib.c
|
||||
DEP_CPP_L3DSL=\
|
||||
".\../common\cmdlib.h"\
|
||||
".\../common\l3dslib.h"\
|
||||
".\../common\mathlib.h"\
|
||||
".\../common\trilib.h"\
|
||||
|
||||
|
||||
"$(INTDIR)\l3dslib.obj" : $(SOURCE) $(DEP_CPP_L3DSL) "$(INTDIR)"
|
||||
$(CPP) $(CPP_PROJ) $(SOURCE)
|
||||
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\lbmlib.c
|
||||
DEP_CPP_LBMLI=\
|
||||
".\../common\cmdlib.h"\
|
||||
".\../common\lbmlib.h"\
|
||||
|
||||
|
||||
"$(INTDIR)\lbmlib.obj" : $(SOURCE) $(DEP_CPP_LBMLI) "$(INTDIR)"
|
||||
$(CPP) $(CPP_PROJ) $(SOURCE)
|
||||
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\mathlib.c
|
||||
DEP_CPP_MATHL=\
|
||||
".\../common\cmdlib.h"\
|
||||
".\../common\mathlib.h"\
|
||||
|
||||
|
||||
"$(INTDIR)\mathlib.obj" : $(SOURCE) $(DEP_CPP_MATHL) "$(INTDIR)"
|
||||
$(CPP) $(CPP_PROJ) $(SOURCE)
|
||||
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\scriplib.c
|
||||
DEP_CPP_SCRIP=\
|
||||
".\../common\cmdlib.h"\
|
||||
".\../common\scriplib.h"\
|
||||
|
||||
|
||||
"$(INTDIR)\scriplib.obj" : $(SOURCE) $(DEP_CPP_SCRIP) "$(INTDIR)"
|
||||
$(CPP) $(CPP_PROJ) $(SOURCE)
|
||||
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\threads.c
|
||||
DEP_CPP_THREA=\
|
||||
".\../common\cmdlib.h"\
|
||||
".\../common\threads.h"\
|
||||
{$(INCLUDE)}"\sys\TYPES.H"\
|
||||
|
||||
|
||||
"$(INTDIR)\threads.obj" : $(SOURCE) $(DEP_CPP_THREA) "$(INTDIR)"
|
||||
$(CPP) $(CPP_PROJ) $(SOURCE)
|
||||
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\trilib.c
|
||||
DEP_CPP_TRILI=\
|
||||
".\../common\cmdlib.h"\
|
||||
".\../common\mathlib.h"\
|
||||
".\../common\trilib.h"\
|
||||
|
||||
|
||||
"$(INTDIR)\trilib.obj" : $(SOURCE) $(DEP_CPP_TRILI) "$(INTDIR)"
|
||||
$(CPP) $(CPP_PROJ) $(SOURCE)
|
||||
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\cmdlib.c
|
||||
DEP_CPP_CMDLI=\
|
||||
".\../common\cmdlib.h"\
|
||||
{$(INCLUDE)}"\sys\STAT.H"\
|
||||
{$(INCLUDE)}"\sys\TYPES.H"\
|
||||
|
||||
|
||||
"$(INTDIR)\cmdlib.obj" : $(SOURCE) $(DEP_CPP_CMDLI) "$(INTDIR)"
|
||||
$(CPP) $(CPP_PROJ) $(SOURCE)
|
||||
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\models.c
|
||||
DEP_CPP_MODEL=\
|
||||
"..\common\qfiles.h"\
|
||||
".\../common\bspfile.h"\
|
||||
".\../common\cmdlib.h"\
|
||||
".\../common\l3dslib.h"\
|
||||
".\../common\lbmlib.h"\
|
||||
".\../common\mathlib.h"\
|
||||
".\../common\scriplib.h"\
|
||||
".\../common\threads.h"\
|
||||
".\../common\trilib.h"\
|
||||
".\anorms.h"\
|
||||
".\qdata.h"\
|
||||
{$(INCLUDE)}"\sys\STAT.H"\
|
||||
{$(INCLUDE)}"\sys\TYPES.H"\
|
||||
|
||||
|
||||
"$(INTDIR)\models.obj" : $(SOURCE) $(DEP_CPP_MODEL) "$(INTDIR)"
|
||||
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\qdata.c
|
||||
DEP_CPP_QDATA=\
|
||||
"..\common\qfiles.h"\
|
||||
".\../common\bspfile.h"\
|
||||
".\../common\cmdlib.h"\
|
||||
".\../common\l3dslib.h"\
|
||||
".\../common\lbmlib.h"\
|
||||
".\../common\mathlib.h"\
|
||||
".\../common\scriplib.h"\
|
||||
".\../common\threads.h"\
|
||||
".\../common\trilib.h"\
|
||||
".\qdata.h"\
|
||||
{$(INCLUDE)}"\sys\STAT.H"\
|
||||
{$(INCLUDE)}"\sys\TYPES.H"\
|
||||
|
||||
|
||||
"$(INTDIR)\qdata.obj" : $(SOURCE) $(DEP_CPP_QDATA) "$(INTDIR)"
|
||||
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\mathlib.h
|
||||
|
||||
!IF "$(CFG)" == "qdata - Win32 Release"
|
||||
|
||||
!ELSEIF "$(CFG)" == "qdata - Win32 Debug"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\lbmlib.h
|
||||
|
||||
!IF "$(CFG)" == "qdata - Win32 Release"
|
||||
|
||||
!ELSEIF "$(CFG)" == "qdata - Win32 Debug"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\cmdlib.h
|
||||
|
||||
!IF "$(CFG)" == "qdata - Win32 Release"
|
||||
|
||||
!ELSEIF "$(CFG)" == "qdata - Win32 Debug"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\tables.c
|
||||
DEP_CPP_TABLE=\
|
||||
"..\common\qfiles.h"\
|
||||
".\../common\bspfile.h"\
|
||||
".\../common\cmdlib.h"\
|
||||
".\../common\l3dslib.h"\
|
||||
".\../common\lbmlib.h"\
|
||||
".\../common\mathlib.h"\
|
||||
".\../common\scriplib.h"\
|
||||
".\../common\threads.h"\
|
||||
".\../common\trilib.h"\
|
||||
".\qdata.h"\
|
||||
{$(INCLUDE)}"\sys\STAT.H"\
|
||||
{$(INCLUDE)}"\sys\TYPES.H"\
|
||||
|
||||
|
||||
"$(INTDIR)\tables.obj" : $(SOURCE) $(DEP_CPP_TABLE) "$(INTDIR)"
|
||||
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\bspfile.h
|
||||
|
||||
!IF "$(CFG)" == "qdata - Win32 Release"
|
||||
|
||||
!ELSEIF "$(CFG)" == "qdata - Win32 Debug"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\qfiles.h
|
||||
|
||||
!IF "$(CFG)" == "qdata - Win32 Release"
|
||||
|
||||
!ELSEIF "$(CFG)" == "qdata - Win32 Debug"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\bspfile.c
|
||||
DEP_CPP_BSPFI=\
|
||||
"..\common\qfiles.h"\
|
||||
".\../common\bspfile.h"\
|
||||
".\../common\cmdlib.h"\
|
||||
".\../common\mathlib.h"\
|
||||
".\../common\scriplib.h"\
|
||||
|
||||
|
||||
"$(INTDIR)\bspfile.obj" : $(SOURCE) $(DEP_CPP_BSPFI) "$(INTDIR)"
|
||||
$(CPP) $(CPP_PROJ) $(SOURCE)
|
||||
|
||||
|
||||
# End Source File
|
||||
# End Target
|
||||
# End Project
|
||||
################################################################################
|
228
tools/quake2/extra/qdata/sprites.c
Normal file
228
tools/quake2/extra/qdata/sprites.c
Normal file
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "qdata.h"
|
||||
|
||||
#define MAX_SPRFRAMES MAX_MD2SKINS
|
||||
|
||||
dsprite_t sprite;
|
||||
dsprframe_t frames[MAX_SPRFRAMES];
|
||||
|
||||
byte *byteimage, *lbmpalette;
|
||||
int byteimagewidth, byteimageheight;
|
||||
|
||||
char spritename[1024];
|
||||
|
||||
|
||||
void FinishSprite (void);
|
||||
void Cmd_Spritename (void);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
FinishSprite
|
||||
==============
|
||||
*/
|
||||
void FinishSprite (void)
|
||||
{
|
||||
FILE *spriteouthandle;
|
||||
int i, curframe;
|
||||
dsprite_t spritetemp;
|
||||
char savename[1024];
|
||||
|
||||
if (sprite.numframes == 0)
|
||||
return;
|
||||
|
||||
if (!strlen(spritename))
|
||||
Error ("Didn't name sprite file");
|
||||
|
||||
sprintf (savename, "%s%s.sp2", gamedir, spritename);
|
||||
|
||||
if (g_release)
|
||||
{
|
||||
char name[1024];
|
||||
|
||||
sprintf (name, "%s.sp2", spritename);
|
||||
ReleaseFile (name);
|
||||
spritename[0] = 0; // clear for a new sprite
|
||||
sprite.numframes = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
printf ("saving in %s\n", savename);
|
||||
CreatePath (savename);
|
||||
spriteouthandle = SafeOpenWrite (savename);
|
||||
|
||||
|
||||
//
|
||||
// write out the sprite header
|
||||
//
|
||||
spritetemp.ident = LittleLong (IDSPRITEHEADER);
|
||||
spritetemp.version = LittleLong (SPRITE_VERSION);
|
||||
spritetemp.numframes = LittleLong (sprite.numframes);
|
||||
|
||||
SafeWrite (spriteouthandle, &spritetemp, 12);
|
||||
|
||||
//
|
||||
// write out the frames
|
||||
//
|
||||
curframe = 0;
|
||||
|
||||
for (i=0 ; i<sprite.numframes ; i++)
|
||||
{
|
||||
frames[i].width = LittleLong(frames[i].width);
|
||||
frames[i].height = LittleLong(frames[i].height);
|
||||
frames[i].origin_x = LittleLong(frames[i].origin_x);
|
||||
frames[i].origin_y = LittleLong(frames[i].origin_y);
|
||||
}
|
||||
SafeWrite (spriteouthandle, frames, sizeof(frames[0])*sprite.numframes);
|
||||
|
||||
fclose (spriteouthandle);
|
||||
|
||||
spritename[0] = 0; // clear for a new sprite
|
||||
sprite.numframes = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
Cmd_Load
|
||||
===============
|
||||
*/
|
||||
void Cmd_Load (void)
|
||||
{
|
||||
char *name;
|
||||
|
||||
GetToken (false);
|
||||
|
||||
if (g_release)
|
||||
return;
|
||||
|
||||
name = ExpandPathAndArchive(token);
|
||||
|
||||
// load the image
|
||||
printf ("loading %s\n", name);
|
||||
Load256Image (name, &byteimage, &lbmpalette,
|
||||
&byteimagewidth, &byteimageheight);
|
||||
RemapZero (byteimage, lbmpalette,
|
||||
byteimagewidth, byteimageheight);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
Cmd_SpriteFrame
|
||||
===============
|
||||
*/
|
||||
void Cmd_SpriteFrame (void)
|
||||
{
|
||||
int y,xl,yl,xh,yh,w,h;
|
||||
dsprframe_t *pframe;
|
||||
int ox, oy;
|
||||
byte *cropped;
|
||||
char savename[1024];
|
||||
|
||||
GetToken (false);
|
||||
xl = atoi (token);
|
||||
GetToken (false);
|
||||
yl = atoi (token);
|
||||
GetToken (false);
|
||||
w = atoi (token);
|
||||
GetToken (false);
|
||||
h = atoi (token);
|
||||
|
||||
// origin offset is optional
|
||||
if (TokenAvailable ())
|
||||
{
|
||||
GetToken (false);
|
||||
ox = atoi (token);
|
||||
GetToken (false);
|
||||
oy = atoi (token);
|
||||
}
|
||||
else
|
||||
{
|
||||
ox = w/2;
|
||||
oy = h/2;
|
||||
}
|
||||
|
||||
if ((xl & 0x07) || (yl & 0x07) || (w & 0x07) || (h & 0x07))
|
||||
Error ("Sprite dimensions not multiples of 8\n");
|
||||
|
||||
if ((w > 256) || (h > 256))
|
||||
Error ("Sprite has a dimension longer than 256");
|
||||
|
||||
xh = xl+w;
|
||||
yh = yl+h;
|
||||
|
||||
if (sprite.numframes >= MAX_SPRFRAMES)
|
||||
Error ("Too many frames; increase MAX_SPRFRAMES\n");
|
||||
|
||||
pframe = &frames[sprite.numframes];
|
||||
pframe->width = w;
|
||||
pframe->height = h;
|
||||
pframe->origin_x = ox;
|
||||
pframe->origin_y = oy;
|
||||
sprintf (pframe->name, "%s_%i.pcx", spritename, sprite.numframes);
|
||||
sprintf (savename, "%s%s_%i.pcx", gamedir, spritename, sprite.numframes);
|
||||
sprite.numframes++;
|
||||
|
||||
if (g_release)
|
||||
{
|
||||
ReleaseFile (pframe->name);
|
||||
return;
|
||||
}
|
||||
|
||||
// crop it to the proper size
|
||||
cropped = malloc (w*h);
|
||||
for (y=0 ; y<h ; y++)
|
||||
{
|
||||
memcpy (cropped+y*w, byteimage+(y+yl)*byteimagewidth+xl, w);
|
||||
}
|
||||
|
||||
// save off the new image
|
||||
printf ("saving %s\n", savename);
|
||||
CreatePath (savename);
|
||||
WritePCXfile (savename, cropped, w, h, lbmpalette);
|
||||
|
||||
free (cropped);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
Cmd_SpriteName
|
||||
==============
|
||||
*/
|
||||
void Cmd_SpriteName (void)
|
||||
{
|
||||
if (sprite.numframes)
|
||||
FinishSprite ();
|
||||
|
||||
GetToken (false);
|
||||
strcpy (spritename, token);
|
||||
memset (&sprite, 0, sizeof(sprite));
|
||||
memset (&frames, 0, sizeof(frames));
|
||||
}
|
||||
|
172
tools/quake2/extra/qdata/tables.c
Normal file
172
tools/quake2/extra/qdata/tables.c
Normal file
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "qdata.h"
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
ALPHALIGHT GENERATION
|
||||
|
||||
Find alphamap values that best match modulated lightmap values
|
||||
|
||||
This isn't used anymore, but I'm keeping it around...
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
unsigned short alphamap[32*32*32];
|
||||
unsigned char inverse16to8table[65536];
|
||||
|
||||
/*
|
||||
static int FindNearestColor( unsigned int color )
|
||||
{
|
||||
int i;
|
||||
int closest_so_far = 0;
|
||||
float closest_distance_so_far = 100000000;
|
||||
float d;
|
||||
float r[2], g[2], b[2];
|
||||
|
||||
// incoming color is assumed to be in 0xRRGGBB format
|
||||
r[0] = ( color & 31 ) << 3;
|
||||
g[0] = ( ( color >> 5 ) & 63 ) << 2;
|
||||
b[0] = ( ( color >> 11 ) & 31 ) << 3;
|
||||
|
||||
for ( i = 0; i < 256; i++ )
|
||||
{
|
||||
r[1] = ( d_8to24table[i] >> 0 ) & 0xFF;
|
||||
g[1] = ( d_8to24table[i] >> 8 ) & 0xFF;
|
||||
b[1] = ( d_8to24table[i] >> 16 ) & 0xFF;
|
||||
|
||||
d = ( r[1] - r[0] ) * ( r[1] - r[0] ) +
|
||||
( g[1] - g[0] ) * ( g[1] - g[0] ) +
|
||||
( b[1] - b[0] ) * ( b[1] - b[0] );
|
||||
|
||||
if ( d < closest_distance_so_far )
|
||||
{
|
||||
closest_distance_so_far = d;
|
||||
closest_so_far = i;
|
||||
}
|
||||
}
|
||||
|
||||
return closest_so_far;
|
||||
}
|
||||
*/
|
||||
|
||||
extern byte BestColor( int, int, int, int, int );
|
||||
|
||||
void Inverse16_BuildTable( void )
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
** create the 16-to-8 table
|
||||
*/
|
||||
for ( i = 0; i < 65536; i++ )
|
||||
{
|
||||
int r = i & 31;
|
||||
int g = ( i >> 5 ) & 63;
|
||||
int b = ( i >> 11 ) & 31;
|
||||
|
||||
r <<= 3;
|
||||
g <<= 2;
|
||||
b <<= 3;
|
||||
|
||||
inverse16to8table[i] = BestColor( r, g, b, 0, 255 );
|
||||
}
|
||||
}
|
||||
|
||||
void Alphalight_Thread (int i)
|
||||
{
|
||||
int j;
|
||||
float r, g, b;
|
||||
float mr, mg, mb, ma;
|
||||
float distortion, bestdistortion;
|
||||
float v;
|
||||
|
||||
r = (i>>10) * (1.0/16);
|
||||
g = ((i>>5)&31) * (1.0/16);
|
||||
b = (i&31) * (1.0/16);
|
||||
|
||||
bestdistortion = 999999;
|
||||
for (j=0 ; j<16*16*16*16 ; j++)
|
||||
{
|
||||
mr = (j>>12) * (1.0/16);
|
||||
mg = ((j>>8)&15) * (1.0/16);
|
||||
mb = ((j>>4)&15) * (1.0/16);
|
||||
ma = (j&15) * (1.0/16);
|
||||
|
||||
v = r * 0.5 - (mr*ma + 0.5*(1.0-ma));
|
||||
distortion = v*v;
|
||||
v = g * 0.5 - (mg*ma + 0.5*(1.0-ma));
|
||||
distortion += v*v;
|
||||
v = b * 0.5 - (mb*ma + 0.5*(1.0-ma));
|
||||
distortion += v*v;
|
||||
|
||||
distortion *= 1.0 + ma*4;
|
||||
|
||||
if (distortion < bestdistortion)
|
||||
{
|
||||
bestdistortion = distortion;
|
||||
alphamap[i] = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cmd_Alphalight (void)
|
||||
{
|
||||
char savename[1024];
|
||||
|
||||
GetToken (false);
|
||||
|
||||
if (g_release)
|
||||
{
|
||||
ReleaseFile (token);
|
||||
return;
|
||||
}
|
||||
|
||||
sprintf (savename, "%s%s", gamedir, token);
|
||||
printf ("Building alphalight table...\n");
|
||||
|
||||
RunThreadsOnIndividual (32*32*32, true, Alphalight_Thread);
|
||||
|
||||
SaveFile (savename, (byte *)alphamap, sizeof(alphamap));
|
||||
}
|
||||
|
||||
|
||||
void Cmd_Inverse16Table( void )
|
||||
{
|
||||
char savename[1024];
|
||||
|
||||
if ( g_release )
|
||||
{
|
||||
sprintf (savename, "pics/16to8.dat");
|
||||
ReleaseFile( savename );
|
||||
return;
|
||||
}
|
||||
|
||||
sprintf (savename, "%spics/16to8.dat", gamedir);
|
||||
printf ("Building inverse 16-to-8 table...\n");
|
||||
|
||||
Inverse16_BuildTable();
|
||||
|
||||
SaveFile( savename, (byte *) inverse16to8table, sizeof( inverse16to8table ) );
|
||||
}
|
1259
tools/quake2/extra/qdata/video.c
Normal file
1259
tools/quake2/extra/qdata/video.c
Normal file
File diff suppressed because it is too large
Load diff
1568
tools/quake2/extra/qe4/brush.c
Normal file
1568
tools/quake2/extra/qe4/brush.c
Normal file
File diff suppressed because it is too large
Load diff
87
tools/quake2/extra/qe4/brush.h
Normal file
87
tools/quake2/extra/qe4/brush.h
Normal file
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// brush.h
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int numpoints;
|
||||
int maxpoints;
|
||||
float points[8][5]; // variable sized
|
||||
} winding_t;
|
||||
|
||||
|
||||
// the normals on planes point OUT of the brush
|
||||
#define MAXPOINTS 16
|
||||
typedef struct face_s
|
||||
{
|
||||
struct face_s *next;
|
||||
vec3_t planepts[3];
|
||||
texdef_t texdef;
|
||||
|
||||
plane_t plane;
|
||||
|
||||
winding_t *face_winding;
|
||||
|
||||
vec3_t d_color;
|
||||
qtexture_t *d_texture;
|
||||
|
||||
// int d_numpoints;
|
||||
// vec3_t *d_points;
|
||||
} face_t;
|
||||
|
||||
#define MAX_FACES 16
|
||||
typedef struct brush_s
|
||||
{
|
||||
struct brush_s *prev, *next; // links in active/selected
|
||||
struct brush_s *oprev, *onext; // links in entity
|
||||
struct entity_s *owner;
|
||||
vec3_t mins, maxs;
|
||||
|
||||
face_t *brush_faces;
|
||||
} brush_t;
|
||||
|
||||
|
||||
void Brush_AddToList (brush_t *b, brush_t *list);
|
||||
void Brush_Build(brush_t *b);
|
||||
void Brush_BuildWindings( brush_t *b );
|
||||
brush_t *Brush_Clone (brush_t *b);
|
||||
brush_t *Brush_Create (vec3_t mins, vec3_t maxs, texdef_t *texdef);
|
||||
void Brush_Draw( brush_t *b );
|
||||
void Brush_DrawXY( brush_t *b );
|
||||
void Brush_Free (brush_t *b);
|
||||
void Brush_MakeSided (int sides);
|
||||
void Brush_Move (brush_t *b, vec3_t move);
|
||||
brush_t *Brush_Parse (void);
|
||||
face_t *Brush_Ray (vec3_t origin, vec3_t dir, brush_t *b, float *dist);
|
||||
void Brush_RemoveFromList (brush_t *b);
|
||||
void Brush_SelectFaceForDragging (brush_t *b, face_t *f, qboolean shear);
|
||||
void Brush_SetTexture (brush_t *b, texdef_t *texdef);
|
||||
void Brush_SideSelect (brush_t *b, vec3_t origin, vec3_t dir, qboolean shear);
|
||||
void Brush_Write (brush_t *b, FILE *f);
|
||||
void Brush_RemoveEmptyFaces ( brush_t *b );
|
||||
|
||||
int AddPlanept (float *f);
|
||||
face_t *Face_Clone (face_t *f);
|
||||
void Face_Draw( face_t *face );
|
||||
winding_t *MakeFaceWinding (brush_t *b, face_t *face);
|
378
tools/quake2/extra/qe4/bspfile.h
Normal file
378
tools/quake2/extra/qe4/bspfile.h
Normal file
|
@ -0,0 +1,378 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// upper design bounds
|
||||
// leaffaces, leafbrushes, planes, and verts are still bounded by
|
||||
// 16 bit short limits
|
||||
#define MAX_MAP_MODELS 1024
|
||||
#define MAX_MAP_BRUSHES 8192
|
||||
#define MAX_MAP_ENTITIES 2048
|
||||
#define MAX_MAP_PATHS 2048
|
||||
#define MAX_MAP_ENTSTRING 0x20000
|
||||
#define MAX_MAP_TEXTURES 1024
|
||||
#define MAX_MAP_TEXINFO 8192
|
||||
|
||||
#define MAX_MAP_PLANES 65536
|
||||
#define MAX_MAP_NODES 65536
|
||||
#define MAX_MAP_BRUSHSIDES 65536
|
||||
#define MAX_MAP_LEAFS 65536
|
||||
#define MAX_MAP_VERTS 65536
|
||||
#define MAX_MAP_FACES 65536
|
||||
#define MAX_MAP_LEAFFACES 65536
|
||||
#define MAX_MAP_LEAFBRUSHES 65536
|
||||
#define MAX_MAP_PORTALS 65536
|
||||
#define MAX_MAP_EDGES 128000
|
||||
#define MAX_MAP_SURFEDGES 256000
|
||||
#define MAX_MAP_MIPTEX 0x200000
|
||||
#define MAX_MAP_LIGHTING 0x200000
|
||||
#define MAX_MAP_VISIBILITY 0x100000
|
||||
|
||||
// key / value pair sizes
|
||||
|
||||
#define MAX_KEY 32
|
||||
#define MAX_VALUE 1024
|
||||
|
||||
//=============================================================================
|
||||
|
||||
#define BSPVERSION 34
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int fileofs, filelen;
|
||||
} lump_t;
|
||||
|
||||
#define LUMP_ENTITIES 0
|
||||
#define LUMP_PLANES 1
|
||||
#define LUMP_TEXTURES 2
|
||||
#define LUMP_VERTEXES 3
|
||||
#define LUMP_VISIBILITY 4
|
||||
#define LUMP_NODES 5
|
||||
#define LUMP_TEXINFO 6
|
||||
#define LUMP_FACES 7
|
||||
#define LUMP_LIGHTING 8
|
||||
#define LUMP_LEAFS 9
|
||||
#define LUMP_LEAFFACES 10
|
||||
#define LUMP_LEAFBRUSHES 11
|
||||
#define LUMP_EDGES 12
|
||||
#define LUMP_SURFEDGES 13
|
||||
#define LUMP_MODELS 14
|
||||
#define LUMP_PATHS 15
|
||||
#define LUMP_BRUSHES 16
|
||||
#define LUMP_BRUSHSIDES 17
|
||||
#define LUMP_POP 18
|
||||
|
||||
#define HEADER_LUMPS 18
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int version;
|
||||
lump_t lumps[HEADER_LUMPS];
|
||||
} dheader_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float mins[3], maxs[3];
|
||||
float origin[3]; // for sounds or lights
|
||||
int headnode;
|
||||
int visleafs; // not including the solid leaf 0
|
||||
int firstface, numfaces;
|
||||
} dmodel_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int nummiptex;
|
||||
int dataofs[4]; // [nummiptex]
|
||||
} dmiptexlump_t;
|
||||
|
||||
#define MIPLEVELS 4
|
||||
typedef struct miptex_s
|
||||
{
|
||||
char name[16];
|
||||
unsigned width, height;
|
||||
unsigned offsets[MIPLEVELS]; // four mip maps stored
|
||||
int flags;
|
||||
int value;
|
||||
} miptex_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float point[3];
|
||||
} dvertex_t;
|
||||
|
||||
|
||||
// 0-2 are axial planes
|
||||
#define PLANE_X 0
|
||||
#define PLANE_Y 1
|
||||
#define PLANE_Z 2
|
||||
|
||||
// 3-5 are non-axial planes snapped to the nearest
|
||||
#define PLANE_ANYX 3
|
||||
#define PLANE_ANYY 4
|
||||
#define PLANE_ANYZ 5
|
||||
|
||||
// planes (x&~1) and (x&~1)+1 are allways opposites
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float normal[3];
|
||||
float dist;
|
||||
int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate
|
||||
} dplane_t;
|
||||
|
||||
|
||||
// contents flags are seperate bits
|
||||
// a given brush can contribute multiple content bits
|
||||
// multiple brushes can be in a single leaf
|
||||
|
||||
// lower bits are stronger, and will eat weaker brushes completely
|
||||
#define CONTENTS_SOLID 1 // an eye is never valid in a solid
|
||||
#define CONTENTS_WINDOW 2 // translucent, but not watery
|
||||
#define CONTENTS_LAVA 8
|
||||
#define CONTENTS_SLIME 16
|
||||
#define CONTENTS_WATER 32
|
||||
#define CONTENTS_THINWATER 64 // translucent faces
|
||||
|
||||
#define LAST_VISIBLE_CONTENTS 64
|
||||
|
||||
// remaining contents are non-visible, and don't eat brushes
|
||||
#define CONTENTS_MONSTER 128
|
||||
#define CONTENTS_PLAYERCLIP 256
|
||||
#define CONTENTS_MONSTERCLIP 512
|
||||
|
||||
|
||||
// currents can be added to any other contents, and may be mixed
|
||||
#define CONTENTS_CURRENT_0 1024
|
||||
#define CONTENTS_CURRENT_90 2048
|
||||
#define CONTENTS_CURRENT_180 4096
|
||||
#define CONTENTS_CURRENT_270 8192
|
||||
#define CONTENTS_CURRENT_UP 16384
|
||||
#define CONTENTS_CURRENT_DOWN 32768
|
||||
|
||||
#define CONTENTS_ORIGIN 65536 // removed before processing
|
||||
|
||||
|
||||
|
||||
// !!! if this is changed, it must be changed in asm_i386.h too !!!
|
||||
typedef struct
|
||||
{
|
||||
int planenum;
|
||||
int children[2]; // negative numbers are -(leafs+1), not nodes
|
||||
short mins[3]; // for frustom culling
|
||||
short maxs[3];
|
||||
unsigned short firstface;
|
||||
unsigned short numfaces; // counting both sides
|
||||
} dnode_t;
|
||||
|
||||
typedef struct texinfo_s
|
||||
{
|
||||
float vecs[2][4]; // [s/t][xyz offset]
|
||||
int miptex;
|
||||
int flags; // miptex flags + overrides
|
||||
int value; // light emition, etc
|
||||
} texinfo_t;
|
||||
|
||||
#define TEX_SPECIAL 1 // sky or slime, no lightmap or 256 subdivision
|
||||
#define SURF_LIGHT 2
|
||||
|
||||
#define SURF_WATER 4
|
||||
#define SURF_SLIME 8
|
||||
#define SURF_LAVA 16
|
||||
#define SURF_WINDOW 32
|
||||
|
||||
#define SURF_SKY 64
|
||||
#define SURF_MIRROR 128
|
||||
|
||||
#define SURF_SLIPPERY 256
|
||||
|
||||
// note that edge 0 is never used, because negative edge nums are used for
|
||||
// counterclockwise use of the edge in a face
|
||||
typedef struct
|
||||
{
|
||||
unsigned short v[2]; // vertex numbers
|
||||
} dedge_t;
|
||||
|
||||
#define MAXLIGHTMAPS 4
|
||||
typedef struct
|
||||
{
|
||||
unsigned short planenum;
|
||||
short side;
|
||||
|
||||
int firstedge; // we must support > 64k edges
|
||||
short numedges;
|
||||
short texinfo;
|
||||
|
||||
// lighting info
|
||||
byte styles[MAXLIGHTMAPS];
|
||||
int lightofs; // start of [numstyles*surfsize] samples
|
||||
} dface_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int contents; // OR of all brushes
|
||||
int visofs; // -1 = no visibility info
|
||||
|
||||
short mins[3]; // for frustum culling
|
||||
short maxs[3];
|
||||
|
||||
unsigned short firstleafface;
|
||||
unsigned short numleaffaces;
|
||||
|
||||
unsigned short firstleafbrush;
|
||||
unsigned short numleafbrushes;
|
||||
} dleaf_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned short planenum; // facing out of the leaf
|
||||
short texinfo;
|
||||
} dbrushside_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int firstside;
|
||||
int numsides;
|
||||
int contents;
|
||||
} dbrush_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float origin[3];
|
||||
float angles[3];
|
||||
int next, prev;
|
||||
int flags;
|
||||
float speed;
|
||||
} dpath_t;
|
||||
|
||||
//============================================================================
|
||||
|
||||
#ifndef QUAKE_GAME
|
||||
|
||||
#define ANGLE_UP -1
|
||||
#define ANGLE_DOWN -2
|
||||
|
||||
|
||||
// the utilities get to be lazy and just use large static arrays
|
||||
|
||||
extern int nummodels;
|
||||
extern dmodel_t dmodels[MAX_MAP_MODELS];
|
||||
|
||||
extern int visdatasize;
|
||||
extern byte dvisdata[MAX_MAP_VISIBILITY];
|
||||
|
||||
extern int lightdatasize;
|
||||
extern byte dlightdata[MAX_MAP_LIGHTING];
|
||||
|
||||
extern int texdatasize;
|
||||
extern byte dtexdata[MAX_MAP_MIPTEX]; // (dmiptexlump_t)
|
||||
|
||||
extern int entdatasize;
|
||||
extern char dentdata[MAX_MAP_ENTSTRING];
|
||||
|
||||
extern int numleafs;
|
||||
extern dleaf_t dleafs[MAX_MAP_LEAFS];
|
||||
|
||||
extern int numplanes;
|
||||
extern dplane_t dplanes[MAX_MAP_PLANES];
|
||||
|
||||
extern int numvertexes;
|
||||
extern dvertex_t dvertexes[MAX_MAP_VERTS];
|
||||
|
||||
extern int numnodes;
|
||||
extern dnode_t dnodes[MAX_MAP_NODES];
|
||||
|
||||
extern int numtexinfo;
|
||||
extern texinfo_t texinfo[MAX_MAP_TEXINFO];
|
||||
|
||||
extern int numfaces;
|
||||
extern dface_t dfaces[MAX_MAP_FACES];
|
||||
|
||||
extern int numedges;
|
||||
extern dedge_t dedges[MAX_MAP_EDGES];
|
||||
|
||||
extern int numleaffaces;
|
||||
extern unsigned short dleaffaces[MAX_MAP_LEAFFACES];
|
||||
|
||||
extern int numleafbrushes;
|
||||
extern unsigned short dleafbrushes[MAX_MAP_LEAFBRUSHES];
|
||||
|
||||
extern int numsurfedges;
|
||||
extern int dsurfedges[MAX_MAP_SURFEDGES];
|
||||
|
||||
extern int numpaths;
|
||||
extern dpath_t dpaths[MAX_MAP_PATHS];
|
||||
|
||||
extern int numbrushes;
|
||||
extern dbrush_t dbrushes[MAX_MAP_BRUSHES];
|
||||
|
||||
extern int numbrushsides;
|
||||
extern dbrushside_t dbrushsides[MAX_MAP_BRUSHSIDES];
|
||||
|
||||
|
||||
void DecompressVis (byte *in, byte *decompressed);
|
||||
int CompressVis (byte *vis, byte *dest);
|
||||
|
||||
void LoadBSPFile (char *filename);
|
||||
void WriteBSPFile (char *filename);
|
||||
void PrintBSPFileSizes (void);
|
||||
|
||||
//===============
|
||||
|
||||
|
||||
typedef struct epair_s
|
||||
{
|
||||
struct epair_s *next;
|
||||
char *key;
|
||||
char *value;
|
||||
} epair_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
vec3_t origin;
|
||||
int firstbrush;
|
||||
int numbrushes;
|
||||
epair_t *epairs;
|
||||
} entity_t;
|
||||
|
||||
extern int num_entities;
|
||||
extern entity_t entities[MAX_MAP_ENTITIES];
|
||||
|
||||
void ParseEntities (void);
|
||||
void UnparseEntities (void);
|
||||
|
||||
void SetKeyValue (entity_t *ent, char *key, char *value);
|
||||
char *ValueForKey (entity_t *ent, char *key);
|
||||
// will return "" if not present
|
||||
|
||||
vec_t FloatForKey (entity_t *ent, char *key);
|
||||
void GetVectorForKey (entity_t *ent, char *key, vec3_t vec);
|
||||
|
||||
epair_t *ParseEpair (void);
|
||||
|
||||
void PrintEntity (entity_t *ent);
|
||||
|
||||
extern int r_leaftovis[MAX_MAP_LEAFS];
|
||||
extern int r_vistoleaf[MAX_MAP_LEAFS];
|
||||
extern int r_numvisleafs;
|
||||
|
||||
#endif
|
594
tools/quake2/extra/qe4/camera.c
Normal file
594
tools/quake2/extra/qe4/camera.c
Normal file
|
@ -0,0 +1,594 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "qe3.h"
|
||||
|
||||
#define PAGEFLIPS 2
|
||||
|
||||
void DrawPathLines (void);
|
||||
|
||||
camera_t camera;
|
||||
|
||||
/*
|
||||
============
|
||||
Cam_Init
|
||||
============
|
||||
*/
|
||||
void Cam_Init (void)
|
||||
{
|
||||
// camera.draw_mode = cd_texture;
|
||||
// camera.draw_mode = cd_solid;
|
||||
// camera.draw_mode = cd_wire;
|
||||
|
||||
camera.timing = false;
|
||||
|
||||
camera.origin[0] = 0;
|
||||
camera.origin[1] = 20;
|
||||
camera.origin[2] = 46;
|
||||
|
||||
camera.color[0] = 0.3;
|
||||
camera.color[1] = 0.3;
|
||||
camera.color[2] = 0.3;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
|
||||
void Cam_BuildMatrix (void)
|
||||
{
|
||||
float xa, ya;
|
||||
float matrix[4][4];
|
||||
int i;
|
||||
|
||||
xa = camera.angles[0]/180*Q_PI;
|
||||
ya = camera.angles[1]/180*Q_PI;
|
||||
|
||||
// the movement matrix is kept 2d
|
||||
|
||||
camera.forward[0] = cos(ya);
|
||||
camera.forward[1] = sin(ya);
|
||||
camera.right[0] = camera.forward[1];
|
||||
camera.right[1] = -camera.forward[0];
|
||||
|
||||
glGetFloatv (GL_PROJECTION_MATRIX, &matrix[0][0]);
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
camera.vright[i] = matrix[i][0];
|
||||
camera.vup[i] = matrix[i][1];
|
||||
camera.vpn[i] = matrix[i][2];
|
||||
}
|
||||
|
||||
VectorNormalize (camera.vright);
|
||||
VectorNormalize (camera.vup);
|
||||
VectorNormalize (camera.vpn);
|
||||
}
|
||||
|
||||
//===============================================
|
||||
|
||||
/*
|
||||
===============
|
||||
Cam_ChangeFloor
|
||||
===============
|
||||
*/
|
||||
void Cam_ChangeFloor (qboolean up)
|
||||
{
|
||||
brush_t *b;
|
||||
float d, bestd, current;
|
||||
vec3_t start, dir;
|
||||
|
||||
start[0] = camera.origin[0];
|
||||
start[1] = camera.origin[1];
|
||||
start[2] = 8192;
|
||||
dir[0] = dir[1] = 0;
|
||||
dir[2] = -1;
|
||||
|
||||
current = 8192 - (camera.origin[2] - 48);
|
||||
if (up)
|
||||
bestd = 0;
|
||||
else
|
||||
bestd = 16384;
|
||||
|
||||
for (b=active_brushes.next ; b != &active_brushes ; b=b->next)
|
||||
{
|
||||
if (!Brush_Ray (start, dir, b, &d))
|
||||
continue;
|
||||
if (up && d < current && d > bestd)
|
||||
bestd = d;
|
||||
if (!up && d > current && d < bestd)
|
||||
bestd = d;
|
||||
}
|
||||
|
||||
if (bestd == 0 || bestd == 16384)
|
||||
return;
|
||||
|
||||
camera.origin[2] += current - bestd;
|
||||
Sys_UpdateWindows (W_CAMERA|W_Z_OVERLAY);
|
||||
}
|
||||
|
||||
|
||||
//===============================================
|
||||
|
||||
int cambuttonstate;
|
||||
static int buttonx, buttony;
|
||||
static int cursorx, cursory;
|
||||
|
||||
face_t *side_select;
|
||||
|
||||
#define ANGLE_SPEED 300
|
||||
#define MOVE_SPEED 400
|
||||
|
||||
/*
|
||||
================
|
||||
Cam_PositionDrag
|
||||
================
|
||||
*/
|
||||
void Cam_PositionDrag (void)
|
||||
{
|
||||
int x, y;
|
||||
|
||||
Sys_GetCursorPos (&x, &y);
|
||||
if (x != cursorx || y != cursory)
|
||||
{
|
||||
x -= cursorx;
|
||||
VectorMA (camera.origin, x, camera.vright, camera.origin);
|
||||
y -= cursory;
|
||||
camera.origin[2] -= y;
|
||||
|
||||
Sys_SetCursorPos (cursorx, cursory);
|
||||
Sys_UpdateWindows (W_CAMERA | W_XY_OVERLAY);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
Cam_MouseControl
|
||||
===============
|
||||
*/
|
||||
void Cam_MouseControl (float dtime)
|
||||
{
|
||||
int xl, xh;
|
||||
int yl, yh;
|
||||
float xf, yf;
|
||||
|
||||
if (cambuttonstate != MK_RBUTTON)
|
||||
return;
|
||||
|
||||
xf = (float)(buttonx - camera.width/2) / (camera.width/2);
|
||||
yf = (float)(buttony - camera.height/2) / (camera.height/2);
|
||||
|
||||
xl = camera.width/3;
|
||||
xh = xl*2;
|
||||
yl = camera.height/3;
|
||||
yh = yl*2;
|
||||
|
||||
#if 0
|
||||
// strafe
|
||||
if (buttony < yl && (buttonx < xl || buttonx > xh))
|
||||
VectorMA (camera.origin, xf*dtime*MOVE_SPEED, camera.right, camera.origin);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
xf *= 1.0 - fabs(yf);
|
||||
if (xf < 0)
|
||||
{
|
||||
xf += 0.1;
|
||||
if (xf > 0)
|
||||
xf = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
xf -= 0.1;
|
||||
if (xf < 0)
|
||||
xf = 0;
|
||||
}
|
||||
|
||||
VectorMA (camera.origin, yf*dtime*MOVE_SPEED, camera.forward, camera.origin);
|
||||
camera.angles[YAW] += xf*-dtime*ANGLE_SPEED;
|
||||
}
|
||||
Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
Cam_MouseDown
|
||||
==============
|
||||
*/
|
||||
void Cam_MouseDown (int x, int y, int buttons)
|
||||
{
|
||||
vec3_t dir;
|
||||
float f, r, u;
|
||||
int i;
|
||||
|
||||
//
|
||||
// calc ray direction
|
||||
//
|
||||
u = (float)(y - camera.height/2) / (camera.width/2);
|
||||
r = (float)(x - camera.width/2) / (camera.width/2);
|
||||
f = 1;
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
dir[i] = camera.vpn[i] * f + camera.vright[i] * r + camera.vup[i] * u;
|
||||
VectorNormalize (dir);
|
||||
|
||||
Sys_GetCursorPos (&cursorx, &cursory);
|
||||
|
||||
cambuttonstate = buttons;
|
||||
buttonx = x;
|
||||
buttony = y;
|
||||
|
||||
// LBUTTON = manipulate selection
|
||||
// shift-LBUTTON = select
|
||||
// middle button = grab texture
|
||||
// ctrl-middle button = set entire brush to texture
|
||||
// ctrl-shift-middle button = set single face to texture
|
||||
if ( (buttons == MK_LBUTTON)
|
||||
|| (buttons == (MK_LBUTTON | MK_SHIFT))
|
||||
|| (buttons == (MK_LBUTTON | MK_CONTROL))
|
||||
|| (buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT))
|
||||
|| (buttons == MK_MBUTTON)
|
||||
|| (buttons == (MK_MBUTTON|MK_CONTROL))
|
||||
|| (buttons == (MK_MBUTTON|MK_SHIFT|MK_CONTROL)) )
|
||||
{
|
||||
Drag_Begin (x, y, buttons,
|
||||
camera.vright, camera.vup,
|
||||
camera.origin, dir);
|
||||
return;
|
||||
}
|
||||
|
||||
if (buttons == MK_RBUTTON)
|
||||
{
|
||||
Cam_MouseControl (0.1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
Cam_MouseUp
|
||||
==============
|
||||
*/
|
||||
void Cam_MouseUp (int x, int y, int buttons)
|
||||
{
|
||||
cambuttonstate = 0;
|
||||
Drag_MouseUp ();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
Cam_MouseMoved
|
||||
==============
|
||||
*/
|
||||
void Cam_MouseMoved (int x, int y, int buttons)
|
||||
{
|
||||
cambuttonstate = buttons;
|
||||
if (!buttons)
|
||||
return;
|
||||
buttonx = x;
|
||||
buttony = y;
|
||||
|
||||
if (buttons == (MK_RBUTTON|MK_CONTROL) )
|
||||
{
|
||||
Cam_PositionDrag ();
|
||||
Sys_UpdateWindows (W_XY|W_CAMERA|W_Z);
|
||||
return;
|
||||
}
|
||||
|
||||
Sys_GetCursorPos (&cursorx, &cursory);
|
||||
|
||||
if (buttons & (MK_LBUTTON | MK_MBUTTON) )
|
||||
{
|
||||
Drag_MouseMoved (x, y, buttons);
|
||||
Sys_UpdateWindows (W_XY|W_CAMERA|W_Z);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
vec3_t cull1, cull2;
|
||||
int cullv1[3], cullv2[3];
|
||||
|
||||
void InitCull (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
VectorSubtract (camera.vpn, camera.vright, cull1);
|
||||
VectorAdd (camera.vpn, camera.vright, cull2);
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
if (cull1[i] > 0)
|
||||
cullv1[i] = 3+i;
|
||||
else
|
||||
cullv1[i] = i;
|
||||
if (cull2[i] > 0)
|
||||
cullv2[i] = 3+i;
|
||||
else
|
||||
cullv2[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
qboolean CullBrush (brush_t *b)
|
||||
{
|
||||
int i;
|
||||
vec3_t point;
|
||||
float d;
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
point[i] = b->mins[cullv1[i]] - camera.origin[i];
|
||||
|
||||
d = DotProduct (point, cull1);
|
||||
if (d < -1)
|
||||
return true;
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
point[i] = b->mins[cullv2[i]] - camera.origin[i];
|
||||
|
||||
d = DotProduct (point, cull2);
|
||||
if (d < -1)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
Cam_Draw
|
||||
==============
|
||||
*/
|
||||
void Cam_Draw (void)
|
||||
{
|
||||
brush_t *brush;
|
||||
face_t *face;
|
||||
float screenaspect;
|
||||
float yfov;
|
||||
double start, end;
|
||||
int i;
|
||||
|
||||
if (!active_brushes.next)
|
||||
return; // not valid yet
|
||||
|
||||
if (camera.timing)
|
||||
start = Sys_DoubleTime ();
|
||||
|
||||
//
|
||||
// clear
|
||||
//
|
||||
QE_CheckOpenGLForErrors();
|
||||
|
||||
glViewport(0, 0, camera.width, camera.height);
|
||||
glScissor(0, 0, camera.width, camera.height);
|
||||
glClearColor (
|
||||
g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][0],
|
||||
g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][1],
|
||||
g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][2],
|
||||
0);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
//
|
||||
// set up viewpoint
|
||||
//
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity ();
|
||||
|
||||
screenaspect = (float)camera.width/camera.height;
|
||||
yfov = 2*atan((float)camera.height/camera.width)*180/Q_PI;
|
||||
gluPerspective (yfov, screenaspect, 2, 8192);
|
||||
|
||||
glRotatef (-90, 1, 0, 0); // put Z going up
|
||||
glRotatef (90, 0, 0, 1); // put Z going up
|
||||
glRotatef (camera.angles[0], 0, 1, 0);
|
||||
glRotatef (-camera.angles[1], 0, 0, 1);
|
||||
glTranslatef (-camera.origin[0], -camera.origin[1], -camera.origin[2]);
|
||||
|
||||
Cam_BuildMatrix ();
|
||||
|
||||
InitCull ();
|
||||
|
||||
//
|
||||
// draw stuff
|
||||
//
|
||||
|
||||
switch (camera.draw_mode)
|
||||
{
|
||||
case cd_wire:
|
||||
glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisable(GL_TEXTURE_1D);
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glColor3f(1.0, 1.0, 1.0);
|
||||
// glEnable (GL_LINE_SMOOTH);
|
||||
break;
|
||||
|
||||
case cd_solid:
|
||||
glCullFace(GL_FRONT);
|
||||
glEnable(GL_CULL_FACE);
|
||||
glShadeModel (GL_FLAT);
|
||||
|
||||
glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthFunc (GL_LEQUAL);
|
||||
break;
|
||||
|
||||
case cd_texture:
|
||||
glCullFace(GL_FRONT);
|
||||
glEnable(GL_CULL_FACE);
|
||||
|
||||
glShadeModel (GL_FLAT);
|
||||
|
||||
glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
glDisable(GL_BLEND);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthFunc (GL_LEQUAL);
|
||||
|
||||
#if 0
|
||||
|
||||
{
|
||||
GLfloat fogColor[4] = {0.0, 1.0, 0.0, 0.25};
|
||||
|
||||
glFogi (GL_FOG_MODE, GL_LINEAR);
|
||||
glHint (GL_FOG_HINT, GL_NICEST); /* per pixel */
|
||||
glFogf (GL_FOG_START, -8192);
|
||||
glFogf (GL_FOG_END, 65536);
|
||||
glFogfv (GL_FOG_COLOR, fogColor);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
break;
|
||||
|
||||
case cd_blend:
|
||||
glCullFace(GL_FRONT);
|
||||
glEnable(GL_CULL_FACE);
|
||||
|
||||
glShadeModel (GL_FLAT);
|
||||
|
||||
glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glEnable (GL_BLEND);
|
||||
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
break;
|
||||
}
|
||||
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
for (brush = active_brushes.next ; brush != &active_brushes ; brush=brush->next)
|
||||
{
|
||||
if (CullBrush (brush))
|
||||
continue;
|
||||
if (FilterBrush (brush))
|
||||
continue;
|
||||
|
||||
Brush_Draw( brush );
|
||||
}
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
|
||||
//
|
||||
// now draw selected brushes
|
||||
//
|
||||
|
||||
glTranslatef (g_qeglobals.d_select_translate[0], g_qeglobals.d_select_translate[1], g_qeglobals.d_select_translate[2]);
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
|
||||
// draw normally
|
||||
for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next)
|
||||
{
|
||||
Brush_Draw( brush );
|
||||
}
|
||||
|
||||
// blend on top
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
|
||||
glColor4f(1.0, 0.0, 0.0, 0.3);
|
||||
glEnable (GL_BLEND);
|
||||
glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
|
||||
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDisable (GL_TEXTURE_2D);
|
||||
for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next)
|
||||
for (face=brush->brush_faces ; face ; face=face->next)
|
||||
Face_Draw( face );
|
||||
if (selected_face)
|
||||
Face_Draw(selected_face);
|
||||
|
||||
// non-zbuffered outline
|
||||
|
||||
glDisable (GL_BLEND);
|
||||
glDisable (GL_DEPTH_TEST);
|
||||
glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
|
||||
glColor3f (1, 1, 1);
|
||||
for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next)
|
||||
for (face=brush->brush_faces ; face ; face=face->next)
|
||||
Face_Draw( face );
|
||||
|
||||
// edge / vertex flags
|
||||
|
||||
if (g_qeglobals.d_select_mode == sel_vertex)
|
||||
{
|
||||
glPointSize (4);
|
||||
glColor3f (0,1,0);
|
||||
glBegin (GL_POINTS);
|
||||
for (i=0 ; i<g_qeglobals.d_numpoints ; i++)
|
||||
glVertex3fv (g_qeglobals.d_points[i]);
|
||||
glEnd ();
|
||||
glPointSize (1);
|
||||
}
|
||||
else if (g_qeglobals.d_select_mode == sel_edge)
|
||||
{
|
||||
float *v1, *v2;
|
||||
|
||||
glPointSize (4);
|
||||
glColor3f (0,0,1);
|
||||
glBegin (GL_POINTS);
|
||||
for (i=0 ; i<g_qeglobals.d_numedges ; i++)
|
||||
{
|
||||
v1 = g_qeglobals.d_points[g_qeglobals.d_edges[i].p1];
|
||||
v2 = g_qeglobals.d_points[g_qeglobals.d_edges[i].p2];
|
||||
glVertex3f ( (v1[0]+v2[0])*0.5,(v1[1]+v2[1])*0.5,(v1[2]+v2[2])*0.5);
|
||||
}
|
||||
glEnd ();
|
||||
glPointSize (1);
|
||||
}
|
||||
|
||||
//
|
||||
// draw pointfile
|
||||
//
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
DrawPathLines ();
|
||||
|
||||
if (g_qeglobals.d_pointfile_display_list)
|
||||
{
|
||||
Pointfile_Draw();
|
||||
// glCallList (g_qeglobals.d_pointfile_display_list);
|
||||
}
|
||||
|
||||
// bind back to the default texture so that we don't have problems
|
||||
// elsewhere using/modifying texture maps between contexts
|
||||
glBindTexture( GL_TEXTURE_2D, 0 );
|
||||
|
||||
glFinish();
|
||||
QE_CheckOpenGLForErrors();
|
||||
// Sys_EndWait();
|
||||
if (camera.timing)
|
||||
{
|
||||
end = Sys_DoubleTime ();
|
||||
Sys_Printf ("Camera: %i ms\n", (int)(1000*(end-start)));
|
||||
}
|
||||
}
|
||||
|
63
tools/quake2/extra/qe4/camera.h
Normal file
63
tools/quake2/extra/qe4/camera.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// window system independent camera view code
|
||||
|
||||
typedef enum
|
||||
{
|
||||
cd_wire,
|
||||
cd_solid,
|
||||
cd_texture,
|
||||
cd_blend
|
||||
} camera_draw_mode;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int width, height;
|
||||
|
||||
qboolean timing;
|
||||
|
||||
vec3_t origin;
|
||||
vec3_t angles;
|
||||
|
||||
camera_draw_mode draw_mode;
|
||||
|
||||
vec3_t color; // background
|
||||
|
||||
vec3_t forward, right, up; // move matrix
|
||||
|
||||
vec3_t vup, vpn, vright; // view matrix
|
||||
} camera_t;
|
||||
|
||||
extern camera_t camera;
|
||||
|
||||
void Cam_Init ();
|
||||
void Cam_KeyDown (int key);
|
||||
void Cam_MouseDown (int x, int y, int buttons);
|
||||
void Cam_MouseUp (int x, int y, int buttons);
|
||||
void Cam_MouseMoved (int x, int y, int buttons);
|
||||
void Cam_MouseControl (float dtime);
|
||||
void Cam_Draw ();
|
||||
|
||||
void Cam_HomeView ();
|
||||
void Cam_ChangeFloor (qboolean up);
|
||||
|
686
tools/quake2/extra/qe4/cmdlib.c
Normal file
686
tools/quake2/extra/qe4/cmdlib.c
Normal file
|
@ -0,0 +1,686 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// cmdlib.c
|
||||
|
||||
#include "cmdlib.h"
|
||||
|
||||
#define PATHSEPERATOR '/'
|
||||
|
||||
char com_token[1024];
|
||||
qboolean com_eof;
|
||||
|
||||
/*
|
||||
================
|
||||
I_FloatTime
|
||||
================
|
||||
*/
|
||||
double I_FloatTime (void)
|
||||
{
|
||||
time_t t;
|
||||
|
||||
time (&t);
|
||||
|
||||
return t;
|
||||
#if 0
|
||||
// more precise, less portable
|
||||
struct timeval tp;
|
||||
struct timezone tzp;
|
||||
static int secbase;
|
||||
|
||||
gettimeofday(&tp, &tzp);
|
||||
|
||||
if (!secbase)
|
||||
{
|
||||
secbase = tp.tv_sec;
|
||||
return tp.tv_usec/1000000.0;
|
||||
}
|
||||
|
||||
return (tp.tv_sec - secbase) + tp.tv_usec/1000000.0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
COM_Parse
|
||||
|
||||
Parse a token out of a string
|
||||
==============
|
||||
*/
|
||||
char *COM_Parse (char *data)
|
||||
{
|
||||
int c;
|
||||
int len;
|
||||
|
||||
len = 0;
|
||||
com_token[0] = 0;
|
||||
|
||||
if (!data)
|
||||
return NULL;
|
||||
|
||||
// skip whitespace
|
||||
skipwhite:
|
||||
while ( (c = *data) <= ' ')
|
||||
{
|
||||
if (c == 0)
|
||||
{
|
||||
com_eof = true;
|
||||
return NULL; // end of file;
|
||||
}
|
||||
data++;
|
||||
}
|
||||
|
||||
// skip // comments
|
||||
if (c=='/' && data[1] == '/')
|
||||
{
|
||||
while (*data && *data != '\n')
|
||||
data++;
|
||||
goto skipwhite;
|
||||
}
|
||||
|
||||
|
||||
// handle quoted strings specially
|
||||
if (c == '\"')
|
||||
{
|
||||
data++;
|
||||
do
|
||||
{
|
||||
c = *data++;
|
||||
if (c=='\"')
|
||||
{
|
||||
com_token[len] = 0;
|
||||
return data;
|
||||
}
|
||||
com_token[len] = c;
|
||||
len++;
|
||||
} while (1);
|
||||
}
|
||||
|
||||
// parse single characters
|
||||
if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
|
||||
{
|
||||
com_token[len] = c;
|
||||
len++;
|
||||
com_token[len] = 0;
|
||||
return data+1;
|
||||
}
|
||||
|
||||
// parse a regular word
|
||||
do
|
||||
{
|
||||
com_token[len] = c;
|
||||
data++;
|
||||
len++;
|
||||
c = *data;
|
||||
if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
|
||||
break;
|
||||
} while (c>32);
|
||||
|
||||
com_token[len] = 0;
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
int Q_strncasecmp (char *s1, char *s2, int n)
|
||||
{
|
||||
int c1, c2;
|
||||
|
||||
while (1)
|
||||
{
|
||||
c1 = *s1++;
|
||||
c2 = *s2++;
|
||||
|
||||
if (!n--)
|
||||
return 0; // strings are equal until end point
|
||||
|
||||
if (c1 != c2)
|
||||
{
|
||||
if (c1 >= 'a' && c1 <= 'z')
|
||||
c1 -= ('a' - 'A');
|
||||
if (c2 >= 'a' && c2 <= 'z')
|
||||
c2 -= ('a' - 'A');
|
||||
if (c1 != c2)
|
||||
return -1; // strings not equal
|
||||
}
|
||||
if (!c1)
|
||||
return 0; // strings are equal
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Q_strcasecmp (char *s1, char *s2)
|
||||
{
|
||||
return Q_strncasecmp (s1, s2, 99999);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
MISC FUNCTIONS
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
|
||||
int argc;
|
||||
char *argv[MAX_NUM_ARGVS];
|
||||
|
||||
/*
|
||||
============
|
||||
ParseCommandLine
|
||||
============
|
||||
*/
|
||||
void ParseCommandLine (char *lpCmdLine)
|
||||
{
|
||||
argc = 1;
|
||||
argv[0] = "programname";
|
||||
|
||||
while (*lpCmdLine && (argc < MAX_NUM_ARGVS))
|
||||
{
|
||||
while (*lpCmdLine && ((*lpCmdLine <= 32) || (*lpCmdLine > 126)))
|
||||
lpCmdLine++;
|
||||
|
||||
if (*lpCmdLine)
|
||||
{
|
||||
argv[argc] = lpCmdLine;
|
||||
argc++;
|
||||
|
||||
while (*lpCmdLine && ((*lpCmdLine > 32) && (*lpCmdLine <= 126)))
|
||||
lpCmdLine++;
|
||||
|
||||
if (*lpCmdLine)
|
||||
{
|
||||
*lpCmdLine = 0;
|
||||
lpCmdLine++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
CheckParm
|
||||
|
||||
Checks for the given parameter in the program's command line arguments
|
||||
Returns the argument number (1 to argc-1) or 0 if not present
|
||||
=================
|
||||
*/
|
||||
int CheckParm (char *check)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 1;i<argc;i++)
|
||||
{
|
||||
if ( !Q_strcasecmp(check, argv[i]) )
|
||||
return i;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Q_filelength
|
||||
================
|
||||
*/
|
||||
int Q_filelength (FILE *f)
|
||||
{
|
||||
int pos;
|
||||
int end;
|
||||
|
||||
pos = ftell (f);
|
||||
fseek (f, 0, SEEK_END);
|
||||
end = ftell (f);
|
||||
fseek (f, pos, SEEK_SET);
|
||||
|
||||
return end;
|
||||
}
|
||||
|
||||
|
||||
FILE *SafeOpenWrite (char *filename)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
f = fopen(filename, "wb");
|
||||
|
||||
if (!f)
|
||||
Error ("Error opening %s: %s",filename,strerror(errno));
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
FILE *SafeOpenRead (char *filename)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
f = fopen(filename, "rb");
|
||||
|
||||
if (!f)
|
||||
Error ("Error opening %s: %s",filename,strerror(errno));
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
void SafeRead (FILE *f, void *buffer, int count)
|
||||
{
|
||||
if ( (int)fread (buffer, 1, count, f) != count)
|
||||
Error ("File read failure");
|
||||
}
|
||||
|
||||
|
||||
void SafeWrite (FILE *f, void *buffer, int count)
|
||||
{
|
||||
if ( (int)fwrite (buffer, 1, count, f) != count)
|
||||
Error ("File read failure");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
LoadFile
|
||||
==============
|
||||
*/
|
||||
int LoadFile (char *filename, void **bufferptr)
|
||||
{
|
||||
FILE *f;
|
||||
int length;
|
||||
void *buffer;
|
||||
extern void *qmalloc( size_t size );
|
||||
|
||||
f = fopen (filename, "rb");
|
||||
if (!f)
|
||||
{
|
||||
*bufferptr = NULL;
|
||||
return -1;
|
||||
}
|
||||
length = Q_filelength (f);
|
||||
buffer = qmalloc (length+1);
|
||||
((char *)buffer)[length] = 0;
|
||||
SafeRead (f, buffer, length);
|
||||
fclose (f);
|
||||
|
||||
*bufferptr = buffer;
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
LoadFileNoCrash
|
||||
|
||||
returns -1 length if not present
|
||||
==============
|
||||
*/
|
||||
int LoadFileNoCrash (char *filename, void **bufferptr)
|
||||
{
|
||||
FILE *f;
|
||||
int length;
|
||||
void *buffer;
|
||||
|
||||
f = fopen (filename, "rb");
|
||||
if (!f)
|
||||
return -1;
|
||||
length = Q_filelength (f);
|
||||
buffer = qmalloc (length+1);
|
||||
((char *)buffer)[length] = 0;
|
||||
SafeRead (f, buffer, length);
|
||||
fclose (f);
|
||||
|
||||
*bufferptr = buffer;
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
SaveFile
|
||||
==============
|
||||
*/
|
||||
void SaveFile (char *filename, void *buffer, int count)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
f = SafeOpenWrite (filename);
|
||||
SafeWrite (f, buffer, count);
|
||||
fclose (f);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DefaultExtension (char *path, char *extension)
|
||||
{
|
||||
char *src;
|
||||
//
|
||||
// if path doesn't have a .EXT, append extension
|
||||
// (extension should include the .)
|
||||
//
|
||||
src = path + strlen(path) - 1;
|
||||
|
||||
while (*src != PATHSEPERATOR && src != path)
|
||||
{
|
||||
if (*src == '.')
|
||||
return; // it has an extension
|
||||
src--;
|
||||
}
|
||||
|
||||
strcat (path, extension);
|
||||
}
|
||||
|
||||
|
||||
void DefaultPath (char *path, char *basepath)
|
||||
{
|
||||
char temp[128];
|
||||
|
||||
if (path[0] == PATHSEPERATOR)
|
||||
return; // absolute path location
|
||||
strcpy (temp,path);
|
||||
strcpy (path,basepath);
|
||||
strcat (path,temp);
|
||||
}
|
||||
|
||||
|
||||
void StripFilename (char *path)
|
||||
{
|
||||
int length;
|
||||
|
||||
length = strlen(path)-1;
|
||||
while (length > 0 && path[length] != PATHSEPERATOR)
|
||||
length--;
|
||||
path[length] = 0;
|
||||
}
|
||||
|
||||
void StripExtension (char *path)
|
||||
{
|
||||
int length;
|
||||
|
||||
length = strlen(path)-1;
|
||||
while (length > 0 && path[length] != '.')
|
||||
{
|
||||
length--;
|
||||
if (path[length] == '/')
|
||||
return; // no extension
|
||||
}
|
||||
if (length)
|
||||
path[length] = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
Extract file parts
|
||||
====================
|
||||
*/
|
||||
void ExtractFilePath (char *path, char *dest)
|
||||
{
|
||||
char *src;
|
||||
|
||||
src = path + strlen(path) - 1;
|
||||
|
||||
//
|
||||
// back up until a \ or the start
|
||||
//
|
||||
while (src != path && *(src-1) != PATHSEPERATOR)
|
||||
src--;
|
||||
|
||||
memcpy (dest, path, src-path);
|
||||
dest[src-path] = 0;
|
||||
}
|
||||
|
||||
void ExtractFileName (char *path, char *dest)
|
||||
{
|
||||
char *src;
|
||||
|
||||
src = path + strlen(path) - 1;
|
||||
|
||||
//
|
||||
// back up until a \ or the start
|
||||
//
|
||||
while (src != path && *(src-1) != '/'
|
||||
&& *(src-1) != '\\' )
|
||||
src--;
|
||||
|
||||
while (*src)
|
||||
{
|
||||
*dest++ = *src++;
|
||||
}
|
||||
*dest = 0;
|
||||
}
|
||||
|
||||
void ExtractFileBase (char *path, char *dest)
|
||||
{
|
||||
char *src;
|
||||
|
||||
src = path + strlen(path) - 1;
|
||||
|
||||
//
|
||||
// back up until a \ or the start
|
||||
//
|
||||
while (src != path && *(src-1) != '/'
|
||||
&& *(src-1) != '\\' )
|
||||
src--;
|
||||
|
||||
while (*src && *src != '.')
|
||||
{
|
||||
*dest++ = *src++;
|
||||
}
|
||||
*dest = 0;
|
||||
}
|
||||
|
||||
void ExtractFileExtension (char *path, char *dest)
|
||||
{
|
||||
char *src;
|
||||
|
||||
src = path + strlen(path) - 1;
|
||||
|
||||
//
|
||||
// back up until a . or the start
|
||||
//
|
||||
while (src != path && *(src-1) != '.')
|
||||
src--;
|
||||
if (src == path)
|
||||
{
|
||||
*dest = 0; // no extension
|
||||
return;
|
||||
}
|
||||
|
||||
strcpy (dest,src);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
ParseNum / ParseHex
|
||||
==============
|
||||
*/
|
||||
int ParseHex (char *hex)
|
||||
{
|
||||
char *str;
|
||||
int num;
|
||||
|
||||
num = 0;
|
||||
str = hex;
|
||||
|
||||
while (*str)
|
||||
{
|
||||
num <<= 4;
|
||||
if (*str >= '0' && *str <= '9')
|
||||
num += *str-'0';
|
||||
else if (*str >= 'a' && *str <= 'f')
|
||||
num += 10 + *str-'a';
|
||||
else if (*str >= 'A' && *str <= 'F')
|
||||
num += 10 + *str-'A';
|
||||
else
|
||||
Error ("Bad hex number: %s",hex);
|
||||
str++;
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
|
||||
int ParseNum (char *str)
|
||||
{
|
||||
if (str[0] == '$')
|
||||
return ParseHex (str+1);
|
||||
if (str[0] == '0' && str[1] == 'x')
|
||||
return ParseHex (str+2);
|
||||
return atol (str);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
============================================================================
|
||||
|
||||
BYTE ORDER FUNCTIONS
|
||||
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifdef _SGI_SOURCE
|
||||
#define __BIG_ENDIAN__
|
||||
#endif
|
||||
|
||||
#ifdef __BIG_ENDIAN__
|
||||
|
||||
short LittleShort (short l)
|
||||
{
|
||||
byte b1,b2;
|
||||
|
||||
b1 = l&255;
|
||||
b2 = (l>>8)&255;
|
||||
|
||||
return (b1<<8) + b2;
|
||||
}
|
||||
|
||||
short BigShort (short l)
|
||||
{
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
int LittleLong (int l)
|
||||
{
|
||||
byte b1,b2,b3,b4;
|
||||
|
||||
b1 = l&255;
|
||||
b2 = (l>>8)&255;
|
||||
b3 = (l>>16)&255;
|
||||
b4 = (l>>24)&255;
|
||||
|
||||
return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
|
||||
}
|
||||
|
||||
int BigLong (int l)
|
||||
{
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
float LittleFloat (float l)
|
||||
{
|
||||
union {byte b[4]; float f;} in, out;
|
||||
|
||||
in.f = l;
|
||||
out.b[0] = in.b[3];
|
||||
out.b[1] = in.b[2];
|
||||
out.b[2] = in.b[1];
|
||||
out.b[3] = in.b[0];
|
||||
|
||||
return out.f;
|
||||
}
|
||||
|
||||
float BigFloat (float l)
|
||||
{
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
|
||||
short BigShort (short l)
|
||||
{
|
||||
byte b1,b2;
|
||||
|
||||
b1 = l&255;
|
||||
b2 = (l>>8)&255;
|
||||
|
||||
return (b1<<8) + b2;
|
||||
}
|
||||
|
||||
short LittleShort (short l)
|
||||
{
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
int BigLong (int l)
|
||||
{
|
||||
byte b1,b2,b3,b4;
|
||||
|
||||
b1 = l&255;
|
||||
b2 = (l>>8)&255;
|
||||
b3 = (l>>16)&255;
|
||||
b4 = (l>>24)&255;
|
||||
|
||||
return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
|
||||
}
|
||||
|
||||
int LittleLong (int l)
|
||||
{
|
||||
return l;
|
||||
}
|
||||
|
||||
float BigFloat (float l)
|
||||
{
|
||||
union {byte b[4]; float f;} in, out;
|
||||
|
||||
in.f = l;
|
||||
out.b[0] = in.b[3];
|
||||
out.b[1] = in.b[2];
|
||||
out.b[2] = in.b[1];
|
||||
out.b[3] = in.b[0];
|
||||
|
||||
return out.f;
|
||||
}
|
||||
|
||||
float LittleFloat (float l)
|
||||
{
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
99
tools/quake2/extra/qe4/cmdlib.h
Normal file
99
tools/quake2/extra/qe4/cmdlib.h
Normal file
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// cmdlib.h
|
||||
|
||||
#ifndef __CMDLIB__
|
||||
#define __CMDLIB__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifndef __BYTEBOOL__
|
||||
#define __BYTEBOOL__
|
||||
typedef enum {false, true} qboolean;
|
||||
typedef unsigned char byte;
|
||||
#endif
|
||||
|
||||
// the dec offsetof macro doesn't work very well...
|
||||
#define myoffsetof(type,identifier) ((size_t)&((type *)0)->identifier)
|
||||
|
||||
|
||||
// set these before calling CheckParm
|
||||
extern int myargc;
|
||||
extern char **myargv;
|
||||
|
||||
int Q_strncasecmp (char *s1, char *s2, int n);
|
||||
int Q_strcasecmp (char *s1, char *s2);
|
||||
|
||||
int Q_filelength (FILE *f);
|
||||
|
||||
double I_FloatTime (void);
|
||||
|
||||
void Error (char *error, ...);
|
||||
int CheckParm (char *check);
|
||||
void ParseCommandLine (char *lpCmdLine);
|
||||
|
||||
FILE *SafeOpenWrite (char *filename);
|
||||
FILE *SafeOpenRead (char *filename);
|
||||
void SafeRead (FILE *f, void *buffer, int count);
|
||||
void SafeWrite (FILE *f, void *buffer, int count);
|
||||
|
||||
int LoadFile (char *filename, void **bufferptr);
|
||||
int LoadFileNoCrash (char *filename, void **bufferptr);
|
||||
void SaveFile (char *filename, void *buffer, int count);
|
||||
|
||||
void DefaultExtension (char *path, char *extension);
|
||||
void DefaultPath (char *path, char *basepath);
|
||||
void StripFilename (char *path);
|
||||
void StripExtension (char *path);
|
||||
|
||||
void ExtractFilePath (char *path, char *dest);
|
||||
void ExtractFileName (char *path, char *dest);
|
||||
void ExtractFileBase (char *path, char *dest);
|
||||
void ExtractFileExtension (char *path, char *dest);
|
||||
|
||||
int ParseNum (char *str);
|
||||
|
||||
short BigShort (short l);
|
||||
short LittleShort (short l);
|
||||
int BigLong (int l);
|
||||
int LittleLong (int l);
|
||||
float BigFloat (float l);
|
||||
float LittleFloat (float l);
|
||||
|
||||
|
||||
char *COM_Parse (char *data);
|
||||
|
||||
extern char com_token[1024];
|
||||
extern qboolean com_eof;
|
||||
|
||||
#define MAX_NUM_ARGVS 32
|
||||
extern int argc;
|
||||
extern char *argv[MAX_NUM_ARGVS];
|
||||
|
||||
#endif
|
168
tools/quake2/extra/qe4/csg.c
Normal file
168
tools/quake2/extra/qe4/csg.c
Normal file
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "qe3.h"
|
||||
|
||||
/*
|
||||
==============
|
||||
CSG_SplitBrushByFace
|
||||
|
||||
The incoming brush is NOT freed.
|
||||
The incoming face is NOT left referenced.
|
||||
==============
|
||||
*/
|
||||
void CSG_SplitBrushByFace (brush_t *in, face_t *f, brush_t **front, brush_t **back)
|
||||
{
|
||||
brush_t *b;
|
||||
face_t *nf;
|
||||
vec3_t temp;
|
||||
|
||||
b = Brush_Clone (in);
|
||||
nf = Face_Clone (f);
|
||||
|
||||
nf->texdef = b->brush_faces->texdef;
|
||||
nf->next = b->brush_faces;
|
||||
b->brush_faces = nf;
|
||||
|
||||
Brush_Build( b );
|
||||
Brush_RemoveEmptyFaces ( b );
|
||||
if ( !b->brush_faces )
|
||||
{ // completely clipped away
|
||||
Brush_Free (b);
|
||||
*back = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
Entity_LinkBrush (in->owner, b);
|
||||
*back = b;
|
||||
}
|
||||
|
||||
b = Brush_Clone (in);
|
||||
nf = Face_Clone (f);
|
||||
// swap the plane winding
|
||||
VectorCopy (nf->planepts[0], temp);
|
||||
VectorCopy (nf->planepts[1], nf->planepts[0]);
|
||||
VectorCopy (temp, nf->planepts[1]);
|
||||
|
||||
nf->texdef = b->brush_faces->texdef;
|
||||
nf->next = b->brush_faces;
|
||||
b->brush_faces = nf;
|
||||
|
||||
Brush_Build( b );
|
||||
Brush_RemoveEmptyFaces ( b );
|
||||
if ( !b->brush_faces )
|
||||
{ // completely clipped away
|
||||
Brush_Free (b);
|
||||
*front = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
Entity_LinkBrush (in->owner, b);
|
||||
*front = b;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
CSG_MakeHollow
|
||||
=============
|
||||
*/
|
||||
void CSG_MakeHollow (void)
|
||||
{
|
||||
brush_t *b, *front, *back, *next;
|
||||
face_t *f;
|
||||
face_t split;
|
||||
vec3_t move;
|
||||
int i;
|
||||
|
||||
for (b = selected_brushes.next ; b != &selected_brushes ; b=next)
|
||||
{
|
||||
next = b->next;
|
||||
for (f = b->brush_faces ; f ; f=f->next)
|
||||
{
|
||||
split = *f;
|
||||
VectorScale (f->plane.normal, g_qeglobals.d_gridsize, move);
|
||||
for (i=0 ; i<3 ; i++)
|
||||
VectorSubtract (split.planepts[i], move, split.planepts[i]);
|
||||
|
||||
CSG_SplitBrushByFace (b, &split, &front, &back);
|
||||
if (back)
|
||||
Brush_Free (back);
|
||||
if (front)
|
||||
Brush_AddToList (front, &selected_brushes);
|
||||
}
|
||||
Brush_Free (b);
|
||||
}
|
||||
Sys_UpdateWindows (W_ALL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
CSG_Subtract
|
||||
=============
|
||||
*/
|
||||
void CSG_Subtract (void)
|
||||
{
|
||||
brush_t *b, *s, *frag, *front, *back, *next, *snext;
|
||||
face_t *f;
|
||||
int i;
|
||||
|
||||
Sys_Printf ("Subtracting...\n");
|
||||
|
||||
for (b = selected_brushes.next ; b != &selected_brushes ; b=next)
|
||||
{
|
||||
next = b->next;
|
||||
|
||||
if (b->owner->eclass->fixedsize)
|
||||
continue; // can't use texture from a fixed entity, so don't subtract
|
||||
|
||||
for (s=active_brushes.next ; s != &active_brushes ; s=snext)
|
||||
{
|
||||
snext = s->next;
|
||||
if (s->owner->eclass->fixedsize)
|
||||
continue;
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
if (b->mins[i] >= s->maxs[i] - ON_EPSILON
|
||||
|| b->maxs[i] <= s->mins[i] + ON_EPSILON)
|
||||
break;
|
||||
if (i != 3)
|
||||
continue; // definately don't touch
|
||||
|
||||
frag = s;
|
||||
for (f = b->brush_faces ; f && frag ; f=f->next)
|
||||
{
|
||||
CSG_SplitBrushByFace (frag, f, &front, &back);
|
||||
Brush_Free (frag);
|
||||
frag = back;
|
||||
if (front)
|
||||
Brush_AddToList (front, &active_brushes);
|
||||
}
|
||||
if (frag)
|
||||
Brush_Free (frag);
|
||||
}
|
||||
}
|
||||
|
||||
Sys_Printf ("done.\n");
|
||||
Sys_UpdateWindows (W_ALL);
|
||||
}
|
457
tools/quake2/extra/qe4/drag.c
Normal file
457
tools/quake2/extra/qe4/drag.c
Normal file
|
@ -0,0 +1,457 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "qe3.h"
|
||||
|
||||
/*
|
||||
|
||||
drag either multiple brushes, or select plane points from
|
||||
a single brush.
|
||||
|
||||
*/
|
||||
|
||||
qboolean drag_ok;
|
||||
vec3_t drag_xvec;
|
||||
vec3_t drag_yvec;
|
||||
|
||||
static int buttonstate;
|
||||
static int pressx, pressy;
|
||||
static vec3_t pressdelta;
|
||||
static int buttonx, buttony;
|
||||
|
||||
|
||||
//int num_move_points;
|
||||
//float *move_points[1024];
|
||||
|
||||
int lastx, lasty;
|
||||
|
||||
qboolean drag_first;
|
||||
|
||||
|
||||
void AxializeVector (vec3_t v)
|
||||
{
|
||||
vec3_t a;
|
||||
float o;
|
||||
int i;
|
||||
|
||||
if (!v[0] && !v[1])
|
||||
return;
|
||||
if (!v[1] && !v[2])
|
||||
return;
|
||||
if (!v[0] && !v[2])
|
||||
return;
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
a[i] = fabs(v[i]);
|
||||
if (a[0] > a[1] && a[0] > a[2])
|
||||
i = 0;
|
||||
else if (a[1] > a[0] && a[1] > a[2])
|
||||
i = 1;
|
||||
else
|
||||
i = 2;
|
||||
|
||||
o = v[i];
|
||||
VectorCopy (vec3_origin, v);
|
||||
if (o<0)
|
||||
v[i] = -1;
|
||||
else
|
||||
v[i] = 1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===========
|
||||
Drag_Setup
|
||||
===========
|
||||
*/
|
||||
void Drag_Setup (int x, int y, int buttons,
|
||||
vec3_t xaxis, vec3_t yaxis,
|
||||
vec3_t origin, vec3_t dir)
|
||||
{
|
||||
trace_t t;
|
||||
face_t *f;
|
||||
|
||||
if (selected_brushes.next == &selected_brushes)
|
||||
{
|
||||
Sys_Status("No selection to drag\n", 0);
|
||||
return;
|
||||
}
|
||||
|
||||
drag_first = true;
|
||||
g_qeglobals.d_num_move_points = 0;
|
||||
VectorCopy (vec3_origin, pressdelta);
|
||||
pressx = x;
|
||||
pressy = y;
|
||||
|
||||
VectorCopy (xaxis, drag_xvec);
|
||||
AxializeVector (drag_xvec);
|
||||
VectorCopy (yaxis, drag_yvec);
|
||||
AxializeVector (drag_yvec);
|
||||
|
||||
if (g_qeglobals.d_select_mode == sel_vertex)
|
||||
{
|
||||
SelectVertexByRay (origin, dir);
|
||||
if (g_qeglobals.d_num_move_points)
|
||||
{
|
||||
drag_ok = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (g_qeglobals.d_select_mode == sel_edge)
|
||||
{
|
||||
SelectEdgeByRay (origin, dir);
|
||||
if (g_qeglobals.d_num_move_points)
|
||||
{
|
||||
drag_ok = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// check for direct hit first
|
||||
//
|
||||
t = Test_Ray (origin, dir, true);
|
||||
if (t.selected)
|
||||
{
|
||||
drag_ok = true;
|
||||
|
||||
if (buttons == (MK_LBUTTON|MK_CONTROL) )
|
||||
{
|
||||
Sys_Printf ("Shear dragging face\n");
|
||||
Brush_SelectFaceForDragging (t.brush, t.face, true);
|
||||
}
|
||||
else if (buttons == (MK_LBUTTON|MK_CONTROL|MK_SHIFT) )
|
||||
{
|
||||
Sys_Printf ("Sticky dragging brush\n");
|
||||
for (f=t.brush->brush_faces ; f ; f=f->next)
|
||||
Brush_SelectFaceForDragging (t.brush, f, false);
|
||||
}
|
||||
else
|
||||
Sys_Printf ("Dragging entire selection\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge)
|
||||
return;
|
||||
|
||||
//
|
||||
// check for side hit
|
||||
//
|
||||
if (selected_brushes.next->next != &selected_brushes)
|
||||
{
|
||||
Sys_Printf ("Click isn't inside multiple selection\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (selected_brushes.next->owner->eclass->fixedsize)
|
||||
{
|
||||
Sys_Printf ("Can't stretch fixed size entities\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (buttons & MK_CONTROL)
|
||||
Brush_SideSelect (selected_brushes.next, origin, dir, true);
|
||||
else
|
||||
Brush_SideSelect (selected_brushes.next, origin, dir, false);
|
||||
|
||||
|
||||
Sys_Printf ("Side stretch\n");
|
||||
drag_ok = true;
|
||||
}
|
||||
|
||||
entity_t *peLink;
|
||||
|
||||
void UpdateTarget(vec3_t origin, vec3_t dir)
|
||||
{
|
||||
trace_t t;
|
||||
entity_t *pe;
|
||||
int i;
|
||||
char sz[128];
|
||||
|
||||
t = Test_Ray (origin, dir, 0);
|
||||
|
||||
if (!t.brush)
|
||||
return;
|
||||
|
||||
pe = t.brush->owner;
|
||||
|
||||
if (pe == NULL)
|
||||
return;
|
||||
|
||||
// is this the first?
|
||||
if (peLink != NULL)
|
||||
{
|
||||
|
||||
// Get the target id from out current target
|
||||
// if there is no id, make one
|
||||
|
||||
i = IntForKey(pe, "target");
|
||||
if (i <= 0)
|
||||
{
|
||||
i = GetUniqueTargetId(1);
|
||||
sprintf(sz, "%d", i);
|
||||
|
||||
SetKeyValue(pe, "target", sz);
|
||||
}
|
||||
|
||||
// set the target # into our src
|
||||
|
||||
sprintf(sz, "%d", i);
|
||||
SetKeyValue(peLink, "targetname", sz);
|
||||
|
||||
Sys_UpdateWindows(W_ENTITY);
|
||||
|
||||
}
|
||||
|
||||
// promote the target to the src
|
||||
|
||||
peLink = pe;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
Drag_Begin
|
||||
===========
|
||||
*/
|
||||
void Drag_Begin (int x, int y, int buttons,
|
||||
vec3_t xaxis, vec3_t yaxis,
|
||||
vec3_t origin, vec3_t dir)
|
||||
{
|
||||
trace_t t;
|
||||
|
||||
drag_ok = false;
|
||||
VectorCopy (vec3_origin, pressdelta);
|
||||
|
||||
drag_first = true;
|
||||
peLink = NULL;
|
||||
|
||||
// shift LBUTTON = select entire brush
|
||||
if (buttons == (MK_LBUTTON | MK_SHIFT))
|
||||
{
|
||||
if (!dir[0] && !dir[1])
|
||||
Select_Ray (origin, dir, SF_ENTITIES_FIRST); // hack for XY
|
||||
else
|
||||
Select_Ray (origin, dir, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// ctrl-shift LBUTTON = select single face
|
||||
if (buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT))
|
||||
{
|
||||
Select_Deselect ();
|
||||
Select_Ray (origin, dir, SF_SINGLEFACE);
|
||||
return;
|
||||
}
|
||||
|
||||
// LBUTTON + all other modifiers = manipulate selection
|
||||
if (buttons & MK_LBUTTON)
|
||||
{
|
||||
Drag_Setup (x, y, buttons, xaxis, yaxis, origin, dir);
|
||||
return;
|
||||
}
|
||||
|
||||
// middle button = grab texture
|
||||
if (buttons == MK_MBUTTON)
|
||||
{
|
||||
t = Test_Ray (origin, dir, false);
|
||||
if (t.face)
|
||||
{
|
||||
g_qeglobals.d_new_brush_bottom_z = t.brush->mins[2];
|
||||
g_qeglobals.d_new_brush_top_z = t.brush->maxs[2];
|
||||
Texture_SetTexture (&t.face->texdef);
|
||||
}
|
||||
else
|
||||
Sys_Printf ("Did not select a texture\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// ctrl-middle button = set entire brush to texture
|
||||
if (buttons == (MK_MBUTTON|MK_CONTROL) )
|
||||
{
|
||||
t = Test_Ray (origin, dir, false);
|
||||
if (t.brush)
|
||||
{
|
||||
if (t.brush->brush_faces->texdef.name[0] == '(')
|
||||
Sys_Printf ("Can't change an entity texture\n");
|
||||
else
|
||||
{
|
||||
Brush_SetTexture (t.brush, &g_qeglobals.d_texturewin.texdef);
|
||||
Sys_UpdateWindows (W_ALL);
|
||||
}
|
||||
}
|
||||
else
|
||||
Sys_Printf ("Didn't hit a btrush\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// ctrl-shift-middle button = set single face to texture
|
||||
if (buttons == (MK_MBUTTON|MK_SHIFT|MK_CONTROL) )
|
||||
{
|
||||
t = Test_Ray (origin, dir, false);
|
||||
if (t.brush)
|
||||
{
|
||||
if (t.brush->brush_faces->texdef.name[0] == '(')
|
||||
Sys_Printf ("Can't change an entity texture\n");
|
||||
else
|
||||
{
|
||||
t.face->texdef = g_qeglobals.d_texturewin.texdef;
|
||||
Brush_Build( t.brush );
|
||||
Sys_UpdateWindows (W_ALL);
|
||||
}
|
||||
}
|
||||
else
|
||||
Sys_Printf ("Didn't hit a btrush\n");
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===========
|
||||
MoveSelection
|
||||
===========
|
||||
*/
|
||||
void MoveSelection (vec3_t move)
|
||||
{
|
||||
int i;
|
||||
brush_t *b;
|
||||
|
||||
if (!move[0] && !move[1] && !move[2])
|
||||
return;
|
||||
|
||||
Sys_UpdateWindows (W_XY|W_CAMERA);
|
||||
|
||||
//
|
||||
// dragging only a part of the selection
|
||||
//
|
||||
if (g_qeglobals.d_num_move_points)
|
||||
{
|
||||
for (i=0 ; i<g_qeglobals.d_num_move_points ; i++)
|
||||
VectorAdd (g_qeglobals.d_move_points[i], move, g_qeglobals.d_move_points[i]);
|
||||
|
||||
for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
|
||||
{
|
||||
Brush_Build( b );
|
||||
for (i=0 ; i<3 ; i++)
|
||||
if (b->mins[i] > b->maxs[i]
|
||||
|| b->maxs[i] - b->mins[i] > 4096)
|
||||
break; // dragged backwards or fucked up
|
||||
if (i != 3)
|
||||
break;
|
||||
}
|
||||
|
||||
// if any of the brushes were crushed out of existance
|
||||
// calcel the entire move
|
||||
if (b != &selected_brushes)
|
||||
{
|
||||
Sys_Printf ("Brush dragged backwards, move canceled\n");
|
||||
for (i=0 ; i<g_qeglobals.d_num_move_points ; i++)
|
||||
VectorSubtract (g_qeglobals.d_move_points[i], move, g_qeglobals.d_move_points[i]);
|
||||
|
||||
for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
|
||||
Brush_Build( b );
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// if there are lots of brushes selected, just translate instead
|
||||
// of rebuilding the brushes
|
||||
//
|
||||
if (drag_yvec[2] == 0 && selected_brushes.next->next != &selected_brushes)
|
||||
{
|
||||
VectorAdd (g_qeglobals.d_select_translate, move, g_qeglobals.d_select_translate);
|
||||
}
|
||||
else
|
||||
{
|
||||
Select_Move (move);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
Drag_MouseMoved
|
||||
===========
|
||||
*/
|
||||
void Drag_MouseMoved (int x, int y, int buttons)
|
||||
{
|
||||
vec3_t move, delta;
|
||||
int i;
|
||||
char movestring[128];
|
||||
|
||||
if (!buttons)
|
||||
{
|
||||
drag_ok = false;
|
||||
return;
|
||||
}
|
||||
if (!drag_ok)
|
||||
return;
|
||||
|
||||
// clear along one axis
|
||||
if (buttons & MK_SHIFT)
|
||||
{
|
||||
drag_first = false;
|
||||
if (abs(x-pressx) > abs(y-pressy))
|
||||
y = pressy;
|
||||
else
|
||||
x = pressx;
|
||||
}
|
||||
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
move[i] = drag_xvec[i]*(x - pressx)
|
||||
+ drag_yvec[i]*(y - pressy);
|
||||
move[i] = floor(move[i]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize;
|
||||
}
|
||||
|
||||
sprintf (movestring, "drag (%i %i %i)", (int)move[0], (int)move[1], (int)move[2]);
|
||||
Sys_Status (movestring, 0);
|
||||
|
||||
VectorSubtract (move, pressdelta, delta);
|
||||
MoveSelection (delta);
|
||||
VectorCopy (move, pressdelta);
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
Drag_MouseUp
|
||||
===========
|
||||
*/
|
||||
void Drag_MouseUp (void)
|
||||
{
|
||||
Sys_Status ("drag completed.", 0);
|
||||
if (g_qeglobals.d_select_translate[0] || g_qeglobals.d_select_translate[1] || g_qeglobals.d_select_translate[2])
|
||||
{
|
||||
Select_Move (g_qeglobals.d_select_translate);
|
||||
VectorCopy (vec3_origin, g_qeglobals.d_select_translate);
|
||||
Sys_UpdateWindows (W_CAMERA);
|
||||
}
|
||||
}
|
281
tools/quake2/extra/qe4/eclass.c
Normal file
281
tools/quake2/extra/qe4/eclass.c
Normal file
|
@ -0,0 +1,281 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "qe3.h"
|
||||
#include "io.h"
|
||||
|
||||
eclass_t *eclass;
|
||||
eclass_t *eclass_bad;
|
||||
char eclass_directory[1024];
|
||||
|
||||
/*
|
||||
|
||||
the classname, color triple, and bounding box are parsed out of comments
|
||||
A ? size means take the exact brush size.
|
||||
|
||||
/*QUAKED <classname> (0 0 0) ?
|
||||
/*QUAKED <classname> (0 0 0) (-8 -8 -8) (8 8 8)
|
||||
|
||||
Flag names can follow the size description:
|
||||
|
||||
/*QUAKED func_door (0 .5 .8) ? START_OPEN STONE_SOUND DOOR_DONT_LINK GOLD_KEY SILVER_KEY
|
||||
|
||||
*/
|
||||
char *debugname;
|
||||
|
||||
eclass_t *Eclass_InitFromText (char *text)
|
||||
{
|
||||
char *t;
|
||||
int len;
|
||||
int r, i;
|
||||
char parms[256], *p;
|
||||
eclass_t *e;
|
||||
char color[128];
|
||||
|
||||
e = qmalloc(sizeof(*e));
|
||||
memset (e, 0, sizeof(*e));
|
||||
|
||||
text += strlen("/*QUAKED ");
|
||||
|
||||
// grab the name
|
||||
text = COM_Parse (text);
|
||||
e->name = qmalloc (strlen(com_token)+1);
|
||||
strcpy (e->name, com_token);
|
||||
debugname = e->name;
|
||||
|
||||
// grab the color, reformat as texture name
|
||||
r = sscanf (text," (%f %f %f)", &e->color[0], &e->color[1], &e->color[2]);
|
||||
if (r != 3)
|
||||
return e;
|
||||
sprintf (color, "(%f %f %f)", e->color[0], e->color[1], e->color[2]);
|
||||
strcpy (e->texdef.name, color);
|
||||
|
||||
while (*text != ')')
|
||||
{
|
||||
if (!*text)
|
||||
return e;
|
||||
text++;
|
||||
}
|
||||
text++;
|
||||
|
||||
// get the size
|
||||
text = COM_Parse (text);
|
||||
if (com_token[0] == '(')
|
||||
{ // parse the size as two vectors
|
||||
e->fixedsize = true;
|
||||
r = sscanf (text,"%f %f %f) (%f %f %f)", &e->mins[0], &e->mins[1], &e->mins[2],
|
||||
&e->maxs[0], &e->maxs[1], &e->maxs[2]);
|
||||
if (r != 6)
|
||||
return e;
|
||||
|
||||
for (i=0 ; i<2 ; i++)
|
||||
{
|
||||
while (*text != ')')
|
||||
{
|
||||
if (!*text)
|
||||
return e;
|
||||
text++;
|
||||
}
|
||||
text++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // use the brushes
|
||||
}
|
||||
|
||||
// get the flags
|
||||
|
||||
|
||||
// copy to the first /n
|
||||
p = parms;
|
||||
while (*text && *text != '\n')
|
||||
*p++ = *text++;
|
||||
*p = 0;
|
||||
text++;
|
||||
|
||||
// any remaining words are parm flags
|
||||
p = parms;
|
||||
for (i=0 ; i<8 ; i++)
|
||||
{
|
||||
p = COM_Parse (p);
|
||||
if (!p)
|
||||
break;
|
||||
strcpy (e->flagnames[i], com_token);
|
||||
}
|
||||
|
||||
// find the length until close comment
|
||||
for (t=text ; t[0] && !(t[0]=='*' && t[1]=='/') ; t++)
|
||||
;
|
||||
|
||||
// copy the comment block out
|
||||
len = t-text;
|
||||
e->comments = qmalloc (len+1);
|
||||
memcpy (e->comments, text, len);
|
||||
#if 0
|
||||
for (i=0 ; i<len ; i++)
|
||||
if (text[i] == '\n')
|
||||
e->comments[i] = '\r';
|
||||
else
|
||||
e->comments[i] = text[i];
|
||||
#endif
|
||||
e->comments[len] = 0;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
Eclass_InsertAlphabetized
|
||||
=================
|
||||
*/
|
||||
void Eclass_InsertAlphabetized (eclass_t *e)
|
||||
{
|
||||
eclass_t *s;
|
||||
|
||||
if (!eclass)
|
||||
{
|
||||
eclass = e;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
s = eclass;
|
||||
if (stricmp (e->name, s->name) < 0)
|
||||
{
|
||||
e->next = s;
|
||||
eclass = e;
|
||||
return;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
if (!s->next || stricmp (e->name, s->next->name) < 0)
|
||||
{
|
||||
e->next = s->next;
|
||||
s->next = e;
|
||||
return;
|
||||
}
|
||||
s=s->next;
|
||||
} while (1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
Eclass_ScanFile
|
||||
=================
|
||||
*/
|
||||
void Eclass_ScanFile (char *filename)
|
||||
{
|
||||
int size;
|
||||
char *data;
|
||||
eclass_t *e;
|
||||
int i;
|
||||
char temp[1024];
|
||||
|
||||
QE_ConvertDOSToUnixName( temp, filename );
|
||||
|
||||
Sys_Printf ("ScanFile: %s\n", temp);
|
||||
|
||||
size = LoadFile (filename, (void *)&data);
|
||||
|
||||
for (i=0 ; i<size ; i++)
|
||||
if (!strncmp(data+i, "/*QUAKED",8))
|
||||
{
|
||||
e = Eclass_InitFromText (data+i);
|
||||
if (e)
|
||||
Eclass_InsertAlphabetized (e);
|
||||
else
|
||||
printf ("Error parsing: %s in %s\n",debugname, filename);
|
||||
}
|
||||
|
||||
free (data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Eclass_InitForSourceDirectory (char *path)
|
||||
{
|
||||
struct _finddata_t fileinfo;
|
||||
int handle;
|
||||
char filename[1024];
|
||||
char filebase[1024];
|
||||
char temp[1024];
|
||||
char *s;
|
||||
|
||||
QE_ConvertDOSToUnixName( temp, path );
|
||||
|
||||
Sys_Printf ("Eclass_InitForSourceDirectory: %s\n", temp );
|
||||
|
||||
strcpy (filebase, path);
|
||||
s = filebase + strlen(filebase)-1;
|
||||
while (*s != '\\' && *s != '/' && s!=filebase)
|
||||
s--;
|
||||
*s = 0;
|
||||
|
||||
eclass = NULL;
|
||||
|
||||
handle = _findfirst (path, &fileinfo);
|
||||
if (handle != -1)
|
||||
{
|
||||
do
|
||||
{
|
||||
sprintf (filename, "%s\\%s", filebase, fileinfo.name);
|
||||
Eclass_ScanFile (filename);
|
||||
} while (_findnext( handle, &fileinfo ) != -1);
|
||||
|
||||
_findclose (handle);
|
||||
}
|
||||
|
||||
eclass_bad = Eclass_InitFromText ("/*QUAKED UNKNOWN_CLASS (0 0.5 0) ?");
|
||||
}
|
||||
|
||||
eclass_t *Eclass_ForName (char *name, qboolean has_brushes)
|
||||
{
|
||||
eclass_t *e;
|
||||
char init[1024];
|
||||
|
||||
if (!name)
|
||||
return eclass_bad;
|
||||
|
||||
for (e=eclass ; e ; e=e->next)
|
||||
if (!strcmp (name, e->name))
|
||||
return e;
|
||||
|
||||
// create a new class for it
|
||||
if (has_brushes)
|
||||
{
|
||||
sprintf (init, "/*QUAKED %s (0 0.5 0) ?\nNot found in source.\n", name);
|
||||
e = Eclass_InitFromText (init);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf (init, "/*QUAKED %s (0 0.5 0) (-8 -8 -8) (8 8 8)\nNot found in source.\n", name);
|
||||
e = Eclass_InitFromText (init);
|
||||
}
|
||||
|
||||
Eclass_InsertAlphabetized (e);
|
||||
|
||||
return e;
|
||||
}
|
||||
|
538
tools/quake2/extra/qe4/entity.c
Normal file
538
tools/quake2/extra/qe4/entity.c
Normal file
|
@ -0,0 +1,538 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "qe3.h"
|
||||
|
||||
char *ValueForKey (entity_t *ent, char *key)
|
||||
{
|
||||
epair_t *ep;
|
||||
|
||||
for (ep=ent->epairs ; ep ; ep=ep->next)
|
||||
if (!strcmp (ep->key, key) )
|
||||
return ep->value;
|
||||
return "";
|
||||
}
|
||||
|
||||
void SetKeyValue (entity_t *ent, char *key, char *value)
|
||||
{
|
||||
epair_t *ep;
|
||||
|
||||
if (ent == NULL)
|
||||
return;
|
||||
|
||||
if (!key || !key[0])
|
||||
return;
|
||||
|
||||
for (ep=ent->epairs ; ep ; ep=ep->next)
|
||||
if (!strcmp (ep->key, key) )
|
||||
{
|
||||
free (ep->value);
|
||||
ep->value = qmalloc(strlen(value)+1);
|
||||
strcpy (ep->value, value);
|
||||
return;
|
||||
}
|
||||
ep = qmalloc (sizeof(*ep));
|
||||
ep->next = ent->epairs;
|
||||
ent->epairs = ep;
|
||||
ep->key = qmalloc(strlen(key)+1);
|
||||
strcpy (ep->key, key);
|
||||
ep->value = qmalloc(strlen(value)+1);
|
||||
strcpy (ep->value, value);
|
||||
}
|
||||
|
||||
void DeleteKey (entity_t *ent, char *key)
|
||||
{
|
||||
epair_t **ep, *next;
|
||||
|
||||
ep = &ent->epairs;
|
||||
while (*ep)
|
||||
{
|
||||
next = *ep;
|
||||
if ( !strcmp (next->key, key) )
|
||||
{
|
||||
*ep = next->next;
|
||||
free(next->key);
|
||||
free(next->value);
|
||||
free(next);
|
||||
return;
|
||||
}
|
||||
ep = &next->next;
|
||||
}
|
||||
}
|
||||
|
||||
float FloatForKey (entity_t *ent, char *key)
|
||||
{
|
||||
char *k;
|
||||
|
||||
k = ValueForKey (ent, key);
|
||||
return atof(k);
|
||||
}
|
||||
|
||||
int IntForKey (entity_t *ent, char *key)
|
||||
{
|
||||
char *k;
|
||||
|
||||
k = ValueForKey (ent, key);
|
||||
return atoi(k);
|
||||
}
|
||||
|
||||
void GetVectorForKey (entity_t *ent, char *key, vec3_t vec)
|
||||
{
|
||||
char *k;
|
||||
|
||||
k = ValueForKey (ent, key);
|
||||
sscanf (k, "%f %f %f", &vec[0], &vec[1], &vec[2]);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
Entity_Free
|
||||
|
||||
Frees the entity and any brushes is has.
|
||||
The entity is removed from the global entities list.
|
||||
===============
|
||||
*/
|
||||
void Entity_Free (entity_t *e)
|
||||
{
|
||||
epair_t *ep, *next;
|
||||
|
||||
while (e->brushes.onext != &e->brushes)
|
||||
Brush_Free (e->brushes.onext);
|
||||
|
||||
if (e->next)
|
||||
{
|
||||
e->next->prev = e->prev;
|
||||
e->prev->next = e->next;
|
||||
}
|
||||
|
||||
for (ep = e->epairs ; ep ; ep=next)
|
||||
{
|
||||
next = ep->next;
|
||||
free (ep);
|
||||
}
|
||||
free (e);
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
ParseEpair
|
||||
=================
|
||||
*/
|
||||
epair_t *ParseEpair (void)
|
||||
{
|
||||
epair_t *e;
|
||||
|
||||
e = qmalloc (sizeof(*e));
|
||||
|
||||
e->key = qmalloc(strlen(token)+1);
|
||||
strcpy (e->key, token);
|
||||
|
||||
GetToken (false);
|
||||
e->value = qmalloc(strlen(token)+1);
|
||||
strcpy (e->value, token);
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Entity_Parse
|
||||
|
||||
If onlypairs is set, the classname info will not
|
||||
be looked up, and the entity will not be added
|
||||
to the global list. Used for parsing the project.
|
||||
================
|
||||
*/
|
||||
entity_t *Entity_Parse (qboolean onlypairs)
|
||||
{
|
||||
entity_t *ent;
|
||||
eclass_t *e;
|
||||
brush_t *b;
|
||||
vec3_t mins, maxs;
|
||||
epair_t *ep;
|
||||
qboolean has_brushes;
|
||||
|
||||
if (!GetToken (true))
|
||||
return NULL;
|
||||
|
||||
if (strcmp (token, "{") )
|
||||
Error ("ParseEntity: { not found");
|
||||
|
||||
ent = qmalloc (sizeof(*ent));
|
||||
ent->brushes.onext = ent->brushes.oprev = &ent->brushes;
|
||||
|
||||
do
|
||||
{
|
||||
if (!GetToken (true))
|
||||
Error ("ParseEntity: EOF without closing brace");
|
||||
if (!strcmp (token, "}") )
|
||||
break;
|
||||
if (!strcmp (token, "{") )
|
||||
{
|
||||
b = Brush_Parse ();
|
||||
b->owner = ent;
|
||||
|
||||
// add to the end of the entity chain
|
||||
b->onext = &ent->brushes;
|
||||
b->oprev = ent->brushes.oprev;
|
||||
ent->brushes.oprev->onext = b;
|
||||
ent->brushes.oprev = b;
|
||||
}
|
||||
else
|
||||
{
|
||||
ep = ParseEpair ();
|
||||
ep->next = ent->epairs;
|
||||
ent->epairs = ep;
|
||||
}
|
||||
} while (1);
|
||||
|
||||
if (onlypairs)
|
||||
return ent;
|
||||
|
||||
if (ent->brushes.onext == &ent->brushes)
|
||||
has_brushes = false;
|
||||
else
|
||||
has_brushes = true;
|
||||
|
||||
GetVectorForKey (ent, "origin", ent->origin);
|
||||
|
||||
e = Eclass_ForName (ValueForKey (ent, "classname"), has_brushes);
|
||||
ent->eclass = e;
|
||||
if (e->fixedsize)
|
||||
{ // fixed size entity
|
||||
if (ent->brushes.onext != &ent->brushes)
|
||||
{
|
||||
printf ("Warning: Fixed size entity with brushes\n");
|
||||
#if 0
|
||||
while (ent->brushes.onext != &ent->brushes)
|
||||
{ // FIXME: this will free the entity and crash!
|
||||
Brush_Free (b);
|
||||
}
|
||||
#endif
|
||||
ent->brushes.next = ent->brushes.prev = &ent->brushes;
|
||||
}
|
||||
// create a custom brush
|
||||
VectorAdd (e->mins, ent->origin, mins);
|
||||
VectorAdd (e->maxs, ent->origin, maxs);
|
||||
b = Brush_Create (mins, maxs, &e->texdef);
|
||||
b->owner = ent;
|
||||
|
||||
b->onext = ent->brushes.onext;
|
||||
b->oprev = &ent->brushes;
|
||||
ent->brushes.onext->oprev = b;
|
||||
ent->brushes.onext = b;
|
||||
}
|
||||
else
|
||||
{ // brush entity
|
||||
if (ent->brushes.next == &ent->brushes)
|
||||
printf ("Warning: Brush entity with no brushes\n");
|
||||
}
|
||||
|
||||
// add all the brushes to the main list
|
||||
for (b=ent->brushes.onext ; b != &ent->brushes ; b=b->onext)
|
||||
{
|
||||
b->next = active_brushes.next;
|
||||
active_brushes.next->prev = b;
|
||||
b->prev = &active_brushes;
|
||||
active_brushes.next = b;
|
||||
}
|
||||
|
||||
return ent;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Entity_Write
|
||||
============
|
||||
*/
|
||||
void Entity_Write (entity_t *e, FILE *f, qboolean use_region)
|
||||
{
|
||||
epair_t *ep;
|
||||
brush_t *b;
|
||||
vec3_t origin;
|
||||
char text[128];
|
||||
int count;
|
||||
|
||||
// if none of the entities brushes are in the region,
|
||||
// don't write the entity at all
|
||||
if (use_region)
|
||||
{
|
||||
// in region mode, save the camera position as playerstart
|
||||
if ( !strcmp(ValueForKey (e, "classname"), "info_player_start") )
|
||||
{
|
||||
fprintf (f, "{\n");
|
||||
fprintf (f, "\"classname\" \"info_player_start\"\n");
|
||||
fprintf (f, "\"origin\" \"%i %i %i\"\n", (int)camera.origin[0],
|
||||
(int)camera.origin[1], (int)camera.origin[2]);
|
||||
fprintf (f, "\"angle\" \"%i\"\n", (int)camera.angles[YAW]);
|
||||
fprintf (f, "}\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (b=e->brushes.onext ; b != &e->brushes ; b=b->onext)
|
||||
if (!Map_IsBrushFiltered(b))
|
||||
break; // got one
|
||||
|
||||
if (b == &e->brushes)
|
||||
return; // nothing visible
|
||||
}
|
||||
|
||||
// if fixedsize, calculate a new origin based on the current
|
||||
// brush position
|
||||
if (e->eclass->fixedsize)
|
||||
{
|
||||
VectorSubtract (e->brushes.onext->mins, e->eclass->mins, origin);
|
||||
sprintf (text, "%i %i %i", (int)origin[0],
|
||||
(int)origin[1], (int)origin[2]);
|
||||
SetKeyValue (e, "origin", text);
|
||||
}
|
||||
|
||||
fprintf (f, "{\n");
|
||||
for (ep = e->epairs ; ep ; ep=ep->next)
|
||||
fprintf (f, "\"%s\" \"%s\"\n", ep->key, ep->value);
|
||||
|
||||
if (!e->eclass->fixedsize)
|
||||
{
|
||||
count = 0;
|
||||
for (b=e->brushes.onext ; b != &e->brushes ; b=b->onext)
|
||||
{
|
||||
if (!use_region || !Map_IsBrushFiltered (b))
|
||||
{
|
||||
fprintf (f, "// brush %i\n", count);
|
||||
count++;
|
||||
Brush_Write (b, f);
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf (f, "}\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
Entity_Create
|
||||
|
||||
Creates a new entity out of the selected_brushes list.
|
||||
If the entity class is fixed size, the brushes are only
|
||||
used to find a midpoint. Otherwise, the brushes have
|
||||
their ownershi[ transfered to the new entity.
|
||||
============
|
||||
*/
|
||||
entity_t *Entity_Create (eclass_t *c)
|
||||
{
|
||||
entity_t *e;
|
||||
brush_t *b;
|
||||
vec3_t mins, maxs;
|
||||
int i;
|
||||
|
||||
// check to make sure the brushes are ok
|
||||
|
||||
for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
|
||||
if (b->owner != world_entity)
|
||||
{
|
||||
Sys_Printf ("Entity NOT created, brushes not all from world\n");
|
||||
Sys_Beep ();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// create it
|
||||
|
||||
e = qmalloc(sizeof(*e));
|
||||
e->brushes.onext = e->brushes.oprev = &e->brushes;
|
||||
e->eclass = c;
|
||||
SetKeyValue (e, "classname", c->name);
|
||||
|
||||
// add the entity to the entity list
|
||||
e->next = entities.next;
|
||||
entities.next = e;
|
||||
e->next->prev = e;
|
||||
e->prev = &entities;
|
||||
|
||||
if (c->fixedsize)
|
||||
{
|
||||
//
|
||||
// just use the selection for positioning
|
||||
//
|
||||
b = selected_brushes.next;
|
||||
for (i=0 ; i<3 ; i++)
|
||||
e->origin[i] = b->mins[i] - c->mins[i];
|
||||
|
||||
// create a custom brush
|
||||
VectorAdd (c->mins, e->origin, mins);
|
||||
VectorAdd (c->maxs, e->origin, maxs);
|
||||
b = Brush_Create (mins, maxs, &c->texdef);
|
||||
|
||||
Entity_LinkBrush (e, b);
|
||||
|
||||
// delete the current selection
|
||||
Select_Delete ();
|
||||
|
||||
// select the new brush
|
||||
b->next = b->prev = &selected_brushes;
|
||||
selected_brushes.next = selected_brushes.prev = b;
|
||||
|
||||
Brush_Build( b );
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// change the selected brushes over to the new entity
|
||||
//
|
||||
for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
|
||||
{
|
||||
Entity_UnlinkBrush (b);
|
||||
Entity_LinkBrush (e, b);
|
||||
Brush_Build( b ); // so the key brush gets a name
|
||||
}
|
||||
}
|
||||
|
||||
Sys_UpdateWindows (W_ALL);
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===========
|
||||
Entity_LinkBrush
|
||||
===========
|
||||
*/
|
||||
void Entity_LinkBrush (entity_t *e, brush_t *b)
|
||||
{
|
||||
if (b->oprev || b->onext)
|
||||
Error ("Entity_LinkBrush: Allready linked");
|
||||
b->owner = e;
|
||||
|
||||
b->onext = e->brushes.onext;
|
||||
b->oprev = &e->brushes;
|
||||
e->brushes.onext->oprev = b;
|
||||
e->brushes.onext = b;
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
Entity_UnlinkBrush
|
||||
===========
|
||||
*/
|
||||
void Entity_UnlinkBrush (brush_t *b)
|
||||
{
|
||||
if (!b->owner || !b->onext || !b->oprev)
|
||||
Error ("Entity_UnlinkBrush: Not currently linked");
|
||||
b->onext->oprev = b->oprev;
|
||||
b->oprev->onext = b->onext;
|
||||
b->onext = b->oprev = NULL;
|
||||
b->owner = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
===========
|
||||
Entity_Clone
|
||||
===========
|
||||
*/
|
||||
entity_t *Entity_Clone (entity_t *e)
|
||||
{
|
||||
entity_t *n;
|
||||
epair_t *ep, *np;
|
||||
|
||||
n = qmalloc(sizeof(*n));
|
||||
n->brushes.onext = n->brushes.oprev = &n->brushes;
|
||||
n->eclass = e->eclass;
|
||||
|
||||
// add the entity to the entity list
|
||||
n->next = entities.next;
|
||||
entities.next = n;
|
||||
n->next->prev = n;
|
||||
n->prev = &entities;
|
||||
|
||||
for (ep = e->epairs ; ep ; ep=ep->next)
|
||||
{
|
||||
np = qmalloc(sizeof(*np));
|
||||
np->key = copystring(ep->key);
|
||||
np->value = copystring(ep->value);
|
||||
np->next = n->epairs;
|
||||
n->epairs = np;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
int GetUniqueTargetId(int iHint)
|
||||
{
|
||||
int iMin, iMax, i;
|
||||
BOOL fFound;
|
||||
entity_t *pe;
|
||||
|
||||
fFound = FALSE;
|
||||
pe = entities.next;
|
||||
iMin = 0;
|
||||
iMax = 0;
|
||||
|
||||
for (; pe != NULL && pe != &entities ; pe = pe->next)
|
||||
{
|
||||
i = IntForKey(pe, "target");
|
||||
if (i)
|
||||
{
|
||||
iMin = min(i, iMin);
|
||||
iMax = max(i, iMax);
|
||||
if (i == iHint)
|
||||
fFound = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (fFound)
|
||||
return iMax + 1;
|
||||
else
|
||||
return iHint;
|
||||
}
|
||||
|
||||
entity_t *FindEntity(char *pszKey, char *pszValue)
|
||||
{
|
||||
entity_t *pe;
|
||||
|
||||
pe = entities.next;
|
||||
|
||||
for (; pe != NULL && pe != &entities ; pe = pe->next)
|
||||
{
|
||||
if (!strcmp(ValueForKey(pe, pszKey), pszValue))
|
||||
return pe;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
entity_t *FindEntityInt(char *pszKey, int iValue)
|
||||
{
|
||||
entity_t *pe;
|
||||
|
||||
pe = entities.next;
|
||||
|
||||
for (; pe != NULL && pe != &entities ; pe = pe->next)
|
||||
{
|
||||
if (IntForKey(pe, pszKey) == iValue)
|
||||
return pe;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
84
tools/quake2/extra/qe4/entity.h
Normal file
84
tools/quake2/extra/qe4/entity.h
Normal file
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// entity.h
|
||||
|
||||
|
||||
#define MAX_FLAGS 8
|
||||
|
||||
typedef struct eclass_s
|
||||
{
|
||||
struct eclass_s *next;
|
||||
char *name;
|
||||
qboolean fixedsize;
|
||||
qboolean unknown; // wasn't found in source
|
||||
vec3_t mins, maxs;
|
||||
vec3_t color;
|
||||
texdef_t texdef;
|
||||
char *comments;
|
||||
char flagnames[MAX_FLAGS][32];
|
||||
} eclass_t;
|
||||
|
||||
extern eclass_t *eclass;
|
||||
|
||||
void Eclass_InitForSourceDirectory (char *path);
|
||||
eclass_t *Eclass_ForName (char *name, qboolean has_brushes);
|
||||
|
||||
//===================================================
|
||||
|
||||
|
||||
typedef struct epair_s
|
||||
{
|
||||
struct epair_s *next;
|
||||
char *key;
|
||||
char *value;
|
||||
} epair_t;
|
||||
|
||||
typedef struct entity_s
|
||||
{
|
||||
struct entity_s *prev, *next;
|
||||
brush_t brushes; // head/tail of list
|
||||
vec3_t origin;
|
||||
eclass_t *eclass;
|
||||
epair_t *epairs;
|
||||
} entity_t;
|
||||
|
||||
char *ValueForKey (entity_t *ent, char *key);
|
||||
void SetKeyValue (entity_t *ent, char *key, char *value);
|
||||
void DeleteKey (entity_t *ent, char *key);
|
||||
float FloatForKey (entity_t *ent, char *key);
|
||||
int IntForKey (entity_t *ent, char *key);
|
||||
void GetVectorForKey (entity_t *ent, char *key, vec3_t vec);
|
||||
|
||||
void Entity_Free (entity_t *e);
|
||||
entity_t *Entity_Parse (qboolean onlypairs);
|
||||
void Entity_Write (entity_t *e, FILE *f, qboolean use_region);
|
||||
entity_t *Entity_Create (eclass_t *c);
|
||||
entity_t *Entity_Clone (entity_t *e);
|
||||
|
||||
void Entity_LinkBrush (entity_t *e, brush_t *b);
|
||||
void Entity_UnlinkBrush (brush_t *b);
|
||||
entity_t *FindEntity(char *pszKey, char *pszValue);
|
||||
entity_t *FindEntityInt(char *pszKey, int iValue);
|
||||
|
||||
int GetUniqueTargetId(int iHint);
|
||||
|
66
tools/quake2/extra/qe4/entityw.h
Normal file
66
tools/quake2/extra/qe4/entityw.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// entity.h
|
||||
|
||||
#define DlgXBorder 5
|
||||
#define DlgYBorder 5
|
||||
|
||||
|
||||
#define EntList 0
|
||||
#define EntComment 1
|
||||
#define EntCheck1 2
|
||||
#define EntCheck2 3
|
||||
#define EntCheck3 4
|
||||
#define EntCheck4 5
|
||||
#define EntCheck5 6
|
||||
#define EntCheck6 7
|
||||
#define EntCheck7 8
|
||||
#define EntCheck8 9
|
||||
#define EntCheck9 10
|
||||
#define EntCheck10 11
|
||||
#define EntCheck11 12
|
||||
#define EntCheck12 13
|
||||
#define EntProps 14
|
||||
#define EntDir0 15
|
||||
#define EntDir45 16
|
||||
#define EntDir90 17
|
||||
#define EntDir135 18
|
||||
#define EntDir180 19
|
||||
#define EntDir225 20
|
||||
#define EntDir270 21
|
||||
#define EntDir315 22
|
||||
#define EntDirUp 23
|
||||
#define EntDirDown 24
|
||||
#define EntDelProp 25
|
||||
#define EntKeyLabel 26
|
||||
#define EntKeyField 27
|
||||
#define EntValueLabel 28
|
||||
#define EntValueField 29
|
||||
#define EntColor 30
|
||||
|
||||
#define EntLast 31
|
||||
|
||||
extern HWND hwndEnt[EntLast];
|
||||
|
||||
extern int rgIds[EntLast];
|
||||
|
98
tools/quake2/extra/qe4/glingr.h
Normal file
98
tools/quake2/extra/qe4/glingr.h
Normal file
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// This .h file contains constants, typedefs, etc. for Intergraph
|
||||
// extensions to OpenGL. These extensions are:
|
||||
//
|
||||
// Multiple Palette Extension
|
||||
// Texture Object Extension
|
||||
|
||||
#define GL_INGR_multiple_palette 1
|
||||
#define GL_EXT_texture_object 1
|
||||
|
||||
|
||||
// New constants and typedefs for the Multiple Palette Extension
|
||||
#define GL_PALETTE_INGR 0x80c0
|
||||
#define GL_MAX_PALETTES_INGR 0x80c1
|
||||
#define GL_MAX_PALETTE_ENTRIES_INGR 0x80c2
|
||||
#define GL_CURRENT_PALETTE_INGR 0x80c3
|
||||
#define GL_PALETTE_WRITEMASK_INGR 0x80c4
|
||||
#define GL_CURRENT_RASTER_PALETTE_INGR 0x80c5
|
||||
#define GL_PALETTE_CLEAR_VALUE_INGR 0x80c6
|
||||
|
||||
// Function prototypes for the Multiple Palette Extension routines
|
||||
typedef void (APIENTRY *PALETTEFUNCPTR)(GLuint);
|
||||
typedef void (APIENTRY *PALETTEMASKFUNCPTR)(GLboolean);
|
||||
typedef void (APIENTRY *WGLLOADPALETTEFUNCPTR)(GLuint, GLsizei, GLuint *);
|
||||
typedef void (APIENTRY *CLEARPALETTEFUNCPTR)(GLuint);
|
||||
|
||||
|
||||
// New Constants and typedefs for the Texture Object Extension
|
||||
#define GL_TEXTURE_PRIORITY_EXT 0x8066
|
||||
#define GL_TEXTURE_RESIDENT_EXT 0x8067
|
||||
#define GL_TEXTURE_1D_BINDING_EXT 0x8068
|
||||
#define GL_TEXTURE_2D_BINDING_EXT 0x8069
|
||||
|
||||
// Function prototypes for the Texture Object Extension routines
|
||||
typedef GLboolean (APIENTRY *ARETEXRESFUNCPTR)(GLsizei, const GLuint *,
|
||||
const GLboolean *);
|
||||
typedef void (APIENTRY *BINDTEXFUNCPTR)(GLenum, GLuint);
|
||||
typedef void (APIENTRY *DELTEXFUNCPTR)(GLsizei, const GLuint *);
|
||||
typedef void (APIENTRY *GENTEXFUNCPTR)(GLsizei, GLuint *);
|
||||
typedef GLboolean (APIENTRY *ISTEXFUNCPTR)(GLuint);
|
||||
typedef void (APIENTRY *PRIORTEXFUNCPTR)(GLsizei, const GLuint *,
|
||||
const GLclampf *);
|
||||
|
||||
|
||||
/* OpenGL ExtEscape escape function constants */
|
||||
#ifndef OPENGL_GETINFO
|
||||
#define OPENGL_GETINFO 4353 /* for OpenGL ExtEscape */
|
||||
#endif
|
||||
|
||||
// OPENGL_GETINFO ExtEscape sub-escape numbers. They are defined by
|
||||
// Microsoft.
|
||||
|
||||
#ifndef OPENGL_GETINFO_DRVNAME
|
||||
|
||||
#define OPENGL_GETINFO_DRVNAME 0
|
||||
|
||||
|
||||
// Input structure for OPENGL_GETINFO ExtEscape.
|
||||
|
||||
typedef struct _OPENGLGETINFO
|
||||
{
|
||||
ULONG ulSubEsc;
|
||||
} OPENGLGETINFO, *POPENGLGETINFO;
|
||||
|
||||
|
||||
// Output structure for OPENGL_GETINFO_DRVNAME ExtEscape.
|
||||
|
||||
typedef struct _GLDRVNAMERET
|
||||
{
|
||||
ULONG ulVersion; // must be 1 for this version
|
||||
ULONG ulDriverVersion; // driver specific version number
|
||||
WCHAR awch[MAX_PATH+1];
|
||||
} GLDRVNAMERET, *PGLDRVNAMERET;
|
||||
|
||||
#endif
|
||||
|
||||
|
BIN
tools/quake2/extra/qe4/icon1.ico
Normal file
BIN
tools/quake2/extra/qe4/icon1.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 766 B |
835
tools/quake2/extra/qe4/lbmlib.c
Normal file
835
tools/quake2/extra/qe4/lbmlib.c
Normal file
|
@ -0,0 +1,835 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// lbmlib.c
|
||||
|
||||
#include "cmdlib.h"
|
||||
#include "lbmlib.h"
|
||||
|
||||
|
||||
|
||||
/*
|
||||
============================================================================
|
||||
|
||||
LBM STUFF
|
||||
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
|
||||
typedef unsigned char UBYTE;
|
||||
//conflicts with windows typedef short WORD;
|
||||
typedef unsigned short UWORD;
|
||||
typedef long LONG;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ms_none,
|
||||
ms_mask,
|
||||
ms_transcolor,
|
||||
ms_lasso
|
||||
} mask_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
cm_none,
|
||||
cm_rle1
|
||||
} compress_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UWORD w,h;
|
||||
short x,y;
|
||||
UBYTE nPlanes;
|
||||
UBYTE masking;
|
||||
UBYTE compression;
|
||||
UBYTE pad1;
|
||||
UWORD transparentColor;
|
||||
UBYTE xAspect,yAspect;
|
||||
short pageWidth,pageHeight;
|
||||
} bmhd_t;
|
||||
|
||||
extern bmhd_t bmhd; // will be in native byte order
|
||||
|
||||
|
||||
|
||||
#define FORMID ('F'+('O'<<8)+((int)'R'<<16)+((int)'M'<<24))
|
||||
#define ILBMID ('I'+('L'<<8)+((int)'B'<<16)+((int)'M'<<24))
|
||||
#define PBMID ('P'+('B'<<8)+((int)'M'<<16)+((int)' '<<24))
|
||||
#define BMHDID ('B'+('M'<<8)+((int)'H'<<16)+((int)'D'<<24))
|
||||
#define BODYID ('B'+('O'<<8)+((int)'D'<<16)+((int)'Y'<<24))
|
||||
#define CMAPID ('C'+('M'<<8)+((int)'A'<<16)+((int)'P'<<24))
|
||||
|
||||
|
||||
bmhd_t bmhd;
|
||||
|
||||
int Align (int l)
|
||||
{
|
||||
if (l&1)
|
||||
return l+1;
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
LBMRLEdecompress
|
||||
|
||||
Source must be evenly aligned!
|
||||
================
|
||||
*/
|
||||
byte *LBMRLEDecompress (byte *source,byte *unpacked, int bpwidth)
|
||||
{
|
||||
int count;
|
||||
byte b,rept;
|
||||
|
||||
count = 0;
|
||||
|
||||
do
|
||||
{
|
||||
rept = *source++;
|
||||
|
||||
if (rept > 0x80)
|
||||
{
|
||||
rept = (rept^0xff)+2;
|
||||
b = *source++;
|
||||
memset(unpacked,b,rept);
|
||||
unpacked += rept;
|
||||
}
|
||||
else if (rept < 0x80)
|
||||
{
|
||||
rept++;
|
||||
memcpy(unpacked,source,rept);
|
||||
unpacked += rept;
|
||||
source += rept;
|
||||
}
|
||||
else
|
||||
rept = 0; // rept of 0x80 is NOP
|
||||
|
||||
count += rept;
|
||||
|
||||
} while (count<bpwidth);
|
||||
|
||||
if (count>bpwidth)
|
||||
Error ("Decompression exceeded width!\n");
|
||||
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
LoadLBM
|
||||
=================
|
||||
*/
|
||||
void LoadLBM (char *filename, byte **picture, byte **palette)
|
||||
{
|
||||
byte *LBMbuffer, *picbuffer, *cmapbuffer;
|
||||
int y;
|
||||
byte *LBM_P, *LBMEND_P;
|
||||
byte *pic_p;
|
||||
byte *body_p;
|
||||
|
||||
int formtype,formlength;
|
||||
int chunktype,chunklength;
|
||||
|
||||
// qiet compiler warnings
|
||||
picbuffer = NULL;
|
||||
cmapbuffer = NULL;
|
||||
|
||||
//
|
||||
// load the LBM
|
||||
//
|
||||
LoadFile (filename, (void **)&LBMbuffer);
|
||||
|
||||
//
|
||||
// parse the LBM header
|
||||
//
|
||||
LBM_P = LBMbuffer;
|
||||
if ( *(int *)LBMbuffer != LittleLong(FORMID) )
|
||||
Error ("No FORM ID at start of file!\n");
|
||||
|
||||
LBM_P += 4;
|
||||
formlength = BigLong( *(int *)LBM_P );
|
||||
LBM_P += 4;
|
||||
LBMEND_P = LBM_P + Align(formlength);
|
||||
|
||||
formtype = LittleLong(*(int *)LBM_P);
|
||||
|
||||
if (formtype != ILBMID && formtype != PBMID)
|
||||
Error ("Unrecognized form type: %c%c%c%c\n", formtype&0xff
|
||||
,(formtype>>8)&0xff,(formtype>>16)&0xff,(formtype>>24)&0xff);
|
||||
|
||||
LBM_P += 4;
|
||||
|
||||
//
|
||||
// parse chunks
|
||||
//
|
||||
|
||||
while (LBM_P < LBMEND_P)
|
||||
{
|
||||
chunktype = LBM_P[0] + (LBM_P[1]<<8) + (LBM_P[2]<<16) + (LBM_P[3]<<24);
|
||||
LBM_P += 4;
|
||||
chunklength = LBM_P[3] + (LBM_P[2]<<8) + (LBM_P[1]<<16) + (LBM_P[0]<<24);
|
||||
LBM_P += 4;
|
||||
|
||||
switch ( chunktype )
|
||||
{
|
||||
case BMHDID:
|
||||
memcpy (&bmhd,LBM_P,sizeof(bmhd));
|
||||
bmhd.w = BigShort(bmhd.w);
|
||||
bmhd.h = BigShort(bmhd.h);
|
||||
bmhd.x = BigShort(bmhd.x);
|
||||
bmhd.y = BigShort(bmhd.y);
|
||||
bmhd.pageWidth = BigShort(bmhd.pageWidth);
|
||||
bmhd.pageHeight = BigShort(bmhd.pageHeight);
|
||||
break;
|
||||
|
||||
case CMAPID:
|
||||
cmapbuffer = malloc (768);
|
||||
memset (cmapbuffer, 0, 768);
|
||||
memcpy (cmapbuffer, LBM_P, chunklength);
|
||||
break;
|
||||
|
||||
case BODYID:
|
||||
body_p = LBM_P;
|
||||
|
||||
pic_p = picbuffer = malloc (bmhd.w*bmhd.h);
|
||||
if (formtype == PBMID)
|
||||
{
|
||||
//
|
||||
// unpack PBM
|
||||
//
|
||||
for (y=0 ; y<bmhd.h ; y++, pic_p += bmhd.w)
|
||||
{
|
||||
if (bmhd.compression == cm_rle1)
|
||||
body_p = LBMRLEDecompress ((byte *)body_p
|
||||
, pic_p , bmhd.w);
|
||||
else if (bmhd.compression == cm_none)
|
||||
{
|
||||
memcpy (pic_p,body_p,bmhd.w);
|
||||
body_p += Align(bmhd.w);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// unpack ILBM
|
||||
//
|
||||
Error ("%s is an interlaced LBM, not packed", filename);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
LBM_P += Align(chunklength);
|
||||
}
|
||||
|
||||
free (LBMbuffer);
|
||||
|
||||
*picture = picbuffer;
|
||||
|
||||
if (palette)
|
||||
*palette = cmapbuffer;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============================================================================
|
||||
|
||||
WRITE LBM
|
||||
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
==============
|
||||
WriteLBMfile
|
||||
==============
|
||||
*/
|
||||
void WriteLBMfile (char *filename, byte *data,
|
||||
int width, int height, byte *palette)
|
||||
{
|
||||
byte *lbm, *lbmptr;
|
||||
int *formlength, *bmhdlength, *cmaplength, *bodylength;
|
||||
int length;
|
||||
bmhd_t basebmhd;
|
||||
|
||||
lbm = lbmptr = malloc (width*height+1000);
|
||||
|
||||
//
|
||||
// start FORM
|
||||
//
|
||||
*lbmptr++ = 'F';
|
||||
*lbmptr++ = 'O';
|
||||
*lbmptr++ = 'R';
|
||||
*lbmptr++ = 'M';
|
||||
|
||||
formlength = (int*)lbmptr;
|
||||
lbmptr+=4; // leave space for length
|
||||
|
||||
*lbmptr++ = 'P';
|
||||
*lbmptr++ = 'B';
|
||||
*lbmptr++ = 'M';
|
||||
*lbmptr++ = ' ';
|
||||
|
||||
//
|
||||
// write BMHD
|
||||
//
|
||||
*lbmptr++ = 'B';
|
||||
*lbmptr++ = 'M';
|
||||
*lbmptr++ = 'H';
|
||||
*lbmptr++ = 'D';
|
||||
|
||||
bmhdlength = (int *)lbmptr;
|
||||
lbmptr+=4; // leave space for length
|
||||
|
||||
memset (&basebmhd,0,sizeof(basebmhd));
|
||||
basebmhd.w = BigShort((short)width);
|
||||
basebmhd.h = BigShort((short)height);
|
||||
basebmhd.nPlanes = 8;
|
||||
basebmhd.xAspect = 5;
|
||||
basebmhd.yAspect = 6;
|
||||
basebmhd.pageWidth = BigShort((short)width);
|
||||
basebmhd.pageHeight = BigShort((short)height);
|
||||
|
||||
memcpy (lbmptr,&basebmhd,sizeof(basebmhd));
|
||||
lbmptr += sizeof(basebmhd);
|
||||
|
||||
length = lbmptr-(byte *)bmhdlength-4;
|
||||
*bmhdlength = BigLong(length);
|
||||
if (length&1)
|
||||
*lbmptr++ = 0; // pad chunk to even offset
|
||||
|
||||
//
|
||||
// write CMAP
|
||||
//
|
||||
*lbmptr++ = 'C';
|
||||
*lbmptr++ = 'M';
|
||||
*lbmptr++ = 'A';
|
||||
*lbmptr++ = 'P';
|
||||
|
||||
cmaplength = (int *)lbmptr;
|
||||
lbmptr+=4; // leave space for length
|
||||
|
||||
memcpy (lbmptr,palette,768);
|
||||
lbmptr += 768;
|
||||
|
||||
length = lbmptr-(byte *)cmaplength-4;
|
||||
*cmaplength = BigLong(length);
|
||||
if (length&1)
|
||||
*lbmptr++ = 0; // pad chunk to even offset
|
||||
|
||||
//
|
||||
// write BODY
|
||||
//
|
||||
*lbmptr++ = 'B';
|
||||
*lbmptr++ = 'O';
|
||||
*lbmptr++ = 'D';
|
||||
*lbmptr++ = 'Y';
|
||||
|
||||
bodylength = (int *)lbmptr;
|
||||
lbmptr+=4; // leave space for length
|
||||
|
||||
memcpy (lbmptr,data,width*height);
|
||||
lbmptr += width*height;
|
||||
|
||||
length = lbmptr-(byte *)bodylength-4;
|
||||
*bodylength = BigLong(length);
|
||||
if (length&1)
|
||||
*lbmptr++ = 0; // pad chunk to even offset
|
||||
|
||||
//
|
||||
// done
|
||||
//
|
||||
length = lbmptr-(byte *)formlength-4;
|
||||
*formlength = BigLong(length);
|
||||
if (length&1)
|
||||
*lbmptr++ = 0; // pad chunk to even offset
|
||||
|
||||
//
|
||||
// write output file
|
||||
//
|
||||
SaveFile (filename, lbm, lbmptr-lbm);
|
||||
free (lbm);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============================================================================
|
||||
|
||||
LOAD PCX
|
||||
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char manufacturer;
|
||||
char version;
|
||||
char encoding;
|
||||
char bits_per_pixel;
|
||||
unsigned short xmin,ymin,xmax,ymax;
|
||||
unsigned short hres,vres;
|
||||
unsigned char palette[48];
|
||||
char reserved;
|
||||
char color_planes;
|
||||
unsigned short bytes_per_line;
|
||||
unsigned short palette_type;
|
||||
char filler[58];
|
||||
unsigned char data; // unbounded
|
||||
} pcx_t;
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
LoadPCX
|
||||
==============
|
||||
*/
|
||||
void LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height)
|
||||
{
|
||||
byte *raw;
|
||||
pcx_t *pcx;
|
||||
int x, y;
|
||||
int len;
|
||||
int dataByte, runLength;
|
||||
byte *out, *pix;
|
||||
|
||||
if (pic)
|
||||
*pic = NULL;
|
||||
if (palette)
|
||||
*palette = NULL;
|
||||
if (width)
|
||||
*width = 0;
|
||||
if (height)
|
||||
*height = 0;
|
||||
|
||||
//
|
||||
// load the file
|
||||
//
|
||||
len = LoadFile (filename, (void **)&raw);
|
||||
if (len == -1)
|
||||
return;
|
||||
|
||||
//
|
||||
// parse the PCX file
|
||||
//
|
||||
pcx = (pcx_t *)raw;
|
||||
raw = &pcx->data;
|
||||
|
||||
pcx->xmin = LittleShort(pcx->xmin);
|
||||
pcx->ymin = LittleShort(pcx->ymin);
|
||||
pcx->xmax = LittleShort(pcx->xmax);
|
||||
pcx->ymax = LittleShort(pcx->ymax);
|
||||
pcx->hres = LittleShort(pcx->hres);
|
||||
pcx->vres = LittleShort(pcx->vres);
|
||||
pcx->bytes_per_line = LittleShort(pcx->bytes_per_line);
|
||||
pcx->palette_type = LittleShort(pcx->palette_type);
|
||||
|
||||
if (pcx->manufacturer != 0x0a
|
||||
|| pcx->version != 5
|
||||
|| pcx->encoding != 1
|
||||
|| pcx->bits_per_pixel != 8
|
||||
|| pcx->xmax >= 640
|
||||
|| pcx->ymax >= 480)
|
||||
Error ("Bad pcx file %s", filename);
|
||||
|
||||
if (palette)
|
||||
{
|
||||
*palette = malloc(768);
|
||||
memcpy (*palette, (byte *)pcx + len - 768, 768);
|
||||
}
|
||||
|
||||
if (width)
|
||||
*width = pcx->xmax+1;
|
||||
if (height)
|
||||
*height = pcx->ymax+1;
|
||||
|
||||
if (!pic)
|
||||
return;
|
||||
|
||||
out = malloc ( (pcx->ymax+1) * (pcx->xmax+1) );
|
||||
if (!out)
|
||||
Error ("Skin_Cache: couldn't allocate");
|
||||
|
||||
*pic = out;
|
||||
|
||||
pix = out;
|
||||
|
||||
for (y=0 ; y<=pcx->ymax ; y++, pix += pcx->xmax+1)
|
||||
{
|
||||
for (x=0 ; x<=pcx->xmax ; )
|
||||
{
|
||||
dataByte = *raw++;
|
||||
|
||||
if((dataByte & 0xC0) == 0xC0)
|
||||
{
|
||||
runLength = dataByte & 0x3F;
|
||||
dataByte = *raw++;
|
||||
}
|
||||
else
|
||||
runLength = 1;
|
||||
|
||||
while(runLength-- > 0)
|
||||
pix[x++] = dataByte;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( raw - (byte *)pcx > len)
|
||||
Error ("PCX file %s was malformed", filename);
|
||||
|
||||
free (pcx);
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
WritePCXfile
|
||||
==============
|
||||
*/
|
||||
void WritePCXfile (char *filename, byte *data,
|
||||
int width, int height, byte *palette)
|
||||
{
|
||||
int i, j, length;
|
||||
pcx_t *pcx;
|
||||
byte *pack;
|
||||
|
||||
pcx = malloc (width*height*2+1000);
|
||||
memset (pcx, 0, sizeof(*pcx));
|
||||
|
||||
pcx->manufacturer = 0x0a; // PCX id
|
||||
pcx->version = 5; // 256 color
|
||||
pcx->encoding = 1; // uncompressed
|
||||
pcx->bits_per_pixel = 8; // 256 color
|
||||
pcx->xmin = 0;
|
||||
pcx->ymin = 0;
|
||||
pcx->xmax = LittleShort((short)(width-1));
|
||||
pcx->ymax = LittleShort((short)(height-1));
|
||||
pcx->hres = LittleShort((short)width);
|
||||
pcx->vres = LittleShort((short)height);
|
||||
pcx->color_planes = 1; // chunky image
|
||||
pcx->bytes_per_line = LittleShort((short)width);
|
||||
pcx->palette_type = LittleShort(2); // not a grey scale
|
||||
|
||||
// pack the image
|
||||
pack = &pcx->data;
|
||||
|
||||
for (i=0 ; i<height ; i++)
|
||||
{
|
||||
for (j=0 ; j<width ; j++)
|
||||
{
|
||||
if ( (*data & 0xc0) != 0xc0)
|
||||
*pack++ = *data++;
|
||||
else
|
||||
{
|
||||
*pack++ = 0xc1;
|
||||
*pack++ = *data++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// write the palette
|
||||
*pack++ = 0x0c; // palette ID byte
|
||||
for (i=0 ; i<768 ; i++)
|
||||
*pack++ = *palette++;
|
||||
|
||||
// write output file
|
||||
length = pack - (byte *)pcx;
|
||||
SaveFile (filename, pcx, length);
|
||||
|
||||
free (pcx);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============================================================================
|
||||
|
||||
LOAD IMAGE
|
||||
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
==============
|
||||
Load256Image
|
||||
|
||||
Will load either an lbm or pcx, depending on extension.
|
||||
Any of the return pointers can be NULL if you don't want them.
|
||||
==============
|
||||
*/
|
||||
void Load256Image (char *name, byte **pixels, byte **palette,
|
||||
int *width, int *height)
|
||||
{
|
||||
char ext[128];
|
||||
|
||||
ExtractFileExtension (name, ext);
|
||||
if (!Q_strcasecmp (ext, "lbm"))
|
||||
{
|
||||
LoadLBM (name, pixels, palette);
|
||||
if (width)
|
||||
*width = bmhd.w;
|
||||
if (height)
|
||||
*height = bmhd.h;
|
||||
}
|
||||
else if (!Q_strcasecmp (ext, "pcx"))
|
||||
{
|
||||
LoadPCX (name, pixels, palette, width, height);
|
||||
}
|
||||
else
|
||||
Error ("%s doesn't have a known image extension", name);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
Save256Image
|
||||
|
||||
Will save either an lbm or pcx, depending on extension.
|
||||
==============
|
||||
*/
|
||||
void Save256Image (char *name, byte *pixels, byte *palette,
|
||||
int width, int height)
|
||||
{
|
||||
char ext[128];
|
||||
|
||||
ExtractFileExtension (name, ext);
|
||||
if (!Q_strcasecmp (ext, "lbm"))
|
||||
{
|
||||
WriteLBMfile (name, pixels, width, height, palette);
|
||||
}
|
||||
else if (!Q_strcasecmp (ext, "pcx"))
|
||||
{
|
||||
WritePCXfile (name, pixels, width, height, palette);
|
||||
}
|
||||
else
|
||||
Error ("%s doesn't have a known image extension", name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
============================================================================
|
||||
|
||||
TARGA IMAGE
|
||||
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
typedef 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;
|
||||
} TargaHeader;
|
||||
|
||||
int fgetLittleShort (FILE *f)
|
||||
{
|
||||
byte b1, b2;
|
||||
|
||||
b1 = fgetc(f);
|
||||
b2 = fgetc(f);
|
||||
|
||||
return (short)(b1 + b2*256);
|
||||
}
|
||||
|
||||
int fgetLittleLong (FILE *f)
|
||||
{
|
||||
byte b1, b2, b3, b4;
|
||||
|
||||
b1 = fgetc(f);
|
||||
b2 = fgetc(f);
|
||||
b3 = fgetc(f);
|
||||
b4 = fgetc(f);
|
||||
|
||||
return b1 + (b2<<8) + (b3<<16) + (b4<<24);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
LoadTGA
|
||||
=============
|
||||
*/
|
||||
void LoadTGA (char *name, byte **pixels, int *width, int *height)
|
||||
{
|
||||
int columns, rows, numPixels;
|
||||
byte *pixbuf;
|
||||
int row, column;
|
||||
FILE *fin;
|
||||
byte *targa_rgba;
|
||||
TargaHeader targa_header;
|
||||
|
||||
fin = fopen (name, "rb");
|
||||
if (!fin)
|
||||
Error ("Couldn't read %s", name);
|
||||
|
||||
targa_header.id_length = fgetc(fin);
|
||||
targa_header.colormap_type = fgetc(fin);
|
||||
targa_header.image_type = fgetc(fin);
|
||||
|
||||
targa_header.colormap_index = fgetLittleShort(fin);
|
||||
targa_header.colormap_length = fgetLittleShort(fin);
|
||||
targa_header.colormap_size = fgetc(fin);
|
||||
targa_header.x_origin = fgetLittleShort(fin);
|
||||
targa_header.y_origin = fgetLittleShort(fin);
|
||||
targa_header.width = fgetLittleShort(fin);
|
||||
targa_header.height = fgetLittleShort(fin);
|
||||
targa_header.pixel_size = fgetc(fin);
|
||||
targa_header.attributes = fgetc(fin);
|
||||
|
||||
if (targa_header.image_type!=2
|
||||
&& targa_header.image_type!=10)
|
||||
Error ("LoadTGA: Only type 2 and 10 targa RGB images supported\n");
|
||||
|
||||
if (targa_header.colormap_type !=0
|
||||
|| (targa_header.pixel_size!=32 && targa_header.pixel_size!=24))
|
||||
Error ("Texture_LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");
|
||||
|
||||
columns = targa_header.width;
|
||||
rows = targa_header.height;
|
||||
numPixels = columns * rows;
|
||||
|
||||
if (width)
|
||||
*width = columns;
|
||||
if (height)
|
||||
*height = rows;
|
||||
targa_rgba = malloc(numPixels*4);
|
||||
*pixels = targa_rgba;
|
||||
|
||||
if (targa_header.id_length != 0)
|
||||
fseek(fin, targa_header.id_length, SEEK_CUR); // skip TARGA image comment
|
||||
|
||||
if (targa_header.image_type==2) { // Uncompressed, RGB images
|
||||
for(row=rows-1; row>=0; row--) {
|
||||
pixbuf = targa_rgba + row*columns*4;
|
||||
for(column=0; column<columns; column++) {
|
||||
unsigned char red,green,blue,alphabyte;
|
||||
switch (targa_header.pixel_size) {
|
||||
case 24:
|
||||
|
||||
blue = getc(fin);
|
||||
green = getc(fin);
|
||||
red = getc(fin);
|
||||
*pixbuf++ = red;
|
||||
*pixbuf++ = green;
|
||||
*pixbuf++ = blue;
|
||||
*pixbuf++ = 255;
|
||||
break;
|
||||
case 32:
|
||||
blue = getc(fin);
|
||||
green = getc(fin);
|
||||
red = getc(fin);
|
||||
alphabyte = getc(fin);
|
||||
*pixbuf++ = red;
|
||||
*pixbuf++ = green;
|
||||
*pixbuf++ = blue;
|
||||
*pixbuf++ = alphabyte;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (targa_header.image_type==10) { // Runlength encoded RGB images
|
||||
unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j;
|
||||
for(row=rows-1; row>=0; row--) {
|
||||
pixbuf = targa_rgba + row*columns*4;
|
||||
for(column=0; column<columns; ) {
|
||||
packetHeader=getc(fin);
|
||||
packetSize = 1 + (packetHeader & 0x7f);
|
||||
if (packetHeader & 0x80) { // run-length packet
|
||||
switch (targa_header.pixel_size) {
|
||||
case 24:
|
||||
blue = getc(fin);
|
||||
green = getc(fin);
|
||||
red = getc(fin);
|
||||
alphabyte = 255;
|
||||
break;
|
||||
case 32:
|
||||
blue = getc(fin);
|
||||
green = getc(fin);
|
||||
red = getc(fin);
|
||||
alphabyte = getc(fin);
|
||||
break;
|
||||
}
|
||||
|
||||
for(j=0;j<packetSize;j++) {
|
||||
*pixbuf++=red;
|
||||
*pixbuf++=green;
|
||||
*pixbuf++=blue;
|
||||
*pixbuf++=alphabyte;
|
||||
column++;
|
||||
if (column==columns) { // run spans across rows
|
||||
column=0;
|
||||
if (row>0)
|
||||
row--;
|
||||
else
|
||||
goto breakOut;
|
||||
pixbuf = targa_rgba + row*columns*4;
|
||||
}
|
||||
}
|
||||
}
|
||||
else { // non run-length packet
|
||||
for(j=0;j<packetSize;j++) {
|
||||
switch (targa_header.pixel_size) {
|
||||
case 24:
|
||||
blue = getc(fin);
|
||||
green = getc(fin);
|
||||
red = getc(fin);
|
||||
*pixbuf++ = red;
|
||||
*pixbuf++ = green;
|
||||
*pixbuf++ = blue;
|
||||
*pixbuf++ = 255;
|
||||
break;
|
||||
case 32:
|
||||
blue = getc(fin);
|
||||
green = getc(fin);
|
||||
red = getc(fin);
|
||||
alphabyte = getc(fin);
|
||||
*pixbuf++ = red;
|
||||
*pixbuf++ = green;
|
||||
*pixbuf++ = blue;
|
||||
*pixbuf++ = alphabyte;
|
||||
break;
|
||||
}
|
||||
column++;
|
||||
if (column==columns) { // pixel packet run spans across rows
|
||||
column=0;
|
||||
if (row>0)
|
||||
row--;
|
||||
else
|
||||
goto breakOut;
|
||||
pixbuf = targa_rgba + row*columns*4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
breakOut:;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fin);
|
||||
}
|
40
tools/quake2/extra/qe4/lbmlib.h
Normal file
40
tools/quake2/extra/qe4/lbmlib.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// piclib.h
|
||||
|
||||
|
||||
void LoadLBM (char *filename, byte **picture, byte **palette);
|
||||
void WriteLBMfile (char *filename, byte *data, int width, int height
|
||||
, byte *palette);
|
||||
void LoadPCX (char *filename, byte **picture, byte **palette, int *width, int *height);
|
||||
void WritePCXfile (char *filename, byte *data, int width, int height
|
||||
, byte *palette);
|
||||
|
||||
// loads / saves either lbm or pcx, depending on extension
|
||||
void Load256Image (char *name, byte **pixels, byte **palette,
|
||||
int *width, int *height);
|
||||
void Save256Image (char *name, byte *pixels, byte *palette,
|
||||
int width, int height);
|
||||
|
||||
|
||||
void LoadTGA (char *filename, byte **pixels, int *width, int *height);
|
23
tools/quake2/extra/qe4/makefile
Normal file
23
tools/quake2/extra/qe4/makefile
Normal file
|
@ -0,0 +1,23 @@
|
|||
|
||||
TARGETOS=WINNT
|
||||
|
||||
!include <ntwin32.mak>
|
||||
|
||||
# This line allows NMAKE to work as well
|
||||
|
||||
all: gengl.exe
|
||||
|
||||
# Update the object file if necessary
|
||||
|
||||
gengl.obj: gengl.c gengl.h
|
||||
$(cc) $(cflags) $(cvars) $(cdebug) $(cf) gengl.c
|
||||
|
||||
render.obj: render.c gengl.h
|
||||
$(cc) $(cflags) $(cvars) $(cdebug) $(cf) render.c
|
||||
|
||||
gengl.res: gengl.rc genglrc.h
|
||||
rc -r gengl.rc
|
||||
|
||||
gengl.exe: gengl.obj gengl.res render.obj
|
||||
$(link) $(linkdebug) /NODEFAULTLIB $(guilflags) -out:gengl.exe \
|
||||
gengl.obj render.obj gengl.res $(guilibsdll) opengl32.lib glu32.lib
|
661
tools/quake2/extra/qe4/map.c
Normal file
661
tools/quake2/extra/qe4/map.c
Normal file
|
@ -0,0 +1,661 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// map.c
|
||||
|
||||
#include "qe3.h"
|
||||
|
||||
qboolean modified; // for quit confirmation (0 = clean, 1 = unsaved,
|
||||
// 2 = autosaved, but not regular saved)
|
||||
|
||||
char currentmap[1024];
|
||||
|
||||
brush_t active_brushes; // brushes currently being displayed
|
||||
brush_t selected_brushes; // highlighted
|
||||
face_t *selected_face;
|
||||
brush_t *selected_face_brush;
|
||||
brush_t filtered_brushes; // brushes that have been filtered or regioned
|
||||
|
||||
entity_t entities; // head/tail of doubly linked list
|
||||
|
||||
entity_t *world_entity;
|
||||
|
||||
void AddRegionBrushes (void);
|
||||
void RemoveRegionBrushes (void);
|
||||
|
||||
/*
|
||||
=============================================================
|
||||
|
||||
Cross map selection saving
|
||||
|
||||
this could fuck up if you have only part of a complex entity selected...
|
||||
=============================================================
|
||||
*/
|
||||
|
||||
brush_t between_brushes;
|
||||
entity_t between_entities;
|
||||
|
||||
|
||||
void Map_SaveBetween (void)
|
||||
{
|
||||
brush_t *b;
|
||||
entity_t *e, *e2;
|
||||
|
||||
between_brushes.next = selected_brushes.next;
|
||||
between_brushes.prev = selected_brushes.prev;
|
||||
between_brushes.next->prev = &between_brushes;
|
||||
between_brushes.prev->next = &between_brushes;
|
||||
|
||||
between_entities.next = between_entities.prev = &between_entities;
|
||||
selected_brushes.next = selected_brushes.prev = &selected_brushes;
|
||||
|
||||
for (b=between_brushes.next ; b != &between_brushes ; b=b->next)
|
||||
{
|
||||
e = b->owner;
|
||||
if (e == world_entity)
|
||||
b->owner = NULL;
|
||||
else
|
||||
{
|
||||
for (e2=between_entities.next ; e2 != &between_entities ; e2=e2->next)
|
||||
if (e2 == e)
|
||||
goto next; // allready got the entity
|
||||
// move the entity over
|
||||
e->prev->next = e->next;
|
||||
e->next->prev = e->prev;
|
||||
e->next = between_entities.next;
|
||||
e->prev = &between_entities;
|
||||
e->next->prev = e;
|
||||
e->prev->next = e;
|
||||
}
|
||||
next: ;
|
||||
}
|
||||
}
|
||||
|
||||
void Map_RestoreBetween (void)
|
||||
{
|
||||
entity_t *head, *tail;
|
||||
brush_t *b;
|
||||
|
||||
if (!between_brushes.next)
|
||||
return;
|
||||
|
||||
for (b=between_brushes.next ; b != &between_brushes ; b=b->next)
|
||||
{
|
||||
if (!b->owner)
|
||||
{
|
||||
b->owner = world_entity;
|
||||
b->onext = world_entity->brushes.onext;
|
||||
b->oprev = &world_entity->brushes;
|
||||
b->onext->oprev = b;
|
||||
b->oprev->onext = b;
|
||||
}
|
||||
}
|
||||
|
||||
selected_brushes.next = between_brushes.next;
|
||||
selected_brushes.prev = between_brushes.prev;
|
||||
selected_brushes.next->prev = &selected_brushes;
|
||||
selected_brushes.prev->next = &selected_brushes;
|
||||
|
||||
head = between_entities.next;
|
||||
tail = between_entities.prev;
|
||||
|
||||
if (head != tail)
|
||||
{
|
||||
entities.prev->next = head;
|
||||
head->prev = entities.prev;
|
||||
tail->next = &entities;
|
||||
entities.prev = tail;
|
||||
}
|
||||
|
||||
between_brushes.next = NULL;
|
||||
between_entities.next = NULL;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
||||
void Map_BuildBrushData(void)
|
||||
{
|
||||
brush_t *b, *next;
|
||||
|
||||
if (active_brushes.next == NULL)
|
||||
return;
|
||||
|
||||
Sys_BeginWait (); // this could take a while
|
||||
|
||||
for (b=active_brushes.next ; b != NULL && b != &active_brushes ; b=next)
|
||||
{
|
||||
next = b->next;
|
||||
Brush_Build( b );
|
||||
if (!b->brush_faces)
|
||||
{
|
||||
Brush_Free (b);
|
||||
Sys_Printf ("Removed degenerate brush\n");
|
||||
}
|
||||
}
|
||||
|
||||
Sys_EndWait();
|
||||
}
|
||||
|
||||
entity_t *Map_FindClass (char *cname)
|
||||
{
|
||||
entity_t *ent;
|
||||
|
||||
for (ent = entities.next ; ent != &entities ; ent=ent->next)
|
||||
{
|
||||
if (!strcmp(cname, ValueForKey (ent, "classname")))
|
||||
return ent;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Map_Free
|
||||
================
|
||||
*/
|
||||
void Map_Free (void)
|
||||
{
|
||||
if (selected_brushes.next &&
|
||||
(selected_brushes.next != &selected_brushes) )
|
||||
{
|
||||
if (MessageBox(g_qeglobals.d_hwndMain, "Copy selection?", "", MB_YESNO) == IDYES)
|
||||
Map_SaveBetween ();
|
||||
}
|
||||
|
||||
Texture_ClearInuse ();
|
||||
Pointfile_Clear ();
|
||||
strcpy (currentmap, "unnamed.map");
|
||||
Sys_SetTitle (currentmap);
|
||||
g_qeglobals.d_num_entities = 0;
|
||||
|
||||
if (!active_brushes.next)
|
||||
{ // first map
|
||||
active_brushes.prev = active_brushes.next = &active_brushes;
|
||||
selected_brushes.prev = selected_brushes.next = &selected_brushes;
|
||||
filtered_brushes.prev = filtered_brushes.next = &filtered_brushes;
|
||||
|
||||
entities.prev = entities.next = &entities;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (active_brushes.next != &active_brushes)
|
||||
Brush_Free (active_brushes.next);
|
||||
while (selected_brushes.next != &selected_brushes)
|
||||
Brush_Free (selected_brushes.next);
|
||||
while (filtered_brushes.next != &filtered_brushes)
|
||||
Brush_Free (filtered_brushes.next);
|
||||
|
||||
while (entities.next != &entities)
|
||||
Entity_Free (entities.next);
|
||||
}
|
||||
|
||||
world_entity = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Map_LoadFile
|
||||
================
|
||||
*/
|
||||
void Map_LoadFile (char *filename)
|
||||
{
|
||||
char *buf;
|
||||
entity_t *ent;
|
||||
char temp[1024];
|
||||
|
||||
Sys_BeginWait ();
|
||||
|
||||
SetInspectorMode(W_CONSOLE);
|
||||
|
||||
QE_ConvertDOSToUnixName( temp, filename );
|
||||
Sys_Printf ("Map_LoadFile: %s\n", temp );
|
||||
|
||||
Map_Free ();
|
||||
|
||||
g_qeglobals.d_parsed_brushes = 0;
|
||||
strcpy (currentmap, filename);
|
||||
LoadFile (filename, (void **)&buf);
|
||||
|
||||
StartTokenParsing (buf);
|
||||
|
||||
g_qeglobals.d_num_entities = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
ent = Entity_Parse (false);
|
||||
if (!ent)
|
||||
break;
|
||||
if (!strcmp(ValueForKey (ent, "classname"), "worldspawn"))
|
||||
{
|
||||
if (world_entity)
|
||||
Sys_Printf ("WARNING: multiple worldspawn\n");
|
||||
world_entity = ent;
|
||||
}
|
||||
else
|
||||
{
|
||||
// add the entity to the end of the entity list
|
||||
ent->next = &entities;
|
||||
ent->prev = entities.prev;
|
||||
entities.prev->next = ent;
|
||||
entities.prev = ent;
|
||||
g_qeglobals.d_num_entities++;
|
||||
}
|
||||
}
|
||||
|
||||
free (buf);
|
||||
|
||||
if (!world_entity)
|
||||
{
|
||||
Sys_Printf ("No worldspawn in map.\n");
|
||||
Map_New ();
|
||||
return;
|
||||
}
|
||||
|
||||
Sys_Printf ("--- LoadMapFile ---\n");
|
||||
Sys_Printf ("%s\n", temp );
|
||||
|
||||
Sys_Printf ("%5i brushes\n", g_qeglobals.d_parsed_brushes );
|
||||
Sys_Printf ("%5i entities\n", g_qeglobals.d_num_entities);
|
||||
|
||||
Map_RestoreBetween ();
|
||||
|
||||
Sys_Printf ("Map_BuildAllDisplayLists\n");
|
||||
Map_BuildBrushData();
|
||||
|
||||
//
|
||||
// move the view to a start position
|
||||
//
|
||||
ent = Map_FindClass ("info_player_start");
|
||||
if (!ent)
|
||||
ent = Map_FindClass ("info_player_deathmatch");
|
||||
camera.angles[PITCH] = 0;
|
||||
if (ent)
|
||||
{
|
||||
GetVectorForKey (ent, "origin", camera.origin);
|
||||
GetVectorForKey (ent, "origin", g_qeglobals.d_xy.origin);
|
||||
camera.angles[YAW] = FloatForKey (ent, "angle");
|
||||
}
|
||||
else
|
||||
{
|
||||
camera.angles[YAW] = 0;
|
||||
VectorCopy (vec3_origin, camera.origin);
|
||||
VectorCopy (vec3_origin, g_qeglobals.d_xy.origin);
|
||||
}
|
||||
|
||||
Sys_UpdateWindows (W_ALL);
|
||||
|
||||
Map_RegionOff ();
|
||||
|
||||
modified = false;
|
||||
Sys_SetTitle (temp);
|
||||
|
||||
Texture_ShowInuse ();
|
||||
|
||||
Sys_EndWait();
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
Map_SaveFile
|
||||
===========
|
||||
*/
|
||||
void Map_SaveFile (char *filename, qboolean use_region )
|
||||
{
|
||||
entity_t *e, *next;
|
||||
FILE *f;
|
||||
char temp[1024];
|
||||
int count;
|
||||
|
||||
QE_ConvertDOSToUnixName( temp, filename );
|
||||
|
||||
if (!use_region)
|
||||
{
|
||||
char backup[1024];
|
||||
|
||||
// rename current to .bak
|
||||
strcpy (backup, filename);
|
||||
StripExtension (backup);
|
||||
strcat (backup, ".bak");
|
||||
_unlink (backup);
|
||||
rename (filename, backup);
|
||||
}
|
||||
|
||||
Sys_Printf ("Map_SaveFile: %s\n", filename);
|
||||
|
||||
f = fopen(filename, "w");
|
||||
if (!f)
|
||||
{
|
||||
Sys_Printf ("ERROR!!!! Couldn't open %s\n", filename);
|
||||
return;
|
||||
}
|
||||
|
||||
if (use_region)
|
||||
AddRegionBrushes ();
|
||||
|
||||
// write world entity first
|
||||
Entity_Write (world_entity, f, use_region);
|
||||
|
||||
// then write all other ents
|
||||
count = 1;
|
||||
for (e=entities.next ; e != &entities ; e=next)
|
||||
{
|
||||
fprintf (f, "// entity %i\n", count);
|
||||
count++;
|
||||
next = e->next;
|
||||
if (e->brushes.onext == &e->brushes)
|
||||
Entity_Free (e); // no brushes left, so remove it
|
||||
else
|
||||
Entity_Write (e, f, use_region);
|
||||
}
|
||||
|
||||
fclose (f);
|
||||
|
||||
if (use_region)
|
||||
RemoveRegionBrushes ();
|
||||
|
||||
Sys_Printf ("Saved.\n");
|
||||
modified = false;
|
||||
|
||||
if ( !strstr( temp, "autosave" ) )
|
||||
Sys_SetTitle (temp);
|
||||
|
||||
if (!use_region)
|
||||
{
|
||||
time_t timer;
|
||||
FILE *f;
|
||||
|
||||
time (&timer);
|
||||
MessageBeep (MB_ICONEXCLAMATION);
|
||||
f = fopen ("c:/tstamps.log", "a");
|
||||
if (f)
|
||||
{
|
||||
fprintf (f, "%4i : %35s : %s", g_qeglobals.d_workcount, filename, ctime(&timer));
|
||||
fclose (f);
|
||||
g_qeglobals.d_workcount = 0;
|
||||
}
|
||||
fclose (f);
|
||||
Sys_Status ("Saved.\n", 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
Map_New
|
||||
===========
|
||||
*/
|
||||
void Map_New (void)
|
||||
{
|
||||
Sys_Printf ("Map_New\n");
|
||||
Map_Free ();
|
||||
world_entity = qmalloc(sizeof(*world_entity));
|
||||
world_entity->brushes.onext =
|
||||
world_entity->brushes.oprev = &world_entity->brushes;
|
||||
SetKeyValue (world_entity, "classname", "worldspawn");
|
||||
world_entity->eclass = Eclass_ForName ("worldspawn", true);
|
||||
|
||||
camera.angles[YAW] = 0;
|
||||
VectorCopy (vec3_origin, camera.origin);
|
||||
camera.origin[2] = 48;
|
||||
VectorCopy (vec3_origin, g_qeglobals.d_xy.origin);
|
||||
|
||||
Map_RestoreBetween ();
|
||||
|
||||
Sys_UpdateWindows (W_ALL);
|
||||
modified = false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===========================================================
|
||||
|
||||
REGION
|
||||
|
||||
===========================================================
|
||||
*/
|
||||
|
||||
qboolean region_active;
|
||||
vec3_t region_mins = {-4096, -4096, -4096};
|
||||
vec3_t region_maxs = {4096, 4096, 4096};
|
||||
|
||||
brush_t *region_sides[4];
|
||||
|
||||
/*
|
||||
===========
|
||||
AddRegionBrushes
|
||||
|
||||
a regioned map will have temp walls put up at the region boundary
|
||||
===========
|
||||
*/
|
||||
void AddRegionBrushes (void)
|
||||
{
|
||||
vec3_t mins, maxs;
|
||||
int i;
|
||||
texdef_t td;
|
||||
|
||||
if (!region_active)
|
||||
return;
|
||||
|
||||
memset (&td, 0, sizeof(td));
|
||||
strcpy (td.name, "REGION");
|
||||
|
||||
mins[0] = region_mins[0] - 16;
|
||||
maxs[0] = region_mins[0] + 1;
|
||||
mins[1] = region_mins[1] - 16;
|
||||
maxs[1] = region_maxs[1] + 16;
|
||||
mins[2] = -2048;
|
||||
maxs[2] = 2048;
|
||||
region_sides[0] = Brush_Create (mins, maxs, &td);
|
||||
|
||||
mins[0] = region_maxs[0] - 1;
|
||||
maxs[0] = region_maxs[0] + 16;
|
||||
region_sides[1] = Brush_Create (mins, maxs, &td);
|
||||
|
||||
mins[0] = region_mins[0] - 16;
|
||||
maxs[0] = region_maxs[0] + 16;
|
||||
mins[1] = region_mins[1] - 16;
|
||||
maxs[1] = region_mins[1] + 1;
|
||||
region_sides[2] = Brush_Create (mins, maxs, &td);
|
||||
|
||||
mins[1] = region_maxs[1] - 1;
|
||||
maxs[1] = region_maxs[1] + 16;
|
||||
region_sides[3] = Brush_Create (mins, maxs, &td);
|
||||
|
||||
for (i=0 ; i<4 ; i++)
|
||||
{
|
||||
Brush_AddToList (region_sides[i], &selected_brushes);
|
||||
Entity_LinkBrush (world_entity, region_sides[i]);
|
||||
Brush_Build( region_sides[i] );
|
||||
}
|
||||
}
|
||||
|
||||
void RemoveRegionBrushes (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!region_active)
|
||||
return;
|
||||
for (i=0 ; i<4 ; i++)
|
||||
Brush_Free (region_sides[i]);
|
||||
}
|
||||
|
||||
|
||||
qboolean Map_IsBrushFiltered (brush_t *b)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
if (b->mins[i] > region_maxs[i])
|
||||
return true;
|
||||
if (b->maxs[i] < region_mins[i])
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
Map_RegionOff
|
||||
|
||||
Other filtering options may still be on
|
||||
===========
|
||||
*/
|
||||
void Map_RegionOff (void)
|
||||
{
|
||||
brush_t *b, *next;
|
||||
int i;
|
||||
|
||||
region_active = false;
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
region_maxs[i] = 4096;
|
||||
region_mins[i] = -4096;
|
||||
}
|
||||
|
||||
for (b=filtered_brushes.next ; b != &filtered_brushes ; b=next)
|
||||
{
|
||||
next = b->next;
|
||||
if (Map_IsBrushFiltered (b))
|
||||
continue; // still filtered
|
||||
Brush_RemoveFromList (b);
|
||||
Brush_AddToList (b, &active_brushes);
|
||||
}
|
||||
|
||||
Sys_UpdateWindows (W_ALL);
|
||||
}
|
||||
|
||||
void Map_ApplyRegion (void)
|
||||
{
|
||||
brush_t *b, *next;
|
||||
|
||||
region_active = true;
|
||||
for (b=active_brushes.next ; b != &active_brushes ; b=next)
|
||||
{
|
||||
next = b->next;
|
||||
if (!Map_IsBrushFiltered (b))
|
||||
continue; // still filtered
|
||||
Brush_RemoveFromList (b);
|
||||
Brush_AddToList (b, &filtered_brushes);
|
||||
}
|
||||
|
||||
Sys_UpdateWindows (W_ALL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
========================
|
||||
Map_RegionSelectedBrushes
|
||||
========================
|
||||
*/
|
||||
void Map_RegionSelectedBrushes (void)
|
||||
{
|
||||
Map_RegionOff ();
|
||||
|
||||
region_active = true;
|
||||
Select_GetBounds (region_mins, region_maxs);
|
||||
|
||||
// move the entire active_brushes list to filtered_brushes
|
||||
filtered_brushes.next = active_brushes.next;
|
||||
filtered_brushes.prev = active_brushes.prev;
|
||||
filtered_brushes.next->prev = &filtered_brushes;
|
||||
filtered_brushes.prev->next = &filtered_brushes;
|
||||
|
||||
// move the entire selected_brushes list to active_brushes
|
||||
active_brushes.next = selected_brushes.next;
|
||||
active_brushes.prev = selected_brushes.prev;
|
||||
active_brushes.next->prev = &active_brushes;
|
||||
active_brushes.prev->next = &active_brushes;
|
||||
|
||||
// clear selected_brushes
|
||||
selected_brushes.next = selected_brushes.prev = &selected_brushes;
|
||||
|
||||
Sys_UpdateWindows (W_ALL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===========
|
||||
Map_RegionXY
|
||||
===========
|
||||
*/
|
||||
void Map_RegionXY (void)
|
||||
{
|
||||
Map_RegionOff ();
|
||||
|
||||
region_mins[0] = g_qeglobals.d_xy.origin[0] - 0.5*g_qeglobals.d_xy.width/g_qeglobals.d_xy.scale;
|
||||
region_maxs[0] = g_qeglobals.d_xy.origin[0] + 0.5*g_qeglobals.d_xy.width/g_qeglobals.d_xy.scale;
|
||||
region_mins[1] = g_qeglobals.d_xy.origin[1] - 0.5*g_qeglobals.d_xy.height/g_qeglobals.d_xy.scale;
|
||||
region_maxs[1] = g_qeglobals.d_xy.origin[1] + 0.5*g_qeglobals.d_xy.height/g_qeglobals.d_xy.scale;
|
||||
region_mins[2] = -4096;
|
||||
region_maxs[2] = 4096;
|
||||
|
||||
Map_ApplyRegion ();
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
Map_RegionTallBrush
|
||||
===========
|
||||
*/
|
||||
void Map_RegionTallBrush (void)
|
||||
{
|
||||
brush_t *b;
|
||||
|
||||
if (!QE_SingleBrush ())
|
||||
return;
|
||||
|
||||
b = selected_brushes.next;
|
||||
|
||||
Map_RegionOff ();
|
||||
|
||||
VectorCopy (b->mins, region_mins);
|
||||
VectorCopy (b->maxs, region_maxs);
|
||||
region_mins[2] = -4096;
|
||||
region_maxs[2] = 4096;
|
||||
|
||||
Select_Delete ();
|
||||
Map_ApplyRegion ();
|
||||
}
|
||||
/*
|
||||
===========
|
||||
Map_RegionBrush
|
||||
===========
|
||||
*/
|
||||
void Map_RegionBrush (void)
|
||||
{
|
||||
brush_t *b;
|
||||
|
||||
if (!QE_SingleBrush ())
|
||||
return;
|
||||
|
||||
b = selected_brushes.next;
|
||||
|
||||
Map_RegionOff ();
|
||||
|
||||
VectorCopy (b->mins, region_mins);
|
||||
VectorCopy (b->maxs, region_maxs);
|
||||
|
||||
Select_Delete ();
|
||||
Map_ApplyRegion ();
|
||||
}
|
||||
|
53
tools/quake2/extra/qe4/map.h
Normal file
53
tools/quake2/extra/qe4/map.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// map.h -- the state of the current world that all views are displaying
|
||||
|
||||
extern char currentmap[1024];
|
||||
|
||||
// head/tail of doubly linked lists
|
||||
extern brush_t active_brushes; // brushes currently being displayed
|
||||
extern brush_t selected_brushes; // highlighted
|
||||
extern face_t *selected_face;
|
||||
extern brush_t *selected_face_brush;
|
||||
extern brush_t filtered_brushes; // brushes that have been filtered or regioned
|
||||
|
||||
extern entity_t entities;
|
||||
extern entity_t *world_entity; // the world entity is NOT included in
|
||||
// the entities chain
|
||||
|
||||
extern qboolean modified; // for quit confirmations
|
||||
|
||||
extern vec3_t region_mins, region_maxs;
|
||||
extern qboolean region_active;
|
||||
|
||||
void Map_LoadFile (char *filename);
|
||||
void Map_SaveFile (char *filename, qboolean use_region);
|
||||
void Map_New (void);
|
||||
void Map_BuildBrushData(void);
|
||||
|
||||
void Map_RegionOff (void);
|
||||
void Map_RegionXY (void);
|
||||
void Map_RegionTallBrush (void);
|
||||
void Map_RegionBrush (void);
|
||||
void Map_RegionSelectedBrushes (void);
|
||||
qboolean Map_IsBrushFiltered (brush_t *b);
|
131
tools/quake2/extra/qe4/mathlib.c
Normal file
131
tools/quake2/extra/qe4/mathlib.c
Normal file
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// mathlib.c -- math primitives
|
||||
|
||||
#include "cmdlib.h"
|
||||
#include "mathlib.h"
|
||||
|
||||
vec3_t vec3_origin = {0.0f,0.0f,0.0f};
|
||||
|
||||
|
||||
float VectorLength(vec3_t v)
|
||||
{
|
||||
int i;
|
||||
float length;
|
||||
|
||||
length = 0.0f;
|
||||
for (i=0 ; i< 3 ; i++)
|
||||
length += v[i]*v[i];
|
||||
length = (float)sqrt (length);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
qboolean VectorCompare (vec3_t v1, vec3_t v2)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
if (fabs(v1[i]-v2[i]) > EQUAL_EPSILON)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
vec_t Q_rint (vec_t in)
|
||||
{
|
||||
return (float)floor (in + 0.5);
|
||||
}
|
||||
|
||||
void VectorMA (vec3_t va, float scale, vec3_t vb, vec3_t vc)
|
||||
{
|
||||
vc[0] = va[0] + scale*vb[0];
|
||||
vc[1] = va[1] + scale*vb[1];
|
||||
vc[2] = va[2] + scale*vb[2];
|
||||
}
|
||||
|
||||
void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross)
|
||||
{
|
||||
cross[0] = v1[1]*v2[2] - v1[2]*v2[1];
|
||||
cross[1] = v1[2]*v2[0] - v1[0]*v2[2];
|
||||
cross[2] = v1[0]*v2[1] - v1[1]*v2[0];
|
||||
}
|
||||
|
||||
vec_t _DotProduct (vec3_t v1, vec3_t v2)
|
||||
{
|
||||
return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
|
||||
}
|
||||
|
||||
void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out)
|
||||
{
|
||||
out[0] = va[0]-vb[0];
|
||||
out[1] = va[1]-vb[1];
|
||||
out[2] = va[2]-vb[2];
|
||||
}
|
||||
|
||||
void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out)
|
||||
{
|
||||
out[0] = va[0]+vb[0];
|
||||
out[1] = va[1]+vb[1];
|
||||
out[2] = va[2]+vb[2];
|
||||
}
|
||||
|
||||
void _VectorCopy (vec3_t in, vec3_t out)
|
||||
{
|
||||
out[0] = in[0];
|
||||
out[1] = in[1];
|
||||
out[2] = in[2];
|
||||
}
|
||||
|
||||
vec_t VectorNormalize (vec3_t v)
|
||||
{
|
||||
int i;
|
||||
float length;
|
||||
|
||||
length = 0.0f;
|
||||
for (i=0 ; i< 3 ; i++)
|
||||
length += v[i]*v[i];
|
||||
length = (float)sqrt (length);
|
||||
if (length == 0)
|
||||
return (vec_t)0;
|
||||
|
||||
for (i=0 ; i< 3 ; i++)
|
||||
v[i] /= length;
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
void VectorInverse (vec3_t v)
|
||||
{
|
||||
v[0] = -v[0];
|
||||
v[1] = -v[1];
|
||||
v[2] = -v[2];
|
||||
}
|
||||
|
||||
void VectorScale (vec3_t v, vec_t scale, vec3_t out)
|
||||
{
|
||||
out[0] = v[0] * scale;
|
||||
out[1] = v[1] * scale;
|
||||
out[2] = v[2] * scale;
|
||||
}
|
||||
|
66
tools/quake2/extra/qe4/mathlib.h
Normal file
66
tools/quake2/extra/qe4/mathlib.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __MATHLIB__
|
||||
#define __MATHLIB__
|
||||
|
||||
// mathlib.h
|
||||
|
||||
#include <math.h>
|
||||
|
||||
typedef float vec_t;
|
||||
typedef vec_t vec3_t[3];
|
||||
|
||||
#define SIDE_FRONT 0
|
||||
#define SIDE_ON 2
|
||||
#define SIDE_BACK 1
|
||||
#define SIDE_CROSS -2
|
||||
|
||||
#define Q_PI 3.14159265358979323846
|
||||
|
||||
extern vec3_t vec3_origin;
|
||||
|
||||
#define EQUAL_EPSILON 0.001
|
||||
|
||||
qboolean VectorCompare (vec3_t v1, vec3_t v2);
|
||||
|
||||
#define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2])
|
||||
#define VectorSubtract(a,b,c) {c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];}
|
||||
#define VectorAdd(a,b,c) {c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2];}
|
||||
#define VectorCopy(a,b) {b[0]=a[0];b[1]=a[1];b[2]=a[2];}
|
||||
|
||||
vec_t Q_rint (vec_t in);
|
||||
vec_t _DotProduct (vec3_t v1, vec3_t v2);
|
||||
void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out);
|
||||
void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out);
|
||||
void _VectorCopy (vec3_t in, vec3_t out);
|
||||
|
||||
float VectorLength(vec3_t v);
|
||||
|
||||
void VectorMA (vec3_t va, float scale, vec3_t vb, vec3_t vc);
|
||||
|
||||
void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross);
|
||||
vec_t VectorNormalize (vec3_t v);
|
||||
void VectorInverse (vec3_t v);
|
||||
void VectorScale (vec3_t v, vec_t scale, vec3_t out);
|
||||
|
||||
#endif
|
671
tools/quake2/extra/qe4/mru.c
Normal file
671
tools/quake2/extra/qe4/mru.c
Normal file
|
@ -0,0 +1,671 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code 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.
|
||||
|
||||
Quake 2 Tools source code 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 Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
//*************************************************************
|
||||
// File name: mru.c
|
||||
//
|
||||
// Description:
|
||||
//
|
||||
// Routines for MRU support
|
||||
//
|
||||
// Development Team:
|
||||
//
|
||||
// Gilles Vollant (100144.2636@compuserve.com)
|
||||
//
|
||||
//*************************************************************
|
||||
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mru.h"
|
||||
// CreateMruMenu : MRUMENU constructor
|
||||
// wNbLruShowInit : nb of item showed in menu
|
||||
// wNbLruMenuInit : nb of item stored in memory
|
||||
// wMaxSizeLruItemInit : size max. of filename
|
||||
|
||||
|
||||
//*************************************************************
|
||||
//
|
||||
// CreateMruMenu()
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// Allocate and Initialize an MRU and return a pointer on it
|
||||
//
|
||||
//
|
||||
// Parameters:
|
||||
//
|
||||
// WORD wNbLruShowInit - Maximum number of item displayed on menu
|
||||
// WORD wNbLruMenuInit - Maximum number of item stored in memory
|
||||
// WORD wMaxSizeLruItemInit - Maximum size of an item (ie size of pathname)
|
||||
// WORD wIdMruInit - ID of the first item in the menu (default:IDMRU)
|
||||
//
|
||||
//
|
||||
// Return: (LPMRUMENU)
|
||||
//
|
||||
// Pointer on a MRUMENU structure, used by other function
|
||||
//
|
||||
//
|
||||
// Comments:
|
||||
// wNbLruShowInit <= wNbLruMenuInit
|
||||
//
|
||||
//
|
||||
// History: Date Author Comment
|
||||
// 09/24/94 G. Vollant Created
|
||||
//
|
||||
//*************************************************************
|
||||
|
||||
LPMRUMENU CreateMruMenu (WORD wNbLruShowInit,
|
||||
WORD wNbLruMenuInit,WORD wMaxSizeLruItemInit,WORD wIdMruInit)
|
||||
{
|
||||
LPMRUMENU lpMruMenu;
|
||||
lpMruMenu = (LPMRUMENU)GlobalAllocPtr(GHND,sizeof(MRUMENU));
|
||||
|
||||
lpMruMenu->wNbItemFill = 0;
|
||||
lpMruMenu->wNbLruMenu = wNbLruMenuInit;
|
||||
lpMruMenu->wNbLruShow = wNbLruShowInit;
|
||||
lpMruMenu->wIdMru = wIdMruInit;
|
||||
lpMruMenu->wMaxSizeLruItem = wMaxSizeLruItemInit;
|
||||
lpMruMenu->lpMRU = (LPSTR)GlobalAllocPtr(GHND,
|
||||
lpMruMenu->wNbLruMenu*(UINT)lpMruMenu->wMaxSizeLruItem);
|
||||
if (lpMruMenu->lpMRU == NULL)
|
||||
{
|
||||
GlobalFreePtr(lpMruMenu);
|
||||
lpMruMenu = NULL;
|
||||
}
|
||||
return lpMruMenu;
|
||||
}
|
||||
|
||||
//*************************************************************
|
||||
//
|
||||
// CreateMruMenuDefault()
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// Allocate and Initialize an MRU and return a pointer on it
|
||||
// Use default parameter
|
||||
//
|
||||
//
|
||||
// Parameters:
|
||||
//
|
||||
//
|
||||
// Return: (LPMRUMENU)
|
||||
//
|
||||
// Pointer on a MRUMENU structure, used by other function
|
||||
//
|
||||
//
|
||||
// Comments:
|
||||
//
|
||||
//
|
||||
// History: Date Author Comment
|
||||
// 09/24/94 G. Vollant Created
|
||||
//
|
||||
//*************************************************************
|
||||
|
||||
LPMRUMENU CreateMruMenuDefault()
|
||||
{
|
||||
return CreateMruMenu (NBMRUMENUSHOW,NBMRUMENU,MAXSIZEMRUITEM,IDMRU);
|
||||
}
|
||||
|
||||
|
||||
//*************************************************************
|
||||
//
|
||||
// DeleteMruMenu()
|
||||
//
|
||||
// Purpose:
|
||||
// Destructor :
|
||||
// Clean and free a MRUMENU structure
|
||||
//
|
||||
// Parameters:
|
||||
//
|
||||
// LPMRUMENU lpMruMenu - pointer on MRUMENU, allocated
|
||||
// by CreateMruMenu() or CreateMruMenuDefault()
|
||||
//
|
||||
//
|
||||
// Return: void
|
||||
//
|
||||
//
|
||||
// Comments:
|
||||
//
|
||||
//
|
||||
// History: Date Author Comment
|
||||
// 09/24/94 G. Vollant Created
|
||||
//
|
||||
//*************************************************************
|
||||
void DeleteMruMenu(LPMRUMENU lpMruMenu)
|
||||
{
|
||||
GlobalFreePtr(lpMruMenu->lpMRU);
|
||||
GlobalFreePtr(lpMruMenu);
|
||||
}
|
||||
|
||||
//*************************************************************
|
||||
//
|
||||
// SetNbLruShow()
|
||||
//
|
||||
// Purpose:
|
||||
// Change the maximum number of item displayed on menu
|
||||
//
|
||||
// Parameters:
|
||||
// LPMRUMENU lpMruMenu - pointer on MRUMENU
|
||||
// WORD wNbLruShowInit - Maximum number of item displayed on menu
|
||||
//
|
||||
//
|
||||
// Return: void
|
||||
//
|
||||
//
|
||||
// Comments:
|
||||
//
|
||||
//
|
||||
// History: Date Author Comment
|
||||
// 09/24/94 G. Vollant Created
|
||||
//
|
||||
//*************************************************************
|
||||
void SetNbLruShow (LPMRUMENU lpMruMenu,WORD wNbLruShowInit)
|
||||
{
|
||||
lpMruMenu->wNbLruShow = min(wNbLruShowInit,lpMruMenu->wNbLruMenu);
|
||||
}
|
||||
|
||||
//*************************************************************
|
||||
//
|
||||
// SetMenuItem()
|
||||
//
|
||||
// Purpose:
|
||||
// Set the filename of an item
|
||||
//
|
||||
// Parameters:
|
||||
// LPMRUMENU lpMruMenu - pointer on MRUMENU
|
||||
// WORD wItem - Number of Item to set, zero based
|
||||
// LPSTR lpItem - String, contain the filename of the item
|
||||
//
|
||||
//
|
||||
// Return: (BOOL)
|
||||
// TRUE - Function run successfully
|
||||
// FALSE - Function don't run successfully
|
||||
//
|
||||
//
|
||||
// Comments:
|
||||
// used when load .INI or reg database
|
||||
//
|
||||
// History: Date Author Comment
|
||||
// 09/24/94 G. Vollant Created
|
||||
//
|
||||
//*************************************************************
|
||||
BOOL SetMenuItem (LPMRUMENU lpMruMenu,WORD wItem,LPSTR lpItem)
|
||||
{
|
||||
if (wItem >= NBMRUMENU)
|
||||
return FALSE;
|
||||
_fstrncpy((lpMruMenu->lpMRU) +
|
||||
((lpMruMenu->wMaxSizeLruItem) * (UINT)wItem),
|
||||
lpItem,lpMruMenu->wMaxSizeLruItem-1);
|
||||
lpMruMenu->wNbItemFill = max(lpMruMenu->wNbItemFill,wItem+1);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//*************************************************************
|
||||
//
|
||||
// GetMenuItem()
|
||||
//
|
||||
// Purpose:
|
||||
// Get the filename of an item
|
||||
//
|
||||
// Parameters:
|
||||
// LPMRUMENU lpMruMenu - pointer on MRUMENU
|
||||
// WORD wItem - Number of Item to set, zero based
|
||||
// BOOL fIDMBased - TRUE : wItem is based on ID menu item
|
||||
// FALSE : wItem is zero-based
|
||||
// LPSTR lpItem - String where the filename of the item will be
|
||||
// stored by GetMenuItem()
|
||||
// UINT uiSize - Size of the lpItem buffer
|
||||
//
|
||||
//
|
||||
// Return: (BOOL)
|
||||
// TRUE - Function run successfully
|
||||
// FALSE - Function don't run successfully
|
||||
//
|
||||
//
|
||||
// Comments:
|
||||
// Used for saving in .INI or reg database, or when user select
|
||||
// an MRU in File menu
|
||||
//
|
||||
// History: Date Author Comment
|
||||
// 09/24/94 G. Vollant Created
|
||||
//
|
||||
//*************************************************************
|
||||
BOOL GetMenuItem (LPMRUMENU lpMruMenu,WORD wItem,
|
||||
BOOL fIDMBased,LPSTR lpItem,UINT uiSize)
|
||||
{
|
||||
if (fIDMBased)
|
||||
wItem -= (lpMruMenu->wIdMru + 1);
|
||||
if (wItem >= lpMruMenu->wNbItemFill)
|
||||
return FALSE;
|
||||
_fstrncpy(lpItem,(lpMruMenu->lpMRU) +
|
||||
((lpMruMenu->wMaxSizeLruItem) * (UINT)(wItem)),uiSize);
|
||||
*(lpItem+uiSize-1) = '\0';
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//*************************************************************
|
||||
//
|
||||
// AddNewItem()
|
||||
//
|
||||
// Purpose:
|
||||
// Add an item at the begin of the list
|
||||
//
|
||||
// Parameters:
|
||||
// LPMRUMENU lpMruMenu - pointer on MRUMENU
|
||||
// LPSTR lpItem - String contain the filename to add
|
||||
//
|
||||
// Return: (BOOL)
|
||||
// TRUE - Function run successfully
|
||||
// FALSE - Function don't run successfully
|
||||
//
|
||||
//
|
||||
// Comments:
|
||||
// Used when used open a file (using File Open common
|
||||
// dialog, Drag and drop or MRU)
|
||||
//
|
||||
// History: Date Author Comment
|
||||
// 09/24/94 G. Vollant Created
|
||||
//
|
||||
//*************************************************************
|
||||
void AddNewItem (LPMRUMENU lpMruMenu,LPSTR lpItem)
|
||||
{
|
||||
WORD i,j;
|
||||
for (i=0;i<lpMruMenu->wNbItemFill;i++)
|
||||
if (lstrcmpi(lpItem,(lpMruMenu->lpMRU) +
|
||||
((lpMruMenu->wMaxSizeLruItem) * (UINT)i)) == 0)
|
||||
{
|
||||
// Shift the other items
|
||||
for (j=i;j>0;j--)
|
||||
lstrcpy((lpMruMenu->lpMRU) + (lpMruMenu->wMaxSizeLruItem * (UINT)j),
|
||||
(lpMruMenu->lpMRU) + (lpMruMenu->wMaxSizeLruItem * (UINT)(j-1)));
|
||||
_fstrncpy(lpMruMenu->lpMRU,lpItem,lpMruMenu->wMaxSizeLruItem-1);
|
||||
return ;
|
||||
}
|
||||
lpMruMenu->wNbItemFill = min(lpMruMenu->wNbItemFill+1,lpMruMenu->wNbLruMenu);
|
||||
for (i=lpMruMenu->wNbItemFill-1;i>0;i--)
|
||||
lstrcpy(lpMruMenu->lpMRU + (lpMruMenu->wMaxSizeLruItem * (UINT)i),
|
||||
lpMruMenu->lpMRU + (lpMruMenu->wMaxSizeLruItem * (UINT)(i-1)));
|
||||
_fstrncpy(lpMruMenu->lpMRU,lpItem,lpMruMenu->wMaxSizeLruItem-1);
|
||||
}
|
||||
|
||||
//*************************************************************
|
||||
//
|
||||
// DelMenuItem()
|
||||
//
|
||||
// Purpose:
|
||||
// Delete an item
|
||||
//
|
||||
// Parameters:
|
||||
// LPMRUMENU lpMruMenu - pointer on MRUMENU
|
||||
// WORD wItem - Number of Item to set, zero based
|
||||
// BOOL fIDMBased - TRUE : wItem is based on ID menu item
|
||||
// FALSE : wItem is zero-based
|
||||
//
|
||||
// Return: (BOOL)
|
||||
// TRUE - Function run successfully
|
||||
// FALSE - Function don't run successfully
|
||||
//
|
||||
//
|
||||
// Comments:
|
||||
// Used when used open a file, using MRU, and when an error
|
||||
// occured (by example, when file was deleted)
|
||||
//
|
||||
// History: Date Author Comment
|
||||
// 09/24/94 G. Vollant Created
|
||||
//
|
||||
//*************************************************************
|
||||
BOOL DelMenuItem(LPMRUMENU lpMruMenu,WORD wItem,BOOL fIDMBased)
|
||||
{
|
||||
WORD i;
|
||||
if (fIDMBased)
|
||||
wItem -= (lpMruMenu->wIdMru + 1);
|
||||
if (lpMruMenu->wNbItemFill <= wItem)
|
||||
return FALSE;
|
||||
lpMruMenu->wNbItemFill--;
|
||||
for (i=wItem;i<lpMruMenu->wNbItemFill;i++)
|
||||
lstrcpy(lpMruMenu->lpMRU + (lpMruMenu->wMaxSizeLruItem * (UINT)i),
|
||||
lpMruMenu->lpMRU + (lpMruMenu->wMaxSizeLruItem * (UINT)(i+1)));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//*************************************************************
|
||||
//
|
||||
// PlaceMenuMRUItem()
|
||||
//
|
||||
// Purpose:
|
||||
// Add MRU at the end of a menu
|
||||
//
|
||||
// Parameters:
|
||||
// LPMRUMENU lpMruMenu - pointer on MRUMENU
|
||||
// HMENU hMenu - Handle of menu where MRU must be added
|
||||
// UINT uiItem - Item of menu entry where MRU must be added
|
||||
//
|
||||
// Return: void
|
||||
//
|
||||
//
|
||||
// Comments:
|
||||
// Used MRU is modified, for refresh the File menu
|
||||
//
|
||||
// History: Date Author Comment
|
||||
// 09/24/94 G. Vollant Created
|
||||
//
|
||||
//*************************************************************
|
||||
void PlaceMenuMRUItem(LPMRUMENU lpMruMenu,HMENU hMenu,UINT uiItem)
|
||||
{
|
||||
int i;
|
||||
WORD wNbShow;
|
||||
if (hMenu == NULL)
|
||||
return;
|
||||
// remove old MRU in menu
|
||||
for (i=0;i<=(int)(lpMruMenu->wNbLruMenu);i++)
|
||||
RemoveMenu(hMenu,i+lpMruMenu->wIdMru,MF_BYCOMMAND);
|
||||
|
||||
if (lpMruMenu->wNbItemFill == 0)
|
||||
return;
|
||||
|
||||
// If they are item, insert a separator before the files
|
||||
InsertMenu(hMenu,uiItem,MF_SEPARATOR,lpMruMenu->wIdMru,NULL);
|
||||
|
||||
wNbShow = min(lpMruMenu->wNbItemFill,lpMruMenu->wNbLruShow);
|
||||
for (i=(int)wNbShow-1;i>=0;i--)
|
||||
{
|
||||
LPSTR lpTxt;
|
||||
if (lpTxt = (LPSTR)GlobalAllocPtr(GHND,lpMruMenu->wMaxSizeLruItem + 20))
|
||||
{
|
||||
wsprintf(lpTxt,"&%lu %s",
|
||||
(DWORD)(i+1),lpMruMenu->lpMRU + (lpMruMenu->wMaxSizeLruItem*(UINT)i));
|
||||
InsertMenu(hMenu,(((WORD)i)!=(wNbShow-1)) ? (lpMruMenu->wIdMru+i+2) : lpMruMenu->wIdMru,
|
||||
MF_STRING,lpMruMenu->wIdMru+i+1,lpTxt);
|
||||
GlobalFreePtr(lpTxt);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
//*************************************************************
|
||||
//
|
||||
// SaveMruInIni()
|
||||
//
|
||||
// Purpose:
|
||||
// Save MRU in a private .INI
|
||||
//
|
||||
// Parameters:
|
||||
// LPMRUMENU lpMruMenu - pointer on MRUMENU
|
||||
// LPSTR lpszSection - Points to a null-terminated string containing
|
||||
// the name of the section
|
||||
// LPSTR lpszFile - Points to a null-terminated string that names
|
||||
// the initialization file.
|
||||
//
|
||||
// Return: (BOOL)
|
||||
// TRUE - Function run successfully
|
||||
// FALSE - Function don't run successfully
|
||||
//
|
||||
//
|
||||
// Comments:
|
||||
// See WritePrivateProfileString API for more info on lpszSection and lpszFile
|
||||
//
|
||||
// History: Date Author Comment
|
||||
// 09/24/94 G. Vollant Created
|
||||
//
|
||||
//*************************************************************
|
||||
BOOL SaveMruInIni(LPMRUMENU lpMruMenu,LPSTR lpszSection,LPSTR lpszFile)
|
||||
{
|
||||
LPSTR lpTxt;
|
||||
WORD i;
|
||||
|
||||
lpTxt = (LPSTR)GlobalAllocPtr(GHND,lpMruMenu->wMaxSizeLruItem + 20);
|
||||
if (lpTxt == NULL)
|
||||
return FALSE;
|
||||
|
||||
for (i=0;i<lpMruMenu->wNbLruMenu;i++)
|
||||
{
|
||||
char szEntry[16];
|
||||
wsprintf(szEntry,"File%lu",(DWORD)i+1);
|
||||
if (!GetMenuItem(lpMruMenu,i,FALSE,lpTxt,lpMruMenu->wMaxSizeLruItem + 10))
|
||||
*lpTxt = '\0';
|
||||
WritePrivateProfileString(lpszSection,szEntry,lpTxt,lpszFile);
|
||||
}
|
||||
GlobalFreePtr(lpTxt);
|
||||
WritePrivateProfileString(NULL,NULL,NULL,lpszFile); // flush cache
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
//*************************************************************
|
||||
//
|
||||
// LoadMruInIni()
|
||||
//
|
||||
// Purpose:
|
||||
// Load MRU from a private .INI
|
||||
//
|
||||
// Parameters:
|
||||
// LPMRUMENU lpMruMenu - pointer on MRUMENU
|
||||
// LPSTR lpszSection - Points to a null-terminated string containing
|
||||
// the name of the section
|
||||
// LPSTR lpszFile - Points to a null-terminated string that names
|
||||
// the initialization file.
|
||||
//
|
||||
// Return: (BOOL)
|
||||
// TRUE - Function run successfully
|
||||
// FALSE - Function don't run successfully
|
||||
//
|
||||
//
|
||||
// Comments:
|
||||
// See GetPrivateProfileString API for more info on lpszSection and lpszFile
|
||||
//
|
||||
// History: Date Author Comment
|
||||
// 09/24/94 G. Vollant Created
|
||||
//
|
||||
//*************************************************************
|
||||
BOOL LoadMruInIni(LPMRUMENU lpMruMenu,LPSTR lpszSection,LPSTR lpszFile)
|
||||
{
|
||||
LPSTR lpTxt;
|
||||
WORD i;
|
||||
lpTxt = (LPSTR)GlobalAllocPtr(GHND,lpMruMenu->wMaxSizeLruItem + 20);
|
||||
if (lpTxt == NULL)
|
||||
return FALSE;
|
||||
|
||||
for (i=0;i<lpMruMenu->wNbLruMenu;i++)
|
||||
{
|
||||
char szEntry[16];
|
||||
|
||||
wsprintf(szEntry,"File%lu",(DWORD)i+1);
|
||||
GetPrivateProfileString(lpszSection,szEntry,"",lpTxt,
|
||||
lpMruMenu->wMaxSizeLruItem + 10,lpszFile);
|
||||
if (*lpTxt == '\0')
|
||||
break;
|
||||
SetMenuItem(lpMruMenu,i,lpTxt);
|
||||
}
|
||||
GlobalFreePtr(lpTxt);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
BOOL IsWin395OrHigher(void)
|
||||
{
|
||||
WORD wVer;
|
||||
|
||||
wVer = LOWORD(GetVersion());
|
||||
wVer = (((WORD)LOBYTE(wVer)) << 8) | (WORD)HIBYTE(wVer);
|
||||
|
||||
return (wVer >= 0x035F); // 5F = 95 dec
|
||||
}
|
||||
|
||||
|
||||
//*************************************************************
|
||||
//
|
||||
// SaveMruInReg()
|
||||
//
|
||||
// Purpose:
|
||||
// Save MRU in the registry
|
||||
//
|
||||
// Parameters:
|
||||
// LPMRUMENU lpMruMenu - pointer on MRUMENU
|
||||
// LPSTR lpszKey - Points to a null-terminated string
|
||||
// specifying the name of a key that
|
||||
// this function opens or creates.
|
||||
//
|
||||
// Return: (BOOL)
|
||||
// TRUE - Function run successfully
|
||||
// FALSE - Function don't run successfully
|
||||
//
|
||||
//
|
||||
// Comments:
|
||||
// Win32 function designed for Windows NT and Windows 95
|
||||
// See RegCreateKeyEx API for more info on lpszKey
|
||||
//
|
||||
// History: Date Author Comment
|
||||
// 09/24/94 G. Vollant Created
|
||||
//
|
||||
//*************************************************************
|
||||
BOOL SaveMruInReg(LPMRUMENU lpMruMenu,LPSTR lpszKey)
|
||||
{
|
||||
LPSTR lpTxt;
|
||||
WORD i;
|
||||
HKEY hCurKey;
|
||||
DWORD dwDisp;
|
||||
|
||||
lpTxt = (LPSTR)GlobalAllocPtr(GHND,lpMruMenu->wMaxSizeLruItem + 20);
|
||||
if (lpTxt == NULL)
|
||||
return FALSE;
|
||||
|
||||
RegCreateKeyEx(HKEY_CURRENT_USER,lpszKey,0,NULL,
|
||||
REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,&hCurKey,&dwDisp);
|
||||
|
||||
for (i=0;i<lpMruMenu->wNbLruMenu;i++)
|
||||
{
|
||||
char szEntry[16];
|
||||
wsprintf(szEntry,"File%lu",(DWORD)i+1);
|
||||
if (!GetMenuItem(lpMruMenu,i,FALSE,lpTxt,lpMruMenu->wMaxSizeLruItem + 10))
|
||||
*lpTxt = '\0';
|
||||
RegSetValueEx(hCurKey,szEntry,0,REG_SZ,lpTxt,lstrlen(lpTxt));
|
||||
}
|
||||
RegCloseKey(hCurKey);
|
||||
GlobalFreePtr(lpTxt);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//*************************************************************
|
||||
//
|
||||
// LoadMruInReg()
|
||||
//
|
||||
// Purpose:
|
||||
// Load MRU from the registry
|
||||
//
|
||||
// Parameters:
|
||||
// LPMRUMENU lpMruMenu - pointer on MRUMENU
|
||||
// LPSTR lpszKey - Points to a null-terminated string
|
||||
// specifying the name of a key that
|
||||
// this function opens or creates.
|
||||
//
|
||||
// Return: (BOOL)
|
||||
// TRUE - Function run successfully
|
||||
// FALSE - Function don't run successfully
|
||||
//
|
||||
//
|
||||
// Comments:
|
||||
// Win32 function designed for Windows NT and Windows 95
|
||||
// See RegOpenKeyEx API for more info on lpszKey
|
||||
//
|
||||
// History: Date Author Comment
|
||||
// 09/24/94 G. Vollant Created
|
||||
//
|
||||
//*************************************************************
|
||||
BOOL LoadMruInReg(LPMRUMENU lpMruMenu,LPSTR lpszKey)
|
||||
{
|
||||
LPSTR lpTxt;
|
||||
WORD i;
|
||||
HKEY hCurKey;
|
||||
DWORD dwType;
|
||||
lpTxt = (LPSTR)GlobalAllocPtr(GHND,lpMruMenu->wMaxSizeLruItem + 20);
|
||||
if (lpTxt == NULL)
|
||||
return FALSE;
|
||||
|
||||
RegOpenKeyEx(HKEY_CURRENT_USER,lpszKey,0,KEY_READ,&hCurKey);
|
||||
|
||||
|
||||
for (i=0;i<lpMruMenu->wNbLruMenu;i++)
|
||||
{
|
||||
char szEntry[16];
|
||||
DWORD dwSizeBuf;
|
||||
wsprintf(szEntry,"File%lu",(DWORD)i+1);
|
||||
*lpTxt = '\0';
|
||||
dwSizeBuf = lpMruMenu->wMaxSizeLruItem + 10;
|
||||
RegQueryValueEx(hCurKey,szEntry,NULL,&dwType,(LPBYTE)lpTxt,&dwSizeBuf);
|
||||
*(lpTxt+dwSizeBuf)='\0';
|
||||
if (*lpTxt == '\0')
|
||||
break;
|
||||
SetMenuItem(lpMruMenu,i,lpTxt);
|
||||
}
|
||||
RegCloseKey(hCurKey);
|
||||
GlobalFreePtr(lpTxt);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
//*************************************************************
|
||||
//
|
||||
// GetWin32Kind()
|
||||
//
|
||||
// Purpose:
|
||||
// Get the Win32 platform
|
||||
//
|
||||
// Parameters:
|
||||
//
|
||||
// Return: (WIN32KIND)
|
||||
// WINNT - Run under Windows NT
|
||||
// WIN32S - Run under Windows 3.1x + Win32s
|
||||
// WIN95ORGREATHER - Run under Windows 95
|
||||
//
|
||||
//
|
||||
// Comments:
|
||||
// Win32 function designed for Windows NT and Windows 95
|
||||
// See RegOpenKeyEx API for more info on lpszKey
|
||||
//
|
||||
// History: Date Author Comment
|
||||
// 09/24/94 G. Vollant Created
|
||||
//
|
||||
//*************************************************************
|
||||
WIN32KIND GetWin32Kind()
|
||||
{
|
||||
BOOL IsWin395OrHigher(void);
|
||||
|
||||
WORD wVer;
|
||||
|
||||
if ((GetVersion() & 0x80000000) == 0)
|
||||
return WINNT;
|
||||
wVer = LOWORD(GetVersion());
|
||||
wVer = (((WORD)LOBYTE(wVer)) << 8) | (WORD)HIBYTE(wVer);
|
||||
|
||||
if (wVer >= 0x035F)
|
||||
return WIN95ORGREATHER;
|
||||
else
|
||||
return WIN32S;
|
||||
}
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue