//-------------------------------------------------------------- // find a file in parent directories BOOL mgOSFindFile( mgString& location, const char* fileName) { WCHAR* oldCWD = _wgetcwd(NULL, 0); if (oldCWD == NULL) return false; mgString cwd(oldCWD); while (true) { if (cwd.endsWith("\\")) location.format("%s%s", (const char*) cwd, fileName); else location.format("%s\\%s", (const char*) cwd, fileName); WCHAR* wideName; int wideLen; location.toWCHAR(wideName, wideLen); struct _stat filestat; BOOL found = 0 == _wstat(wideName, &filestat); delete wideName; wideName = NULL; if (found) return true; else { // remove last directory from cwd int slash = cwd.reverseFind(cwd.length(), '\\'); if (slash != -1) cwd.deleteAt(slash, cwd.length()-slash); else return false; // no more directories. file not found. } } }
//----------------------------------------------------------------------------- // set a variable void SeaOfMemes::debugSetVariable( const char* varName, const char* value, mgString& reply) { if (m_world == NULL) { reply.format("cannot set %s", varName); return; } double len; if (1 != sscanf(value, "%lf", &len)) { reply.format("invalid value %s", value); return; } // keep rotation times in range len = max(1, len); reply = "ok"; if (_stricmp(varName, "planetDayLen") == 0) m_world->m_planetDayLen = len; else if (_stricmp(varName, "moonDayLen") == 0) m_world->m_moonDayLen = len; else if (_stricmp(varName, "ringDayLen") == 0) m_world->m_ringDayLen = len; else if (_stricmp(varName, "moonMonthLen") == 0) m_world->m_moonMonthLen = len; else if (_stricmp(varName, "beltMonthLen") == 0) m_world->m_beltMonthLen = len; else reply.format("cannot set %s" ,varName); }
//-------------------------------------------------------------- // check version of OpenGL available BOOL mgLinuxGL33Support::checkVersion( int reqGLVersion, int reqShaderVersion, mgString& errorMsg) { const char* glVersionStr = (const char*) glGetString(GL_VERSION); if (glVersionStr == NULL) { errorMsg = "cannot read OpenGL version"; return false; } int major, minor, glVersion; if (2 != sscanf(glVersionStr, "%d.%d", &major, &minor)) { errorMsg.format("cannot parse OpenGL version %s", (const char*) glVersionStr); return false; } // trim trailing zeros. 3.3 and 3.30 are the same while (minor%10 == 0) minor /= 10; glVersion = major*100 + minor; const char* shaderVersionStr = (const char*) glGetString(GL_SHADING_LANGUAGE_VERSION); if (shaderVersionStr == NULL) { errorMsg = "cannot read OpenGL Shader Language version"; return false; } int shaderVersion; if (2 != sscanf(shaderVersionStr, "%d.%d", &major, &minor)) { errorMsg.format("cannot parse OpenGL version %s", (const char*) shaderVersionStr); return false; } // trim trailing zeros. 3.3 and 3.30 are the same while (minor%10 == 0) minor /= 10; shaderVersion = major*100 + minor; if (glVersion < reqGLVersion || shaderVersion < reqShaderVersion) { errorMsg.format("App requested OpenGl %d.%d, shader %d.%d\nSystem has OpenGL %d.%d, shader %d.%d", reqGLVersion/100, reqGLVersion%100, reqShaderVersion/100, reqShaderVersion%100, glVersion/100, glVersion%100, shaderVersion/100, shaderVersion%100); return false; } return true; }
//-------------------------------------------------------------------------- // return shader log error messages as a string void mgLinuxGL33Support::getShaderLog( GLuint shader, mgString& log) { GLint logLen, retLen; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLen); char* logText = new char[logLen]; glGetShaderInfoLog(shader, logLen, &retLen, logText); log.empty(); log.write((const char*) logText, retLen); delete logText; }
//-------------------------------------------------------------------------- // get shader log error messages as string void GL21getShaderLog( GLuint shader, mgString& logStr) { GLint logLen, retLen; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLen); char* logText = new char[logLen]; glGetShaderInfoLog(shader, logLen, &retLen, logText); logStr.empty(); logStr.write(logText, retLen); delete logText; }
//----------------------------------------------------------------------------- // return value of variable void SeaOfMemes::debugGetVariable( const char* varName, mgString& value) { mgPoint3 eyePt; if (m_world == NULL) { value = "unknown"; return; } m_world->getEyePt(eyePt); if (_stricmp(varName, "eyePt.x") == 0) value.format("%g", eyePt.x); else if (_stricmp(varName, "eyePt.y") == 0) value.format("%g", eyePt.y); else if (_stricmp(varName, "eyePt.z") == 0) value.format("%g", eyePt.z); else if (_stricmp(varName, "planetDayLen") == 0) value.format("%g", m_world->m_planetDayLen); else if (_stricmp(varName, "moonDayLen") == 0) value.format("%g", m_world->m_moonDayLen); else if (_stricmp(varName, "ringDayLen") == 0) value.format("%g", m_world->m_ringDayLen); else if (_stricmp(varName, "moonMonthLen") == 0) value.format("%g", m_world->m_moonMonthLen); else if (_stricmp(varName, "beltMonthLen") == 0) value.format("%g", m_world->m_beltMonthLen); else value = "unknown variable"; }
//-------------------------------------------------------------- // comma format speed void SpeedUI::commaFormat( mgString& line, const char* suffix, int value) { line.format("%d %s", value, (const char*) suffix); // add the commas int posn = line.find(0, ' ')-3; while (posn > 0) { line.insertAt(posn, ",", 1); posn -= 3; } }
//-------------------------------------------------------------- // substitute vars into message and return void mgErrorTable::unknownMsg( mgString& text, // returned message text const char* msgId, const char* varNames, const char* varValues) { // no error message, so format args text.format("Unknown error(%s)", (const char*) msgId); int namePosn = 0; int valuePosn = 0; mgString argName; mgString argValue; while (true) { namePosn = parseVar(argName, varNames, namePosn); valuePosn = parseVar(argValue, varValues, valuePosn); if (namePosn == -1 || valuePosn == -1) break; text += ", "; text += argName; text += "=\""; text += argValue; text += "\""; } }
//-------------------------------------------------------------- // process input line void mgDebugPane::processInput( const mgString& input) { mgString verb; int posn = input.getToken(0, " *(=", verb); if (verb.equalsIgnoreCase("help")) { mgString helpText; m_debugApp->debugHelp(helpText); m_console->addLine(OUTPUT_COLOR, NULL, helpText); } else if (verb.equalsIgnoreCase("list")) { listVariables(); listFunctions(); } else { if (!parseGetVariable(input)) { if (!parseSetVariable(input)) { if (!parseCallFunction(input)) m_console->addLine(ERROR_COLOR, NULL, "Unknown command."); } } } }
//-------------------------------------------------------------- // set slashes appropriately for OS void mgOSFixFileName( mgString& name) { name.trim(); // convert any backslashes to forward slashes mgString bs("/"); char letter[MG_MAX_LETTER]; int posn = 0; while (posn < name.length()) { int next = name.nextLetter(posn, letter); if (strcmp(letter, "\\") == 0) next = name.setLetter(posn, bs); posn = next; } }
//-------------------------------------------------------------- // get cursor X coordinate int mgSimpleField::getCursorX( const mgString& displayStr) { int cursorX = 0; int posn = m_cursorPosn - m_scrollPosn; // if cursor position within displayed text if (posn <= displayStr.length()) { // measure string from scroll position up to cursor cursorX = m_font->stringWidth(displayStr, posn); } else { // measure string from scroll position, plus blanks to cursor position cursorX = m_font->stringWidth(displayStr, displayStr.length()); cursorX += m_font->stringWidth(" ", 1) * (posn - displayStr.length()); } return cursorX; }
//-------------------------------------------------------------- // resolve possibly relative file name. void mgOSResolveRelativeName( const char* sourceFile, const char* relName, mgString& absName) { mgString name(relName); mgOSFixFileName(name); // if relative name starts with /, we're done if (name.startsWith("/")) { absName = name; return; } // assume it's really relative. strip last directory in source file absName = sourceFile; int lastSlash = absName.reverseFind(absName.length(), "/"); if (lastSlash != -1) absName.deleteAt(lastSlash+1, absName.length()-(lastSlash+1)); else absName.empty(); // source file has no dir absName += name; }
//-------------------------------------------------------------- // parse a name or value off the strings int mgErrorTable::parseVar( mgString& value, const char* argString, int posn) { value.empty(); while (true) { char c = argString[posn++]; if (c == '\0') return -1; if (c == MG_ERROR_DELIM) return posn; value += c; } }
//-------------------------------------------------------------- // write stats to debug void ChunkWorld::debugStats( mgString& status) { m_chunkLock->lock(); int unloadedCount = 0; int inmemoryCount = 0; int indisplayCount = 0; int needsUpdateCount = 0; ChunkListNode* lruItem = m_LRUList.m_first; while (lruItem != NULL) { ChunkObj* oldest = lruItem->m_chunk; switch (oldest->m_status) { case CHUNK_UNLOADED: unloadedCount++; break; case CHUNK_INMEMORY: inmemoryCount++; break; case CHUNK_INDISPLAY: indisplayCount++; break; case CHUNK_NEEDSUPDATE: needsUpdateCount++; break; } lruItem = lruItem->m_next; } status.format("system memory = %gM (%d chunks), display memory = %gM (%d chunks), update = %d, LRU = %d chunks (%d unloaded)", m_systemMemUsed/(1024*1024.0), inmemoryCount, m_displayMemUsed/(1024*1024.0), indisplayCount, needsUpdateCount, m_LRUList.length(), unloadedCount); m_chunkLock->unlock(); }
//-------------------------------------------------------------- // resolve possibly relative file name. void mgOSResolveRelativeName( const char* sourceName, const char* relName, mgString& absName) { mgString name(relName); mgOSFixFileName(name); // if relative name starts with backslash, we're done if (name.startsWith("\\")) { absName = name; return; } // if relative name starts with X: (drive letter), we're done char letter[MG_MAX_LETTER]; int posn = name.nextLetter(0, letter); if (posn < name.length()) { posn = name.nextLetter(posn, letter); if (strcmp(letter, ":") == 0) { absName = name; return; } } // assume it's really relative. strip last directory in source file mgString sourceFile(sourceName); int lastSlash = sourceFile.reverseFind(sourceFile.length(), '\\'); if (lastSlash != -1) sourceFile.substring(absName, 0, lastSlash+1); else absName.empty(); // source file has no dir absName += name; }
//----------------------------------------------------------------------------- // report status for debug log void Landscape::appDebugStats( mgString& status) { status.format("max count = %d", m_maxCount); }
//----------------------------------------------------------------- // get font string void mgTextBuffer::getFont( mgString& fontSpec) { fontSpec.format("%s-%d%s%s", (const char*) m_fontFace, m_fontSize, m_fontBold == mgTrue? "-b" : "", m_fontItalic == mgTrue ? "-i" : ""); }
//-------------------------------------------------------------- // find a file in parent directories BOOL mgOSFindFile( mgString& location, const char* fileName) { char* oldCWD = getcwd(NULL, 0); if (oldCWD == NULL) return false; mgString cwd(oldCWD); while (true) { if (cwd.endsWith("/")) location.format("%s%s", (const char*) cwd, fileName); else location.format("%s/%s", (const char*) cwd, fileName); struct stat filestat; if (0 == stat(location, &filestat)) return true; else { // remove last directory from cwd int slash = cwd.reverseFind(cwd.length(), '/'); if (slash != -1) cwd.deleteAt(slash, cwd.length()-slash); else return false; // no more directories. file not found. } } }