2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
26 ===========================================================================
29 #include "../idlib/precompiled.h"
34 GUIs and script remain separately parsed
36 Following a parse, all referenced media (and other decls) will have been touched.
38 sinTable and cosTable are required for the rotate material keyword to function
40 A new FindType on a purged decl will cause it to be reloaded, but a stale pointer to a purged
41 decl will look like a defaulted decl.
43 Moving a decl from one file to another will not be handled correctly by a reload, the material
46 NULL or empty decl names will always return NULL
47 Should probably make a default decl for this
49 Decls are initially created without a textSource
50 A parse without textSource set should always just call MakeDefault()
51 A parse that has an error should internally call MakeDefault()
52 A purge does nothing to a defaulted decl
54 Should we have a "purged" media state separate from the "defaulted" media state?
56 reloading over a decl name that was defaulted
58 reloading over a decl name that was valid
60 missing reload over a previously explicit definition
64 #define USE_COMPRESSED_DECLS
65 //#define GET_HUFFMAN_FREQUENCIES
71 idDecl * (*allocator)( void );
78 declType_t defaultType;
83 class idDeclLocal : public idDeclBase {
84 friend class idDeclFile;
85 friend class idDeclManagerLocal;
89 virtual ~idDeclLocal() {};
90 virtual const char * GetName( void ) const;
91 virtual declType_t GetType( void ) const;
92 virtual declState_t GetState( void ) const;
93 virtual bool IsImplicit( void ) const;
94 virtual bool IsValid( void ) const;
95 virtual void Invalidate( void );
96 virtual void Reload( void );
97 virtual void EnsureNotPurged( void );
98 virtual int Index( void ) const;
99 virtual int GetLineNum( void ) const;
100 virtual const char * GetFileName( void ) const;
101 virtual size_t Size( void ) const;
102 virtual void GetText( char *text ) const;
103 virtual int GetTextLength( void ) const;
104 virtual void SetText( const char *text );
105 virtual bool ReplaceSourceFileText( void );
106 virtual bool SourceFileChanged( void ) const;
107 virtual void MakeDefault( void );
108 virtual bool EverReferenced( void ) const;
111 virtual bool SetDefaultText( void );
112 virtual const char * DefaultDefinition( void ) const;
113 virtual bool Parse( const char *text, const int textLength );
114 virtual void FreeData( void );
115 virtual void List( void ) const;
116 virtual void Print( void ) const;
119 void AllocateSelf( void );
121 // Parses the decl definition.
122 // After calling parse, a decl will be guaranteed usable.
123 void ParseLocal( void );
125 // Does a MakeDefualt, but flags the decl so that it
126 // will Parse() the next time the decl is found.
129 // Set textSource possible with compression.
130 void SetTextLocal( const char *text, const int length );
135 idStr name; // name of the decl
136 char * textSource; // decl text definition
137 int textLength; // length of textSource
138 int compressedLength; // compressed length
139 idDeclFile * sourceFile; // source file in which the decl was defined
140 int sourceTextOffset; // offset in source file to decl text
141 int sourceTextLength; // length of decl text in source file
142 int sourceLine; // this is where the actual declaration token starts
143 int checksum; // checksum of the decl text
144 declType_t type; // decl type
145 declState_t declState; // decl state
146 int index; // index in the per-type list
148 bool parsedOutsideLevelLoad; // these decls will never be purged
149 bool everReferenced; // set to true if the decl was ever used
150 bool referencedThisLevel; // set to true when the decl is used for the current level
151 bool redefinedInReload; // used during file reloading to make sure a decl that has
152 // its source removed will be defaulted
153 idDeclLocal * nextInFile; // next decl in the decl file
159 idDeclFile( const char *fileName, declType_t defaultType );
161 void Reload( bool force );
166 declType_t defaultType;
176 class idDeclManagerLocal : public idDeclManager {
177 friend class idDeclLocal;
180 virtual void Init( void );
181 virtual void Shutdown( void );
182 virtual void Reload( bool force );
183 virtual void BeginLevelLoad();
184 virtual void EndLevelLoad();
185 virtual void RegisterDeclType( const char *typeName, declType_t type, idDecl *(*allocator)( void ) );
186 virtual void RegisterDeclFolder( const char *folder, const char *extension, declType_t defaultType );
187 virtual int GetChecksum( void ) const;
188 virtual int GetNumDeclTypes( void ) const;
189 virtual int GetNumDecls( declType_t type );
190 virtual const char * GetDeclNameFromType( declType_t type ) const;
191 virtual declType_t GetDeclTypeFromName( const char *typeName ) const;
192 virtual const idDecl * FindType( declType_t type, const char *name, bool makeDefault = true );
193 virtual const idDecl * DeclByIndex( declType_t type, int index, bool forceParse = true );
195 virtual const idDecl* FindDeclWithoutParsing( declType_t type, const char *name, bool makeDefault = true );
196 virtual void ReloadFile( const char* filename, bool force );
198 virtual void ListType( const idCmdArgs &args, declType_t type );
199 virtual void PrintType( const idCmdArgs &args, declType_t type );
201 virtual idDecl * CreateNewDecl( declType_t type, const char *name, const char *fileName );
203 //BSM Added for the material editors rename capabilities
204 virtual bool RenameDecl( declType_t type, const char* oldName, const char* newName );
206 virtual void MediaPrint( const char *fmt, ... ) id_attribute((format(printf,2,3)));
207 virtual void WritePrecacheCommands( idFile *f );
209 virtual const idMaterial * FindMaterial( const char *name, bool makeDefault = true );
210 virtual const idDeclSkin * FindSkin( const char *name, bool makeDefault = true );
211 virtual const idSoundShader * FindSound( const char *name, bool makeDefault = true );
213 virtual const idMaterial * MaterialByIndex( int index, bool forceParse = true );
214 virtual const idDeclSkin * SkinByIndex( int index, bool forceParse = true );
215 virtual const idSoundShader * SoundByIndex( int index, bool forceParse = true );
218 static void MakeNameCanonical( const char *name, char *result, int maxLength );
219 idDeclLocal * FindTypeWithoutParsing( declType_t type, const char *name, bool makeDefault = true );
221 idDeclType * GetDeclType( int type ) const { return declTypes[type]; }
222 const idDeclFile * GetImplicitDeclFile( void ) const { return &implicitDecls; }
225 idList<idDeclType *> declTypes;
226 idList<idDeclFolder *> declFolders;
228 idList<idDeclFile *> loadedFiles;
229 idHashIndex hashTables[DECL_MAX_TYPES];
230 idList<idDeclLocal *> linearLists[DECL_MAX_TYPES];
231 idDeclFile implicitDecls; // this holds all the decls that were created because explicit
232 // text definitions were not found. Decls that became default
233 // because of a parse error are not in this list.
234 int checksum; // checksum of all loaded decl text
235 int indent; // for MediaPrint
236 bool insideLevelLoad;
238 static idCVar decl_show;
241 static void ListDecls_f( const idCmdArgs &args );
242 static void ReloadDecls_f( const idCmdArgs &args );
243 static void TouchDecl_f( const idCmdArgs &args );
246 idCVar idDeclManagerLocal::decl_show( "decl_show", "0", CVAR_SYSTEM, "set to 1 to print parses, 2 to also print references", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> );
248 idDeclManagerLocal declManagerLocal;
249 idDeclManager * declManager = &declManagerLocal;
252 ====================================================================================
254 decl text huffman compression
256 ====================================================================================
259 const int MAX_HUFFMAN_SYMBOLS = 256;
261 typedef struct huffmanNode_s {
264 struct huffmanNode_s * next;
265 struct huffmanNode_s * children[2];
268 typedef struct huffmanCode_s {
269 unsigned long bits[8];
273 // compression ratio = 64%
274 static int huffmanFrequencies[] = {
275 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
276 0x00000001, 0x00078fb6, 0x000352a7, 0x00000002, 0x00000001, 0x0002795e, 0x00000001, 0x00000001,
277 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
278 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
279 0x00049600, 0x000000dd, 0x00018732, 0x0000005a, 0x00000007, 0x00000092, 0x0000000a, 0x00000919,
280 0x00002dcf, 0x00002dda, 0x00004dfc, 0x0000039a, 0x000058be, 0x00002d13, 0x00014d8c, 0x00023c60,
281 0x0002ddb0, 0x0000d1fc, 0x000078c4, 0x00003ec7, 0x00003113, 0x00006b59, 0x00002499, 0x0000184a,
282 0x0000250b, 0x00004e38, 0x000001ca, 0x00000011, 0x00000020, 0x000023da, 0x00000012, 0x00000091,
283 0x0000000b, 0x00000b14, 0x0000035d, 0x0000137e, 0x000020c9, 0x00000e11, 0x000004b4, 0x00000737,
284 0x000006b8, 0x00001110, 0x000006b3, 0x000000fe, 0x00000f02, 0x00000d73, 0x000005f6, 0x00000be4,
285 0x00000d86, 0x0000014d, 0x00000d89, 0x0000129b, 0x00000db3, 0x0000015a, 0x00000167, 0x00000375,
286 0x00000028, 0x00000112, 0x00000018, 0x00000678, 0x0000081a, 0x00000677, 0x00000003, 0x00018112,
287 0x00000001, 0x000441ee, 0x000124b0, 0x0001fa3f, 0x00026125, 0x0005a411, 0x0000e50f, 0x00011820,
288 0x00010f13, 0x0002e723, 0x00003518, 0x00005738, 0x0002cc26, 0x0002a9b7, 0x0002db81, 0x0003b5fa,
289 0x000185d2, 0x00001299, 0x00030773, 0x0003920d, 0x000411cd, 0x00018751, 0x00005fbd, 0x000099b0,
290 0x00009242, 0x00007cf2, 0x00002809, 0x00005a1d, 0x00000001, 0x00005a1d, 0x00000001, 0x00000001,
292 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
293 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
294 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
295 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
296 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
297 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
298 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
299 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
300 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
301 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
302 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
303 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
304 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
305 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
306 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
307 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
310 static huffmanCode_t huffmanCodes[MAX_HUFFMAN_SYMBOLS];
311 static huffmanNode_t *huffmanTree = NULL;
312 static int totalUncompressedLength = 0;
313 static int totalCompressedLength = 0;
314 static int maxHuffmanBits = 0;
319 ClearHuffmanFrequencies
322 void ClearHuffmanFrequencies( void ) {
325 for( i = 0; i < MAX_HUFFMAN_SYMBOLS; i++ ) {
326 huffmanFrequencies[i] = 1;
335 huffmanNode_t *InsertHuffmanNode( huffmanNode_t *firstNode, huffmanNode_t *node ) {
336 huffmanNode_t *n, *lastNode;
339 for ( n = firstNode; n; n = n->next ) {
340 if ( node->frequency <= n->frequency ) {
346 node->next = lastNode->next;
347 lastNode->next = node;
349 node->next = firstNode;
360 void BuildHuffmanCode_r( huffmanNode_t *node, huffmanCode_t code, huffmanCode_t codes[MAX_HUFFMAN_SYMBOLS] ) {
361 if ( node->symbol == -1 ) {
362 huffmanCode_t newCode = code;
363 assert( code.numBits < sizeof( codes[0].bits ) * 8 );
365 if ( code.numBits > maxHuffmanBits ) {
366 maxHuffmanBits = newCode.numBits;
368 BuildHuffmanCode_r( node->children[0], newCode, codes );
369 newCode.bits[code.numBits >> 5] |= 1 << ( code.numBits & 31 );
370 BuildHuffmanCode_r( node->children[1], newCode, codes );
372 assert( code.numBits <= sizeof( codes[0].bits ) * 8 );
373 codes[node->symbol] = code;
382 void FreeHuffmanTree_r( huffmanNode_t *node ) {
383 if ( node->symbol == -1 ) {
384 FreeHuffmanTree_r( node->children[0] );
385 FreeHuffmanTree_r( node->children[1] );
395 int HuffmanHeight_r( huffmanNode_t *node ) {
396 if ( node == NULL ) {
399 int left = HuffmanHeight_r( node->children[0] );
400 int right = HuffmanHeight_r( node->children[1] );
401 if ( left > right ) {
412 void SetupHuffman( void ) {
414 huffmanNode_t *firstNode, *node;
418 for( i = 0; i < MAX_HUFFMAN_SYMBOLS; i++ ) {
419 node = new huffmanNode_t;
421 node->frequency = huffmanFrequencies[i];
423 node->children[0] = NULL;
424 node->children[1] = NULL;
425 firstNode = InsertHuffmanNode( firstNode, node );
428 for( i = 1; i < MAX_HUFFMAN_SYMBOLS; i++ ) {
429 node = new huffmanNode_t;
431 node->frequency = firstNode->frequency + firstNode->next->frequency;
433 node->children[0] = firstNode;
434 node->children[1] = firstNode->next;
435 firstNode = InsertHuffmanNode( firstNode->next->next, node );
439 memset( &code, 0, sizeof( code ) );
440 BuildHuffmanCode_r( firstNode, code, huffmanCodes );
442 huffmanTree = firstNode;
444 height = HuffmanHeight_r( firstNode );
445 assert( maxHuffmanBits == height );
453 void ShutdownHuffman( void ) {
455 FreeHuffmanTree_r( huffmanTree );
464 int HuffmanCompressText( const char *text, int textLength, byte *compressed, int maxCompressedSize ) {
468 totalUncompressedLength += textLength;
470 msg.Init( compressed, maxCompressedSize );
472 for ( i = 0; i < textLength; i++ ) {
473 const huffmanCode_t &code = huffmanCodes[(unsigned char)text[i]];
474 for ( j = 0; j < ( code.numBits >> 5 ); j++ ) {
475 msg.WriteBits( code.bits[j], 32 );
477 if ( code.numBits & 31 ) {
478 msg.WriteBits( code.bits[j], code.numBits & 31 );
482 totalCompressedLength += msg.GetSize();
484 return msg.GetSize();
489 HuffmanDecompressText
492 int HuffmanDecompressText( char *text, int textLength, const byte *compressed, int compressedSize ) {
497 msg.Init( compressed, compressedSize );
498 msg.SetSize( compressedSize );
500 for ( i = 0; i < textLength; i++ ) {
503 bit = msg.ReadBits( 1 );
504 node = node->children[bit];
505 } while( node->symbol == -1 );
506 text[i] = node->symbol;
509 return msg.GetReadCount();
514 ListHuffmanFrequencies_f
517 void ListHuffmanFrequencies_f( const idCmdArgs &args ) {
520 compression = !totalUncompressedLength ? 100 : 100 * totalCompressedLength / totalUncompressedLength;
521 common->Printf( "// compression ratio = %d%%\n", (int)compression );
522 common->Printf( "static int huffmanFrequencies[] = {\n" );
523 for( i = 0; i < MAX_HUFFMAN_SYMBOLS; i += 8 ) {
524 common->Printf( "\t0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x,\n",
525 huffmanFrequencies[i+0], huffmanFrequencies[i+1],
526 huffmanFrequencies[i+2], huffmanFrequencies[i+3],
527 huffmanFrequencies[i+4], huffmanFrequencies[i+5],
528 huffmanFrequencies[i+6], huffmanFrequencies[i+7]);
530 common->Printf( "}\n" );
534 ====================================================================================
538 ====================================================================================
543 idDeclFile::idDeclFile
546 idDeclFile::idDeclFile( const char *fileName, declType_t defaultType ) {
547 this->fileName = fileName;
548 this->defaultType = defaultType;
558 idDeclFile::idDeclFile
561 idDeclFile::idDeclFile() {
562 this->fileName = "<implicit file>";
563 this->defaultType = DECL_MAX_TYPES;
575 ForceReload will cause it to reload even if the timestamp hasn't changed
578 void idDeclFile::Reload( bool force ) {
579 // check for an unchanged timestamp
580 if ( !force && timestamp != 0 ) {
581 ID_TIME_T testTimeStamp;
582 fileSystem->ReadFile( fileName, NULL, &testTimeStamp );
584 if ( testTimeStamp == timestamp ) {
595 idDeclFile::LoadAndParse
597 This is used during both the initial load, and any reloads
600 int c_savedMemory = 0;
602 int idDeclFile::LoadAndParse() {
611 idDeclLocal *newDecl;
615 common->DPrintf( "...loading '%s'\n", fileName.c_str() );
616 length = fileSystem->ReadFile( fileName, (void **)&buffer, ×tamp );
617 if ( length == -1 ) {
618 common->FatalError( "couldn't load %s", fileName.c_str() );
622 if ( !src.LoadMemory( buffer, length, fileName ) ) {
623 common->Error( "Couldn't parse %s", fileName.c_str() );
628 // mark all the defs that were from the last reload of this file
629 for ( idDeclLocal *decl = decls; decl; decl = decl->nextInFile ) {
630 decl->redefinedInReload = false;
633 src.SetFlags( DECL_LEXER_FLAGS );
635 checksum = MD5_BlockChecksum( buffer, length );
639 // scan through, identifying each individual declaration
642 startMarker = src.GetFileOffset();
643 sourceLine = src.GetLineNum();
645 // parse the decl type name
646 if ( !src.ReadToken( &token ) ) {
650 declType_t identifiedType = DECL_MAX_TYPES;
652 // get the decl type from the type name
653 numTypes = declManagerLocal.GetNumDeclTypes();
654 for ( i = 0; i < numTypes; i++ ) {
655 idDeclType *typeInfo = declManagerLocal.GetDeclType( i );
656 if ( typeInfo && typeInfo->typeName.Icmp( token ) == 0 ) {
657 identifiedType = (declType_t) typeInfo->type;
662 if ( i >= numTypes ) {
664 if ( token.Icmp( "{" ) == 0 ) {
666 // if we ever see an open brace, we somehow missed the [type] <name> prefix
667 src.Warning( "Missing decl name" );
668 src.SkipBracedSection( false );
673 if ( defaultType == DECL_MAX_TYPES ) {
674 src.Warning( "No type" );
677 src.UnreadToken( &token );
678 // use the default type
679 identifiedType = defaultType;
683 // now parse the name
684 if ( !src.ReadToken( &token ) ) {
685 src.Warning( "Type without definition at end of file" );
689 if ( !token.Icmp( "{" ) ) {
690 // if we ever see an open brace, we somehow missed the [type] <name> prefix
691 src.Warning( "Missing decl name" );
692 src.SkipBracedSection( false );
696 // FIXME: export decls are only used by the model exporter, they are skipped here for now
697 if ( identifiedType == DECL_MODELEXPORT ) {
698 src.SkipBracedSection();
704 // make sure there's a '{'
705 if ( !src.ReadToken( &token ) ) {
706 src.Warning( "Type without definition at end of file" );
709 if ( token != "{" ) {
710 src.Warning( "Expecting '{' but found '%s'", token.c_str() );
713 src.UnreadToken( &token );
715 // now take everything until a matched closing brace
716 src.SkipBracedSection();
717 size = src.GetFileOffset() - startMarker;
719 // look it up, possibly getting a newly created default decl
721 newDecl = declManagerLocal.FindTypeWithoutParsing( identifiedType, name, false );
723 // update the existing copy
724 if ( newDecl->sourceFile != this || newDecl->redefinedInReload ) {
725 src.Warning( "%s '%s' previously defined at %s:%i", declManagerLocal.GetDeclNameFromType( identifiedType ),
726 name.c_str(), newDecl->sourceFile->fileName.c_str(), newDecl->sourceLine );
729 if ( newDecl->declState != DS_UNPARSED ) {
733 // allow it to be created as a default, then add it to the per-file list
734 newDecl = declManagerLocal.FindTypeWithoutParsing( identifiedType, name, true );
735 newDecl->nextInFile = this->decls;
736 this->decls = newDecl;
739 newDecl->redefinedInReload = true;
741 if ( newDecl->textSource ) {
742 Mem_Free( newDecl->textSource );
743 newDecl->textSource = NULL;
746 newDecl->SetTextLocal( buffer + startMarker, size );
747 newDecl->sourceFile = this;
748 newDecl->sourceTextOffset = startMarker;
749 newDecl->sourceTextLength = size;
750 newDecl->sourceLine = sourceLine;
751 newDecl->declState = DS_UNPARSED;
753 // if it is currently in use, reparse it immedaitely
755 newDecl->ParseLocal();
759 numLines = src.GetLineNum();
763 // any defs that weren't redefinedInReload should now be defaulted
764 for ( idDeclLocal *decl = decls ; decl ; decl = decl->nextInFile ) {
765 if ( decl->redefinedInReload == false ) {
767 decl->sourceTextOffset = decl->sourceFile->fileSize;
768 decl->sourceTextLength = 0;
769 decl->sourceLine = decl->sourceFile->numLines;
777 ====================================================================================
781 ====================================================================================
784 const char *listDeclStrings[] = { "current", "all", "ever", NULL };
788 idDeclManagerLocal::Init
791 void idDeclManagerLocal::Init( void ) {
793 common->Printf( "----- Initializing Decls -----\n" );
797 #ifdef USE_COMPRESSED_DECLS
801 #ifdef GET_HUFFMAN_FREQUENCIES
802 ClearHuffmanFrequencies();
805 // decls used throughout the engine
806 RegisterDeclType( "table", DECL_TABLE, idDeclAllocator<idDeclTable> );
807 RegisterDeclType( "material", DECL_MATERIAL, idDeclAllocator<idMaterial> );
808 RegisterDeclType( "skin", DECL_SKIN, idDeclAllocator<idDeclSkin> );
809 RegisterDeclType( "sound", DECL_SOUND, idDeclAllocator<idSoundShader> );
811 RegisterDeclType( "entityDef", DECL_ENTITYDEF, idDeclAllocator<idDeclEntityDef> );
812 RegisterDeclType( "mapDef", DECL_MAPDEF, idDeclAllocator<idDeclEntityDef> );
813 RegisterDeclType( "fx", DECL_FX, idDeclAllocator<idDeclFX> );
814 RegisterDeclType( "particle", DECL_PARTICLE, idDeclAllocator<idDeclParticle> );
815 RegisterDeclType( "articulatedFigure", DECL_AF, idDeclAllocator<idDeclAF> );
816 RegisterDeclType( "pda", DECL_PDA, idDeclAllocator<idDeclPDA> );
817 RegisterDeclType( "email", DECL_EMAIL, idDeclAllocator<idDeclEmail> );
818 RegisterDeclType( "video", DECL_VIDEO, idDeclAllocator<idDeclVideo> );
819 RegisterDeclType( "audio", DECL_AUDIO, idDeclAllocator<idDeclAudio> );
821 RegisterDeclFolder( "materials", ".mtr", DECL_MATERIAL );
822 RegisterDeclFolder( "skins", ".skin", DECL_SKIN );
823 RegisterDeclFolder( "sound", ".sndshd", DECL_SOUND );
825 // add console commands
826 cmdSystem->AddCommand( "listDecls", ListDecls_f, CMD_FL_SYSTEM, "lists all decls" );
828 cmdSystem->AddCommand( "reloadDecls", ReloadDecls_f, CMD_FL_SYSTEM, "reloads decls" );
829 cmdSystem->AddCommand( "touch", TouchDecl_f, CMD_FL_SYSTEM, "touches a decl" );
831 cmdSystem->AddCommand( "listTables", idListDecls_f<DECL_TABLE>, CMD_FL_SYSTEM, "lists tables", idCmdSystem::ArgCompletion_String<listDeclStrings> );
832 cmdSystem->AddCommand( "listMaterials", idListDecls_f<DECL_MATERIAL>, CMD_FL_SYSTEM, "lists materials", idCmdSystem::ArgCompletion_String<listDeclStrings> );
833 cmdSystem->AddCommand( "listSkins", idListDecls_f<DECL_SKIN>, CMD_FL_SYSTEM, "lists skins", idCmdSystem::ArgCompletion_String<listDeclStrings> );
834 cmdSystem->AddCommand( "listSoundShaders", idListDecls_f<DECL_SOUND>, CMD_FL_SYSTEM, "lists sound shaders", idCmdSystem::ArgCompletion_String<listDeclStrings> );
836 cmdSystem->AddCommand( "listEntityDefs", idListDecls_f<DECL_ENTITYDEF>, CMD_FL_SYSTEM, "lists entity defs", idCmdSystem::ArgCompletion_String<listDeclStrings> );
837 cmdSystem->AddCommand( "listFX", idListDecls_f<DECL_FX>, CMD_FL_SYSTEM, "lists FX systems", idCmdSystem::ArgCompletion_String<listDeclStrings> );
838 cmdSystem->AddCommand( "listParticles", idListDecls_f<DECL_PARTICLE>, CMD_FL_SYSTEM, "lists particle systems", idCmdSystem::ArgCompletion_String<listDeclStrings> );
839 cmdSystem->AddCommand( "listAF", idListDecls_f<DECL_AF>, CMD_FL_SYSTEM, "lists articulated figures", idCmdSystem::ArgCompletion_String<listDeclStrings>);
841 cmdSystem->AddCommand( "listPDAs", idListDecls_f<DECL_PDA>, CMD_FL_SYSTEM, "lists PDAs", idCmdSystem::ArgCompletion_String<listDeclStrings> );
842 cmdSystem->AddCommand( "listEmails", idListDecls_f<DECL_EMAIL>, CMD_FL_SYSTEM, "lists Emails", idCmdSystem::ArgCompletion_String<listDeclStrings> );
843 cmdSystem->AddCommand( "listVideos", idListDecls_f<DECL_VIDEO>, CMD_FL_SYSTEM, "lists Videos", idCmdSystem::ArgCompletion_String<listDeclStrings> );
844 cmdSystem->AddCommand( "listAudios", idListDecls_f<DECL_AUDIO>, CMD_FL_SYSTEM, "lists Audios", idCmdSystem::ArgCompletion_String<listDeclStrings> );
846 cmdSystem->AddCommand( "printTable", idPrintDecls_f<DECL_TABLE>, CMD_FL_SYSTEM, "prints a table", idCmdSystem::ArgCompletion_Decl<DECL_TABLE> );
847 cmdSystem->AddCommand( "printMaterial", idPrintDecls_f<DECL_MATERIAL>, CMD_FL_SYSTEM, "prints a material", idCmdSystem::ArgCompletion_Decl<DECL_MATERIAL> );
848 cmdSystem->AddCommand( "printSkin", idPrintDecls_f<DECL_SKIN>, CMD_FL_SYSTEM, "prints a skin", idCmdSystem::ArgCompletion_Decl<DECL_SKIN> );
849 cmdSystem->AddCommand( "printSoundShader", idPrintDecls_f<DECL_SOUND>, CMD_FL_SYSTEM, "prints a sound shader", idCmdSystem::ArgCompletion_Decl<DECL_SOUND> );
851 cmdSystem->AddCommand( "printEntityDef", idPrintDecls_f<DECL_ENTITYDEF>, CMD_FL_SYSTEM, "prints an entity def", idCmdSystem::ArgCompletion_Decl<DECL_ENTITYDEF> );
852 cmdSystem->AddCommand( "printFX", idPrintDecls_f<DECL_FX>, CMD_FL_SYSTEM, "prints an FX system", idCmdSystem::ArgCompletion_Decl<DECL_FX> );
853 cmdSystem->AddCommand( "printParticle", idPrintDecls_f<DECL_PARTICLE>, CMD_FL_SYSTEM, "prints a particle system", idCmdSystem::ArgCompletion_Decl<DECL_PARTICLE> );
854 cmdSystem->AddCommand( "printAF", idPrintDecls_f<DECL_AF>, CMD_FL_SYSTEM, "prints an articulated figure", idCmdSystem::ArgCompletion_Decl<DECL_AF> );
856 cmdSystem->AddCommand( "printPDA", idPrintDecls_f<DECL_PDA>, CMD_FL_SYSTEM, "prints an PDA", idCmdSystem::ArgCompletion_Decl<DECL_PDA> );
857 cmdSystem->AddCommand( "printEmail", idPrintDecls_f<DECL_EMAIL>, CMD_FL_SYSTEM, "prints an Email", idCmdSystem::ArgCompletion_Decl<DECL_EMAIL> );
858 cmdSystem->AddCommand( "printVideo", idPrintDecls_f<DECL_VIDEO>, CMD_FL_SYSTEM, "prints a Audio", idCmdSystem::ArgCompletion_Decl<DECL_VIDEO> );
859 cmdSystem->AddCommand( "printAudio", idPrintDecls_f<DECL_AUDIO>, CMD_FL_SYSTEM, "prints an Video", idCmdSystem::ArgCompletion_Decl<DECL_AUDIO> );
861 cmdSystem->AddCommand( "listHuffmanFrequencies", ListHuffmanFrequencies_f, CMD_FL_SYSTEM, "lists decl text character frequencies" );
863 common->Printf( "------------------------------\n" );
868 idDeclManagerLocal::Shutdown
871 void idDeclManagerLocal::Shutdown( void ) {
876 for ( i = 0; i < DECL_MAX_TYPES; i++ ) {
877 for ( j = 0; j < linearLists[i].Num(); j++ ) {
878 decl = linearLists[i][j];
879 if ( decl->self != NULL ) {
880 decl->self->FreeData();
883 if ( decl->textSource ) {
884 Mem_Free( decl->textSource );
885 decl->textSource = NULL;
889 linearLists[i].Clear();
890 hashTables[i].Free();
894 loadedFiles.DeleteContents( true );
896 // free the decl types and folders
897 declTypes.DeleteContents( true );
898 declFolders.DeleteContents( true );
900 #ifdef USE_COMPRESSED_DECLS
907 idDeclManagerLocal::Reload
910 void idDeclManagerLocal::Reload( bool force ) {
911 for ( int i = 0; i < loadedFiles.Num(); i++ ) {
912 loadedFiles[i]->Reload( force );
918 idDeclManagerLocal::BeginLevelLoad
921 void idDeclManagerLocal::BeginLevelLoad() {
922 insideLevelLoad = true;
924 // clear all the referencedThisLevel flags and purge all the data
925 // so the next reference will cause a reparse
926 for ( int i = 0; i < DECL_MAX_TYPES; i++ ) {
927 int num = linearLists[i].Num();
928 for ( int j = 0 ; j < num ; j++ ) {
929 idDeclLocal *decl = linearLists[i][j];
937 idDeclManagerLocal::EndLevelLoad
940 void idDeclManagerLocal::EndLevelLoad() {
941 insideLevelLoad = false;
943 // we don't need to do anything here, but the image manager, model manager,
944 // and sound sample manager will need to free media that was not referenced
949 idDeclManagerLocal::RegisterDeclType
952 void idDeclManagerLocal::RegisterDeclType( const char *typeName, declType_t type, idDecl *(*allocator)( void ) ) {
953 idDeclType *declType;
955 if ( type < declTypes.Num() && declTypes[(int)type] ) {
956 common->Warning( "idDeclManager::RegisterDeclType: type '%s' already exists", typeName );
960 declType = new idDeclType;
961 declType->typeName = typeName;
962 declType->type = type;
963 declType->allocator = allocator;
965 if ( (int)type + 1 > declTypes.Num() ) {
966 declTypes.AssureSize( (int)type + 1, NULL );
968 declTypes[type] = declType;
973 idDeclManagerLocal::RegisterDeclFolder
976 void idDeclManagerLocal::RegisterDeclFolder( const char *folder, const char *extension, declType_t defaultType ) {
979 idDeclFolder *declFolder;
980 idFileList *fileList;
983 // check whether this folder / extension combination already exists
984 for ( i = 0; i < declFolders.Num(); i++ ) {
985 if ( declFolders[i]->folder.Icmp( folder ) == 0 && declFolders[i]->extension.Icmp( extension ) == 0 ) {
989 if ( i < declFolders.Num() ) {
990 declFolder = declFolders[i];
992 declFolder = new idDeclFolder;
993 declFolder->folder = folder;
994 declFolder->extension = extension;
995 declFolder->defaultType = defaultType;
996 declFolders.Append( declFolder );
999 // scan for decl files
1000 fileList = fileSystem->ListFiles( declFolder->folder, declFolder->extension, true );
1002 // load and parse decl files
1003 for ( i = 0; i < fileList->GetNumFiles(); i++ ) {
1004 fileName = declFolder->folder + "/" + fileList->GetFile( i );
1006 // check whether this file has already been loaded
1007 for ( j = 0; j < loadedFiles.Num(); j++ ) {
1008 if ( fileName.Icmp( loadedFiles[j]->fileName ) == 0 ) {
1012 if ( j < loadedFiles.Num() ) {
1013 df = loadedFiles[j];
1015 df = new idDeclFile( fileName, defaultType );
1016 loadedFiles.Append( df );
1021 fileSystem->FreeFileList( fileList );
1026 idDeclManagerLocal::GetChecksum
1029 int idDeclManagerLocal::GetChecksum( void ) const {
1030 int i, j, total, num;
1033 // get the total number of decls
1035 for ( i = 0; i < DECL_MAX_TYPES; i++ ) {
1036 total += linearLists[i].Num();
1039 checksumData = (int *) _alloca16( total * 2 * sizeof( int ) );
1042 for ( i = 0; i < DECL_MAX_TYPES; i++ ) {
1043 declType_t type = (declType_t) i;
1045 // FIXME: not particularly pretty but PDAs and associated decls are localized and should not be checksummed
1046 if ( type == DECL_PDA || type == DECL_VIDEO || type == DECL_AUDIO || type == DECL_EMAIL ) {
1050 num = linearLists[i].Num();
1051 for ( j = 0; j < num; j++ ) {
1052 idDeclLocal *decl = linearLists[i][j];
1054 if ( decl->sourceFile == &implicitDecls ) {
1058 checksumData[total*2+0] = total;
1059 checksumData[total*2+1] = decl->checksum;
1064 LittleRevBytes( checksumData, sizeof(int), total * 2 );
1065 return MD5_BlockChecksum( checksumData, total * 2 * sizeof( int ) );
1070 idDeclManagerLocal::GetNumDeclTypes
1073 int idDeclManagerLocal::GetNumDeclTypes( void ) const {
1074 return declTypes.Num();
1079 idDeclManagerLocal::GetDeclNameFromType
1082 const char * idDeclManagerLocal::GetDeclNameFromType( declType_t type ) const {
1083 int typeIndex = (int)type;
1085 if ( typeIndex < 0 || typeIndex >= declTypes.Num() || declTypes[typeIndex] == NULL ) {
1086 common->FatalError( "idDeclManager::GetDeclNameFromType: bad type: %i", typeIndex );
1088 return declTypes[typeIndex]->typeName;
1093 idDeclManagerLocal::GetDeclTypeFromName
1096 declType_t idDeclManagerLocal::GetDeclTypeFromName( const char *typeName ) const {
1099 for ( i = 0; i < declTypes.Num(); i++ ) {
1100 if ( declTypes[i] && declTypes[i]->typeName.Icmp( typeName ) == 0 ) {
1101 return (declType_t)declTypes[i]->type;
1104 return DECL_MAX_TYPES;
1109 idDeclManagerLocal::FindType
1111 External users will always cause the decl to be parsed before returning
1114 const idDecl *idDeclManagerLocal::FindType( declType_t type, const char *name, bool makeDefault ) {
1117 if ( !name || !name[0] ) {
1118 name = "_emptyName";
1119 //common->Warning( "idDeclManager::FindType: empty %s name", GetDeclType( (int)type )->typeName.c_str() );
1122 decl = FindTypeWithoutParsing( type, name, makeDefault );
1127 decl->AllocateSelf();
1129 // if it hasn't been parsed yet, parse it now
1130 if ( decl->declState == DS_UNPARSED ) {
1134 // mark it as referenced
1135 decl->referencedThisLevel = true;
1136 decl->everReferenced = true;
1137 if ( insideLevelLoad ) {
1138 decl->parsedOutsideLevelLoad = false;
1146 idDeclManagerLocal::FindDeclWithoutParsing
1149 const idDecl* idDeclManagerLocal::FindDeclWithoutParsing( declType_t type, const char *name, bool makeDefault) {
1151 decl = FindTypeWithoutParsing(type, name, makeDefault);
1160 idDeclManagerLocal::ReloadFile
1163 void idDeclManagerLocal::ReloadFile( const char* filename, bool force ) {
1164 for ( int i = 0; i < loadedFiles.Num(); i++ ) {
1165 if(!loadedFiles[i]->fileName.Icmp(filename)) {
1166 checksum ^= loadedFiles[i]->checksum;
1167 loadedFiles[i]->Reload( force );
1168 checksum ^= loadedFiles[i]->checksum;
1175 idDeclManagerLocal::GetNumDecls
1178 int idDeclManagerLocal::GetNumDecls( declType_t type ) {
1179 int typeIndex = (int)type;
1181 if ( typeIndex < 0 || typeIndex >= declTypes.Num() || declTypes[typeIndex] == NULL ) {
1182 common->FatalError( "idDeclManager::GetNumDecls: bad type: %i", typeIndex );
1184 return linearLists[ typeIndex ].Num();
1189 idDeclManagerLocal::DeclByIndex
1192 const idDecl *idDeclManagerLocal::DeclByIndex( declType_t type, int index, bool forceParse ) {
1193 int typeIndex = (int)type;
1195 if ( typeIndex < 0 || typeIndex >= declTypes.Num() || declTypes[typeIndex] == NULL ) {
1196 common->FatalError( "idDeclManager::DeclByIndex: bad type: %i", typeIndex );
1198 if ( index < 0 || index >= linearLists[ typeIndex ].Num() ) {
1199 common->Error( "idDeclManager::DeclByIndex: out of range" );
1201 idDeclLocal *decl = linearLists[ typeIndex ][ index ];
1203 decl->AllocateSelf();
1205 if ( forceParse && decl->declState == DS_UNPARSED ) {
1214 idDeclManagerLocal::ListType
1217 Lists decls currently referenced
1220 Lists decls that have been referenced at least once since app launched
1223 Lists every decl declared, even if it hasn't been referenced or parsed
1225 FIXME: alphabetized, wildcards?
1228 void idDeclManagerLocal::ListType( const idCmdArgs &args, declType_t type ) {
1231 if ( !idStr::Icmp( args.Argv( 1 ), "all" ) ) {
1236 if ( !idStr::Icmp( args.Argv( 1 ), "ever" ) ) {
1242 common->Printf( "--------------------\n" );
1244 int count = linearLists[ (int)type ].Num();
1245 for ( int i = 0 ; i < count ; i++ ) {
1246 idDeclLocal *decl = linearLists[ (int)type ][ i ];
1248 if ( !all && decl->declState == DS_UNPARSED ) {
1252 if ( !all && !ever && !decl->referencedThisLevel ) {
1256 if ( decl->referencedThisLevel ) {
1257 common->Printf( "*" );
1258 } else if ( decl->everReferenced ) {
1259 common->Printf( "." );
1261 common->Printf( " " );
1263 if ( decl->declState == DS_DEFAULTED ) {
1264 common->Printf( "D" );
1266 common->Printf( " " );
1268 common->Printf( "%4i: ", decl->index );
1270 if ( decl->declState == DS_UNPARSED ) {
1271 // doesn't have any type specific data yet
1272 common->Printf( "%s\n", decl->GetName() );
1278 common->Printf( "--------------------\n" );
1279 common->Printf( "%i of %i %s\n", printed, count, declTypes[type]->typeName.c_str() );
1284 idDeclManagerLocal::PrintType
1287 void idDeclManagerLocal::PrintType( const idCmdArgs &args, declType_t type ) {
1288 // individual decl types may use additional command parameters
1289 if ( args.Argc() < 2 ) {
1290 common->Printf( "USAGE: Print<decl type> <decl name> [type specific parms]\n" );
1294 // look it up, skipping the public path so it won't parse or reference
1295 idDeclLocal *decl = FindTypeWithoutParsing( type, args.Argv( 1 ), false );
1297 common->Printf( "%s '%s' not found.\n", declTypes[ type ]->typeName.c_str(), args.Argv( 1 ) );
1301 // print information common to all decls
1302 common->Printf( "%s %s:\n", declTypes[ type ]->typeName.c_str(), decl->name.c_str() );
1303 common->Printf( "source: %s:%i\n", decl->sourceFile->fileName.c_str(), decl->sourceLine );
1304 common->Printf( "----------\n" );
1305 if ( decl->textSource != NULL ) {
1306 char *declText = (char *)_alloca( decl->textLength + 1 );
1307 decl->GetText( declText );
1308 common->Printf( "%s\n", declText );
1310 common->Printf( "NO SOURCE\n" );
1312 common->Printf( "----------\n" );
1313 switch( decl->declState ) {
1315 common->Printf( "Unparsed.\n" );
1318 common->Printf( "<DEFAULTED>\n" );
1321 common->Printf( "Parsed.\n" );
1325 if ( decl->referencedThisLevel ) {
1326 common->Printf( "Currently referenced this level.\n" );
1327 } else if ( decl->everReferenced ) {
1328 common->Printf( "Referenced in a previous level.\n" );
1330 common->Printf( "Never referenced.\n" );
1333 // allow type-specific data to be printed
1334 if ( decl->self != NULL ) {
1335 decl->self->Print();
1341 idDeclManagerLocal::CreateNewDecl
1344 idDecl *idDeclManagerLocal::CreateNewDecl( declType_t type, const char *name, const char *_fileName ) {
1345 int typeIndex = (int)type;
1348 if ( typeIndex < 0 || typeIndex >= declTypes.Num() || declTypes[typeIndex] == NULL ) {
1349 common->FatalError( "idDeclManager::CreateNewDecl: bad type: %i", typeIndex );
1352 char canonicalName[MAX_STRING_CHARS];
1354 MakeNameCanonical( name, canonicalName, sizeof( canonicalName ) );
1356 idStr fileName = _fileName;
1357 fileName.BackSlashesToSlashes();
1359 // see if it already exists
1360 hash = hashTables[typeIndex].GenerateKey( canonicalName, false );
1361 for ( i = hashTables[typeIndex].First( hash ); i >= 0; i = hashTables[typeIndex].Next( i ) ) {
1362 if ( linearLists[typeIndex][i]->name.Icmp( canonicalName ) == 0 ) {
1363 linearLists[typeIndex][i]->AllocateSelf();
1364 return linearLists[typeIndex][i]->self;
1368 idDeclFile *sourceFile;
1370 // find existing source file or create a new one
1371 for ( i = 0; i < loadedFiles.Num(); i++ ) {
1372 if ( loadedFiles[i]->fileName.Icmp( fileName ) == 0 ) {
1376 if ( i < loadedFiles.Num() ) {
1377 sourceFile = loadedFiles[i];
1379 sourceFile = new idDeclFile( fileName, type );
1380 loadedFiles.Append( sourceFile );
1383 idDeclLocal *decl = new idDeclLocal;
1384 decl->name = canonicalName;
1386 decl->declState = DS_UNPARSED;
1387 decl->AllocateSelf();
1388 idStr header = declTypes[typeIndex]->typeName;
1389 idStr defaultText = decl->self->DefaultDefinition();
1392 int size = header.Length() + 1 + idStr::Length( canonicalName ) + 1 + defaultText.Length();
1393 char *declText = ( char * ) _alloca( size + 1 );
1395 memcpy( declText, header, header.Length() );
1396 declText[header.Length()] = ' ';
1397 memcpy( declText + header.Length() + 1, canonicalName, idStr::Length( canonicalName ) );
1398 declText[header.Length() + 1 + idStr::Length( canonicalName )] = ' ';
1399 memcpy( declText + header.Length() + 1 + idStr::Length( canonicalName ) + 1, defaultText, defaultText.Length() + 1 );
1401 decl->SetTextLocal( declText, size );
1402 decl->sourceFile = sourceFile;
1403 decl->sourceTextOffset = sourceFile->fileSize;
1404 decl->sourceTextLength = 0;
1405 decl->sourceLine = sourceFile->numLines;
1409 // add this decl to the source file list
1410 decl->nextInFile = sourceFile->decls;
1411 sourceFile->decls = decl;
1413 // add it to the hash table and linear list
1414 decl->index = linearLists[typeIndex].Num();
1415 hashTables[typeIndex].Add( hash, linearLists[typeIndex].Append( decl ) );
1422 idDeclManagerLocal::RenameDecl
1425 bool idDeclManagerLocal::RenameDecl( declType_t type, const char* oldName, const char* newName ) {
1427 char canonicalOldName[MAX_STRING_CHARS];
1428 MakeNameCanonical( oldName, canonicalOldName, sizeof( canonicalOldName ));
1430 char canonicalNewName[MAX_STRING_CHARS];
1431 MakeNameCanonical( newName, canonicalNewName, sizeof( canonicalNewName ) );
1433 idDeclLocal *decl = NULL;
1435 // make sure it already exists
1436 int typeIndex = (int)type;
1438 hash = hashTables[typeIndex].GenerateKey( canonicalOldName, false );
1439 for ( i = hashTables[typeIndex].First( hash ); i >= 0; i = hashTables[typeIndex].Next( i ) ) {
1440 if ( linearLists[typeIndex][i]->name.Icmp( canonicalOldName ) == 0 ) {
1441 decl = linearLists[typeIndex][i];
1448 //if ( !hashTables[(int)type].Get( canonicalOldName, &declPtr ) )
1454 decl->name = canonicalNewName;
1457 // add it to the hash table
1458 //hashTables[(int)decl->type].Set( decl->name, decl );
1459 int newhash = hashTables[typeIndex].GenerateKey( canonicalNewName, false );
1460 hashTables[typeIndex].Add( newhash, decl->index );
1462 //Remove the old hash item
1463 hashTables[typeIndex].Remove(hash, decl->index);
1470 idDeclManagerLocal::MediaPrint
1472 This is just used to nicely indent media caching prints
1475 void idDeclManagerLocal::MediaPrint( const char *fmt, ... ) {
1476 if ( !decl_show.GetInteger() ) {
1479 for ( int i = 0 ; i < indent ; i++ ) {
1480 common->Printf( " " );
1484 va_start (argptr,fmt);
1485 idStr::vsnPrintf( buffer, sizeof(buffer), fmt, argptr );
1487 buffer[sizeof(buffer)-1] = '\0';
1489 common->Printf( "%s", buffer );
1494 idDeclManagerLocal::WritePrecacheCommands
1497 void idDeclManagerLocal::WritePrecacheCommands( idFile *f ) {
1498 for ( int i = 0; i < declTypes.Num(); i++ ) {
1501 if ( declTypes[i] == NULL ) {
1505 num = linearLists[i].Num();
1507 for ( int j = 0 ; j < num ; j++ ) {
1508 idDeclLocal *decl = linearLists[i][j];
1510 if ( !decl->referencedThisLevel ) {
1515 sprintf( str, "touch %s %s\n", declTypes[i]->typeName.c_str(), decl->GetName() );
1516 common->Printf( "%s", str );
1517 f->Printf( "%s", str );
1522 /********************************************************************/
1524 const idMaterial *idDeclManagerLocal::FindMaterial( const char *name, bool makeDefault ) {
1525 return static_cast<const idMaterial *>( FindType( DECL_MATERIAL, name, makeDefault ) );
1528 const idMaterial *idDeclManagerLocal::MaterialByIndex( int index, bool forceParse ) {
1529 return static_cast<const idMaterial *>( DeclByIndex( DECL_MATERIAL, index, forceParse ) );
1532 /********************************************************************/
1534 const idDeclSkin *idDeclManagerLocal::FindSkin( const char *name, bool makeDefault ) {
1535 return static_cast<const idDeclSkin *>( FindType( DECL_SKIN, name, makeDefault ) );
1538 const idDeclSkin *idDeclManagerLocal::SkinByIndex( int index, bool forceParse ) {
1539 return static_cast<const idDeclSkin *>( DeclByIndex( DECL_SKIN, index, forceParse ) );
1542 /********************************************************************/
1544 const idSoundShader *idDeclManagerLocal::FindSound( const char *name, bool makeDefault ) {
1545 return static_cast<const idSoundShader *>( FindType( DECL_SOUND, name, makeDefault ) );
1548 const idSoundShader *idDeclManagerLocal::SoundByIndex( int index, bool forceParse ) {
1549 return static_cast<const idSoundShader *>( DeclByIndex( DECL_SOUND, index, forceParse ) );
1554 idDeclManagerLocal::MakeNameCanonical
1557 void idDeclManagerLocal::MakeNameCanonical( const char *name, char *result, int maxLength ) {
1561 for ( i = 0; i < maxLength && name[i] != '\0'; i++ ) {
1565 } else if ( c == '.' ) {
1569 result[i] = idStr::ToLower( c );
1572 if ( lastDot != -1 ) {
1573 result[lastDot] = '\0';
1581 idDeclManagerLocal::ListDecls_f
1584 void idDeclManagerLocal::ListDecls_f( const idCmdArgs &args ) {
1588 int totalStructs = 0;
1590 for ( i = 0; i < declManagerLocal.declTypes.Num(); i++ ) {
1593 if ( declManagerLocal.declTypes[i] == NULL ) {
1597 num = declManagerLocal.linearLists[i].Num();
1601 for ( j = 0; j < num; j++ ) {
1602 size += declManagerLocal.linearLists[i][j]->Size();
1603 if ( declManagerLocal.linearLists[i][j]->self != NULL ) {
1604 size += declManagerLocal.linearLists[i][j]->self->Size();
1607 totalStructs += size;
1609 common->Printf( "%4ik %4i %s\n", size >> 10, num, declManagerLocal.declTypes[i]->typeName.c_str() );
1612 for ( i = 0 ; i < declManagerLocal.loadedFiles.Num() ; i++ ) {
1613 idDeclFile *df = declManagerLocal.loadedFiles[i];
1614 totalText += df->fileSize;
1617 common->Printf( "%i total decls is %i decl files\n", totalDecls, declManagerLocal.loadedFiles.Num() );
1618 common->Printf( "%iKB in text, %iKB in structures\n", totalText >> 10, totalStructs >> 10 );
1623 idDeclManagerLocal::ReloadDecls_f
1625 Reload will not find any new files created in the directories, it
1626 will only reload existing files.
1628 A reload will never cause anything to be purged.
1631 void idDeclManagerLocal::ReloadDecls_f( const idCmdArgs &args ) {
1634 if ( !idStr::Icmp( args.Argv( 1 ), "all" ) ) {
1636 common->Printf( "reloading all decl files:\n" );
1639 common->Printf( "reloading changed decl files:\n" );
1642 soundSystem->SetMute( true );
1644 declManagerLocal.Reload( force );
1646 soundSystem->SetMute( false );
1651 idDeclManagerLocal::TouchDecl_f
1654 void idDeclManagerLocal::TouchDecl_f( const idCmdArgs &args ) {
1657 if ( args.Argc() != 3 ) {
1658 common->Printf( "usage: touch <type> <name>\n" );
1659 common->Printf( "valid types: " );
1660 for ( int i = 0 ; i < declManagerLocal.declTypes.Num() ; i++ ) {
1661 if ( declManagerLocal.declTypes[i] ) {
1662 common->Printf( "%s ", declManagerLocal.declTypes[i]->typeName.c_str() );
1665 common->Printf( "\n" );
1669 for ( i = 0; i < declManagerLocal.declTypes.Num(); i++ ) {
1670 if ( declManagerLocal.declTypes[i] && declManagerLocal.declTypes[i]->typeName.Icmp( args.Argv( 1 ) ) == 0 ) {
1674 if ( i >= declManagerLocal.declTypes.Num() ) {
1675 common->Printf( "unknown decl type '%s'\n", args.Argv( 1 ) );
1679 const idDecl *decl = declManagerLocal.FindType( (declType_t)i, args.Argv( 2 ), false );
1681 common->Printf( "%s '%s' not found\n", declManagerLocal.declTypes[i]->typeName.c_str(), args.Argv( 2 ) );
1687 idDeclManagerLocal::FindTypeWithoutParsing
1689 This finds or creats the decl, but does not cause a parse. This is only used internally.
1692 idDeclLocal *idDeclManagerLocal::FindTypeWithoutParsing( declType_t type, const char *name, bool makeDefault ) {
1693 int typeIndex = (int)type;
1696 if ( typeIndex < 0 || typeIndex >= declTypes.Num() || declTypes[typeIndex] == NULL ) {
1697 common->FatalError( "idDeclManager::FindTypeWithoutParsing: bad type: %i", typeIndex );
1700 char canonicalName[MAX_STRING_CHARS];
1702 MakeNameCanonical( name, canonicalName, sizeof( canonicalName ) );
1704 // see if it already exists
1705 hash = hashTables[typeIndex].GenerateKey( canonicalName, false );
1706 for ( i = hashTables[typeIndex].First( hash ); i >= 0; i = hashTables[typeIndex].Next( i ) ) {
1707 if ( linearLists[typeIndex][i]->name.Icmp( canonicalName ) == 0 ) {
1708 // only print these when decl_show is set to 2, because it can be a lot of clutter
1709 if ( decl_show.GetInteger() > 1 ) {
1710 MediaPrint( "referencing %s %s\n", declTypes[ type ]->typeName.c_str(), name );
1712 return linearLists[typeIndex][i];
1716 if ( !makeDefault ) {
1720 idDeclLocal *decl = new idDeclLocal;
1722 decl->name = canonicalName;
1724 decl->declState = DS_UNPARSED;
1725 decl->textSource = NULL;
1726 decl->textLength = 0;
1727 decl->sourceFile = &implicitDecls;
1728 decl->referencedThisLevel = false;
1729 decl->everReferenced = false;
1730 decl->parsedOutsideLevelLoad = !insideLevelLoad;
1732 // add it to the linear list and hash table
1733 decl->index = linearLists[typeIndex].Num();
1734 hashTables[typeIndex].Add( hash, linearLists[typeIndex].Append( decl ) );
1741 ====================================================================================
1745 ====================================================================================
1750 idDeclLocal::idDeclLocal
1753 idDeclLocal::idDeclLocal( void ) {
1757 compressedLength = 0;
1759 sourceTextOffset = 0;
1760 sourceTextLength = 0;
1763 type = DECL_ENTITYDEF;
1765 declState = DS_UNPARSED;
1766 parsedOutsideLevelLoad = false;
1767 referencedThisLevel = false;
1768 everReferenced = false;
1769 redefinedInReload = false;
1775 idDeclLocal::GetName
1778 const char *idDeclLocal::GetName( void ) const {
1779 return name.c_str();
1784 idDeclLocal::GetType
1787 declType_t idDeclLocal::GetType( void ) const {
1793 idDeclLocal::GetState
1796 declState_t idDeclLocal::GetState( void ) const {
1802 idDeclLocal::IsImplicit
1805 bool idDeclLocal::IsImplicit( void ) const {
1806 return ( sourceFile == declManagerLocal.GetImplicitDeclFile() );
1811 idDeclLocal::IsValid
1814 bool idDeclLocal::IsValid( void ) const {
1815 return ( declState != DS_UNPARSED );
1820 idDeclLocal::Invalidate
1823 void idDeclLocal::Invalidate( void ) {
1824 declState = DS_UNPARSED;
1829 idDeclLocal::EnsureNotPurged
1832 void idDeclLocal::EnsureNotPurged( void ) {
1833 if ( declState == DS_UNPARSED ) {
1843 int idDeclLocal::Index( void ) const {
1849 idDeclLocal::GetLineNum
1852 int idDeclLocal::GetLineNum( void ) const {
1858 idDeclLocal::GetFileName
1861 const char *idDeclLocal::GetFileName( void ) const {
1862 return ( sourceFile ) ? sourceFile->fileName.c_str() : "*invalid*";
1870 size_t idDeclLocal::Size( void ) const {
1871 return sizeof( idDecl ) + name.Allocated();
1876 idDeclLocal::GetText
1879 void idDeclLocal::GetText( char *text ) const {
1880 #ifdef USE_COMPRESSED_DECLS
1881 HuffmanDecompressText( text, textLength, (byte *)textSource, compressedLength );
1883 memcpy( text, textSource, textLength+1 );
1889 idDeclLocal::GetTextLength
1892 int idDeclLocal::GetTextLength( void ) const {
1898 idDeclLocal::SetText
1901 void idDeclLocal::SetText( const char *text ) {
1902 SetTextLocal( text, idStr::Length( text ) );
1907 idDeclLocal::SetTextLocal
1910 void idDeclLocal::SetTextLocal( const char *text, const int length ) {
1912 Mem_Free( textSource );
1914 checksum = MD5_BlockChecksum( text, length );
1916 #ifdef GET_HUFFMAN_FREQUENCIES
1917 for( int i = 0; i < length; i++ ) {
1918 huffmanFrequencies[((const unsigned char *)text)[i]]++;
1922 #ifdef USE_COMPRESSED_DECLS
1923 int maxBytesPerCode = ( maxHuffmanBits + 7 ) >> 3;
1924 byte *compressed = (byte *)_alloca( length * maxBytesPerCode );
1925 compressedLength = HuffmanCompressText( text, length, compressed, length * maxBytesPerCode );
1926 textSource = (char *)Mem_Alloc( compressedLength );
1927 memcpy( textSource, compressed, compressedLength );
1929 compressedLength = length;
1930 textSource = (char *) Mem_Alloc( length + 1 );
1931 memcpy( textSource, text, length );
1932 textSource[length] = '\0';
1934 textLength = length;
1939 idDeclLocal::ReplaceSourceFileText
1942 bool idDeclLocal::ReplaceSourceFileText( void ) {
1943 int oldFileLength, newFileLength;
1947 common->Printf( "Writing \'%s\' to \'%s\'...\n", GetName(), GetFileName() );
1949 if ( sourceFile == &declManagerLocal.implicitDecls ) {
1950 common->Warning( "Can't save implicit declaration %s.", GetName() );
1954 // get length and allocate buffer to hold the file
1955 oldFileLength = sourceFile->fileSize;
1956 newFileLength = oldFileLength - sourceTextLength + textLength;
1957 buffer = (char *) Mem_Alloc( Max( newFileLength, oldFileLength ) );
1959 // read original file
1960 if ( sourceFile->fileSize ) {
1962 file = fileSystem->OpenFileRead( GetFileName() );
1965 common->Warning( "Couldn't open %s for reading.", GetFileName() );
1969 if ( file->Length() != sourceFile->fileSize || file->Timestamp() != sourceFile->timestamp ) {
1971 common->Warning( "The file %s has been modified outside of the engine.", GetFileName() );
1975 file->Read( buffer, oldFileLength );
1976 fileSystem->CloseFile( file );
1978 if ( MD5_BlockChecksum( buffer, oldFileLength ) != sourceFile->checksum ) {
1980 common->Warning( "The file %s has been modified outside of the engine.", GetFileName() );
1986 char *declText = (char *) _alloca( textLength + 1 );
1987 GetText( declText );
1988 memmove( buffer + sourceTextOffset + textLength, buffer + sourceTextOffset + sourceTextLength, oldFileLength - sourceTextOffset - sourceTextLength );
1989 memcpy( buffer + sourceTextOffset, declText, textLength );
1991 // write out new file
1992 file = fileSystem->OpenFileWrite( GetFileName(), "fs_devpath" );
1995 common->Warning( "Couldn't open %s for writing.", GetFileName() );
1998 file->Write( buffer, newFileLength );
1999 fileSystem->CloseFile( file );
2001 // set new file size, checksum and timestamp
2002 sourceFile->fileSize = newFileLength;
2003 sourceFile->checksum = MD5_BlockChecksum( buffer, newFileLength );
2004 fileSystem->ReadFile( GetFileName(), NULL, &sourceFile->timestamp );
2009 // move all decls in the same file
2010 for ( idDeclLocal *decl = sourceFile->decls; decl; decl = decl->nextInFile ) {
2011 if (decl->sourceTextOffset > sourceTextOffset) {
2012 decl->sourceTextOffset += textLength - sourceTextLength;
2016 // set new size of text in source file
2017 sourceTextLength = textLength;
2024 idDeclLocal::SourceFileChanged
2027 bool idDeclLocal::SourceFileChanged( void ) const {
2029 ID_TIME_T newTimestamp;
2031 if ( sourceFile->fileSize <= 0 ) {
2035 newLength = fileSystem->ReadFile( GetFileName(), NULL, &newTimestamp );
2037 if ( newLength != sourceFile->fileSize || newTimestamp != sourceFile->timestamp ) {
2046 idDeclLocal::MakeDefault
2049 void idDeclLocal::MakeDefault() {
2050 static int recursionLevel;
2051 const char *defaultText;
2053 declManagerLocal.MediaPrint( "DEFAULTED\n" );
2054 declState = DS_DEFAULTED;
2058 defaultText = self->DefaultDefinition();
2060 // a parse error inside a DefaultDefinition() string could
2061 // cause an infinite loop, but normal default definitions could
2062 // still reference other default definitions, so we can't
2063 // just dump out on the first recursion
2064 if ( ++recursionLevel > 100 ) {
2065 common->FatalError( "idDecl::MakeDefault: bad DefaultDefinition(): %s", defaultText );
2068 // always free data before parsing
2072 self->Parse( defaultText, strlen( defaultText ) );
2074 // we could still eventually hit the recursion if we have enough Error() calls inside Parse...
2080 idDeclLocal::SetDefaultText
2083 bool idDeclLocal::SetDefaultText( void ) {
2089 idDeclLocal::DefaultDefinition
2092 const char *idDeclLocal::DefaultDefinition() const {
2101 bool idDeclLocal::Parse( const char *text, const int textLength ) {
2104 src.LoadMemory( text, textLength, GetFileName(), GetLineNum() );
2105 src.SetFlags( DECL_LEXER_FLAGS );
2106 src.SkipUntilString( "{" );
2107 src.SkipBracedSection( false );
2113 idDeclLocal::FreeData
2116 void idDeclLocal::FreeData() {
2124 void idDeclLocal::List() const {
2125 common->Printf( "%s\n", GetName() );
2133 void idDeclLocal::Print() const {
2141 void idDeclLocal::Reload( void ) {
2142 this->sourceFile->Reload( false );
2147 idDeclLocal::AllocateSelf
2150 void idDeclLocal::AllocateSelf( void ) {
2151 if ( self == NULL ) {
2152 self = declManagerLocal.GetDeclType( (int)type )->allocator();
2159 idDeclLocal::ParseLocal
2162 void idDeclLocal::ParseLocal( void ) {
2163 bool generatedDefaultText = false;
2167 // always free data before parsing
2170 declManagerLocal.MediaPrint( "parsing %s %s\n", declManagerLocal.declTypes[type]->typeName.c_str(), name.c_str() );
2172 // if no text source try to generate default text
2173 if ( textSource == NULL ) {
2174 generatedDefaultText = self->SetDefaultText();
2177 // indent for DEFAULTED or media file references
2178 declManagerLocal.indent++;
2180 // no text immediately causes a MakeDefault()
2181 if ( textSource == NULL ) {
2183 declManagerLocal.indent--;
2187 declState = DS_PARSED;
2190 char *declText = (char *) _alloca( ( GetTextLength() + 1 ) * sizeof( char ) );
2191 GetText( declText );
2192 self->Parse( declText, GetTextLength() );
2194 // free generated text
2195 if ( generatedDefaultText ) {
2196 Mem_Free( textSource );
2201 declManagerLocal.indent--;
2209 void idDeclLocal::Purge( void ) {
2210 // never purge things that were referenced outside level load,
2211 // like the console and menu graphics
2212 if ( parsedOutsideLevelLoad ) {
2216 referencedThisLevel = false;
2219 // the next Find() for this will re-parse the real data
2220 declState = DS_UNPARSED;
2225 idDeclLocal::EverReferenced
2228 bool idDeclLocal::EverReferenced( void ) const {
2229 return everReferenced;