/*============================================================================= Parser.cpp : Script parser implementations. Copyright (c) 2001 Crytek Studios. All Rights Reserved. Revision history: * Created by Khonich Andrey =============================================================================*/ #include "RenderPCH.h" #define PARSER_CPP const char *kWhiteSpace = " ,"; char *pCurCommand; /*---------------------------------------------------------------- Skips all control characters and any characters in the toSkip string. Changes the buf pointer. ----------------------------------------------------------------*/ void SkipCharacters (char **buf, const char *toSkip) { char theChar; char *skip; while ((theChar = **buf) != 0) { if (theChar >= 0x20) // NOT control character, tab cr, lf, etc { skip = (char *) toSkip; while (*skip) { if (theChar == *skip) break; ++skip; } if (*skip == 0) // exhausted the skip string return; // we are now at first NON skipped character } ++*buf; // skip this character } // we must be at the end of the buffer if we get here } _inline static int IsComment(char **buf) { if (!(*buf)) return 0; if (**buf == ';') return 1; if ((*buf)[0] == '/' && (*buf)[1] == '/') return 2; if ((*buf)[0] == '/' && (*buf)[1] == '*') return 3; return 0; } char *gShObjectNotFound = NULL; void SkipComments(char **buf, bool bSkipWhiteSpace) { int n; static int m; while (n=IsComment(buf)) { switch (n) { case 1: // skip comment lines. *buf = strchr (*buf, '\n'); if (*buf && bSkipWhiteSpace) SkipCharacters (buf, kWhiteSpace); break; case 2: // skip comment lines. *buf = strchr (*buf, '\n'); if (*buf && bSkipWhiteSpace) SkipCharacters (buf, kWhiteSpace); break; case 3: // skip comment blocks. m = 0; do { *buf = strchr (*buf, '*'); if (!(*buf)) break; if ((*buf)[-1] == '/') { *buf += 1; m++; } else if ((*buf)[1] == '/') { *buf += 2; m--; } else *buf += 1; } while (m); if (!(*buf)) { if (gShObjectNotFound) iLog->Log (gShObjectNotFound); iLog->Log ("Warning: Comment lines don't closed\n"); break; } if (bSkipWhiteSpace) SkipCharacters (buf, kWhiteSpace); break; } } } void RemoveCR(char *pbuf) { while (*pbuf) { if (*pbuf == 0xd) *pbuf = 0x20; pbuf++; } } char *RemoveComments(char *pbuf) { char *ppbuf[1]; char *prevbuf = pbuf; while (true) { ppbuf[0] = prevbuf; SkipCharacters (ppbuf, kWhiteSpace); prevbuf = ppbuf[0]; if (IsComment(ppbuf)) { SkipComments (ppbuf, false); if (prevbuf != ppbuf[0]) { memset(prevbuf, 0x20202020, ppbuf[0]-prevbuf); prevbuf = ppbuf[0]; } } else { while (prevbuf[0] != ' ' && prevbuf[0] != 9 && prevbuf[0] != 0xa && prevbuf[0] != 0) { prevbuf++; } } if (!*prevbuf) break; } return pbuf; } /*---------------------------------------------------------------- Pass in a pointer to a buffer of text. This pointer is modified to point to the text after the object description. The token id for the object is returned. The name pointer will point to the optional name string in the buffer. The data pointer will point to the optional data for the object. The text buffer will get modified so BEWARE. ----------------------------------------------------------------*/ long shGetObject (char **buf, tokenDesc * tokens, char **name, char **data) { if (!*buf) return 0; SkipCharacters (buf, kWhiteSpace); SkipComments(buf, true); if (!(*buf)) return -2; if (!**buf) // at end of file return -2; // find the token. // for now just use brute force. Improve later. tokenDesc *ptokens = tokens; while (tokens->id != 0) { if (!strnicmp (tokens->token, *buf, strlen (tokens->token))) { // here we could be matching PART of a string // we could detect this here or the token list // could just have the longer tokens first in the list pCurCommand = *buf; break; } ++tokens; } if (tokens->id == 0) { char *p = strchr (*buf, '\n'); char pp[1024]; if (p) { strncpy(pp, *buf, p - *buf); pp[p - *buf] = 0; *buf = p; } else strcpy(pp, *buf); if (gShObjectNotFound) iLog->Log (gShObjectNotFound); iLog->Log ("Warning: Found token '%s' which was not one of the list (Skipping).\n", pp); while (ptokens->id != 0) { iLog->Log (" %s\n", ptokens->token); ptokens++; } return 0; // token not found !error! } // skip the token *buf += strlen (tokens->token); SkipCharacters (buf, kWhiteSpace); // get optional name *name = GetSubText (buf, 0x27, 0x27); // single quotes SkipCharacters (buf, kWhiteSpace); // get optional data if (**buf == '=') // hmm, this is an assignment and not a command/object { ++*buf; // skip the '=' *data = GetAssignmentText (buf); } else { *data = GetSubText (buf, '(', ')'); if (!*data) *data = GetSubText (buf, '{', '}'); } return tokens->id; } static int sRecurse; static char *sTempBuf1[32]; static char *sTempBuf2; std::vector g_Macros; static std::vector sStaticMacros; static TArray sbIFDEF; static int sFill(char **buf, char *dst) { int n = 0; SkipCharacters (buf, kWhiteSpace); while (**buf > 0x20) { dst[n++] = **buf; ++*buf; } dst[n] = 0; return n; } int fxFill(char **buf, char *dst) { int n = 0; SkipCharacters (buf, kWhiteSpace); while (**buf != ';') { if (**buf == 0) break; dst[n++] = **buf; ++*buf; } dst[n] = 0; return n; } static int sFillCR(char **buf, char *dst) { int n = 0; SkipCharacters (buf, kWhiteSpace); while (**buf != 0xa) { if (**buf == 0) break; dst[n++] = **buf; ++*buf; } dst[n] = 0; return n; } static void fxAddMacro(char *Name, char *Macro) { SPair pr; pr.MacroName = Name; pr.Macro = Macro ? Macro : ""; sStaticMacros.push_back(pr); } void fxParserInit(void) { #if defined (DIRECT3D8) || defined (DIRECT3D9) fxAddMacro("D3D", NULL); fxAddMacro("DIRECT3D", NULL); #if defined (DIRECT3D8) fxAddMacro("DIRECT3D8", NULL); fxAddMacro("D3D8", NULL); #elif defined (DIRECT3D9) fxAddMacro("DIRECT3D9", NULL); fxAddMacro("D3D9", NULL); #endif #elif OPENGL fxAddMacro("OGL", NULL); fxAddMacro("OPENGL", NULL); #elif defined (XBOX) fxAddMacro("XBOX", NULL); #elif defined (XBOX2) fxAddMacro("XBOX2", NULL); #elif defined (GC) fxAddMacro("GC", NULL); fxAddMacro("GAMECUBE", NULL); #elif defined (PS2) fxAddMacro("PS2", NULL); #elif defined (PS3) fxAddMacro("PS3", NULL); #endif #if !defined(LINUX) if (gRenDev->GetFeatures() & RFT_DEPTHMAPS) fxAddMacro("DEPTHMAP", NULL); if (gRenDev->GetFeatures() & RFT_SHADOWMAP_SELFSHADOW) fxAddMacro("SELFSHADOW", NULL); if (gRenDev->GetFeatures() & RFT_HW_ENVBUMPPROJECTED) fxAddMacro("PROJECTEDENVBUMP", NULL); int nGPU = gRenDev->GetFeatures() & RFT_HW_MASK; switch(nGPU) { case RFT_HW_GF2: fxAddMacro("NV1X", NULL); break; case RFT_HW_GF3: fxAddMacro("NV2X", NULL); break; case RFT_HW_GFFX: fxAddMacro("NV3X", NULL); break; case RFT_HW_NV4X: fxAddMacro("NV4X", NULL); break; case RFT_HW_RADEON: fxAddMacro("R3XX", NULL); fxAddMacro("ATI", NULL); fxAddMacro("RADEON", NULL); break; default: assert(0); } if (gRenDev->GetFeatures() & RFT_HW_HDR) fxAddMacro("HDR", NULL); if (gRenDev->GetFeatures() & RFT_HW_PS30) fxAddMacro("PS30", NULL); if (gRenDev->GetFeatures() & RFT_HW_PS30) fxAddMacro("PS30", NULL); #endif//LINUX char *VPSup = gRenDev->GetVertexProfile(true); char *PPSup = gRenDev->GetPixelProfile(true); fxAddMacro(VPSup, NULL); fxAddMacro(PPSup, NULL); } void fxStart() { int i; g_Macros.clear(); sbIFDEF.Free(); for (i=0; i<32; i++) { SAFE_DELETE_ARRAY(sTempBuf1[i]); } SAFE_DELETE_ARRAY(sTempBuf2); sRecurse = 0; } void fxIncrLevel() { assert (sRecurse < 31); sRecurse++; sRecurse = min(sRecurse, 31); SAFE_DELETE_ARRAY(sTempBuf1[sRecurse]); } void fxDecrLevel() { assert (sRecurse > 0); SAFE_DELETE_ARRAY(sTempBuf1[sRecurse]); sRecurse--; sRecurse = max(sRecurse, 0); } void fxIgnoreBlock(char **buf) { int nLevel = 0; char *start = *buf; while (true) { char *posS = strchr(*buf, '#'); if (!posS) { Warning( 0,0,"Couldn't find #endif directive for associated #ifdef"); return; } if (posS[1]=='i' && posS[2]=='f') { nLevel++; *buf = posS+2; continue; } if (!strncmp(&posS[1], "endif", 5)) { if (!nLevel) { *buf = posS+6; break; } nLevel--; *buf = posS+4; } else *buf = posS+1; } } int fxFindMacro(std::vector& Macros, char *name) { int i; for (i=0; im_cEF.m_ShadersPath[1], name); FILE *fp = iSystem->GetIPak()->FOpen(nameNew, "rb"); iSystem->GetIPak()->FSeek(fp, 0, SEEK_END); int lenInc = iSystem->GetIPak()->FTell(fp); iSystem->GetIPak()->FSeek(fp, 0, SEEK_SET); int len = strlen(*buf); char *tmpBuf = new char[len+lenInc+1]; lenInc = iSystem->GetIPak()->FRead(tmpBuf, 1, lenInc, fp); iSystem->GetIPak()->FClose(fp); tmpBuf[lenInc] = 0; RemoveCR(tmpBuf); memcpy(&tmpBuf[lenInc], *buf, len); tmpBuf[len+lenInc] = 0; SAFE_DELETE_ARRAY(sTempBuf1[sRecurse]); sTempBuf1[sRecurse] = tmpBuf; *buf = tmpBuf; } else if (!strcmp(&command[1], "define")) { char name[256]; TArray macro; sFill(buf, name); while (**buf <= 0x20) {++*buf;} while (**buf != 0xa && **buf != 0xd) { if (**buf == '\\') { macro.AddElem(0x20); while (**buf != '\n') {++*buf;} ++*buf; continue; } macro.AddElem(**buf); ++*buf; } macro.AddElem(0); SPair pr; pr.MacroName = name; pr.Macro = ¯o[0]; g_Macros.push_back(pr); } else if (!strcmp(&command[1], "ifdef")) { char name[256]; sFill(buf, name); int nID; nID = fxFindMacro(g_Macros, name); if (nID == -1) nID = fxFindMacro(sStaticMacros, name); if (nID == -1) { sbIFDEF.AddElem(false); fxIgnoreBlock(buf); } else sbIFDEF.AddElem(true); } else if (!strcmp(&command[1], "else")) { int nLevel = sbIFDEF.Num()-1; if (nLevel < 0) { Warning( 0,0,"#else without #ifdef"); return; } if (sbIFDEF[nLevel] == true) fxIgnoreBlock(buf); } else if (!strcmp(&command[1], "endif")) { int nLevel = sbIFDEF.Num()-1; if (nLevel < 0) { Warning( 0,0,"#endif without #ifdef"); return; } sbIFDEF.Remove(nLevel); } } bool fxTranslate(char **buf, const char *command) { int i; for (i=0; iid != 0) { if (!strnicmp (tokens->token, *buf, strlen (tokens->token))) { // here we could be matching PART of a string // we could detect this here or the token list // could just have the longer tokens first in the list pCurCommand = *buf; break; } ++tokens; } if (tokens->id == 0) { if (gShObjectNotFound) iLog->Log (gShObjectNotFound); iLog->Log ("Warning: Found token '%s' which was not one of the list (Skipping).\n", token); while (ptokens->id != 0) { iLog->Log (" %s\n", ptokens->token); ptokens++; } return 0; // token not found !error! } // skip the token *buf += strlen (tokens->token); SkipCharacters (buf, kWhiteSpace); if (**buf == '[') { ++*buf; SkipCharacters (buf, kWhiteSpace); nIndex = atoi(*buf); while(**buf != ']') {++*buf;} ++*buf; SkipCharacters (buf, kWhiteSpace); } // get optional name *name = GetSubText (buf, 0x27, 0x27); // single quotes SkipCharacters (buf, kWhiteSpace); // get optional data if (**buf == '=') // hmm, this is an assignment and not a command/object { ++*buf; // skip the '=' *data = fxGetAssignmentText (buf); } else { *data = GetSubText (buf, '(', ')'); if (!*data) *data = GetSubText (buf, '{', '}'); } return tokens->id; } long fxGetObject(char **buf, SFXTokenDesc *tokens, char **name, char **value, char **data, char **assign, char **annotations, std::vector& Structs) { if (!*buf) return 0; // name: name of parameter // value: follows '=' assignment // data: inside '{' '}' brackets // assign: follows ':' assignment // annotations: inside '<' '>' brackets // find the token. // for now just use brute force. Improve later. SFXTokenDesc *ptokens = tokens; char *tmpBuf; char Token[256]; while (true) { SkipCharacters (buf, kWhiteSpace); SkipComments(buf, true); bool bFunction = false; if (!(*buf)) return -2; if (!**buf) // at end of file return -2; tmpBuf = *buf; sFill(buf, Token); SkipCharacters (buf, kWhiteSpace); SkipComments(buf, true); bool bFound = false; if (Token[0] == '#') { if (Token[1] > 0x20) fxPreprocess(buf, Token); else { *buf = tmpBuf; sFillCR(buf, Token); SFXStruct str; str.m_Name = ""; str.m_Struct = Token; Structs.push_back(str); } } else { *buf = tmpBuf; // Check for function while (true) { // Check for vertex/pixel shader/function SkipCharacters(buf, kWhiteSpace); SkipComments(buf, kWhiteSpace); if (!**buf) break; char szOut[128]; char *saveBuf = *buf; int i = 0; while (**buf > 0x20) { szOut[i++] = **buf; ++*buf; } szOut[i] = 0; SkipCharacters(buf, kWhiteSpace); while (**buf != '(' && **buf > 0x20) { ++*buf; } if (**buf <= 0x20) SkipCharacters(buf, kWhiteSpace); if (**buf == '(') { char *s = strchr(*buf, '{'); assert(s); if (s) { int nRecurse = 0; while (*s >= 0) { if (*s == '{') nRecurse++; else if (*s == '}') { nRecurse--; if (nRecurse == 0) break; } s++; } } if (s) { char *sBuf = saveBuf; s[1] = 0; SFXStruct str; str.m_Name = sGetFuncName(sBuf); str.m_Struct = sBuf; Structs.push_back(str); *buf = s+2; bFunction = true; } } else { *buf = saveBuf; break; } } if (!bFunction) { bFound = fxTranslate(buf, Token); if (!bFound) break; } } } int len; while (tokens->id != 0) { len = strlen(tokens->token); if (!strnicmp (tokens->token, Token, len)) { pCurCommand = *buf; break; } tokens++; } if (tokens->id == 0) { if (gShObjectNotFound) iLog->Log (gShObjectNotFound); iLog->Log ("Warning: FX parser found token '%s' which was not one of the list (Skipping).\n", Token); while (ptokens->id != 0) { iLog->Log (" %s\n", ptokens->token); ptokens++; } return 0; // token not found !error! } if (tokens->id < 0) { *data = tmpBuf; while (**buf != 0xa && **buf != 0xd && **buf != 0) { ++*buf; } **buf = 0; ++*buf; fxTranslate(data); return -tokens->id; } // skip the token *buf += len; while (**buf > 0x20) { ++*buf; } SkipCharacters (buf, kWhiteSpace); *name = GetAssignmentText(buf); SkipCharacters (buf, kWhiteSpace); if (**buf == ':') { ++*buf; // skip the ':' *assign = GetAssignmentText(buf); } else *assign = 0; // get optional annotations SkipCharacters (buf, kWhiteSpace); *annotations = GetSubText (buf, '<', '>'); SkipCharacters (buf, kWhiteSpace); // get optional data if (**buf == '=') // hmm, this is an assignment and not a command/object { ++*buf; // skip the '=' *value = fxGetAssignmentText2 (buf); } else *value = NULL; SkipCharacters (buf, kWhiteSpace); char *d = GetSubText (buf, '{', '}'); //if (d) // fxTranslate(&d); *data = d; if (!*data) *data = GetSubText (buf, '(', ')'); return tokens->id; } void fxGetParams(char *annot, std::vector & prms) { char *buf = annot; SFXParam prm; while (buf[0]) { SkipCharacters (&buf, kWhiteSpace); if (!buf[0]) break; if (!strnicmp(buf, "string", sizeof("string")-1)) prm.m_Type = eType_STRING; else if (!strnicmp(buf, "float", sizeof("float")-1)) prm.m_Type = eType_FLOAT; else if (!strnicmp(buf, "int", sizeof("int")-1)) prm.m_Type = eType_INT; else if (!strnicmp(buf, "bool", sizeof("bool")-1)) prm.m_Type = eType_BOOL; while (*buf > 0x20) { ++buf; } SkipCharacters (&buf, kWhiteSpace); prm.m_Name = GetAssignmentText(&buf); SkipCharacters (&buf, kWhiteSpace); if (buf[0] == '=') { buf++; SkipCharacters (&buf, kWhiteSpace); if (buf[0] == '"') { prm.m_Value.m_String = &buf[1]; char *s = strchr(&buf[1], '"'); s[0] = 0; buf = s+1; } else { switch(prm.m_Type) { case eType_FLOAT: prm.m_Value.m_Float = shGetFloat(buf); break; case eType_INT: prm.m_Value.m_Float = shGetInt(buf); break; default: assert(0); } while (*buf > 0x20) { ++buf; } } } else prm.m_Value.m_Int = 0; prms.push_back(prm); SkipCharacters (&buf, kWhiteSpace); assert (buf[0] == ';'); buf++; } } /*---------------------------------------------------------------- Pass in a pointer to a buffer of text. This pointer is modified to point to the text after the command description. The token id for the command is returned. The params pointer will point to the optional data for the object. The text buffer will get modified so BEWARE. ----------------------------------------------------------------*/ long shGetCommand (char **buf, tokenDesc * tokens, char **params) { char *name; return shGetObject (buf, tokens, &name, params); } /*---------------------------------------------------------------- Returns the string of text between the open and close characters. Modifies the buffer. Moves the buffer pointer to after the last delimiter. Can return nil; buffer MUST already be at the opening delimiter. Skips nested delimiters too. NOTE: Should skip quoted text, does not at this time. ----------------------------------------------------------------*/ char *GetSubText (char **buf, char open, char close) { if (**buf == 0 || **buf != open) return 0; ++*buf; // skip opening delimiter char *result = *buf; // now find the closing delimiter char theChar; long skip = 1; if (open == close) // we cant nest identical delimiters open = 0; while ((theChar = **buf) != 0) { if (theChar == open) ++skip; if (theChar == close) { if (--skip == 0) { **buf = 0; // null terminate the result string ++*buf; // move past the closing delimiter break; } } ++*buf; // try next character } return result; } int shGetVar (char **buf, char **vr, char **val) { static char v[128]; SkipCharacters (buf, kWhiteSpace); SkipComments(buf, true); if (!**buf) // at end of file return -2; int i = 0; v[0] = 0; char c; while (c=(*buf)[i]) { if (c == 0x20 || c == '=') { strncpy(v, *buf, i); v[i] = 0; break; } i++; } if (!v[0]) return 0; int ret = 1; *vr = v; // skip the token *buf += strlen (v); SkipCharacters (buf, kWhiteSpace); // get optional data if (**buf == '=') // hmm, this is an assignment and not a command/object { ++*buf; // skip the '=' *val = GetAssignmentText (buf); } else { *val = GetSubText (buf, '(', ')'); if (!*val) *val = GetSubText (buf, '{', '}'); } return ret; } /*---------------------------------------------------------------- Returns the string of text after a = up to the next whitespace. Terminates the string and moves the buf pointer. ----------------------------------------------------------------*/ char *GetAssignmentText (char **buf) { SkipCharacters (buf, kWhiteSpace); char *result = *buf; // now, we need to find the next whitespace to end the data char theChar; while ((theChar = **buf) != 0) { if (theChar <= 0x20 || theChar == ';') // space and control chars break; ++*buf; } **buf = 0; // null terminate it if (theChar) // skip the terminator ++*buf; return result; } char *fxGetAssignmentText (char **buf) { SkipCharacters (buf, kWhiteSpace); char *result = *buf; // now, we need to find the next ';' to end the data char theChar; while ((theChar = **buf) != 0) { if (theChar == ';') // line terminate break; ++*buf; } **buf = 0; // null terminate it if (theChar) // skip the terminator ++*buf; return result; } char *fxGetAssignmentText2 (char **buf) { SkipCharacters (buf, kWhiteSpace); char *result = *buf; // now, we need to find the next ';' to end the data char theChar; if (**buf == '{') { while ((theChar = **buf) != 0) { if (theChar == ';') // line terminate break; ++*buf; } } else { while ((theChar = **buf) != 0) { if (theChar <= 0x20) // space and control chars break; ++*buf; } } **buf = 0; // null terminate it if (theChar) // skip the terminator ++*buf; return result; } bool shGetBool(char *buf) { if (!buf) return false; if ( !strnicmp(buf, "yes", 3) ) return true; if ( !strnicmp(buf, "true", 4) ) return true; if ( !strnicmp(buf, "on", 2) ) return true; if ( !strncmp(buf, "1", 1) ) return true; return false; } float shGetFloat(char *buf) { if (!buf) return 0; float f; sscanf(buf, "%f", &f); return f; } void shGetFloat(char *buf, float *v1, float *v2) { if (!buf) return; float f, f1; int n = sscanf(buf, "%f %f", &f, &f1); if (n == 1) { *v1 = f; *v2 = f; } else { *v1 = f; *v2 = f1; } } int shGetInt(char *buf) { if (!buf) return 0; int i; sscanf(buf, "%i", &i); return i; } int shGetHex(const char *buf) { if (!buf) return 0; int i; sscanf(buf, "%x", &i); return i; } uint64 shGetHex64(const char *buf) { if (!buf) return 0; uint64 i; sscanf(buf, "%I64x", &i); return i; } void shGetVector(char *buf, Vec3d& v) { if (!buf) return; sscanf(buf, "%f %f %f", &v[0], &v[1], &v[2]); } void shGetVector(char *buf, float v[3]) { if (!buf) return; sscanf(buf, "%f %f %f", &v[0], &v[1], &v[2]); } void shGetVector4(char *buf, vec4_t& v) { if (!buf) return; sscanf(buf, "%f %f %f %f", &v[0], &v[1], &v[2], &v[3]); } static struct SColAsc { char *nam; CFColor col; SColAsc(char *name, const CFColor& c) { nam = name; col = c; } } sCols[] = { SColAsc("Aquamarine", Col_Aquamarine), SColAsc("Black", Col_Black), SColAsc("Blue", Col_Blue), SColAsc("BlueViolet", Col_BlueViolet), SColAsc("Brown", Col_Brown), SColAsc("CadetBlue", Col_CadetBlue), SColAsc("Coral", Col_Coral), SColAsc("CornflowerBlue", Col_CornflowerBlue), SColAsc("Cyan", Col_Cyan), SColAsc("DarkGreen", Col_DarkGreen), SColAsc("DarkOliveGreen", Col_DarkOliveGreen), SColAsc("DarkOrchild", Col_DarkOrchild), SColAsc("DarkSlateBlue", Col_DarkSlateBlue), SColAsc("DarkSlateGray", Col_DarkSlateGray), SColAsc("DarkSlateGrey", Col_DarkSlateGrey), SColAsc("DarkTurquoise", Col_DarkTurquoise), SColAsc("DarkWood", Col_DarkWood), SColAsc("DimGray", Col_DimGray), SColAsc("DimGrey", Col_DimGrey), SColAsc("FireBrick", Col_FireBrick), SColAsc("ForestGreen", Col_ForestGreen), SColAsc("Gold", Col_Gold), SColAsc("Goldenrod", Col_Goldenrod), SColAsc("Gray", Col_Gray), SColAsc("Green", Col_Green), SColAsc("GreenYellow", Col_GreenYellow), SColAsc("Grey", Col_Grey), SColAsc("IndianRed", Col_IndianRed), SColAsc("Khaki", Col_Khaki), SColAsc("LightBlue", Col_LightBlue), SColAsc("LightGray", Col_LightGray), SColAsc("LightGrey", Col_LightGrey), SColAsc("LightSteelBlue", Col_LightSteelBlue), SColAsc("LightWood", Col_LightWood), SColAsc("LimeGreen", Col_LimeGreen), SColAsc("Magenta", Col_Magenta), SColAsc("Maroon", Col_Maroon), SColAsc("MedianWood", Col_MedianWood), SColAsc("MediumAquamarine", Col_MediumAquamarine), SColAsc("MediumBlue", Col_MediumBlue), SColAsc("MediumForestGreen", Col_MediumForestGreen), SColAsc("MediumGoldenrod", Col_MediumGoldenrod), SColAsc("MediumOrchid", Col_MediumOrchid), SColAsc("MediumSeaGreen", Col_MediumSeaGreen), SColAsc("MediumSlateBlue", Col_MediumSlateBlue), SColAsc("MediumSpringGreen", Col_MediumSpringGreen), SColAsc("MediumTurquoise", Col_MediumTurquoise), SColAsc("MediumVioletRed", Col_MediumVioletRed), SColAsc("MidnightBlue", Col_MidnightBlue), SColAsc("Navy", Col_Navy), SColAsc("NavyBlue", Col_NavyBlue), SColAsc("Orange", Col_Orange), SColAsc("OrangeRed", Col_OrangeRed), SColAsc("Orchid", Col_Orchid), SColAsc("PaleGreen", Col_PaleGreen), SColAsc("Pink", Col_Pink), SColAsc("Plum", Col_Plum), SColAsc("Red", Col_Red), SColAsc("Salmon", Col_Salmon), SColAsc("SeaGreen", Col_SeaGreen), SColAsc("Sienna", Col_Sienna), SColAsc("SkyBlue", Col_SkyBlue), SColAsc("SlateBlue", Col_SlateBlue), SColAsc("SpringGreen", Col_SpringGreen), SColAsc("SteelBlue", Col_SteelBlue), SColAsc("Tan", Col_Tan), SColAsc("Thistle", Col_Thistle), SColAsc("Turquoise", Col_Turquoise), SColAsc("Violet", Col_Violet), SColAsc("VioletRed", Col_VioletRed), SColAsc("Wheat", Col_Wheat), SColAsc("White", Col_White), SColAsc("Yellow", Col_Yellow), SColAsc("YellowGreen", Col_YellowGreen), SColAsc(NULL, CFColor(1.0f,1.0f,1.0f)) }; #include void shGetColor(char *buf, CFColor& v) { char name[64]; if (!buf) { v = Col_White; return; } if (isalpha(buf[0])) { int n = 0; float scal = 1; strcpy(name, buf); char nm[64]; if (strchr(buf, '*')) { while (buf[n] != '*') { if (buf[n] == 0x20) break; nm[n] = buf[n]; n++; } nm[n] = 0; if (buf[n] == 0x20) { while (buf[n] != '*') n++; } n++; while (buf[n] == 0x20) n++; scal = shGetFloat(&buf[n]); strcpy(name, nm); } n = 0; while (sCols[n].nam) { if (!stricmp(sCols[n].nam, name)) { v = sCols[n].col; if (scal != 1) v.ScaleCol(scal); return; } n++; } } int n = sscanf(buf, "%f %f %f %f", &v.r, &v.g, &v.b, &v.a); switch (n) { case 0: v.r = v.g = v.b = v.a = 1.0f; break; case 1: v.g = v.b = v.a = 1.0f; break; case 2: v.b = v.a = 1.0f; break; case 3: v.a = 1.0f; break; } //v.Clamp(); } void shGetColor(char *buf, float v[4]) { char name[64]; if (!buf) { v[0] = 1.0f; v[1] = 1.0f; v[2] = 1.0f; v[3] = 1.0f; return; } if (isalpha(buf[0])) { int n = 0; float scal = 1; strcpy(name, buf); char nm[64]; if (strchr(buf, '*')) { while (buf[n] != '*') { if (buf[n] == 0x20) break; nm[n] = buf[n]; n++; } nm[n] = 0; if (buf[n] == 0x20) { while (buf[n] != '*') n++; } n++; while (buf[n] == 0x20) n++; scal = shGetFloat(&buf[n]); strcpy(name, nm); } n = 0; while (sCols[n].nam) { if (!stricmp(sCols[n].nam, name)) { v[0] = sCols[n].col[0]; v[1] = sCols[n].col[1]; v[2] = sCols[n].col[2]; v[3] = sCols[n].col[3]; if (scal != 1) { v[0] *= scal; v[1] *= scal; v[2] *= scal; } return; } n++; } } int n = sscanf(buf, "%f %f %f %f", &v[0], &v[1], &v[2], &v[3]); switch (n) { case 0: v[0] = v[1] = v[2] = v[3] = 1.0f; break; case 1: v[1] = v[2] = v[3] = 1.0f; break; case 2: v[2] = v[3] = 1.0f; break; case 3: v[3] = 1.0f; break; } //v.Clamp(); } char *fxReplaceInText(char *pText, const char *pSubStr, const char *pReplace) { char *pTextIn = pText; int nLenSubStr = strlen(pSubStr); int nLenReplace = strlen(pReplace); char *pOut = NULL; int nCurSearch = 0; while (true) { char *Str = strstr(&pText[nCurSearch], pSubStr); if (!Str) return pText; if (nLenSubStr == nLenReplace) { memcpy(Str, pReplace, nLenReplace); continue; } int nLenText = strlen(pText); int nNewLen = nLenText-nLenSubStr+nLenReplace; pOut = new char[nNewLen+1]; int nOffs = Str-pText; memcpy(pOut, pText, nOffs); memcpy(&pOut[nOffs],pReplace,nLenReplace); memcpy(&pOut[nOffs+nLenReplace],&pText[nOffs+nLenSubStr],nLenText-nOffs-nLenSubStr); pOut[nNewLen] = 0; if (pText && pText != pTextIn) delete [] pText; pText = pOut; nCurSearch = nOffs + nLenReplace; } } char *fxReplaceInText2(char *pText, const char *pSubStr, const char *pReplace) { char *pTextIn = pText; int nLenSubStr = strlen(pSubStr); int nLenReplace = strlen(pReplace); char *pOut = NULL; int nCurSearch = 0; while (true) { char *Str = strstr(&pText[nCurSearch], pSubStr); if (!Str) return pText; if ((Str[-1] >= 0x30 && Str[-1] <= 0x7f) || (Str[nLenSubStr] >= 0x30 && Str[nLenSubStr] <= 0x7f)) { if (Str[-1] != ';' && Str[nLenSubStr] != ';') { nCurSearch += nLenSubStr; continue; } } if (nLenSubStr == nLenReplace) { memcpy(Str, pReplace, nLenReplace); continue; } int nLenText = strlen(pText); int nNewLen = nLenText-nLenSubStr+nLenReplace; pOut = new char[nNewLen+1]; int nOffs = Str-pText; memcpy(pOut, pText, nOffs); memcpy(&pOut[nOffs],pReplace,nLenReplace); memcpy(&pOut[nOffs+nLenReplace],&pText[nOffs+nLenSubStr],nLenText-nOffs-nLenSubStr); pOut[nNewLen] = 0; if (pText && pText != pTextIn) delete [] pText; pText = pOut; nCurSearch = nOffs + nLenReplace; } }