diff --git a/doomsday/libdoomsday/include/doomsday/defs/dedfile.h b/doomsday/libdoomsday/include/doomsday/defs/dedfile.h index 37b1947bab..5032bfebd6 100644 --- a/doomsday/libdoomsday/include/doomsday/defs/dedfile.h +++ b/doomsday/libdoomsday/include/doomsday/defs/dedfile.h @@ -31,9 +31,20 @@ LIBDOOMSDAY_PUBLIC void Def_ReadProcessDED(ded_t *defs, char const* path); */ LIBDOOMSDAY_PUBLIC int DED_ReadLump(ded_t* ded, lumpnum_t lumpNum); +/** + * Reads definitions from the given buffer. + * The definition is being loaded from @a _sourcefile (DED or WAD). + * + * @param buffer The data to be read, must be null-terminated. + * @param _sourceFile Just FYI. + */ +int DED_ReadData(ded_t* ded, const char* buffer, const char* _sourceFile); + /** * @return @c true, if the file was successfully loaded. */ int DED_Read(ded_t* ded, const char* path); +void DED_SetError(char const *str); + #endif // LIBDOOMSDAY_DEFS_DED_H diff --git a/doomsday/libdoomsday/include/doomsday/defs/dedparser.h b/doomsday/libdoomsday/include/doomsday/defs/dedparser.h index 1e04e7f030..b161f83dbd 100644 --- a/doomsday/libdoomsday/include/doomsday/defs/dedparser.h +++ b/doomsday/libdoomsday/include/doomsday/defs/dedparser.h @@ -21,17 +21,25 @@ #ifndef LIBDOOMSDAY_DED_V1_PARSER_H #define LIBDOOMSDAY_DED_V1_PARSER_H +#include #include "../libdoomsday.h" #include "ded.h" -LIBDOOMSDAY_PUBLIC int DED_ReadLump(ded_t* ded, lumpnum_t lumpNum); - LIBDOOMSDAY_PUBLIC void DED_SetXGClassLinks(struct xgclass_s *links); -int DED_ReadData(ded_t* ded, const char* buffer, const char* _sourceFile); +/** + * Parser of DED v1 definitions. + * @ingroup data + */ +class LIBDOOMSDAY_PUBLIC DEDParser +{ +public: + DEDParser(ded_t *ded); -void DED_Include(ded_t *ded, const char* fileName, const char* parentDirectory); + int parse(char const *buffer, char const *sourceFile); -void DED_SetError(char const *str); +private: + DENG2_PRIVATE(d) +}; #endif // LIBDOOMSDAY_DED_V1_PARSER_H diff --git a/doomsday/libdoomsday/src/defs/dedfile.cpp b/doomsday/libdoomsday/src/defs/dedfile.cpp index 9bb0a6ac78..c82a870e19 100644 --- a/doomsday/libdoomsday/src/defs/dedfile.cpp +++ b/doomsday/libdoomsday/src/defs/dedfile.cpp @@ -26,7 +26,12 @@ using namespace de; -extern char dedReadError[512]; // in defs/parser.cpp +char dedReadError[512]; + +void DED_SetError(char const *str) +{ + strncpy(dedReadError, str, sizeof(dedReadError)); +} void Def_ReadProcessDED(ded_t *defs, char const* path) { @@ -118,3 +123,8 @@ int DED_Read(ded_t* ded, const char* path) Str_Free(&transPath); return result; } + +int DED_ReadData(ded_t* ded, const char* buffer, const char* _sourceFile) +{ + return DEDParser(ded).parse(buffer, _sourceFile); +} diff --git a/doomsday/libdoomsday/src/defs/dedparser.cpp b/doomsday/libdoomsday/src/defs/dedparser.cpp index f1ad208cdc..69379a5b85 100644 --- a/doomsday/libdoomsday/src/defs/dedparser.cpp +++ b/doomsday/libdoomsday/src/defs/dedparser.cpp @@ -42,21 +42,13 @@ #include "doomsday/filesys/fs_main.h" #include "doomsday/filesys/fs_util.h" #include "doomsday/uri.h" +#include "xgclass.h" #include #include #include #include -/* -#include "de_base.h" -#include "de_console.h" -#include "de_system.h" -#include "de_filesys.h" -#include "de_misc.h" -#include "de_defs.h"*/ -#include "xgclass.h" - #include #include #include @@ -76,15 +68,15 @@ using namespace de; #define ISTOKEN(X) (!stricmp(token, X)) #define READSTR(X) if(!ReadString(X, sizeof(X))) { \ - DED_SetError("Syntax error in string value."); \ + setError("Syntax error in string value."); \ retVal = false; goto ded_end_read; } #define READURI(X, SHM) if(!ReadUri(X, SHM)) { \ - DED_SetError("Syntax error parsing resource path."); \ + setError("Syntax error parsing resource path."); \ retVal = false; goto ded_end_read; } -#define MISSING_SC_ERROR DED_SetError("Missing semicolon."); \ +#define MISSING_SC_ERROR setError("Missing semicolon."); \ retVal = false; goto ded_end_read; #define CHECKSC if(source->version <= 5) { ReadToken(); if(!ISTOKEN(";")) { MISSING_SC_ERROR; } } @@ -105,8 +97,8 @@ using namespace de; #define READUINT(X) if(!ReadInt(&X, true)) { FAILURE } #define READFLT(X) if(!ReadFloat(&X)) { FAILURE } #define READNBYTEVEC(X,N) if(!ReadNByteVector(X, N)) { FAILURE } -#define READFLAGS(X,P) if(!ReadFlags(ded, &X, P)) { FAILURE } -#define READBLENDMODE(X) if(!ReadBlendmode(ded, &X)) { FAILURE } +#define READFLAGS(X,P) if(!ReadFlags(&X, P)) { FAILURE } +#define READBLENDMODE(X) if(!ReadBlendmode(&X)) { FAILURE } #define READSTRING(S,I) if(!ReadString(S, sizeof(S))) { I = strtol(token,0,0); } #define RV_BYTE(lab, X) if(ISLABEL(lab)) { READBYTE(X); } else @@ -125,48 +117,14 @@ using namespace de; #define RV_FLAGS(lab, X, P) if(ISLABEL(lab)) { READFLAGS(X, P); } else #define RV_BLENDMODE(lab, X) if(ISLABEL(lab)) { READBLENDMODE(X); } else #define RV_ANYSTR(lab, X) if(ISLABEL(lab)) { if(!ReadAnyString(&X)) { FAILURE } } else -#define RV_END { SetError2("Unknown label.", label); retVal = false; goto ded_end_read; } - -typedef struct dedsource_s { - const char* buffer; - const char* pos; - dd_bool atEnd; - int lineNumber; - const char* fileName; - int version; // v6 does not require semicolons. -} dedsource_t; - -char dedReadError[512]; - -static struct xgclass_s* xgClassLinks; - -static dedsource_t sourceStack[MAX_RECUR_DEPTH]; -static dedsource_t* source; // Points to the current source. - -static char token[MAX_TOKEN_LEN+1]; -static char unreadToken[MAX_TOKEN_LEN+1]; +#define RV_END { setError("Unknown label.", label); retVal = false; goto ded_end_read; } -static char* sdup(char const* str) -{ - if(!str) return NULL; - - char* newstr = (char*) M_Malloc(strlen(str) + 1); - strcpy(newstr, str); - return newstr; -} - -void DED_SetError(char const *str) -{ - sprintf(dedReadError, "Error in %s:\n Line %i: %s", - source ? source->fileName : "?", source ? source->lineNumber : 0, - str); -} +static struct xgclass_s *xgClassLinks; -static void SetError2(char const* str, char const* more) +static char *sdup(char const *str) { - sprintf(dedReadError, "Error in %s:\n Line %i: %s (%s)", - source ? source->fileName : "?", source ? source->lineNumber : 0, - str, more); + if(!str) return 0; + return strdup(str); } void DED_SetXGClassLinks(struct xgclass_s *links) @@ -174,2560 +132,2611 @@ void DED_SetXGClassLinks(struct xgclass_s *links) xgClassLinks = links; } -/** - * Reads a single character from the input file. Increments the line - * number counter if necessary. - */ -static int FGetC(void) +DENG2_PIMPL(DEDParser) { - int ch = (unsigned char) *source->pos; - - if(ch) - source->pos++; - else - source->atEnd = true; - if(ch == '\n') - source->lineNumber++; - if(ch == '\r') - return FGetC(); - - return ch; -} + ded_t *ded; -/** - * Undoes an FGetC. - */ -static int FUngetC(int ch) -{ - if(source->atEnd) - return 0; - if(ch == '\n') - source->lineNumber--; - if(source->pos > source->buffer) - source->pos--; - - return ch; -} + struct dedsource_s + { + const char* buffer; + const char* pos; + dd_bool atEnd; + int lineNumber; + const char* fileName; + int version; // v6 does not require semicolons. + }; -/** - * Reads stuff until a newline is found. - */ -static void SkipComment(void) -{ - int ch = FGetC(); - dd_bool seq = false; + typedef dedsource_s dedsource_t; - if(ch == '\n') - return; // Comment ends right away. + dedsource_t sourceStack[MAX_RECUR_DEPTH]; + dedsource_t* source; // Points to the current source. - if(ch != '>') // Single-line comment? + char token[MAX_TOKEN_LEN+1]; + char unreadToken[MAX_TOKEN_LEN+1]; + + Instance(Public *i) : Base(i), ded(0), source(0) { - while(FGetC() != '\n' && !source->atEnd) {} + zap(sourceStack); + zap(token); + zap(unreadToken); } - else // Multiline comment? + + void DED_InitReader(const char* buffer, const char* fileName) { - while(!source->atEnd) + if(source && source - sourceStack >= MAX_RECUR_DEPTH) { - ch = FGetC(); - if(seq) - { - if(ch == '#') - break; - seq = false; - } + App_FatalError("DED_InitReader: Include recursion is too deep.\n"); + } - if(ch == '<') - seq = true; + if(!source) + { + // This'll be the first source. + source = sourceStack; + } + else + { + // Take the next entry in the stack. + source++; } - } -} -static int ReadToken(void) -{ - int ch; - char* out = token; + source->pos = source->buffer = buffer; + source->atEnd = false; + source->lineNumber = 1; + source->fileName = fileName; + source->version = DED_VERSION; + } - // Has a token been unread? - if(unreadToken[0]) + void DED_CloseReader(void) { - strcpy(token, unreadToken); - strcpy(unreadToken, ""); - return true; + if(source == sourceStack) + { + source = NULL; + } + else + { + memset(source, 0, sizeof(*source)); + source--; + } } - ch = FGetC(); - if(source->atEnd) - return false; - - // Skip whitespace and comments in the beginning. - while((ch == '#' || isspace(ch))) + /** + * Reads a single character from the input file. Increments the line + * number counter if necessary. + */ + int FGetC(void) { - if(ch == '#') - SkipComment(); - ch = FGetC(); - if(source->atEnd) - return false; + int ch = (unsigned char) *source->pos; + + if(ch) + source->pos++; + else + source->atEnd = true; + if(ch == '\n') + source->lineNumber++; + if(ch == '\r') + return FGetC(); + + return ch; } - // Always store the first character. - *out++ = ch; - if(STOPCHAR(ch)) + /** + * Undoes an FGetC. + */ + int FUngetC(int ch) { - // Stop here. - *out = 0; - return true; + if(source->atEnd) + return 0; + if(ch == '\n') + source->lineNumber--; + if(source->pos > source->buffer) + source->pos--; + + return ch; } - while(!STOPCHAR(ch) && !source->atEnd) + /** + * Reads stuff until a newline is found. + */ + void SkipComment(void) { - // Store the character in the buffer. - ch = FGetC(); - *out++ = ch; - } - *(out - 1) = 0; // End token. + int ch = FGetC(); + dd_bool seq = false; - // Put the last read character back in the stream. - FUngetC(ch); - return true; -} + if(ch == '\n') + return; // Comment ends right away. -static void UnreadToken(const char* token) -{ - // The next time ReadToken() is called, this is returned. - strcpy(unreadToken, token); -} + if(ch != '>') // Single-line comment? + { + while(FGetC() != '\n' && !source->atEnd) {} + } + else // Multiline comment? + { + while(!source->atEnd) + { + ch = FGetC(); + if(seq) + { + if(ch == '#') + break; + seq = false; + } -/** - * Current pos in the file is at the first ". - * Does not expand escape sequences, only checks for \". - * - * @return @c true if successful. - */ -static int ReadString(String &dest, bool inside = false, bool doubleq = false) -{ - if(!inside) - { - ReadToken(); - if(!ISTOKEN("\"")) - return false; + if(ch == '<') + seq = true; + } + } } - bool esc = false, newl = false; - - // Start reading the characters. - int ch = FGetC(); - while(esc || ch != '"') // The string-end-character. + int ReadToken(void) { - if(source->atEnd) - return false; + int ch; + char* out = token; - // If a newline is found, skip all whitespace that follows. - if(newl) + // Has a token been unread? + if(unreadToken[0]) { - if(isspace(ch)) - { - ch = FGetC(); - continue; - } - else - { - // End the skip. - newl = false; - } + strcpy(token, unreadToken); + strcpy(unreadToken, ""); + return true; } - // An escape character? - if(!esc && ch == '\\') + ch = FGetC(); + if(source->atEnd) + return false; + + // Skip whitespace and comments in the beginning. + while((ch == '#' || isspace(ch))) { - esc = true; + if(ch == '#') + SkipComment(); + ch = FGetC(); + if(source->atEnd) + return false; } - else + + // Always store the first character. + *out++ = ch; + if(STOPCHAR(ch)) { - // In case it's something other than \" or \\, just insert - // the whole sequence as-is. - if(esc && ch != '"' && ch != '\\') - dest += '\\'; - esc = false; + // Stop here. + *out = 0; + return true; } - if(ch == '\n') - newl = true; - // Store the character in the buffer. - if(!esc && !newl) + while(!STOPCHAR(ch) && !source->atEnd) { - dest += char(ch); - if(doubleq && ch == '"') - dest += '"'; + // Store the character in the buffer. + ch = FGetC(); + *out++ = ch; } + *(out - 1) = 0; // End token. - // Read the next character, please. - ch = FGetC(); + // Put the last read character back in the stream. + FUngetC(ch); + return true; } - return true; -} - -static int ReadString(char *dest, int maxLen) -{ - DENG_ASSERT(dest != 0); - String buffer; - if(!ReadString(buffer)) return false; - qstrncpy(dest, buffer.toUtf8().constData(), maxLen); - return true; -} + void UnreadToken(const char* token) + { + // The next time ReadToken() is called, this is returned. + strcpy(unreadToken, token); + } -/** - * Read a string of (pretty much) any length. - */ -static int ReadAnyString(char **dest) -{ - String buffer; + /** + * Current pos in the file is at the first ". + * Does not expand escape sequences, only checks for \". + * + * @return @c true if successful. + */ + int ReadString(String &dest, bool inside = false, bool doubleq = false) + { + if(!inside) + { + ReadToken(); + if(!ISTOKEN("\"")) + return false; + } - if(!ReadString(buffer)) - return false; + bool esc = false, newl = false; - // Get rid of the old string. - if(*dest) - M_Free(*dest); + // Start reading the characters. + int ch = FGetC(); + while(esc || ch != '"') // The string-end-character. + { + if(source->atEnd) + return false; - // Make a copy. - QByteArray bufferUtf8 = buffer.toUtf8(); - *dest = (char *) M_Malloc(bufferUtf8.length() + 1); - qstrcpy(*dest, bufferUtf8.constData()); + // If a newline is found, skip all whitespace that follows. + if(newl) + { + if(isspace(ch)) + { + ch = FGetC(); + continue; + } + else + { + // End the skip. + newl = false; + } + } - return true; -} + // An escape character? + if(!esc && ch == '\\') + { + esc = true; + } + else + { + // In case it's something other than \" or \\, just insert + // the whole sequence as-is. + if(esc && ch != '"' && ch != '\\') + dest += '\\'; + esc = false; + } + if(ch == '\n') + newl = true; -static int ReadUri(de::Uri **dest_, char const *defaultScheme) -{ - String buffer; + // Store the character in the buffer. + if(!esc && !newl) + { + dest += char(ch); + if(doubleq && ch == '"') + dest += '"'; + } - if(!ReadString(buffer)) - return false; + // Read the next character, please. + ch = FGetC(); + } - // URIs are expected to use forward slashes. - buffer = Path::normalizeString(buffer); + return true; + } - if(!*dest_) - *dest_ = new de::Uri(buffer, RC_NULL); - else - (*dest_)->setUri(buffer, RC_NULL); + int ReadString(char *dest, int maxLen) + { + DENG_ASSERT(dest != 0); + String buffer; + if(!ReadString(buffer)) return false; + qstrncpy(dest, buffer.toUtf8().constData(), maxLen); + return true; + } - de::Uri *dest = *dest_; + /** + * Read a string of (pretty much) any length. + */ + int ReadAnyString(char **dest) + { + String buffer; - if(defaultScheme && defaultScheme[0] && dest->scheme().isEmpty()) - dest->setScheme(defaultScheme); + if(!ReadString(buffer)) + return false; - return true; -} + // Get rid of the old string. + if(*dest) + M_Free(*dest); -static int ReadNByteVector(unsigned char* dest, int max) -{ - int i; + // Make a copy. + QByteArray bufferUtf8 = buffer.toUtf8(); + *dest = (char *) M_Malloc(bufferUtf8.length() + 1); + qstrcpy(*dest, bufferUtf8.constData()); - FINDBEGIN; - for(i = 0; i < max; ++i) - { - ReadToken(); - if(ISTOKEN("}")) - return true; - dest[i] = strtoul(token, 0, 0); + return true; } - FINDEND; - return true; -} -/** - * @return @c true, if successful. - */ -static int ReadByte(unsigned char* dest) -{ - ReadToken(); - if(ISTOKEN(";")) + int ReadUri(de::Uri **dest_, char const *defaultScheme) { - DED_SetError("Missing integer value."); - return false; - } - - *dest = strtoul(token, 0, 0); - return true; -} + String buffer; -/** - * @return @c true, if successful. - */ -static int ReadInt(int* dest, int unsign) -{ - ReadToken(); - if(ISTOKEN(";")) - { - DED_SetError("Missing integer value."); - return false; - } + if(!ReadString(buffer)) + return false; - *dest = unsign? (int)strtoul(token, 0, 0) : strtol(token, 0, 0); - return true; -} + // URIs are expected to use forward slashes. + buffer = Path::normalizeString(buffer); -/** - * @return @c true, if successful. - */ -static int ReadFloat(float* dest) -{ - ReadToken(); - if(ISTOKEN(";")) - { - DED_SetError("Missing float value."); - return false; - } + if(!*dest_) + *dest_ = new de::Uri(buffer, RC_NULL); + else + (*dest_)->setUri(buffer, RC_NULL); - *dest = (float) strtod(token, 0); - return true; -} + de::Uri *dest = *dest_; -static int ReadFlags(ded_t *ded, int *dest, char const *prefix) -{ - // By default, no flags are set. - *dest = 0; + if(defaultScheme && defaultScheme[0] && dest->scheme().isEmpty()) + dest->setScheme(defaultScheme); - ReadToken(); - if(ISTOKEN(";")) - { - DED_SetError("Missing flags value."); - return false; - } - if(ISTOKEN("0")) - { - // No flags defined. return true; } - UnreadToken(token); - String flag; - if(ISTOKEN("\"")) + int ReadNByteVector(unsigned char* dest, int max) { - // The old format. - if(!ReadString(flag)) - return false; + int i; - flag.strip(); - - if(!flag.isEmpty()) - { - *dest = ded->evalFlags2(flag.toUtf8().constData()); - } - else + FINDBEGIN; + for(i = 0; i < max; ++i) { - *dest = 0; + ReadToken(); + if(ISTOKEN("}")) + return true; + dest[i] = strtoul(token, 0, 0); } + FINDEND; return true; } - for(;;) + /** + * @return @c true, if successful. + */ + int ReadByte(unsigned char* dest) { - // Read the flag. ReadToken(); - if(prefix) - { - flag = String(prefix) + String(token); - } - else + if(ISTOKEN(";")) { - flag = String(token); + setError("Missing integer value."); + return false; } - flag.strip(); + *dest = strtoul(token, 0, 0); + return true; + } - if(!flag.isEmpty()) + /** + * @return @c true, if successful. + */ + int ReadInt(int* dest, int unsign) + { + ReadToken(); + if(ISTOKEN(";")) { - *dest |= ded->evalFlags2(flag.toUtf8().constData()); + setError("Missing integer value."); + return false; } - if(!ReadToken()) - break; - - if(!ISTOKEN("|")) // | is required for multiple flags. - { - UnreadToken(token); - break; - } + *dest = unsign? (int)strtoul(token, 0, 0) : strtol(token, 0, 0); + return true; } - return true; -} - -static int ReadBlendmode(ded_t *ded, blendmode_t *dest) -{ - LOG_AS("ReadBlendmode"); - - String flag; - blendmode_t bm; - - ReadToken(); - UnreadToken(token); - if(ISTOKEN("\"")) - { - // The old format. - if(!ReadString(flag)) return false; - - bm = blendmode_t(ded->evalFlags2(flag.toUtf8().constData())); - } - else + /** + * @return @c true, if successful. + */ + int ReadFloat(float* dest) { - // Read the blendmode. ReadToken(); + if(ISTOKEN(";")) + { + setError("Missing float value."); + return false; + } - flag = String("bm_") + String(token); - - bm = blendmode_t(ded->evalFlags2(flag.toUtf8().constData())); + *dest = (float) strtod(token, 0); + return true; } - if(bm != BM_NORMAL) - { - *dest = bm; - } - else + int ReadFlags(int *dest, char const *prefix) { - LOG_RES_WARNING("Unknown BlendMode '%s' in \"%s\" on line #%i") - << flag << (source ? source->fileName : "?") << (source ? source->lineNumber : 0); - } - - return true; -} + // By default, no flags are set. + *dest = 0; -/** - * @return @c true, if successful. - */ -static int ReadLabel(char* label) -{ - strcpy(label, ""); - for(;;) - { ReadToken(); - if(source->atEnd) + if(ISTOKEN(";")) { - DED_SetError("Unexpected end of file."); + setError("Missing flags value."); return false; } - if(ISTOKEN("}")) // End block. + if(ISTOKEN("0")) { - strcpy(label, token); + // No flags defined. return true; } - if(ISTOKEN(";")) + + UnreadToken(token); + String flag; + if(ISTOKEN("\"")) { - if(source->version <= 5) - { - DED_SetError("Label without value."); + // The old format. + if(!ReadString(flag)) return false; + + flag.strip(); + + if(!flag.isEmpty()) + { + *dest = ded->evalFlags2(flag.toUtf8().constData()); + } + else + { + *dest = 0; } - continue; // Semicolons are optional in v6. + return true; } - if(ISTOKEN("=") || ISTOKEN("{")) - break; - if(label[0]) - strcat(label, " "); - strcat(label, token); - } + for(;;) + { + // Read the flag. + ReadToken(); + if(prefix) + { + flag = String(prefix) + String(token); + } + else + { + flag = String(token); + } - return true; -} + flag.strip(); -static void DED_InitReader(const char* buffer, const char* fileName) -{ - if(source && source - sourceStack >= MAX_RECUR_DEPTH) - { - App_FatalError("DED_InitReader: Include recursion is too deep.\n"); - } + if(!flag.isEmpty()) + { + *dest |= ded->evalFlags2(flag.toUtf8().constData()); + } - if(!source) - { - // This'll be the first source. - source = sourceStack; - } - else - { - // Take the next entry in the stack. - source++; - } + if(!ReadToken()) + break; - source->pos = source->buffer = buffer; - source->atEnd = false; - source->lineNumber = 1; - source->fileName = fileName; - source->version = DED_VERSION; -} + if(!ISTOKEN("|")) // | is required for multiple flags. + { + UnreadToken(token); + break; + } + } -static void DED_CloseReader(void) -{ - if(source == sourceStack) - { - source = NULL; + return true; } - else + + int ReadBlendmode(blendmode_t *dest) { - memset(source, 0, sizeof(*source)); - source--; - } -} + LOG_AS("ReadBlendmode"); -/** - * @param cond Condition token. Can be a command line option - * or a game mode. - * @return @c true if the condition passes. - */ -static dd_bool DED_CheckCondition(char const *cond, dd_bool expected) -{ - dd_bool value = false; + String flag; + blendmode_t bm; - if(cond[0] == '-') - { - // A command line option. - value = (CommandLine_Check(token) != 0); - } - else if(isalnum(cond[0]) && !App::game().isNull()) - { - // A game mode. - value = !String(cond).compareWithoutCase(App::game().id()); - } - - return value == expected; -} + ReadToken(); + UnreadToken(token); + if(ISTOKEN("\"")) + { + // The old format. + if(!ReadString(flag)) return false; -/** - * Reads definitions from the given buffer. - * The definition is being loaded from @a _sourcefile (DED or WAD). - * - * @param buffer The data to be read, must be null-terminated. - * @param _sourceFile Just FYI. - */ -int DED_ReadData(ded_t* ded, const char* buffer, const char* _sourceFile) -{ - char dummy[128], label[128], tmp[256]; - int dummyInt, idx, retVal = true; - int prevMobjDefIdx = -1; // For "Copy". - int prevStateDefIdx = -1; // For "Copy" - int prevLightDefIdx = -1; // For "Copy". - int prevMaterialDefIdx = -1; // For "Copy". - int prevModelDefIdx = -1; // For "Copy". - int prevMapInfoDefIdx = -1; // For "Copy". - int prevSkyDefIdx = -1; // For "Copy". - int prevDetailDefIdx = -1; // For "Copy". - int prevGenDefIdx = -1; // For "Copy". - int prevDecorDefIdx = -1; // For "Copy". - int prevRefDefIdx = -1; // For "Copy". - int prevLineTypeDefIdx = -1; // For "Copy". - int prevSectorTypeDefIdx = -1; // For "Copy". - int depth; - char* rootStr = 0, *ptr; - int bCopyNext = 0; - ddstring_t sourceFile, sourceFileDir; - - Str_Init(&sourceFile); Str_Set(&sourceFile, _sourceFile); - F_FixSlashes(&sourceFile, &sourceFile); - F_ExpandBasePath(&sourceFile, &sourceFile); - - // For including other files -- we must know where we are. - Str_Init(&sourceFileDir); - F_FileDir(&sourceFileDir, &sourceFile); - - // Get the next entry from the source stack. - DED_InitReader(buffer, Str_Text(&sourceFile)); - - while(ReadToken()) - { - if(ISTOKEN("Copy") || ISTOKEN("*")) + bm = blendmode_t(ded->evalFlags2(flag.toUtf8().constData())); + } + else { - bCopyNext = true; - continue; // Read the next token. + // Read the blendmode. + ReadToken(); + + flag = String("bm_") + String(token); + + bm = blendmode_t(ded->evalFlags2(flag.toUtf8().constData())); } - if(ISTOKEN(";")) + if(bm != BM_NORMAL) { - // Unnecessary semicolon? Just skip it. - continue; + *dest = bm; } - - if(ISTOKEN("SkipIf")) + else { - dd_bool expected = true; + LOG_RES_WARNING("Unknown BlendMode '%s' in \"%s\" on line #%i") + << flag << (source ? source->fileName : "?") << (source ? source->lineNumber : 0); + } + + return true; + } + /** + * @return @c true, if successful. + */ + int ReadLabel(char* label) + { + strcpy(label, ""); + for(;;) + { ReadToken(); - if(ISTOKEN("Not")) + if(source->atEnd) { - expected = false; - ReadToken(); + setError("Unexpected end of file."); + return false; } - - if(DED_CheckCondition(token, expected)) + if(ISTOKEN("}")) // End block. + { + strcpy(label, token); + return true; + } + if(ISTOKEN(";")) { - // Ah, we're done. Get out of here. - goto ded_end_read; + if(source->version <= 5) + { + setError("Label without value."); + return false; + } + continue; // Semicolons are optional in v6. } - CHECKSC; + if(ISTOKEN("=") || ISTOKEN("{")) + break; + + if(label[0]) + strcat(label, " "); + strcat(label, token); } - if(ISTOKEN("Include")) - { - // A new include. - READSTR(tmp); - CHECKSC; + return true; + } - DED_Include(ded, tmp, Str_Text(&sourceFileDir)); - strcpy(label, ""); - } + /** + * @param cond Condition token. Can be a command line option + * or a game mode. + * @return @c true if the condition passes. + */ + dd_bool DED_CheckCondition(char const *cond, dd_bool expected) + { + dd_bool value = false; - if(ISTOKEN("IncludeIf")) // An optional include. + if(cond[0] == '-') + { + // A command line option. + value = (CommandLine_Check(token) != 0); + } + else if(isalnum(cond[0]) && !App::game().isNull()) { - dd_bool expected = true; + // A game mode. + value = !String(cond).compareWithoutCase(App::game().id()); + } - ReadToken(); - if(ISTOKEN("Not")) - { - expected = false; - ReadToken(); - } + return value == expected; + } - if(DED_CheckCondition(token, expected)) + int readData(const char* buffer, const char* _sourceFile) + { + char dummy[128], label[128], tmp[256]; + int dummyInt, idx, retVal = true; + int prevMobjDefIdx = -1; // For "Copy". + int prevStateDefIdx = -1; // For "Copy" + int prevLightDefIdx = -1; // For "Copy". + int prevMaterialDefIdx = -1; // For "Copy". + int prevModelDefIdx = -1; // For "Copy". + int prevMapInfoDefIdx = -1; // For "Copy". + int prevSkyDefIdx = -1; // For "Copy". + int prevDetailDefIdx = -1; // For "Copy". + int prevGenDefIdx = -1; // For "Copy". + int prevDecorDefIdx = -1; // For "Copy". + int prevRefDefIdx = -1; // For "Copy". + int prevLineTypeDefIdx = -1; // For "Copy". + int prevSectorTypeDefIdx = -1; // For "Copy". + int depth; + char *rootStr = 0, *ptr; + int bCopyNext = 0; + ::Str sourceFile, sourceFileDir; + + Str_Init(&sourceFile); Str_Set(&sourceFile, _sourceFile); + F_FixSlashes(&sourceFile, &sourceFile); + F_ExpandBasePath(&sourceFile, &sourceFile); + + // For including other files -- we must know where we are. + Str_Init(&sourceFileDir); + F_FileDir(&sourceFileDir, &sourceFile); + + // Get the next entry from the source stack. + DED_InitReader(buffer, Str_Text(&sourceFile)); + + while(ReadToken()) + { + if(ISTOKEN("Copy") || ISTOKEN("*")) { - READSTR(tmp); - CHECKSC; - - DED_Include(ded, tmp, Str_Text(&sourceFileDir)); - strcpy(label, ""); + bCopyNext = true; + continue; // Read the next token. } - else + + if(ISTOKEN(";")) { - // Arg not found; just skip it. - READSTR(tmp); - CHECKSC; + // Unnecessary semicolon? Just skip it. + continue; } - } - if(ISTOKEN("ModelPath")) - { - READSTR(label); - CHECKSC; + if(ISTOKEN("SkipIf")) + { + dd_bool expected = true; - de::Uri newSearchPath = de::Uri::fromNativeDirPath(NativePath(label)); - FS1::Scheme& scheme = App_FileSystem().scheme(ResourceClass::classForId(RC_MODEL).defaultScheme()); - scheme.addSearchPath(reinterpret_cast(newSearchPath), FS1::ExtraPaths); - } + ReadToken(); + if(ISTOKEN("Not")) + { + expected = false; + ReadToken(); + } - if(ISTOKEN("Header")) - { - FINDBEGIN; - for(;;) - { - READLABEL; - if(ISLABEL("Version")) + if(DED_CheckCondition(token, expected)) { - READINT(ded->version); - source->version = ded->version; + // Ah, we're done. Get out of here. + goto ded_end_read; } - else RV_STR("Thing prefix", dummy) - RV_STR("State prefix", dummy) - RV_STR("Sprite prefix", dummy) - RV_STR("Sfx prefix", dummy) - RV_STR("Mus prefix", dummy) - RV_STR("Text prefix", dummy) - RV_STR("Model path", dummy) - RV_FLAGS("Common model flags", ded->modelFlags, "df_") - RV_FLT("Default model scale", ded->modelScale) - RV_FLT("Default model offset", ded->modelOffset) - RV_END CHECKSC; } - } - if(ISTOKEN("Flag")) - { - // A new flag. - idx = DED_AddFlag(ded, "", "", 0); - FINDBEGIN; - for(;;) + if(ISTOKEN("Include")) { - READLABEL; - RV_STR("ID", ded->flags[idx].id) - RV_UINT("Value", ded->flags[idx].value) - RV_STR("Info", ded->flags[idx].text) - RV_END + // A new include. + READSTR(tmp); CHECKSC; - } - } - - if(ISTOKEN("Mobj") || ISTOKEN("Thing")) - { - dd_bool bModify = false; - ded_mobj_t* mo, dummyMo; - ReadToken(); - if(!ISTOKEN("Mods")) - { - // A new mobj type. - idx = DED_AddMobj(ded, ""); - mo = &ded->mobjs[idx]; + DED_Include(tmp, Str_Text(&sourceFileDir)); + strcpy(label, ""); } - else if(!bCopyNext) + + if(ISTOKEN("IncludeIf")) // An optional include. { - ded_mobjid_t otherMobjId; + dd_bool expected = true; - READSTR(otherMobjId); ReadToken(); + if(ISTOKEN("Not")) + { + expected = false; + ReadToken(); + } - idx = ded->getMobjNum(otherMobjId); - if(idx < 0) + if(DED_CheckCondition(token, expected)) { - LOG_RES_WARNING("Ignoring unknown Mobj %s in %s on line #%i") - << otherMobjId << (source? source->fileName : "?") - << (source? source->lineNumber : 0); + READSTR(tmp); + CHECKSC; - // We'll read into a dummy definition. - memset(&dummyMo, 0, sizeof(dummyMo)); - mo = &dummyMo; + DED_Include(tmp, Str_Text(&sourceFileDir)); + strcpy(label, ""); } else { - mo = &ded->mobjs[idx]; - bModify = true; + // Arg not found; just skip it. + READSTR(tmp); + CHECKSC; } } - else - { - DED_SetError("Cannot both Copy(Previous) and Modify."); - retVal = false; - goto ded_end_read; - } - if(prevMobjDefIdx >= 0 && bCopyNext) + if(ISTOKEN("ModelPath")) { - // Should we copy the previous definition? - memcpy(mo, ded->mobjs + prevMobjDefIdx, sizeof(*mo)); + READSTR(label); + CHECKSC; + + de::Uri newSearchPath = de::Uri::fromNativeDirPath(NativePath(label)); + FS1::Scheme& scheme = App_FileSystem().scheme(ResourceClass::classForId(RC_MODEL).defaultScheme()); + scheme.addSearchPath(reinterpret_cast(newSearchPath), FS1::ExtraPaths); } - FINDBEGIN; - for(;;) + if(ISTOKEN("Header")) { - READLABEL; - // ID cannot be changed when modifying - if(!bModify && ISLABEL("ID")) + FINDBEGIN; + for(;;) { - READSTR(mo->id); + READLABEL; + if(ISLABEL("Version")) + { + READINT(ded->version); + source->version = ded->version; + } + else RV_STR("Thing prefix", dummy) + RV_STR("State prefix", dummy) + RV_STR("Sprite prefix", dummy) + RV_STR("Sfx prefix", dummy) + RV_STR("Mus prefix", dummy) + RV_STR("Text prefix", dummy) + RV_STR("Model path", dummy) + RV_FLAGS("Common model flags", ded->modelFlags, "df_") + RV_FLT("Default model scale", ded->modelScale) + RV_FLT("Default model offset", ded->modelOffset) + RV_END + CHECKSC; } - else RV_INT("DoomEd number", mo->doomEdNum) - RV_STR("Name", mo->name) - RV_STR("Spawn state", mo->states[SN_SPAWN]) - RV_STR("See state", mo->states[SN_SEE]) - RV_STR("Pain state", mo->states[SN_PAIN]) - RV_STR("Melee state", mo->states[SN_MELEE]) - RV_STR("Missile state", mo->states[SN_MISSILE]) - RV_STR("Crash state", mo->states[SN_CRASH]) - RV_STR("Death state", mo->states[SN_DEATH]) - RV_STR("Xdeath state", mo->states[SN_XDEATH]) - RV_STR("Raise state", mo->states[SN_RAISE]) - RV_STR("See sound", mo->seeSound) - RV_STR("Attack sound", mo->attackSound) - RV_STR("Pain sound", mo->painSound) - RV_STR("Death sound", mo->deathSound) - RV_STR("Active sound", mo->activeSound) - RV_INT("Reaction time", mo->reactionTime) - RV_INT("Pain chance", mo->painChance) - RV_INT("Spawn health", mo->spawnHealth) - RV_FLT("Speed", mo->speed) - RV_FLT("Radius", mo->radius) - RV_FLT("Height", mo->height) - RV_INT("Mass", mo->mass) - RV_INT("Damage", mo->damage) - RV_FLAGS("Flags", mo->flags[0], "mf_") - RV_FLAGS("Flags2", mo->flags[1], "mf2_") - RV_FLAGS("Flags3", mo->flags[2], "mf3_") - RV_INT("Misc1", mo->misc[0]) - RV_INT("Misc2", mo->misc[1]) - RV_INT("Misc3", mo->misc[2]) - RV_INT("Misc4", mo->misc[3]) - RV_END - CHECKSC; } - // If we did not read into a dummy update the previous index. - if(idx > 0) + if(ISTOKEN("Flag")) { - prevMobjDefIdx = idx; + // A new flag. + idx = DED_AddFlag(ded, "", "", 0); + FINDBEGIN; + for(;;) + { + READLABEL; + RV_STR("ID", ded->flags[idx].id) + RV_UINT("Value", ded->flags[idx].value) + RV_STR("Info", ded->flags[idx].text) + RV_END + CHECKSC; + } } - } - if(ISTOKEN("State")) - { - dd_bool bModify = false; - ded_state_t* st, dummyState; - - ReadToken(); - if(!ISTOKEN("Mods")) - { - // A new state. - idx = DED_AddState(ded, ""); - st = &ded->states[idx]; - } - else if(!bCopyNext) + if(ISTOKEN("Mobj") || ISTOKEN("Thing")) { - ded_stateid_t otherStateId; + dd_bool bModify = false; + ded_mobj_t* mo, dummyMo; - READSTR(otherStateId); ReadToken(); - - idx = ded->getStateNum(otherStateId); - if(idx < 0) + if(!ISTOKEN("Mods")) { - LOG_RES_WARNING("Ignoring unknown State %s in %s on line #%i") - << otherStateId << (source? source->fileName : "?") - << (source? source->lineNumber : 0); - - // We'll read into a dummy definition. - memset(&dummyState, 0, sizeof(dummyState)); - st = &dummyState; + // A new mobj type. + idx = DED_AddMobj(ded, ""); + mo = &ded->mobjs[idx]; } - else + else if(!bCopyNext) { - st = &ded->states[idx]; - bModify = true; - } - } - else - { - DED_SetError("Cannot both Copy(Previous) and Modify."); - retVal = false; - goto ded_end_read; - } + ded_mobjid_t otherMobjId; - if(prevStateDefIdx >= 0 && bCopyNext) - { - // Should we copy the previous definition? - memcpy(st, ded->states + prevStateDefIdx, sizeof(*st)); + READSTR(otherMobjId); + ReadToken(); + + idx = ded->getMobjNum(otherMobjId); + if(idx < 0) + { + LOG_RES_WARNING("Ignoring unknown Mobj %s in %s on line #%i") + << otherMobjId << (source? source->fileName : "?") + << (source? source->lineNumber : 0); - if(st->execute) + // We'll read into a dummy definition. + memset(&dummyMo, 0, sizeof(dummyMo)); + mo = &dummyMo; + } + else + { + mo = &ded->mobjs[idx]; + bModify = true; + } + } + else { - // Make a copy of the execute command string. - size_t len = strlen(st->execute); - char* newCmdStr = (char*) M_Malloc(len+1); - memcpy(newCmdStr, st->execute, len+1); - st->execute = newCmdStr; + setError("Cannot both Copy(Previous) and Modify."); + retVal = false; + goto ded_end_read; } - } - FINDBEGIN; - for(;;) - { - READLABEL; - // ID cannot be changed when modifying - if(!bModify && ISLABEL("ID")) + if(prevMobjDefIdx >= 0 && bCopyNext) { - READSTR(st->id); + // Should we copy the previous definition? + memcpy(mo, ded->mobjs + prevMobjDefIdx, sizeof(*mo)); } - else if(ISLABEL("Frame")) - { -// Legacy state frame flags: -#define FF_FULLBRIGHT 0x8000 -#define FF_FRAMEMASK 0x7fff - READINT(st->frame); - if(st->frame & FF_FULLBRIGHT) + FINDBEGIN; + for(;;) + { + READLABEL; + // ID cannot be changed when modifying + if(!bModify && ISLABEL("ID")) { - st->frame &= FF_FRAMEMASK; - st->flags |= STF_FULLBRIGHT; + READSTR(mo->id); } - -#undef FF_FRAMEMASK -#undef FF_FULLBRIGHT + else RV_INT("DoomEd number", mo->doomEdNum) + RV_STR("Name", mo->name) + RV_STR("Spawn state", mo->states[SN_SPAWN]) + RV_STR("See state", mo->states[SN_SEE]) + RV_STR("Pain state", mo->states[SN_PAIN]) + RV_STR("Melee state", mo->states[SN_MELEE]) + RV_STR("Missile state", mo->states[SN_MISSILE]) + RV_STR("Crash state", mo->states[SN_CRASH]) + RV_STR("Death state", mo->states[SN_DEATH]) + RV_STR("Xdeath state", mo->states[SN_XDEATH]) + RV_STR("Raise state", mo->states[SN_RAISE]) + RV_STR("See sound", mo->seeSound) + RV_STR("Attack sound", mo->attackSound) + RV_STR("Pain sound", mo->painSound) + RV_STR("Death sound", mo->deathSound) + RV_STR("Active sound", mo->activeSound) + RV_INT("Reaction time", mo->reactionTime) + RV_INT("Pain chance", mo->painChance) + RV_INT("Spawn health", mo->spawnHealth) + RV_FLT("Speed", mo->speed) + RV_FLT("Radius", mo->radius) + RV_FLT("Height", mo->height) + RV_INT("Mass", mo->mass) + RV_INT("Damage", mo->damage) + RV_FLAGS("Flags", mo->flags[0], "mf_") + RV_FLAGS("Flags2", mo->flags[1], "mf2_") + RV_FLAGS("Flags3", mo->flags[2], "mf3_") + RV_INT("Misc1", mo->misc[0]) + RV_INT("Misc2", mo->misc[1]) + RV_INT("Misc3", mo->misc[2]) + RV_INT("Misc4", mo->misc[3]) + RV_END + CHECKSC; } - else RV_FLAGS("Flags", st->flags, "statef_") - RV_STR("Sprite", st->sprite.id) - RV_INT("Tics", st->tics) - RV_STR("Action", st->action) - RV_STR("Next state", st->nextState) - RV_INT("Misc1", st->misc[0]) - RV_INT("Misc2", st->misc[1]) - RV_INT("Misc3", st->misc[2]) - RV_ANYSTR("Execute", st->execute) - RV_END - CHECKSC; - } - // If we did not read into a dummy update the previous index. - if(idx > 0) - { - prevStateDefIdx = idx; + // If we did not read into a dummy update the previous index. + if(idx > 0) + { + prevMobjDefIdx = idx; + } } - } - if(ISTOKEN("Sprite")) - { - // A new sprite. - idx = DED_AddSprite(ded, ""); - FINDBEGIN; - for(;;) + if(ISTOKEN("State")) { - READLABEL; - RV_STR("ID", ded->sprites[idx].id) - RV_END - CHECKSC; - } - } + dd_bool bModify = false; + ded_state_t* st, dummyState; - if(ISTOKEN("Light")) - { - ded_light_t* lig; - - // A new light. - idx = DED_AddLight(ded, ""); - lig = &ded->lights[idx]; + ReadToken(); + if(!ISTOKEN("Mods")) + { + // A new state. + idx = DED_AddState(ded, ""); + st = &ded->states[idx]; + } + else if(!bCopyNext) + { + ded_stateid_t otherStateId; - // Should we copy the previous definition? - if(prevLightDefIdx >= 0 && bCopyNext) - { - const ded_light_t* prevLight = ded->lights + prevLightDefIdx; + READSTR(otherStateId); + ReadToken(); - memcpy(lig, prevLight, sizeof(*lig)); - if(lig->up) lig->up = new de::Uri(*lig->up); - if(lig->down) lig->down = new de::Uri(*lig->down); - if(lig->sides) lig->sides = new de::Uri(*lig->sides); - if(lig->flare) lig->flare = new de::Uri(*lig->flare); - } + idx = ded->getStateNum(otherStateId); + if(idx < 0) + { + LOG_RES_WARNING("Ignoring unknown State %s in %s on line #%i") + << otherStateId << (source? source->fileName : "?") + << (source? source->lineNumber : 0); - FINDBEGIN; - for(;;) - { - READLABEL; - RV_STR("State", lig->state) - RV_STR("Map", lig->uniqueMapID) - RV_FLT("X Offset", lig->offset[VX]) - RV_FLT("Y Offset", lig->offset[VY]) - RV_VEC("Origin", lig->offset, 3) - RV_FLT("Size", lig->size) - RV_FLT("Intensity", lig->size) - RV_FLT("Red", lig->color[0]) - RV_FLT("Green", lig->color[1]) - RV_FLT("Blue", lig->color[2]) - RV_VEC("Color", lig->color, 3) - if(ISLABEL("Sector levels")) - { - int b; - FINDBEGIN; - for(b = 0; b < 2; ++b) + // We'll read into a dummy definition. + memset(&dummyState, 0, sizeof(dummyState)); + st = &dummyState; + } + else { - READFLT(lig->lightLevel[b]) - lig->lightLevel[b] /= 255.0f; - if(lig->lightLevel[b] < 0) - lig->lightLevel[b] = 0; - else if(lig->lightLevel[b] > 1) - lig->lightLevel[b] = 1; + st = &ded->states[idx]; + bModify = true; } - ReadToken(); } else - RV_FLAGS("Flags", lig->flags, "lgf_") - RV_URI("Top map", &lig->up, "LightMaps") - RV_URI("Bottom map", &lig->down, "LightMaps") - RV_URI("Side map", &lig->sides, "LightMaps") - RV_URI("Flare map", &lig->flare, "LightMaps") - RV_FLT("Halo radius", lig->haloRadius) - RV_END - CHECKSC; - } - prevLightDefIdx = idx; - } + { + setError("Cannot both Copy(Previous) and Modify."); + retVal = false; + goto ded_end_read; + } - if(ISTOKEN("Material")) - { - bool bModify = false; - ded_material_t *mat, dummyMat; + if(prevStateDefIdx >= 0 && bCopyNext) + { + // Should we copy the previous definition? + memcpy(st, ded->states + prevStateDefIdx, sizeof(*st)); - ReadToken(); - if(!ISTOKEN("Mods")) - { - // A new material. - idx = DED_AddMaterial(ded, 0); - mat = &ded->materials[idx]; - } - else if(!bCopyNext) - { - de::Uri *otherMat = 0; + if(st->execute) + { + // Make a copy of the execute command string. + size_t len = strlen(st->execute); + char* newCmdStr = (char*) M_Malloc(len+1); + memcpy(newCmdStr, st->execute, len+1); + st->execute = newCmdStr; + } + } - READURI(&otherMat, NULL); - ReadToken(); + FINDBEGIN; + for(;;) + { + READLABEL; + // ID cannot be changed when modifying + if(!bModify && ISLABEL("ID")) + { + READSTR(st->id); + } + else if(ISLABEL("Frame")) + { + // Legacy state frame flags: + #define FF_FULLBRIGHT 0x8000 + #define FF_FRAMEMASK 0x7fff - mat = ded->getMaterial(otherMat->compose().toLatin1()); + READINT(st->frame); + if(st->frame & FF_FULLBRIGHT) + { + st->frame &= FF_FRAMEMASK; + st->flags |= STF_FULLBRIGHT; + } - if(!mat) - { - LOG_RES_WARNING("Ignoring unknown Material %s in %s on line #%i") - << otherMat->asText() - << (source? source->fileName : "?") - << (source? source->lineNumber : 0); - - // We'll read into a dummy definition. - idx = -1; - memset(&dummyMat, 0, sizeof(dummyMat)); - mat = &dummyMat; + #undef FF_FRAMEMASK + #undef FF_FULLBRIGHT + } + else RV_FLAGS("Flags", st->flags, "statef_") + RV_STR("Sprite", st->sprite.id) + RV_INT("Tics", st->tics) + RV_STR("Action", st->action) + RV_STR("Next state", st->nextState) + RV_INT("Misc1", st->misc[0]) + RV_INT("Misc2", st->misc[1]) + RV_INT("Misc3", st->misc[2]) + RV_ANYSTR("Execute", st->execute) + RV_END + CHECKSC; } - else + + // If we did not read into a dummy update the previous index. + if(idx > 0) { - idx = mat - ded->materials; - bModify = true; + prevStateDefIdx = idx; } - delete otherMat; } - else + + if(ISTOKEN("Sprite")) { - DED_SetError("Cannot both Copy(Previous) and Modify."); - retVal = false; - goto ded_end_read; + // A new sprite. + idx = DED_AddSprite(ded, ""); + FINDBEGIN; + for(;;) + { + READLABEL; + RV_STR("ID", ded->sprites[idx].id) + RV_END + CHECKSC; + } } - // Should we copy the previous definition? - if(prevMaterialDefIdx >= 0 && bCopyNext) + if(ISTOKEN("Light")) { - ded_material_t const *prevMaterial = ded->materials + prevMaterialDefIdx; - de::Uri *uri = mat->uri; + ded_light_t* lig; - std::memcpy(mat, prevMaterial, sizeof(*mat)); - mat->uri = uri; - if(prevMaterial->uri) - { - if(mat->uri) - *mat->uri = *prevMaterial->uri; - else - mat->uri = new de::Uri(*prevMaterial->uri); - } + // A new light. + idx = DED_AddLight(ded, ""); + lig = &ded->lights[idx]; - // Duplicate the layers. - for(int i = 0; i < DED_MAX_MATERIAL_LAYERS; ++i) + // Should we copy the previous definition? + if(prevLightDefIdx >= 0 && bCopyNext) { - ded_material_layer_t const *l = &prevMaterial->layers[i]; - if(!l->stages) continue; + const ded_light_t* prevLight = ded->lights + prevLightDefIdx; - mat->layers[i].stages = (ded_material_layer_stage_t*) M_Malloc(sizeof(*mat->layers[i].stages) * l->stageCount.max); - std::memcpy(mat->layers[i].stages, l->stages, sizeof(*mat->layers[i].stages) * l->stageCount.num); + memcpy(lig, prevLight, sizeof(*lig)); + if(lig->up) lig->up = new de::Uri(*lig->up); + if(lig->down) lig->down = new de::Uri(*lig->down); + if(lig->sides) lig->sides = new de::Uri(*lig->sides); + if(lig->flare) lig->flare = new de::Uri(*lig->flare); + } - for(int k = 0; k < l->stageCount.num; ++k) + FINDBEGIN; + for(;;) + { + READLABEL; + RV_STR("State", lig->state) + RV_STR("Map", lig->uniqueMapID) + RV_FLT("X Offset", lig->offset[VX]) + RV_FLT("Y Offset", lig->offset[VY]) + RV_VEC("Origin", lig->offset, 3) + RV_FLT("Size", lig->size) + RV_FLT("Intensity", lig->size) + RV_FLT("Red", lig->color[0]) + RV_FLT("Green", lig->color[1]) + RV_FLT("Blue", lig->color[2]) + RV_VEC("Color", lig->color, 3) + if(ISLABEL("Sector levels")) { - if(l->stages[k].texture) - mat->layers[i].stages[k].texture = new de::Uri(*l->stages[k].texture); + int b; + FINDBEGIN; + for(b = 0; b < 2; ++b) + { + READFLT(lig->lightLevel[b]) + lig->lightLevel[b] /= 255.0f; + if(lig->lightLevel[b] < 0) + lig->lightLevel[b] = 0; + else if(lig->lightLevel[b] > 1) + lig->lightLevel[b] = 1; + } + ReadToken(); } + else + RV_FLAGS("Flags", lig->flags, "lgf_") + RV_URI("Top map", &lig->up, "LightMaps") + RV_URI("Bottom map", &lig->down, "LightMaps") + RV_URI("Side map", &lig->sides, "LightMaps") + RV_URI("Flare map", &lig->flare, "LightMaps") + RV_FLT("Halo radius", lig->haloRadius) + RV_END + CHECKSC; } + prevLightDefIdx = idx; + } + + if(ISTOKEN("Material")) + { + bool bModify = false; + ded_material_t *mat, dummyMat; - // Duplicate decorations. - for(int i = 0; i < DED_MAX_MATERIAL_DECORATIONS; ++i) + ReadToken(); + if(!ISTOKEN("Mods")) + { + // A new material. + idx = DED_AddMaterial(ded, 0); + mat = &ded->materials[idx]; + } + else if(!bCopyNext) { - ded_material_decoration_t const *dl = &prevMaterial->decorations[i]; - if(!dl->stages) continue; + de::Uri *otherMat = 0; - mat->decorations[i].stages = (ded_decorlight_stage_t *) M_Malloc(sizeof(*mat->decorations[i].stages) * dl->stageCount.max); - std::memcpy(mat->decorations[i].stages, dl->stages, sizeof(*mat->decorations[i].stages) * dl->stageCount.num); + READURI(&otherMat, NULL); + ReadToken(); + + mat = ded->getMaterial(otherMat->compose().toLatin1()); - for(int k = 0; k < dl->stageCount.num; ++k) + if(!mat) + { + LOG_RES_WARNING("Ignoring unknown Material %s in %s on line #%i") + << otherMat->asText() + << (source? source->fileName : "?") + << (source? source->lineNumber : 0); + + // We'll read into a dummy definition. + idx = -1; + memset(&dummyMat, 0, sizeof(dummyMat)); + mat = &dummyMat; + } + else { - ded_decorlight_stage_t *stage = &mat->decorations[i].stages[k]; - if(stage->flare) stage->flare = new de::Uri(*stage->flare); - if(stage->up) stage->up = new de::Uri(*stage->up); - if(stage->down) stage->down = new de::Uri(*stage->down); - if(stage->sides) stage->sides = new de::Uri(*stage->sides); + idx = mat - ded->materials; + bModify = true; } + delete otherMat; } - } - - uint layer = 0; - uint light = 0; - - FINDBEGIN; - forever - { - READLABEL; - // ID cannot be changed when modifying - if(!bModify && ISLABEL("ID")) + else { - READURI(&mat->uri, NULL); + setError("Cannot both Copy(Previous) and Modify."); + retVal = false; + goto ded_end_read; } - else RV_FLAGS("Flags", mat->flags, "matf_") - RV_INT("Width", mat->width) - RV_INT("Height", mat->height) - if(ISLABEL("Layer")) + + // Should we copy the previous definition? + if(prevMaterialDefIdx >= 0 && bCopyNext) { - int layerStage = 0; + ded_material_t const *prevMaterial = ded->materials + prevMaterialDefIdx; + de::Uri *uri = mat->uri; - if(layer >= DED_MAX_MATERIAL_LAYERS) + std::memcpy(mat, prevMaterial, sizeof(*mat)); + mat->uri = uri; + if(prevMaterial->uri) { - DED_SetError("Too many Material layers."); - retVal = false; - goto ded_end_read; + if(mat->uri) + *mat->uri = *prevMaterial->uri; + else + mat->uri = new de::Uri(*prevMaterial->uri); } - FINDBEGIN; - forever + // Duplicate the layers. + for(int i = 0; i < DED_MAX_MATERIAL_LAYERS; ++i) { - READLABEL; - if(ISLABEL("Stage")) - { - // Need to allocate a new stage? - if(layerStage >= mat->layers[layer].stageCount.num) - { - DED_AddMaterialLayerStage(&mat->layers[layer]); + ded_material_layer_t const *l = &prevMaterial->layers[i]; + if(!l->stages) continue; - if(mat->autoGenerated && layerStage > 0) - { - // When adding a new stage to an autogenerated material - // initialize by copying values from the previous stage. - ded_material_layer_stage_t const - &prevSt = mat->layers[layer].stages[layerStage - 1]; - ded_material_layer_stage_t - &st = mat->layers[layer].stages[layerStage]; - - if(prevSt.texture) - st.texture = new de::Uri(*prevSt.texture); - st.tics = prevSt.tics; - st.variance = prevSt.variance; - st.glowStrength = prevSt.glowStrength; - st.glowStrengthVariance = prevSt.glowStrengthVariance; - V2f_Copy(st.texOrigin, prevSt.texOrigin); - } - } + mat->layers[i].stages = (ded_material_layer_stage_t*) M_Malloc(sizeof(*mat->layers[i].stages) * l->stageCount.max); + std::memcpy(mat->layers[i].stages, l->stages, sizeof(*mat->layers[i].stages) * l->stageCount.num); - ded_material_layer_stage_t *st = &mat->layers[layer].stages[layerStage]; + for(int k = 0; k < l->stageCount.num; ++k) + { + if(l->stages[k].texture) + mat->layers[i].stages[k].texture = new de::Uri(*l->stages[k].texture); + } + } - FINDBEGIN; - forever - { - READLABEL; - RV_URI("Texture", &st->texture, 0) // Default to "any" scheme. - RV_INT("Tics", st->tics) - RV_FLT("Rnd", st->variance) - RV_VEC("Offset", st->texOrigin, 2) - RV_FLT("Glow Rnd", st->glowStrengthVariance) - RV_FLT("Glow", st->glowStrength) - RV_END - CHECKSC; - } - layerStage++; + // Duplicate decorations. + for(int i = 0; i < DED_MAX_MATERIAL_DECORATIONS; ++i) + { + ded_material_decoration_t const *dl = &prevMaterial->decorations[i]; + if(!dl->stages) continue; + + mat->decorations[i].stages = (ded_decorlight_stage_t *) M_Malloc(sizeof(*mat->decorations[i].stages) * dl->stageCount.max); + std::memcpy(mat->decorations[i].stages, dl->stages, sizeof(*mat->decorations[i].stages) * dl->stageCount.num); + + for(int k = 0; k < dl->stageCount.num; ++k) + { + ded_decorlight_stage_t *stage = &mat->decorations[i].stages[k]; + if(stage->flare) stage->flare = new de::Uri(*stage->flare); + if(stage->up) stage->up = new de::Uri(*stage->up); + if(stage->down) stage->down = new de::Uri(*stage->down); + if(stage->sides) stage->sides = new de::Uri(*stage->sides); } - else RV_END - CHECKSC; } - layer++; } - else if(ISLABEL("Light")) - { - int lightStage = 0; - if(light == DED_MAX_MATERIAL_DECORATIONS) + uint layer = 0; + uint light = 0; + + FINDBEGIN; + forever + { + READLABEL; + // ID cannot be changed when modifying + if(!bModify && ISLABEL("ID")) { - DED_SetError("Too many lights in material."); - retVal = false; - goto ded_end_read; + READURI(&mat->uri, NULL); } - - ded_material_decoration_t *dl = &mat->decorations[light]; - FINDBEGIN; - for(;;) + else RV_FLAGS("Flags", mat->flags, "matf_") + RV_INT("Width", mat->width) + RV_INT("Height", mat->height) + if(ISLABEL("Layer")) { - READLABEL; - RV_IVEC("Pattern offset", dl->patternOffset, 2) - RV_IVEC("Pattern skip", dl->patternSkip, 2) - if(ISLABEL("Stage")) + int layerStage = 0; + + if(layer >= DED_MAX_MATERIAL_LAYERS) + { + setError("Too many Material layers."); + retVal = false; + goto ded_end_read; + } + + FINDBEGIN; + forever { - // Need to allocate a new stage? - if(lightStage >= dl->stageCount.num) + READLABEL; + if(ISLABEL("Stage")) { - lightStage = DED_AddMaterialDecorationStage(dl); + // Need to allocate a new stage? + if(layerStage >= mat->layers[layer].stageCount.num) + { + DED_AddMaterialLayerStage(&mat->layers[layer]); + + if(mat->autoGenerated && layerStage > 0) + { + // When adding a new stage to an autogenerated material + // initialize by copying values from the previous stage. + ded_material_layer_stage_t const + &prevSt = mat->layers[layer].stages[layerStage - 1]; + ded_material_layer_stage_t + &st = mat->layers[layer].stages[layerStage]; + + if(prevSt.texture) + st.texture = new de::Uri(*prevSt.texture); + st.tics = prevSt.tics; + st.variance = prevSt.variance; + st.glowStrength = prevSt.glowStrength; + st.glowStrengthVariance = prevSt.glowStrengthVariance; + V2f_Copy(st.texOrigin, prevSt.texOrigin); + } + } + + ded_material_layer_stage_t *st = &mat->layers[layer].stages[layerStage]; + + FINDBEGIN; + forever + { + READLABEL; + RV_URI("Texture", &st->texture, 0) // Default to "any" scheme. + RV_INT("Tics", st->tics) + RV_FLT("Rnd", st->variance) + RV_VEC("Offset", st->texOrigin, 2) + RV_FLT("Glow Rnd", st->glowStrengthVariance) + RV_FLT("Glow", st->glowStrength) + RV_END + CHECKSC; + } + layerStage++; } + else RV_END + CHECKSC; + } + layer++; + } + else if(ISLABEL("Light")) + { + int lightStage = 0; - ded_decorlight_stage_t *st = &dl->stages[lightStage]; - FINDBEGIN; - for(;;) + if(light == DED_MAX_MATERIAL_DECORATIONS) + { + setError("Too many lights in material."); + retVal = false; + goto ded_end_read; + } + + ded_material_decoration_t *dl = &mat->decorations[light]; + FINDBEGIN; + for(;;) + { + READLABEL; + RV_IVEC("Pattern offset", dl->patternOffset, 2) + RV_IVEC("Pattern skip", dl->patternSkip, 2) + if(ISLABEL("Stage")) { - READLABEL; - RV_INT("Tics", st->tics) - RV_FLT("Rnd", st->variance) - RV_VEC("Offset", st->pos, 2) - RV_FLT("Distance", st->elevation) - RV_VEC("Color", st->color, 3) - RV_FLT("Radius", st->radius) - RV_FLT("Halo radius", st->haloRadius) - if(ISLABEL("Levels")) + // Need to allocate a new stage? + if(lightStage >= dl->stageCount.num) { - FINDBEGIN; - for(int b = 0; b < 2; ++b) + lightStage = DED_AddMaterialDecorationStage(dl); + } + + ded_decorlight_stage_t *st = &dl->stages[lightStage]; + FINDBEGIN; + for(;;) + { + READLABEL; + RV_INT("Tics", st->tics) + RV_FLT("Rnd", st->variance) + RV_VEC("Offset", st->pos, 2) + RV_FLT("Distance", st->elevation) + RV_VEC("Color", st->color, 3) + RV_FLT("Radius", st->radius) + RV_FLT("Halo radius", st->haloRadius) + if(ISLABEL("Levels")) { - READFLT(st->lightLevels[b]) - st->lightLevels[b] /= 255.0f; - if(st->lightLevels[b] < 0) - st->lightLevels[b] = 0; - else if(st->lightLevels[b] > 1) - st->lightLevels[b] = 1; + FINDBEGIN; + for(int b = 0; b < 2; ++b) + { + READFLT(st->lightLevels[b]) + st->lightLevels[b] /= 255.0f; + if(st->lightLevels[b] < 0) + st->lightLevels[b] = 0; + else if(st->lightLevels[b] > 1) + st->lightLevels[b] = 1; + } + ReadToken(); } - ReadToken(); + else + RV_INT("Flare texture", st->sysFlareIdx) + RV_URI("Flare map", &st->flare, "LightMaps") + RV_URI("Top map", &st->up, "LightMaps") + RV_URI("Bottom map", &st->down, "LightMaps") + RV_URI("Side map", &st->sides, "LightMaps") + RV_END + CHECKSC; } - else - RV_INT("Flare texture", st->sysFlareIdx) - RV_URI("Flare map", &st->flare, "LightMaps") - RV_URI("Top map", &st->up, "LightMaps") - RV_URI("Bottom map", &st->down, "LightMaps") - RV_URI("Side map", &st->sides, "LightMaps") - RV_END - CHECKSC; + lightStage++; } - lightStage++; + else RV_END + CHECKSC; } - else RV_END - CHECKSC; + light++; } - light++; + else RV_END + CHECKSC; } - else RV_END - CHECKSC; - } - // If we did not read into a dummy update the previous index. - if(idx > 0) - { - prevMaterialDefIdx = idx; - } - else - { - /// @todo fixme: Free memory allocated for the dummy. + // If we did not read into a dummy update the previous index. + if(idx > 0) + { + prevMaterialDefIdx = idx; + } + else + { + /// @todo fixme: Free memory allocated for the dummy. + } } - } - if(ISTOKEN("Model")) - { - ded_model_t* mdl, *prevModel = NULL; - uint sub = 0; + if(ISTOKEN("Model")) + { + ded_model_t* mdl, *prevModel = NULL; + uint sub = 0; - // A new model. - idx = DED_AddModel(ded, ""); - mdl = &ded->models[idx]; + // A new model. + idx = DED_AddModel(ded, ""); + mdl = &ded->models[idx]; - if(prevModelDefIdx >= 0) - { - prevModel = &ded->models[prevModelDefIdx]; - // Should we copy the previous definition? - if(bCopyNext) + if(prevModelDefIdx >= 0) { - *mdl = *prevModel; - for(uint i = 0; i < mdl->subCount(); ++i) + prevModel = &ded->models[prevModelDefIdx]; + // Should we copy the previous definition? + if(bCopyNext) { - if(mdl->sub(i).filename) - mdl->sub(i).filename = new de::Uri(*mdl->sub(i).filename); + *mdl = *prevModel; + for(uint i = 0; i < mdl->subCount(); ++i) + { + if(mdl->sub(i).filename) + mdl->sub(i).filename = new de::Uri(*mdl->sub(i).filename); - if(mdl->sub(i).skinFilename) - mdl->sub(i).skinFilename = new de::Uri(*mdl->sub(i).skinFilename); + if(mdl->sub(i).skinFilename) + mdl->sub(i).skinFilename = new de::Uri(*mdl->sub(i).skinFilename); - if(mdl->sub(i).shinySkin) - mdl->sub(i).shinySkin = new de::Uri(*mdl->sub(i).shinySkin); + if(mdl->sub(i).shinySkin) + mdl->sub(i).shinySkin = new de::Uri(*mdl->sub(i).shinySkin); + } } } - } - FINDBEGIN; - for(;;) - { - READLABEL; - RV_STR("ID", mdl->id) - RV_STR("State", mdl->state) - RV_INT("Off", mdl->off) - RV_STR("Sprite", mdl->sprite.id) - RV_INT("Sprite frame", mdl->spriteFrame) - RV_FLAGS("Group", mdl->group, "mg_") - RV_INT("Selector", mdl->selector) - RV_FLAGS("Flags", mdl->flags, "df_") - RV_FLT("Inter", mdl->interMark) - RV_INT("Skin tics", mdl->skinTics) - RV_FLT("Resize", mdl->resize) - if(ISLABEL("Scale")) - { - float scale; READFLT(scale); - mdl->scale = Vector3f(scale, scale, scale); - } - else RV_VEC("Scale XYZ", mdl->scale, 3) - RV_FLT("Offset", mdl->offset[1]) - RV_VEC("Offset XYZ", mdl->offset, 3) - RV_VEC("Interpolate", mdl->interRange, 2) - RV_FLT("Shadow radius", mdl->shadowRadius) - if(ISLABEL("Md2") || ISLABEL("Sub")) + FINDBEGIN; + for(;;) { - // Add another submodel. - if(sub >= mdl->subCount()) + READLABEL; + RV_STR("ID", mdl->id) + RV_STR("State", mdl->state) + RV_INT("Off", mdl->off) + RV_STR("Sprite", mdl->sprite.id) + RV_INT("Sprite frame", mdl->spriteFrame) + RV_FLAGS("Group", mdl->group, "mg_") + RV_INT("Selector", mdl->selector) + RV_FLAGS("Flags", mdl->flags, "df_") + RV_FLT("Inter", mdl->interMark) + RV_INT("Skin tics", mdl->skinTics) + RV_FLT("Resize", mdl->resize) + if(ISLABEL("Scale")) { - mdl->appendSub(); + float scale; READFLT(scale); + mdl->scale = Vector3f(scale, scale, scale); } - DENG_ASSERT(sub < mdl->subCount()); - - FINDBEGIN; - for(;;) + else RV_VEC("Scale XYZ", mdl->scale, 3) + RV_FLT("Offset", mdl->offset[1]) + RV_VEC("Offset XYZ", mdl->offset, 3) + RV_VEC("Interpolate", mdl->interRange, 2) + RV_FLT("Shadow radius", mdl->shadowRadius) + if(ISLABEL("Md2") || ISLABEL("Sub")) { - READLABEL; - RV_URI("File", &mdl->sub(sub).filename, "Models") - RV_STR("Frame", mdl->sub(sub).frame) - RV_INT("Frame range", mdl->sub(sub).frameRange) - RV_BLENDMODE("Blending mode", mdl->sub(sub).blendMode) - RV_INT("Skin", mdl->sub(sub).skin) - RV_URI("Skin file", &mdl->sub(sub).skinFilename, "Models") - RV_INT("Skin range", mdl->sub(sub).skinRange) - RV_VEC("Offset XYZ", mdl->sub(sub).offset, 3) - RV_FLAGS("Flags", mdl->sub(sub).flags, "df_") - RV_FLT("Transparent", mdl->sub(sub).alpha) - RV_FLT("Parm", mdl->sub(sub).parm) - RV_BYTE("Selskin mask", mdl->sub(sub).selSkinBits[0]) - RV_BYTE("Selskin shift", mdl->sub(sub).selSkinBits[1]) - RV_NBVEC("Selskins", mdl->sub(sub).selSkins, 8) - RV_URI("Shiny skin", &mdl->sub(sub).shinySkin, "Models") - RV_FLT("Shiny", mdl->sub(sub).shiny) - RV_VEC("Shiny color", mdl->sub(sub).shinyColor, 3) - RV_FLT("Shiny reaction", mdl->sub(sub).shinyReact) - RV_END - CHECKSC; + // Add another submodel. + if(sub >= mdl->subCount()) + { + mdl->appendSub(); + } + DENG_ASSERT(sub < mdl->subCount()); + + FINDBEGIN; + for(;;) + { + READLABEL; + RV_URI("File", &mdl->sub(sub).filename, "Models") + RV_STR("Frame", mdl->sub(sub).frame) + RV_INT("Frame range", mdl->sub(sub).frameRange) + RV_BLENDMODE("Blending mode", mdl->sub(sub).blendMode) + RV_INT("Skin", mdl->sub(sub).skin) + RV_URI("Skin file", &mdl->sub(sub).skinFilename, "Models") + RV_INT("Skin range", mdl->sub(sub).skinRange) + RV_VEC("Offset XYZ", mdl->sub(sub).offset, 3) + RV_FLAGS("Flags", mdl->sub(sub).flags, "df_") + RV_FLT("Transparent", mdl->sub(sub).alpha) + RV_FLT("Parm", mdl->sub(sub).parm) + RV_BYTE("Selskin mask", mdl->sub(sub).selSkinBits[0]) + RV_BYTE("Selskin shift", mdl->sub(sub).selSkinBits[1]) + RV_NBVEC("Selskins", mdl->sub(sub).selSkins, 8) + RV_URI("Shiny skin", &mdl->sub(sub).shinySkin, "Models") + RV_FLT("Shiny", mdl->sub(sub).shiny) + RV_VEC("Shiny color", mdl->sub(sub).shinyColor, 3) + RV_FLT("Shiny reaction", mdl->sub(sub).shinyReact) + RV_END + CHECKSC; + } + sub++; } - sub++; + else RV_END + CHECKSC; } - else RV_END - CHECKSC; - } - // Some post-processing. No point in doing this in a fancy way, - // the whole reader will be rewritten sooner or later... - if(prevModel) - { - if(!strcmp(mdl->state, "-")) - strcpy(mdl->state, prevModel->state); - if(!strcmp(mdl->sprite.id, "-")) - strcpy(mdl->sprite.id, prevModel->sprite.id); - //if(!strcmp(mdl->group, "-")) strcpy(mdl->group, prevModel->group); - //if(!strcmp(mdl->flags, "-")) strcpy(mdl->flags, prevModel->flags); - - for(uint i = 0; i < mdl->subCount(); ++i) + // Some post-processing. No point in doing this in a fancy way, + // the whole reader will be rewritten sooner or later... + if(prevModel) { - if(mdl->sub(i).filename && !Str_CompareIgnoreCase(mdl->sub(i).filename->pathStr(), "-")) - { - delete mdl->sub(i).filename; - mdl->sub(i).filename = NULL; - } - - if(mdl->sub(i).skinFilename && !Str_CompareIgnoreCase(mdl->sub(i).skinFilename->pathStr(), "-")) - { - delete mdl->sub(i).skinFilename; - mdl->sub(i).skinFilename = NULL; - } + if(!strcmp(mdl->state, "-")) + strcpy(mdl->state, prevModel->state); + if(!strcmp(mdl->sprite.id, "-")) + strcpy(mdl->sprite.id, prevModel->sprite.id); + //if(!strcmp(mdl->group, "-")) strcpy(mdl->group, prevModel->group); + //if(!strcmp(mdl->flags, "-")) strcpy(mdl->flags, prevModel->flags); - if(mdl->sub(i).shinySkin && !Str_CompareIgnoreCase(mdl->sub(i).shinySkin->pathStr(), "-")) + for(uint i = 0; i < mdl->subCount(); ++i) { - delete mdl->sub(i).shinySkin; - mdl->sub(i).shinySkin = NULL; - } - - if(!strcmp(mdl->sub(i).frame, "-")) - memset(mdl->sub(i).frame, 0, sizeof(ded_string_t)); - } - } + if(mdl->sub(i).filename && !Str_CompareIgnoreCase(mdl->sub(i).filename->pathStr(), "-")) + { + delete mdl->sub(i).filename; + mdl->sub(i).filename = NULL; + } - prevModelDefIdx = idx; - } + if(mdl->sub(i).skinFilename && !Str_CompareIgnoreCase(mdl->sub(i).skinFilename->pathStr(), "-")) + { + delete mdl->sub(i).skinFilename; + mdl->sub(i).skinFilename = NULL; + } - if(ISTOKEN("Sound")) - { // A new sound. - ded_sound_t* snd; + if(mdl->sub(i).shinySkin && !Str_CompareIgnoreCase(mdl->sub(i).shinySkin->pathStr(), "-")) + { + delete mdl->sub(i).shinySkin; + mdl->sub(i).shinySkin = NULL; + } - idx = DED_AddSound(ded, ""); - snd = &ded->sounds[idx]; + if(!strcmp(mdl->sub(i).frame, "-")) + memset(mdl->sub(i).frame, 0, sizeof(ded_string_t)); + } + } - FINDBEGIN; - for(;;) - { - READLABEL; - RV_STR("ID", snd->id) - RV_STR("Lump", snd->lumpName) - RV_STR("Name", snd->name) - RV_STR("Link", snd->link) - RV_INT("Link pitch", snd->linkPitch) - RV_INT("Link volume", snd->linkVolume) - RV_INT("Priority", snd->priority) - RV_INT("Max channels", snd->channels) - RV_INT("Group", snd->group) - RV_FLAGS("Flags", snd->flags, "sf_") - RV_URI("Ext", &snd->ext, "Sfx") - RV_URI("File", &snd->ext, "Sfx") - RV_URI("File name", &snd->ext, "Sfx") - RV_END - CHECKSC; + prevModelDefIdx = idx; } - } - if(ISTOKEN("Music")) - { // A new music. - ded_music_t* mus; + if(ISTOKEN("Sound")) + { // A new sound. + ded_sound_t* snd; - idx = DED_AddMusic(ded, ""); - mus = &ded->music[idx]; + idx = DED_AddSound(ded, ""); + snd = &ded->sounds[idx]; - FINDBEGIN; - for(;;) - { - READLABEL; - RV_STR("ID", mus->id) - RV_STR("Lump", mus->lumpName) - RV_URI("File name", &mus->path, "Music") - RV_URI("File", &mus->path, "Music") - RV_URI("Ext", &mus->path, "Music") // Both work. - RV_INT("CD track", mus->cdTrack) - RV_END - CHECKSC; + FINDBEGIN; + for(;;) + { + READLABEL; + RV_STR("ID", snd->id) + RV_STR("Lump", snd->lumpName) + RV_STR("Name", snd->name) + RV_STR("Link", snd->link) + RV_INT("Link pitch", snd->linkPitch) + RV_INT("Link volume", snd->linkVolume) + RV_INT("Priority", snd->priority) + RV_INT("Max channels", snd->channels) + RV_INT("Group", snd->group) + RV_FLAGS("Flags", snd->flags, "sf_") + RV_URI("Ext", &snd->ext, "Sfx") + RV_URI("File", &snd->ext, "Sfx") + RV_URI("File name", &snd->ext, "Sfx") + RV_END + CHECKSC; + } } - } - - if(ISTOKEN("Sky")) - { // A new sky definition. - ded_sky_t* sky; - uint sub = 0; - idx = DED_AddSky(ded, ""); - sky = &ded->skies[idx]; + if(ISTOKEN("Music")) + { // A new music. + ded_music_t* mus; - // Should we copy the previous definition? - if(prevSkyDefIdx >= 0 && bCopyNext) - { - ded_sky_t* prevSky = ded->skies + prevSkyDefIdx; - int i; + idx = DED_AddMusic(ded, ""); + mus = &ded->music[idx]; - memcpy(sky, prevSky, sizeof(*sky)); - for(i = 0; i < NUM_SKY_LAYERS; ++i) - { - if(sky->layers[i].material) - sky->layers[i].material = new de::Uri(*sky->layers[i].material); - } - for(i = 0; i < NUM_SKY_MODELS; ++i) + FINDBEGIN; + for(;;) { - sky->models[i].execute = sdup(sky->models[i].execute); + READLABEL; + RV_STR("ID", mus->id) + RV_STR("Lump", mus->lumpName) + RV_URI("File name", &mus->path, "Music") + RV_URI("File", &mus->path, "Music") + RV_URI("Ext", &mus->path, "Music") // Both work. + RV_INT("CD track", mus->cdTrack) + RV_END + CHECKSC; } } - prevSkyDefIdx = idx; - sub = 0; - FINDBEGIN; - for(;;) - { - READLABEL; - RV_STR("ID", sky->id) - RV_FLAGS("Flags", sky->flags, "sif_") - RV_FLT("Height", sky->height) - RV_FLT("Horizon offset", sky->horizonOffset) - RV_VEC("Light color", sky->color, 3) - if(ISLABEL("Layer 1") || ISLABEL("Layer 2")) + if(ISTOKEN("Sky")) + { // A new sky definition. + ded_sky_t* sky; + uint sub = 0; + + idx = DED_AddSky(ded, ""); + sky = &ded->skies[idx]; + + // Should we copy the previous definition? + if(prevSkyDefIdx >= 0 && bCopyNext) { - ded_skylayer_t *sl = sky->layers + atoi(label+6) - 1; - FINDBEGIN; - for(;;) + ded_sky_t* prevSky = ded->skies + prevSkyDefIdx; + int i; + + memcpy(sky, prevSky, sizeof(*sky)); + for(i = 0; i < NUM_SKY_LAYERS; ++i) { - READLABEL; - RV_URI("Material", &sl->material, 0) - RV_URI("Texture", &sl->material, "Textures" ) - RV_FLAGS("Flags", sl->flags, "slf_") - RV_FLT("Offset", sl->offset) - RV_FLT("Color limit", sl->colorLimit) - RV_END - CHECKSC; + if(sky->layers[i].material) + sky->layers[i].material = new de::Uri(*sky->layers[i].material); + } + for(i = 0; i < NUM_SKY_MODELS; ++i) + { + sky->models[i].execute = sdup(sky->models[i].execute); } } - else if(ISLABEL("Model")) + prevSkyDefIdx = idx; + sub = 0; + + FINDBEGIN; + for(;;) { - ded_skymodel_t *sm = &sky->models[sub]; - if(sub == NUM_SKY_MODELS) - { // Too many! - DED_SetError("Too many Sky models."); - retVal = false; - goto ded_end_read; + READLABEL; + RV_STR("ID", sky->id) + RV_FLAGS("Flags", sky->flags, "sif_") + RV_FLT("Height", sky->height) + RV_FLT("Horizon offset", sky->horizonOffset) + RV_VEC("Light color", sky->color, 3) + if(ISLABEL("Layer 1") || ISLABEL("Layer 2")) + { + ded_skylayer_t *sl = sky->layers + atoi(label+6) - 1; + FINDBEGIN; + for(;;) + { + READLABEL; + RV_URI("Material", &sl->material, 0) + RV_URI("Texture", &sl->material, "Textures" ) + RV_FLAGS("Flags", sl->flags, "slf_") + RV_FLT("Offset", sl->offset) + RV_FLT("Color limit", sl->colorLimit) + RV_END + CHECKSC; + } } - sub++; - - FINDBEGIN; - for(;;) + else if(ISLABEL("Model")) { - READLABEL; - RV_STR("ID", sm->id) - RV_INT("Layer", sm->layer) - RV_FLT("Frame interval", sm->frameInterval) - RV_FLT("Yaw", sm->yaw) - RV_FLT("Yaw speed", sm->yawSpeed) - RV_VEC("Rotate", sm->rotate, 2) - RV_VEC("Offset factor", sm->coordFactor, 3) - RV_VEC("Color", sm->color, 4) - RV_ANYSTR("Execute", sm->execute) - RV_END - CHECKSC; + ded_skymodel_t *sm = &sky->models[sub]; + if(sub == NUM_SKY_MODELS) + { // Too many! + setError("Too many Sky models."); + retVal = false; + goto ded_end_read; + } + sub++; + + FINDBEGIN; + for(;;) + { + READLABEL; + RV_STR("ID", sm->id) + RV_INT("Layer", sm->layer) + RV_FLT("Frame interval", sm->frameInterval) + RV_FLT("Yaw", sm->yaw) + RV_FLT("Yaw speed", sm->yawSpeed) + RV_VEC("Rotate", sm->rotate, 2) + RV_VEC("Offset factor", sm->coordFactor, 3) + RV_VEC("Color", sm->color, 4) + RV_ANYSTR("Execute", sm->execute) + RV_END + CHECKSC; + } } + else RV_END + CHECKSC; } - else RV_END - CHECKSC; } - } - if(ISTOKEN("Map")) // Info - { // A new map info. - uint sub; - ded_mapinfo_t* mi; + if(ISTOKEN("Map")) // Info + { // A new map info. + uint sub; + ded_mapinfo_t* mi; - idx = DED_AddMapInfo(ded, NULL); - mi = &ded->mapInfo[idx]; + idx = DED_AddMapInfo(ded, NULL); + mi = &ded->mapInfo[idx]; - // Should we copy the previous definition? - if(prevMapInfoDefIdx >= 0 && bCopyNext) - { - const ded_mapinfo_t* prevMapInfo = ded->mapInfo + prevMapInfoDefIdx; - de::Uri *uri = mi->uri; - int i; - - memcpy(mi, prevMapInfo, sizeof(*mi)); - mi->uri = uri; - if(prevMapInfo->uri) - { - if(mi->uri) - *mi->uri = *prevMapInfo->uri; - else - mi->uri = new de::Uri(*prevMapInfo->uri); - } - - mi->execute = sdup(mi->execute); - for(i = 0; i < NUM_SKY_LAYERS; ++i) - { - if(mi->sky.layers[i].material) - mi->sky.layers[i].material = new de::Uri(*mi->sky.layers[i].material); - } - for(i = 0; i < NUM_SKY_MODELS; ++i) - { - mi->sky.models[i].execute = sdup(mi->sky.models[i].execute); - } - } - prevMapInfoDefIdx = idx; - sub = 0; - - FINDBEGIN; - for(;;) - { - READLABEL; - RV_URI("ID", &mi->uri, NULL) - RV_STR("Name", mi->name) - RV_STR("Author", mi->author) - RV_FLAGS("Flags", mi->flags, "mif_") - RV_STR("Music", mi->music) - RV_FLT("Par time", mi->parTime) - RV_FLT("Fog color R", mi->fogColor[0]) - RV_FLT("Fog color G", mi->fogColor[1]) - RV_FLT("Fog color B", mi->fogColor[2]) - RV_FLT("Fog start", mi->fogStart) - RV_FLT("Fog end", mi->fogEnd) - RV_FLT("Fog density", mi->fogDensity) - RV_FLT("Ambient light", mi->ambient) - RV_FLT("Gravity", mi->gravity) - RV_ANYSTR("Execute", mi->execute) - RV_STR("Sky", mi->skyID) - RV_FLT("Sky height", mi->sky.height) - RV_FLT("Horizon offset", mi->sky.horizonOffset) - RV_VEC("Sky light color", mi->sky.color, 3) - if(ISLABEL("Sky Layer 1") || ISLABEL("Sky Layer 2")) - { - ded_skylayer_t *sl = mi->sky.layers + atoi(label+10) - 1; - FINDBEGIN; - for(;;) - { - READLABEL; - RV_URI("Material", &sl->material, 0) - RV_URI("Texture", &sl->material, "Textures") - RV_FLAGS("Flags", sl->flags, "slf_") - RV_FLT("Offset", sl->offset) - RV_FLT("Color limit", sl->colorLimit) - RV_END - CHECKSC; - } - } - else if(ISLABEL("Sky Model")) + // Should we copy the previous definition? + if(prevMapInfoDefIdx >= 0 && bCopyNext) { - ded_skymodel_t *sm = &mi->sky.models[sub]; - if(sub == NUM_SKY_MODELS) - { // Too many! - DED_SetError("Too many Sky models."); - retVal = false; - goto ded_end_read; - } - sub++; + const ded_mapinfo_t* prevMapInfo = ded->mapInfo + prevMapInfoDefIdx; + de::Uri *uri = mi->uri; + int i; - FINDBEGIN; - for(;;) + memcpy(mi, prevMapInfo, sizeof(*mi)); + mi->uri = uri; + if(prevMapInfo->uri) { - READLABEL; - RV_STR("ID", sm->id) - RV_INT("Layer", sm->layer) - RV_FLT("Frame interval", sm->frameInterval) - RV_FLT("Yaw", sm->yaw) - RV_FLT("Yaw speed", sm->yawSpeed) - RV_VEC("Rotate", sm->rotate, 2) - RV_VEC("Offset factor", sm->coordFactor, 3) - RV_VEC("Color", sm->color, 4) - RV_ANYSTR("Execute", sm->execute) - RV_END - CHECKSC; + if(mi->uri) + *mi->uri = *prevMapInfo->uri; + else + mi->uri = new de::Uri(*prevMapInfo->uri); } - } - else RV_END - CHECKSC; - } - } - if(ISTOKEN("Text")) - { - // A new text. - idx = DED_AddText(ded, ""); - ded_text_t *txt = &ded->text[idx]; - - FINDBEGIN; - for(;;) - { - READLABEL; - RV_STR("ID", txt->id) - if(ISLABEL("Text")) - { - String buffer; - if(ReadString(buffer)) + mi->execute = sdup(mi->execute); + for(i = 0; i < NUM_SKY_LAYERS; ++i) { - QByteArray bufferUtf8 = buffer.toUtf8(); - txt->text = (char *) M_Realloc(txt->text, bufferUtf8.length() + 1); - qstrcpy(txt->text, bufferUtf8.constData()); + if(mi->sky.layers[i].material) + mi->sky.layers[i].material = new de::Uri(*mi->sky.layers[i].material); } - else + for(i = 0; i < NUM_SKY_MODELS; ++i) { - DED_SetError("Syntax error in Text value."); - retVal = false; - goto ded_end_read; + mi->sky.models[i].execute = sdup(mi->sky.models[i].execute); } } - else RV_END - CHECKSC; - } - } - - if(ISTOKEN("Texture")) - { - ReadToken(); - if(ISTOKEN("Environment")) - { // A new environment. - ded_tenviron_t* tenv; - - idx = DED_AddTextureEnv(ded, ""); - tenv = &ded->textureEnv[idx]; + prevMapInfoDefIdx = idx; + sub = 0; FINDBEGIN; for(;;) { - de::Uri **mn; - READLABEL; - RV_STR("ID", tenv->id) - if(ISLABEL("Material") || ISLABEL("Texture") || ISLABEL("Flat")) + RV_URI("ID", &mi->uri, NULL) + RV_STR("Name", mi->name) + RV_STR("Author", mi->author) + RV_FLAGS("Flags", mi->flags, "mif_") + RV_STR("Music", mi->music) + RV_FLT("Par time", mi->parTime) + RV_FLT("Fog color R", mi->fogColor[0]) + RV_FLT("Fog color G", mi->fogColor[1]) + RV_FLT("Fog color B", mi->fogColor[2]) + RV_FLT("Fog start", mi->fogStart) + RV_FLT("Fog end", mi->fogEnd) + RV_FLT("Fog density", mi->fogDensity) + RV_FLT("Ambient light", mi->ambient) + RV_FLT("Gravity", mi->gravity) + RV_ANYSTR("Execute", mi->execute) + RV_STR("Sky", mi->skyID) + RV_FLT("Sky height", mi->sky.height) + RV_FLT("Horizon offset", mi->sky.horizonOffset) + RV_VEC("Sky light color", mi->sky.color, 3) + if(ISLABEL("Sky Layer 1") || ISLABEL("Sky Layer 2")) { - // A new material path. - ddstring_t schemeName; Str_Init(&schemeName); - Str_Set(&schemeName, ISLABEL("Material")? "" : ISLABEL("Texture")? "Textures" : "Flats"); - mn = (de::Uri **) DED_NewEntry((void **)&tenv->materials, &tenv->count, sizeof(*mn)); + ded_skylayer_t *sl = mi->sky.layers + atoi(label+10) - 1; FINDBEGIN; for(;;) { READLABEL; - RV_URI("ID", mn, Str_Text(&schemeName)) + RV_URI("Material", &sl->material, 0) + RV_URI("Texture", &sl->material, "Textures") + RV_FLAGS("Flags", sl->flags, "slf_") + RV_FLT("Offset", sl->offset) + RV_FLT("Color limit", sl->colorLimit) + RV_END + CHECKSC; + } + } + else if(ISLABEL("Sky Model")) + { + ded_skymodel_t *sm = &mi->sky.models[sub]; + if(sub == NUM_SKY_MODELS) + { // Too many! + setError("Too many Sky models."); + retVal = false; + goto ded_end_read; + } + sub++; + + FINDBEGIN; + for(;;) + { + READLABEL; + RV_STR("ID", sm->id) + RV_INT("Layer", sm->layer) + RV_FLT("Frame interval", sm->frameInterval) + RV_FLT("Yaw", sm->yaw) + RV_FLT("Yaw speed", sm->yawSpeed) + RV_VEC("Rotate", sm->rotate, 2) + RV_VEC("Offset factor", sm->coordFactor, 3) + RV_VEC("Color", sm->color, 4) + RV_ANYSTR("Execute", sm->execute) RV_END CHECKSC; } - Str_Free(&schemeName); } else RV_END CHECKSC; } } - } - if(ISTOKEN("Composite")) - { - ReadToken(); - if(ISTOKEN("BitmapFont")) + if(ISTOKEN("Text")) { - ded_compositefont_t* cfont; - - idx = DED_AddCompositeFont(ded, NULL); - cfont = &ded->compositeFonts[idx]; + // A new text. + idx = DED_AddText(ded, ""); + ded_text_t *txt = &ded->text[idx]; FINDBEGIN; for(;;) { READLABEL; - if(ISLABEL("ID")) + RV_STR("ID", txt->id) + if(ISLABEL("Text")) { - READURI(&cfont->uri, "Game") - CHECKSC; - } - else if(M_IsStringValidInt(label)) - { - ded_compositefont_mappedcharacter_t* mc = 0; - int ascii = atoi(label); - if(ascii < 0 || ascii > 255) + String buffer; + if(ReadString(buffer)) + { + QByteArray bufferUtf8 = buffer.toUtf8(); + txt->text = (char *) M_Realloc(txt->text, bufferUtf8.length() + 1); + qstrcpy(txt->text, bufferUtf8.constData()); + } + else { - DED_SetError("Invalid ascii code."); + setError("Syntax error in Text value."); retVal = false; goto ded_end_read; } + } + else RV_END + CHECKSC; + } + } - { int i; - for(i = 0; i < cfont->charMapCount.num; ++i) - if(cfont->charMap[i].ch == (unsigned char) ascii) - mc = &cfont->charMap[i]; - } + if(ISTOKEN("Texture")) + { + ReadToken(); + if(ISTOKEN("Environment")) + { // A new environment. + ded_tenviron_t* tenv; - if(mc == 0) - { - mc = (ded_compositefont_mappedcharacter_t*) DED_NewEntry((void**)&cfont->charMap, &cfont->charMapCount, sizeof(*mc)); - mc->ch = ascii; - } + idx = DED_AddTextureEnv(ded, ""); + tenv = &ded->textureEnv[idx]; - FINDBEGIN; - for(;;) + FINDBEGIN; + for(;;) + { + de::Uri **mn; + + READLABEL; + RV_STR("ID", tenv->id) + if(ISLABEL("Material") || ISLABEL("Texture") || ISLABEL("Flat")) { - READLABEL; - RV_URI("Texture", &mc->path, "Patches") - RV_END - CHECKSC; + // A new material path. + ddstring_t schemeName; Str_Init(&schemeName); + Str_Set(&schemeName, ISLABEL("Material")? "" : ISLABEL("Texture")? "Textures" : "Flats"); + mn = (de::Uri **) DED_NewEntry((void **)&tenv->materials, &tenv->count, sizeof(*mn)); + FINDBEGIN; + for(;;) + { + READLABEL; + RV_URI("ID", mn, Str_Text(&schemeName)) + RV_END + CHECKSC; + } + Str_Free(&schemeName); } + else RV_END + CHECKSC; } - else - RV_END } } - } - if(ISTOKEN("Values")) // String Values - { - depth = 0; - rootStr = (char*) M_Calloc(1); // A null string. - - FINDBEGIN; - for(;;) + if(ISTOKEN("Composite")) { - // Get the next label but don't stop on }. - READLABEL_NOBREAK; - if(strchr(label, '|')) + ReadToken(); + if(ISTOKEN("BitmapFont")) { - DED_SetError("Value labels can not include '|' characters (ASCII 124)."); - retVal = false; - goto ded_end_read; - } + ded_compositefont_t* cfont; - if(ISTOKEN("=")) - { - // Define a new string. - String buffer; + idx = DED_AddCompositeFont(ded, NULL); + cfont = &ded->compositeFonts[idx]; - if(ReadString(buffer)) + FINDBEGIN; + for(;;) { - // Get a new value entry. - idx = DED_AddValue(ded, 0); - ded_value_t *val = &ded->values[idx]; + READLABEL; + if(ISLABEL("ID")) + { + READURI(&cfont->uri, "Game") + CHECKSC; + } + else if(M_IsStringValidInt(label)) + { + ded_compositefont_mappedcharacter_t* mc = 0; + int ascii = atoi(label); + if(ascii < 0 || ascii > 255) + { + setError("Invalid ascii code."); + retVal = false; + goto ded_end_read; + } - QByteArray bufferUtf8 = buffer.toUtf8(); - val->text = (char *) M_Malloc(bufferUtf8.length() + 1); - qstrcpy(val->text, bufferUtf8.constData()); + { int i; + for(i = 0; i < cfont->charMapCount.num; ++i) + if(cfont->charMap[i].ch == (unsigned char) ascii) + mc = &cfont->charMap[i]; + } + + if(mc == 0) + { + mc = (ded_compositefont_mappedcharacter_t*) DED_NewEntry((void**)&cfont->charMap, &cfont->charMapCount, sizeof(*mc)); + mc->ch = ascii; + } - // Compose the identifier. - val->id = (char *) M_Malloc(strlen(rootStr) + strlen(label) + 1); - strcpy(val->id, rootStr); - strcat(val->id, label); + FINDBEGIN; + for(;;) + { + READLABEL; + RV_URI("Texture", &mc->path, "Patches") + RV_END + CHECKSC; + } + } + else + RV_END } - else + } + } + + if(ISTOKEN("Values")) // String Values + { + depth = 0; + rootStr = (char*) M_Calloc(1); // A null string. + + FINDBEGIN; + for(;;) + { + // Get the next label but don't stop on }. + READLABEL_NOBREAK; + if(strchr(label, '|')) { - DED_SetError("Syntax error in Value string."); + setError("Value labels can not include '|' characters (ASCII 124)."); retVal = false; goto ded_end_read; } - } - else if(ISTOKEN("{")) - { - // Begin a new group. - rootStr = (char*) M_Realloc(rootStr, strlen(rootStr) + strlen(label) + 2); - strcat(rootStr, label); - strcat(rootStr, "|"); // The separator. - // Increase group level. - depth++; - continue; - } - else if(ISTOKEN("}")) - { - size_t len; - // End group. - if(!depth) - break; // End root depth. + if(ISTOKEN("=")) + { + // Define a new string. + String buffer; - // Decrease level and modify rootStr. - depth--; - len = strlen(rootStr); - rootStr[len-1] = 0; // Remove last |. - ptr = strrchr(rootStr, '|'); - if(ptr) + if(ReadString(buffer)) + { + // Get a new value entry. + idx = DED_AddValue(ded, 0); + ded_value_t *val = &ded->values[idx]; + + QByteArray bufferUtf8 = buffer.toUtf8(); + val->text = (char *) M_Malloc(bufferUtf8.length() + 1); + qstrcpy(val->text, bufferUtf8.constData()); + + // Compose the identifier. + val->id = (char *) M_Malloc(strlen(rootStr) + strlen(label) + 1); + strcpy(val->id, rootStr); + strcat(val->id, label); + } + else + { + setError("Syntax error in Value string."); + retVal = false; + goto ded_end_read; + } + } + else if(ISTOKEN("{")) + { + // Begin a new group. + rootStr = (char*) M_Realloc(rootStr, strlen(rootStr) + strlen(label) + 2); + strcat(rootStr, label); + strcat(rootStr, "|"); // The separator. + // Increase group level. + depth++; + continue; + } + else if(ISTOKEN("}")) { - ptr[1] = 0; - rootStr = (char*) M_Realloc(rootStr, strlen(rootStr) + 1); + size_t len; + + // End group. + if(!depth) + break; // End root depth. + + // Decrease level and modify rootStr. + depth--; + len = strlen(rootStr); + rootStr[len-1] = 0; // Remove last |. + ptr = strrchr(rootStr, '|'); + if(ptr) + { + ptr[1] = 0; + rootStr = (char*) M_Realloc(rootStr, strlen(rootStr) + 1); + } + else + { + // Back to level zero. + rootStr = (char*) M_Realloc(rootStr, 1); + *rootStr = 0; + } } else { - // Back to level zero. - rootStr = (char*) M_Realloc(rootStr, 1); - *rootStr = 0; + // Only the above characters are allowed. + setError("Illegal token."); + retVal = false; + goto ded_end_read; } + CHECKSC; } - else - { - // Only the above characters are allowed. - DED_SetError("Illegal token."); - retVal = false; - goto ded_end_read; - } - CHECKSC; + M_Free(rootStr); + rootStr = 0; } - M_Free(rootStr); - rootStr = 0; - } - - if(ISTOKEN("Detail")) // Detail Texture - { - idx = DED_AddDetail(ded, ""); - ded_detailtexture_t *dtl = &ded->details[idx]; - // Should we copy the previous definition? - if(prevDetailDefIdx >= 0 && bCopyNext) + if(ISTOKEN("Detail")) // Detail Texture { - ded_detailtexture_t const *prevDetail = ded->details + prevDetailDefIdx; + idx = DED_AddDetail(ded, ""); + ded_detailtexture_t *dtl = &ded->details[idx]; - std::memcpy(dtl, prevDetail, sizeof(*dtl)); + // Should we copy the previous definition? + if(prevDetailDefIdx >= 0 && bCopyNext) + { + ded_detailtexture_t const *prevDetail = ded->details + prevDetailDefIdx; - if(dtl->material1) dtl->material1 = new de::Uri(*dtl->material1); - if(dtl->material2) dtl->material2 = new de::Uri(*dtl->material2); - if(dtl->stage.texture) dtl->stage.texture = new de::Uri(*dtl->stage.texture); - } + std::memcpy(dtl, prevDetail, sizeof(*dtl)); - FINDBEGIN; - for(;;) - { - READLABEL; - RV_FLAGS("Flags", dtl->flags, "dtf_") - if(ISLABEL("Texture")) - { - READURI(&dtl->material1, "Textures") + if(dtl->material1) dtl->material1 = new de::Uri(*dtl->material1); + if(dtl->material2) dtl->material2 = new de::Uri(*dtl->material2); + if(dtl->stage.texture) dtl->stage.texture = new de::Uri(*dtl->stage.texture); } - else if(ISLABEL("Wall")) // Alias - { - READURI(&dtl->material1, "Textures") - } - else if(ISLABEL("Flat")) - { - READURI(&dtl->material2, "Flats") - } - else if(ISLABEL("Lump")) - { - READURI(&dtl->stage.texture, "Lumps") - } - else if(ISLABEL("File")) + + FINDBEGIN; + for(;;) { - READURI(&dtl->stage.texture, 0) + READLABEL; + RV_FLAGS("Flags", dtl->flags, "dtf_") + if(ISLABEL("Texture")) + { + READURI(&dtl->material1, "Textures") + } + else if(ISLABEL("Wall")) // Alias + { + READURI(&dtl->material1, "Textures") + } + else if(ISLABEL("Flat")) + { + READURI(&dtl->material2, "Flats") + } + else if(ISLABEL("Lump")) + { + READURI(&dtl->stage.texture, "Lumps") + } + else if(ISLABEL("File")) + { + READURI(&dtl->stage.texture, 0) + } + else + RV_FLT("Scale", dtl->stage.scale) + RV_FLT("Strength", dtl->stage.strength) + RV_FLT("Distance", dtl->stage.maxDistance) + RV_END + CHECKSC; } - else - RV_FLT("Scale", dtl->stage.scale) - RV_FLT("Strength", dtl->stage.strength) - RV_FLT("Distance", dtl->stage.maxDistance) - RV_END - CHECKSC; + prevDetailDefIdx = idx; } - prevDetailDefIdx = idx; - } - - if(ISTOKEN("Reflection")) // Surface reflection - { - ded_reflection_t* ref = 0; - idx = DED_AddReflection(ded); - ref = &ded->reflections[idx]; - - // Should we copy the previous definition? - if(prevRefDefIdx >= 0 && bCopyNext) + if(ISTOKEN("Reflection")) // Surface reflection { - const ded_reflection_t* prevRef = ded->reflections + prevRefDefIdx; - - memcpy(ref, prevRef, sizeof(*ref)); + ded_reflection_t* ref = 0; - if(ref->material) ref->material = new de::Uri(*ref->material); - if(ref->stage.texture) ref->stage.texture = new de::Uri(*ref->stage.texture); - if(ref->stage.maskTexture) ref->stage.maskTexture = new de::Uri(*ref->stage.maskTexture); - } + idx = DED_AddReflection(ded); + ref = &ded->reflections[idx]; - FINDBEGIN; - for(;;) - { - READLABEL; - RV_FLAGS("Flags", ref->flags, "rff_") - RV_FLT("Shininess", ref->stage.shininess) - RV_VEC("Min color", ref->stage.minColor, 3) - RV_BLENDMODE("Blending mode", ref->stage.blendMode) - RV_URI("Shiny map", &ref->stage.texture, "LightMaps") - RV_URI("Mask map", &ref->stage.maskTexture, "LightMaps") - RV_FLT("Mask width", ref->stage.maskWidth) - RV_FLT("Mask height", ref->stage.maskHeight) - if(ISLABEL("Material")) - { - READURI(&ref->material, 0) - } - else if(ISLABEL("Texture")) + // Should we copy the previous definition? + if(prevRefDefIdx >= 0 && bCopyNext) { - READURI(&ref->material, "Textures") + const ded_reflection_t* prevRef = ded->reflections + prevRefDefIdx; + + memcpy(ref, prevRef, sizeof(*ref)); + + if(ref->material) ref->material = new de::Uri(*ref->material); + if(ref->stage.texture) ref->stage.texture = new de::Uri(*ref->stage.texture); + if(ref->stage.maskTexture) ref->stage.maskTexture = new de::Uri(*ref->stage.maskTexture); } - else if(ISLABEL("Flat")) + + FINDBEGIN; + for(;;) { - READURI(&ref->material, "Flats") + READLABEL; + RV_FLAGS("Flags", ref->flags, "rff_") + RV_FLT("Shininess", ref->stage.shininess) + RV_VEC("Min color", ref->stage.minColor, 3) + RV_BLENDMODE("Blending mode", ref->stage.blendMode) + RV_URI("Shiny map", &ref->stage.texture, "LightMaps") + RV_URI("Mask map", &ref->stage.maskTexture, "LightMaps") + RV_FLT("Mask width", ref->stage.maskWidth) + RV_FLT("Mask height", ref->stage.maskHeight) + if(ISLABEL("Material")) + { + READURI(&ref->material, 0) + } + else if(ISLABEL("Texture")) + { + READURI(&ref->material, "Textures") + } + else if(ISLABEL("Flat")) + { + READURI(&ref->material, "Flats") + } + else RV_END + CHECKSC; } - else RV_END - CHECKSC; + prevRefDefIdx = idx; } - prevRefDefIdx = idx; - } - if(ISTOKEN("Generator")) // Particle Generator - { - ded_ptcgen_t* gen; - int sub = 0; + if(ISTOKEN("Generator")) // Particle Generator + { + ded_ptcgen_t* gen; + int sub = 0; - idx = DED_AddPtcGen(ded, ""); - gen = &ded->ptcGens[idx]; + idx = DED_AddPtcGen(ded, ""); + gen = &ded->ptcGens[idx]; - // Should we copy the previous definition? - if(prevGenDefIdx >= 0 && bCopyNext) - { - const ded_ptcgen_t* prevGen = ded->ptcGens + prevGenDefIdx; + // Should we copy the previous definition? + if(prevGenDefIdx >= 0 && bCopyNext) + { + const ded_ptcgen_t* prevGen = ded->ptcGens + prevGenDefIdx; - memcpy(gen, prevGen, sizeof(*gen)); + memcpy(gen, prevGen, sizeof(*gen)); - if(gen->map) gen->map = new de::Uri(*gen->map); - if(gen->material) gen->material = new de::Uri(*gen->material); + if(gen->map) gen->map = new de::Uri(*gen->map); + if(gen->material) gen->material = new de::Uri(*gen->material); - // Duplicate the stages array. - if(gen->stages) - { - gen->stages = (ded_ptcstage_t*) M_Malloc(sizeof(ded_ptcstage_t) * gen->stageCount.max); - memcpy(gen->stages, prevGen->stages, sizeof(ded_ptcstage_t) * gen->stageCount.num); + // Duplicate the stages array. + if(gen->stages) + { + gen->stages = (ded_ptcstage_t*) M_Malloc(sizeof(ded_ptcstage_t) * gen->stageCount.max); + memcpy(gen->stages, prevGen->stages, sizeof(ded_ptcstage_t) * gen->stageCount.num); + } } - } - FINDBEGIN; - for(;;) - { - READLABEL; - RV_STR("State", gen->state) - if(ISLABEL("Material")) - { - READURI(&gen->material, 0) - } - else if(ISLABEL("Flat")) - { - READURI(&gen->material, "Flats") - } - else if(ISLABEL("Texture")) - { - READURI(&gen->material, "Textures") - } - else - RV_STR("Mobj", gen->type) - RV_STR("Alt mobj", gen->type2) - RV_STR("Damage mobj", gen->damage) - RV_URI("Map", &gen->map, NULL) - RV_FLAGS("Flags", gen->flags, "gnf_") - RV_FLT("Speed", gen->speed) - RV_FLT("Speed Rnd", gen->speedVariance) - RV_VEC("Vector", gen->vector, 3) - RV_FLT("Vector Rnd", gen->vectorVariance) - RV_FLT("Init vector Rnd", gen->initVectorVariance) - RV_VEC("Center", gen->center, 3) - RV_INT("Submodel", gen->subModel) - RV_FLT("Spawn radius", gen->spawnRadius) - RV_FLT("Min spawn radius", gen->spawnRadiusMin) - RV_FLT("Distance", gen->maxDist) - RV_INT("Spawn age", gen->spawnAge) - RV_INT("Max age", gen->maxAge) - RV_INT("Particles", gen->particles) - RV_FLT("Spawn rate", gen->spawnRate) - RV_FLT("Spawn Rnd", gen->spawnRateVariance) - RV_INT("Presim", gen->preSim) - RV_INT("Alt start", gen->altStart) - RV_FLT("Alt Rnd", gen->altStartVariance) - RV_VEC("Force axis", gen->forceAxis, 3) - RV_FLT("Force radius", gen->forceRadius) - RV_FLT("Force", gen->force) - RV_VEC("Force origin", gen->forceOrigin, 3) - if(ISLABEL("Stage")) + FINDBEGIN; + for(;;) { - ded_ptcstage_t *st = NULL; - - if(sub >= gen->stageCount.num) + READLABEL; + RV_STR("State", gen->state) + if(ISLABEL("Material")) { - // Allocate new stage. - sub = DED_AddPtcGenStage(gen); + READURI(&gen->material, 0) } + else if(ISLABEL("Flat")) + { + READURI(&gen->material, "Flats") + } + else if(ISLABEL("Texture")) + { + READURI(&gen->material, "Textures") + } + else + RV_STR("Mobj", gen->type) + RV_STR("Alt mobj", gen->type2) + RV_STR("Damage mobj", gen->damage) + RV_URI("Map", &gen->map, NULL) + RV_FLAGS("Flags", gen->flags, "gnf_") + RV_FLT("Speed", gen->speed) + RV_FLT("Speed Rnd", gen->speedVariance) + RV_VEC("Vector", gen->vector, 3) + RV_FLT("Vector Rnd", gen->vectorVariance) + RV_FLT("Init vector Rnd", gen->initVectorVariance) + RV_VEC("Center", gen->center, 3) + RV_INT("Submodel", gen->subModel) + RV_FLT("Spawn radius", gen->spawnRadius) + RV_FLT("Min spawn radius", gen->spawnRadiusMin) + RV_FLT("Distance", gen->maxDist) + RV_INT("Spawn age", gen->spawnAge) + RV_INT("Max age", gen->maxAge) + RV_INT("Particles", gen->particles) + RV_FLT("Spawn rate", gen->spawnRate) + RV_FLT("Spawn Rnd", gen->spawnRateVariance) + RV_INT("Presim", gen->preSim) + RV_INT("Alt start", gen->altStart) + RV_FLT("Alt Rnd", gen->altStartVariance) + RV_VEC("Force axis", gen->forceAxis, 3) + RV_FLT("Force radius", gen->forceRadius) + RV_FLT("Force", gen->force) + RV_VEC("Force origin", gen->forceOrigin, 3) + if(ISLABEL("Stage")) + { + ded_ptcstage_t *st = NULL; + + if(sub >= gen->stageCount.num) + { + // Allocate new stage. + sub = DED_AddPtcGenStage(gen); + } - st = &gen->stages[sub]; + st = &gen->stages[sub]; - FINDBEGIN; - for(;;) - { - READLABEL; - RV_FLAGS("Type", st->type, "pt_") - RV_INT("Tics", st->tics) - RV_FLT("Rnd", st->variance) - RV_VEC("Color", st->color, 4) - RV_FLT("Radius", st->radius) - RV_FLT("Radius rnd", st->radiusVariance) - RV_FLAGS("Flags", st->flags, "ptf_") - RV_FLT("Bounce", st->bounce) - RV_FLT("Gravity", st->gravity) - RV_FLT("Resistance", st->resistance) - RV_STR("Frame", st->frameName) - RV_STR("End frame", st->endFrameName) - RV_VEC("Spin", st->spin, 2) - RV_VEC("Spin resistance", st->spinResistance, 2) - RV_STR("Sound", st->sound.name) - RV_FLT("Volume", st->sound.volume) - RV_STR("Hit sound", st->hitSound.name) - RV_FLT("Hit volume", st->hitSound.volume) - RV_VEC("Force", st->vectorForce, 3) - RV_END - CHECKSC; + FINDBEGIN; + for(;;) + { + READLABEL; + RV_FLAGS("Type", st->type, "pt_") + RV_INT("Tics", st->tics) + RV_FLT("Rnd", st->variance) + RV_VEC("Color", st->color, 4) + RV_FLT("Radius", st->radius) + RV_FLT("Radius rnd", st->radiusVariance) + RV_FLAGS("Flags", st->flags, "ptf_") + RV_FLT("Bounce", st->bounce) + RV_FLT("Gravity", st->gravity) + RV_FLT("Resistance", st->resistance) + RV_STR("Frame", st->frameName) + RV_STR("End frame", st->endFrameName) + RV_VEC("Spin", st->spin, 2) + RV_VEC("Spin resistance", st->spinResistance, 2) + RV_STR("Sound", st->sound.name) + RV_FLT("Volume", st->sound.volume) + RV_STR("Hit sound", st->hitSound.name) + RV_FLT("Hit volume", st->hitSound.volume) + RV_VEC("Force", st->vectorForce, 3) + RV_END + CHECKSC; + } + sub++; } - sub++; + else RV_END + CHECKSC; } - else RV_END - CHECKSC; + prevGenDefIdx = idx; } - prevGenDefIdx = idx; - } - - if(ISTOKEN("Finale") || ISTOKEN("InFine")) - { - idx = DED_AddFinale(ded); - ded_finale_t *fin = &ded->finales[idx]; - FINDBEGIN; - for(;;) + if(ISTOKEN("Finale") || ISTOKEN("InFine")) { - READLABEL; - RV_STR("ID", fin->id) - RV_URI("Before", &fin->before, NULL) - RV_URI("After", &fin->after, NULL) - RV_INT("Game", dummyInt) - if(ISLABEL("Script")) - { - String buffer; buffer.reserve(1600); + idx = DED_AddFinale(ded); + ded_finale_t *fin = &ded->finales[idx]; - FINDBEGIN; - ReadToken(); - while(!ISTOKEN("}") && !source->atEnd) + FINDBEGIN; + for(;;) + { + READLABEL; + RV_STR("ID", fin->id) + RV_URI("Before", &fin->before, NULL) + RV_URI("After", &fin->after, NULL) + RV_INT("Game", dummyInt) + if(ISLABEL("Script")) { - if(!buffer.isEmpty()) - buffer += ' '; + String buffer; buffer.reserve(1600); - buffer += String(token); - if(ISTOKEN("\"")) + FINDBEGIN; + ReadToken(); + while(!ISTOKEN("}") && !source->atEnd) { - ReadString(buffer, true, true); - buffer += '"'; + if(!buffer.isEmpty()) + buffer += ' '; + + buffer += String(token); + if(ISTOKEN("\"")) + { + ReadString(buffer, true, true); + buffer += '"'; + } + ReadToken(); } - ReadToken(); + QByteArray bufferUtf8 = buffer.toUtf8(); + fin->script = (char *) M_Realloc(fin->script, bufferUtf8.length() + 1); + qstrcpy(fin->script, bufferUtf8.constData()); } - QByteArray bufferUtf8 = buffer.toUtf8(); - fin->script = (char *) M_Realloc(fin->script, bufferUtf8.length() + 1); - qstrcpy(fin->script, bufferUtf8.constData()); + else RV_END + CHECKSC; } - else RV_END - CHECKSC; } - } - - // An oldschool (light) decoration definition? - if(ISTOKEN("Decoration")) - { - idx = DED_AddDecoration(ded); - ded_decor_t *decor = &ded->decorations[idx]; - // Should we copy the previous definition? - if(prevDecorDefIdx >= 0 && bCopyNext) + // An oldschool (light) decoration definition? + if(ISTOKEN("Decoration")) { - ded_decor_t const *prevDecor = ded->decorations + prevDecorDefIdx; - - std::memcpy(decor, prevDecor, sizeof(*decor)); - if(decor->material) decor->material = new de::Uri(*decor->material); + idx = DED_AddDecoration(ded); + ded_decor_t *decor = &ded->decorations[idx]; - for(int i = 0; i < DED_DECOR_NUM_LIGHTS; ++i) + // Should we copy the previous definition? + if(prevDecorDefIdx >= 0 && bCopyNext) { - ded_decoration_t *dl = &decor->lights[i]; - if(dl->stage.flare) dl->stage.flare = new de::Uri(*dl->stage.flare); - if(dl->stage.up) dl->stage.up = new de::Uri(*dl->stage.up); - if(dl->stage.down) dl->stage.down = new de::Uri(*dl->stage.down); - if(dl->stage.sides) dl->stage.sides = new de::Uri(*dl->stage.sides); - } - } + ded_decor_t const *prevDecor = ded->decorations + prevDecorDefIdx; - uint sub = 0; - FINDBEGIN; - for(;;) - { - READLABEL; - RV_FLAGS("Flags", decor->flags, "dcf_") - if(ISLABEL("Material")) - { - READURI(&decor->material, 0) - } - else if(ISLABEL("Texture")) - { - READURI(&decor->material, "Textures") - } - else if(ISLABEL("Flat")) - { - READURI(&decor->material, "Flats") + std::memcpy(decor, prevDecor, sizeof(*decor)); + if(decor->material) decor->material = new de::Uri(*decor->material); + + for(int i = 0; i < DED_DECOR_NUM_LIGHTS; ++i) + { + ded_decoration_t *dl = &decor->lights[i]; + if(dl->stage.flare) dl->stage.flare = new de::Uri(*dl->stage.flare); + if(dl->stage.up) dl->stage.up = new de::Uri(*dl->stage.up); + if(dl->stage.down) dl->stage.down = new de::Uri(*dl->stage.down); + if(dl->stage.sides) dl->stage.sides = new de::Uri(*dl->stage.sides); + } } - else if(ISLABEL("Light")) + + uint sub = 0; + FINDBEGIN; + for(;;) { - if(sub == DED_DECOR_NUM_LIGHTS) + READLABEL; + RV_FLAGS("Flags", decor->flags, "dcf_") + if(ISLABEL("Material")) { - DED_SetError("Too many lights in decoration."); - retVal = false; - goto ded_end_read; + READURI(&decor->material, 0) } - - ded_decoration_t *dl = &decor->lights[sub]; - FINDBEGIN; - for(;;) + else if(ISLABEL("Texture")) { - READLABEL; - RV_VEC("Offset", dl->stage.pos, 2) - RV_FLT("Distance", dl->stage.elevation) - RV_VEC("Color", dl->stage.color, 3) - RV_FLT("Radius", dl->stage.radius) - RV_FLT("Halo radius", dl->stage.haloRadius) - RV_IVEC("Pattern offset", dl->patternOffset, 2) - RV_IVEC("Pattern skip", dl->patternSkip, 2) - if(ISLABEL("Levels")) + READURI(&decor->material, "Textures") + } + else if(ISLABEL("Flat")) + { + READURI(&decor->material, "Flats") + } + else if(ISLABEL("Light")) + { + if(sub == DED_DECOR_NUM_LIGHTS) { - FINDBEGIN; - for(int b = 0; b < 2; ++b) + setError("Too many lights in decoration."); + retVal = false; + goto ded_end_read; + } + + ded_decoration_t *dl = &decor->lights[sub]; + FINDBEGIN; + for(;;) + { + READLABEL; + RV_VEC("Offset", dl->stage.pos, 2) + RV_FLT("Distance", dl->stage.elevation) + RV_VEC("Color", dl->stage.color, 3) + RV_FLT("Radius", dl->stage.radius) + RV_FLT("Halo radius", dl->stage.haloRadius) + RV_IVEC("Pattern offset", dl->patternOffset, 2) + RV_IVEC("Pattern skip", dl->patternSkip, 2) + if(ISLABEL("Levels")) { - READFLT(dl->stage.lightLevels[b]) - dl->stage.lightLevels[b] /= 255.0f; - if(dl->stage.lightLevels[b] < 0) - dl->stage.lightLevels[b] = 0; - else if(dl->stage.lightLevels[b] > 1) - dl->stage.lightLevels[b] = 1; + FINDBEGIN; + for(int b = 0; b < 2; ++b) + { + READFLT(dl->stage.lightLevels[b]) + dl->stage.lightLevels[b] /= 255.0f; + if(dl->stage.lightLevels[b] < 0) + dl->stage.lightLevels[b] = 0; + else if(dl->stage.lightLevels[b] > 1) + dl->stage.lightLevels[b] = 1; + } + ReadToken(); } - ReadToken(); + else + RV_INT("Flare texture", dl->stage.sysFlareIdx) + RV_URI("Flare map", &dl->stage.flare, "LightMaps") + RV_URI("Top map", &dl->stage.up, "LightMaps") + RV_URI("Bottom map", &dl->stage.down, "LightMaps") + RV_URI("Side map", &dl->stage.sides, "LightMaps") + RV_END + CHECKSC; } - else - RV_INT("Flare texture", dl->stage.sysFlareIdx) - RV_URI("Flare map", &dl->stage.flare, "LightMaps") - RV_URI("Top map", &dl->stage.up, "LightMaps") - RV_URI("Bottom map", &dl->stage.down, "LightMaps") - RV_URI("Side map", &dl->stage.sides, "LightMaps") - RV_END - CHECKSC; + sub++; } - sub++; + else RV_END + CHECKSC; } - else RV_END - CHECKSC; + prevDecorDefIdx = idx; } - prevDecorDefIdx = idx; - } - if(ISTOKEN("Group")) - { - int sub; - ded_group_t* grp; + if(ISTOKEN("Group")) + { + int sub; + ded_group_t* grp; - idx = DED_AddGroup(ded); - grp = &ded->groups[idx]; - sub = 0; + idx = DED_AddGroup(ded); + grp = &ded->groups[idx]; + sub = 0; - FINDBEGIN; - for(;;) - { - READLABEL; - if(ISLABEL("Texture") || ISLABEL("Flat")) + FINDBEGIN; + for(;;) { - ded_group_member_t* memb; - ddstring_t schemeName; Str_Init(&schemeName); - Str_Set(&schemeName, ISLABEL("Texture")? "Textures" : "Flats"); + READLABEL; + if(ISLABEL("Texture") || ISLABEL("Flat")) + { + ded_group_member_t* memb; + ddstring_t schemeName; Str_Init(&schemeName); + Str_Set(&schemeName, ISLABEL("Texture")? "Textures" : "Flats"); - // Need to allocate new stage? - if(sub >= grp->count.num) - sub = DED_AddGroupMember(grp); - memb = &grp->members[sub]; + // Need to allocate new stage? + if(sub >= grp->count.num) + sub = DED_AddGroupMember(grp); + memb = &grp->members[sub]; - FINDBEGIN; - for(;;) - { - READLABEL; - RV_URI("ID", &memb->material, Str_Text(&schemeName)) - RV_INT("Tics", memb->tics) - RV_INT("Random", memb->randomTics) - RV_END - CHECKSC; + FINDBEGIN; + for(;;) + { + READLABEL; + RV_URI("ID", &memb->material, Str_Text(&schemeName)) + RV_INT("Tics", memb->tics) + RV_INT("Random", memb->randomTics) + RV_END + CHECKSC; + } + Str_Free(&schemeName); + ++sub; } - Str_Free(&schemeName); - ++sub; + else RV_FLAGS("Flags", grp->flags, "tgf_") + RV_END + CHECKSC; } - else RV_FLAGS("Flags", grp->flags, "tgf_") - RV_END - CHECKSC; } - } - - /*if(ISTOKEN("XGClass")) // XG Class - { - // A new XG Class definition - idx = DED_AddXGClass(ded); - xgc = ded->xgClasses + idx; - sub = 0; - FINDBEGIN; - for(;;) + /*if(ISTOKEN("XGClass")) // XG Class { - READLABEL; - RV_STR("ID", xgc->id) - RV_STR("Name", xgc->name) - if(ISLABEL("Property")) - { - ded_xgclass_property_t *xgcp = NULL; + // A new XG Class definition + idx = DED_AddXGClass(ded); + xgc = ded->xgClasses + idx; + sub = 0; - if(sub >= xgc->properties_count.num) + FINDBEGIN; + for(;;) + { + READLABEL; + RV_STR("ID", xgc->id) + RV_STR("Name", xgc->name) + if(ISLABEL("Property")) { - // Allocate new property - sub = DED_AddXGClassProperty(xgc); - } + ded_xgclass_property_t *xgcp = NULL; - xgcp = &xgc->properties[sub]; + if(sub >= xgc->properties_count.num) + { + // Allocate new property + sub = DED_AddXGClassProperty(xgc); + } - FINDBEGIN; - for(;;) - { - READLABEL; - RV_FLAGS("ID", xgcp->id, "xgcp_") - RV_FLAGS("Flags", xgcp->flags, "xgcpf_") - RV_STR("Name", xgcp->name) - RV_STR("Flag Group", xgcp->flagprefix) - RV_END - CHECKSC; + xgcp = &xgc->properties[sub]; + + FINDBEGIN; + for(;;) + { + READLABEL; + RV_FLAGS("ID", xgcp->id, "xgcp_") + RV_FLAGS("Flags", xgcp->flags, "xgcpf_") + RV_STR("Name", xgcp->name) + RV_STR("Flag Group", xgcp->flagprefix) + RV_END + CHECKSC; + } + sub++; } - sub++; + else RV_END + CHECKSC; } - else RV_END - CHECKSC; - } - }*/ - - if(ISTOKEN("Line")) // Line Type - { - ded_linetype_t* l; - - // A new line type. - idx = DED_AddLineType(ded, 0); - l = &ded->lineTypes[idx]; + }*/ - // Should we copy the previous definition? - if(prevLineTypeDefIdx >= 0 && bCopyNext) + if(ISTOKEN("Line")) // Line Type { - const ded_linetype_t* prevLineType = ded->lineTypes + prevLineTypeDefIdx; + ded_linetype_t* l; - memcpy(l, prevLineType, sizeof(*l)); - - if(l->actMaterial) l->actMaterial = new de::Uri(*l->actMaterial); - if(l->deactMaterial) l->deactMaterial = new de::Uri(*l->deactMaterial); - } + // A new line type. + idx = DED_AddLineType(ded, 0); + l = &ded->lineTypes[idx]; - FINDBEGIN; - for(;;) - { - READLABEL; - RV_INT("ID", l->id) - RV_STR("Comment", l->comment) - RV_FLAGS("Flags", l->flags[0], "ltf_") - RV_FLAGS("Flags2", l->flags[1], "ltf2_") - RV_FLAGS("Flags3", l->flags[2], "ltf3_") - RV_FLAGS("Class", l->lineClass, "ltc_") - RV_FLAGS("Type", l->actType, "lat_") - RV_INT("Count", l->actCount) - RV_FLT("Time", l->actTime) - RV_INT("Act tag", l->actTag) - RV_INT("Ap0", l->aparm[0]) - RV_INT("Ap1", l->aparm[1]) - RV_INT("Ap2", l->aparm[2]) - RV_INT("Ap3", l->aparm[3]) - RV_FLAGS("Ap4", l->aparm[4], "lref_") - RV_INT("Ap5", l->aparm[5]) - RV_FLAGS("Ap6", l->aparm[6], "lref_") - RV_INT("Ap7", l->aparm[7]) - RV_INT("Ap8", l->aparm[8]) - RV_STR("Ap9", l->aparm9) - RV_INT("Health above", l->aparm[0]) - RV_INT("Health below", l->aparm[1]) - RV_INT("Power above", l->aparm[2]) - RV_INT("Power below", l->aparm[3]) - RV_FLAGS("Line act lref", l->aparm[4], "lref_") - RV_INT("Line act lrefd", l->aparm[5]) - RV_FLAGS("Line inact lref", l->aparm[6], "lref_") - RV_INT("Line inact lrefd", l->aparm[7]) - RV_INT("Color", l->aparm[8]) - RV_STR("Thing type", l->aparm9) - RV_FLT("Ticker start time", l->tickerStart) - RV_FLT("Ticker end time", l->tickerEnd) - RV_INT("Ticker tics", l->tickerInterval) - RV_STR("Act sound", l->actSound) - RV_STR("Deact sound", l->deactSound) - RV_INT("Event chain", l->evChain) - RV_INT("Act chain", l->actChain) - RV_INT("Deact chain", l->deactChain) - RV_FLAGS("Wall section", l->wallSection, "lws_") - if(ISLABEL("Act material")) - { - READURI(&l->actMaterial, 0) - } - else if(ISLABEL("Act texture")) // Alias - { - READURI(&l->actMaterial, "Textures") - } - else if(ISLABEL("Deact material")) - { - READURI(&l->deactMaterial, 0) - } - else if(ISLABEL("Deact texture")) // Alias + // Should we copy the previous definition? + if(prevLineTypeDefIdx >= 0 && bCopyNext) { - READURI(&l->deactMaterial, "Textures") + const ded_linetype_t* prevLineType = ded->lineTypes + prevLineTypeDefIdx; + + memcpy(l, prevLineType, sizeof(*l)); + + if(l->actMaterial) l->actMaterial = new de::Uri(*l->actMaterial); + if(l->deactMaterial) l->deactMaterial = new de::Uri(*l->deactMaterial); } - else - RV_INT("Act type", l->actLineType) - RV_INT("Deact type", l->deactLineType) - RV_STR("Act message", l->actMsg) - RV_STR("Deact message", l->deactMsg) - RV_FLT("Texmove angle", l->materialMoveAngle) - RV_FLT("Materialmove angle", l->materialMoveAngle) // Alias - RV_FLT("Texmove speed", l->materialMoveSpeed) - RV_FLT("Materialmove speed", l->materialMoveSpeed) // Alias - RV_STR_INT("Ip0", l->iparmStr[0], l->iparm[0]) - RV_STR_INT("Ip1", l->iparmStr[1], l->iparm[1]) - RV_STR_INT("Ip2", l->iparmStr[2], l->iparm[2]) - RV_STR_INT("Ip3", l->iparmStr[3], l->iparm[3]) - RV_STR_INT("Ip4", l->iparmStr[4], l->iparm[4]) - RV_STR_INT("Ip5", l->iparmStr[5], l->iparm[5]) - RV_STR_INT("Ip6", l->iparmStr[6], l->iparm[6]) - RV_STR_INT("Ip7", l->iparmStr[7], l->iparm[7]) - RV_STR_INT("Ip8", l->iparmStr[8], l->iparm[8]) - RV_STR_INT("Ip9", l->iparmStr[9], l->iparm[9]) - RV_STR_INT("Ip10", l->iparmStr[10], l->iparm[10]) - RV_STR_INT("Ip11", l->iparmStr[11], l->iparm[11]) - RV_STR_INT("Ip12", l->iparmStr[12], l->iparm[12]) - RV_STR_INT("Ip13", l->iparmStr[13], l->iparm[13]) - RV_STR_INT("Ip14", l->iparmStr[14], l->iparm[14]) - RV_STR_INT("Ip15", l->iparmStr[15], l->iparm[15]) - RV_STR_INT("Ip16", l->iparmStr[16], l->iparm[16]) - RV_STR_INT("Ip17", l->iparmStr[17], l->iparm[17]) - RV_STR_INT("Ip18", l->iparmStr[18], l->iparm[18]) - RV_STR_INT("Ip19", l->iparmStr[19], l->iparm[19]) - RV_FLT("Fp0", l->fparm[0]) - RV_FLT("Fp1", l->fparm[1]) - RV_FLT("Fp2", l->fparm[2]) - RV_FLT("Fp3", l->fparm[3]) - RV_FLT("Fp4", l->fparm[4]) - RV_FLT("Fp5", l->fparm[5]) - RV_FLT("Fp6", l->fparm[6]) - RV_FLT("Fp7", l->fparm[7]) - RV_FLT("Fp8", l->fparm[8]) - RV_FLT("Fp9", l->fparm[9]) - RV_FLT("Fp10", l->fparm[10]) - RV_FLT("Fp11", l->fparm[11]) - RV_FLT("Fp12", l->fparm[12]) - RV_FLT("Fp13", l->fparm[13]) - RV_FLT("Fp14", l->fparm[14]) - RV_FLT("Fp15", l->fparm[15]) - RV_FLT("Fp16", l->fparm[16]) - RV_FLT("Fp17", l->fparm[17]) - RV_FLT("Fp18", l->fparm[18]) - RV_FLT("Fp19", l->fparm[19]) - RV_STR("Sp0", l->sparm[0]) - RV_STR("Sp1", l->sparm[1]) - RV_STR("Sp2", l->sparm[2]) - RV_STR("Sp3", l->sparm[3]) - RV_STR("Sp4", l->sparm[4]) - if(l->lineClass) + + FINDBEGIN; + for(;;) { - // IpX Alt names can only be used if the class is defined first! - // they also support the DED v6 flags format. - int i; - for(i = 0; i < 20; ++i) + READLABEL; + RV_INT("ID", l->id) + RV_STR("Comment", l->comment) + RV_FLAGS("Flags", l->flags[0], "ltf_") + RV_FLAGS("Flags2", l->flags[1], "ltf2_") + RV_FLAGS("Flags3", l->flags[2], "ltf3_") + RV_FLAGS("Class", l->lineClass, "ltc_") + RV_FLAGS("Type", l->actType, "lat_") + RV_INT("Count", l->actCount) + RV_FLT("Time", l->actTime) + RV_INT("Act tag", l->actTag) + RV_INT("Ap0", l->aparm[0]) + RV_INT("Ap1", l->aparm[1]) + RV_INT("Ap2", l->aparm[2]) + RV_INT("Ap3", l->aparm[3]) + RV_FLAGS("Ap4", l->aparm[4], "lref_") + RV_INT("Ap5", l->aparm[5]) + RV_FLAGS("Ap6", l->aparm[6], "lref_") + RV_INT("Ap7", l->aparm[7]) + RV_INT("Ap8", l->aparm[8]) + RV_STR("Ap9", l->aparm9) + RV_INT("Health above", l->aparm[0]) + RV_INT("Health below", l->aparm[1]) + RV_INT("Power above", l->aparm[2]) + RV_INT("Power below", l->aparm[3]) + RV_FLAGS("Line act lref", l->aparm[4], "lref_") + RV_INT("Line act lrefd", l->aparm[5]) + RV_FLAGS("Line inact lref", l->aparm[6], "lref_") + RV_INT("Line inact lrefd", l->aparm[7]) + RV_INT("Color", l->aparm[8]) + RV_STR("Thing type", l->aparm9) + RV_FLT("Ticker start time", l->tickerStart) + RV_FLT("Ticker end time", l->tickerEnd) + RV_INT("Ticker tics", l->tickerInterval) + RV_STR("Act sound", l->actSound) + RV_STR("Deact sound", l->deactSound) + RV_INT("Event chain", l->evChain) + RV_INT("Act chain", l->actChain) + RV_INT("Deact chain", l->deactChain) + RV_FLAGS("Wall section", l->wallSection, "lws_") + if(ISLABEL("Act material")) + { + READURI(&l->actMaterial, 0) + } + else if(ISLABEL("Act texture")) // Alias + { + READURI(&l->actMaterial, "Textures") + } + else if(ISLABEL("Deact material")) { - xgclassparm_t const& iParm = xgClassLinks[l->lineClass].iparm[i]; + READURI(&l->deactMaterial, 0) + } + else if(ISLABEL("Deact texture")) // Alias + { + READURI(&l->deactMaterial, "Textures") + } + else + RV_INT("Act type", l->actLineType) + RV_INT("Deact type", l->deactLineType) + RV_STR("Act message", l->actMsg) + RV_STR("Deact message", l->deactMsg) + RV_FLT("Texmove angle", l->materialMoveAngle) + RV_FLT("Materialmove angle", l->materialMoveAngle) // Alias + RV_FLT("Texmove speed", l->materialMoveSpeed) + RV_FLT("Materialmove speed", l->materialMoveSpeed) // Alias + RV_STR_INT("Ip0", l->iparmStr[0], l->iparm[0]) + RV_STR_INT("Ip1", l->iparmStr[1], l->iparm[1]) + RV_STR_INT("Ip2", l->iparmStr[2], l->iparm[2]) + RV_STR_INT("Ip3", l->iparmStr[3], l->iparm[3]) + RV_STR_INT("Ip4", l->iparmStr[4], l->iparm[4]) + RV_STR_INT("Ip5", l->iparmStr[5], l->iparm[5]) + RV_STR_INT("Ip6", l->iparmStr[6], l->iparm[6]) + RV_STR_INT("Ip7", l->iparmStr[7], l->iparm[7]) + RV_STR_INT("Ip8", l->iparmStr[8], l->iparm[8]) + RV_STR_INT("Ip9", l->iparmStr[9], l->iparm[9]) + RV_STR_INT("Ip10", l->iparmStr[10], l->iparm[10]) + RV_STR_INT("Ip11", l->iparmStr[11], l->iparm[11]) + RV_STR_INT("Ip12", l->iparmStr[12], l->iparm[12]) + RV_STR_INT("Ip13", l->iparmStr[13], l->iparm[13]) + RV_STR_INT("Ip14", l->iparmStr[14], l->iparm[14]) + RV_STR_INT("Ip15", l->iparmStr[15], l->iparm[15]) + RV_STR_INT("Ip16", l->iparmStr[16], l->iparm[16]) + RV_STR_INT("Ip17", l->iparmStr[17], l->iparm[17]) + RV_STR_INT("Ip18", l->iparmStr[18], l->iparm[18]) + RV_STR_INT("Ip19", l->iparmStr[19], l->iparm[19]) + RV_FLT("Fp0", l->fparm[0]) + RV_FLT("Fp1", l->fparm[1]) + RV_FLT("Fp2", l->fparm[2]) + RV_FLT("Fp3", l->fparm[3]) + RV_FLT("Fp4", l->fparm[4]) + RV_FLT("Fp5", l->fparm[5]) + RV_FLT("Fp6", l->fparm[6]) + RV_FLT("Fp7", l->fparm[7]) + RV_FLT("Fp8", l->fparm[8]) + RV_FLT("Fp9", l->fparm[9]) + RV_FLT("Fp10", l->fparm[10]) + RV_FLT("Fp11", l->fparm[11]) + RV_FLT("Fp12", l->fparm[12]) + RV_FLT("Fp13", l->fparm[13]) + RV_FLT("Fp14", l->fparm[14]) + RV_FLT("Fp15", l->fparm[15]) + RV_FLT("Fp16", l->fparm[16]) + RV_FLT("Fp17", l->fparm[17]) + RV_FLT("Fp18", l->fparm[18]) + RV_FLT("Fp19", l->fparm[19]) + RV_STR("Sp0", l->sparm[0]) + RV_STR("Sp1", l->sparm[1]) + RV_STR("Sp2", l->sparm[2]) + RV_STR("Sp3", l->sparm[3]) + RV_STR("Sp4", l->sparm[4]) + if(l->lineClass) + { + // IpX Alt names can only be used if the class is defined first! + // they also support the DED v6 flags format. + int i; + for(i = 0; i < 20; ++i) + { + xgclassparm_t const& iParm = xgClassLinks[l->lineClass].iparm[i]; - if(!iParm.name || !iParm.name[0]) continue; - if(!ISLABEL(iParm.name)) continue; + if(!iParm.name || !iParm.name[0]) continue; + if(!ISLABEL(iParm.name)) continue; - if(iParm.flagPrefix && iParm.flagPrefix[0]) - { - READFLAGS(l->iparm[i], iParm.flagPrefix) - } - else - { - READSTRING(l->iparmStr[i], l->iparm[i]) + if(iParm.flagPrefix && iParm.flagPrefix[0]) + { + READFLAGS(l->iparm[i], iParm.flagPrefix) + } + else + { + READSTRING(l->iparmStr[i], l->iparm[i]) + } + break; } - break; - } - // Not a known label? - if(i == 20) RV_END + // Not a known label? + if(i == 20) RV_END - } else - RV_END - CHECKSC; + } else + RV_END + CHECKSC; + } + prevLineTypeDefIdx = idx; } - prevLineTypeDefIdx = idx; - } - if(ISTOKEN("Sector")) // Sector Type - { - ded_sectortype_t* sec; + if(ISTOKEN("Sector")) // Sector Type + { + ded_sectortype_t* sec; - // A new sector type. - idx = DED_AddSectorType(ded, 0); - sec = &ded->sectorTypes[idx]; + // A new sector type. + idx = DED_AddSectorType(ded, 0); + sec = &ded->sectorTypes[idx]; - if(prevSectorTypeDefIdx >= 0 && bCopyNext) - { - // Should we copy the previous definition? - memcpy(sec, ded->sectorTypes + prevSectorTypeDefIdx, - sizeof(*sec)); - } + if(prevSectorTypeDefIdx >= 0 && bCopyNext) + { + // Should we copy the previous definition? + memcpy(sec, ded->sectorTypes + prevSectorTypeDefIdx, + sizeof(*sec)); + } - FINDBEGIN; - for(;;) - { - READLABEL; - RV_INT("ID", sec->id) - RV_STR("Comment", sec->comment) - RV_FLAGS("Flags", sec->flags, "stf_") - RV_INT("Act tag", sec->actTag) - RV_INT("Floor chain", sec->chain[0]) - RV_INT("Ceiling chain", sec->chain[1]) - RV_INT("Inside chain", sec->chain[2]) - RV_INT("Ticker chain", sec->chain[3]) - RV_FLAGS("Floor chain flags", sec->chainFlags[0], "scef_") - RV_FLAGS("Ceiling chain flags", sec->chainFlags[1], "scef_") - RV_FLAGS("Inside chain flags", sec->chainFlags[2], "scef_") - RV_FLAGS("Ticker chain flags", sec->chainFlags[3], "scef_") - RV_FLT("Floor chain start time", sec->start[0]) - RV_FLT("Ceiling chain start time", sec->start[1]) - RV_FLT("Inside chain start time", sec->start[2]) - RV_FLT("Ticker chain start time", sec->start[3]) - RV_FLT("Floor chain end time", sec->end[0]) - RV_FLT("Ceiling chain end time", sec->end[1]) - RV_FLT("Inside chain end time", sec->end[2]) - RV_FLT("Ticker chain end time", sec->end[3]) - RV_FLT("Floor chain min interval", sec->interval[0][0]) - RV_FLT("Ceiling chain min interval", sec->interval[1][0]) - RV_FLT("Inside chain min interval", sec->interval[2][0]) - RV_FLT("Ticker chain min interval", sec->interval[3][0]) - RV_FLT("Floor chain max interval", sec->interval[0][1]) - RV_FLT("Ceiling chain max interval", sec->interval[1][1]) - RV_FLT("Inside chain max interval", sec->interval[2][1]) - RV_FLT("Ticker chain max interval", sec->interval[3][1]) - RV_INT("Floor chain count", sec->count[0]) - RV_INT("Ceiling chain count", sec->count[1]) - RV_INT("Inside chain count", sec->count[2]) - RV_INT("Ticker chain count", sec->count[3]) - RV_STR("Ambient sound", sec->ambientSound) - RV_FLT("Ambient min interval", sec->soundInterval[0]) - RV_FLT("Ambient max interval", sec->soundInterval[1]) - RV_FLT("Floor texmove angle", sec->materialMoveAngle[0]) - RV_FLT("Floor materialmove angle", sec->materialMoveAngle[0]) // Alias - RV_FLT("Ceiling texmove angle", sec->materialMoveAngle[1]) - RV_FLT("Ceiling materialmove angle", sec->materialMoveAngle[1]) // Alias - RV_FLT("Floor texmove speed", sec->materialMoveSpeed[0]) - RV_FLT("Floor materialmove speed", sec->materialMoveSpeed[0]) // Alias - RV_FLT("Ceiling texmove speed", sec->materialMoveSpeed[1]) - RV_FLT("Ceiling materialmove speed", sec->materialMoveSpeed[1]) // Alias - RV_FLT("Wind angle", sec->windAngle) - RV_FLT("Wind speed", sec->windSpeed) - RV_FLT("Vertical wind", sec->verticalWind) - RV_FLT("Gravity", sec->gravity) - RV_FLT("Friction", sec->friction) - RV_STR("Light fn", sec->lightFunc) - RV_INT("Light fn min tics", sec->lightInterval[0]) - RV_INT("Light fn max tics", sec->lightInterval[1]) - RV_STR("Red fn", sec->colFunc[0]) - RV_STR("Green fn", sec->colFunc[1]) - RV_STR("Blue fn", sec->colFunc[2]) - RV_INT("Red fn min tics", sec->colInterval[0][0]) - RV_INT("Red fn max tics", sec->colInterval[0][1]) - RV_INT("Green fn min tics", sec->colInterval[1][0]) - RV_INT("Green fn max tics", sec->colInterval[1][1]) - RV_INT("Blue fn min tics", sec->colInterval[2][0]) - RV_INT("Blue fn max tics", sec->colInterval[2][1]) - RV_STR("Floor fn", sec->floorFunc) - RV_FLT("Floor fn scale", sec->floorMul) - RV_FLT("Floor fn offset", sec->floorOff) - RV_INT("Floor fn min tics", sec->floorInterval[0]) - RV_INT("Floor fn max tics", sec->floorInterval[1]) - RV_STR("Ceiling fn", sec->ceilFunc) - RV_FLT("Ceiling fn scale", sec->ceilMul) - RV_FLT("Ceiling fn offset", sec->ceilOff) - RV_INT("Ceiling fn min tics", sec->ceilInterval[0]) - RV_INT("Ceiling fn max tics", sec->ceilInterval[1]) - RV_END - CHECKSC; + FINDBEGIN; + for(;;) + { + READLABEL; + RV_INT("ID", sec->id) + RV_STR("Comment", sec->comment) + RV_FLAGS("Flags", sec->flags, "stf_") + RV_INT("Act tag", sec->actTag) + RV_INT("Floor chain", sec->chain[0]) + RV_INT("Ceiling chain", sec->chain[1]) + RV_INT("Inside chain", sec->chain[2]) + RV_INT("Ticker chain", sec->chain[3]) + RV_FLAGS("Floor chain flags", sec->chainFlags[0], "scef_") + RV_FLAGS("Ceiling chain flags", sec->chainFlags[1], "scef_") + RV_FLAGS("Inside chain flags", sec->chainFlags[2], "scef_") + RV_FLAGS("Ticker chain flags", sec->chainFlags[3], "scef_") + RV_FLT("Floor chain start time", sec->start[0]) + RV_FLT("Ceiling chain start time", sec->start[1]) + RV_FLT("Inside chain start time", sec->start[2]) + RV_FLT("Ticker chain start time", sec->start[3]) + RV_FLT("Floor chain end time", sec->end[0]) + RV_FLT("Ceiling chain end time", sec->end[1]) + RV_FLT("Inside chain end time", sec->end[2]) + RV_FLT("Ticker chain end time", sec->end[3]) + RV_FLT("Floor chain min interval", sec->interval[0][0]) + RV_FLT("Ceiling chain min interval", sec->interval[1][0]) + RV_FLT("Inside chain min interval", sec->interval[2][0]) + RV_FLT("Ticker chain min interval", sec->interval[3][0]) + RV_FLT("Floor chain max interval", sec->interval[0][1]) + RV_FLT("Ceiling chain max interval", sec->interval[1][1]) + RV_FLT("Inside chain max interval", sec->interval[2][1]) + RV_FLT("Ticker chain max interval", sec->interval[3][1]) + RV_INT("Floor chain count", sec->count[0]) + RV_INT("Ceiling chain count", sec->count[1]) + RV_INT("Inside chain count", sec->count[2]) + RV_INT("Ticker chain count", sec->count[3]) + RV_STR("Ambient sound", sec->ambientSound) + RV_FLT("Ambient min interval", sec->soundInterval[0]) + RV_FLT("Ambient max interval", sec->soundInterval[1]) + RV_FLT("Floor texmove angle", sec->materialMoveAngle[0]) + RV_FLT("Floor materialmove angle", sec->materialMoveAngle[0]) // Alias + RV_FLT("Ceiling texmove angle", sec->materialMoveAngle[1]) + RV_FLT("Ceiling materialmove angle", sec->materialMoveAngle[1]) // Alias + RV_FLT("Floor texmove speed", sec->materialMoveSpeed[0]) + RV_FLT("Floor materialmove speed", sec->materialMoveSpeed[0]) // Alias + RV_FLT("Ceiling texmove speed", sec->materialMoveSpeed[1]) + RV_FLT("Ceiling materialmove speed", sec->materialMoveSpeed[1]) // Alias + RV_FLT("Wind angle", sec->windAngle) + RV_FLT("Wind speed", sec->windSpeed) + RV_FLT("Vertical wind", sec->verticalWind) + RV_FLT("Gravity", sec->gravity) + RV_FLT("Friction", sec->friction) + RV_STR("Light fn", sec->lightFunc) + RV_INT("Light fn min tics", sec->lightInterval[0]) + RV_INT("Light fn max tics", sec->lightInterval[1]) + RV_STR("Red fn", sec->colFunc[0]) + RV_STR("Green fn", sec->colFunc[1]) + RV_STR("Blue fn", sec->colFunc[2]) + RV_INT("Red fn min tics", sec->colInterval[0][0]) + RV_INT("Red fn max tics", sec->colInterval[0][1]) + RV_INT("Green fn min tics", sec->colInterval[1][0]) + RV_INT("Green fn max tics", sec->colInterval[1][1]) + RV_INT("Blue fn min tics", sec->colInterval[2][0]) + RV_INT("Blue fn max tics", sec->colInterval[2][1]) + RV_STR("Floor fn", sec->floorFunc) + RV_FLT("Floor fn scale", sec->floorMul) + RV_FLT("Floor fn offset", sec->floorOff) + RV_INT("Floor fn min tics", sec->floorInterval[0]) + RV_INT("Floor fn max tics", sec->floorInterval[1]) + RV_STR("Ceiling fn", sec->ceilFunc) + RV_FLT("Ceiling fn scale", sec->ceilMul) + RV_FLT("Ceiling fn offset", sec->ceilOff) + RV_INT("Ceiling fn min tics", sec->ceilInterval[0]) + RV_INT("Ceiling fn max tics", sec->ceilInterval[1]) + RV_END + CHECKSC; + } + prevSectorTypeDefIdx = idx; } - prevSectorTypeDefIdx = idx; + bCopyNext = false; } - bCopyNext = false; - } -ded_end_read: - M_Free(rootStr); + ded_end_read: + M_Free(rootStr); - // Free the source stack entry we were using. - DED_CloseReader(); + // Free the source stack entry we were using. + DED_CloseReader(); - Str_Free(&sourceFile); - Str_Free(&sourceFileDir); + Str_Free(&sourceFile); + Str_Free(&sourceFileDir); - return retVal; -} -/* *INDENT-ON* */ + return retVal; + } -void DED_Include(ded_t *ded, const char* fileName, const char* parentDirectory) -{ - ddstring_t tmp; + void DED_Include(const char* fileName, const char* parentDirectory) + { + ddstring_t tmp; + + Str_Init(&tmp); Str_Set(&tmp, fileName); + F_FixSlashes(&tmp, &tmp); + F_ExpandBasePath(&tmp, &tmp); + if(!F_IsAbsolute(&tmp)) + { + Str_Prepend(&tmp, parentDirectory); + } + + Def_ReadProcessDED(ded, Str_Text(&tmp)); + Str_Free(&tmp); + + // Reset state for continuing. + strncpy(token, "", MAX_TOKEN_LEN); + } - Str_Init(&tmp); Str_Set(&tmp, fileName); - F_FixSlashes(&tmp, &tmp); - F_ExpandBasePath(&tmp, &tmp); - if(!F_IsAbsolute(&tmp)) + void setError(char const *str, char const *more = 0) { - Str_Prepend(&tmp, parentDirectory); + extern char dedReadError[512]; + if(more) + { + sprintf(dedReadError, "Error in %s:\n Line %i: %s (%s)", + source? source->fileName : "?", + source? source->lineNumber : 0, + str, more); + } + else + { + sprintf(dedReadError, "Error in %s:\n Line %i: %s", + source? source->fileName : "?", + source? source->lineNumber : 0, + str); + } } +}; - Def_ReadProcessDED(ded, Str_Text(&tmp)); - Str_Free(&tmp); +DEDParser::DEDParser(ded_t *ded) : d(new Instance(this)) +{ + d->ded = ded; +} - // Reset state for continuing. - strncpy(token, "", MAX_TOKEN_LEN); +int DEDParser::parse(const char *buffer, const char *sourceFile) +{ + return d->readData(buffer, sourceFile); }